|
|
|
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
|
|
|
|
<meta http-equiv="Pragma" content="no-cache" />
|
|
|
|
|
<meta http-equiv="Expires" content="0" />
|
|
|
|
|
<link rel="canonical" href="http://d3js.org/">
|
|
|
|
|
<title>cola.js: Constraint-based Layout in the Browser</title>
|
|
|
|
|
<style>
|
|
|
|
|
|
|
|
|
|
@import url(style.css);
|
|
|
|
|
|
|
|
|
|
#examples {
|
|
|
|
|
width: 960px;
|
|
|
|
|
height: 189px;
|
|
|
|
|
margin-bottom: 2em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.examplecontainer {
|
|
|
|
|
width: 226px;
|
|
|
|
|
height: 180px;
|
|
|
|
|
float: left
|
|
|
|
|
}
|
|
|
|
|
.example img {
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
margin-top: auto;
|
|
|
|
|
margin-bottom: auto;
|
|
|
|
|
max-width: 90%;
|
|
|
|
|
max-height: 90%;
|
|
|
|
|
height: auto;
|
|
|
|
|
border: solid 2px #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.example:hover img {
|
|
|
|
|
border-color: steelblue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.example:not(:nth-child(4n)) img {
|
|
|
|
|
margin-right: 13px;
|
|
|
|
|
}
|
|
|
|
|
#left {
|
|
|
|
|
float: right;
|
|
|
|
|
width: 50%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#right {
|
|
|
|
|
margin-right: 50%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<div id="body">
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<b><a href="./">Overview</a></b>
|
|
|
|
|
<a style="margin-left:1em;" href="https://github.com/tgdwyer/WebCola/wiki">Wiki</a>
|
|
|
|
|
<a style="margin-left:1em;" href="http://marvl.infotech.monash.edu/webcola/doc/index.html">API</a>
|
|
|
|
|
<a style="margin-left:1em;" href="https://github.com/tgdwyer/WebCola">Source</a>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<h1>cola.js</h1>
|
|
|
|
|
<h2>Constraint-Based Layout in the Browser</h2>
|
|
|
|
|
|
|
|
|
|
<div id="examples"></div>
|
|
|
|
|
|
|
|
|
|
<script src="extern/d3.v3.min.js?3.0.0rc1"></script>
|
|
|
|
|
<link rel="stylesheet" href="extern/hljs/styles/github.css">
|
|
|
|
|
<script src="extern/hljs/highlight.pack.js"></script>
|
|
|
|
|
<script>
|
|
|
|
|
hljs.initHighlightingOnLoad();
|
|
|
|
|
|
|
|
|
|
var examples = [
|
|
|
|
|
"downwardedges",
|
|
|
|
|
"unconstrained",
|
|
|
|
|
"unconstrainedsmallworld",
|
|
|
|
|
"nonoverlapping",
|
|
|
|
|
"smallnonoverlappinggraph",
|
|
|
|
|
"modifyinggraph",
|
|
|
|
|
"onlinebrowse",
|
|
|
|
|
"alignment",
|
|
|
|
|
"smallgroups",
|
|
|
|
|
"browsemovies.gif",
|
|
|
|
|
"SucroseBreakdown",
|
|
|
|
|
"unix",
|
|
|
|
|
"ariel",
|
|
|
|
|
"egonetwork",
|
|
|
|
|
"disconnected_graphs",
|
|
|
|
|
"powergraph",
|
|
|
|
|
"3dLayout.gif",
|
|
|
|
|
"dotpowergraph",
|
|
|
|
|
"gridifiedSmallGroups",
|
|
|
|
|
"3dtree.gif",
|
|
|
|
|
"cygenegene.gif",
|
|
|
|
|
"pageBoundsConstraints",
|
|
|
|
|
"smallworldwithgroups",
|
|
|
|
|
"brainnetwork2.gif"
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
function shuffle(array) {
|
|
|
|
|
var m = array.length, t, i;
|
|
|
|
|
|
|
|
|
|
// While there remain elements to shuffle.
|
|
|
|
|
while (m) {
|
|
|
|
|
|
|
|
|
|
// Pick a remaining element.
|
|
|
|
|
i = Math.floor(Math.random() * m--);
|
|
|
|
|
|
|
|
|
|
// And swap it with the current element.
|
|
|
|
|
t = array[m];
|
|
|
|
|
array[m] = array[i];
|
|
|
|
|
array[i] = t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
d3.select("#examples").selectAll(".example")
|
|
|
|
|
.data(shuffle(examples).slice(0, 24))
|
|
|
|
|
.enter()
|
|
|
|
|
.append('div')
|
|
|
|
|
.attr('class', 'examplecontainer')
|
|
|
|
|
.append("a")
|
|
|
|
|
.attr("class", "example")
|
|
|
|
|
.attr("href", function (d) {
|
|
|
|
|
return "examples/" + (d.match(/\.gif/) ? d.slice(0, -4) : d) + ".html"
|
|
|
|
|
})
|
|
|
|
|
.append("img")
|
|
|
|
|
.attr("src", function (d) {
|
|
|
|
|
return "examples/" + d + (d.match(/\.gif/) ? '' : ".png")
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<!--<p><aside>See <a href="https://github.com/mbostock/d3/wiki/Gallery">more examples</a>.</aside>-->
|
|
|
|
|
|
|
|
|
|
<p><b>cola.js</b> (A.K.A. "WebCoLa") is an <a href="https://raw.github.com/tgdwyer/WebCola/master/LICENSE">open-source</a> JavaScript library for arranging your HTML5 documents and diagrams using constraint-based optimization techniques.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
It works well with libraries like <a href="http://d3js.org">D3.js</a>, <a href="http://www.svgjs.com">svg.js</a>, and <a href="http://js.cytoscape.org">Cytoscape.js</a>.
|
|
|
|
|
The core layout is based on a complete rewrite in Javascript of the C++ <a href="http://adaptagrams.org">libcola</a> library.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<aside>
|
|
|
|
|
<p>
|
|
|
|
|
<b>cola.js</b> is developed by <br /><a href="http://marvl.infotech.monash.edu/~dwyer">Tim Dwyer</a> at the <a href="http://marvl.infotech.monash.edu">
|
|
|
|
|
Monash Adaptive Visualisation Lab.
|
|
|
|
|
<img src="http://marvl.infotech.monash.edu.au/wp-content/themes/marvl/marvl.png" width="155px" alt="MArVL Logo" />
|
|
|
|
|
</a>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
Additional contributions gratefully received from:
|
|
|
|
|
<ul> <li>Maxim Shishmarev</li>
|
|
|
|
|
<li>Nicholas Smith</li>
|
|
|
|
|
<li><a href="https://github.com/bollwyvl">bollwyvl</a></li>
|
|
|
|
|
<li><a href="https://github.com/Craxic">Matt Ready</a></li>
|
|
|
|
|
<li><a href="https://github.com/maxkfranz">Max Franz</a></li>
|
|
|
|
|
</ul>
|
|
|
|
|
</p>
|
|
|
|
|
</aside>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
It also has an adaptor for d3.js that allows you to use cola as a drop-in replacement for the <a href="https://github.com/mbostock/d3/wiki/Force-Layout">D3 force layout</a>.
|
|
|
|
|
The layout converges to a local optimum unlike the D3 force layout, which forces convergence through a simple annealing strategy.
|
|
|
|
|
Thus, compared to D3 force layout:
|
|
|
|
|
<ul>
|
|
|
|
|
<li>CoLa achieves higher quality layout;</li>
|
|
|
|
|
<li>is much more stable in <a href="examples/browsemovies.html">interactive applications</a> (no "jitter");</li>
|
|
|
|
|
<li>it allows user specified constraints such as <a href="examples/alignment.html">alignments</a> and <a href="examples/smallgroups.html">grouping</a>;</li>
|
|
|
|
|
<li>it can automatically generate constraints to:
|
|
|
|
|
<ul>
|
|
|
|
|
<li><a href="examples/smallnonoverlappinggraph.html">avoid overlapping nodes</a>; or</li>
|
|
|
|
|
<li> provide <a href="examples/unix.html">flow layout for directed graphs</a>;</li>
|
|
|
|
|
</ul> </li>
|
|
|
|
|
<li>it may be less scalable to very large graphs.</li>
|
|
|
|
|
</ul>
|
|
|
|
|
However, it works well on an average machine on graphs with fewer than 100 nodes.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<aside><b>⇐ NEW! NUOVO! NOUVEAU!</b>
|
|
|
|
|
</aside> <p>
|
|
|
|
|
cola.js can now (optionally) <a href="examples/unix.html">route edges to avoid intersections with node boundaries</a>.
|
|
|
|
|
</p>
|
|
|
|
|
<h2>Getting Started with D3</h2>
|
|
|
|
|
<p>
|
|
|
|
|
Replacing D3 force layout with cola.js is easy. Include the following in your html:
|
|
|
|
|
<pre><code class="html"><script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script></code></pre>
|
|
|
|
|
</p>
|
|
|
|
|
<p>Or, if you don't like your javascript files being loaded from Australia, then host the cola.v3.min.js file locally.</p>
|
|
|
|
|
<p>Then replace D3 force with cola as follows:</p>
|
|
|
|
|
<table>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>D3 force setup:</td>
|
|
|
|
|
<td>cola setup:</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<pre><code>var force = d3.layout.force()
|
|
|
|
|
.charge(-120)
|
|
|
|
|
.linkDistance(30)
|
|
|
|
|
.size([width, height]);
|
|
|
|
|
</code></pre>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<pre><code>var d3cola = cola.d3adaptor()
|
|
|
|
|
.linkDistance(30)
|
|
|
|
|
.size([width, height]);
|
|
|
|
|
</code></pre>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
<p>You then use <code>cola</code> as you would <code>force</code> (or just continue to call it <code>force</code> if you don't care what it's actually doing as much as me).</p>
|
|
|
|
|
<p>
|
|
|
|
|
Note that while with D3 force layout you may have had to mess with parameters like "charge" to get reasonable node separation,
|
|
|
|
|
cola should do a much better job of respecting the specified link distance in the final layout.
|
|
|
|
|
This is because cola is directly trying to minimize the variance between ideal link distance and the actual distance in the drawing.
|
|
|
|
|
In other words, just set linkDistance to something reasonable for the size of your nodes (in the same coordinate system).
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
There are some other optional parameters available. In the <a href="examples/downwardedges.html">downward pointing edges example</a>
|
|
|
|
|
we kick off layout like so:
|
|
|
|
|
</p>
|
|
|
|
|
<pre><code>d3cola
|
|
|
|
|
.nodes(graph.nodes)
|
|
|
|
|
.links(graph.links)
|
|
|
|
|
.constraints(graph.constraints)
|
|
|
|
|
.symmetricDiffLinkLengths(5)
|
|
|
|
|
.avoidOverlaps(true)
|
|
|
|
|
.start(10,15,20);
|
|
|
|
|
</code></pre>
|
|
|
|
|
<p>We specify nodes and links exactly as in D3 force layout. However, <code>constraints</code> is a new parameter. It is an array containing constraints specified like so:<p>
|
|
|
|
|
<p><pre><code>{"axis":"y", "left":0, "right":1, "gap":25}</code></pre></p>
|
|
|
|
|
<p>This says that the center of <code>graph.nodes[0]</code> must be at least 25 pixels above the center of <code>graph.nodes[1]</code>. To be more precise, it is an inequality constraint that requires: <pre><code>graph.nodes[0].y + gap <= graph.nodes[1].y</code></pre></p>
|
|
|
|
|
<p><code>avoidOverlaps(true)</code> dynamically generates constraints while layout progresses in order to prevent the bounding boxes of nodes from sliding over one another (see <a href="examples/smallnonoverlappinggraph.html">this example</a>).</p>
|
|
|
|
|
<p><code>symmetricDiffLinkLengths(5)</code> computes ideal lengths on each link to make extra space around high-degree nodes, using 5 as the basic length.
|
|
|
|
|
Alternately, you can pass your own function <code>f</code> into <code>linkDistance(f)</code> that returns a specific length for each link (e.g. based on your data).</p>
|
|
|
|
|
<p>
|
|
|
|
|
The <code>start()</code> method now includes up to three integer arguments. In the example above, start will initially apply 10 iterations of layout with no constraints, 15 iterations with only structural (user-specified) constraints and 20 iterations of layout with all constraints including anti-overlap constraints.
|
|
|
|
|
Specifying such a schedule is useful to allow the graph to untangle before making it relatively "rigid" with constraints.
|
|
|
|
|
</p>
|
|
|
|
|
<p>Click through the examples above to see other cola.js features in action.</p>
|
|
|
|
|
<p>I'm currently working hard to add more options and to support more classes of constraints, so please watch this space - and don't be shy about <a href="http://marvl.infotech.monash.edu/~dwyer">sending me feedback</a>.</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<h2>Using cola.js in cytoscape.js</h2>
|
|
|
|
|
<p>
|
|
|
|
|
<a href="http://js.cytoscape.org">Cytoscape.js</a> has <a href="https://github.com/cytoscape/cytoscape.js-cola">full support for Cola.js via an extension</a>. Cytoscape.js has a full graph
|
|
|
|
|
theory model, highly customisable styling, gesture support, and layouts — such that Cola.js can be run in Cytoscape.js
|
|
|
|
|
in a single line of code:
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>cy.layout({ name: 'cola' /* and maybe some other options */ });</code></pre>
|
|
|
|
|
<script>
|
|
|
|
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
|
|
|
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
|
|
|
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
|
|
|
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
|
|
|
|
|
|
|
|
|
ga('create', 'UA-63535113-1', 'auto');
|
|
|
|
|
ga('send', 'pageview');
|
|
|
|
|
|
|
|
|
|
</script>
|