fix(map): 修复平板触控与信息窗定位
统一鼠标、触摸和触控笔的画布坐标转换。修复 autofit 及浏览器缩放下的信息窗偏移,并支持平板点击机器人显示详情、点击空白隐藏。
This commit is contained in:
parent
10c9e576e3
commit
520811e883
@ -106,11 +106,14 @@ const init = () => {
|
||||
*/
|
||||
function resizeCanvasToContainer() {
|
||||
if (!mapCanvas || !containerRef.value) return;
|
||||
const containerRect = containerRef.value.getBoundingClientRect(); // 获取容器实际尺寸
|
||||
if (!containerRect.width || !containerRect.height) return;
|
||||
// clientWidth/clientHeight 是布局坐标,不受 autofit.js 的 CSS transform 影响。
|
||||
// getBoundingClientRect() 返回的是缩放后的屏幕尺寸,不能用于 Canvas 逻辑尺寸。
|
||||
const containerWidth = containerRef.value.clientWidth;
|
||||
const containerHeight = containerRef.value.clientHeight;
|
||||
if (!containerWidth || !containerHeight) return;
|
||||
applicationState.devicePixelRatio = window.devicePixelRatio || 1; // 获取设备像素比
|
||||
applicationState.canvasWidthPx = containerRect.width; // 更新逻辑宽度
|
||||
applicationState.canvasHeightPx = containerRect.height; // 逻辑高度 = 容器高度 - 状态栏高度
|
||||
applicationState.canvasWidthPx = containerWidth; // 更新逻辑宽度
|
||||
applicationState.canvasHeightPx = containerHeight; // 逻辑高度 = 容器高度 - 状态栏高度
|
||||
mapCanvas.width = applicationState.canvasWidthPx * applicationState.devicePixelRatio; // Canvas 物理像素宽
|
||||
mapCanvas.height = applicationState.canvasHeightPx * applicationState.devicePixelRatio; // Canvas 物理像素高
|
||||
mapCanvas.style.width = applicationState.canvasWidthPx + 'px'; // CSS 显示宽度
|
||||
@ -292,12 +295,25 @@ const bindEvent = () => {
|
||||
let activePointerId = null
|
||||
let lastPointerX = 0
|
||||
let lastPointerY = 0
|
||||
let pointerStartX = 0
|
||||
let pointerStartY = 0
|
||||
let hasDragged = false
|
||||
|
||||
const getCanvasPointerPosition = (pointerEvent) => {
|
||||
const canvasRect = mapCanvas.getBoundingClientRect()
|
||||
const scaleX = applicationState.canvasWidthPx / canvasRect.width
|
||||
const scaleY = applicationState.canvasHeightPx / canvasRect.height
|
||||
return {
|
||||
x: (pointerEvent.clientX - canvasRect.left) * scaleX,
|
||||
y: (pointerEvent.clientY - canvasRect.top) * scaleY
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer Events 同时支持鼠标、触控笔和 Pad 触摸。
|
||||
mapCanvas.addEventListener('pointermove', (pointerEvent) => {
|
||||
const canvasRect = mapCanvas.getBoundingClientRect(); // Canvas 在页面中的位置
|
||||
applicationState.mouseState.screenX = pointerEvent.clientX - canvasRect.left;
|
||||
applicationState.mouseState.screenY = pointerEvent.clientY - canvasRect.top;
|
||||
const pointerPosition = getCanvasPointerPosition(pointerEvent)
|
||||
applicationState.mouseState.screenX = pointerPosition.x;
|
||||
applicationState.mouseState.screenY = pointerPosition.y;
|
||||
// 反算世界坐标
|
||||
const worldPos = screenToWorld(applicationState.mouseState.screenX, applicationState.mouseState.screenY, applicationState);
|
||||
applicationState.mouseState.worldX = worldPos.x;
|
||||
@ -305,12 +321,15 @@ const bindEvent = () => {
|
||||
|
||||
if (applicationState.mouseState.isDragging && pointerEvent.pointerId === activePointerId) {
|
||||
pointerEvent.preventDefault()
|
||||
const movementX = pointerEvent.clientX - lastPointerX
|
||||
const movementY = pointerEvent.clientY - lastPointerY
|
||||
const movementX = pointerPosition.x - lastPointerX
|
||||
const movementY = pointerPosition.y - lastPointerY
|
||||
if (Math.hypot(pointerPosition.x - pointerStartX, pointerPosition.y - pointerStartY) > 6) {
|
||||
hasDragged = true
|
||||
}
|
||||
applicationState.camera.centerX -= movementX / applicationState.camera.pixelsPerMeter;
|
||||
applicationState.camera.centerY += movementY / applicationState.camera.pixelsPerMeter;
|
||||
lastPointerX = pointerEvent.clientX
|
||||
lastPointerY = pointerEvent.clientY
|
||||
lastPointerX = pointerPosition.x
|
||||
lastPointerY = pointerPosition.y
|
||||
}
|
||||
|
||||
if (pointerEvent.pointerType === 'mouse') {
|
||||
@ -319,9 +338,7 @@ const bindEvent = () => {
|
||||
});
|
||||
|
||||
mapCanvas.addEventListener('click', (mouseEvent) => {
|
||||
const canvasRect = mapCanvas.getBoundingClientRect(); // Canvas 在页面中的位置
|
||||
const screenX = mouseEvent.clientX - canvasRect.left; // 鼠标在 Canvas 上的 X
|
||||
const screenY = mouseEvent.clientY - canvasRect.top; // 鼠标在 Canvas 上的 Y
|
||||
const { x: screenX, y: screenY } = getCanvasPointerPosition(mouseEvent)
|
||||
const worldPos = screenToWorld(screenX, screenY, applicationState);
|
||||
})
|
||||
|
||||
@ -331,15 +348,33 @@ const bindEvent = () => {
|
||||
return
|
||||
}
|
||||
pointerEvent.preventDefault()
|
||||
const pointerPosition = getCanvasPointerPosition(pointerEvent)
|
||||
activePointerId = pointerEvent.pointerId
|
||||
lastPointerX = pointerEvent.clientX
|
||||
lastPointerY = pointerEvent.clientY
|
||||
lastPointerX = pointerPosition.x
|
||||
lastPointerY = pointerPosition.y
|
||||
pointerStartX = pointerPosition.x
|
||||
pointerStartY = pointerPosition.y
|
||||
hasDragged = false
|
||||
applicationState.mouseState.isDragging = true;
|
||||
mapCanvas.setPointerCapture(pointerEvent.pointerId)
|
||||
});
|
||||
|
||||
const endPointerDrag = (pointerEvent) => {
|
||||
const endPointerDrag = (pointerEvent, cancelled = false) => {
|
||||
if (pointerEvent.pointerId !== activePointerId) return
|
||||
|
||||
// Pad/触控笔轻点时执行命中检测;轻点空白区域会隐藏信息窗。
|
||||
if (!cancelled && !hasDragged && pointerEvent.pointerType !== 'mouse') {
|
||||
const pointerPosition = getCanvasPointerPosition(pointerEvent)
|
||||
applicationState.mouseState.screenX = pointerPosition.x
|
||||
applicationState.mouseState.screenY = pointerPosition.y
|
||||
const worldPos = screenToWorld(
|
||||
applicationState.mouseState.screenX,
|
||||
applicationState.mouseState.screenY,
|
||||
applicationState
|
||||
)
|
||||
updateTooltipDisplay(hitTestRobots(worldPos.x, worldPos.y, applicationState))
|
||||
}
|
||||
|
||||
applicationState.mouseState.isDragging = false;
|
||||
if (mapCanvas.hasPointerCapture(pointerEvent.pointerId)) {
|
||||
mapCanvas.releasePointerCapture(pointerEvent.pointerId)
|
||||
@ -347,8 +382,8 @@ const bindEvent = () => {
|
||||
activePointerId = null
|
||||
}
|
||||
|
||||
mapCanvas.addEventListener('pointerup', endPointerDrag);
|
||||
mapCanvas.addEventListener('pointercancel', endPointerDrag);
|
||||
mapCanvas.addEventListener('pointerup', (pointerEvent) => endPointerDrag(pointerEvent));
|
||||
mapCanvas.addEventListener('pointercancel', (pointerEvent) => endPointerDrag(pointerEvent, true));
|
||||
|
||||
// ── 滚轮:缩放(向鼠标位置缩放)──
|
||||
mapCanvas.addEventListener('wheel', (wheelEvent) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user