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