mousemove事件随鼠标拖拽方向表现异常?Canvas矩形绘制问题
问题分析与解决方案
核心问题有两个,直接导致了拖拽方向异常:
坐标系统不一致
你在mousedown事件中用clientX - canvas1.getBoundingClientRect().left计算的是相对于Canvas元素的鼠标坐标,但mousemove里却用了pageX(相对于文档的坐标),当页面滚动时两者会产生偏差,且本身不属于同一坐标系,直接导致宽高计算错误。宽高为负数时Canvas API不生效
当鼠标从下往上/从右往左拖拽时,rect.w或rect.h会变成负数。而Canvas的clearRect()和strokeRect()函数在宽高参数为负数时,不会执行任何绘制/清除操作——这就导致上一帧的矩形残留,形成你看到的"幽灵框"。
修改后的代码
关键调整点:
- 统一使用相对于Canvas的坐标计算鼠标位置
- 不管拖拽方向,计算矩形的实际起始点(取起始和当前坐标的最小值)与宽高(取差值的绝对值)
- 确保
clearRect()和strokeRect()的参数始终为正数
canvas1.addEventListener('mousedown', function(e) { var x = e.clientX - canvas1.getBoundingClientRect().left; var y = e.clientY - canvas1.getBoundingClientRect().top; if (rect.currentActiveBox == currentActiveBox) { console.log('clearing ', rect); ctx.clearRect(rect.startX - 6 , rect.startY - 6, rect.w + 8, rect.h + 8); } rect.startX = x; rect.startY = y; // 初始化宽高为0,避免首次绘制异常 rect.w = 0; rect.h = 0; isDrawing = true; rect.currentActiveBox = currentActiveBox; rects[currentActiveBox] = JSON.parse(JSON.stringify(rect)); }); canvas1.addEventListener('mousemove', function(e) { if(isDrawing === true) { // 统一获取相对于Canvas的当前鼠标坐标 const currentX = e.clientX - canvas1.getBoundingClientRect().left; const currentY = e.clientY - canvas1.getBoundingClientRect().top; // 计算兼容任意拖拽方向的矩形参数 const drawX = Math.min(rect.startX, currentX); const drawY = Math.min(rect.startY, currentY); const drawW = Math.abs(currentX - rect.startX); const drawH = Math.abs(currentY - rect.startY); // 清除上一帧的矩形(沿用原有的偏移量,避免边框残留) ctx.clearRect(rect.startX - 6, rect.startY - 6, rect.w + 8, rect.h + 8); // 更新rect对象的属性 rect.w = drawW; rect.h = drawH; // 若需保留鼠标按下时的原始起始点,可新增drawX/drawY属性存储绘制用坐标,不修改startX/startY // 绘制当前矩形 ctx.beginPath(); ctx.strokeStyle = "red"; ctx.lineWidth = 3; ctx.strokeRect(drawX, drawY, drawW, drawH); rects[currentActiveBox] = JSON.parse(JSON.stringify(rect)); } });
额外说明
- 原
mousedown事件未初始化rect.w和rect.h,补充后可避免首次绘制时出现异常值 - 如果需要区分鼠标按下的原始位置与矩形实际左上角,可新增独立属性存储绘制用坐标,不修改
rect.startX/rect.startY
内容的提问来源于stack exchange,提问作者E_K
相关产品推荐
相关产品推荐

