Skip to content
This repository was archived by the owner on Nov 7, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions arcdiagram/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# d3.arcdiagram

A plugin for rendering
[Arc Diagrams](http://en.wikipedia.org/wiki/Arc_diagram).
Examples:

* http://bl.ocks.org/goodmami/fd03b250588e1e1143bd
* http://bl.ocks.org/goodmami/41d4ecc7520b73c21538
157 changes: 157 additions & 0 deletions arcdiagram/arcdiagram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
(function() {
d3.arcDiagram = function() {
var sortNodes,
sortLinks = arcDiagramSortLinks,
linkLevel = arcDiagramLinkLevelCompact,
nodeWidth = 0,
separation = 1,
nodeXOffset = 0,
levelHeight = arcDiagramLevelHeight,
nodes = [],
links = [];

function arc() {
var levelIndex = d3.range(nodes.length).map(function() { return []; }),
nw = typeof nodeWidth === "function" ? nodeWidth : function() { return nodeWidth; },
sep = typeof separation === "function" ? separation : function() { return separation; },
nxo = typeof nodeXOffset === "function" ? nodeXOffset : function() { return nodeXOffset; },
lh = typeof levelHeight === "function" ? levelHeight : function() { return levelHeight; },
curX = 0,
nodeIndexMap, idx1, idx2;

// node calculations
nodes.forEach(function(n, i) { n.index = i; });
// if sorting nodes, do it here and create a mapping from old to
// new positions
nodeIndexMap = {};
if (sortNodes) nodes.sort(sortNodes);
nodes.forEach(function(n, i) {
nodeIndexMap[n.index] = i; n.index = i;
// while we're iterating, we can set the x, dx, and y values
n.x = curX + nxo(n);
curX += nw(n) + sep(n);
n.y = 0;
});

// link calculations
// first, reassign source and index, if necessary.
links.forEach(function(link) {
link.source = nodeIndexMap[link.source] || link.source;
link.target = nodeIndexMap[link.target] || link.target;
// also set distance, which is useful for sorting.
link.distance = Math.abs(link.source - link.target);
});
if (sortLinks) links.sort(sortLinks);

// now we can find the level of each link
links.forEach(function(link) {
link.level = linkLevel(link, levelIndex);
arcDiagramUpdateLevelIndex(link, levelIndex);
// and while we're iterating, set the position values
link.x1 = (nodes[link.source] || {}).x;
link.x2 = (nodes[link.target] || {}).x;
link.height = lh(link);
});
}

arc.sortNodes = function(x) {
if (!arguments.length) return sortNodes;
sortNodes = x;
return arc;
}

arc.sortLinks = function(x) {
if (!arguments.length) return sortLinks;
sortLinks = x;
return arc;
}

arc.linkLevel = function(x) {
if (!arguments.length) return linkLevel;
if (x.toLowerCase() == "compact")
linkLevel = arcDiagramLinkLevelCompact;
else if (x.toLowerCase() == "distance")
linkLevel = arcDiagramLinkLevelDistance;
else
linkLevel = x;
return arc;
}

arc.nodeWidth = function(x) {
if (!arguments.length) return nodeWidth;
nodeWidth = typeof x === "function" ? x : +x;
return arc;
}

arc.separation = function(x) {
if (!arguments.length) return separation;
separation = typeof x === "function" ? x : +x;
return arc;
}

arc.nodeXOffset = function(x) {
if (!arguments.length) return nodeXOffset;
nodeXOffset = typeof x === "function" ? x : +x;
return arc;
}

arc.levelHeight = function(x) {
if (!arguments.length) return levelHeight;
levelHeight = typeof x === "function" ? x : +x;
return arc;
}

arc.nodes = function(x) {
if (!arguments.length) return nodes;
nodes = x;
return arc;
}

arc.links = function(x) {
if (!arguments.length) return links;
links = x;
return arc;
}

return arc;
}

function arcDiagramSortLinks(a, b) { return a.distance - b.distance; }

function arcDiagramLinkLevelCompact(link, levelIndex) {
var level = 1, idx1, idx2;

if (link.source <= link.target) {
idx1 = link.source; idx2 = link.target;
} else {
idx1 = link.target; idx2 = link.source;
}

for (var i = idx1; i < idx2; i++) {
if (levelIndex[i][level]) {
level += 1;
i = idx1 - 1; // restart the for-loop
continue;
}
}
return level;
}

function arcDiagramLinkLevelDistance(link, levelIndex) {
return link.distance;
}

function arcDiagramLevelHeight(link) {
return link.level;
}

function arcDiagramUpdateLevelIndex(link, levelIndex) {
var idx1, idx2;
if (link.source <= link.target) {
idx1 = link.source; idx2 = link.target;
} else {
idx1 = link.target; idx2 = link.source;
}
d3.range(idx1, idx2).forEach(function(i) { levelIndex[i][link.level] = true; });
}
})();