Skip to content

Instantly share code, notes, and snippets.

@erkal
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erkal/9746652 to your computer and use it in GitHub Desktop.
Save erkal/9746652 to your computer and use it in GitHub Desktop.
Directed Links with Polygons

Directed Links with Polygons.

This is an alternative to: Mobile Patent Suits

The mobile patent suits version is here

How? The width of the links and the length & width of arrow-heads are determined by parameters. These parameters are read from the link properties. Nodes must have a property named "r" which then determines the radius of representing circles. This property is used by the creation of the polygon to shorten the link preventing the arrow head disappearing behind the target node.

Explanation of the Code: Click here to see the picture

Why? svg markers don't seem to be easy to play with, particularly if node radii vary.

What more can be done? One may create curved links by using svg path instead of polygon.

<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment