Built with blockbuilder.org
forked from lmeyerov's block: force demo
forked from lmeyerov's block: force demo
Built with blockbuilder.org
forked from lmeyerov's block: force demo
forked from lmeyerov's block: force demo
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
svg { width:100%; height: 100% } | |
</style> | |
</head> | |
<body> | |
<script> | |
var w = 960, h = 500; | |
var n = 10; | |
var RADIUS = 100; | |
var ANCHORS = 3; | |
var vis = d3.select("body").append("svg:svg") | |
.attr("width", w) | |
.attr("height", h); | |
var coords = d3.range(n).map(function (d) { | |
return {x: Math.random() * w, y: Math.random() * h} | |
}); | |
var nodes = [].concat( | |
d3.range(n).map(function (d) { | |
return { | |
x: coords[d].x, | |
y: coords[d].y, | |
}; }), | |
d3.range(n * ANCHORS).map(function (d) { | |
var i = d % n; | |
var angle = 2 * Math.PI * Math.floor(d/n) / ANCHORS; | |
return { | |
fixed: true, | |
anchor: true, | |
x: coords[i].x + RADIUS * Math.cos(angle), | |
y: coords[i].y + RADIUS * Math.sin(angle) | |
}; | |
})); | |
var links = [].concat( | |
d3.range(n * 3).map(function (d) { | |
return { | |
source: d % n, | |
target: (d * 3) % n}; | |
}), | |
d3.range(n * ANCHORS).map(function (d) { | |
return { | |
source: d % n, | |
target: n + d, | |
anchor: true}; | |
})); | |
var force = d3.layout.force() | |
.nodes(nodes).links(links) | |
.linkStrength(function (d) { return d.anchor ? 0.8 : 0.1; }) | |
.gravity(.05).distance(100).charge(-100).size([w, h]) | |
.start(); | |
var link = vis.selectAll("line.link") | |
.data(links) | |
.enter().append("svg:line") | |
.attr("stroke", function (d) { return d.anchor ?"#EEE":"red"; }) | |
.attr("stroke-width", "2px") | |
.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; }); | |
var node_drag = d3.behavior.drag() | |
.on("dragstart", function () { force.stop(); }) | |
.on("drag", function (d, i) { | |
if (!d.anchor) { | |
d.px += d3.event.dx; | |
d.py += d3.event.dy; | |
d.x += d3.event.dx; | |
d.y += d3.event.dy; | |
tick(); | |
} | |
}) | |
.on("dragend", function (d, i) { | |
d.fixed = true; | |
tick(); | |
force.resume(); | |
}); | |
var node = vis.selectAll("g.node") | |
.data(nodes) | |
.enter().append("svg:g") | |
.attr("class", "node") | |
.call(node_drag); | |
node.append("circle") | |
.attr("class", "circle") | |
.attr("cx", "-8px") | |
.attr("cy", "-8px") | |
.attr("r", function (d) { return d.anchor ? "5px" : "16px"}) | |
.attr("height", "16px"); | |
node.append("svg:text") | |
.attr("class", "nodetext") | |
.attr("dx", 12) | |
.attr("dy", ".35em") | |
.text(function(d) { return d.name }); | |
force.on("tick", tick); | |
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 + ")"; }); | |
}; | |
</script> | |
</body> |