| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- /**
- * 点位点选的 DOM 绑定(票 10):「左键点一下」与「左键拖着地图走」必须分开。
- *
- * 为什么必须有这道区分:票 03 的相机契约里左键是**平移**(抓着地图拖)。如果按下就打开点位摘要,
- * 用户每次拖完地图都会弹出一张卡片 —— 那不是新功能,是把已有交互弄坏。判据是**按下与松开的位移**:
- * 不超过阈值算点选,超过算拖拽。
- *
- * 本模块只**观察**事件,不 preventDefault、不 stopPropagation、不抢 pointer capture:
- * 相机的手感与三键契约完全不变(绑定在同一个元素上,两套监听互不干扰)。
- */
- /** 点选允许的最大位移(像素):手指/鼠标总会有几像素抖动,0 会把正常点选判成拖拽。 */
- export const CLICK_MAX_DRAG_PX = 4
- /**
- * 纯判据:两次坐标算不算「点一下」(脱浏览器可断言)。
- * @param {{x: number, y: number}} down 按下时的窗口坐标
- * @param {{x: number, y: number}} up 松开时的窗口坐标
- * @param {number} [maxDrag] 允许的最大位移
- */
- export function isClickGesture(down, up, maxDrag = CLICK_MAX_DRAG_PX) {
- if (!down || !up) return false
- const dx = Number(up.x) - Number(down.x)
- const dy = Number(up.y) - Number(down.y)
- if (!Number.isFinite(dx) || !Number.isFinite(dy)) return false
- return Math.hypot(dx, dy) <= maxDrag
- }
- /**
- * 绑定点选输入。
- * @param {Element} element 事件源(地图宿主:Cesium 画布的事件会冒泡到这里)
- * @param {(point: {x: number, y: number}) => void} onPick 判定为点选时回调(窗口坐标)
- * @param {object} [options] `{ maxDrag }`
- * @returns {() => void} detach
- */
- export function attachPointPick(element, onPick, options = {}) {
- // 与 `attachCameraInput` 同一道判据:不是可绑定元素就退回空 detach(脱浏览器调用不抛错)。
- if (!element || typeof element.addEventListener !== 'function') return () => {}
- const maxDrag = Number.isFinite(options.maxDrag) ? options.maxDrag : CLICK_MAX_DRAG_PX
- let down = null
- const onPointerDown = (event) => {
- // 只认左键:右键是轨道旋转(票 03),中键与其它键不参与点选。
- down = event.button === 0 ? { x: event.clientX, y: event.clientY, id: event.pointerId } : null
- }
- const onPointerUp = (event) => {
- const start = down
- down = null
- if (!start || event.pointerId !== start.id) return
- if (!isClickGesture(start, { x: event.clientX, y: event.clientY }, maxDrag)) return
- if (typeof onPick === 'function') onPick({ x: event.clientX, y: event.clientY })
- }
- const onPointerCancel = () => {
- down = null
- }
- element.addEventListener('pointerdown', onPointerDown)
- element.addEventListener('pointerup', onPointerUp)
- element.addEventListener('pointercancel', onPointerCancel)
- return () => {
- element.removeEventListener('pointerdown', onPointerDown)
- element.removeEventListener('pointerup', onPointerUp)
- element.removeEventListener('pointercancel', onPointerCancel)
- }
- }
|