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

如何使用translate方法实现可拖拽Canvas?上下拖拽失效求助

问题描述

想要实现类似Google Maps的游戏地图拖拽效果,但当前代码仅能左右拖拽,无法上下拖拽,需要简单易懂的解决方案。

原尝试代码

JavaScript

const canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');

const drawRects = () => {
  ctx.fillStyle = 'red';
  ctx.fillRect(0, 0, 1000, 1000);
  
  ctx.fillStyle = 'aqua';
  ctx.fillRect(1000, 1000, 1000, 1000);
  
  ctx.fillStyle = 'green';
  ctx.fillRect(0, 1000, 1000, 1000);
  
  ctx.fillStyle = 'magenta';
  ctx.fillRect(1000, 0, 1000, 1000);
}


const mouse = {
  isDown: false,
  isUp: false,
  isPressed: false,
  x: 0,
  y: 0
}

const pos = {
  x: 0,
  y: 0
}


function tick() {
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  
  canvas.width += 0;
  
  if(mouse.isPressed){
    ctx.translate(mouse.x - pos.x, mouse.y - pos.y)
  }
  
  drawRects()
  
  requestAnimationFrame(tick)
}

canvas.addEventListener('mousedown', e => {
  pos.x = e.offsetX;
  pos.y = e.offsetY;
  
  mouse.isDown = true;
  mouse.isUp = false;
  mouse.isPressed = true;
})

canvas.addEventListener('mousemove', e => {
  if(!mouse.isDown) return;
  
  mouse.x = e.offsetX;
  mouse.y = e.offsetY;
})

canvas.addEventListener('mouseup', e => {
  mouse.isDown = false;
  mouse.isUp = true;
})


tick()

CSS

body{
  margin: 0;
}

HTML

<canvas></canvas>
解决方案

问题根源

  1. 错误的清屏方式:使用canvas.width += 0会重置画布的所有状态(包括Y轴相关的变换),直接导致上下拖拽失效;
  2. 拖拽逻辑缺陷:没有累积画布的偏移量,且鼠标松开后未重置mouse.isPressed,导致拖拽逻辑混乱。

修改后的代码

const canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');

// 记录画布的累积偏移量
const offset = { x: 0, y: 0 };
// 记录鼠标按下时的初始位置
const startMouse = { x: 0, y: 0 };

const drawRects = () => {
  ctx.fillStyle = 'red';
  ctx.fillRect(0, 0, 1000, 1000);
  
  ctx.fillStyle = 'aqua';
  ctx.fillRect(1000, 1000, 1000, 1000);
  
  ctx.fillStyle = 'green';
  ctx.fillRect(0, 1000, 1000, 1000);
  
  ctx.fillStyle = 'magenta';
  ctx.fillRect(1000, 0, 1000, 1000);
}

function tick() {
  // 重置变换并正确清屏
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 应用累积的偏移量
  ctx.translate(offset.x, offset.y);
  
  drawRects();
  
  requestAnimationFrame(tick);
}

canvas.addEventListener('mousedown', e => {
  // 记录鼠标按下时的位置
  startMouse.x = e.offsetX;
  startMouse.y = e.offsetY;
});

canvas.addEventListener('mousemove', e => {
  if (!e.buttons) return; // 仅当鼠标左键按下时响应
  
  // 计算鼠标移动差值,更新画布偏移
  offset.x += e.offsetX - startMouse.x;
  offset.y += e.offsetY - startMouse.y;
  
  // 更新鼠标初始位置,确保后续移动计算准确
  startMouse.x = e.offsetX;
  startMouse.y = e.offsetY;
});

tick();

关键修改点

  • 用ctx.clearRect(0, 0, canvas.width, canvas.height)替代canvas.width += 0,正确清屏且不破坏画布状态;
  • 新增offset对象记录画布的累积偏移量,实现连贯的拖拽效果;
  • 使用e.buttons判断鼠标按下状态,简化状态管理;
  • 鼠标移动时实时更新累积偏移量,确保XY轴拖拽逻辑一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:35:46