唯杰地图 logo唯杰地图
VJMAP
EN

map-interaction

vjmap/references/event/map-interaction.md 4.4 KB172 行
原文

本文回答:map.on 鼠标 / 触摸 / 键盘事件 —— click / mousemove / wheel / contextmenu / touch。

一、鼠标事件列表

事件 说明
click 单击
dblclick 双击
contextmenu 右键
mousedown / mouseup 按下 / 抬起
mousemove 移动(高频)
mouseover / mouseout 进入 / 离开 canvas
mouseenter / mouseleave 仅 map.on(type, layerId, fn) 有效(进入 / 离开该图层要素);不带 layerId 永不触发
wheel 滚轮
dragstart / drag / dragend 拖拽

二、事件对象结构

interface MapMouseEvent {
  type: string;
  lngLat: { lng, lat };
  point: { x, y };            // 容器像素
  originalEvent: MouseEvent;
  features?: Feature[];       // 带图层过滤时才有
  preventDefault(): void;
}

CAD 坐标:

map.on('click', e => {
  const lngLat = e.lngLat;
  const cad = map.fromLngLat(lngLat);    // {x, y}
});

三、带图层过滤

map.on('click', 'my-layer', e => {
  console.log(e.features[0].properties);
});
map.on('mouseenter', 'my-layer', () => map.getCanvas().style.cursor = 'pointer');
map.on('mouseleave', 'my-layer', () => map.getCanvas().style.cursor = '');

图层级事件只在命中该图层要素时触发。

四、触摸事件

事件 说明
touchstart / touchmove / touchend / touchcancel 触摸
map.on('touchstart', e => console.log(e.points));   // 多指时 points 是数组

五、键盘事件

vjmap 不派发地图级键盘事件:map.on('keydown' / 'keyup') 收不到真实按键(canvas 上的按键只交给内置键盘平移 / 缩放 handler;仅 map.fire('keyup', …) 程序化派发能触发)。用 DOM 监听:

map.getCanvas().focus();   // canvas 获得焦点后按键才会落到地图容器上
map.getCanvasContainer().addEventListener('keydown', e => console.log(e.key));
// 或全局:window.addEventListener('keydown', e => ...)

六、右键菜单

只要有 map.on('contextmenu') 监听(或 dragRotate 处于启用状态),引擎自动对原生事件调 preventDefault,浏览器菜单不会弹出:

map.on('contextmenu', e => {
  // 无需 e.preventDefault():它只给内部 handler 打标记,不是用来防浏览器菜单的
  showMyMenu(e.point.x, e.point.y);
});

右键拖拽默认是旋转 / 俯仰(不是平移),禁用:

map.dragRotate.disable();

七、滚轮 / 缩放

map.on('wheel', e => {
  // e.originalEvent.deltaY
});

map.on('zoom', () => console.log(map.getZoom()));

禁用滚轮缩放:

map.scrollZoom.disable();

八、拖拽识别

按下到抬起位移 ≥ clickTolerance(默认 3px)时引擎本就不派发 click,拖完图不会误触发 click。若仍需拖拽标志,必须在 mousedown 复位(否则拖拽后没有 click 来清标志,会吞掉下一次真正的点击):

let didDrag = false;
map.on('mousedown', () => didDrag = false);
map.on('dragstart', () => didDrag = true);
map.on('click', e => {
  if (didDrag) return;
  // 真正 click
});

九、指针样式

map.getCanvas().style.cursor = 'pointer';
map.getCanvas().style.cursor = 'crosshair';
map.getCanvas().style.cursor = '';

十、节流高频事件

mousemove 每秒 60+ 次:

function throttle(fn, ms) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last > ms) { last = now; fn(...args); }
  };
}

map.on('mousemove', throttle(e => {
  // 贵的查询
}, 100));

或用 requestAnimationFrame 合并:

let pending = false;
map.on('mousemove', e => {
  if (pending) return;
  pending = true;
  requestAnimationFrame(() => {
    // 处理
    pending = false;
  });
});

十一、常见坑

  1. click 不 fire:canvas 上层有 DOM 挡住。
  2. e.features 空:图层 id 错 / 图层未 add。
  3. contextmenu 不 fire:多半被上层 DOM 遮挡(同 click)。
  4. map.on('keydown') 不 fire:地图不派发键盘事件,改用 DOM addEventListener(见 §五)。
  5. 高频 mousemove 卡顿:必节流。
  6. addControl 前绑定事件 → 有时候事件 ordering 导致控件先接管;尽量 await map.onLoad() 后再绑。

相关