
在 Mars3d 中實現多點重疊右擊選擇重疊點菜單標簽Mars3DCesiumVue3三維地圖前言最近用 Mars3D 做三維地圖項目時遇到個需求地圖上加載若干 3D 模型站點當多個站點位置完全重疊同一經緯度時右鍵彈出選擇列表讓用戶挑哪一個單個 graphic 時彈出詳情/定位/刪除操作菜單。之前使用算法計算麻煩改為插件方法drillPick一、需求場景地圖上加載 12 個城市站點北京1和北京2坐標完全一致用于測試重疊拾取用戶右鍵時命中單個模型菜單 [“詳情”, “定位”, “刪除”]命中重疊模型如 北京1北京2菜單 [“北京2”, “北京1”]點哪一項就操作哪個沒命中模型空地不彈菜單普通scene.pick()只能拿到頂層 graphic要拿到所有命中對象必須用穿透拾取scene.drillPick(position, limit)。二、踩坑drillPick 拿不到 graphic第一直覺代碼graphicLayer.on(mars3d.EventType.rightDown,function(event){constpickedmap.scene.drillPick(event.windowPosition,10);console.log(picked);});輸出結果picked.length 2?穿透拾取正確picked[0].id undefined?按 Cesium 文檔pickedObject.id應該返回 primitive id進而能拿到綁定的 graphic 對象。Mars3D 包裝后這個字段是空的這是第一個坑。三、破局三個隱藏字段 必須顯式開啟3.1 關鍵字段打開 Console 一層層扒primitivepicked[0].primitive._mars3d_graphicId// 2graphic 在圖層內的 idpicked[0].primitive._mars3d_layerId// m-0f6db520-...圖層 idpicked[0].primitive._id// Cesium 原生 id未設置時也是 undefinedMars3D 把 graphic id 掛在了帶_mars3d_前綴的私有字段上。結合map.getLayer(lid).getGraphicById(gid)即可反查constgraphicspicked.map((p){constgidp.primitive?._mars3d_graphicId;constlidp.primitive?._mars3d_layerId;if(gidnull)returnnull;constlayerlid?map.getLayer(lid):graphicLayer;returnlayer?layer.getGraphicById(gid):null;}).filter(Boolean);3.2 必須顯式開啟穿透拾取這是第二個坑Mars3D 默認allowDrillPick false出于性能考慮必須顯式設置newmars3d.graphic.ModelPrimitive({id:i1,name:item.name,position:item.position,allowDrillPick:true,// ← 不開則 drillPick 返回空數組style:{/* ... */},});四、最終實現4.1 右鍵回調核心 30 行graphicLayer.on(mars3d.EventType.rightDown,function(event){constgraphicevent.graphic;// 穿透拾取limit 給個合理上限constpickedObjectsmap.scene.drillPick(event.windowPosition,20);if(!graphic)return;// 從 drillPick 反查 graphic 實例過濾非 modelPconstgraphicspickedObjects.map((p){constgidp.primitive?._mars3d_graphicId;constlidp.primitive?._mars3d_layerId;if(gidnull)returnnull;constlayerlid?map.getLayer(lid):graphicLayer;returnlayer?layer.getGraphicById(gid):null;}).filter(Boolean).filter((g)g.typemodelP);if(graphics.length0)return;// 多 graphic 重疊 → 聚合選擇單個 → 操作菜單if(graphics.length1){handleBindSelectContextMenu(graphic,graphics);}else{handleBindContextMenu(graphic);}});4.2 數據驅動的菜單分發不同類型 graphic 顯示不同菜單項新增類型只需加一行constMENU_BY_TYPE{modelP:[{text:詳情,action:detail},{text:定位,action:flyTo},{text:刪除,action:remove},],default:[{text:詳情,action:detail}],};consthandleMenuAction(action,graphic){switch(action){casedetail:console.log(詳情:,graphic);break;caseflyTo:graphic.flyTo({duration:1});break;caseremove:graphic.remove();break;default:console.log(未實現:,action);}};consthandleBindContextMenu(graphic){constitemsMENU_BY_TYPE[graphic.type]||MENU_BY_TYPE.default;graphic.bindContextMenu(items.map((item)({text:item.text,callback:()handleMenuAction(item.action,graphic),})));};consthandleBindSelectContextMenu(graphic,graphics){// 多要素聚合每項名 真實 graphic 的 name/attrgraphic.bindContextMenu(graphics.map((g)({text:g.name||g.attr?.remark||#${g.id??},callback:()handleBindContextMenu(g),})));};五、效果驗證場景右鍵菜單成都單 graphic[詳情, 定位, 刪除]北京1北京2 重疊[北京2, 北京1]南京滁州 重疊[滁州, 南京]空地無模型不彈菜單六、總結四個關鍵點反查 graphic用primitive._mars3d_graphicId_mars3d_layerId別用pickedObject.id必須開啟new ModelPrimitive({ allowDrillPick: true })數據驅動菜單MENU_BY_TYPE表 action 派發新增類型零成本多 graphic 重疊先彈聚合選擇菜單再遞歸綁定詳情菜單希望幫到同樣用 Mars3D 的朋友。有問題評論區交流