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

如何在HTML/JavaScript中绘制居中六边形数点阵?

如何绘制居中六边形数对应的点阵

核心问题分析

需要绘制第18个居中六边形数的点阵(共919个点),要求适配指定尺寸的正方形画布,且点之间各方向间距满足最小要求(比如8px)。当前核心卡点是通过三角函数计算每个点的坐标,以及根据画布尺寸确定合适的点间距。

数学逻辑与坐标计算

正六边形的6条边对应6个固定方向,角度分别为0°、60°、120°、180°、240°、300°,转换成JS中Math.sin/Math.cos所需的弧度,对应0, π/3, 2π/3, π, 4π/3, 5π/3。

针对居中六边形点阵:

  1. 步长计算:设点半径为MIN_RADIUS,点间最小间隙为IDEAL_GAP,则相邻点的圆心间距至少为2 * MIN_RADIUS + IDEAL_GAP(记为MIN_STEP)。同时要确保整个六边形能放进画布:

    • 六边形总宽度 = 2 * MAX_DEPTH * 步长(最左到最右点的距离)
    • 六边形总高度 = MAX_DEPTH * 步长 * Math.sqrt(3)(正六边形高度为√3倍边长)
    • 取画布宽高中的较小值反推最大可用步长,再和MIN_STEP比较,取较小值作为最终步长STEP。
  2. 点坐标计算:

    • 中心坐标为画布中点:centerX = canvas.width / 2,centerY = canvas.height / 2,先绘制中心的1个点。
    • 每个深度d(从1到MAX_DEPTH)对应一个壳层,每条边有d个点,共6*d个点。通过三角函数计算每条边的顶点坐标,再用线性插值得到边上的中间点。

修正后的代码实现

const canvas = document.querySelector('#canvas')
const context = canvas.getContext('2d')
const canvasWidth = canvas.width
const canvasHeight = canvas.height

const MAX_DEPTH = 18
const MIN_RADIUS = 4
const IDEAL_GAP = 4
const MIN_STEP = 2 * MIN_RADIUS + IDEAL_GAP // 点之间的最小圆心间距

// 计算最大可用步长,确保六边形能完整放入画布
const maxStepByWidth = canvasWidth / (2 * MAX_DEPTH)
const maxStepByHeight = canvasHeight / (MAX_DEPTH * Math.sqrt(3))
const STEP = Math.min(maxStepByWidth, maxStepByHeight, MIN_STEP)

const COLOR = ['red', 'orange', 'yellow', 'green', 'blue', 'violet']
const centerX = canvasWidth / 2
const centerY = canvasHeight / 2

// 绘制中心的点
drawCircle({ cx: centerX, cy: centerY, r: MIN_RADIUS, depth: 0 })

// 绘制每个深度的壳层
for (let d = 1; d <= MAX_DEPTH; d++) {
  // 遍历6条边
  for (let side = 0; side < 6; side++) {
    // 当前边的起始/结束角度(弧度)
    const startAngle = side * Math.PI / 3
    const endAngle = (side + 1) * Math.PI / 3

    // 计算当前边的两个端点坐标(深度d的顶点)
    const startX = centerX + d * STEP * Math.cos(startAngle)
    const startY = centerY + d * STEP * Math.sin(startAngle)
    const endX = centerX + d * STEP * Math.cos(endAngle)
    const endY = centerY + d * STEP * Math.sin(endAngle)

    // 绘制这条边上的d个点(含起始端点,不含结束端点,避免重复)
    for (let i = 0; i < d; i++) {
      // 线性插值计算点坐标
      const ratio = d === 1 ? 0 : i / (d - 1)
      const cx = startX + (endX - startX) * ratio
      const cy = startY + (endY - startY) * ratio
      drawCircle({ cx, cy, r: MIN_RADIUS, depth: d })
    }
  }
}

function drawCircle({ cx, cy, r, depth }) {
  context.beginPath()
  context.arc(cx, cy, r, 0, 2 * Math.PI, false)
  context.fillStyle = COLOR[(depth - 1) % COLOR.length] ?? 'black'
  context.fill()
}
<h1>Canvas below</h1>
<canvas id="canvas" width="800" height="800"></canvas>
<h1>Canvas above</h1>

代码说明

  1. 步长计算:优先保证点间距满足最小要求,同时确保六边形能完整放入画布,取两者中的较小值作为最终步长。
  2. 中心绘制:先绘制最中心的1个点,对应居中六边形数的起始点。
  3. 壳层绘制:
    • 对每个深度d,遍历6条边,每条边对应60°的角度区间。
    • 通过线性插值计算每条边上的d个点,避免顶点重复绘制(每条边只包含起始端点,结束端点由下一条边绘制)。
    • 用三角函数计算顶点坐标,再通过比例插值得到边上的中间点。

拓展到其他多边形/星形数的思路

  • 中心多边形数:比如中心五边形、七边形,只需改变边数m,角度间隔改为2π/m,每个深度d的壳层点数为m*d,按同样的线性插值逻辑绘制。
  • 多边形数:这类数从单个顶点向外扩展,需根据不同类型调整坐标逻辑(比如三角形数按行绘制,正方形数按网格排列),核心是找到点阵的排列规律再做坐标转换。
  • 星形数:先确定星形的角度间隔(比如五角星为72°),再计算顶点和边上点的坐标,本质仍是三角函数的应用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:10:04