这是我在stackoverflow中的第一个问题,我希望你能帮我解决这个问题,而我还没有找到解决方案。我想在Web应用程序中使用D3 v4和sunburst可视化来显示和导航json文件给出的一些数据。我设法用sunburst(带工具提示)显示数据,当用户点击相应的弧时,它还允许使用转换放大到子项。
对于我的应用程序,我想使用一个初始的小json文件,它只显示完整(更大)数据的一部分。当用户点击弧(可以检索其他信息)时,这些小数据应按需扩展并在旭日动态中可视化。此外,当用户去"返回"对于父弧,应删除最近新添加的数据,以便仅再次显示初始数据。
所以工作流程:开始时有一个森伯斯特(data1
);用户点击子弧;这个弧应该是旭日新的焦点/中心,同时初始数据扩展到(data2
)更新旭日形象;用户看到新焦点和所选弧的新加载的子节点;当用户导航回来时,应再次显示(data1
)。最后一部分仍然缺失,我将在稍后处理,但在此之前我遇到了问题。我设法在两个数据集之间实现切换,但新焦点和旭日行为的结果并不像预期的那样。 (data1
)和(data2
)是flare.json数据集中的部分数据示例,当点击arc" analytics"对于哪些新数据应加载和可视化,在转换后,其三个孩子(缺少"优化")中仅有两个("群集"和#34;图#34;)是显示。但是,另外点击" analytics"的弧线。揭示了越来越多失踪的第三个孩子。我点击的越多,"正确"结果以某种方式近似。
我在JSFiddle中创建了一个工作示例,展示了我的关注点和出现的问题。另外,这是代码:
var width = 500;
var height = 500;
var radius = Math.min(width, height) / 2 - 10;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var x = d3.scaleLinear()
.range([0, 2 * Math.PI]);
var y = d3.scaleSqrt()
.range([0, radius]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var arc = d3.arc()
.padAngle(.01)
.padRadius(radius/3)
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); })
.innerRadius(function(d) { return Math.max(0, y(d.y0)); })
.outerRadius(function(d) { return Math.max(0, y(d.y1)); });
var partition = d3.partition();
var root = d3.hierarchy( data1 ).count();
var g = svg.selectAll("g")
.data( partition(root).descendants(), function(d){return d.data.name;})
.enter().append("g");
var tt = d3.select("body").append("tt")
.attr("class", "tooltip")
.style("opacity", 0);
var path = g.append("path")
.attr("d", arc)
.style("stroke", "white")
.style('stroke-width', 0.5)
.attr( "id", function(d){ return 'path' + d.data.name; })
.style("fill", function(d) { return color((d.children ? d : d.parent).data.name); })
.style("opacity", 0)
.on("click", click)
.on("mouseover", function(d) {
tt.transition()
.duration(200)
.style("opacity", 1.0);
tt.html( showTooltipInfo(d) )
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tt.transition()
.duration(500)
.style("opacity", 0);
})
.each(function(d,i){
this.xx0 = d.x0;
this.xx1 = d.x1;
this.yy0 = d.y0;
this.yy1 = d.y1;
})
.transition()
.duration(1000)
.style("opacity", 1);
function showTooltipInfo(d){
return d.data.name;
}
function click(d) {
svg.selectAll("g").select("path")
.transition()
.duration(750)
.attrTween("d", arcTweenZoom(d))
.each(function(d,i){
this.xx0 = d.x0;
this.xx1 = d.x1;
this.yy0 = d.y0;
this.yy1 = d.y1;
});
var selectedD = d;
setTimeout(function () {
var newRoot;
if (selectedD.data.name === "analytics")
newRoot = d3.hierarchy( data2 ).count();
else
return;
var groups = svg.selectAll("g")
.data( partition(newRoot).descendants(), function(d){return d.data.name;} );
groups.exit()
.transition()
.duration(10)
.style("opacity", 0)
.remove();
groups.select("path")
.transition()
.duration(750)
.attrTween("d", arcTweenData)
.each(function(d,i){
this.xx0 = d.x0;
this.xx1 = d.x1;
this.yy0 = d.y0;
this.yy1 = d.y1;
});
groups.enter().append("g").append("path")
.attr("d", arc)
.style("stroke", "white")
.style('stroke-width', 0.5)
.attr( "id", function(d){ return 'path' + d.data.name; })
.style("fill", function(d) { return color((d.children ? d : d.parent).data.name); })
.style("opacity", 0)
.on("click", click)
.on("mouseover", function(d) {
tt.transition()
.duration(200)
.style("opacity", 1.0);
tt.html( showTooltipInfo(d) )
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tt.transition()
.duration(500)
.style("opacity", 0);
})
.each(function(d,i){
this.xx0 = d.x0;
this.xx1 = d.x1;
this.yy0 = d.y0;
this.yy1 = d.y1;
})
.transition()
.delay(250)
.duration(750)
.style("opacity", 1);
}, 500);
}
function arcTweenData(a){
if ( this.xx0 !== undefined ){
var oi = d3.interpolate({x0: this.xx0, x1: this.xx1, y0: this.yy0, y1: this.yy1}, a);
var that = this;
return function(t) {
var b = oi(t);
that.xx0 = b.x0;
that.xx1 = b.x1;
that.yy0 = b.y0;
that.yy1 = b.y1;
return arc(b);
};
}
}
function arcTweenZoom(d){
var xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
yd = d3.interpolate(y.domain(), [d.y0, 1]),
yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]);
return function(d, i){
return i ? function(t){return arc(d)} : function(t){x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d);}
}
}
数据集data1
和data2
:
var data1 = {
"name": "flare",
"children": [
{
"name": "analytics",
"children": []
},
{
"name": "animate",
"children": [
{"name": "Easing", "size": 17010},
{"name": "FunctionSequence", "size": 5842},
{
"name": "interpolate",
"children": [
{"name": "ArrayInterpolator", "size": 1983},
{"name": "ColorInterpolator", "size": 2047},
{"name": "DateInterpolator", "size": 1375},
{"name": "Interpolator", "size": 8746},
{"name": "MatrixInterpolator", "size": 2202},
{"name": "NumberInterpolator", "size": 1382},
{"name": "ObjectInterpolator", "size": 1629},
{"name": "PointInterpolator", "size": 1675},
{"name": "RectangleInterpolator", "size": 2042}
]
},
{"name": "ISchedulable", "size": 1041},
{"name": "Parallel", "size": 5176},
{"name": "Pause", "size": 449},
{"name": "Scheduler", "size": 5593},
{"name": "Sequence", "size": 5534},
{"name": "Transition", "size": 9201},
{"name": "Transitioner", "size": 19975},
{"name": "TransitionEvent", "size": 1116},
{"name": "Tween", "size": 6006}
]
}]
};
var data2 = {
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
{
"name": "graph",
"children": [
{"name": "BetweennessCentrality", "size": 3534},
{"name": "LinkDistance", "size": 5731},
{"name": "MaxFlowMinCut", "size": 7840},
{"name": "ShortestPaths", "size": 5914},
{"name": "SpanningTree", "size": 3416}
]
},
{
"name": "optimization",
"children": [
{"name": "AspectRatioBanker", "size": 7074}
]
}
]
},
{
"name": "animate",
"children": [
{"name": "Easing", "size": 17010},
{"name": "FunctionSequence", "size": 5842},
{
"name": "interpolate",
"children": [
{"name": "ArrayInterpolator", "size": 1983},
{"name": "ColorInterpolator", "size": 2047},
{"name": "DateInterpolator", "size": 1375},
{"name": "Interpolator", "size": 8746},
{"name": "MatrixInterpolator", "size": 2202},
{"name": "NumberInterpolator", "size": 1382},
{"name": "ObjectInterpolator", "size": 1629},
{"name": "PointInterpolator", "size": 1675},
{"name": "RectangleInterpolator", "size": 2042}
]
},
{"name": "ISchedulable", "size": 1041},
{"name": "Parallel", "size": 5176},
{"name": "Pause", "size": 449},
{"name": "Scheduler", "size": 5593},
{"name": "Sequence", "size": 5534},
{"name": "Transition", "size": 9201},
{"name": "Transitioner", "size": 19975},
{"name": "TransitionEvent", "size": 1116},
{"name": "Tween", "size": 6006}
]
}]
};
我在click方法中使用setTimeout
调用的原因是,当我立即将切换应用于新数据时,click方法开头的第一个转换/缩放事件不会应用,因为切换发生得太快。在这种情况下,我的方法可能完全错误。
你知道我做错了什么或建议我如何才能更好地解决这个问题?
任何帮助表示赞赏!非常感谢你提前了!