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

如何在Canvas对象与鼠标位置不同时实现鼠标拖动同步移动?

实现Canvas圆形的拖动功能(保持点击时的相对距离)

核心思路

要实现这个需求,我们需要通过监听鼠标的三个关键事件来控制圆形的拖动逻辑:

  • mousedown:记录点击瞬间的鼠标位置、圆心位置,计算两者的偏移量(这是保持相对距离的关键),并标记开始拖动状态
  • mousemove:如果处于拖动状态,根据当前鼠标位置和之前的偏移量,实时更新圆心坐标并重新绘制圆形
  • mouseup:结束拖动状态

同时要处理Canvas全屏显示的问题,以及窗口大小变化时的适配。

完整代码实现

<!DOCTYPE html>
<html>
<head>
    <style>
        /* 去掉页面边距,让Canvas占满全屏 */
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="dragCanvas"></canvas>

    <script>
        const canvas = document.getElementById('dragCanvas');
        const ctx = canvas.getContext('2d');

        // 设置Canvas全屏
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            // 窗口大小变化后重新绘制圆形
            drawCircle();
        }
        resizeCanvas();
        window.addEventListener('resize', resizeCanvas);

        // 初始圆心位置
        let circleX = 500;
        let circleY = 500;
        const circleRadius = 30; // 圆形半径,可调整

        // 拖动状态变量
        let isDragging = false;
        let offsetX, offsetY;

        // 绘制圆形的函数
        function drawCircle() {
            // 清空画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // 绘制圆形
            ctx.beginPath();
            ctx.arc(circleX, circleY, circleRadius, 0, Math.PI * 2);
            ctx.fillStyle = '#2ecc71';
            ctx.fill();
            ctx.strokeStyle = '#27ae60';
            ctx.lineWidth = 2;
            ctx.stroke();
        }

        // 监听鼠标按下事件
        canvas.addEventListener('mousedown', (e) => {
            // 获取鼠标相对于Canvas的坐标(排除页面滚动等影响)
            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            // 计算鼠标与圆心的偏移量(点击时的相对位置)
            offsetX = mouseX - circleX;
            offsetY = mouseY - circleY;

            // 标记开始拖动
            isDragging = true;
        });

        // 监听鼠标移动事件
        canvas.addEventListener('mousemove', (e) => {
            if (!isDragging) return;

            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            // 根据偏移量更新圆心位置,保持点击时的相对距离
            circleX = mouseX - offsetX;
            circleY = mouseY - offsetY;

            // 重新绘制圆形
            drawCircle();
        });

        // 监听鼠标松开事件
        canvas.addEventListener('mouseup', () => {
            isDragging = false;
        });

        // 初始绘制圆形
        drawCircle();
    </script>
</body>
</html>

代码说明

  1. 全屏Canvas设置:通过CSS去掉页面边距,JS监听resize事件动态调整Canvas尺寸,确保始终占满窗口
  2. 拖动逻辑:
    • 按下鼠标时,计算鼠标与圆心的偏移量offsetX和offsetY,这个值在拖动过程中保持不变,保证圆形和鼠标的相对距离一致
    • 拖动过程中,用当前鼠标位置减去偏移量,得到新的圆心坐标,再重新绘制圆形
    • 松开鼠标后,取消拖动状态,停止更新位置
  3. 坐标计算:使用getBoundingClientRect()获取Canvas的位置,确保鼠标坐标是相对于Canvas的,避免页面滚动或边框导致的坐标偏差

内容的提问来源于stack exchange,提问作者Péter Vatler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:25:19