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