d3 圆形打包布局详解用 d3.pack 构建层级包含图Enclosure Diagram【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3本文以 d3 仓库中的 圆形打包布局文档 为主体完整讲解d3.pack系列 APIpack()、radius、size、padding、packSiblings、packEnclose的语义、参数取值与默认值并结合仓库中的 d3-hierarchy 模块说明、层级数据 API 文档 与 版本变更历史 补充前置调用链与底层算法依据。读完本文你可以独立完成一棵「叶子圆大小编码数值、嵌套圆表示子树累计规模」的包含图布局并理解其近似性来源与可复用的底层几何算法。包含图与圆形打包定位与适用场景层级模块总览 将层级可视化归纳为三类节点连线图node-link如树状图、邻接图adjacency如 icicle/sunburst、包含图enclosure。圆形打包circle packing属于包含图用「包含嵌套」关系表达层级拓扑用叶子圆的面积编码数据的量化维度。原文档对这类图的刻画值得逐句重视叶子圆的大小编码数据的量化维度是图中唯一可精确比较的部分外围的父级圆展示各子树的近似累计规模——由于圆嵌套必然产生「浪费」的空白空间父级圆的面积存在失真与 矩形树图treemap 相比circle packing 的空间利用率更低但这些「浪费」的空间反而更突出地揭示了层级结构本身。因此选型经验是追求空间利用效率、强调各单元精确可比时选 treemap强调嵌套关系可读性、允许父级近似时选 pack。前置条件先 sum、再 sort最后 packpack(root)要求输入是一棵已经构建好的 hierarchy。pack 文档 明确要求在把 hierarchy 传给 pack 布局之前必须先调用root.sum()并且通常还需要调用root.sort()来决定布局顺序。这一点在 hierarchy.md 的node.sort一节 得到了呼应——文档专门给出了「circle-packing 推荐」的排序比较函数root .sum((d) d.value) .sort((a, b) b.value - a.value);两个容易踩坑的细节sum()的访问器对**每个节点包括内部节点**求值若只有叶子携带数值内部节点应返回 0原文示例root.sum((d) d.value ? 1 : 0)比较函数收到的是两个节点a、b而非两个 data 对象所以要写b.value - a.value而不是b.data.value - a.data.valuesort必须在调用布局之前执行排序结果才会影响布局。API 全解d3.pack 与它的四个访问器pack() 与 pack(root)d3.pack()以默认配置创建一个 pack 布局调用pack(root)则对该roothierarchy 计算布局在root及其每个后代上写入三个属性属性含义node.x圆心的 x 坐标node.y圆心的 y 坐标node.r圆的半径这与 CHANGES.md 中记录的 v4 重写一致布局以 root 节点为输入而非直接操作 JSON 数据布局结果挂载在节点对象上输入数据与计算结果由此分离。pack.radius(radius)传入radius时设置为布局的半径访问器并返回该布局不传时返回当前访问器默认值为null。访问器为null时默认每个叶子圆的半径由叶子的node.value即sum()的结果推导再按布局尺寸等比缩放。访问器非null时叶子圆半径精确等于函数返回值布局不再从value推导半径。pack.size(size)传入size时设置为[width, height]形式的二元数组并返回该布局不传时返回当前尺寸默认值为[1, 1]。半径自动缩放、两遍填充算法都以这个尺寸为基准。pack.padding(padding)传入padding时设置为 padding 访问器数字或函数函数形式可按父节点动态计算这一点是 v4 重写新增的能力不传时返回当前访问器默认值为常数 0。作用范围相邻兄弟圆之间的切线间隙约等于该 padding父圆与其子圆之间的间隙也约等于该 padding后者同样是 v4 新增见 CHANGES.md 对d3.pack重写的记录。重要限制若未指定显式radiuspadding 只是近似值——因为要在布局尺寸内完成填充需要两遍two-pass算法先无 padding 打包计算一个缩放因子并作用于指定 padding最后带 padding 重新打包。一个可直接复用的端到端示例综合以上语义一个完整的包含图计算与渲染流程如下适用于当前仓库构建出的d3v7.9.0 产物见 package.json// 1. 构建 hierarchy先 sum必需再 sort影响布局顺序 const root d3.hierarchy(data) .sum(d d.value ? d.value : 0) // 若只有叶子携带数值内部节点返回 0 .sort((a, b) b.value - a.value); // circle-packing 推荐排序 // 2. 创建并配置 pack 布局 const pack d3.pack() .size([960, 960]) // 默认 [1, 1]务必设为实际画布尺寸 .padding(2); // 默认 0兄弟间隙与父子间隙均受其影响 // 3. 计算布局为 root 及所有后代写入 x / y / r pack(root); // 4. 渲染所有后代 d3.select(#chart) .append(svg) .attr(viewBox, 0 0 960 960) .selectAll(circle) .data(root.descendants()) .join(circle) .attr(cx, d d.x) .attr(cy, d d.y) .attr(r, d Math.max(0, d.r)) .attr(fill, d d.children ? none : steelblue);其中d.children ? none : steelblue的写法体现了包含图的语义分工父级圆只作轮廓近似累计值叶子圆才实心编码数值避免把失真的父级面积当成精确数据来比较。可独立复用的几何原语pack 布局由两个非层级non-hierarchical的几何函数支撑它们脱离 hierarchy 也可单独使用在 CHANGES.md 中被明确记录为 v4 重写时新增/保留的公共 API。packSiblings(circles)对传入的圆数组做打包每个圆必须有circle.r属性函数为每个圆写入circle.x、circle.y。圆的位置按 CHANGES.md 所引 Wang 等人的front-chain packing 算法计算——即沿一条「前链」逐个把圆贴合到已有圆上这是 pack 布局兄弟圆排布的实际算法基础。packEnclose(circles)计算能完全包住给定圆数组的最小圆smallest enclosing circle。输入要求每个圆具备circle.r、circle.x、circle.y返回的包围圆同样带x、y、r。它采用Matoušek-Sharir-Welzl 算法求精确解。从实现历史看这个「精确」是 v4 重写的关键改进之一CHANGES.md 记录 3.x 时代每个父圆的包围圆是用 Wang 等人算法的近似值算出的而 4.0 起改用 Welzl 算法计算精确最小包围圆同时修复了 major bugs 并改善了整体打包效果。仓库内正好保留了这两代输出的对比图CHANGES.md 第 841 行附近左图为 3.x 输出右图为 4.0 输出可直观看到重写后父圆贴合更紧、结果更规整packEnclose也意味着 pack 布局「父圆半径 包住子圆的精确最小圆」这一行为有据可查——父级圆的近似失真主要来自圆嵌套的固有空白而非包围圆计算误差。在 d3 仓库中的落点与引用方式本仓库是d3主包v7.9.0见 package.json通过依赖d3-hierarchy: ^3.1.2引入 d3-hierarchy并在 src/index.js 中export * from d3-hierarchy;整体再导出——因此d3.pack、d3.packSiblings、d3.packEnclose都以d3.命名空间暴露给使用者构建入口为 bundle.js经 rollup.config.js 产出dist/d3.jsUMD、dist/d3.mjsESM、dist/d3.min.js压缩版三种产物构建产物中 src/index.js 的再导出链条保证 pack API 完整包含文档链接完整性由 test/docs-test.js 自动校验爬取docs/下所有 Markdown 的内部链接与锚点断言无 404这也是 docs/d3-hierarchy/pack.md 中内部锚点如#pack_radius、#pack_size能被稳定引用的工程保障相关文档可进一步延伸阅读hierarchy节点构造、sum/sort/descendants、treemap空间利用率的对照方案、stratify从表格数据构建 hierarchy 的前置步骤。小结d3.pack的完整心智模型可以归纳为四条输入契约先root.sum()必需root.sort()推荐按聚合值降序再交给pack(root)输出契约每个节点得到x、y、r叶子圆可精确比较父级圆是近似累计三个访问器radius默认null由value推导、size默认[1, 1]、padding默认0支持函数无显式半径时为两遍近似可复用原语packSiblingsfront-chain 打包与packEncloseWelzl 精确最小包围圆可脱离层级单独使用v4 重写正是靠它们获得了更精确、更规整的打包结果。适用前提说明以上内容以当前仓库d3 v7.9.0、d3-hierarchy ^3.1.2、Node 12见 package.json的实际内容为准确认布局算法的细节实现位于 d3-hierarchy 依赖包内部本仓库以再导出与文档的形式承载其行为说明。【免费下载链接】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),仅供参考