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

如何避免HTML5 Canvas中随机生成的坐标出现重叠问题

解决方法

你当前的场景只需要生成少量文本,最直接高效的方案是增加已生成坐标的距离校验逻辑,步骤如下:

  1. 新增数组存储已生成文本的坐标、宽高信息
  2. 每次生成符合三角形边界要求的新坐标后,校验该坐标和所有已存储坐标的间距是否大于预设的最小安全距离
  3. 校验通过后再绘制文本,同时把当前文本的信息存入数组

你可以直接使用修改后的代码:

JS代码

function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

function area(x1, y1, x2, y2, x3, y3) {
  return Math.abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0);
}

function isInside(x1, y1, x2, y2, x3, y3, x, y) {
  let A = area(x1, y1, x2, y2, x3, y3);
  let A1 = area(x, y, x2, y2, x3, y3);
  let A2 = area(x1, y1, x, y, x3, y3);
  let A3 = area(x1, y1, x2, y2, x, y);
  return (A == A1 + A2 + A3);
}

// 新增:校验新坐标和已有文本是否重叠
function checkOverlap(newText, existingTexts, minGapX = 8, minGapY = 4) {
  for (let text of existingTexts) {
    // 横向重叠判断:两个文本的水平区间有交集
    const xOverlap = !(newText.x + newText.width + minGapX < text.x || text.x + text.width + minGapX < newText.x)
    // 纵向重叠判断:两个文本的垂直区间有交集
    const yOverlap = !(newText.y - newText.height + minGapY < text.y || text.y - text.height + minGapY < newText.y)
    if (xOverlap && yOverlap) return true
  }
  return false
}

let canvas = document.querySelector('canvas')
const CANVAS_SIZE = 300
canvas.width = CANVAS_SIZE
canvas.height = CANVAS_SIZE
const ctx = canvas.getContext('2d');
let arrayOfText = ['A', 'B', 'C', 'D']
// 新增:存储已生成的文本信息
let placedTexts = []
// 字体大小固定,提前算文本高度(行高一般是字体大小的1.1-1.2倍)
const FONT_SIZE = 14
const TEXT_HEIGHT = FONT_SIZE * 1.2

ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(225, 25);
ctx.lineTo(225, 225);
ctx.lineTo(25, 25);
ctx.strokeStyle = "#bb0874"
ctx.stroke()

ctx.font = `600 ${FONT_SIZE}px Arial`;

for (let i = 0; i < arrayOfText.length; i++) {
  const currentText = arrayOfText[i]
  // 先算当前文本的宽度
  const textWidth = ctx.measureText(currentText).width
  while (true) {
    let x = randomIntFromInterval(40, 180)
    let y = randomIntFromInterval(15, 160)
    if (isInside(25, 25, 225, 25, 225, 225, x, y)) {
      const newTextInfo = {
        x: x,
        y: y,
        width: textWidth,
        height: TEXT_HEIGHT
      }
      // 校验和已有文本是否重叠
      if (!checkOverlap(newTextInfo, placedTexts)) {
        ctx.fillText(currentText, x, y);
        placedTexts.push(newTextInfo)
        break;
      }
    }
  }
}

CSS代码

canvas {
  border: 1px solid black;
}

HTML代码

<body>
  <canvas></canvas>
</body>

如果后续需要生成数十个以上的文本,可改用网格预划分方案:将三角形区域按最小文本宽高划分为网格,提前标记所有落在三角形内的网格,每次随机抽取未使用的网格放置文本,不需要反复做重叠校验,性能更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 15:24:02