适配devicePixelRatio后,如何正确捕获Canvas的鼠标/触摸位置?
修正Canvas适配DPR后的坐标捕获问题
当你通过window.devicePixelRatio放大Canvas的实际像素尺寸后,DOM元素的显示尺寸(用户视觉上的大小)和Canvas内部的像素缓冲区尺寸已不匹配,直接用触摸/鼠标位置计算会出现偏移。需要做两步核心修正:
1. 同步Canvas的实际像素尺寸与显示尺寸
设置Canvas的width/height(实际像素缓冲区大小)时,必须同时指定CSS显示尺寸,避免浏览器自动拉伸Canvas导致的坐标错位:
const canvas = canvasRef.current const context = canvas.getContext('2d') context.globalCompositeOperation = 'source-over' context.clearRect(0, 0, canvas.width, canvas.height) const image = new Image() image.src = backgroundImage image.onload = () => { onLoadCanvas() const devicePixelRatio = window.devicePixelRatio || 1 const displayWidth = window.innerWidth const displayHeight = window.innerHeight // 设置Canvas实际像素缓冲区大小(适配DPR) canvas.width = displayWidth * devicePixelRatio canvas.height = displayHeight * devicePixelRatio // 设置Canvas页面显示尺寸(与窗口一致) canvas.style.width = `${displayWidth}px` canvas.style.height = `${displayHeight}px` context.drawImage(image, 0, 0, canvas.width, canvas.height) }
2. 修正触摸/鼠标坐标映射逻辑
事件获取的位置是基于Canvas显示尺寸的,需要除以devicePixelRatio才能映射到Canvas内部的像素坐标:
const canvas = canvasRef.current const devicePixelRatio = window.devicePixelRatio || 1 const rect = canvas.getBoundingClientRect() let x, y if (isMobile) { x = (e.touches[0].pageX - rect.left) / devicePixelRatio y = (e.touches[0].pageY - rect.top) / devicePixelRatio } else { // 桌面端用clientX/clientY替代layerX,提升兼容性 x = (e.clientX - rect.left) / devicePixelRatio y = (e.clientY - rect.top) / devicePixelRatio }
关键说明:
canvas.width/canvas.height是Canvas的实际像素缓冲区大小,决定画面清晰度;canvas.style.width/canvas.style.height是Canvas在页面的显示尺寸,必须和窗口大小匹配;- 触摸/鼠标事件的坐标是基于显示尺寸的,必须通过
devicePixelRatio转换,才能对应到Canvas内部的绘制坐标。
内容的提问来源于stack exchange,提问作者Diego Cândido
相关产品推荐
相关产品推荐

