将D3 V3圆形打包图升级至V4遇层级API调用错误求助
解决D3 V3到V4打包图迁移的
d3.hierarchy.pack is not a function错误 嘿,我帮你搞定这个迁移问题!这个错误完全是因为D3 V4对布局API做了彻底的重构——和V3的用法差异很大,你之前的调用方式不符合V4的API规范。
问题根源
D3 V3里的d3.layout.pack()是一个集成了数据层级处理和布局计算的方法,但V4把这两部分拆分开了:
- 层级数据结构的构建交给
d3.hierarchy() - 打包布局的计算交给
d3.pack()
你错误地尝试用d3.hierarchy.pack()这种链式调用,而实际上这两个方法是独立的,所以才会抛出“不是函数”的错误。
修复步骤&代码对比
下面直接拿你的场景来对比修改:
原V3核心代码片段
// V3 中创建打包布局并计算节点 var pack = d3.layout.pack() .size([width, height]) .padding(2); var nodes = pack.nodes(flareData); // 直接传入原始flare数据
修改后的V4核心代码
// V4 第一步:先构建层级数据结构,必须指定sum/value来计算节点大小 var root = d3.hierarchy(flareData) .sum(function(d) { return d.size; }); // 这里的size对应你数据中的数值字段,按需调整 // V4 第二步:创建打包布局实例 var pack = d3.pack() .size([width, height]) .padding(2); // V4 第三步:计算布局并获取所有节点数组 var nodes = pack(root).descendants(); // 用descendants()获取所有节点,等价于V3的pack.nodes()返回值
完整的displayFlareGraph函数修改示例
如果你的原函数是这样的(V3版本):
function displayFlareGraph(selector, flareData, width, height) { var svg = d3.select(selector) .append("svg") .attr("width", width) .attr("height", height); var pack = d3.layout.pack() .size([width, height]) .padding(2); var nodes = pack.nodes(flareData); // 绘制节点和文本的逻辑 var node = svg.selectAll(".node") .data(nodes) .enter().append("g") .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); node.append("circle") .attr("r", function(d) { return d.r; }); node.filter(function(d) { return !d.children; }).append("text") .attr("dy", ".3em") .style("text-anchor", "middle") .text(function(d) { return d.name.substring(0, d.r / 3); }); }
那么修改后的V4版本应该是:
function displayFlareGraph(selector, flareData, width, height) { var svg = d3.select(selector) .append("svg") .attr("width", width) .attr("height", height); // 1. 构建层级结构并计算节点权重 var root = d3.hierarchy(flareData) .sum(function(d) { return d.size; }); // 2. 创建打包布局 var pack = d3.pack() .size([width, height]) .padding(2); // 3. 计算布局并获取所有节点 var nodes = pack(root).descendants(); // 绘制逻辑基本和V3一致,无需大改 var node = svg.selectAll(".node") .data(nodes) .enter().append("g") .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); node.append("circle") .attr("r", function(d) { return d.r; }); node.filter(function(d) { return !d.children; }).append("text") .attr("dy", ".3em") .style("text-anchor", "middle") .text(function(d) { return d.name.substring(0, d.r / 3); }); }
关键注意点
- 必须指定sum/value:V3的pack布局会自动推断节点大小,但V4需要你通过
.sum()或.value()明确告诉布局如何计算每个节点的权重,否则所有节点的半径都会是0。 - 获取节点的方式:V4中
pack(root)返回的是根节点对象,需要调用.descendants()来获取包含所有子节点的数组,这和V3的pack.nodes(data)返回结果一致。 - 命名空间变化:V3的布局都在
d3.layout下,V4直接把pack、tree等布局放在顶级的d3对象下,所以要用d3.pack()而不是d3.layout.pack()。
内容的提问来源于stack exchange,提问作者loretoparisi
相关产品推荐
相关产品推荐

