Mouseover nodes to get details and stop the animation. An example of d3.layout.orbit that demonstrates different revolution speeds, different orbital scales and animation available in the layout.
-
-
Save mayblue9/6ad80afeba295fcd6326 to your computer and use it in GitHub Desktop.
Orbit Layout 4
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}; | |
function _orbitLayout() { | |
return _orbitLayout; | |
} | |
_orbitLayout.mode = function() { | |
//Atomic, Solar, other? | |
} | |
_orbitLayout.start = function() { | |
//activate animation here | |
tickInterval = setInterval( | |
function() { | |
currentTickStep++; | |
flattenedNodes.forEach(function(_node){ | |
if (_node.parent) { | |
_node.x = _node.parent.x + ( (_node.parent.ring / 2) * Math.sin( _node.angle + (currentTickStep * tickRadianStep * tickRadianFunction(_node))) ); | |
_node.y = _node.parent.y + ( (_node.parent.ring / 2) * 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() { | |
var _data = nestedNodes; | |
//If you have an array of elements, then create a root node (center) | |
//In the future, maybe make a binary star kind of thing? | |
if (!childrenAccessor(_data)) { | |
orbitNodes = {key: "root", values: _data} | |
childrenAccessor(orbitNodes).forEach(function (_node) { | |
_node.parent = orbitNodes; | |
}) | |
} | |
//otherwise assume it is an object with a root node | |
else { | |
orbitNodes = _data; | |
} | |
orbitNodes.x = orbitSize[0] / 2; | |
orbitNodes.y = orbitSize[1] / 2; | |
orbitNodes.deltaX = function(_x) {return _x} | |
orbitNodes.deltaY = function(_y) {return _y} | |
orbitNodes.ring = orbitSize[0] / 2; | |
orbitNodes.depth = 0; | |
flattenedNodes.push(orbitNodes); | |
traverseNestedData(orbitNodes) | |
function traverseNestedData(_node) { | |
if(childrenAccessor(_node)) { | |
var thisPie = d3.layout.pie().value(function(d) {return childrenAccessor(d) ? 4 : 1}); | |
var piedValues = thisPie(childrenAccessor(_node)); | |
orbitalRings.push({source: _node, x: _node.x, y: _node.y, r: _node.ring / 2}); | |
for (var x = 0; x<childrenAccessor(_node).length;x++) { | |
childrenAccessor(_node)[x].angle = ((piedValues[x].endAngle - piedValues[x].startAngle) / 2) + piedValues[x].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].deltaX = function(_x) {return _x} | |
childrenAccessor(_node)[x].deltaY = function(_y) {return _y} | |
childrenAccessor(_node)[x].ring = childrenAccessor(_node)[x].parent.ring / orbitDepthAdjust(_node); | |
flattenedNodes.push(childrenAccessor(_node)[x]); | |
traverseNestedData(childrenAccessor(_node)[x]); | |
} | |
} | |
} | |
} | |
} |
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": "flare", | |
"children": [ | |
{ | |
"name": "analytics", | |
"children": [ | |
{ | |
"name": "cluster", | |
"children": [ | |
{"name": "AgglomerativeCluster", "size": 3938}, | |
{"name": "CommunityStructure", "size": 3812}, | |
{"name": "HierarchicalCluster", "size": 6714}, | |
{"name": "MergeEdge", "size": 743} | |
] | |
}, | |
{ | |
"name": "graph", | |
"children": [ | |
{"name": "BetweennessCentrality", "size": 3534}, | |
{"name": "LinkDistance", "size": 5731}, | |
{"name": "MaxFlowMinCut", "size": 7840}, | |
{"name": "ShortestPaths", "size": 5914}, | |
{"name": "SpanningTree", "size": 3416} | |
] | |
}, | |
{ | |
"name": "optimization", | |
"children": [ | |
{"name": "AspectRatioBanker", "size": 7074} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "animate", | |
"children": [ | |
{"name": "Easing", "size": 17010}, | |
{"name": "FunctionSequence", "size": 5842}, | |
{ | |
"name": "interpolate", | |
"children": [ | |
{"name": "ArrayInterpolator", "size": 1983}, | |
{"name": "ColorInterpolator", "size": 2047}, | |
{"name": "DateInterpolator", "size": 1375}, | |
{"name": "Interpolator", "size": 8746}, | |
{"name": "MatrixInterpolator", "size": 2202}, | |
{"name": "NumberInterpolator", "size": 1382}, | |
{"name": "ObjectInterpolator", "size": 1629}, | |
{"name": "PointInterpolator", "size": 1675}, | |
{"name": "RectangleInterpolator", "size": 2042} | |
] | |
}, | |
{"name": "ISchedulable", "size": 1041}, | |
{"name": "Parallel", "size": 5176}, | |
{"name": "Pause", "size": 449}, | |
{"name": "Scheduler", "size": 5593}, | |
{"name": "Sequence", "size": 5534}, | |
{"name": "Transition", "size": 9201}, | |
{"name": "Transitioner", "size": 19975}, | |
{"name": "TransitionEvent", "size": 1116}, | |
{"name": "Tween", "size": 6006} | |
] | |
}, | |
{ | |
"name": "data", | |
"children": [ | |
{ | |
"name": "converters", | |
"children": [ | |
{"name": "Converters", "size": 721}, | |
{"name": "DelimitedTextConverter", "size": 4294}, | |
{"name": "GraphMLConverter", "size": 9800}, | |
{"name": "IDataConverter", "size": 1314}, | |
{"name": "JSONConverter", "size": 2220} | |
] | |
}, | |
{"name": "DataField", "size": 1759}, | |
{"name": "DataSchema", "size": 2165}, | |
{"name": "DataSet", "size": 586}, | |
{"name": "DataSource", "size": 3331}, | |
{"name": "DataTable", "size": 772}, | |
{"name": "DataUtil", "size": 3322} | |
] | |
}, | |
{ | |
"name": "display", | |
"children": [ | |
{"name": "DirtySprite", "size": 8833}, | |
{"name": "LineSprite", "size": 1732}, | |
{"name": "RectSprite", "size": 3623}, | |
{"name": "TextSprite", "size": 10066} | |
] | |
}, | |
{ | |
"name": "flex", | |
"children": [ | |
{"name": "FlareVis", "size": 4116} | |
] | |
}, | |
{ | |
"name": "physics", | |
"children": [ | |
{"name": "DragForce", "size": 1082}, | |
{"name": "GravityForce", "size": 1336}, | |
{"name": "IForce", "size": 319}, | |
{"name": "NBodyForce", "size": 10498}, | |
{"name": "Particle", "size": 2822}, | |
{"name": "Simulation", "size": 9983}, | |
{"name": "Spring", "size": 2213}, | |
{"name": "SpringForce", "size": 1681} | |
] | |
}, | |
{ | |
"name": "query", | |
"children": [ | |
{"name": "AggregateExpression", "size": 1616}, | |
{"name": "And", "size": 1027}, | |
{"name": "Arithmetic", "size": 3891}, | |
{"name": "Average", "size": 891}, | |
{"name": "BinaryExpression", "size": 2893}, | |
{"name": "Comparison", "size": 5103}, | |
{"name": "CompositeExpression", "size": 3677}, | |
{"name": "Count", "size": 781}, | |
{"name": "DateUtil", "size": 4141}, | |
{"name": "Distinct", "size": 933}, | |
{"name": "Expression", "size": 5130}, | |
{"name": "ExpressionIterator", "size": 3617}, | |
{"name": "Fn", "size": 3240}, | |
{"name": "If", "size": 2732}, | |
{"name": "IsA", "size": 2039}, | |
{"name": "Literal", "size": 1214}, | |
{"name": "Match", "size": 3748}, | |
{"name": "Maximum", "size": 843}, | |
{ | |
"name": "methods", | |
"children": [ | |
{"name": "add", "size": 593}, | |
{"name": "and", "size": 330}, | |
{"name": "average", "size": 287}, | |
{"name": "count", "size": 277}, | |
{"name": "distinct", "size": 292}, | |
{"name": "div", "size": 595}, | |
{"name": "eq", "size": 594}, | |
{"name": "fn", "size": 460}, | |
{"name": "gt", "size": 603}, | |
{"name": "gte", "size": 625}, | |
{"name": "iff", "size": 748}, | |
{"name": "isa", "size": 461}, | |
{"name": "lt", "size": 597}, | |
{"name": "lte", "size": 619}, | |
{"name": "max", "size": 283}, | |
{"name": "min", "size": 283}, | |
{"name": "mod", "size": 591}, | |
{"name": "mul", "size": 603}, | |
{"name": "neq", "size": 599}, | |
{"name": "not", "size": 386}, | |
{"name": "or", "size": 323}, | |
{"name": "orderby", "size": 307}, | |
{"name": "range", "size": 772}, | |
{"name": "select", "size": 296}, | |
{"name": "stddev", "size": 363}, | |
{"name": "sub", "size": 600}, | |
{"name": "sum", "size": 280}, | |
{"name": "update", "size": 307}, | |
{"name": "variance", "size": 335}, | |
{"name": "where", "size": 299}, | |
{"name": "xor", "size": 354}, | |
{"name": "_", "size": 264} | |
] | |
}, | |
{"name": "Minimum", "size": 843}, | |
{"name": "Not", "size": 1554}, | |
{"name": "Or", "size": 970}, | |
{"name": "Query", "size": 13896}, | |
{"name": "Range", "size": 1594}, | |
{"name": "StringUtil", "size": 4130}, | |
{"name": "Sum", "size": 791}, | |
{"name": "Variable", "size": 1124}, | |
{"name": "Variance", "size": 1876}, | |
{"name": "Xor", "size": 1101} | |
] | |
}, | |
{ | |
"name": "scale", | |
"children": [ | |
{"name": "IScaleMap", "size": 2105}, | |
{"name": "LinearScale", "size": 1316}, | |
{"name": "LogScale", "size": 3151}, | |
{"name": "OrdinalScale", "size": 3770}, | |
{"name": "QuantileScale", "size": 2435}, | |
{"name": "QuantitativeScale", "size": 4839}, | |
{"name": "RootScale", "size": 1756}, | |
{"name": "Scale", "size": 4268}, | |
{"name": "ScaleType", "size": 1821}, | |
{"name": "TimeScale", "size": 5833} | |
] | |
}, | |
{ | |
"name": "util", | |
"children": [ | |
{"name": "Arrays", "size": 8258}, | |
{"name": "Colors", "size": 10001}, | |
{"name": "Dates", "size": 8217}, | |
{"name": "Displays", "size": 12555}, | |
{"name": "Filter", "size": 2324}, | |
{"name": "Geometry", "size": 10993}, | |
{ | |
"name": "heap", | |
"children": [ | |
{"name": "FibonacciHeap", "size": 9354}, | |
{"name": "HeapNode", "size": 1233} | |
] | |
}, | |
{"name": "IEvaluable", "size": 335}, | |
{"name": "IPredicate", "size": 383}, | |
{"name": "IValueProxy", "size": 874}, | |
{ | |
"name": "math", | |
"children": [ | |
{"name": "DenseMatrix", "size": 3165}, | |
{"name": "IMatrix", "size": 2815}, | |
{"name": "SparseMatrix", "size": 3366} | |
] | |
}, | |
{"name": "Maths", "size": 17705}, | |
{"name": "Orientation", "size": 1486}, | |
{ | |
"name": "palette", | |
"children": [ | |
{"name": "ColorPalette", "size": 6367}, | |
{"name": "Palette", "size": 1229}, | |
{"name": "ShapePalette", "size": 2059}, | |
{"name": "SizePalette", "size": 2291} | |
] | |
}, | |
{"name": "Property", "size": 5559}, | |
{"name": "Shapes", "size": 19118}, | |
{"name": "Sort", "size": 6887}, | |
{"name": "Stats", "size": 6557}, | |
{"name": "Strings", "size": 22026} | |
] | |
}, | |
{ | |
"name": "vis", | |
"children": [ | |
{ | |
"name": "axis", | |
"children": [ | |
{"name": "Axes", "size": 1302}, | |
{"name": "Axis", "size": 24593}, | |
{"name": "AxisGridLine", "size": 652}, | |
{"name": "AxisLabel", "size": 636}, | |
{"name": "CartesianAxes", "size": 6703} | |
] | |
}, | |
{ | |
"name": "controls", | |
"children": [ | |
{"name": "AnchorControl", "size": 2138}, | |
{"name": "ClickControl", "size": 3824}, | |
{"name": "Control", "size": 1353}, | |
{"name": "ControlList", "size": 4665}, | |
{"name": "DragControl", "size": 2649}, | |
{"name": "ExpandControl", "size": 2832}, | |
{"name": "HoverControl", "size": 4896}, | |
{"name": "IControl", "size": 763}, | |
{"name": "PanZoomControl", "size": 5222}, | |
{"name": "SelectionControl", "size": 7862}, | |
{"name": "TooltipControl", "size": 8435} | |
] | |
}, | |
{ | |
"name": "data", | |
"children": [ | |
{"name": "Data", "size": 20544}, | |
{"name": "DataList", "size": 19788}, | |
{"name": "DataSprite", "size": 10349}, | |
{"name": "EdgeSprite", "size": 3301}, | |
{"name": "NodeSprite", "size": 19382}, | |
{ | |
"name": "render", | |
"children": [ | |
{"name": "ArrowType", "size": 698}, | |
{"name": "EdgeRenderer", "size": 5569}, | |
{"name": "IRenderer", "size": 353}, | |
{"name": "ShapeRenderer", "size": 2247} | |
] | |
}, | |
{"name": "ScaleBinding", "size": 11275}, | |
{"name": "Tree", "size": 7147}, | |
{"name": "TreeBuilder", "size": 9930} | |
] | |
}, | |
{ | |
"name": "events", | |
"children": [ | |
{"name": "DataEvent", "size": 2313}, | |
{"name": "SelectionEvent", "size": 1880}, | |
{"name": "TooltipEvent", "size": 1701}, | |
{"name": "VisualizationEvent", "size": 1117} | |
] | |
}, | |
{ | |
"name": "legend", | |
"children": [ | |
{"name": "Legend", "size": 20859}, | |
{"name": "LegendItem", "size": 4614}, | |
{"name": "LegendRange", "size": 10530} | |
] | |
}, | |
{ | |
"name": "operator", | |
"children": [ | |
{ | |
"name": "distortion", | |
"children": [ | |
{"name": "BifocalDistortion", "size": 4461}, | |
{"name": "Distortion", "size": 6314}, | |
{"name": "FisheyeDistortion", "size": 3444} | |
] | |
}, | |
{ | |
"name": "encoder", | |
"children": [ | |
{"name": "ColorEncoder", "size": 3179}, | |
{"name": "Encoder", "size": 4060}, | |
{"name": "PropertyEncoder", "size": 4138}, | |
{"name": "ShapeEncoder", "size": 1690}, | |
{"name": "SizeEncoder", "size": 1830} | |
] | |
}, | |
{ | |
"name": "filter", | |
"children": [ | |
{"name": "FisheyeTreeFilter", "size": 5219}, | |
{"name": "GraphDistanceFilter", "size": 3165}, | |
{"name": "VisibilityFilter", "size": 3509} | |
] | |
}, | |
{"name": "IOperator", "size": 1286}, | |
{ | |
"name": "label", | |
"children": [ | |
{"name": "Labeler", "size": 9956}, | |
{"name": "RadialLabeler", "size": 3899}, | |
{"name": "StackedAreaLabeler", "size": 3202} | |
] | |
}, | |
{ | |
"name": "layout", | |
"children": [ | |
{"name": "AxisLayout", "size": 6725}, | |
{"name": "BundledEdgeRouter", "size": 3727}, | |
{"name": "CircleLayout", "size": 9317}, | |
{"name": "CirclePackingLayout", "size": 12003}, | |
{"name": "DendrogramLayout", "size": 4853}, | |
{"name": "ForceDirectedLayout", "size": 8411}, | |
{"name": "IcicleTreeLayout", "size": 4864}, | |
{"name": "IndentedTreeLayout", "size": 3174}, | |
{"name": "Layout", "size": 7881}, | |
{"name": "NodeLinkTreeLayout", "size": 12870}, | |
{"name": "PieLayout", "size": 2728}, | |
{"name": "RadialTreeLayout", "size": 12348}, | |
{"name": "RandomLayout", "size": 870}, | |
{"name": "StackedAreaLayout", "size": 9121}, | |
{"name": "TreeMapLayout", "size": 9191} | |
] | |
}, | |
{"name": "Operator", "size": 2490}, | |
{"name": "OperatorList", "size": 5248}, | |
{"name": "OperatorSequence", "size": 4190}, | |
{"name": "OperatorSwitch", "size": 2581}, | |
{"name": "SortOperator", "size": 2023} | |
] | |
}, | |
{"name": "Visualization", "size": 16540} | |
] | |
} | |
] | |
} |
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>Orbits 3</title> | |
<meta charset="utf-8" /> | |
</head> | |
<style> | |
#viz, svg { | |
width: 1000px; | |
height: 1000px; | |
} | |
</style> | |
<script> | |
function makeViz() { | |
d3.json("flare.json", function(data) {drawOrbit(data)}); | |
} | |
function drawOrbit(_data) { | |
//down with category20a()!! | |
colors = d3.scale.category20b(); | |
orbitScale = d3.scale.linear().domain([1, 3]).range([3.8, 1.5]).clamp(true); | |
radiusScale = d3.scale.linear().domain([0,1,2,3]).range([20,10,3,1]).clamp(true); | |
orbit = d3.layout.orbit().size([1000,1000]) | |
.children(function(d) {return d.children}) | |
.revolution(function(d) {return d.depth}) | |
.orbitSize(function(d) {return orbitScale(d.depth)}) | |
.speed(.1) | |
.nodes(_data); | |
d3.select("svg").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("mouseout", nodeOut) | |
d3.selectAll("g.node") | |
.append("circle") | |
.attr("r", function(d) {return radiusScale(d.depth)}) | |
.style("fill", function(d) {return colors(d.depth)}) | |
d3.select("svg").selectAll("circle.orbits") | |
.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}) | |
.style("fill", "none") | |
.style("stroke", "black") | |
.style("stroke-width", "1px") | |
.style("stroke-opacity", .15) | |
orbit.on("tick", function() { | |
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}); | |
}); | |
orbit.start(); | |
function nodeOver(d) { | |
orbit.stop(); | |
d3.select(this).append("text").text(d.name).style("text-anchor", "middle").attr("y", 35); | |
d3.select(this).select("circle").style("stroke", "black").style("stroke-width", 3); | |
} | |
function nodeOut() { | |
orbit.start(); | |
d3.selectAll("text").remove(); | |
d3.selectAll("g.node > circle").style("stroke", "none").style("stroke-width", 0); | |
} | |
} | |
</script> | |
<body onload="makeViz()"> | |
<div id="viz"><svg></svg></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