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

为何Canvas中fillText绘制的文本应当显示却无法展示/直接消失?

问题根因

你的绘制顺序完全颠倒了:先绘制了文本,之后才调用fillRect填充当前网格的底色,直接把刚绘制完成的文本完全覆盖。

  • 用减号计算textY时,文本位置落到了上一行的网格区域,当前网格的fillRect不会覆盖到上一行的内容,因此文本可以显示但整体向上偏移一个网格的位置
  • 用加号计算textY时,文本刚好落在当前网格内部,绘制完文本后马上被后续的fillRect色块覆盖,因此完全不可见
  • 长文本被截断的原因同理:超出当前网格范围的文本部分,会被相邻网格的fillRect色块覆盖

解决方案

1. 调整绘制顺序

把网格填充、边框绘制的逻辑移到文本绘制之前,保证文本渲染在最上层不会被覆盖。同时优化重复解析JSON的性能问题,修改后代码如下:

import { mapColorsToNumbers } from "./mapColorToNumber";

export const drawGame = (pixelArt, ctx) => {
  // 提前解析一次像素数据,避免重复parse消耗性能
  const pixelList = JSON.parse(pixelArt.pixels);
  const rectCount = pixelList.length;

  const canvasPixelsCount =
    pixelArt.pixelArtWidth * pixelArt.pixelArtHeight - 1000;

  const newRectSize = Math.sqrt(canvasPixelsCount / rectCount);
  const colorsWithCodes = mapColorsToNumbers(pixelList);
  
  pixelList.forEach((pixel) => {
    // 第一步:先填充网格底色
    if (pixel.pickedColor !== "white") {
      ctx.fillStyle = "grey";
    } else {
      ctx.fillStyle = "white";
    }
    ctx.fillRect(
      pixel.x * newRectSize,
      pixel.y * newRectSize,
      newRectSize,
      newRectSize
    );

    // 第二步:绘制网格边框
    ctx.strokeStyle = "white";
    ctx.strokeRect(
      pixel.x * newRectSize,
      pixel.y * newRectSize,
      newRectSize,
      newRectSize
    );

    // 第三步:最后绘制文本,保证在最上层
    ctx.fillStyle = "red";
    // 动态设置字体大小,适配网格尺寸,避免文本溢出
    ctx.font = `${Math.max(12, newRectSize * 0.6)}px serif`;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    const textX = pixel.x * newRectSize + newRectSize / 2;
    const textY = pixel.y * newRectSize + newRectSize / 2;
    ctx.fillText("1", textX, textY);
  });
};

2. 额外优化建议

如果还存在长文本溢出的情况,可以使用ctx.measureText()方法提前计算文本宽度,当文本宽度超过网格宽度时自动缩小字体,或者添加省略号处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:48:04