This is the dagre d3 renderer packaged for Meteor with some additional helpful utilities.
You can view the original non-meteor repository here.
Dagre is a JavaScript library that makes it easy to lay out directed graphs on the client-side. The dagre-d3 library acts a front-end to dagre, providing actual rendering using D3.
There will be a demo of the new ReactiveDagre
class added to the meteor implementation soon.
You can install it with meteorite:
mrt add dagred3
With dagre-d3, you will first create a graph, then render it. Much of this process is wrapped in ReactiveDagre
, which is outlined below.
The renderer uses graphlib to create graphs in dagre, so its probably worth taking a look at its API. Graphlib comes bundled with dagre-d3.
// Create a new directed graph
var g = new dagreD3.Digraph();
// Add nodes to the graph. The first argument is the node id. The second is
// metadata about the node. In this case we're going to add labels to each of
// our nodes.
g.addNode("kspacey", { label: "Kevin Spacey" });
g.addNode("swilliams", { label: "Saul Williams" });
g.addNode("bpitt", { label: "Brad Pitt" });
g.addNode("hford", { label: "Harrison Ford" });
g.addNode("lwilson", { label: "Luke Wilson" });
g.addNode("kbacon", { label: "Kevin Bacon" });
// Add edges to the graph. The first argument is the edge id. Here we use null
// to indicate that an arbitrary edge id can be assigned automatically. The
// second argument is the source of the edge. The third argument is the target
// of the edge. The last argument is the edge metadata.
g.addEdge(null, "kspacey", "swilliams", { label: "K-PAX" });
g.addEdge(null, "swilliams", "kbacon", { label: "These Vagabond Shoes" });
g.addEdge(null, "bpitt", "kbacon", { label: "Sleepers" });
g.addEdge(null, "hford", "lwilson", { label: "Anchorman 2" });
g.addEdge(null, "lwilson", "kbacon", { label: "Telling Lies in America" });
To render the graph, we first need to create an SVG element on our page:
<svg width=650 height=680>
<g transform="translate(20,20)"/>
</svg>
Then we ask the renderer to draw our graph in the SVG element:
var renderer = new dagreD3.Renderer();
renderer.run(g, d3.select("svg g"));
We also need to add some basic style information to get a usable graph. These values can be tweaked, of course.
<style>
svg {
overflow: hidden;
}
.node rect {
stroke: #333;
stroke-width: 1.5px;
fill: #fff;
}
.edgeLabel rect {
fill: #fff;
}
.edgePath {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
</style>
This produces the graph:
This section describes experimental rendering configuration.
renderer.edgeInterpolate(x)
sets the path interpolation used with d3. For a list of interpolation options, see the D3 API.renderer.edgeTension(x)
is used to set the tension for use with d3. See the D3 API for details.For example, to set the edge interpolation to 'linear':
renderer.edgeTension('linear');
renderer.run(g, d3.select('svg g'));
Here are a few methods you can call on the layout object to change layout behavior:
debugLevel(x)
sets the level of logging verbosity to the number x
. Currently 4 is th max.nodeSep(x)
sets the separation between adjacent nodes in the same rank to x
pixels.edgeSep(x)
sets the separation between adjacent edges in the same rank to x
pixels.rankSep(x)
sets the sepration between ranks in the layout to x
pixels.rankDir(x)
sets the direction of the layout.
"TB"
for top-to-bottom layout"LR"
sets layout to left-to-rightFor example, to set node separation to 20 pixels and the rank direction to left-to-right:
var layout = dagreD3.layout()
.nodeSep(20)
.rankDir("LR");
renderer.layout(layout).run(g, d3.select("svg g"));
This produces the following graph:
The class added in this implementation for Meteor is ReactiveDagre
. It automatically re-renders the layout with transitions when you add nodes, and wraps a lot of the init phases. Future support is planned for reactive functions in the data, for example, basing a graph off of a traditional Meteor function.
Right now, this is the simplified initialization process:
g = new ReactiveDagre "svg g"
graphBuilt = false
buildGraph = ->
if !graphBuilt
graphBuilt = true
g.layout.nodeSep(20).rankDir("LR")
#Third option is no-render, if you don't want the graph to update immediately
g.addNode "cool", {label: "Something Cool"}, true
g.addNode "awesome", {label: "Something Awesome"}, true
g.addEdge null, "cool", "awesome", {label: "Leads To"}, true
Template.dagre.rendered = ->
buildGraph()
g.render()
Once the graph is initially rendered, if you call g.addNode
or g.addEdge
, the graph will update automatically, with a nice 500ms transition. You can override the transition function by overwriting ReactiveDagre.prototype.transition
.
You can also remove edges or nodes by ID using g.delNode
or g.delEdge
.
Please note that you're setting basically an HTML selector in the constructor of ReactiveDagre
. If you try to add nodes when Meteor hasn't yet rendered your base svg g
, it will throw errors. It is safe to constuct ReactiveDagre
without any DOM, however.
dagre-d3 is licensed under the terms of the MIT License. See the LICENSE file for details.