我正在尝试在d3.js中构建一个定向力图,它上面有一个点击监听器,用于更改基础数据并重绘图形。我相信我遵循Bostock先生的更新模式,但我遇到的问题是当我运行由点击监听器触发的更新时,节点从屏幕底部消失,留下链接和标签。
此更新似乎运行,更新现有节点(在这种情况下将它们变为绿色)然后忽略“enter”和“exit”部分(这是所需的行为)然后点击发送节点的tick()函数南。
我可以通过删除节点上的“g”标签并因此解耦标签和节点来实现这一点,这显然是不可取的。
我情不自禁地觉得我错过了一些明显的东西!或许我应该以不同的方式解决这个问题?
以下是代码:
var width = 960,
height = 500,
links,
nodes,
root;
var force = d3.layout.force()
.size([width, height])
.charge(-200)
.linkDistance(50)
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
d3.json("test.json", function(json) {
root = json;
update();
});
function update() {
nodes = root.nodes
links = root.links
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
svg.append("svg:defs").append("marker")
.attr("id", "end")
.attr("refX", 15)
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M 0,0 V 4 L8,2 Z");
// Update the links…
//link = link.data(links, function(d) { return d.target.name; });
link = link.data(links)
// Exit any old links.
link.exit().remove();
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "link")
.attr("marker-end", "url(#end)")
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
// Update the nodes…
node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });
node.style("fill", "green")
// Exit any old nodes.
node.exit().remove();
// Enter any new nodes.
node.enter().append("g")
.append("svg:circle")
.attr("class", "node")
.attr("id", function(d) {return "node" + d.index; })
.attr("r", 12)
.style("fill", "#BBB")
.on("click", click)
.call(force.drag);
node.append("svg:text")
.attr("dx", 16)
.attr("dy", ".15em")
.attr("class", "nodelabel")
.text(function(d) { return d.name });
}
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
function click(d) {
if (!d3.event.defaultPrevented) {
// DO ANYTHING
update()
}
}
,test.json的内容是:
{
"nodes": [
{"name" : "John"},
{"name" : "Alison"},
{"name" : "Phil"},
{"name" : "Jim"},
{"name" : "Jane"},
{"name" : "Mary"},
{"name" : "Joe"}
],
"links": [
{"source": 1, "target": 0},
{"source": 2, "target": 0},
{"source": 3, "target": 0},
{"source": 4, "target": 0},
{"source": 5, "target": 1},
{"source": 6, "target": 1}
]
}
答案 0 :(得分:1)
node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });
然后在tick函数中我正在更新这些节点:
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
所以这是非常正确的,然而,节点被封装在“g”标签中以及文本标签,但tick()
功能仅作用于节点。修复是强制tick()
中的transform属性更新整个组而不仅仅是节点:
svg.selectAll("g").attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
现在一切正常!