移动端带滚动时Canvas矩形控件绘制异常的修复方案咨询
修复Canvas滚动时绘制矩形控件的位置异常问题
我刚帮你排查了这个问题,核心原因是触摸/鼠标事件的坐标是基于当前视口的,而不是Canvas元素本身的坐标系——当页面滚动后,Canvas的左上角已经偏离了视口左上角,直接用clientX/clientY计算就会出现偏移错误。
解决思路
我们需要把事件的视口坐标转换为Canvas内部的坐标:
- 通过
getBoundingClientRect()获取Canvas相对于视口的实时偏移量(left和top) - 用事件的
clientX减去Canvas的left偏移,clientY减去top偏移,得到Canvas内部的正确坐标
修复后的完整代码
<html> <body> <canvas id="canvas_transparent" height="3000" width="1000" style="border: 1px solid black;"></canvas> </body> </html> <script type="text/javascript"> var canvas = document.getElementById("canvas_transparent"); var ctx = canvas.getContext("2d"); var isDrawing = false; var startX, startY, endX, endY; // 获取Canvas的实时偏移 function getCanvasOffset() { const rect = canvas.getBoundingClientRect(); return { left: rect.left + window.scrollX, top: rect.top + window.scrollY }; } // 处理触摸/鼠标按下事件 function startDraw(e) { e.preventDefault(); isDrawing = true; const offset = getCanvasOffset(); // 兼容鼠标和触摸事件 const x = e.clientX || e.touches[0].clientX; const y = e.clientY || e.touches[0].clientY; startX = x - offset.left; startY = y - offset.top; } // 处理触摸/鼠标移动事件 function draw(e) { if (!isDrawing) return; e.preventDefault(); const offset = getCanvasOffset(); const x = e.clientX || e.touches[0].clientX; const y = e.clientY || e.touches[0].clientY; endX = x - offset.left; endY = y - offset.top; // 清除画布并重新绘制当前矩形 ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.strokeRect(startX, startY, endX - startX, endY - startY); } // 处理触摸/鼠标松开事件 function endDraw() { isDrawing = false; } // 绑定事件(兼容鼠标和触摸) canvas.addEventListener("mousedown", startDraw); canvas.addEventListener("mousemove", draw); canvas.addEventListener("mouseup", endDraw); canvas.addEventListener("mouseleave", endDraw); canvas.addEventListener("touchstart", startDraw); canvas.addEventListener("touchmove", draw); canvas.addEventListener("touchend", endDraw); </script>
关键细节说明
getBoundingClientRect()的使用:这个方法会返回元素在视口中的位置,加上window.scrollX/scrollY能得到元素相对于文档的绝对偏移,确保滚动后坐标计算依然准确。- 兼容鼠标和触摸事件:移动端主要用触摸事件,所以同时绑定了鼠标和触摸事件,并且处理了触摸事件的
touches[0]来获取坐标。 - 实时偏移计算:每次事件触发时都重新获取偏移,避免因为滚动导致偏移量变化而出现错误。
你可以用Chrome的iPhone 6/7/8视图测试,先滚动页面到任意位置,再拖拽绘制矩形,现在控件的位置应该完全匹配你的拖拽轨迹了。
内容的提问来源于stack exchange,提问作者Zulqarnain Jalil
相关产品推荐
相关产品推荐

