|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
|
|
<style> |
|
.link { |
|
stroke: white; |
|
fill: black; |
|
} |
|
.node { |
|
fill: steelblue; |
|
stroke: #fff; |
|
stroke-width: 2px; |
|
} |
|
</style> |
|
|
|
<body> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script> |
|
|
|
var width = 960, |
|
height = 500, |
|
nodes = [{r: 10}, {r: 15}, {r: 20}, {r: 25}], |
|
list = [[0, 1], [0, 2], [1, 2], [2, 1], [2, 0], [2, 3], [3, 1], [0, 3]], |
|
links = list.map(createLinks); |
|
|
|
function createLinks (a) { |
|
return {source: a[0], target: a[1], linkWidth: 5, headLength:20, headWidth: 8} |
|
} |
|
|
|
var force = d3.layout.force() |
|
.size([width, height]) |
|
.nodes(nodes) |
|
.links(links) |
|
.linkDistance(150) |
|
.on("tick", tick) |
|
.start(); |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
svgLinks = svg.selectAll(".link").data(links) |
|
.enter().append("polygon") |
|
.attr("class", "link"); |
|
|
|
svgNodes = svg.selectAll(".node").data(nodes) |
|
.enter().append("circle") |
|
.attr("class", "node") |
|
.attr("r", function (d) {return d.r}) |
|
.call(force.drag); |
|
|
|
function tick() { |
|
svgNodes |
|
.attr("cx", function (d) {return d.x}) |
|
.attr("cy", function (d) {return d.y}); |
|
svgLinks |
|
.attr("points", calculatePolygon); |
|
} |
|
|
|
function calculatePolygon(d) { |
|
var p2 = d.source, |
|
w = diff(d.target, p2), |
|
wl = length(w), |
|
v1 = scale(w, (wl - d.target.r) / wl), |
|
p1 = sum(p2, v1), |
|
v2 = scale(rotate90(w), d.linkWidth / length(w)), |
|
p3 = sum(p2, v2), |
|
v1l = length(v1), |
|
v3 = scale(v1, (v1l - d.headLength) / v1l), |
|
p4 = sum(p3, v3), |
|
v2l = length(v2), |
|
v4 = scale(v2, d.headWidth / v2l), |
|
p5 = sum(p4, v4); |
|
|
|
return pr(p1) +" "+ pr(p2) +" "+ pr(p3) +" "+ pr(p4) +" "+ pr(p5); |
|
|
|
function length(v) {return Math.sqrt(v.x * v.x + v.y * v.y)} |
|
function diff(v, w) {return {x: v.x - w.x, y: v.y - w.y}} |
|
function sum(v, w) {return {x: v.x + w.x, y: v.y + w.y}} |
|
function scale(v, f) {return {x: f * v.x, y: f * v.y}} |
|
function rotate90(v) {return {x: v.y, y: -v.x}} // clockwise |
|
function pr(v) {return v.x +","+ v.y} |
|
} |
|
|
|
</script> |