我正在尝试使用d3.js创建一个完全动态的Sunburst图。 我找到的示例和教程倾向于使用现有/完全填充的数据结构,这些数据结构可能能够修改现有弧的值,但不允许根据需要添加子弧。
同样,我找到的教程允许新数据集只是替换现有结构并从头开始绘制。 这不是我试图实现的行为。
我需要的是基于提供的传入数据的动态构建图。
我可以将子项附加到数据集的末尾,转换并呈现结果而不会出现问题。每当我在现有结构中的某个地方插入一个孩子时,就会出现问题,d3的selectAll()没有按预期运行。它包括新的弧(尚未绘制),导致任何剩余的弧被错误地渲染。然后当转换弧时,它似乎得到弧Dom ID和它所代表的数据混合起来。新弧不可见,并且应存放新弧的空白空间。
要清楚我的意图是:
分为jsfiddle示例的四个步骤:
初始化图形(绘制一个不可见的“根”弧)
{姓名:" a_0",儿童:[]}
将First Child数据及其子项添加到root
{姓名:" a_0",儿童:[ {name:" a_1",children:[{name:" a_2",children:[{name:" a_3" }]}]} ]}
将第二个子项和基础子项添加到root
{姓名:" a_0",儿童:[ {name:" a_1",children:[{name:" a_2",children:[{name:" a_3" }]}]}, {name:" a_4",children:[{name:" a_5",children:[{name:" a_6" }]}]} ]}
在现有弧a_2
中插入另一个子项{姓名:" a_0",儿童:[ {姓名:" a_1",孩子:[ {姓名:" a_2",孩子:[ {姓名:" a_3" }, {姓名:" a_7" } ]} ]}, {姓名:" a_4",孩子:[ {姓名:" a_5",孩子:[ {姓名:" a_6" } ]} ]} ]}
第1步可以正常使用
第2步正确绘制弧
第3步转换现有弧并将新弧添加到图中
第4步会导致一些意想不到的行为。
在现有和进入新弧线的过程中,一些弧线会跳跃到#34;失去与各自数据的正确关联 最终结果似乎是:
最终结果如何以及实际发生的情况并不相同。
看起来我在正确的轨道上一路走到a_6,但是在添加a_7时我没有弄清楚这种行为的原因。
jsFidde执行上述步骤,包括:
问题:
jsfiddle https://jsfiddle.net/mfitzgerald/j2eowwya/
上的工作示例var dataObj = { name:"a_0", color: "none" };
var height = 300;
var width = 500;
var radius = Math.min(width, height) / 2;
var graph = d3.select("#graph")
.attr('height', height)
.attr('width', width)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, radius * radius])
.value(function(d, i) { return 1; });
var arc = d3.svg.arc()
.startAngle(function(d) { if (isNaN(d.x)) { d.x = 0; } d.x0 = d.x; return d.x; })
.endAngle(function(d) { if (isNaN(d.dx)) { d.dx = 0; } d.dx0 = d.dx; return d.x + d.dx; })
.innerRadius(function(d) { if (isNaN(d.y)) { d.y = 0; } d.y0 = d.y; return Math.sqrt(d.y); })
.outerRadius(function(d) { if (isNaN(d.dy)) { d.dy = 0; } d.dy0 = d.dy; return Math.sqrt(d.y + d.dy); });
var arcTween = function(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0, y: a.y0, dy: a.dy0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
a.y0 = b.y;
a.dy0 = b.dy;
displayStats("arctween", b);
return arc(b);
};
}
// Root Arc
graph.datum(dataObj).selectAll('path.arc')
.data(partition.nodes)
.enter()
.append('path')
.attr('class', function(d) { return "arc " + d.name; })
.attr("d", arc)
.attr("id", function(d, i) { return "path_"+i; })
.attr("name", function(d) { return d.name; })
.style("fill", "none");
function updateGraph() {
console.log("Update Graph");
console.log(dataObj);
var update = graph.datum(dataObj).selectAll('path.arc')
.data(partition.nodes);
// Move existing Arcs
update.each(function(d, i) {
displayStats("target", d, i, "existing");
var domId = $(this).attr("id");
console.log("["+i+"] Exist Arc name:"+d.name+", dom_id:"+domId);
})
.transition()
.delay(function(d, i) { return i * 250; })
.duration(1500)
.attrTween("d", arcTween);
// Add New Arcs
update.enter().append('path')
.attr('class', function(d, i) { return "arc "+d.name; })
.attr("d", arc)
.attr("id", function(d, i) {
var domId = "path_"+i;
console.log("["+i+"] NEW Arc name:"+d.name+", dom_id:"+domId);
displayStats("target", d, i, "new");
return domId;
})
.style("stroke", "#fff")
.style("fill", function(d) { return d.color; })
.style("opacity", 0)
.transition()
.delay(function(d, i) { return i * 250; })
.duration(1500)
.style("opacity", .5)
.attrTween("d", arcTween);
}
答案 0 :(得分:0)
@Gordon回答了这个问题。在updateGraph代码中加入.data()时,通过添加key function解决了该问题。
上的分叉示例var update = graph.datum(dataObj).selectAll('path.arc')
.data(partition.nodes, function(d) { return d.name; } );
我相信问题的答案是:
<强> 更新 强>
需要进行额外的修改,因为DOM id是由数据元素的数组索引设置的,但仍然存在与DOM和基础图/数据的无效关联。
这将导致2 a_4 DOM id&#39; s。而不是使用节点名称作为DOM ID的数组索引应该保持这种关联正确。