js实现 沃罗诺伊图(Voronoi Diagram)

首先看效果。

沃洛伊图效果

前提代码:

  // 主要是用于确保 canvas 元素存在 且能获取到 canvas 渲染上下文
  const canvas = document.getElementsByTagName('canvas')[0] || document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  // 画布大小
  const size = 900
  canvas.height = size
  canvas.width = size
  if (document.getElementsByTagName('canvas'[0])) {
    document.body.append(canvas)
  }
  canvas.style.boxShadow = '0 0 .5rem 0 gray'

  // 获取颜色
  const getColor = () => {
    let color = ''
    for (let i = 0; i < 6; i++) color += Math.floor(Math.random() * 16).toString(16)
    return '#' + color
  }
  /**
   * 判断距离
   * @param { [number,number]} point1 点位一
   * @param { [number,number]} point2 点位二
   * @returns 两点之间的距离
   */
  const judgeDistance = (point1, point2) => Math.sqrt(Math.pow(point1[0] - point2[0], 2) + Math.pow(point1[1] - point2[1], 2))

  /**
   * 生成随机点位
   * @param { number } width 最大宽度 即 x 轴
   * @param { number } height 最大高度 即 y 轴
   * @returns
   */
  const randomPoint = (width, height) => [Math.floor(Math.random() * width) + 1, Math.floor(Math.random() * height) + 1]

我的理解就是先生成随机 n 个 key 点,然后根据这些点进行划分图形。

  // 随机的点数量
  const keyPointNum = 30
  // 保存点位代表的颜色 Map<number,string>
  const color = new Map()
  // 点坐标 [x,y][]
  const keyPoint = []
  // 循环生成指定数量的 key 点 并同时生成该 key 点代表的颜色
  for (let i = 0; i < keyPointNum; i++) {
    const [x, y] = randomPoint(size, size)
    keyPoint.push(`${x},${y}`)
    color.set(i, getColor())
  }

然后就是划分区域了。

// 这边的思路就是从 0,0 到 width,height 一个一个的坐标去判断
// 找到和生成的 key 点距离最近的那一个
// 找到后就将这个坐标的颜色变成该 key 点的颜色
for (let i = 0; i < size; i++) {
    for (let j = 0; j < size; j++) {
      // 最近的点索引
      let near = -1
      // 最小距离
      let min = -1
      for (let k = 0; k < keyPoint.length; k++) {
        const [_x, _y] = keyPoint[k].split(',')
        const [x, y] = [Number(_x), Number(_y)]
        const distance = judgeDistance([i, j], [x, y])
        // 初次赋值
        if (min < 0) min = distance
        // 判断距离是否是最小的
        if (min > distance) {
          min = distance
          near = k
        }
      }
      ctx.beginPath()
      ctx.fillStyle = color.get(near)
      ctx.fillRect(i, j, 1, 1)
      ctx.closePath()
    }
  }

js实现 沃罗诺伊图(Voronoi Diagram)
http://localhost:8080/archives/3c98657d-01ea-4afb-a6fd-74f6a56b881e
作者
inksha
发布于
2024年09月14日
许可协议