license: gpl-3.0 |
redirect: https://observablehq.com/@d3/d3-collapsible-tree |
Collapsible Folder Tree With Pure JavaScript – jslists. A lightweight tree view plugin that displays hierarchical data in a collapsible, selectable tree structure with checkboxes. Parallax progress bar radio button range slider responsive menu scroll scroll animation scrollbar select side menu smooth scroll SVG switch tabs text. JSFiddle or its authors are not responsible or liable for any loss or damage of any kind during the usage of provided code. Bug tracker Roadmap (vote for features) About Docs Service status. Help keep us running. If you don't mind tech-related ads (no tracking or remarketing), and want to keep us running, whitelist JSFiddle in your blocker.
{ |
'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} |
] |
} |
] |
} |
<!DOCTYPE html> |
<metacharset='utf-8'> |
<style> |
.node { |
cursor: pointer; |
} |
.nodecircle { |
fill: #fff; |
stroke: steelblue; |
stroke-width: 1.5px; |
} |
.nodetext { |
font: 10pxsans-serif; |
} |
.link { |
fill: none; |
stroke: #ccc; |
stroke-width: 1.5px; |
} |
</style> |
<body> |
<scriptsrc='//d3js.org/d3.v3.min.js'></script> |
<script> |
var margin = {top:20, right:120, bottom:20, left:120}, |
width =960-margin.right-margin.left, |
height =800-margin.top-margin.bottom; |
var i =0, |
duration =750, |
root; |
var tree =d3.layout.tree() |
.size([height, width]); |
var diagonal =d3.svg.diagonal() |
.projection(function(d) { return [d.y, d.x]; }); |
var svg =d3.select('body').append('svg') |
.attr('width', width +margin.right+margin.left) |
.attr('height', height +margin.top+margin.bottom) |
.append('g') |
.attr('transform', 'translate('+margin.left+','+margin.top+')'); |
d3.json('flare.json', function(error, flare) { |
if (error) throw error; |
root = flare; |
root.x0= height /2; |
root.y0=0; |
functioncollapse(d) { |
if (d.children) { |
d._children=d.children; |
d._children.forEach(collapse); |
d.children=null; |
} |
} |
root.children.forEach(collapse); |
update(root); |
}); |
d3.select(self.frameElement).style('height', '800px'); |
functionupdate(source) { |
// Compute the new tree layout. |
var nodes =tree.nodes(root).reverse(), |
links =tree.links(nodes); |
// Normalize for fixed-depth. |
nodes.forEach(function(d) { d.y=d.depth*180; }); |
// Update the nodes… |
var node =svg.selectAll('g.node') |
.data(nodes, function(d) { returnd.id|| (d.id=++i); }); |
// Enter any new nodes at the parent's previous position. |
var nodeEnter =node.enter().append('g') |
.attr('class', 'node') |
.attr('transform', function(d) { return'translate('+source.y0+','+source.x0+')'; }) |
.on('click', click); |
nodeEnter.append('circle') |
.attr('r', 1e-6) |
.style('fill', function(d) { returnd._children?'lightsteelblue':'#fff'; }); |
nodeEnter.append('text') |
.attr('x', function(d) { returnd.children||d._children?-10:10; }) |
.attr('dy', '.35em') |
.attr('text-anchor', function(d) { returnd.children||d._children?'end':'start'; }) |
.text(function(d) { returnd.name; }) |
.style('fill-opacity', 1e-6); |
// Transition nodes to their new position. |
var nodeUpdate =node.transition() |
.duration(duration) |
.attr('transform', function(d) { return'translate('+d.y+','+d.x+')'; }); |
nodeUpdate.select('circle') |
.attr('r', 4.5) |
.style('fill', function(d) { returnd._children?'lightsteelblue':'#fff'; }); |
nodeUpdate.select('text') |
.style('fill-opacity', 1); |
// Transition exiting nodes to the parent's new position. |
var nodeExit =node.exit().transition() |
.duration(duration) |
.attr('transform', function(d) { return'translate('+source.y+','+source.x+')'; }) |
.remove(); |
nodeExit.select('circle') |
.attr('r', 1e-6); |
nodeExit.select('text') |
.style('fill-opacity', 1e-6); |
// Update the links… |
var link =svg.selectAll('path.link') |
.data(links, function(d) { returnd.target.id; }); |
// Enter any new links at the parent's previous position. |
link.enter().insert('path', 'g') |
.attr('class', 'link') |
.attr('d', function(d) { |
var o = {x:source.x0, y:source.y0}; |
returndiagonal({source: o, target: o}); |
}); |
// Transition links to their new position. |
link.transition() |
.duration(duration) |
.attr('d', diagonal); |
// Transition exiting nodes to the parent's new position. |
link.exit().transition() |
.duration(duration) |
.attr('d', function(d) { |
var o = {x:source.x, y:source.y}; |
returndiagonal({source: o, target: o}); |
}) |
.remove(); |
// Stash the old positions for transition. |
nodes.forEach(function(d) { |
d.x0=d.x; |
d.y0=d.y; |
}); |
} |
// Toggle children on click. |
functionclick(d) { |
if (d.children) { |
d._children=d.children; |
d.children=null; |
} else { |
d.children=d._children; |
d._children=null; |
} |
update(d); |
} |
</script> |
commented Jul 6, 2013
Awesome work. |
commented Jul 18, 2013
What are you using to structure your JSON for this? Edit: and yes. Awesome work for sure. |
commented Sep 10, 2013
Hi, I'm not and expert programming, but I copy and paste the HTML code in Dreamweaver and it doesn't work, what should I do to make ti work??? Thanks!! |
commented Sep 11, 2013
The file structure is the same as the collapsible force graph here: I think it is the same file, actually - readme.json You're going to need that file (or a similar one of your own) to run the script. |
commented Oct 21, 2013
hi , can i use the data call from the database to use the same design , really its awesome |
commented Jan 16, 2014
Hi, Can I have two separate parents links for a child. In the below example doctor1 should have a link to Hospital which has only link to Group Practice1.. |
commented Sep 8, 2014
HowTo go to a specified node? |
commented Sep 22, 2014
How can I change the distance between parent and child nodes so that I can fit more generations onto my graph? |
commented Jan 28, 2015
Can you please send the HTML code that invokes this Java script? It would be very helpful. Much Appreciated :) |
commented Jan 29, 2015
Is possible to change orientation of the tree? for example start in the bottom and grow to top? Amazing work! |
commented Jul 28, 2015
Hi @mbostock is there a license associated with this gist and in general all your gists on http://bl.ocks.org/mbostock ? |
commented Sep 16, 2015
Hi, Thanks. How do you add a new node from new json, like if I had a database query based upon my parent. Not asking for the database stuff, just how to add a new node in the toggleing function. Thanks again. |
commented Sep 20, 2015
I have been trying to implement this tree because of the collapsible capabilities but have no success. I've been working on it for a couple days now (I'm new to d3) and have only been able to get this one http://bl.ocks.org/d3noob/8324872 to work. Whenever I try the collapsible version, only a blank screen appears. Do you have any ideas why this would be happening? |
commented Mar 18, 2016
Thanks for the example, I use this with my own data. It works well. |
commented Jan 30, 2017
Is it possible to display the number of children each node has along with its name? |
commented Sep 6, 2017
Hai |
commented Aug 22, 2018
What you need to run this example. I save both flare.json and index.html in same local folder in my computer. Opening index.html with browser does not open any chart. Does it need to be run with flask ?? |
commented Sep 17, 2018 • edited
edited
Rohit, you need to do a couple of things to run successfully.
|
commented Jan 3, 2019
This looks awesome! But is there a way to run this locally without the need for a server? Trying to avoid the CORS issue but haven't been lucky so far when loading the data. Thanks! |
This tool creates SVG (Standard Vector Graphics) files to illustrateinformation structured as a basic tree.
Here I define tree as an ordered graph without loops where every node has zeroor one 'parent' nodes in the same tree.
It's a very common structure in computing and will be familiar to most as thestructure of folders on a personal computer (as seen in the 'Unix'example). It's also the structure of classes in a single-inheritance objectoriented programming language (as seen in the 'Java' example).
However lots of real world data can be formatted this way too. For instance an'org chart' of the hierarchy of an organization (because everyone has a boss,apart from the boss of the company).
Project
I wanted to visualize binary search trees to help understand a problem, but Icouldn't find a simple tool to take tree data as text and to output it as a linedrawing. I also became interested in the problem of arranging arbitrary treearrangements neatly, in the original breadthwise order, without overlapping andwith sensible spacing between elements. So, I decided to make a tree diagramtool myself.
It may be useful as a tool to generate diagrams of tree structures fordocuments, presentations and so forth, so I've put it online.
The tool is written in pure JavaScript and creates SVGs that all modern browserscan render. This means the scripts can also be dropped directly into webapplications that create tree data on the fly, as a reporting/visualizationtool. The source is freely licensed under GPL.
Use
To make your own diagrams all you have to do is visit one of the demo pages andedit the data (specified in classic tabular style, e.g:
This will generate the diagram below:
You can edit the options (provided as editable JSON in an edit box on the page)to customize the image in various ways. For instance setting 'flipXY': 1
will convert the image to a horizontal diagram.
I won't detail all the options here because it's designed for experimentation;just play with the values and see what you get. You can change the relativesize and margins of the nodes, line spacing in the labels, arrow size anddirection and more.
To change the colors or line styles of the nodes and arrows, or the label fontsize and style, simply edit the CSS data on the page. For instance, editing theCSS as follows...
.. would result in this diagram:
Method
The diagram generator has the task of building diagrams that have elementspositioned and spaced sensibly, without nodes or lines overlapping, and makingthe best use of available space (the nominated rectangle the diagram mayoccupy). Element positions need to be considered as a whole, as repositioningany element will have a knock-on effect on any other elements it might nowoverlap, free space to better position, and so on.
After experimentation I developed a relatively simple method with all nodeshaving their vertical position fixed in a level based on the distance to theirtree root. The horizontal positions are in order of the breath order of thenodes in the tree, but other than that, they are allowed to move horizontally.The method relies on identifying the one level which has least potential to berepositioned, laying this out with regular spacing and fitting the other levelsaround it.
Relative values are given in the options for the widths of nodes and the spacesbetween sibling nodes (nodes that share the same parent) and cousin nodes (nodesthat are the same distance from their roots but don't share the same parent).
The tree structure is converted into an array of levels.
Each level is measured for its minimum width given the spacing ratios in theoptions.
The level that occupies the most screen width is nominated as the fixedlevel.
All levels between the fixed level up to an including the root are nowconsidered in turn. For nodes that have children (in the level below) they aregiven an ideal horizontal position as the average (horizontally) of theirchildren.
A 'sweep' process then travels left to right across the nodes and forcing therightmost node of each considered pair further right to ensure that it is notpositioned too closely to its predecessor. As this may push nodes outside thediagram area, a return sweep performs the same operation from right to leftwith the rightmost element constrained to the available horizontal space.
These positions won't result in overlapping elements. However because of theway the sweep operates, elements will often result in nodes positionedimmediately to the right of neighbours when there is a large gap remainingthat could be occupied. In order to have nodes occupy the central position inthe available space, a third and fourth sweep are performed in mirror-image ofthe first two (right to left then left to right). Naturally after sweep fourthe elements are often positioned immediately to the left of neighbours. So,the positions after sweep two and sweep four are averaged to determine thefinal position of the nodes; non- overlapping and evenly positioned in theavailable space.
- A similar operation is performed on all the levels below the fixed leveltravelling downwards. On this occasion, the ideal horizontal position for thenodes is an even distribution of children underneath, with the group centeredon their parent node.
Contact
I hope some find the tool useful or interesting. Check out the site and asever, feel free to contact me at [email protected].