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

Canvas网格鼠标高亮异常:红色方块远离原点后尺寸变大

Canvas网格鼠标悬停高亮方块异常放大问题解决

核心问题分析

你的代码里有三个关键错误导致方块随远离原点变大:

  • ctx.rect()参数误用:Canvas的rect(x, y, width, height)方法后两个参数是方块的宽高,不是结束坐标。你错误地传入了tileEndx和tileEndy(即结束位置),导致越往后的方块宽高越大(比如第n个格子的宽高会是32*(n+1))。
  • 重复绑定鼠标事件:每次draw()执行都绑定mousemove事件,会导致事件监听叠加,鼠标移动时多次触发坐标赋值,可能引发异常。
  • 鼠标坐标未相对Canvas:使用clientX/clientY会受Canvas在页面中的位置影响,应该用offsetX/offsetY获取相对Canvas的坐标。

修复后的代码

JavaScript部分

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

const TILE_SIZE = 32;
var xtiles = Math.floor(canvas.width / TILE_SIZE);
var ytiles = Math.floor(canvas.height / TILE_SIZE);

var posX = 0;
var posY = 0;

// 只绑定一次鼠标移动事件
canvas.addEventListener('mousemove', (event) => {
  // 获取相对于Canvas的坐标
  posX = event.offsetX;
  posY = event.offsetY;
});

function drawTiles() {
  // 绘制灰色网格
  for (let y = 0; y < ytiles; y++) {
    for (let x = 0; x < xtiles; x++) {
      const tileX = x * TILE_SIZE;
      const tileY = y * TILE_SIZE;
      ctx.beginPath();
      ctx.rect(tileX, tileY, TILE_SIZE, TILE_SIZE);
      ctx.fillStyle = "grey";
      ctx.fill();
      ctx.stroke();
      ctx.closePath();
    }
  }

  // 计算高亮方块的位置
  const highlightX = Math.floor(posX / TILE_SIZE) * TILE_SIZE;
  const highlightY = Math.floor(posY / TILE_SIZE) * TILE_SIZE;

  // 绘制红色高亮方块
  ctx.beginPath();
  ctx.rect(highlightX, highlightY, TILE_SIZE, TILE_SIZE);
  ctx.fillStyle = "red";
  ctx.fill();
  ctx.stroke();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawTiles();
}

setInterval(draw, 100);

HTML部分

<canvas id="myCanvas" width="480" height="320"></canvas>

额外优化点

  • 用常量TILE_SIZE统一管理格子大小,方便后续修改
  • 简化网格绘制循环,直接通过索引计算格子位置,避免维护start/end变量
  • 初始给posX/posY赋值,避免首次绘制时的undefined问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:35:08