關於Stack Overflow的第一個問題,請耐心等待!我對d3.js是新手,但一直對其他人能夠完成的事情感到驚訝......我幾乎同樣驚訝於我自己能夠取得的進展。很顯然,我並不是在追求什麼,所以我希望這裏的善良的靈魂能夠讓我看到光明。將新節點添加到Force-directed佈局
我的本意是做一個可重用的JavaScript功能,只需執行以下操作:
- 創建在指定的DOM元素的空力向圖
- 允許您添加和刪除標記,圖像 - 承載節點操作圖,指定
我已經採取http://bl.ocks.org/950642爲起點它們之間的連接,因爲這是基本我希望能夠創建什麼樣的佈局:
這裏是我的代碼如下所示:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="underscore-min.js"></script>
<script type="text/javascript" src="d3.v2.min.js"></script>
<style type="text/css">
.link { stroke: #ccc; }
.nodetext { pointer-events: none; font: 10px sans-serif; }
body { width:100%; height:100%; margin:none; padding:none; }
#graph { width:500px;height:500px; border:3px solid black;border-radius:12px; margin:auto; }
</style>
</head>
<body>
<div id="graph"></div>
</body>
<script type="text/javascript">
function myGraph(el) {
// Initialise the graph object
var graph = this.graph = {
"nodes":[{"name":"Cause"},{"name":"Effect"}],
"links":[{"source":0,"target":1}]
};
// Add and remove elements on the graph object
this.addNode = function (name) {
graph["nodes"].push({"name":name});
update();
}
this.removeNode = function (name) {
graph["nodes"] = _.filter(graph["nodes"], function(node) {return (node["name"] != name)});
graph["links"] = _.filter(graph["links"], function(link) {return ((link["source"]["name"] != name)&&(link["target"]["name"] != name))});
update();
}
var findNode = function (name) {
for (var i in graph["nodes"]) if (graph["nodes"][i]["name"] === name) return graph["nodes"][i];
}
this.addLink = function (source, target) {
graph["links"].push({"source":findNode(source),"target":findNode(target)});
update();
}
// set up the D3 visualisation in the specified element
var w = $(el).innerWidth(),
h = $(el).innerHeight();
var vis = d3.select(el).append("svg:svg")
.attr("width", w)
.attr("height", h);
var force = d3.layout.force()
.nodes(graph.nodes)
.links(graph.links)
.gravity(.05)
.distance(100)
.charge(-100)
.size([w, h]);
var update = function() {
var link = vis.selectAll("line.link")
.data(graph.links);
link.enter().insert("line")
.attr("class", "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; });
link.exit().remove();
var node = vis.selectAll("g.node")
.data(graph.nodes);
node.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("image")
.attr("class", "circle")
.attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
node.append("text")
.attr("class", "nodetext")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
node.exit().remove();
force.on("tick", function() {
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 + ")"; });
});
// Restart the force layout.
force
.nodes(graph.nodes)
.links(graph.links)
.start();
}
// Make it all go
update();
}
graph = new myGraph("#graph");
// These are the sort of commands I want to be able to give the object.
graph.addNode("A");
graph.addNode("B");
graph.addLink("A", "B");
</script>
</html>
我每次添加一個新的節點,它重新標籤,所有現有的節點;這些堆在彼此的頂部,事情開始變得醜陋。我明白這是爲什麼:因爲當我在添加新節點時調用update()
函數函數時,它會對整個數據集執行node.append(...)
。我不知道如何做到這一點只有我添加的節點 ...我只能顯然使用node.enter()
來創建一個新的元素,所以這不適用於我需要綁定的額外元素到節點。我怎樣才能解決這個問題?
非常感謝您提供任何有關此問題的指導!
編輯,因爲我迅速修復了以前提到
是的,先生。順便說一句,這是一個非常好的答案! – Maziyar 2014-03-21 04:16:59
添加新數據時使用'force.start()'而不是'force.resume()'是關鍵。非常感謝! – Mouagip 2014-06-10 09:05:01
這太棒了。如果它自動縮放縮放級別(可能會減少收費,直到所有東西都適合?),那麼要冷靜一些,因此所有東西都按照它正在繪製的盒子的大小裝配。 – 2014-07-31 12:43:11