资讯详情

如何用 d3-delaunay 为点集生成 Voronoi 图?

📅 2026/9/13 19:32:14 | 华诺云谱 👁 阅读
如何用 d3-delaunay 为点集生成 Voronoi 图?
如何用 d3-delaunay 为点集生成 Voronoi 图【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3手头有一组二维点需要把平面划分成“离哪个点最近”的若干区域——这就是 d3-delaunay 要解决的 Voronoi 图问题。d3-delaunay 基于 Delaunay 三角剖分计算 Voronoi 图每个单元表示平面上离对应点最近的区域图本身由三角剖分中相邻三角形的外心相连构成见 d3-delaunay 概述。D3 可运行在任何 JavaScript 环境d3-delaunay 包含在d3主包中仓库 package.json 声明依赖d3-delaunay: ^6.0.4装好d3就能直接使用d3.DelaunayAPI。下面按“建三角剖分 → 生成 Voronoi 图 → 渲染 → 验证”的顺序走一遍完整操作路径。准备获取 d3 包在 Node 项目中用包管理器安装文档列出的三种方式任选其一npm install d3yarn add d3pnpm add d3然后在模块中加载import * as d3 from d3;如果是在纯 HTML 页面里使用文档推荐从 CDN 加载 ES module 版本d37script typemodule import * as d3 from https://cdn.jsdelivr.net/npm/d37/esm; /script文档同时提供 UMD 版本以普通script引入后导出d3全局以及可供本地下载的 UMD bundle用于离线或需要本地文件的场景。第一步从点集创建 Delaunay 三角剖分Voronoi 图通过delaunay.voronoi()生成所以第一步是先构造三角剖分。文档给出两种入口按点数据的形态选择Delaunay API点数据是二元素数组时用Delaunay.fromconst points [[0, 0], [0, 100], [100, 0], [100, 100]]; const delaunay d3.Delaunay.from(points);点数据是对象时通过fx、fy访问器取坐标const delaunay d3.Delaunay.from( [{x: 0, y: 0}, {x: 0, y: 1}, {x: 1, y: 0}, {x: 1, y: 1}], (d) d.x, (d) d.y );点数据已经或可以表示为扁平坐标数组时直接用构造器new d3.Delaunayconst delaunay new d3.Delaunay(Float64Array.of(0, 0, 0, 1, 1, 0, 1, 1));文档明确提示Delaunay.from通常比new Delaunay慢因为它需要先把坐标物化成一个新的扁平数组。对性能敏感的场景优先用Float64Array构造。第二步生成 Voronoi 图对三角剖分调用voronoi(bounds)即可得到 Voronoi 图const delaunay d3.Delaunay.from([[0, 0], [0, 100], [100, 0], [100, 100]]); const voronoi delaunay.voronoi([0, 0, 640, 480]);bounds是[xmin, ymin, xmax, ymax]渲染时图会被裁剪到这个视口。不传时默认为[0, 0, 960, 500]所以 bounds 应当与你的画布尺寸一致。退化情况也要知道即使不存在三角剖分——0 个、1 个、2 个点或所有点共线——voronoi依然会返回 Voronoi 图对象不会抛错Voronoi API。第三步渲染 Voronoi 图整张图render()voronoi.render(context)把 Voronoi 单元网格渲染到指定context如果不调用时不传 context则直接返回 SVG path 字符串const pathString voronoi.render();传给 context 的对象必须实现 CanvasPathMethods API 中的moveTo和lineTo方法因此 SVG 路径和 Canvas 2D 上下文都适用。下面是一个按文档示例组合出的完整 HTML 页面点集、bounds、SVG 尺寸都取自文档中的例子SVG 创建与挂载方式沿用 getting-started 中d3.create(svg)的写法!DOCTYPE html div idcontainer/div script typemodule import * as d3 from https://cdn.jsdelivr.net/npm/d37/esm; const points [[0, 0], [0, 100], [100, 0], [100, 100]]; const delaunay d3.Delaunay.from(points); const voronoi delaunay.voronoi([0, 0, 640, 480]); const svg d3.create(svg) .attr(width, 640) .attr(height, 480); svg.append(path) .attr(d, voronoi.render()) .attr(fill, none) .attr(stroke, currentColor); container.append(svg.node()); /script打开页面应看到 4 个点划分出的 Voronoi 分界线。单个 cell 和视口renderCell / renderBounds只需要画某一个单元或视口边框时const cellPath voronoi.renderCell(0); // 第 0 个点的 cell const boundsPath voronoi.renderBounds(); // 视口矩形注意两者对 context 的要求不同renderCell的 context 需要moveTo、lineTo、closePath三个方法renderBounds的 context 需要rect方法。不传 context 时同样返回 SVG path 字符串。只要多边形数据cellPolygon / cellPolygons不走渲染、直接取坐标时const polygon voronoi.cellPolygon(0);返回的是凸的闭合多边形[[x0, y0], [x1, y1], …, [x0, y0]]首尾坐标相同代表第 0 个点对应的单元。voronoi.cellPolygons()则迭代所有非空 cell 的多边形cell 索引作为属性随元素返回适合批量处理后再自己上色或打洞。验证生成结果文档没有给出固定的示例输出但给出了各方法返回值的明确形态可以据此做三项检查render() 的返回值不传 context 时必须是 SVG path 字符串能直接赋给path的d属性并在浏览器中画出分界网格。若返回为空或图形与点集明显不符先检查 bounds 是否与画布一致。cellPolygon 的形状返回值应为闭合多边形第一个和最后一个坐标相等voronoi.circumcentersFloat64Array每对连续的cx、cy是一个 Delaunay 三角形的外心构成这些多边形单元格的坐标可以用来交叉核对。单元归属判断用delaunay.find(x, y)与voronoi.contains(i, x, y)组合验证。find返回离指定点最近的输入点索引contains的定义就是“点 i 是指定点的最近点”二者按文档定义自洽const i delaunay.find(25, 25); voronoi.contains(i, 25, 25); // truecontains不受视口 bounds 影响——bounds 只作用于render、renderBounds、renderCell这三个渲染方法见voronoi.xmin/ymin/xmax/ymax的说明所以即使某单元被视口裁掉归属判断仍然成立。查询相邻 cell 与更新点集相邻 cellconst neighbors Array.from(voronoi.neighbors(0));返回与 cell 0 共享公共边的相邻 cell 索引。文档特别提醒一个容易踩的坑Voronoi 邻居一定是 Delaunay 图上的邻居但反过来不成立——当公共边被视口裁剪掉时voronoi.neighbors返回的邻居会比delaunay.neighbors少。需要完整的几何邻接关系时用 Delaunay 侧的neighbors。点集原地修改后重算点被原地修改后文档提到这是 Lloyds relaxation 的典型用法调用voronoi.update();它会同时更新 Voronoi 图和底层的 Delaunay 三角剖分内部调用delaunay.update无需重新Delaunay.from。边界与限制开放 cell位于凸包外沿的点其 Voronoi cell 是向无限延伸的开放区域。voronoi.vectors返回 Float64Array其中每个非零的四元组描述一个开放 cell给出两条开放半直线的方向需要用 bounds 将其裁剪闭合后再渲染。bounds 的作用范围只裁剪渲染结果render、renderBounds、renderCell不影响contains等查询方法。退化输入0、1、2 个点或共线点集仍返回 Voronoi 图对象但此时不存在有效的三角剖分triangles等结构没有内容可遍历。性能入口扁平Float64Array配new d3.Delaunay是最快路径Delaunay.from会额外物化一份扁平坐标数组文档注明它通常更慢。voronoi.delaunay可随时取回该图关联的 Delaunay 三角剖分对象方便在两种结构间来回使用。API 细节可继续查 Voronoi 文档 与 Delaunay 文档安装与环境配置参见 Getting started。【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。