You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

mousemove事件随鼠标拖拽方向表现异常?Canvas矩形绘制问题

问题分析与解决方案

核心问题有两个,直接导致了拖拽方向异常:

  1. 坐标系统不一致
    你在mousedown事件中用clientX - canvas1.getBoundingClientRect().left计算的是相对于Canvas元素的鼠标坐标,但mousemove里却用了pageX(相对于文档的坐标),当页面滚动时两者会产生偏差,且本身不属于同一坐标系,直接导致宽高计算错误。

  2. 宽高为负数时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:02:52