Skip to content

Instantly share code, notes, and snippets.

@gka
Forked from mbostock/.block
Last active December 14, 2015 20:40
Show Gist options
  • Save gka/5145845 to your computer and use it in GitHub Desktop.
Save gka/5145845 to your computer and use it in GitHub Desktop.
d3 inter-dependency graph
[{"imports": ["d3.map"], "name": "d3.ease", "size": 2495}, {"imports": ["d3.behavior", "d3.event", "d3.selection", "d3.touches", "d3.mouse", "d3.rebind"], "name": "d3.behavior.drag", "size": 2363}, {"imports": ["d3.layout", "d3.layout.hierarchy", "d3.layout.tree"], "name": "d3.layout.pack", "size": 4980}, {"imports": ["d3.scale", "d3.interpolate", "d3.rebind", "d3.range", "d3.format", "d3.scale.nice"], "name": "d3.scale.linear", "size": 2944}, {"imports": [], "name": "d3.extent", "size": 567}, {"imports": ["d3.geo.clip", "d3.geo.circle", "d3.geo.spherical", "d3.geo.cartesian"], "name": "d3.geo.clip.circle", "size": 3480}, {"imports": ["d3.geo", "d3.geo.azimuthal", "d3.geo.projection"], "name": "d3.geo.orthographic", "size": 203}, {"imports": ["d3.transition", "d3.selection.filter"], "name": "d3.transition.filter", "size": 537}, {"imports": [], "name": "d3.ascending", "size": 87}, {"imports": ["d3.layout", "d3.layout.hierarchy", "d3.max", "d3.layout.tree"], "name": "d3.layout.cluster", "size": 2242}, {"imports": ["d3.svg.area"], "name": "d3.svg.area.radial", "size": 354}, {"imports": ["d3.time", "d3.time.day", "d3.time.year", "d3.time.interval"], "name": "d3.time.day", "size": 547}, {"imports": ["d3.geo"], "name": "d3.geo.azimuthal", "size": 561}, {"imports": ["d3.geo", "d3.geo.stream"], "name": "d3.geo.centroid", "size": 3391}, {"imports": ["d3.transition"], "name": "d3.transition.remove", "size": 191}, {"imports": ["d3.scale", "d3.range"], "name": "d3.scale.ordinal", "size": 2657}, {"imports": ["d3.transition", "d3.selection.selectAll"], "name": "d3.transition.selectAll", "size": 784}, {"imports": ["d3.geo", "d3.geo.azimuthal", "d3.geo.projection"], "name": "d3.geo.gnomonic", "size": 210}, {"imports": ["d3.time", "d3.time.day", "d3.time.year", "d3.time.interval"], "name": "d3.time.year", "size": 326}, {"imports": ["d3.geo"], "name": "d3.geo.compose", "size": 250}, {"imports": ["d3.time", "d3.time.minute", "d3.time.interval"], "name": "d3.time.minute", "size": 356}, {"imports": ["d3.layout"], "name": "d3.layout.bundle", "size": 1500}, {"imports": ["d3.selection"], "name": "d3.selection.node", "size": 244}, {"imports": ["d3.number"], "name": "d3.mean", "size": 338}, {"imports": ["d3.scale", "d3.scale.pow"], "name": "d3.scale.sqrt", "size": 70}, {"imports": ["d3.scale"], "name": "d3.scale.bilinear", "size": 212}, {"imports": ["d3.geom"], "name": "d3.geom.quadtree", "size": 3160}, {"imports": ["d3.class"], "name": "d3.map", "size": 1182}, {"imports": ["d3.selection"], "name": "d3.selection.select", "size": 793}, {"imports": ["d3.min"], "name": "d3.zip", "size": 328}, {"imports": ["d3.layout", "d3.bisect", "d3.min", "d3.max", "d3.functor"], "name": "d3.layout.histogram", "size": 3391}, {"imports": [], "name": "d3.max", "size": 458}, {"imports": ["d3.scale"], "name": "d3.scale.nice", "size": 395}, {"imports": ["d3.selection"], "name": "d3.selection.datum", "size": 153}, {"imports": ["d3.transition", "d3.selection.each"], "name": "d3.transition.each", "size": 599}, {"imports": ["d3.dispatch", "d3.event", "d3.rebind"], "name": "d3.xhr", "size": 2871}, {"imports": ["d3.time.format"], "name": "d3.time.format.locale", "size": 350}, {"imports": ["d3.geo", "d3.geo.projection"], "name": "d3.geo.equirectangular", "size": 236}, {"imports": ["d3.svg", "d3.map", "d3.functor"], "name": "d3.svg.line", "size": 11692}, {"imports": [], "name": "d3.dispatch", "size": 1436}, {"imports": [], "name": "d3.noop", "size": 22}, {"imports": ["d3.geo", "d3.rebind", "d3.geo.resample", "d3.geo.clip.circle", "d3.geo.compose", "d3.geo.rotation"], "name": "d3.geo.projection", "size": 2992}, {"imports": ["d3.selection", "d3.event"], "name": "d3.selection.on", "size": 1661}, {"imports": ["d3.behavior", "d3.event", "d3.selection", "d3.mouse", "d3.touches", "d3.rebind"], "name": "d3.behavior.zoom", "size": 5128}, {"imports": ["d3.event", "d3.dispatch"], "name": "d3.event", "size": 1705}, {"imports": ["d3.layout", "d3.sum", "d3.range"], "name": "d3.layout.pie", "size": 2739}, {"imports": ["d3.geo.path"], "name": "d3.geo.path.context", "size": 962}, {"imports": [], "name": "d3.layout", "size": 16}, {"imports": [], "name": "d3.xyz", "size": 217}, {"imports": ["d3.selection", "d3.requote", "d3.collapse"], "name": "d3.selection.classed", "size": 2552}, {"imports": [], "name": "d3.min", "size": 458}, {"imports": [], "name": "d3.nest", "size": 1806}, {"imports": ["d3.selection", "d3.selection.enter"], "name": "d3.selection.data", "size": 2908}, {"imports": ["d3.xhr"], "name": "d3.xml", "size": 140}, {"imports": ["d3.layout", "d3.layout.hierarchy"], "name": "d3.layout.partition", "size": 1109}, {"imports": ["d3.transition", "d3.ns", "d3.interpolate", "d3.transition.tween"], "name": "d3.transition.attr", "size": 1861}, {"imports": ["d3.rgb"], "name": "d3.hsl", "size": 1397}, {"imports": ["d3.selection"], "name": "d3.selection.root", "size": 547}, {"imports": ["d3.time", "d3.bisect", "d3.rebind", "d3.time.second", "d3.time.minute", "d3.time.hour", "d3.time.day", "d3.time.week", "d3.time.month", "d3.time.year", "d3.time.format", "d3.scale.linear", "d3.scale.nice"], "name": "d3.time.scale", "size": 3915}, {"imports": ["d3.geo", "d3.merge", "d3.geo.spherical"], "name": "d3.geo.clip", "size": 8472}, {"imports": ["d3.geo", "d3.geo.cartesian"], "name": "d3.geo.resample", "size": 2627}, {"imports": ["d3.geo.path", "d3.geom.polygon"], "name": "d3.geo.path.area", "size": 1000}, {"imports": ["d3.svg.diagonal"], "name": "d3.svg.diagonal.radial", "size": 583}, {"imports": ["d3.time"], "name": "d3.time.interval", "size": 1489}, {"imports": ["d3.bisect"], "name": "d3.bisect", "size": 764}, {"imports": ["d3.selection"], "name": "d3.selection.each", "size": 415}, {"imports": ["d3.scale", "d3.scale.ordinal"], "name": "d3.scale.category", "size": 1441}, {"imports": ["d3.geo"], "name": "d3.geo.spherical", "size": 265}, {"imports": ["d3.selection"], "name": "d3.selection.html", "size": 359}, {"imports": [], "name": "d3.random", "size": 668}, {"imports": ["d3.scale", "d3.scale.linear"], "name": "d3.scale.identity", "size": 603}, {"imports": ["d3.dsv"], "name": "d3.dsv.csv", "size": 34}, {"imports": ["d3.geo.clip"], "name": "d3.geo.clip.antimeridian", "size": 2793}, {"imports": ["d3.geo", "d3.geo.stream"], "name": "d3.geo.area", "size": 2065}, {"imports": ["d3.geo.azimuthal", "d3.geo", "d3.geo.projection"], "name": "d3.geo.azimuthal.equidistant", "size": 297}, {"imports": ["d3.geo.path", "d3.geom.polygon"], "name": "d3.geo.path.centroid", "size": 2246}, {"imports": ["d3.transition", "d3.selection.each"], "name": "d3.transition.tween", "size": 728}, {"imports": ["d3.compat"], "name": "d3.compat.date", "size": 62}, {"imports": ["d3.geo", "d3.geo.projection"], "name": "d3.geo.mercator", "size": 395}, {"imports": ["d3.formatPrefix", "d3.map", "d3.round"], "name": "d3.format", "size": 4227}, {"imports": ["d3.layout", "d3.permute", "d3.map", "d3.range"], "name": "d3.layout.stack", "size": 5329}, {"imports": ["d3.time", "d3.requote", "d3.map"], "name": "d3.time.format", "size": 8657}, {"imports": ["d3.geo", "d3.geo.compose"], "name": "d3.geo.rotation", "size": 1552}, {"imports": ["d3.selection"], "name": "d3.selection", "size": 961}, {"imports": ["d3.time.scale", "d3.time.format.utc", "d3.scale.linear"], "name": "d3.time.scale.utc", "size": 1415}, {"imports": [], "name": "d3.range", "size": 623}, {"imports": ["d3.svg", "d3.functor"], "name": "d3.svg.area", "size": 2683}, {"imports": [], "name": "d3.number", "size": 59}, {"imports": ["d3.transition", "d3.selection.each"], "name": "d3.transition.duration", "size": 365}, {"imports": ["d3.core"], "name": "d3.core.module", "size": 37}, {"imports": ["d3.rgb", "d3.lab"], "name": "d3.hcl", "size": 940}, {"imports": ["d3.event", "d3.mouse"], "name": "d3.touches", "size": 289}, {"imports": ["d3.xhr"], "name": "d3.html", "size": 275}, {"imports": ["d3.transition", "d3.dispatch", "d3.timer"], "name": "d3.transition", "size": 2467}, {"imports": [], "name": "d3.quantile", "size": 239}, {"imports": ["d3.geo", "d3.geo.stream"], "name": "d3.geo.bounds", "size": 753}, {"imports": [], "name": "d3.uninterpolate", "size": 278}, {"imports": ["d3.selection"], "name": "d3.selection.text", "size": 367}, {"imports": ["d3.zip"], "name": "d3.transpose", "size": 72}, {"imports": [], "name": "d3.svg", "size": 13}, {"imports": ["d3.xhr"], "name": "d3.dsv", "size": 2655}, {"imports": ["d3.time", "d3.time.second", "d3.time.interval"], "name": "d3.time.second", "size": 356}, {"imports": [], "name": "d3.round", "size": 115}, {"imports": [], "name": "d3.descending", "size": 88}, {"imports": ["d3.round", "d3.format"], "name": "d3.formatPrefix", "size": 690}, {"imports": ["d3.scale", "d3.scale.linear", "d3.format", "d3.scale.nice"], "name": "d3.scale.log", "size": 2201}, {"imports": ["d3.transition", "d3.selection.each"], "name": "d3.transition.delay", "size": 323}, {"imports": ["d3.layout", "d3.layout.hierarchy"], "name": "d3.layout.treemap", "size": 6511}, {"imports": ["d3.time", "d3.time.day", "d3.time.month", "d3.time.interval"], "name": "d3.time.month", "size": 318}, {"imports": [], "name": "d3.sum", "size": 282}, {"imports": ["d3.layout", "d3.rebind", "d3.merge"], "name": "d3.layout.hierarchy", "size": 2724}, {"imports": [], "name": "d3.array", "size": 780}, {"imports": [], "name": "d3.ns", "size": 564}, {"imports": [], "name": "d3.time", "size": 1744}, {"imports": ["d3.geo", "d3.geo.projection"], "name": "d3.geo.albers", "size": 966}, {"imports": ["d3.layout", "d3.range"], "name": "d3.layout.chord", "size": 3502}, {"imports": ["d3.time", "d3.time.hour", "d3.time.interval"], "name": "d3.time.hour", "size": 417}, {"imports": [], "name": "d3.collapse", "size": 68}, {"imports": ["d3.compat"], "name": "d3.compat.style", "size": 366}, {"imports": ["d3.selection", "d3.ascending"], "name": "d3.selection.sort", "size": 414}, {"imports": ["d3.layout", "d3.dispatch", "d3.geom.quadtree", "d3.timer", "d3.behavior.drag", "d3.event", "d3.rebind"], "name": "d3.layout.force", "size": 8853}, {"imports": [], "name": "d3.class", "size": 260}, {"imports": ["d3.time", "d3.time.day", "d3.time.year", "d3.time.week", "d3.time.interval"], "name": "d3.time.week", "size": 910}, {"imports": ["d3.selection"], "name": "d3.selection.remove", "size": 235}, {"imports": ["d3.selection"], "name": "d3.selection.property", "size": 1358}, {"imports": ["d3.transition", "d3.selection.select"], "name": "d3.transition.select", "size": 728}, {"imports": ["d3.geo.azimuthal.equal", "d3.geo", "d3.geo.azimuthal", "d3.geo.projection"], "name": "d3.geo.azimuthal.equal.area", "size": 304}, {"imports": ["d3.scale", "d3.quantile", "d3.bisect", "d3.ascending"], "name": "d3.scale.quantile", "size": 891}, {"imports": ["d3.interpolate", "d3.transform", "d3.rgb", "d3.hsl", "d3.lab", "d3.hcl"], "name": "d3.interpolate", "size": 7180}, {"imports": ["d3.geo"], "name": "d3.geo.stream", "size": 2480}, {"imports": [], "name": "d3.scale", "size": 283}, {"imports": ["d3.timer"], "name": "d3.timer", "size": 2459}, {"imports": [], "name": "d3.shuffle", "size": 184}, {"imports": ["d3.geo"], "name": "d3.geo.cartesian", "size": 889}, {"imports": ["d3.svg", "d3.scale.linear", "d3.selection", "d3.transition", "d3.scale"], "name": "d3.svg.axis", "size": 7831}, {"imports": [], "name": "d3.keys", "size": 100}, {"imports": ["d3.geo", "d3.geo.stream", "d3.geo.bounds", "d3.geo.path.context", "d3.geo.resample"], "name": "d3.geo.path", "size": 2501}, {"imports": ["d3.geom", "d3.geom.polygon", "d3.range"], "name": "d3.geom.voronoi", "size": 11309}, {"imports": ["d3.geo", "d3.geo.rotation", "d3.geo.spherical", "d3.geo.cartesian"], "name": "d3.geo.circle", "size": 2200}, {"imports": ["d3.geo"], "name": "d3.geo.haversin", "size": 68}, {"imports": [], "name": "d3.requote", "size": 129}, {"imports": [], "name": "d3.functor", "size": 118}, {"imports": [], "name": "d3.transform", "size": 1601}, {"imports": [], "name": "d3.behavior", "size": 18}, {"imports": ["d3.selection", "d3.ns"], "name": "d3.selection.attr", "size": 1932}, {"imports": ["d3.dsv"], "name": "d3.dsv.tsv", "size": 52}, {"imports": ["d3.geom", "d3.geom.voronoi"], "name": "d3.geom.delaunay", "size": 866}, {"imports": [], "name": "d3.merge", "size": 84}, {"imports": ["d3.time.format", "d3.time.format.utc"], "name": "d3.time.format.iso", "size": 473}, {"imports": ["d3.selection.enter", "d3.selection"], "name": "d3.selection.enter.select", "size": 638}, {"imports": ["d3.time.format"], "name": "d3.time.format.utc", "size": 522}, {"imports": ["d3.geom"], "name": "d3.geom.hull", "size": 2688}, {"imports": ["d3.format"], "name": "d3.format.locale", "size": 135}, {"imports": ["d3.svg", "d3.functor"], "name": "d3.svg.chord", "size": 1951}, {"imports": ["d3.selection", "d3.event"], "name": "d3.mouse", "size": 1127}, {"imports": ["d3.transition", "d3.ease", "d3.selection.each"], "name": "d3.transition.ease", "size": 308}, {"imports": [], "name": "d3.permute", "size": 174}, {"imports": ["d3.svg", "d3.map", "d3.functor"], "name": "d3.svg.symbol", "size": 2309}, {"imports": ["d3.selection", "d3.ns"], "name": "d3.selection.insert", "size": 553}, {"imports": ["d3.map", "d3.hsl", "d3.xyz", "d3.lab"], "name": "d3.rgb", "size": 7495}, {"imports": [], "name": "d3.rebind", "size": 599}, {"imports": ["d3.xhr"], "name": "d3.json", "size": 183}, {"imports": [], "name": "d3.true", "size": 38}, {"imports": ["d3.quantile", "d3.ascending"], "name": "d3.median", "size": 200}, {"imports": ["d3.geo", "d3.range"], "name": "d3.geo.graticule", "size": 1788}, {"imports": ["d3.scale"], "name": "d3.scale.quantize", "size": 720}, {"imports": ["d3.xhr"], "name": "d3.text", "size": 144}, {"imports": ["d3.svg", "d3.functor"], "name": "d3.svg.arc", "size": 2616}, {"imports": ["d3.geo", "d3.geo.interpolate"], "name": "d3.geo.greatArc", "size": 1526}, {"imports": [], "name": "d3.geo", "size": 13}, {"imports": ["d3.svg.line"], "name": "d3.svg.line.radial", "size": 467}, {"imports": [], "name": "d3.values", "size": 113}, {"imports": ["d3.selection"], "name": "d3.selection.empty", "size": 69}, {"imports": ["d3.geo", "d3.geo.azimuthal", "d3.geo.projection"], "name": "d3.geo.stereographic", "size": 269}, {"imports": [], "name": "d3.identity", "size": 40}, {"imports": ["d3.selection"], "name": "d3.selection.order", "size": 354}, {"imports": ["d3.svg", "d3.functor"], "name": "d3.svg.diagonal", "size": 894}, {"imports": [], "name": "d3.entries", "size": 136}, {"imports": ["d3.svg", "d3.selection", "d3.event", "d3.touches", "d3.mouse", "d3.rebind", "d3.scale"], "name": "d3.svg.brush", "size": 10419}, {"imports": ["d3.geo.albers", "d3.geo"], "name": "d3.geo.albers.usa", "size": 1590}, {"imports": ["d3.selection", "d3.selection.enter"], "name": "d3.selection.enter", "size": 527}, {"imports": ["d3.selection"], "name": "d3.selection.call", "size": 142}, {"imports": [], "name": "d3.color", "size": 96}, {"imports": ["d3.geom"], "name": "d3.geom.polygon", "size": 2196}, {"imports": ["d3.rgb", "d3.hcl", "d3.xyz"], "name": "d3.lab", "size": 1578}, {"imports": ["d3.geo", "d3.geo.haversin"], "name": "d3.geo.interpolate", "size": 1029}, {"imports": ["d3.scale", "d3.bisect"], "name": "d3.scale.polylinear", "size": 541}, {"imports": ["d3.transition", "d3.interpolate", "d3.transition.tween"], "name": "d3.transition.style", "size": 1919}, {"imports": ["d3.scale", "d3.bisect"], "name": "d3.scale.threshold", "size": 516}, {"imports": ["d3.selection"], "name": "d3.selection.style", "size": 2034}, {"imports": ["d3.selection", "d3.transition"], "name": "d3.selection.transition", "size": 546}, {"imports": ["d3.layout", "d3.layout.hierarchy"], "name": "d3.layout.tree", "size": 6619}, {"imports": ["d3.transition", "d3.transition.tween"], "name": "d3.transition.text", "size": 230}, {"imports": ["d3.selection", "d3.ns"], "name": "d3.selection.append", "size": 405}, {"imports": ["d3.geo.path"], "name": "d3.geo.path.buffer", "size": 1123}, {"imports": ["d3.selection"], "name": "d3.selection.filter", "size": 652}, {"imports": ["d3.scale", "d3.scale.linear", "d3.scale.nice"], "name": "d3.scale.pow", "size": 1257}, {"imports": ["d3.selection"], "name": "d3.selection.selectAll", "size": 630}, {"imports": [], "name": "d3.geom", "size": 14}]

An implementation of Danny Holten's hierarchical edge bundling algorithm in D3, showing dependencies between classes in d3 functions hierarchy. Dependencies are bundled according to the parent packages. This example uses two layouts: a radial d3.layout.cluster to position the tree nodes, and d3.layout.bundle to group the dependencies into spline bundles. Thanks to Jason Davies for contributing the layout implementation!

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link type="text/css" rel="stylesheet" href="style.css"/>
<style type="text/css">
path.arc {
cursor: move;
fill: #fff;
}
.node {
font-size: 10px;
}
.node:hover {
fill: #1f77b4;
}
.link {
fill: none;
stroke: #1f77b4;
stroke-opacity: .4;
pointer-events: none;
}
.link.source, .link.target {
stroke-opacity: 1;
stroke-width: 2px;
}
.node.target {
fill: #d62728 !important;
}
.link.source {
stroke: #d62728;
}
.node.source {
fill: #2ca02c;
}
.link.target {
stroke: #2ca02c;
}
</style>
</head>
<body>
<h2>
D3 imports<br>
hierarchical edge bundling
</h2>
<div style="position:absolute;bottom:0;font-size:18px;">tension: <input style="position:relative;top:3px;" type="range" min="0" max="100" value="85"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="packages.js"></script>
<script type="text/javascript">
var w = 1280,
h = 800,
rx = w / 2,
ry = h / 2,
m0,
rotate = 0;
var splines = [];
var cluster = d3.layout.cluster()
.size([360, ry - 120])
.sort(function(a, b) { return d3.ascending(a.key, b.key); });
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.85)
.radius(function(d) { return d.y; })
.angle(function(d) { return d.x / 180 * Math.PI; });
// Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
var div = d3.select("body").insert("div", "h2")
.style("top", "-80px")
.style("left", "-160px")
.style("width", w + "px")
.style("height", w + "px")
.style("position", "absolute");
var svg = div.append("svg:svg")
.attr("width", w)
.attr("height", w)
.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
svg.append("svg:path")
.attr("class", "arc")
.attr("d", d3.svg.arc().outerRadius(ry - 120).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
.on("mousedown", mousedown);
d3.json("readme-d3-imports.json", function(classes) {
var nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes),
splines = bundle(links);
var path = svg.selectAll("path.link")
.data(links)
.enter().append("svg:path")
.attr("class", function(d) { return "link source-" + d.source.key + " target-" + d.target.key; })
.attr("d", function(d, i) { return line(splines[i]); });
svg.selectAll("g.node")
.data(nodes.filter(function(n) { return !n.children; }))
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function(d) { return "node-" + d.key; })
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
.append("svg:text")
.attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
.text(function(d) { return d.key; })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
d3.select("input[type=range]").on("change", function() {
line.tension(this.value / 100);
path.attr("d", function(d, i) { return line(splines[i]); });
});
});
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
function mouse(e) {
return [e.pageX - rx, e.pageY - ry];
}
function mousedown() {
m0 = mouse(d3.event);
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
}
}
function mouseup() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
rotate += dm;
if (rotate > 360) rotate -= 360;
else if (rotate < 0) rotate += 360;
m0 = null;
div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");
svg
.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
.selectAll("g.node text")
.attr("dx", function(d) { return (d.x + rotate) % 360 < 180 ? 8 : -8; })
.attr("text-anchor", function(d) { return (d.x + rotate) % 360 < 180 ? "start" : "end"; })
.attr("transform", function(d) { return (d.x + rotate) % 360 < 180 ? null : "rotate(180)"; });
}
}
function mouseover(d) {
svg.selectAll("path.link.target-" + d.key)
.classed("target", true)
.each(updateNodes("source", true));
svg.selectAll("path.link.source-" + d.key)
.classed("source", true)
.each(updateNodes("target", true));
}
function mouseout(d) {
svg.selectAll("path.link.source-" + d.key)
.classed("source", false)
.each(updateNodes("target", false));
svg.selectAll("path.link.target-" + d.key)
.classed("target", false)
.each(updateNodes("source", false));
}
function updateNodes(name, value) {
return function(d) {
if (value) this.parentNode.appendChild(this);
svg.select("#node-" + d[name].key).classed(name, value);
};
}
function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
</script>
</body>
</html>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
font: 10px sans-serif;
}
.link {
stroke: steelblue;
stroke-opacity: 0.6;
fill: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var diameter = 960,
radius = diameter / 2,
innerRadius = radius - 120;
var cluster = d3.layout.cluster()
.size([360, innerRadius])
.sort(null)
.value(function(d) { return d.size; });
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(0.55)
.radius(function(d) { return d.y; })
.angle(function(d) { return d.x / 180 * Math.PI; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
d3.json("readme-d3-imports.json", function(error, classes) {
var nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes);
svg.selectAll(".link")
.data(bundle(links))
.enter().append("path")
.attr("class", "link")
.attr("d", line);
svg.selectAll(".node")
.data(nodes.filter(function(n) { return !n.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
.append("text")
.attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
.text(function(d) { return d.key; });
});
d3.select(self.frameElement).style("height", diameter + "px");
var packages = {
// Lazily construct the package hierarchy from class names.
root: function(classes) {
var map = {};
function find(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
if (!node.parent.children) {
node.parent.children = [];
}
node.parent.children.push(node);
node.key = name.substr(3);//name.substring(i + 1);
}
}
return node;
}
classes.forEach(function(d) {
find(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function(nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function(d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function(d) {
if (d.imports) d.imports.forEach(function(i) {
imports.push({source: map[d.name], target: map[i]});
});
});
return imports;
}
};
</script>
(function() {
packages = {
// Lazily construct the package hierarchy from class names.
root: function(classes) {
var map = {};
function find(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
if (!node.parent.children) node.parent.children = [];
node.parent.children.push(node);
node.key = name.substring(3);
}
}
return node;
}
classes.forEach(function(d) {
find(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function(nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function(d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function(d) {
if (d.imports) d.imports.forEach(function(i) {
imports.push({source: map[d.name], target: map[i]});
});
});
return imports;
}
};
})();
body {
font: 300 36px "Helvetica Neue";
height: 640px;
margin: 80px 160px 80px 160px;
overflow: hidden;
position: relative;
width: 960px;
}
a:link, a:visited {
color: #777;
text-decoration: none;
}
a:hover {
color: #666;
}
blockquote {
margin: 0;
}
blockquote:before {
content: "“";
position: absolute;
left: -.4em;
}
blockquote:after {
content: "”";
position: absolute;
}
body > ul {
margin: 0;
padding: 0;
}
h1 {
font-size: 64px;
}
h1, h2, h3 {
font-weight: inherit;
margin: 0;
}
h2, h3 {
text-align: right;
font-size: inherit;
position: absolute;
bottom: 0;
right: 0;
}
h2 {
font-size: 24px;
position: absolute;
}
h3 {
bottom: -20px;
font-size: 18px;
}
.invert {
background: #1f1f1f;
color: #dcdccc;
}
.invert h2, .invert h3 {
color: #7f9f7f;
}
.string, .regexp {
color: #f39;
}
.keyword {
color: #00c;
}
.comment {
color: #777;
font-style: oblique;
}
.number {
color: #369;
}
.class, .special {
color: #1181B8;
}
body > svg {
position: absolute;
top: -80px;
left: -160px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment