作為剛接觸 mapvthree 的新手,今天我專門學習了事件系統。這裏彙總最實用的內容,幫助和我一樣的初學者快速掌握交互的核心用法。
綁定與移除事件,只需記住 add/remove
mapvthree 複用了 Three.js 的 addEventListener / removeEventListener,所以任何繼承自 Object3D 的對象都能直接綁定事件。引擎內部的調度器會幫我們處理拾取、命中檢測等複雜邏輯,我們只需要專注於“監聽哪一個對象”和“響應什麼事件”。
const box = engine.add(new THREE.Mesh(
new THREE.BoxGeometry(10, 10, 10),
new THREE.MeshBasicMaterial({color: 0xaa0000}),
));
const handleClick = (e) => {
console.log('盒子被點擊,地理座標:', e.point);
box.removeEventListener('click', handleClick); // 一次性事件
};
box.addEventListener('click', handleClick);
- 常見事件:
click、dblclick、mousemove、mouseenter、mouseleave、pointerdown、pointerup等 - 一定記得在物體移除或銷燬前調用
removeEventListener,避免內存泄漏
EventParam 裏的信息足夠豐富
每次事件觸發,回調都會收到統一的 EventParam,其中最常用的字段如下:
| 屬性 | 説明 |
|---|---|
target / currentTarget |
觸發事件的對象、綁定事件的對象 |
position |
鼠標在世界座標中的位置(Array[3]) |
point |
鼠標在地理座標中的位置(經緯度) |
index / entity |
當事件來自支持 dataSource 的圖層時,可獲取對應的數據索引和實體 |
event |
原始瀏覽器事件對象 |
box.addEventListener('mousemove', (e) => {
if (e.position) {
helper.position.fromArray(e.position); // 在 3D 空間顯示鼠標所在點
}
});
注意:當事件綁定在engine.map這類場景根對象上時,只能拿到position和point,其它字段不存在。
事件不僅限於幾何體,根對象也能監聽
可以在可視化圖層、地圖根節點甚至 engine.map 上綁定事件,從而實現不同層級的交互。例如:
engine.map.addEventListener('pointerdown', () => {
engine.clock.currentTime = new Date('2025-05-15 18:00:00');
});
engine.map.addEventListener('pointerup', () => {
engine.clock.currentTime = new Date('2025-05-15 14:00:00');
});
這段代碼演示瞭如何在地圖級別監聽按下/抬起事件,並根據交互切換天空時間。
事件冒泡:必要時調用 stopPropagation
事件從子節點向父節點冒泡,沿着場景樹一直傳遞到根對象。我們可以利用冒泡做統一處理,也可以在需要時阻止冒泡。
ear.addEventListener('click', (e) => {
alert('點擊到了耳朵');
e.stopPropagation(); // 阻止繼續觸發頭部或整個人的點擊事件
});
head.addEventListener('click', () => alert('點擊到了頭像'));
human.addEventListener('click', () => alert('點擊到了整個人'));
當需要在某個層級攔截事件時,記得調用 stopPropagation()。
使用建議
- 善用一次性事件:如果某個事件只需要觸發一次,回調裏立即調用
removeEventListener。 - 場景根對象的事件:僅能獲取位置座標,適合做“全局點擊”或“拖拽地圖切換模式”之類的功能。
- 粒度控制:能在具體對象上監聽就不要放在根節點,粒度越精細,代碼越容易維護。
- 性能提示:事件調度器會在幀末集中處理,並做異步、去重等優化,正常使用不必擔心性能問題。
學習筆記就到這裏!事件系統本身並不複雜,關鍵是熟悉addEventListener、EventParam和冒泡這幾個核心概念。掌握它們之後,構建交互式地圖就順手多了。希望這份筆記也能幫到你!