对不起这个愚蠢的问题,我只是一个可怜的d3新手...
我在JSFiddle上有以下demo bubble diagram:我想要实现的是每当我点击它们时增加圆的半径,然后相应地调整包布局。
为方便起见,这是JSFiddle中的代码:
text {
font: 20px sans-serif;
}
<!DOCTYPE html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var root = {
"name": "Root",
"children": [
{
"name": "Leaf One",
"children": null,
"size": 1
},
{
"name": "Leaf Two",
"children": null,
"size": 1
},
{
"name": "Leaf Three",
"children": null,
"size": 1
}
],
"size": 1
};
var diameter = 400,
format = d3.format(",d"),
color = d3.scale.category20c();
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
// not needed in JSfiddle, data is hard-coded:
// d3.json("data.json", function(error, root) {
// if (error) throw error;
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(root))
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("title")
.text(function(d) { return d.className + ": " + format(d.value); });
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d) { return color(d.packageName); });
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.className.substring(0, d.r / 3); });
node.on("click", function(e, i){
var circle = svg.select("circle");
circle.attr("value", function(d) {
d.value += 1;
return d.value;
});
circle.attr("r", function(d) {
d.r += 1.0;
return d.r;
});
});
// });
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
var classes = [];
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
else classes.push({packageName: name, className: node.name, value: node.size});
}
recurse(null, root);
return {children: classes};
}
d3.select(self.frameElement).style("height", diameter + "px");
</script>
我试图通过node.on("click", ...)
方法做到这一点,但我得到了一些卡住,因为修改后的圈子总是第一个:选择我点击的圈子的最佳方式是什么?
此外,在修改圆半径后,如何强制d3包布局刷新?
答案 0 :(得分:1)
首先,你必须记住,在事件处理程序中,this
绑定到当前的DOM元素(在完整的情况下 - <g>
)。因此,您可以选择点击<g>
d3.select(this)
,然后选择以下圈子:
var circle = d3.select(this).select("circle");
(只需按svg.select("circle")
选择DOM中的第一个圆圈,它总是恰好相同的一个圆圈)
为了刷新布局,您必须更新基础数据,重新计算布局,重新计算数据连接和更新值:
// store the underlying data in a value
var classedRoot = classes(root);
// ...your node creating code here
node.on("click", function(d) {
// update the data in classedRoot
d.value += 1;
// recalculate layout
var data = bubble.nodes(classedRoot);
// recompute data join
node.data(data, function(d) { return d.className; }) // use key function
// update values
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.select("circle")
.attr("r", function(d) { return d.r });
});
请注意,此处使用key function可以将更新的数据与已存在的圈子正确绑定。您使用的值对于所有圈子必须是唯一的。我在这里使用了 className ,但如果它不是唯一的,那么您将不得不使用某种ID。
此处已更新jsFiddle