了解 force layout node 及 link 操作
將原本寫死的三個動作,變成可以自由新增 node 與 link
了解 force layout node 及 link 操作
將原本寫死的三個動作,變成可以自由新增 node 與 link
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.link { | |
stroke: #000; | |
stroke-width: 1.5px; | |
} | |
.node { | |
fill: #000; | |
stroke: #fff; | |
stroke-width: 1.5px; | |
} | |
.selected { | |
stroke: #f00; | |
stroke-width: 3px; | |
} | |
.desc { | |
fill: #aaa; | |
} | |
</style> | |
<body> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script> | |
var width = 960, | |
height = 500; | |
var color = d3.scale.category10(); | |
var serial = 0; | |
var nodes = [], | |
links = []; | |
var force = d3.layout.force() | |
.nodes(nodes) | |
.links(links) | |
.charge(-500) | |
.linkDistance(120) | |
.size([width, height]) | |
.on("tick", tick); | |
var drag = force.drag(); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var node = svg.selectAll(".node"), | |
link = svg.selectAll(".link"); | |
svg.append("text") | |
.attr("class", "desc") | |
.attr("x", 10) | |
.attr("y", 20) | |
.text("新增節點:按住 shift 鍵再按滑鼠左鍵"); | |
svg.append("text") | |
.attr("class", "desc") | |
.attr("x", 10) | |
.attr("y", 40) | |
.text("連結節點:對要連結的節點點一下,再點選另一個節點"); | |
setTimeout(function() { | |
var a = {id: serial++}, b = {id: serial++}, c = {id: serial++}; | |
nodes.push(a, b, c); | |
links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); | |
start(); | |
}, 0); | |
function start() { | |
link = link.data(force.links(), function(d) { return d.source.id + "-" + d.target.id; }); | |
link.enter().insert("line", ".node").attr("class", "link"); | |
link.exit().remove(); | |
node = node.data(force.nodes(), function(d) { return d.id;}); | |
node.enter().append("circle") | |
.attr("class", function(d) { return "node"; }) | |
.attr("r", 12) | |
.style("fill", function(d, i) { return color(i); }) | |
.call(drag) | |
.on('click', function(d) { | |
if (d3.select(this).classed("selected")) { | |
d3.select(this).attr("class", function(d) { return "node"; }) | |
} else { | |
d3.select(this).attr("class", function(d) { return "node selected"; }) | |
tryConnect(); | |
} | |
}) | |
.on('dbclick', function(d) { console.log("XD");}); | |
node.exit().remove(); | |
force.start(); | |
} | |
function tick() { | |
node.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
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; }); | |
} | |
function tryConnect() { | |
var selected = svg.selectAll('.selected'); | |
var selectedData = selected.data(); | |
console.log(selectedData); | |
if (selectedData.length == 2) { | |
console.log(links); | |
links.push({source: selectedData[0], target: selectedData[1]}); | |
selected.attr("class", "node"); | |
start(); | |
} | |
} | |
function drawCircle(x, y) { | |
var c = {id: serial++, } | |
nodes.push(c); | |
start(); | |
} | |
svg.on('click', function() { | |
if (d3.event.shiftKey == true) { | |
var coords = d3.mouse(this); | |
drawCircle(coords[0], coords[1]); | |
} | |
}); | |
</script> |