dagre-d3
Version:
A D3-based renderer for Dagre
424 lines (378 loc) • 8.68 kB
HTML
<meta charset="utf-8">
<title>Graph Storyboard. Add and Prune Dependencies Algorithm</title>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="../dagre-d3.js"></script>
<style id="css">
h1 {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
margin-top: 0.8em;
margin-bottom: 0.2em;
}
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
.node rect {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.node polygon {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path.path {
stroke: #333;
fill: none;
stroke-width: 1.5px;
}
div#top-frame {
height: 350px;
}
div#WBS-frame {
float: left;
width: 50%;
}
div#dependencies-frame {
float: left;
width: 50%;
}
div#schedule-frame {
float: none;
}
</style>
<script>
// Polyfill for PhantomJS. This can be safely ignored if not using PhantomJS.
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
</script>
<script>
var dagred3Story = function(svgelement, graphType, interframetime) {
this.interframetime = interframetime;
this.lastrenderTime = null;
this.g = new dagreD3.graphlib.Graph().setGraph({});
//// Setup animation (if required)
//this.g.graph().transition = function(selection) {
// return selection.transition().duration(50);
//}.bind(this);
this.g.setDefaultEdgeLabel(function() { return {}; });
this.g.graph().marginx = 10;
this.g.graph().marginy = 10;
switch(graphType) {
case 'Work Breakdown Structure':
this.WBS = true;
this.Schedule = false;
this.g.graph().ranksep = 30;
this.g.graph().nodesep = 30;
break;
case 'Schedule Network':
this.Schedule = true;
this.WBS = false;
this.g.graph().rankdir = "LR";
this.g.graph().ranksep = 15;
this.g.graph().nodesep = 15;
break;
default:
console.log ("graphType of "+x+" is not implemented")
}
this.svg = d3.select(svgelement);
this.inner = this.svg.append("g");
this.svg.call(d3.zoom().on("zoom", (function() {
this.inner.attr("transform", d3.event.transform)
}).bind(this)));
this.t = 0;
this.dagreD3render = new dagreD3.render();
};
dagred3Story.prototype.animateFrame = function(RenderAfter, Frame) {
this.t += RenderAfter
//var that = this;
setTimeout(function() {
Frame.forEach(function(x) {
if (this.Schedule) {
switch(x[0]) {
case 'setActivity':
this.g.setNode(x[1],{})
break;
case 'removeNode':
this.g.removeNode(x[1])
break;
case 'setMilestone':
this.g.setNode(x[1],{ shape: 'diamond', style: "fill: #fff; stroke: #000" })
break;
case 'AddCoherenceEdge':
this.g.setEdge(x[1], x[2], {
curve: d3.curveBasis
});
break;
case 'AddDependencyEdge':
this.g.setEdge(x[1], x[2], {
curve: d3.curveBasis
,label: 'added'
,labeloffset: 5
,labelpos: 'l'
});
break;
case 'MakeRedundantEdge':
this.g.setEdge(x[1], x[2], {
style: "stroke: #aaa; stroke-dasharray: 5, 10;"
,curve: d3.curveBasis
,arrowheadStyle: "fill: #aaa"
,labelpos: 'c'
,label: 'pruned'
,labelStyle: 'stroke: #aaa'
});
break;
case 'RemoveEdge':
this.g.removeEdge(x[1], x[2]);
break;
default:
console.log ("Schedule Network element "+x+" is not implemented")
}
} else if (this.WBS ) {
switch(x[0]) {
case 'setComponent':
this.g.setNode(x[1],{})
break;
case 'AddWBSEdge':
this.g.setEdge(x[1], x[2], {
arrowhead: 'undirected'
});
break;
default:
console.log ("WBS element "+x+" is not implemented")
}
}
}.bind(this))
if (this.g) {
// Render
this.dagreD3render(this.inner,this.g);
}
}.bind(this), this.t)
};
dagred3Story.prototype.animateStory = function(RenderAfter, Story) {
this.t += RenderAfter
setTimeout(function() {
Story.forEach(function(Frame) {
this.animateFrame(this.interframetime, Frame);
}.bind(this))
}.bind(this), this.t)
};
</script>
<div id="top-frame">
<div id="WBS-frame">
<h1>WBS</h1>
<svg id="WBS" width=250 height=250></svg>
</div>
<div id="dependencies-frame">
<h1>Sequencing</h1>
<svg id="dependencies" width=300 height=250></svg>
</div>
</div>
<div id="schedule-frame">
<h1>Coherent Schedule Network</h1>
<svg id="schedule" width=1150 height=500></svg>
</div>
<script id="js">
var framedelay = 2000;
var dependenciesstory = new dagred3Story("#dependencies", "Schedule Network", framedelay);
dependenciesstory.animateStory(0,
[
[
],[
],[
],[
]
,[
["setActivity", "A.1"]
,
["setMilestone", "A.2 Start"]
,
["AddDependencyEdge", "A.1", "A.2 Start"]
],[
],[
],[
],[
],[
["setActivity", "A.2.2"]
,
["setActivity", "A.2.3"]
,
["AddDependencyEdge", "A.2.2", "A.2.3"]
],[
],[
],[
],[
],[
["setActivity", "A.2.1"]
,
["setActivity", "B"]
,
["AddDependencyEdge", "A.2.1", "B"]
],[
],[
]
]);
var WBSstory = new dagred3Story("#WBS", "Work Breakdown Structure", framedelay);
WBSstory.animateStory(0,
[
[
["setComponent", "Project"]
],[
["setComponent", "A"]
,
["AddWBSEdge", "Project", "A"]
,
["setComponent", "B"]
,
["AddWBSEdge", "Project", "B"]
],[
["setComponent", "A.1"]
,
["AddWBSEdge", "A", "A.1"]
,
["setComponent", "A.2"]
,
["AddWBSEdge", "A", "A.2"]
],[
["setComponent", "A.2.1"]
,
["AddWBSEdge", "A.2", "A.2.1"]
,
["setComponent", "A.2.2"]
,
["AddWBSEdge", "A.2", "A.2.2"]
,
["setComponent", "A.2.3"]
,
["AddWBSEdge", "A.2", "A.2.3"]
]
]);
var schedulestory = new dagred3Story("#schedule", "Schedule Network",framedelay);
// Create the input graph
schedulestory.animateStory(0,
[
[
["setActivity", "Project"]
],[
["removeNode", "Project"]
,
["setMilestone", "Project Finish"]
,
["setMilestone", "Project Start"]
,
["setActivity", "A"]
,
["setActivity", "B"]
,
["AddCoherenceEdge", "Project Start", "A"]
,
["AddCoherenceEdge", "Project Start", "B"]
,
["AddCoherenceEdge", "A", "Project Finish"]
,
["AddCoherenceEdge", "B", "Project Finish"]
],[
["removeNode", "A"]
,
["setMilestone", "A Start"]
,
["setActivity", "A.1"]
,
["setActivity", "A.2"]
,
["setMilestone", "A Finish"]
,
["AddCoherenceEdge", "A Start", "A.1"]
,
["AddCoherenceEdge", "A Start", "A.2"]
,
["AddCoherenceEdge", "A.1", "A Finish"]
,
["AddCoherenceEdge", "A.2", "A Finish"]
,
["AddCoherenceEdge", "Project Start", "A Start"]
,
["AddCoherenceEdge", "A Finish", "Project Finish"]
],[
["removeNode", "A.2"]
,
["setMilestone", "A.2 Start"]
,
["setActivity", "A.2.1"]
,
["setActivity", "A.2.2"]
,
["setActivity", "A.2.3"]
,
["setMilestone", "A.2 Finish"]
,
["AddCoherenceEdge", "A.2 Start", "A.2.1"]
,
["AddCoherenceEdge", "A.2 Start", "A.2.2"]
,
["AddCoherenceEdge", "A.2 Start", "A.2.3"]
,
["AddCoherenceEdge", "A.2.1", "A.2 Finish"]
,
["AddCoherenceEdge", "A.2.2", "A.2 Finish"]
,
["AddCoherenceEdge", "A.2.3", "A.2 Finish"]
,
["AddCoherenceEdge", "A Start", "A.2 Start"]
,
["AddCoherenceEdge", "A.2 Finish", "A Finish"]
]
,[
["AddDependencyEdge", "A.1", "A.2 Start"]
],[
["MakeRedundantEdge", "A Start", "A.2 Start"]
],[
["MakeRedundantEdge", "A.1", "A Finish"]
],[
["RemoveEdge", "A Start", "A.2 Start"]
],[
["RemoveEdge", "A.1", "A Finish"]
],[
["AddDependencyEdge", "A.2.2", "A.2.3"]
],[
["MakeRedundantEdge", "A.2 Start", "A.2.3"]
],[
["MakeRedundantEdge", "A.2.2", "A.2 Finish"]
],[
["RemoveEdge", "A.2 Start", "A.2.3"]
],[
["RemoveEdge", "A.2.2", "A.2 Finish"]
],[
["AddDependencyEdge", "A.2.1", "B"]
],[
["MakeRedundantEdge", "Project Start", "B"]
],[
["RemoveEdge", "Project Start", "B"]
]
]);
</script>
</body>
</html>