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.
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.
| { | |
| "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"} | |
| ] | |
| } |
| 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; | |
| } | |
| } | |
| } | |
| } | |
| } |
| <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="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
| <script src="d3.layout.orbit.js" charset="utf-8" type="text/javascript"></script> | |
| </footer> | |
| </body> | |
| </html> |