forked from emeeks's block: Orbital Layout of D3.js API
Created
November 8, 2015 15:00
-
-
Save wcjohnson11/7a0309cc11757a3e5b3e to your computer and use it in GitHub Desktop.
Orbital Layout of D3.js API
An example of d3.layout.orbit that visualizes the D3 API.
When you mouseover a node, it displays its label and centers the orbit layout on that node. It also draws spokes to children and parents where applicable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "d3", | |
"children": [ | |
{"name": "version"}, | |
{"name": "ascending"}, | |
{"name": "descending"}, | |
{"name": "min"}, | |
{"name": "max"}, | |
{"name": "extent"}, | |
{"name": "sum"}, | |
{"name": "mean"}, | |
{"name": "quantile"}, | |
{"name": "median"}, | |
{"name": "variance"}, | |
{"name": "deviation"}, | |
{"name": "bisectLeft"}, | |
{"name": "bisectRight"}, | |
{"name": "bisect"}, | |
{"name": "bisector"}, | |
{"name": "shuffle"}, | |
{"name": "permute"}, | |
{"name": "pairs"}, | |
{"name": "zip"}, | |
{"name": "transpose"}, | |
{"name": "keys"}, | |
{"name": "values"}, | |
{"name": "entries"}, | |
{"name": "merge"}, | |
{"name": "range"}, | |
{"name": "map"}, | |
{"name": "nest"}, | |
{"name": "set"}, | |
{ | |
"name": "behavior", | |
"children": [ | |
{"name": "drag"}, | |
{"name": "zoom"} | |
] | |
}, | |
{"name": "rebind"}, | |
{"name": "dispatch"}, | |
{"name": "event"}, | |
{"name": "requote"}, | |
{ | |
"name": "selection", | |
"children": [{"name": "enter"}] | |
}, | |
{ | |
"name": "ns", | |
"children": [ | |
{ | |
"name": "prefix", | |
"children": [ | |
{"name": "svg"}, | |
{"name": "xhtml"}, | |
{"name": "xlink"}, | |
{"name": "xml"}, | |
{"name": "xmlns"} | |
] | |
}, | |
{"name": "qualify"} | |
] | |
}, | |
{"name": "select"}, | |
{"name": "selectAll"}, | |
{"name": "mouse"}, | |
{"name": "touch"}, | |
{"name": "touches"}, | |
{"name": "interpolateZoom"}, | |
{"name": "color"}, | |
{"name": "hsl"}, | |
{"name": "hcl"}, | |
{"name": "lab"}, | |
{"name": "rgb"}, | |
{"name": "functor"}, | |
{"name": "xhr"}, | |
{"name": "dsv"}, | |
{ | |
"name": "csv", | |
"children": [ | |
{"name": "parse"}, | |
{"name": "parseRows"}, | |
{"name": "format"}, | |
{"name": "formatRows"} | |
] | |
}, | |
{ | |
"name": "tsv", | |
"children": [ | |
{"name": "parse"}, | |
{"name": "parseRows"}, | |
{"name": "format"}, | |
{"name": "formatRows"} | |
] | |
}, | |
{ | |
"name": "timer", | |
"children": [{"name": "flush"}] | |
}, | |
{"name": "round"}, | |
{"name": "formatPrefix"}, | |
{ | |
"name": "time", | |
"children": [ | |
{ | |
"name": "year", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "years", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "day", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "days", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "dayOfYear"}, | |
{ | |
"name": "sunday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "sundays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "sundayOfYear"}, | |
{ | |
"name": "monday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "mondays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "mondayOfYear"}, | |
{ | |
"name": "tuesday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "tuesdays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "tuesdayOfYear"}, | |
{ | |
"name": "wednesday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "wednesdays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "wednesdayOfYear"}, | |
{ | |
"name": "thursday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "thursdays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "thursdayOfYear"}, | |
{ | |
"name": "friday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "fridays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "fridayOfYear"}, | |
{ | |
"name": "saturday", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "saturdays", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "saturdayOfYear"}, | |
{ | |
"name": "week", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "weeks", | |
"children": [{"name": "utc"}] | |
}, | |
{"name": "weekOfYear"}, | |
{ | |
"name": "format", | |
"children": [ | |
{ | |
"name": "utc", | |
"children": [{"name": "multi"}] | |
}, | |
{"name": "multi"}, | |
{ | |
"name": "iso", | |
"children": [ | |
{"name": "parse"}, | |
{"name": "toString"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "second", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "seconds", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "minute", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "minutes", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "hour", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "hours", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "month", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{ | |
"name": "range", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "utc", | |
"children": [ | |
{"name": "round"}, | |
{"name": "ceil"}, | |
{"name": "offset"}, | |
{"name": "range"} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "months", | |
"children": [{"name": "utc"}] | |
}, | |
{ | |
"name": "scale", | |
"children": [{"name": "utc"}] | |
} | |
] | |
}, | |
{"name": "locale"}, | |
{"name": "format"}, | |
{ | |
"name": "geo", | |
"children": [ | |
{"name": "stream"}, | |
{"name": "area"}, | |
{"name": "bounds"}, | |
{"name": "centroid"}, | |
{"name": "clipExtent"}, | |
{ | |
"name": "conicEqualArea", | |
"children": [{"name": "raw"}] | |
}, | |
{"name": "albers"}, | |
{"name": "albersUsa"}, | |
{"name": "path"}, | |
{"name": "transform"}, | |
{"name": "projection"}, | |
{"name": "projectionMutator"}, | |
{ | |
"name": "equirectangular", | |
"children": [{"name": "raw"}] | |
}, | |
{"name": "rotation"}, | |
{"name": "circle"}, | |
{"name": "distance"}, | |
{"name": "graticule"}, | |
{"name": "greatArc"}, | |
{"name": "interpolate"}, | |
{"name": "length"}, | |
{ | |
"name": "azimuthalEqualArea", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "azimuthalEquidistant", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "conicConformal", | |
"children": [{"name": "raw"}] | |
}, | |
{ | |
"name": "conicEquidistant", | |
"children": [{"name": "raw"}] | |
}, | |
{ | |
"name": "gnomonic", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "mercator", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "orthographic", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "stereographic", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
}, | |
{ | |
"name": "transverseMercator", | |
"children": [ | |
{ | |
"name": "raw", | |
"children": [{"name": "invert"}] | |
} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "geom", | |
"children": [ | |
{"name": "hull"}, | |
{"name": "polygon"}, | |
{"name": "voronoi"}, | |
{"name": "delaunay"}, | |
{"name": "quadtree"} | |
] | |
}, | |
{"name": "interpolateRgb"}, | |
{"name": "interpolateObject"}, | |
{"name": "interpolateNumber"}, | |
{"name": "interpolateString"}, | |
{"name": "interpolate"}, | |
{"name": "interpolators"}, | |
{"name": "interpolateArray"}, | |
{"name": "ease"}, | |
{"name": "interpolateHcl"}, | |
{"name": "interpolateHsl"}, | |
{"name": "interpolateLab"}, | |
{"name": "interpolateRound"}, | |
{"name": "transform"}, | |
{"name": "interpolateTransform"}, | |
{ | |
"name": "layout", | |
"children": [ | |
{"name": "bundle"}, | |
{"name": "chord"}, | |
{"name": "force"}, | |
{"name": "hierarchy"}, | |
{"name": "partition"}, | |
{"name": "pie"}, | |
{"name": "stack"}, | |
{"name": "histogram"}, | |
{"name": "pack"}, | |
{"name": "tree"}, | |
{"name": "cluster"}, | |
{"name": "treemap"} | |
] | |
}, | |
{ | |
"name": "random", | |
"children": [ | |
{"name": "normal"}, | |
{"name": "logNormal"}, | |
{"name": "bates"}, | |
{"name": "irwinHall"} | |
] | |
}, | |
{ | |
"name": "scale", | |
"children": [ | |
{"name": "linear"}, | |
{"name": "log"}, | |
{"name": "pow"}, | |
{"name": "sqrt"}, | |
{"name": "ordinal"}, | |
{"name": "category10"}, | |
{"name": "category20"}, | |
{"name": "category20b"}, | |
{"name": "category20c"}, | |
{"name": "quantile"}, | |
{"name": "quantize"}, | |
{"name": "threshold"}, | |
{"name": "identity"} | |
] | |
}, | |
{ | |
"name": "svg", | |
"children": [ | |
{"name": "arc"}, | |
{ | |
"name": "line", | |
"children": [{"name": "radial"}] | |
}, | |
{ | |
"name": "area", | |
"children": [{"name": "radial"}] | |
}, | |
{"name": "chord"}, | |
{ | |
"name": "diagonal", | |
"children": [{"name": "radial"}] | |
}, | |
{"name": "symbol"}, | |
{"name": "symbolTypes"}, | |
{"name": "axis"}, | |
{"name": "brush"} | |
] | |
}, | |
{"name": "transition"}, | |
{"name": "text"}, | |
{"name": "json"}, | |
{"name": "html"}, | |
{"name": "xml"}, | |
{"name": "hexbin"} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d3.layout.orbit = function() { | |
var currentTickStep = 0; | |
var orbitNodes; | |
var orbitSize = [1,1]; | |
var nestedNodes; | |
var flattenedNodes = []; | |
var tickRadianStep = 0.004363323129985824; | |
var orbitDispatch = d3.dispatch('tick'); | |
var tickInterval; | |
var orbitalRings = []; | |
var orbitDepthAdjust = function() {return 2.95}; | |
var childrenAccessor = function(d) {return d.children}; | |
var tickRadianFunction = function() {return 1}; | |
var fixedOrbitArray = [99]; | |
var orbitMode = "flat"; | |
function _orbitLayout() { | |
return _orbitLayout; | |
} | |
_orbitLayout.mode = function(_mode) { | |
//Atomic, Solar, other? | |
if (!arguments.length) return orbitMode; | |
if (_mode == "solar") { | |
fixedOrbitArray = [1] | |
} | |
if (_mode == "atomic") { | |
fixedOrbitArray = [2,8] | |
} | |
if (_mode == "flat") { | |
fixedOrbitArray = [99] | |
} | |
orbitMode = _mode; | |
if (Array.isArray(_mode)) { | |
fixedOrbitArray = _mode; | |
orbitMode = "custom"; | |
} | |
return this | |
} | |
_orbitLayout.start = function() { | |
//activate animation here | |
tickInterval = setInterval( | |
function() { | |
currentTickStep++; | |
flattenedNodes.forEach(function(_node){ | |
if (_node.parent) { | |
_node.x = _node.parent.x + ( (_node.ring) * Math.sin( _node.angle + (currentTickStep * tickRadianStep * tickRadianFunction(_node))) ); | |
_node.y = _node.parent.y + ( (_node.ring) * Math.cos( _node.angle + (currentTickStep * tickRadianStep * tickRadianFunction(_node))) ); | |
} | |
}) | |
orbitalRings.forEach(function(_ring) { | |
_ring.x = _ring.source.x; | |
_ring.y = _ring.source.y; | |
}) | |
orbitDispatch.tick(); | |
}, | |
10); | |
} | |
_orbitLayout.stop = function() { | |
//deactivate animation here | |
clearInterval(tickInterval); | |
} | |
_orbitLayout.speed = function(_degrees) { | |
if (!arguments.length) return tickRadianStep / (Math.PI / 360); | |
tickRadianStep = tickRadianStep = _degrees * (Math.PI / 360); | |
return this; | |
} | |
_orbitLayout.size = function(_value) { | |
if (!arguments.length) return orbitSize; | |
orbitSize = _value; | |
return this; | |
//change size here | |
} | |
_orbitLayout.revolution = function(_function) { | |
//change ring size reduction (make that into dynamic function) | |
if (!arguments.length) return tickRadianFunction; | |
tickRadianFunction = _function; | |
return this | |
} | |
_orbitLayout.orbitSize = function(_function) { | |
//change ring size reduction (make that into dynamic function) | |
if (!arguments.length) return orbitDepthAdjust; | |
orbitDepthAdjust = _function; | |
return this | |
} | |
_orbitLayout.orbitalRings = function() { | |
//return an array of data corresponding to orbital rings | |
if (!arguments.length) return orbitalRings; | |
return this; | |
} | |
_orbitLayout.nodes = function(_data) { | |
if (!arguments.length) return flattenedNodes; | |
nestedNodes = _data; | |
calculateNodes(); | |
return this; | |
} | |
_orbitLayout.children = function(_function) { | |
if (!arguments.length) return childrenAccessor; | |
//Probably should use d3.functor to turn a string into an object key | |
childrenAccessor = _function; | |
return this; | |
} | |
d3.rebind(_orbitLayout, orbitDispatch, "on"); | |
return _orbitLayout; | |
function calculateNodes() { | |
orbitalRings = []; | |
orbitNodes = nestedNodes; | |
orbitNodes.x = orbitSize[0] / 2; | |
orbitNodes.y = orbitSize[1] / 2; | |
orbitNodes.ring = orbitSize[0] / 2; | |
orbitNodes.depth = 0; | |
flattenedNodes.push(orbitNodes); | |
traverseNestedData(orbitNodes); | |
function traverseNestedData(_node) { | |
if(childrenAccessor(_node)) { | |
var y = 0; | |
var totalChildren = childrenAccessor(_node).length; | |
var _rings = 0; | |
var _total_positions = 0; | |
var _p = 0; | |
while (_total_positions < totalChildren) { | |
if (fixedOrbitArray[_p]) { | |
_total_positions += fixedOrbitArray[_p]; | |
} | |
else { | |
_total_positions += fixedOrbitArray[fixedOrbitArray.length - 1]; | |
} | |
_p++; | |
_rings++; | |
} | |
while (y < totalChildren) { | |
var _pos = 0; | |
var _currentRing = 0; | |
var _p = 0; | |
var _total_positions = 0; | |
while (_total_positions <= y) { | |
if (fixedOrbitArray[_p]) { | |
_total_positions += fixedOrbitArray[_p]; | |
} | |
else { | |
_total_positions += fixedOrbitArray[fixedOrbitArray.length-1]; | |
} | |
_p++; | |
_currentRing++; | |
} | |
var ringSize = fixedOrbitArray[fixedOrbitArray.length-1]; | |
if (fixedOrbitArray[_currentRing-1]) { | |
ringSize = fixedOrbitArray[_currentRing-1]; | |
} | |
if (_node.parent) { | |
var _ring = {source: _node, x: _node.x, y: _node.y, r: _node.parent.ring / orbitDepthAdjust(_node) * (_currentRing / _rings)}; | |
} | |
else { | |
var _ring = {source: _node, x: _node.x, y: _node.y, r: (orbitSize[0] / 2) * (_currentRing / _rings)}; | |
} | |
var thisPie = d3.layout.pie().value(function(d) {return childrenAccessor(d) ? 4 : 1}); | |
var piedValues = thisPie(childrenAccessor(_node).filter(function(d,i) {return i >= y && i <= y+ringSize-1})); | |
for (var x = y; x<y+ringSize && x<totalChildren;x++) { | |
childrenAccessor(_node)[x].angle = ((piedValues[x - y].endAngle - piedValues[x - y].startAngle) / 2) + piedValues[x - y].startAngle; | |
childrenAccessor(_node)[x].parent = _node; | |
childrenAccessor(_node)[x].depth = _node.depth + 1; | |
childrenAccessor(_node)[x].x = childrenAccessor(_node)[x].parent.x + ( (childrenAccessor(_node)[x].parent.ring / 2) * Math.sin( childrenAccessor(_node)[x].angle ) ); | |
childrenAccessor(_node)[x].y = childrenAccessor(_node)[x].parent.y + ( (childrenAccessor(_node)[x].parent.ring / 2) * Math.cos( childrenAccessor(_node)[x].angle ) ); | |
childrenAccessor(_node)[x].ring = _ring.r; | |
flattenedNodes.push(childrenAccessor(_node)[x]); | |
traverseNestedData(childrenAccessor(_node)[x]); | |
} | |
orbitalRings.push(_ring); | |
y+=ringSize; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<title>Orbit Layout Modes</title> | |
<meta charset="utf-8" /> | |
</head> | |
<style> | |
#viz, svg { | |
width: 100%; | |
height: 100%; | |
} | |
text { | |
pointer-events: none; | |
} | |
#buttons { | |
position: fixed; | |
top:0; | |
left:0; | |
} | |
circle.ring { | |
fill: none; | |
stroke: black; | |
stroke-width: 1px; | |
stroke-opacity: .15; | |
} | |
</style> | |
<script> | |
function makeViz() { | |
d3.json("d3.json", function(data) {drawOrbit(data)}); | |
} | |
function drawOrbit(_data) { | |
var center = {}; | |
var recenter = false; | |
for (var x=0;x<_data.children.length;x++) { | |
_data.children[x].size = _data.children[x].children ? _data.children[x].children.length : 0; | |
} | |
_data.children.sort(function(a,b) { | |
if (a.size > b.size) { | |
return 1; | |
} | |
if (a.size < b.size) { | |
return -1; | |
} | |
return 0; | |
}) | |
sizeScale = d3.scale.linear().domain([0,1,5,10,20]).range([4,6,8,10,12]).clamp(true); | |
colorScale = d3.scale.linear().domain([0,1,2,3,4]).range(["rgb(161,208,120)","rgb(247,148,72)","rgb(225,203,208)","rgb(174,223,228)","rgb(245,132,102)"]); | |
planetColors = {Mercury: "gray", Venus: "#d6bb87", Earth: "#677188", Mars: "#7c5541", Jupiter: "#a36a3e", Saturn: "#e9ba85", Uranus: "#73cbf0", Neptune: "#6383d1"} | |
orbit = d3.layout.orbit().size([800,800]) | |
.revolution(customRevolution) | |
.orbitSize(function(d) {return d.depth >= 2 ? 6 : 4}) | |
.speed(.25) | |
.mode([35,36,8,3,1]) | |
.nodes(_data); | |
center = orbit.nodes()[0]; | |
d3.select("svg") | |
.append("g") | |
.attr("class", "viz") | |
.attr("transform", "translate(50,50)") | |
.selectAll("g.node").data(orbit.nodes()) | |
.enter() | |
.append("g") | |
.attr("class", "node") | |
.attr("transform", function(d) {return "translate(" +d.x +"," + d.y+")"}) | |
.on("mouseover", nodeOver) | |
.on("click", recenter) | |
d3.selectAll("g.node") | |
.append("circle") | |
.attr("class", "satellite") | |
.attr("r", function(d) {return sizeScale(d.children ? d.children.length : 0)}) | |
.style("fill", function(d) {return colorScale(d.depth)}) | |
.style("stroke", "brown") | |
.style("stroke-width", "1px") | |
d3.selectAll("g.node").filter(function(d) {return d.depth == 1}) | |
.append("text") | |
.text(function(d) {return d.depth == 0 ? "Sun" : d.key}) | |
.attr("y", 20) | |
.style("text-anchor", "middle") | |
d3.select("g.viz") | |
.selectAll("circle.ring") | |
.data(orbit.orbitalRings()) | |
.enter() | |
.insert("circle", "g") | |
.attr("class", "ring") | |
.attr("r", function(d) {return d.r}) | |
.attr("cx", function(d) {return d.x}) | |
.attr("cy", function(d) {return d.y}) | |
orbit.on("tick", orbitTick); | |
orbit.start(); | |
function orbitTick() { | |
var newX = 200- center.x; | |
var newY = 200 - center.y; | |
d3.select("g.viz") | |
.attr("transform", "scale("+(1 + (center.depth *.1)) +") translate(" + newX + "," + newY + ")") | |
d3.selectAll("g.node") | |
.attr("transform", function(d) {return "translate(" +d.x +"," + d.y+")"}); | |
d3.selectAll("circle.ring") | |
.attr("cx", function(d) {return d.x}) | |
.attr("cy", function(d) {return d.y}); | |
d3.selectAll("line.visible") | |
.attr("x1", function(p) {return p.source.x}) | |
.attr("x2", function(p) {return p.target.x}) | |
.attr("y1", function(p) {return p.source.y}) | |
.attr("y2", function(p) {return p.target.y}) | |
} | |
function changeCenter() { | |
recenter = false; | |
orbit.stop(); | |
var newX = 200 - center.x; | |
var newY = 200 - center.y; | |
d3.select("g.viz") | |
.transition() | |
.duration(1000) | |
.attr("transform", "scale("+(1 + (center.depth *.1)) +") translate(" + newX + "," + newY + ")") | |
.each("end", function() {orbit.start()}) | |
} | |
function customRevolution(d) | |
{ | |
if (d.name == "time") { | |
return d.depth * .25; | |
} | |
if (d.name == "geo") { | |
return -d.depth * .25; | |
} | |
return d.depth | |
} | |
function nodeOver(d) { | |
orbit.stop(); | |
center = d; | |
changeCenter(); | |
d3.selectAll("text.sat").remove(); | |
d3.selectAll("line.visible").remove(); | |
if (d.children) { | |
var lines = d.children.map(function(p) {return {source: d, target: p}}) | |
d3.select("g.viz").selectAll("line.visible") | |
.data(lines) | |
.enter() | |
.insert("line", "g") | |
.attr("x1", function(p) {return p.source.x}) | |
.attr("x2", function(p) {return p.target.x}) | |
.attr("y1", function(p) {return p.source.y}) | |
.attr("y2", function(p) {return p.target.y}) | |
.attr("class", "visible") | |
.style("stroke", "rgb(73,106,154)") | |
.style("stroke-width", 2) | |
} | |
if (d.parent) { | |
d3.select("g.viz").selectAll("line.fake") | |
.data([{source:d, target: d.parent}]) | |
.enter() | |
.insert("line", "g") | |
.attr("x1", function(p) {return p.source.x}) | |
.attr("x2", function(p) {return p.target.x}) | |
.attr("y1", function(p) {return p.source.y}) | |
.attr("y2", function(p) {return p.target.y}) | |
.attr("class", "visible") | |
.style("stroke", "rgb(165,127,124)") | |
.style("stroke-width", 3) | |
} | |
d3.selectAll("g.node") | |
.filter(function(p) {return p == d || p == d.parent || (d.children ? d.children.indexOf(p) > -1 : false)}) | |
.append("text") | |
.text(function(p) {return p.name}) | |
.style("text-anchor", "middle") | |
.attr("y", 15) | |
.attr("class", "sat") | |
.style("fill", "none") | |
.style("stroke", "white") | |
.style("stroke-width", 3) | |
.style("stroke-opacity", .7); | |
d3.selectAll("g.node") | |
.filter(function(p) {return p == d || p == d.parent || (d.children ? d.children.indexOf(p) > -1 : false)}) | |
.append("text") | |
.text(function(p) {return p.name}) | |
.style("text-anchor", "middle") | |
.attr("y", 15) | |
.attr("class", "sat"); | |
d3.selectAll("g.node > circle").style("stroke", "brown").style("stroke-width", 1); | |
d3.select(this).select("circle").style("stroke", "black").style("stroke-width", 3); | |
} | |
} | |
</script> | |
<body onload="makeViz()"> | |
<div id="viz"><svg></svg><div id="buttons"></div></div> | |
<footer> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8" type="text/javascript"></script> | |
<script src="d3.layout.orbit.js" charset="utf-8" type="text/javascript"></script> | |
</footer> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment