08-27-周三_17-09-29

This commit is contained in:
2025-08-27 17:10:05 +08:00
commit 86df397d8f
12735 changed files with 1145479 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+75
View File
@@ -0,0 +1,75 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Arrows</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<style id="css">
body {
font: 300 14px 'Helvetica Neue', Helvetica;
}
.node rect,
.node circle,
.node ellipse {
stroke: #333;
fill: #fff;
stroke-width: 1px;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
</style>
<h1>Dagre D3 Demo: Arrows</h1>
<svg width=960 height=600><g/></svg>
<section>
<p>A sample that shows the different arrows available in dagre-d3.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
["normal", "vee", "undirected"].forEach(function(arrowhead) {
g.setNode(arrowhead + "1", { label: " " });
g.setNode(arrowhead + "2", { label: " " });
g.setEdge(arrowhead + "1", arrowhead + "2", {
arrowhead: arrowhead,
label: arrowhead
});
});
var svg = d3.select("svg"),
inner = svg.select("g");
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
</script>
<script src="demo.js"></script>
+101
View File
@@ -0,0 +1,101 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Clusters</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<h1>Dagre D3 Demo: Clusters</h1>
<style id="css">
.clusters rect {
fill: #00ffd0;
stroke: #999;
stroke-width: 1.5px;
}
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
.node rect {
stroke: #999;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path {
stroke: #333;
stroke-width: 1.5px;
}
</style>
<svg id="svg-canvas" width=960 height=600></svg>
<section>
<p>An example of visualizing clusters. This example shows
how clusters can be applied to a rendered graph.
</section>
<script id="js">
// Create the input graph
var g = new dagreD3.graphlib.Graph({compound:true})
.setGraph({})
.setDefaultEdgeLabel(function() { return {}; });
// Here we're setting the nodes
g.setNode('a', {label: 'A'});
g.setNode('b', {label: 'B'});
g.setNode('c', {label: 'C'});
g.setNode('d', {label: 'D'});
g.setNode('e', {label: 'E'});
g.setNode('f', {label: 'F'});
g.setNode('g', {label: 'G'});
g.setNode('group', {label: 'Group', clusterLabelPos: 'top', style: 'fill: #d3d7e8'});
g.setNode('top_group', {label: 'Top Group', clusterLabelPos: 'bottom', style: 'fill: #ffd47f'});
g.setNode('bottom_group', {label: 'Bottom Group', style: 'fill: #5f9488'});
// Set the parents to define which nodes belong to which cluster
g.setParent('top_group', 'group');
g.setParent('bottom_group', 'group');
g.setParent('b', 'top_group');
g.setParent('c', 'bottom_group');
g.setParent('d', 'bottom_group');
g.setParent('e', 'bottom_group');
g.setParent('f', 'bottom_group');
// Set up edges, no special attributes.
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.setEdge('b', 'd');
g.setEdge('b', 'e');
g.setEdge('b', 'f');
g.setEdge('b', 'g');
g.nodes().forEach(function(v) {
var node = g.node(v);
// Round the corners of the nodes
node.rx = node.ry = 5;
});
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
svgGroup = svg.append("g");
// Run the renderer. This is what draws the final graph.
render(d3.select("svg g"), g);
// Center the graph
var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
svg.attr("height", g.graph().height + 40);
</script>
<script src="demo.js"></script>
+35
View File
@@ -0,0 +1,35 @@
body {
width: 960px;
margin: 0 auto;
color: #333;
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
}
h1 {
font-size: 3em;
font-weight: 300;
}
h2 {
font-size: 1.5em;
font-weight: 300;
}
section {
margin-bottom: 3em;
}
section p {
text-align: justify;
}
svg {
border: 1px solid #ccc;
overflow: hidden;
margin: 0 auto;
}
pre {
border: 1px solid #ccc;
}
+26
View File
@@ -0,0 +1,26 @@
const d3 = window.d3
const bodyElem = d3.select('body')
const jsElem = d3.select('#js')
const jsPanel = bodyElem.append('div').attr('id', 'jsPanel')
const cssElem = d3.select('#css')
const cssPanel = bodyElem.append('div').attr('id', 'cssPanel')
function setupPanel (panel, elem, title) {
panel.append('h2').text(title)
return panel.append('pre').append('code').text(elem.html().trim())
}
const jsCode = setupPanel(jsPanel, jsElem, 'JavaScript')
const cssCode = setupPanel(cssPanel, cssElem, 'CSS')
const hljsRoot = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0'
bodyElem.append('link')
.attr('rel', 'stylesheet')
.attr('href', hljsRoot + '/styles/xcode.min.css')
bodyElem.append('script')
.attr('src', hljsRoot + '/highlight.min.js')
.on('load', function () {
window.hljs.highlightBlock(jsCode.node())
window.hljs.highlightBlock(cssCode.node())
})
+98
View File
@@ -0,0 +1,98 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: DOM Example</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<h1>Dagre D3 Demo: DOM Example</h1>
<style id="css">
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;
}
.edgePath path {
stroke: #333;
stroke-width: 1.5px;
}
table {
border-spacing: 0;
}
table td {
padding: 7px;
}
table td:first-child {
background-color: #afa;
border-top: 1px solid #333;
border-left: 1px solid #333;
border-bottom: 1px solid #333;
border-radius: 5px 0 0 5px;
}
table td:last-child {
background-color: #faa;
border-top: 1px solid #333;
border-right: 1px solid #333;
border-bottom: 1px solid #333;
border-radius: 0 5px 5px 0;
}
</style>
<svg width=960 height=600></svg>
<section>
<p>A sample showing how to use DOM nodes in a graph. Note that IE does not
support this technique.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
g.setNode("root", {
label: function() {
var table = document.createElement("table"),
tr = d3.select(table).append("tr");
tr.append("td").text("A");
tr.append("td").text("B");
return table;
},
padding: 0,
rx: 5,
ry: 5
});
g.setNode("A", { label: "A", fill: "#afa" });
g.setNode("B", { label: "B", fill: "#faa" });
g.setEdge("root", "A", {});
g.setEdge("root", "B", {});
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select('svg'),
svgGroup = svg.append('g');
// Run the renderer. This is what draws the final graph.
render(svgGroup, g);
// Center the graph
var xCenterOffset = (svg.attr('width') - g.graph().width) / 2;
svgGroup.attr('transform', 'translate(' + xCenterOffset + ', 20)');
svg.attr('height', g.graph().height + 40);
</script>
<script src="demo.js"></script>
+283
View File
@@ -0,0 +1,283 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Renderer Demo</title>
<script src="../dagre-d3.js"></script>
<style>
body {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0;
padding: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
background: #333;
}
@-webkit-keyframes flash {
0%, 50%, 100% {
opacity: 1;
}
25%, 75% {
opacity: 0.2;
}
}
@keyframes flash {
0%, 50%, 100% {
opacity: 1;
}
25%, 75% {
opacity: 0.2;
}
}
.warn {
-webkit-animation-duration: 5s;
animation-duration: 5s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
}
.live.map {
width: 100%;
height: 100%;
}
svg {
width: 100%;
height: 100%;
overflow: hidden;
}
.live.map text {
font-weight: 300;
font-size: 14px;
}
.live.map .node rect {
stroke-width: 1.5px;
stroke: #bbb;
fill: #666;
}
.live.map .status {
height: 100%;
width: 15px;
display: block;
float: left;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
margin-right: 4px;
}
.live.map .running .status {
background-color: #7f7;
}
.live.map .running.warn .status {
background-color: #ffed68;
}
.live.map .stopped .status {
background-color: #f77;
}
.live.map .warn .queue {
color: #f77;
}
.warn {
-webkit-animation-name: flash;
animation-name: flash;
}
.live.map .consumers {
margin-right: 2px;
}
.live.map .consumers,
.live.map .name {
margin-top: 4px;
}
.live.map .consumers:after {
content: "x";
}
.live.map .queue {
display: block;
float: left;
width: 130px;
height: 20px;
font-size: 12px;
margin-top: 2px;
}
.live.map .node g div {
width: 200px;
height: 40px;
color: #fff;
}
.live.map .node g div span.consumers {
display: inline-block;
width: 20px;
}
.live.map .edgeLabel text {
width: 50px;
fill: #fff;
}
.live.map .edgePath path {
stroke: #999;
stroke-width: 1.5px;
fill: #999;
}
</style>
<body>
<div class="live map">
<svg><g/></svg>
</div>
<script>
var workers = {
"identifier": {
"consumers": 2,
"count": 20
},
"lost-and-found": {
"consumers": 1,
"count": 1,
"inputQueue": "identifier",
"inputThroughput": 50
},
"monitor": {
"consumers": 1,
"count": 0,
"inputQueue": "identifier",
"inputThroughput": 50
},
"meta-enricher": {
"consumers": 4,
"count": 9900,
"inputQueue": "identifier",
"inputThroughput": 50
},
"geo-enricher": {
"consumers": 2,
"count": 1,
"inputQueue": "meta-enricher",
"inputThroughput": 50
},
"elasticsearch-writer": {
"consumers": 0,
"count": 9900,
"inputQueue": "geo-enricher",
"inputThroughput": 50
}
};
// Set up zoom support
var svg = d3.select("svg"),
inner = svg.select("g"),
zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
var render = new dagreD3.render();
// Left-to-right layout
var g = new dagreD3.graphlib.Graph();
g.setGraph({
nodesep: 70,
ranksep: 50,
rankdir: "LR",
marginx: 20,
marginy: 20
});
function draw(isUpdate) {
for (var id in workers) {
var worker = workers[id];
var className = worker.consumers ? "running" : "stopped";
if (worker.count > 10000) {
className += " warn";
}
var html = "<div>";
html += "<span class=status></span>";
html += "<span class=consumers>"+worker.consumers+"</span>";
html += "<span class=name>"+id+"</span>";
html += "<span class=queue><span class=counter>"+worker.count+"</span></span>";
html += "</div>";
g.setNode(id, {
labelType: "html",
label: html,
rx: 5,
ry: 5,
padding: 0,
class: className
});
if (worker.inputQueue) {
g.setEdge(worker.inputQueue, id, {
label: worker.inputThroughput + "/s",
width: 40
});
}
}
inner.call(render, g);
// Zoom and scale to fit
var graphWidth = g.graph().width + 80;
var graphHeight = g.graph().height + 40;
var width = parseInt(svg.style("width").replace(/px/, ""));
var height = parseInt(svg.style("height").replace(/px/, ""));
var zoomScale = Math.min(width / graphWidth, height / graphHeight);
var translate = [(width/2) - ((graphWidth*zoomScale)/2), (height/2) - ((graphHeight*zoomScale)/2)];
zoom.translate(translate);
zoom.scale(zoomScale);
zoom.event(isUpdate ? svg.transition().duration(500) : d3.select("svg"));
}
// Do some mock queue status updates
setInterval(function() {
var stoppedWorker1Count = workers["elasticsearch-writer"].count;
var stoppedWorker2Count = workers["meta-enricher"].count;
for (var id in workers) {
workers[id].count = Math.ceil(Math.random() * 3);
if (workers[id].inputThroughput) workers[id].inputThroughput = Math.ceil(Math.random() * 250);
}
workers["elasticsearch-writer"].count = stoppedWorker1Count + Math.ceil(Math.random() * 100);
workers["meta-enricher"].count = stoppedWorker2Count + Math.ceil(Math.random() * 100);
draw(true);
}, 1000);
// Do a mock change of worker configuration
setInterval(function() {
workers["elasticsearch-monitor"] = {
"consumers": 0,
"count": 0,
"inputQueue": "elasticsearch-writer",
"inputThroughput": 50
}
}, 5000);
draw();
</script>
+423
View File
@@ -0,0 +1,423 @@
<!doctype html>
<meta charset="utf-8">
<title>Graph Storyboard. Add and Prune Dependencies Algorithm</title>
<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.behavior.zoom().on("zoom", (function() {
this.inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")")
}).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], {
lineInterpolate: 'basis'
});
break;
case 'AddDependencyEdge':
this.g.setEdge(x[1], x[2], {
lineInterpolate: 'basis'
,label: 'added'
,labeloffset: 5
,labelpos: 'l'
});
break;
case 'MakeRedundantEdge':
this.g.setEdge(x[1], x[2], {
style: "stroke: #aaa; stroke-dasharray: 5, 10;"
,lineInterpolate: 'basis'
,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>
File diff suppressed because it is too large Load Diff
+196
View File
@@ -0,0 +1,196 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Tooltip on Hover</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<!-- Pull in JQuery dependencies -->
<link rel="stylesheet" href="tipsy.css">
<script src="./jquery-1.9.1.min.js"></script>
<script src="tipsy.js"></script>
<h1>Dagre D3 Demo: Tooltip on Hover</h1>
<style id="css">
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
.node rect {
stroke: #333;
fill: #fff;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
}
/* This styles the title of the tooltip */
.tipsy .name {
font-size: 1.5em;
font-weight: bold;
color: #60b1fc;
margin: 0;
}
/* This styles the body of the tooltip */
.tipsy .description {
font-size: 1.2em;
}
</style>
<svg width=960 height=600></svg>
<section>
<p>The TCP state diagram
(<a href="http://www.rfc-editor.org/rfc/rfc793.txt">source: RFC 793</a>) with
hover support. Uses <a href="http://bl.ocks.org/ilyabo/1373263">tipsy JS and CSS</a>
for the tooltip.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
// States and transitions from RFC 793
var states = {
CLOSED: {
description: "represents no connection state at all.",
style: "fill: #f77"
},
LISTEN: {
description: "represents waiting for a connection request from any " +
"remote TCP and port."
},
"SYN SENT": {
description: "represents waiting for a matching connection " +
"request after having sent a connection request."
},
"SYN RCVD": {
description: "represents waiting for a confirming connection " +
"request acknowledgment after having both received and sent a " +
"connection request."
},
ESTAB: {
description: "represents an open connection, data received " +
"can be delivered to the user. The normal state for the data " +
"transfer phase of the connection.",
style: "fill: #7f7"
},
"FINWAIT-1": {
description: "represents waiting for a connection termination " +
"request from the remote TCP, or an acknowledgment of the " +
"connection termination request previously sent."
},
"FINWAIT-2": {
description: "represents waiting for a connection termination " +
"request from the remote TCP."
},
"CLOSE WAIT": {
description: "represents waiting for a connection termination " +
"request from the local user."
},
CLOSING: {
description: "represents waiting for a connection termination " +
"request acknowledgment from the remote TCP."
},
"LAST-ACK": {
description: "represents waiting for an acknowledgment of the " +
"connection termination request previously sent to the remote " +
"TCP (which includes an acknowledgment of its connection " +
"termination request)."
},
"TIME WAIT": {
description: "represents waiting for enough time to pass to be " +
"sure the remote TCP received the acknowledgment of its " +
"connection termination request."
}
};
// Add states to the graph, set labels, and style
Object.keys(states).forEach(function(state) {
var value = states[state];
value.label = state;
value.rx = value.ry = 5;
g.setNode(state, value);
});
// Set up the edges
g.setEdge("CLOSED", "LISTEN", { label: "open" });
g.setEdge("LISTEN", "SYN RCVD", { label: "rcv SYN" });
g.setEdge("LISTEN", "SYN SENT", { label: "send" });
g.setEdge("LISTEN", "CLOSED", { label: "close" });
g.setEdge("SYN RCVD", "FINWAIT-1", { label: "close" });
g.setEdge("SYN RCVD", "ESTAB", { label: "rcv ACK of SYN" });
g.setEdge("SYN SENT", "SYN RCVD", { label: "rcv SYN" });
g.setEdge("SYN SENT", "ESTAB", { label: "rcv SYN, ACK" });
g.setEdge("SYN SENT", "CLOSED", { label: "close" });
g.setEdge("ESTAB", "FINWAIT-1", { label: "close" });
g.setEdge("ESTAB", "CLOSE WAIT", { label: "rcv FIN" });
g.setEdge("FINWAIT-1", "FINWAIT-2", { label: "rcv ACK of FIN" });
g.setEdge("FINWAIT-1", "CLOSING", { label: "rcv FIN" });
g.setEdge("CLOSE WAIT", "LAST-ACK", { label: "close" });
g.setEdge("FINWAIT-2", "TIME WAIT", { label: "rcv FIN" });
g.setEdge("CLOSING", "TIME WAIT", { label: "rcv ACK of FIN" });
g.setEdge("LAST-ACK", "CLOSED", { label: "rcv ACK of FIN" });
g.setEdge("TIME WAIT", "CLOSED", { label: "timeout=2MSL" });
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
inner = svg.append("g");
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Simple function to style the tooltip for the given node.
var styleTooltip = function(name, description) {
return "<p class='name'>" + name + "</p><p class='description'>" + description + "</p>";
};
// Run the renderer. This is what draws the final graph.
render(inner, g);
inner.selectAll("g.node")
.attr("title", function(v) { return styleTooltip(v, g.node(v).description) })
.each(function(v) { $(this).tipsy({ gravity: "w", opacity: 1, html: true }); });
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
</script>
<script src="demo.js"></script>
+172
View File
@@ -0,0 +1,172 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre Interactive Demo</title>
<script src="./graphlib-dot.js"></script>
<script src="../dagre-d3.js"></script>
<style>
svg {
border: 1px solid #999;
overflow: hidden;
}
.node {
white-space: nowrap;
}
.node rect,
.node circle,
.node ellipse {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.cluster rect {
stroke: #333;
fill: #000;
fill-opacity: 0.1;
stroke-width: 1.5px;
}
.edgePath path.path {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
</style>
<style>
h1, h2 {
color: #333;
}
textarea {
width: 800px;
}
label {
margin-top: 1em;
display: block;
}
.error {
color: red;
}
</style>
<body onLoad="tryDraw();">
<h1>Dagre Interactive Demo</h1>
<h2>Input</h2>
<form>
<label for="inputGraph">Graphviz Definition</label>
<textarea id="inputGraph" rows="5" style="display: block" onKeyUp="tryDraw();">
/* Example */
digraph {
/* Note: HTML labels do not work in IE, which lacks support for &lt;foreignObject&gt; tags. */
node [rx=5 ry=5 labelStyle="font: 300 14px 'Helvetica Neue', Helvetica"]
edge [labelStyle="font: 300 14px 'Helvetica Neue', Helvetica"]
A [labelType="html"
label="A <span style='font-size:32px'>Big</span> <span style='color:red;'>HTML</span> Source!"];
C;
E [label="Bold Red Sink" style="fill: #f77; font-weight: bold"];
A -&gt; B -&gt; C;
B -&gt; D [label="A blue label" labelStyle="fill: #55f; font-weight: bold;"];
D -&gt; E [label="A thick red edge" style="stroke: #f77; stroke-width: 2px;" arrowheadStyle="fill: #f77"];
C -&gt; E;
A -&gt; D [labelType="html" label="A multi-rank <span style='color:blue;'>HTML</span> edge!"];
}
</textarea>
<a id="graphLink">Link for this graph</a>
</form>
<h2>Graph Visualization</h2>
<svg width=800 height=600>
<g/>
</svg>
<script>
// Input related code goes here
function graphToURL() {
var elems = [window.location.protocol, '//',
window.location.host,
window.location.pathname,
'?'];
var queryParams = [];
if (debugAlignment) {
queryParams.push('alignment=' + debugAlignment);
}
queryParams.push('graph=' + encodeURIComponent(inputGraph.value));
elems.push(queryParams.join('&'));
return elems.join('');
}
var inputGraph = document.querySelector("#inputGraph");
var graphLink = d3.select("#graphLink");
var oldInputGraphValue;
var graphRE = /[?&]graph=([^&]+)/;
var graphMatch = window.location.search.match(graphRE);
if (graphMatch) {
inputGraph.value = decodeURIComponent(graphMatch[1]);
}
var debugAlignmentRE = /[?&]alignment=([^&]+)/;
var debugAlignmentMatch = window.location.search.match(debugAlignmentRE);
var debugAlignment;
if (debugAlignmentMatch) debugAlignment = debugAlignmentMatch[1];
// Set up zoom support
var svg = d3.select("svg"),
inner = d3.select("svg g"),
zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create and configure the renderer
var render = dagreD3.render();
function tryDraw() {
var g;
if (oldInputGraphValue !== inputGraph.value) {
inputGraph.setAttribute("class", "");
oldInputGraphValue = inputGraph.value;
try {
g = graphlibDot.read(inputGraph.value);
} catch (e) {
inputGraph.setAttribute("class", "error");
throw e;
}
// Save link to new graph
graphLink.attr("href", graphToURL());
// Set margins, if not present
if (!g.graph().hasOwnProperty("marginx") &&
!g.graph().hasOwnProperty("marginy")) {
g.graph().marginx = 20;
g.graph().marginy = 20;
}
g.graph().transition = function(selection) {
return selection.transition().duration(500);
};
// Render the graph into svg g
d3.select("svg g").call(render, g);
}
}
</script>
File diff suppressed because one or more lines are too long
+104
View File
@@ -0,0 +1,104 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Sentence Tokenization</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<h1>Dagre D3 Demo: Sentence Tokenization</h1>
<style id="css">
/* This sets the color for "TK" nodes to a light blue green. */
g.type-TK > rect {
fill: #00ffd0;
}
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
.node rect {
stroke: #999;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path {
stroke: #333;
stroke-width: 1.5px;
}
</style>
<svg id="svg-canvas" width=960 height=600></svg>
<section>
<p>An example of visualizing the tokenization of a sentence. This example shows
how CSS classes can be applied to a rendered graph.
</section>
<script id="js">
// Create the input graph
var g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultEdgeLabel(function() { return {}; });
// Here we"re setting nodeclass, which is used by our custom drawNodes function
// below.
g.setNode(0, { label: "TOP", class: "type-TOP" });
g.setNode(1, { label: "S", class: "type-S" });
g.setNode(2, { label: "NP", class: "type-NP" });
g.setNode(3, { label: "DT", class: "type-DT" });
g.setNode(4, { label: "This", class: "type-TK" });
g.setNode(5, { label: "VP", class: "type-VP" });
g.setNode(6, { label: "VBZ", class: "type-VBZ" });
g.setNode(7, { label: "is", class: "type-TK" });
g.setNode(8, { label: "NP", class: "type-NP" });
g.setNode(9, { label: "DT", class: "type-DT" });
g.setNode(10, { label: "an", class: "type-TK" });
g.setNode(11, { label: "NN", class: "type-NN" });
g.setNode(12, { label: "example", class: "type-TK" });
g.setNode(13, { label: ".", class: "type-." });
g.setNode(14, { label: "sentence", class: "type-TK" });
g.nodes().forEach(function(v) {
var node = g.node(v);
// Round the corners of the nodes
node.rx = node.ry = 5;
});
// Set up edges, no special attributes.
g.setEdge(3, 4);
g.setEdge(2, 3);
g.setEdge(1, 2);
g.setEdge(6, 7);
g.setEdge(5, 6);
g.setEdge(9, 10);
g.setEdge(8, 9);
g.setEdge(11,12);
g.setEdge(8, 11);
g.setEdge(5, 8);
g.setEdge(1, 5);
g.setEdge(13,14);
g.setEdge(1, 13);
g.setEdge(0, 1)
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
svgGroup = svg.append("g");
// Run the renderer. This is what draws the final graph.
render(d3.select("svg g"), g);
// Center the graph
var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
svg.attr("height", g.graph().height + 40);
</script>
<script src="demo.js"></script>
+72
View File
@@ -0,0 +1,72 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Shapes</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<style id="css">
body {
font: 300 14px 'Helvetica Neue', Helvetica;
}
.node rect,
.node circle,
.node ellipse,
.node polygon {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
</style>
<h1>Dagre D3 Demo: Shapes</h1>
<svg width=960 height=600><g/></svg>
<section>
<p>A sample that shows the different node shapes available in dagre-d3.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
g.setNode("rect", { shape: "rect" });
g.setNode("circle", { shape: "circle" });
g.setNode("ellipse", { shape: "ellipse" });
g.setNode("diamond", { shape: "diamond" });
var svg = d3.select("svg"),
inner = svg.select("g");
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
</script>
<script src="demo.js"></script>
+105
View File
@@ -0,0 +1,105 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: Style Attributes</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<h1>Dagre D3 Demo: Style Attributes</h1>
<style id="css">
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;
}
.edgePath path.path {
stroke: #333;
fill: none;
stroke-width: 1.5px;
}
.arrowhead {
stroke: blue;
fill: blue;
stroke-width: 1.5px;
}
</style>
<svg id="svg" width=960 height=600></svg>
<section>
<p>An example showing how styles that are set in the input graph can be applied
to nodes, node labels, edges, and edge labels in the rendered graph.
</section>
<script id="js">
// Create the input graph
var g = new dagreD3.graphlib.Graph().setGraph({});
// Fill node "A" with the color green
g.setNode("A", { style: "fill: #afa" });
// Make the label for node "B" bold
g.setNode("B", { labelStyle: "font-weight: bold" });
// Double the size of the font for node "C"
g.setNode("C", { labelStyle: "font-size: 2em" });
g.setNode("D", {});
g.setNode("E", {});
// Make the edge from "A" to "B" red, thick, and dashed
g.setEdge("A", "B", {
style: "stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;",
arrowheadStyle: "fill: #f66"
});
// Make the label for the edge from "C" to "B" italic and underlined
g.setEdge("C", "B", {
label: "A to C",
labelStyle: "font-style: italic; text-decoration: underline;"
});
// Make the edge between A and D smoother.
// see available options for lineInterpolate here: https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate
g.setEdge("A", "D", {
label: "line interpolation different",
lineInterpolate: 'basis'
});
g.setEdge("E", "D", {});
// Make the arrowhead blue
g.setEdge("A", "E", {
label: "Arrowhead class",
arrowheadClass: 'arrowhead'
});
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
inner = svg.append("g");
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
inner.attr("transform", "translate(" + xCenterOffset + ", 20)");
svg.attr("height", g.graph().height + 40);
</script>
<script src="demo.js"></script>
+102
View File
@@ -0,0 +1,102 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: SVG Labels</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<h1>Dagre D3 Demo: SVG Labels</h1>
<style id="css">
text {
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px;
}
.node rect {
stroke: #999;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path {
stroke: #333;
stroke-width: 1.5px;
}
</style>
<svg id="svg-canvas" width=960 height=600></svg>
<section>
<p>An example of adding SVG labels. This allows the user to add any svg
elements to the label. This allows for links to works in IE.</p>
</section>
<script id="js">
// Create the input graph
var g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultEdgeLabel(function() { return {}; });
// Create the SVG label to pass in
// Must create in SVG namespace
// http://stackoverflow.com/questions/7547117/add-a-new-line-in-svg-bug-cannot-see-the-line
// This mimics the same way string labels get added in Dagre-D3
svg_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1');
link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
link.setAttribute('target', '_blank');
link.textContent = 'IE Capable link';
tspan.appendChild(link);
svg_label.appendChild(tspan);
g.setNode(0, { label: svg_label, labelType: 'svg' });
g.setNode(1, { label: "A" });
g.setNode(2, { label: "B" });
g.nodes().forEach(function(v) {
var node = g.node(v);
// Round the corners of the nodes
node.rx = node.ry = 5;
});
svg_edge_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
edge_tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
edge_tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
edge_tspan.setAttribute('dy', '1em');
edge_tspan.setAttribute('x', '1');
edge_link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
edge_link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
edge_link.setAttribute('target', '_blank');
edge_link.textContent = 'IE Capable Edge link';
edge_tspan.appendChild(edge_link);
svg_edge_label.appendChild(edge_tspan);
// Set up edges, no special attributes.
g.setEdge(0, 1, { labelType: "svg", label: svg_edge_label });
g.setEdge(0, 2);
g.setEdge(1, 2);
// Create the renderer
var render = new dagreD3.render();
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
svgGroup = svg.append("g");
// Run the renderer. This is what draws the final graph.
render(d3.select("svg g"), g);
// Center the graph
var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
svg.attr("height", g.graph().height + 40);
</script>
<script src="demo.js"></script>
+104
View File
@@ -0,0 +1,104 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: TCP State Diagram</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<style id="css">
body {
font: 300 14px 'Helvetica Neue', Helvetica;
}
.node rect {
stroke: #333;
fill: #fff;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
</style>
<h1>Dagre D3 Demo: TCP State Diagram</h1>
<svg width=960 height=600><g/></svg>
<section>
<p>A sample rendering of a TCP state diagram
(<a href="http://www.rfc-editor.org/rfc/rfc793.txt">RFC 793</a>). This example
shows how to set custom styles in the input graph and how to set a custom
initial zoom.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
// States and transitions from RFC 793
var states = [ "CLOSED", "LISTEN", "SYN RCVD", "SYN SENT",
"ESTAB", "FINWAIT-1", "CLOSE WAIT", "FINWAIT-2",
"CLOSING", "LAST-ACK", "TIME WAIT" ];
// Automatically label each of the nodes
states.forEach(function(state) { g.setNode(state, { label: state }); });
// Set up the edges
g.setEdge("CLOSED", "LISTEN", { label: "open" });
g.setEdge("LISTEN", "SYN RCVD", { label: "rcv SYN" });
g.setEdge("LISTEN", "SYN SENT", { label: "send" });
g.setEdge("LISTEN", "CLOSED", { label: "close" });
g.setEdge("SYN RCVD", "FINWAIT-1", { label: "close" });
g.setEdge("SYN RCVD", "ESTAB", { label: "rcv ACK of SYN" });
g.setEdge("SYN SENT", "SYN RCVD", { label: "rcv SYN" });
g.setEdge("SYN SENT", "ESTAB", { label: "rcv SYN, ACK" });
g.setEdge("SYN SENT", "CLOSED", { label: "close" });
g.setEdge("ESTAB", "FINWAIT-1", { label: "close" });
g.setEdge("ESTAB", "CLOSE WAIT", { label: "rcv FIN" });
g.setEdge("FINWAIT-1", "FINWAIT-2", { label: "rcv ACK of FIN" });
g.setEdge("FINWAIT-1", "CLOSING", { label: "rcv FIN" });
g.setEdge("CLOSE WAIT", "LAST-ACK", { label: "close" });
g.setEdge("FINWAIT-2", "TIME WAIT", { label: "rcv FIN" });
g.setEdge("CLOSING", "TIME WAIT", { label: "rcv ACK of FIN" });
g.setEdge("LAST-ACK", "CLOSED", { label: "rcv ACK of FIN" });
g.setEdge("TIME WAIT", "CLOSED", { label: "timeout=2MSL" });
// Set some general styles
g.nodes().forEach(function(v) {
var node = g.node(v);
node.rx = node.ry = 5;
});
// Add some custom colors based on state
g.node('CLOSED').style = "fill: #f77";
g.node('ESTAB').style = "fill: #7f7";
var svg = d3.select("svg"),
inner = svg.select("g");
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
</script>
<script src="demo.js"></script>
+25
View File
@@ -0,0 +1,25 @@
.tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; }
.tipsy-inner { background-color: #000; color: #FFF; max-width: 200px; padding: 5px 8px 4px 8px; text-align: center; }
/* Rounded corners */
.tipsy-inner { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }
/* Uncomment for shadow */
.tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }
.tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #000; }
/* Rules to colour arrows */
.tipsy-arrow-n { border-bottom-color: #000; }
.tipsy-arrow-s { border-top-color: #000; }
.tipsy-arrow-e { border-left-color: #000; }
.tipsy-arrow-w { border-right-color: #000; }
.tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
.tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
.tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
.tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
.tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
.tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
.tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
.tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
+288
View File
@@ -0,0 +1,288 @@
// tipsy, facebook style tooltips for jquery
// version 1.0.0a
// (c) 2008-2010 jason frame [jason@onehackoranother.com]
// released under the MIT license
(function($) {
function maybeCall(thing, ctx) {
return (typeof thing == 'function') ? (thing.call(ctx)) : thing;
}
function Tipsy(element, options) {
this.$element = $(element);
this.options = options;
this.enabled = true;
this.fixTitle();
}
Tipsy.prototype = {
show: function() {
var title = this.getTitle();
if (title && this.enabled) {
var $tip = this.tip();
$tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
$tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
$tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body);
var pos = $.extend({}, this.$element.offset(), {
width: this.$element[0].offsetWidth || 0,
height: this.$element[0].offsetHeight || 0
});
if (typeof this.$element[0].nearestViewportElement == 'object') {
// SVG
var el = this.$element[0];
var rect = el.getBoundingClientRect();
pos.width = rect.width;
pos.height = rect.height;
}
var actualWidth = $tip[0].offsetWidth,
actualHeight = $tip[0].offsetHeight,
gravity = maybeCall(this.options.gravity, this.$element[0]);
var tp;
switch (gravity.charAt(0)) {
case 'n':
tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
break;
case 's':
tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
break;
case 'e':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
break;
case 'w':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
break;
}
if (gravity.length == 2) {
if (gravity.charAt(1) == 'w') {
tp.left = pos.left + pos.width / 2 - 15;
} else {
tp.left = pos.left + pos.width / 2 - actualWidth + 15;
}
}
$tip.css(tp).addClass('tipsy-' + gravity);
$tip.find('.tipsy-arrow')[0].className = 'tipsy-arrow tipsy-arrow-' + gravity.charAt(0);
if (this.options.className) {
$tip.addClass(maybeCall(this.options.className, this.$element[0]));
}
if (this.options.fade) {
$tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
} else {
$tip.css({visibility: 'visible', opacity: this.options.opacity});
}
var t = this;
var set_hovered = function(set_hover){
return function(){
t.$tip.stop();
t.tipHovered = set_hover;
if (!set_hover){
if (t.options.delayOut === 0) {
t.hide();
} else {
setTimeout(function() {
if (t.hoverState == 'out') t.hide(); }, t.options.delayOut);
}
}
};
};
$tip.hover(set_hovered(true), set_hovered(false));
}
},
hide: function() {
if (this.options.fade) {
this.tip().stop().fadeOut(function() { $(this).remove(); });
} else {
this.tip().remove();
}
},
fixTitle: function() {
var $e = this.$element;
if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
$e.attr('original-title', $e.attr('title') || '').removeAttr('title');
}
if (typeof $e.context.nearestViewportElement == 'object'){
if ($e.children('title').length){
$e.append('<original-title>' + ($e.children('title').text() || '') + '</original-title>')
.children('title').remove();
}
}
},
getTitle: function() {
var title, $e = this.$element, o = this.options;
this.fixTitle();
if (typeof o.title == 'string') {
var title_name = o.title == 'title' ? 'original-title' : o.title;
if ($e.children(title_name).length){
title = $e.children(title_name).html();
} else{
title = $e.attr(title_name);
}
} else if (typeof o.title == 'function') {
title = o.title.call($e[0]);
}
title = ('' + title).replace(/(^\s*|\s*$)/, "");
return title || o.fallback;
},
tip: function() {
if (!this.$tip) {
this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
}
return this.$tip;
},
validate: function() {
if (!this.$element[0].parentNode) {
this.hide();
this.$element = null;
this.options = null;
}
},
enable: function() { this.enabled = true; },
disable: function() { this.enabled = false; },
toggleEnabled: function() { this.enabled = !this.enabled; }
};
$.fn.tipsy = function(options) {
if (options === true) {
return this.data('tipsy');
} else if (typeof options == 'string') {
var tipsy = this.data('tipsy');
if (tipsy) tipsy[options]();
return this;
}
options = $.extend({}, $.fn.tipsy.defaults, options);
if (options.hoverlock && options.delayOut === 0) {
options.delayOut = 100;
}
function get(ele) {
var tipsy = $.data(ele, 'tipsy');
if (!tipsy) {
tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
$.data(ele, 'tipsy', tipsy);
}
return tipsy;
}
function enter() {
var tipsy = get(this);
tipsy.hoverState = 'in';
if (options.delayIn === 0) {
tipsy.show();
} else {
tipsy.fixTitle();
setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
}
}
function leave() {
var tipsy = get(this);
tipsy.hoverState = 'out';
if (options.delayOut === 0) {
tipsy.hide();
} else {
var to = function() {
if (!tipsy.tipHovered || !options.hoverlock){
if (tipsy.hoverState == 'out') tipsy.hide();
}
};
setTimeout(to, options.delayOut);
}
}
if (options.trigger != 'manual') {
var binder = options.live ? 'live' : 'bind',
eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
this[binder](eventIn, enter)[binder](eventOut, leave);
}
return this;
};
$.fn.tipsy.defaults = {
className: null,
delayIn: 0,
delayOut: 0,
fade: false,
fallback: '',
gravity: 'n',
html: false,
live: false,
offset: 0,
opacity: 0.8,
title: 'title',
trigger: 'hover',
hoverlock: false
};
// Overwrite this method to provide options on a per-element basis.
// For example, you could store the gravity in a 'tipsy-gravity' attribute:
// return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
// (remember - do not modify 'options' in place!)
$.fn.tipsy.elementOptions = function(ele, options) {
return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
};
$.fn.tipsy.autoNS = function() {
return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
};
$.fn.tipsy.autoWE = function() {
return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
};
/**
* yields a closure of the supplied parameters, producing a function that takes
* no arguments and is suitable for use as an autogravity function like so:
*
* @param margin (int) - distance from the viewable region edge that an
* element should be before setting its tooltip's gravity to be away
* from that edge.
* @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer
* if there are no viewable region edges effecting the tooltip's
* gravity. It will try to vary from this minimally, for example,
* if 'sw' is preferred and an element is near the right viewable
* region edge, but not the top edge, it will set the gravity for
* that element's tooltip to be 'se', preserving the southern
* component.
*/
$.fn.tipsy.autoBounds = function(margin, prefer) {
return function() {
var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
boundTop = $(document).scrollTop() + margin,
boundLeft = $(document).scrollLeft() + margin,
$this = $(this);
if ($this.offset().top < boundTop) dir.ns = 'n';
if ($this.offset().left < boundLeft) dir.ew = 'w';
if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
return dir.ns + (dir.ew ? dir.ew : '');
};
};
})(jQuery);
+114
View File
@@ -0,0 +1,114 @@
<!doctype html>
<meta charset="utf-8">
<title>Dagre D3 Demo: User-defined Shapes and Arrows</title>
<link rel="stylesheet" href="demo.css">
<script src="../dagre-d3.js"></script>
<style id="css">
body {
font: 300 14px 'Helvetica Neue', Helvetica;
}
.node rect,
.node circle,
.node ellipse,
.node polygon {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
.edgePath path.path {
stroke: #333;
fill: none;
stroke-width: 1.5px;
}
</style>
<h1>Dagre D3 Demo: User-defined Shapes and Arrows</h1>
<svg width=960 height=600><g/></svg>
<section>
<p>An example that shows how to create and use user-defined shapes and arrows.
</section>
<script id="js">
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
g.setNode("house", { shape: "house", label: "house" });
g.setNode("rect", { shape: "rect" });
g.setEdge("house", "rect", { arrowhead: "hollowPoint" });
var svg = d3.select("svg"),
inner = svg.select("g");
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Add our custom shape (a house)
render.shapes().house = function(parent, bbox, node) {
var w = bbox.width,
h = bbox.height,
points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
{ x: w, y: -h },
{ x: w/2, y: -h * 3/2 },
{ x: 0, y: -h }
];
shapeSvg = parent.insert("polygon", ":first-child")
.attr("points", points.map(function(d) { return d.x + "," + d.y; }).join(" "))
.attr("transform", "translate(" + (-w/2) + "," + (h * 3/4) + ")");
node.intersect = function(point) {
return dagreD3.intersect.polygon(node, points, point);
};
return shapeSvg;
};
// Add our custom arrow (a hollow-point)
render.arrows().hollowPoint = function normal(parent, id, edge, type) {
var marker = parent.append("marker")
.attr("id", id)
.attr("viewBox", "0 0 10 10")
.attr("refX", 9)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 8)
.attr("markerHeight", 6)
.attr("orient", "auto");
var path = marker.append("path")
.attr("d", "M 0 0 L 10 5 L 0 10 z")
.style("stroke-width", 1)
.style("stroke-dasharray", "1,0")
.style("fill", "#fff")
.style("stroke", "#333");
dagreD3.util.applyStyle(path, edge[type + "Style"]);
};
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
</script>
<script src="demo.js"></script>