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

如何用SVG绘制与大六边形各边对齐的每组16个小六边形?

六边形布局问题修复方案

问题概述

尝试绘制一个大六边形,内部放置96个小六边形(6组,每组16个,与大六边形各边对齐),要求大六边形与小六边形间有1px间距,小六边形间也有小间距,但当前布局存在对齐错误,大六边形边线会穿过小六边形。

现有代码

JavaScript

const PADDING = 4;
const HEX_SIZE = 9 - PADDING; // 用内边距值减小六边形尺寸
const sqrt3 = Math.sqrt(3);

function createHexagon(x, y, radius) {
  const points = [];
  for (let i = 0; i < 6; i++) {
    const angle = 2 * Math.PI / 6 * i;
    const pointX = x + radius * Math.cos(angle);
    const pointY = y + radius * Math.sin(angle);
    points.push([pointX, pointY]);
  }
  return points;
}

const svg = d3.select('#hexagonSVG');

function createHexagonLine(startX, startY, angle, count) {
  // 绘制参考线
  svg.append('line')
    .attr('x1', startX)
    .attr('y1', startY)
    .attr('x2', startX + (sqrt3 * HEX_SIZE + PADDING) * count * Math.cos(angle))
    .attr('y2', startY + (sqrt3 * HEX_SIZE + PADDING) * count * Math.sin(angle))
    .attr('stroke', 'black')
    .attr('stroke-width', 1);

  for (let i = 0; i < count; i++) {
    const x = startX + (sqrt3 * HEX_SIZE + PADDING) * i * Math.cos(angle);
    const y = startY + (sqrt3 * HEX_SIZE + PADDING) * i * Math.sin(angle);
    const hexagonPoints = createHexagon(x, y, HEX_SIZE);
    svg.append('polygon')
      .attr('points', hexagonPoints.join(' '))
      .attr('class', 'small');
  }
  return [startX + (sqrt3 * HEX_SIZE + PADDING) * 16 * Math.cos(angle), startY + (sqrt3 * HEX_SIZE + PADDING) * 16 * Math.sin(angle)]
}

l = createHexagonLine(260, 140 + 2 * HEX_SIZE, 0, 16)
x = l[0]
y = l[1]
for (let i = 1; i < 6; i++) {
  const angle = 2 * Math.PI / 6 * i;
  l = createHexagonLine(x, y + 2 * HEX_SIZE, angle, 16);
  x = l[0]
  y = l[1]
}

CSS

svg {
  background: #ddd;
}

.small {
  fill: #666;
  stroke: #333;
  stroke-width: 1px;
}

HTML

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="hexagonSVG" width="800" height="800"></svg>

当前错误效果

当前错误的六边形布局

问题原因与修复

关键问题点

  1. 间距计算错误:正六边形相邻中心的横向间距应为2 * HEX_SIZE + PADDING,纵向(斜向)间距应为sqrt(3) * HEX_SIZE + PADDING,原代码混用了这两个值。
  2. 起始位置与角度偏移错误:每组小六边形的起始点没有根据大六边形的边正确偏移,导致对齐失效。
  3. 大六边形未适配小六边形布局:原代码未绘制正确尺寸的大六边形,且未考虑与小六边形的间距。

修正后的代码

JavaScript

const PADDING = 1; // 小六边形间及与大六边形的间距
const HEX_SIZE = 9; // 小六边形的外接圆半径
const sqrt3 = Math.sqrt(3);
const GROUP_COUNT = 16; // 每组小六边形数量

function createHexagon(x, y, radius) {
  const points = [];
  // 调整起始角度为-60度,让六边形的边与坐标轴对齐(方便布局)
  for (let i = 0; i < 6; i++) {
    const angle = (2 * Math.PI / 6 * i) - Math.PI / 3;
    const pointX = x + radius * Math.cos(angle);
    const pointY = y + radius * Math.sin(angle);
    points.push([pointX, pointY]);
  }
  return points;
}

const svg = d3.select('#hexagonSVG');
const centerX = 400;
const centerY = 400;

// 计算大六边形的半径:小六边形组的总长度 + 间距 + 小六边形半径
const bigHexRadius = (GROUP_COUNT * (2 * HEX_SIZE + PADDING)) / 2 + HEX_SIZE + PADDING;
// 绘制大六边形
const bigHexPoints = createHexagon(centerX, centerY, bigHexRadius);
svg.append('polygon')
  .attr('points', bigHexPoints.join(' '))
  .attr('fill', 'none')
  .attr('stroke', 'black')
  .attr('stroke-width', 1);

// 生成6组小六边形,每组对应大六边形的一条边
for (let edge = 0; edge < 6; edge++) {
  // 每组的起始角度:对应大六边形边的中点方向
  const baseAngle = (2 * Math.PI / 6 * edge) - Math.PI / 3;
  // 起始点:大六边形内侧,距离大六边形边PADDING + HEX_SIZE的位置
  const startX = centerX + (bigHexRadius - HEX_SIZE - PADDING) * Math.cos(baseAngle);
  const startY = centerY + (bigHexRadius - HEX_SIZE - PADDING) * Math.sin(baseAngle);
  // 每组小六边形排列的方向:与大六边形当前边平行的方向
  const lineAngle = baseAngle + Math.PI / 2;

  for (let i = 0; i < GROUP_COUNT; i++) {
    // 计算每个小六边形的中心位置
    const offset = i * (2 * HEX_SIZE + PADDING);
    const x = startX + offset * Math.cos(lineAngle);
    const y = startY + offset * Math.sin(lineAngle);
    const hexPoints = createHexagon(x, y, HEX_SIZE);
    svg.append('polygon')
      .attr('points', hexPoints.join(' '))
      .attr('class', 'small');
  }
}

CSS(保持不变)

svg {
  background: #ddd;
}

.small {
  fill: #666;
  stroke: #333;
  stroke-width: 1px;
}

HTML(保持不变)

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="hexagonSVG" width="800" height="800"></svg>

修复说明

  1. 调整六边形绘制角度:将六边形的起始角度设为-60度,让其边与坐标轴平行,简化布局计算。
  2. 正确计算间距:横向(平行于边)的小六边形中心间距为2 * HEX_SIZE + PADDING,确保小六边形间的间距一致。
  3. 大六边形尺寸适配:根据小六边形组的总长度、间距和小六边形半径,计算出大六边形的半径,确保大六边形在小六边形外侧,间距符合要求。
  4. 分组起始位置校准:每组小六边形的起始点位于大六边形内侧,与大六边形边保持PADDING + HEX_SIZE的距离,排列方向与对应大六边形边平行,完美对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:37:05