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

请求Canvas鼠标拖动已绘制直线并获取新坐标的示例代码

Canvas直线拖动功能实现

下面是实现鼠标拖动Canvas直线并在拖动完成后输出新坐标的完整代码:

<canvas id="graph" width="200" height="200" style="border:1px solid #ccc;"></canvas>
<script>
    const canvas = document.getElementById('graph');
    const ctx = canvas.getContext('2d');
    
    // 存储直线的起点和终点坐标
    let line = {
        start: { x: 50, y: 100 },
        end: { x: 150, y: 100 }
    };
    
    let isDragging = false;
    let dragOffset = { x: 0, y: 0 };
    
    // 绘制直线的函数
    function drawLine() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.beginPath();
        ctx.moveTo(line.start.x, line.start.y);
        ctx.lineTo(line.end.x, line.end.y);
        ctx.stroke();
    }
    
    // 判断点是否在直线附近(容错范围5px)
    function isPointNearLine(mouseX, mouseY) {
        const { start, end } = line;
        // 计算点到直线的距离
        const numerator = Math.abs(
            (end.y - start.y) * mouseX - (end.x - start.x) * mouseY + end.x * start.y - end.y * start.x
        );
        const denominator = Math.sqrt(Math.pow(end.y - start.y, 2) + Math.pow(end.x - start.x, 2));
        const distance = numerator / denominator;
        
        // 同时判断点是否在直线的 bounding box 内
        const minX = Math.min(start.x, end.x);
        const maxX = Math.max(start.x, end.x);
        const minY = Math.min(start.y, end.y);
        const maxY = Math.max(start.y, end.y);
        
        return distance <= 5 && mouseX >= minX - 5 && mouseX <= maxX + 5 && mouseY >= minY -5 && mouseY <= maxY +5;
    }
    
    // 获取鼠标在Canvas内的坐标
    function getMousePos(e) {
        const rect = canvas.getBoundingClientRect();
        return {
            x: e.clientX - rect.left,
            y: e.clientY - rect.top
        };
    }
    
    canvas.addEventListener('mousedown', (e) => {
        const mousePos = getMousePos(e);
        if (isPointNearLine(mousePos.x, mousePos.y)) {
            isDragging = true;
            // 计算鼠标相对于直线中点的偏移
            const midX = (line.start.x + line.end.x) / 2;
            const midY = (line.start.y + line.end.y) / 2;
            dragOffset.x = mousePos.x - midX;
            dragOffset.y = mousePos.y - midY;
        }
    });
    
    canvas.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        const mousePos = getMousePos(e);
        // 根据偏移更新直线的起点和终点
        const midX = mousePos.x - dragOffset.x;
        const midY = mousePos.y - dragOffset.y;
        const lineLength = Math.sqrt(Math.pow(line.end.x - line.start.x, 2) + Math.pow(line.end.y - line.start.y, 2));
        const angle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
        
        line.start.x = midX - (lineLength / 2) * Math.cos(angle);
        line.start.y = midY - (lineLength / 2) * Math.sin(angle);
        line.end.x = midX + (lineLength / 2) * Math.cos(angle);
        line.end.y = midY + (lineLength / 2) * Math.sin(angle);
        
        drawLine();
    });
    
    canvas.addEventListener('mouseup', () => {
        if (isDragging) {
            isDragging = false;
            // 输出新坐标到控制台
            console.log('直线新坐标:');
            console.log('起点:', line.start);
            console.log('终点:', line.end);
        }
    });
    
    // 初始绘制直线
    drawLine();
</script>

关键功能说明

  • 直线坐标存储:用line对象保存直线的起点和终点,方便后续更新。
  • 拖动检测:isPointNearLine函数通过计算点到直线的距离,设置5px的容错范围,让用户更容易选中直线。
  • 鼠标事件处理:
    • mousedown:检测是否点击直线,记录拖动偏移量,开启拖动状态。
    • mousemove:拖动状态下,根据鼠标位置更新直线坐标,保持直线长度不变,并重绘。
    • mouseup:结束拖动,输出新坐标到控制台。
  • 重绘机制:每次拖动时先清空Canvas,再绘制更新后的直线,避免残留旧图形。

内容的提问来源于stack exchange,提问作者mcigorli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:13:14