问题描述
我是d3.js的新手。我在d3.js zoomable sunburst图表中工作。当用户放大到一个特定的弧,我需要捕获这种状态的sunburst图。当用户回到sunburst图或加载图形时,他应该看到他离开的状态。
注意:我不想序列化svg元素来显示sunburst的状态。如果我序列化它,那么图表将是静态的,用户不能点击sunburst并遍历到其他弧。
建议的解决方案:
一个解决方案来到我的心灵模拟鼠标点击sunburst节点,直到最后一个节点用户看着。
我不能为此设计一个算法。
请指导我是否有其他解决方案。
你说的方法很容易实现。我为它做了一个小样本。
单击开始保存
按钮以开始保存Sunburst的状态。执行几个缩放操作后,单击停止保存
按钮。您可以对图表进行任何进一步的更改。现在,点击加载
按钮将显示图表的保存状态。
var width = 500,height = 500,radius = Math.min(width,height)/ 2; var x = d3.scale.linear().range([0,2 * Math.PI]); var y = d3。 scale.sqrt().range([0,radius]); var color = d3.scale.category10(); var svg = d3.select(body)。append(svg).attr(width ,width).attr(height,height).append(g).attr(transform,translate(+ width / 2 +,+(height / 2 + 10)+)rotate (-90 0 0)); var partition = d3.layout.partition().value(function(d){return d.size;}); var arc = d3.svg.arc().startAngle d){return Math.max(0,Math.min(2 * Math.PI,x(dx))) Math.PI,x(dx + d.dx)));}).innerRadius(function(d){return Math.max(0,y(dy)); }; var set = partition.nodes(root); var g = 0; svg.selectAll(g).data(partition.nodes(root)).enter()。append(g); var path = g.append(path).attr(d .style(fill,function(d){return color((d.children?d:d.parent).name);}).on(click,click); var text = g.append文本).attr(x,function(d){return y(dy);}).attr(dx,6)// margin .attr(dy,.35em)/ / vertical-align .attr(transform,function(d){returnrotate(+ computeTextRotation(d)+);}).text(function(d){return d.name;}).style (fill,white); function computeTextRotation(d){var angle = x(dx + d.dx / 2) - Math.PI /返回角度/ Math.PI * 180; } var saveData = false; var savedData = []; d3.select(#saveBtn)。on(click,function(){if(d3.select(this).attr(value)==开始保存){savedData = []; d3.select(this).attr(value,Stop Save); saveData = true;} else {d3.select(this).attr(value,开始保存); saveData = false;}}); d3.select(#loadBtn)。on(click,function(){var root = g.filter(function(d){return d.name = =Root})。data(); click(root [0]); savedData.forEach(function(val){var node = g.filter(function(d,i){return i == val})。 data(); click(node [0]);});}); function click(d,i){if(saveData){if(d.name ==Root){savedData = [] } else {savedData.push(i); }} //淡出所有文本元素if(d.size!== undefined){d.size + = 100; }; text.transition()。attr(opacity,0); path.transition().duration(750).attrTween(d,arcTween(d)).each(end,function(e,i){//检查动画元素的数据e是否在可见角度在d中给出的范围if(ex> = dx&& ex<(dx + d.dx)){//获得相关文本元素的选择var arcText = d3.select(this.parentNode).select (text); //淡入文本元素并重新计算位置arcText.transition()。duration(750).attr(opacity,1).attr(transform,function + computeTextRotation(e)+)}).attr(x,function(d){return y(dy);});}}); } // var wrapLinebreaks = function(t,d,width){alert(0)var el = d3.select(t); var p = d3.select(t.parentNode); p.append(g).attr(x,function(d){return y(dy);}).attr(transform,function(d){returnrotate(+ computeTextRotation(d) +);}).append(foreignObject).attr('x',-width / 2).attr(width,width).attr(height,200).append p).attr('style','word-wrap:break-word; text-align:center;').html(d.name); alert(1)el.remove(); alert(2)}; d3.select(self.frameElement).style(height,height +px); //插值缩放函数arcTween(d){var xd = d3.interpolate(x.domain (y.domain(),[dy,1]),yr = d3.interpolate(y.range(),[dy?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); }; };} function getData(){return {name:Root,children:[{name:A1,children:[{name:B1,size 30},{name:B2,size:40},{name:B3,children:[{name:C1,size:10} name:C2,size:15}]}],{name:A2,children name:B5,size:30},{name:B6,size:10}]},{name:A3,children:[{name :B7,size:50},{name:B8,size:15}]}]}};
path {stroke:#fff; fill-rule:evenodd;}
< script src = https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js\"> ;</script> ;<div id =main>< / div>< ; input type =buttonvalue =Start Saveid =saveBtn/>< input type =buttonvalue =Loadid =loadBtn/>
/ pre>
我不知道你打算在哪里保存sunburst的状态。我建议是一个不错的选择。
希望这有帮助。
I am a newbie to d3.js . I am working in d3.js zoomable sunburst chart http://bl.ocks.org/mbostock/4348373. When the user zoom into a particular arc and I need to capture this state of the sunburst diagram . When the user comes back to the sunburst diagram or load the graph again he should see the state where he left.
Note : I dont want to serialise the svg elements to show the state of the sunburst. If i serialise it then the chart will be static and user cant click on the sunburst and traverse to other arcs.
Proposed Solution : one solution came to my mind is simulate mouse clicks on the sunburst nodes till the last node user looks into. I am not able to devise an algorithm for this . Please guide me whether any other solution is possible ..
The approach you said is easy to implement. I have made a small sample for it.
Click the Start Save
button to start saving the state of Sunburst. Click Stop Save
button after performing a few zooming actions. You can make any further changes to the chart. Now, clicking Load
button will show you the saved state of the chart.
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var color = d3.scale.category10();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ") rotate(-90 0 0)");
var partition = d3.layout.partition()
.value(function(d) {
return d.size;
});
var arc = d3.svg.arc()
.startAngle(function(d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
})
.endAngle(function(d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
})
.innerRadius(function(d) {
return Math.max(0, y(d.y));
})
.outerRadius(function(d) {
return Math.max(0, y(d.y + d.dy));
});
var root = getData();
var savedData = partition.nodes(root);
var g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
var path = g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color((d.children ? d : d.parent).name);
})
.on("click", click);
var text = g.append("text")
.attr("x", function(d) {
return y(d.y);
})
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.attr("transform", function(d) {
return "rotate(" + computeTextRotation(d) + ")";
})
.text(function(d) {
return d.name;
})
.style("fill", "white");
function computeTextRotation(d) {
var angle = x(d.x + d.dx / 2) - Math.PI / 2;
return angle / Math.PI * 180;
}
var saveData = false;
var savedData = [];
d3.select("#saveBtn").on("click", function() {
if (d3.select(this).attr("value") == "Start Save") {
savedData = [];
d3.select(this).attr("value", "Stop Save");
saveData = true;
} else {
d3.select(this).attr("value", "Start Save");
saveData = false;
}
});
d3.select("#loadBtn").on("click", function() {
var root = g.filter(function(d) {
return d.name == "Root"
}).data();
click(root[0]);
savedData.forEach(function(val) {
var node = g.filter(function(d, i) {
return i == val
}).data();
click(node[0]);
});
});
function click(d, i) {
if (saveData) {
if(d.name=="Root"){
savedData = [];
} else{
savedData.push(i);
}
}
// fade out all text elements
if (d.size !== undefined) {
d.size += 100;
};
text.transition().attr("opacity", 0);
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function() {
return "rotate(" + computeTextRotation(e) + ")"
})
.attr("x", function(d) {
return y(d.y);
});
}
});
}
// Word wrap!
var insertLinebreaks = function(t, d, width) {
alert(0)
var el = d3.select(t);
var p = d3.select(t.parentNode);
p.append("g")
.attr("x", function(d) {
return y(d.y);
})
.attr("transform", function(d) {
return "rotate(" + computeTextRotation(d) + ")";
})
.append("foreignObject")
.attr('x', -width / 2)
.attr("width", width)
.attr("height", 200)
.append("xhtml:p")
.attr('style', 'word-wrap: break-word; text-align:center;')
.html(d.name);
alert(1)
el.remove();
alert(2)
};
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 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);
};
};
}
function getData() {
return {
"name": "Root",
"children": [{
"name": "A1",
"children": [{
"name": "B1",
"size": 30
}, {
"name": "B2",
"size": 40
}, {
"name": "B3",
"children": [{
"name": "C1",
"size": 10
}, {
"name": "C2",
"size": 15
}]
}]
}, {
"name": "A2",
"children": [{
"name": "B4",
"size": 40
}, {
"name": "B5",
"size": 30
}, {
"name": "B6",
"size": 10
}]
}, {
"name": "A3",
"children": [{
"name": "B7",
"size": 50
}, {
"name": "B8",
"size": 15
}
]
}]
}
};
path {
stroke: #fff;
fill-rule: evenodd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="main"></div>
<input type="button" value="Start Save" id="saveBtn"/>
<input type="button" value="Load" id="loadBtn"/>
I don't know where do you plan to save the state of the sunburst. I would suggest that Localstorage would be a nice option.
Hope this helps.
这篇关于捕获/保存d3.js Sunburst图表的当前状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!