提交 83012726 authored 作者: Christof Angermueller's avatar Christof Angermueller

Allow to move entire OFG nodes

上级 d882859c
# Experiment <a href="http://bl.ocks.org/3116713" title="view this gist via bl.ocks.org">?</a> <a href="http://bl.ocks.org/GerHobbelt" title="view a list of all my gists at bl.ocks.org">8</a>
copy of [http://mbostock.github.com/d3/talk/20111018/collision.html](http://mbostock.github.com/d3/talk/20111018/collision.html)
\ No newline at end of file
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<head>
<script src="http://d3js.org/d3.v2.js"></script>
<link type="text/css" rel="stylesheet" href="style000.css">
<style type="text/css">
circle {
stroke: #000;
stroke-opacity: .5;
}
</style>
</head>
<body>
<div id="body">
<div id="footer">
Collision Detection
<div class="hint">move the mouse to repel nodes</div>
</div>
</div>
<script type="text/javascript">
var w = 1280,
h = 800;
var nodes = d3.range(200).map(function() { return {radius: Math.random() * 12 + 4}; }),
color = d3.scale.category10();
var force = d3.layout.force()
.gravity(0.05)
.charge(function(d, i) { return i ? 0 : -2000; })
.nodes(nodes)
.size([w, h]);
var root = nodes[0];
root.radius = 0;
root.fixed = true;
force.start();
var svg = d3.select("#body").append("svg:svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("circle")
.data(nodes.slice(1))
.enter().append("svg:circle")
.attr("r", function(d) { return d.radius - 2; })
.style("fill", function(d, i) { return color(i % 3); });
force.on("tick", function(e) {
var q = d3.geom.quadtree(nodes),
i = 0,
n = nodes.length;
while (++i < n) {
q.visit(collide(nodes[i]));
}
svg.selectAll("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
svg.on("mousemove", function() {
var p1 = d3.svg.mouse(this);
root.px = p1[0];
root.py = p1[1];
force.resume();
});
function collide(node) {
var r = node.radius + 16,
nx1 = node.x - r,
nx2 = node.x + r,
ny1 = node.y - r,
ny2 = node.y + r;
return function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x,
y = node.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = node.radius + quad.point.radius;
if (l < r) {
l = (l - r) / l * .5;
x *= l;
node.x -= x;
quad.point.x += x;
y *= l;
node.y -= y;
quad.point.y += y;
}
}
return x1 > nx2
|| x2 < nx1
|| y1 > ny2
|| y2 < ny1;
};
}
</script>
</body>
</html>
<!-- This document saved from http://mbostock.github.com/d3/talk/20111018/collision.html -->
body {
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: "Helvetica Neue", Helvetica;
}
#chart, #header, #footer {
position: absolute;
top: 0;
}
#header, #footer {
z-index: 1;
display: block;
font-size: 36px;
font-weight: 300;
text-shadow: 0 1px 0 #fff;
}
#header.inverted, #footer.inverted {
color: #fff;
text-shadow: 0 1px 4px #000;
}
#header {
top: 80px;
left: 140px;
width: 1000px;
}
#footer {
top: 680px;
right: 140px;
text-align: right;
}
rect {
fill: none;
pointer-events: all;
}
pre {
font-size: 18px;
}
line {
stroke: #000;
stroke-width: 1.5px;
}
.string, .regexp {
color: #f39;
}
.keyword {
color: #00c;
}
.comment {
color: #777;
font-style: oblique;
}
.number {
color: #369;
}
.class, .special {
color: #1181B8;
}
a:link, a:visited {
color: #000;
text-decoration: none;
}
a:hover {
color: #666;
}
.hint {
position: absolute;
right: 0;
width: 1280px;
font-size: 12px;
color: #999;
}
\ No newline at end of file
...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
'id': child.id, 'id': child.id,
'value': child, 'value': child,
'index': nodes.length, 'index': nodes.length,
'fixed': true, 'fixed': fixedDefault,
'group': group, 'group': group,
'isParent': child.showChilds, 'isParent': child.showChilds,
'parent': parent 'parent': parent
...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
} else { } else {
group.nodes.push(node); group.nodes.push(node);
} }
group.childs = [];
for (var i = group.id + 1; i < groups.length; ++i) {
group.childs.push(groups[i].id);
}
} }
} }
...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) {
graph.nodesd[node.id] = node; graph.nodesd[node.id] = node;
} }
graph.groupsd = {};
for (var i in graph.groups) {
var group = graph.groups[i];
graph.groupsd[group.id] = group;
}
graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;}); graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;});
graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;}); graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;});
...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) {
if (exists(prevParent)) { if (exists(prevParent)) {
group.pos = [prevParent.x, prevParent.y]; group.pos = [prevParent.x, prevParent.y];
} else { } else {
group.pos = parent.pos.slice(0); group.pos = parent.value.pos.slice(0);
} }
group.pos[0] += parent.value.cx; group.pos[0] += parent.value.cx;
group.pos[1] += parent.value.cy; group.pos[1] += parent.value.cy;
...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) {
} }
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
node.x = group.pos[0];
node.y = group.pos[1];
} else {
node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0]; node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0];
node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1]; node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1];
} }
...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) { ...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) {
var points = []; var points = [];
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
points.push([node.x, node.y]);
} else {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]); points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]); points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]); points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]); points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
} }
} }
for (var k in group.childs) {
var nodes = graph.groupsd[group.childs[k]].nodes;
for (var j in nodes) {
var node = nodes[j];
if (!node.isParent) {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
}
}
}
hulls.push({group: i, path: d3.geom.hull(points)}); hulls.push({group: i, path: d3.geom.hull(points)});
} }
return hulls; return hulls;
...@@ -314,6 +331,42 @@ function setupGraph() { ...@@ -314,6 +331,42 @@ function setupGraph() {
var isEdgeOver = false; var isEdgeOver = false;
var isEdgeLabelOver = false; var isEdgeLabelOver = false;
var dragHulls = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault();
layout.stop();
})
.on("drag", function dragged(d) {
var group = graph.groups[d.group];
for (var i in group.nodes) {
var node = group.nodes[i];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
}
group.pos[0] += d3.event.dx;
group.pos[1] += d3.event.dy;
for (var k in group.childs) {
var cgroup = graph.groupsd[group.childs[k]];
var nodes = cgroup.nodes;
for (var j in nodes) {
var node = nodes[j];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
cgroup.pos[0] += d3.event.dx;
cgroup.pos[1] += d3.event.dy;
}
}
updateGraph();
})
.on('dragend', function(d) {layout.resume();});
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls = pane.selectAll('#hulls').remove(); hulls = pane.selectAll('#hulls').remove();
hulls = pane.append('g').attr('id', 'hulls') hulls = pane.append('g').attr('id', 'hulls')
...@@ -321,12 +374,18 @@ function setupGraph() { ...@@ -321,12 +374,18 @@ function setupGraph() {
.data(graph.hulls).enter() .data(graph.hulls).enter()
.append('path') .append('path')
.attr('class', 'hull') .attr('class', 'hull')
.attr('d', drawCluster); .attr('d', drawCluster)
.call(dragHulls);
hulls.on('dblclick', function(d) { hulls.on('dblclick', function(d) {
var parent = graph.groups[d.group].parent; var group = graph.groups[d.group];
parent.value.showChilds = !parent.value.showChilds; group.parent.value.showChilds = !group.parent.value.showChilds;
if (!group.parent.value.showChilds) {
for (i in group.childs) {
var child = graph.groupsd[group.childs[i]];
child.parent.value.showChilds = false;
}
}
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
setupGraph(); setupGraph();
}); });
...@@ -376,6 +435,12 @@ function setupGraph() { ...@@ -376,6 +435,12 @@ function setupGraph() {
if (d.value.hasChilds) { if (d.value.hasChilds) {
d.value.showChilds = !d.value.showChilds; d.value.showChilds = !d.value.showChilds;
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
if (!fixedDefault && d.value.showChilds) {
var n = dotGraph.neighbors(d.id);
for (i in n) {
graph.nodesd[n[i]].fixed = false;
}
}
setupGraph(); setupGraph();
} }
}); });
...@@ -422,11 +487,15 @@ function setupGraph() { ...@@ -422,11 +487,15 @@ function setupGraph() {
.nodes(graph.nodes) .nodes(graph.nodes)
.links(graph.edges) .links(graph.edges)
.size(graph.size) .size(graph.size)
.charge(-300) .linkDistance(function(d) {
.linkDistance(400) return 300;
.linkStrength(0.4) })
.gravity(0) .charge(-600)
.on('tick', updateGraph); .linkStrength(1)
.gravity(0.05)
.friction(0.5)
.on('tick', updateGraph)
.start();
// Drag behavour // Drag behavour
var drag = layout.drag() var drag = layout.drag()
...@@ -436,9 +505,6 @@ function setupGraph() { ...@@ -436,9 +505,6 @@ function setupGraph() {
d.fixed = true; d.fixed = true;
}); });
nodes.call(drag); nodes.call(drag);
// Start force layout
layout.start();
} }
function length(x1, y1, x2, y2) { function length(x1, y1, x2, y2) {
...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) { ...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) {
return p; return p;
} }
function collide(node) {
var eps = 10;
var nx1 = node.x - node.value.cx - eps;
var nx2 = node.x + node.value.cx + eps;
var ny1 = node.y - node.value.cy - eps;
var ny2 = node.y + node.value.cy + eps;
return function(quad, x1, y1, x2, y2) {
var point = quad.point;
if (point && (point != node) && !point.fixed && ! node.fixed) {
var px1 = point.x - point.value.cx;
var px2 = point.x + point.value.cx;
var py1 = point.y - point.value.cy;
var py2 = point.y + point.value.cy;
if (!(px1 > nx2 || px2 < nx1 || py1 >= ny2 || py2 <= ny1)) {
var eta = 0.1;
if (px1 < nx1) {
// move quad to left
var d = eta * (px2 - nx1);
point.x -= d;
node.x += d;
} else {
var d = eta * (nx2 - px1);
point.x += d;
node.x -= d;
}
if (py1 < ny1) {
// move quad to top
var d = eta * (py2 - ny1);
point.y -= d;
node.y += d;
} else {
var d = eta * (ny2 - py1);
point.y += d;
node.y -= d;
}
}
}
return x1 > nx2 || x2 < nx1 || y1 >= ny2 || y2 <= ny1;
};
}
function updateGraph() { function updateGraph() {
var q = d3.geom.quadtree(graph.nodes);
for (var i in graph.nodes) {
q.visit(collide(graph.nodes[i]));
}
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls.data(graph.hulls) hulls.data(graph.hulls)
.attr('d', drawCluster); .attr('d', drawCluster);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
var isProfiled = false; var isProfiled = false;
var colorProfile = false; var colorProfile = false;
var fixedDefault = true;
var maxProfilePer = 0; var maxProfilePer = 0;
var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"]; var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"];
......
...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
'id': child.id, 'id': child.id,
'value': child, 'value': child,
'index': nodes.length, 'index': nodes.length,
'fixed': true, 'fixed': fixedDefault,
'group': group, 'group': group,
'isParent': child.showChilds, 'isParent': child.showChilds,
'parent': parent 'parent': parent
...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
} else { } else {
group.nodes.push(node); group.nodes.push(node);
} }
group.childs = [];
for (var i = group.id + 1; i < groups.length; ++i) {
group.childs.push(groups[i].id);
}
} }
} }
...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) {
graph.nodesd[node.id] = node; graph.nodesd[node.id] = node;
} }
graph.groupsd = {};
for (var i in graph.groups) {
var group = graph.groups[i];
graph.groupsd[group.id] = group;
}
graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;}); graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;});
graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;}); graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;});
...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) {
if (exists(prevParent)) { if (exists(prevParent)) {
group.pos = [prevParent.x, prevParent.y]; group.pos = [prevParent.x, prevParent.y];
} else { } else {
group.pos = parent.pos.slice(0); group.pos = parent.value.pos.slice(0);
} }
group.pos[0] += parent.value.cx; group.pos[0] += parent.value.cx;
group.pos[1] += parent.value.cy; group.pos[1] += parent.value.cy;
...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) {
} }
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
node.x = group.pos[0];
node.y = group.pos[1];
} else {
node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0]; node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0];
node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1]; node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1];
} }
...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) { ...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) {
var points = []; var points = [];
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
points.push([node.x, node.y]);
} else {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]); points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]); points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]); points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]); points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
} }
} }
for (var k in group.childs) {
var nodes = graph.groupsd[group.childs[k]].nodes;
for (var j in nodes) {
var node = nodes[j];
if (!node.isParent) {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
}
}
}
hulls.push({group: i, path: d3.geom.hull(points)}); hulls.push({group: i, path: d3.geom.hull(points)});
} }
return hulls; return hulls;
...@@ -314,6 +331,42 @@ function setupGraph() { ...@@ -314,6 +331,42 @@ function setupGraph() {
var isEdgeOver = false; var isEdgeOver = false;
var isEdgeLabelOver = false; var isEdgeLabelOver = false;
var dragHulls = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault();
layout.stop();
})
.on("drag", function dragged(d) {
var group = graph.groups[d.group];
for (var i in group.nodes) {
var node = group.nodes[i];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
}
group.pos[0] += d3.event.dx;
group.pos[1] += d3.event.dy;
for (var k in group.childs) {
var cgroup = graph.groupsd[group.childs[k]];
var nodes = cgroup.nodes;
for (var j in nodes) {
var node = nodes[j];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
cgroup.pos[0] += d3.event.dx;
cgroup.pos[1] += d3.event.dy;
}
}
updateGraph();
})
.on('dragend', function(d) {layout.resume();});
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls = pane.selectAll('#hulls').remove(); hulls = pane.selectAll('#hulls').remove();
hulls = pane.append('g').attr('id', 'hulls') hulls = pane.append('g').attr('id', 'hulls')
...@@ -321,12 +374,18 @@ function setupGraph() { ...@@ -321,12 +374,18 @@ function setupGraph() {
.data(graph.hulls).enter() .data(graph.hulls).enter()
.append('path') .append('path')
.attr('class', 'hull') .attr('class', 'hull')
.attr('d', drawCluster); .attr('d', drawCluster)
.call(dragHulls);
hulls.on('dblclick', function(d) { hulls.on('dblclick', function(d) {
var parent = graph.groups[d.group].parent; var group = graph.groups[d.group];
parent.value.showChilds = !parent.value.showChilds; group.parent.value.showChilds = !group.parent.value.showChilds;
if (!group.parent.value.showChilds) {
for (i in group.childs) {
var child = graph.groupsd[group.childs[i]];
child.parent.value.showChilds = false;
}
}
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
setupGraph(); setupGraph();
}); });
...@@ -376,6 +435,12 @@ function setupGraph() { ...@@ -376,6 +435,12 @@ function setupGraph() {
if (d.value.hasChilds) { if (d.value.hasChilds) {
d.value.showChilds = !d.value.showChilds; d.value.showChilds = !d.value.showChilds;
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
if (!fixedDefault && d.value.showChilds) {
var n = dotGraph.neighbors(d.id);
for (i in n) {
graph.nodesd[n[i]].fixed = false;
}
}
setupGraph(); setupGraph();
} }
}); });
...@@ -422,11 +487,15 @@ function setupGraph() { ...@@ -422,11 +487,15 @@ function setupGraph() {
.nodes(graph.nodes) .nodes(graph.nodes)
.links(graph.edges) .links(graph.edges)
.size(graph.size) .size(graph.size)
.charge(-300) .linkDistance(function(d) {
.linkDistance(400) return 300;
.linkStrength(0.4) })
.gravity(0) .charge(-600)
.on('tick', updateGraph); .linkStrength(1)
.gravity(0.05)
.friction(0.5)
.on('tick', updateGraph)
.start();
// Drag behavour // Drag behavour
var drag = layout.drag() var drag = layout.drag()
...@@ -436,9 +505,6 @@ function setupGraph() { ...@@ -436,9 +505,6 @@ function setupGraph() {
d.fixed = true; d.fixed = true;
}); });
nodes.call(drag); nodes.call(drag);
// Start force layout
layout.start();
} }
function length(x1, y1, x2, y2) { function length(x1, y1, x2, y2) {
...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) { ...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) {
return p; return p;
} }
function collide(node) {
var eps = 10;
var nx1 = node.x - node.value.cx - eps;
var nx2 = node.x + node.value.cx + eps;
var ny1 = node.y - node.value.cy - eps;
var ny2 = node.y + node.value.cy + eps;
return function(quad, x1, y1, x2, y2) {
var point = quad.point;
if (point && (point != node) && !point.fixed && ! node.fixed) {
var px1 = point.x - point.value.cx;
var px2 = point.x + point.value.cx;
var py1 = point.y - point.value.cy;
var py2 = point.y + point.value.cy;
if (!(px1 > nx2 || px2 < nx1 || py1 >= ny2 || py2 <= ny1)) {
var eta = 0.1;
if (px1 < nx1) {
// move quad to left
var d = eta * (px2 - nx1);
point.x -= d;
node.x += d;
} else {
var d = eta * (nx2 - px1);
point.x += d;
node.x -= d;
}
if (py1 < ny1) {
// move quad to top
var d = eta * (py2 - ny1);
point.y -= d;
node.y += d;
} else {
var d = eta * (ny2 - py1);
point.y += d;
node.y -= d;
}
}
}
return x1 > nx2 || x2 < nx1 || y1 >= ny2 || y2 <= ny1;
};
}
function updateGraph() { function updateGraph() {
var q = d3.geom.quadtree(graph.nodes);
for (var i in graph.nodes) {
q.visit(collide(graph.nodes[i]));
}
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls.data(graph.hulls) hulls.data(graph.hulls)
.attr('d', drawCluster); .attr('d', drawCluster);
......
digraph G { digraph G {
graph [bb="0,0,2606,316"]; graph [bb="0,0,2605,316"];
node [label="\N"]; node [label="\N"];
subgraph cluster_n1 { subgraph cluster_n1 {
graph [bb="1160,80,1875,308"]; graph [bb="1159,80,1874,308"];
n11 [fillcolor="#FFAABB", n11 [fillcolor="#FFAABB",
height=0.5, height=0.5,
label="Elemwise{Composite{(i0 + (i1 * i2))}}", label="Elemwise{Composite{(i0 + (i1 * i2))}}",
pos="1510,194", pos="1509,194",
shape=ellipse, shape=ellipse,
style=filled, style=filled,
type=colored, type=colored,
...@@ -14,50 +14,50 @@ digraph G { ...@@ -14,50 +14,50 @@ digraph G {
n15 [fillcolor=dodgerblue, n15 [fillcolor=dodgerblue,
height=0.5, height=0.5,
label="TensorType(float32, scalar)", label="TensorType(float32, scalar)",
pos="1510,106", pos="1509,106",
shape=box, shape=box,
style=filled, style=filled,
width=2.3889]; width=2.3889];
n11 -> n15 [label="TensorType(float32, scalar)", n11 -> n15 [label="TensorType(float32, scalar)",
lp="1588,150", lp="1587,150",
pos="e,1510,124.08 1510,175.6 1510,163.75 1510,147.82 1510,134.29"]; pos="e,1509,124.08 1509,175.6 1509,163.75 1509,147.82 1509,134.29"];
n12 [fillcolor=limegreen, n12 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=x TensorType(float32, scalar)", label="name=x TensorType(float32, scalar)",
pos="1756,282", pos="1755,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n12 -> n11 [label="0 TensorType(float32, scalar)", n12 -> n11 [label="0 TensorType(float32, scalar)",
lp="1791.5,238", lp="1790.5,238",
pos="e,1604.7,208.31 1734.7,263.92 1719.7,252.69 1698.6,238.53 1678,230 1658.1,221.75 1636,215.37 1614.5,210.46"]; pos="e,1603.7,208.31 1733.7,263.92 1718.7,252.69 1697.6,238.53 1677,230 1657.1,221.75 1635,215.37 1613.5,210.46"];
n13 [fillcolor=limegreen, n13 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=y TensorType(float32, scalar)", label="name=y TensorType(float32, scalar)",
pos="1517,282", pos="1516,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n13 -> n11 [label="1 TensorType(float32, scalar)", n13 -> n11 [label="1 TensorType(float32, scalar)",
lp="1594.5,238", lp="1593.5,238",
pos="e,1509.7,212.04 1513.6,263.98 1512.5,258.29 1511.6,251.89 1511,246 1510.3,238.24 1509.9,229.79 1509.8,222.04"]; pos="e,1508.7,212.04 1512.6,263.98 1511.5,258.29 1510.6,251.89 1510,246 1509.3,238.24 1508.9,229.79 1508.8,222.04"];
n14 [fillcolor=limegreen, n14 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=z TensorType(float32, scalar)", label="name=z TensorType(float32, scalar)",
pos="1278,282", pos="1277,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0556]; width=3.0556];
n14 -> n11 [label="2 TensorType(float32, scalar)", n14 -> n11 [label="2 TensorType(float32, scalar)",
lp="1423.5,238", lp="1422.5,238",
pos="e,1408,207.64 1294.3,263.77 1306,252.46 1322.6,238.29 1340,230 1358.1,221.35 1378.3,214.83 1398.3,209.92"]; pos="e,1407,207.64 1293.3,263.77 1305,252.46 1321.6,238.29 1339,230 1357.1,221.35 1377.3,214.83 1397.3,209.92"];
} }
subgraph cluster_n6 { subgraph cluster_n6 {
graph [bb="1883,80,2598,308"]; graph [bb="1882,80,2597,308"];
n61 [fillcolor="#FFAABB", n61 [fillcolor="#FFAABB",
height=0.5, height=0.5,
label="Elemwise{Composite{(i0 + (i1 * i2))}}", label="Elemwise{Composite{(i0 + (i1 * i2))}}",
pos="2233,194", pos="2232,194",
shape=ellipse, shape=ellipse,
style=filled, style=filled,
type=colored, type=colored,
...@@ -65,124 +65,124 @@ digraph G { ...@@ -65,124 +65,124 @@ digraph G {
n65 [fillcolor=dodgerblue, n65 [fillcolor=dodgerblue,
height=0.5, height=0.5,
label="TensorType(float32, scalar)", label="TensorType(float32, scalar)",
pos="2233,106", pos="2232,106",
shape=box, shape=box,
style=filled, style=filled,
width=2.3889]; width=2.3889];
n61 -> n65 [label="TensorType(float32, scalar)", n61 -> n65 [label="TensorType(float32, scalar)",
lp="2311,150", lp="2310,150",
pos="e,2233,124.08 2233,175.6 2233,163.75 2233,147.82 2233,134.29"]; pos="e,2232,124.08 2232,175.6 2232,163.75 2232,147.82 2232,134.29"];
n62 [fillcolor=limegreen, n62 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=x TensorType(float32, scalar)", label="name=x TensorType(float32, scalar)",
pos="2479,282", pos="2478,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n62 -> n61 [label="0 TensorType(float32, scalar)", n62 -> n61 [label="0 TensorType(float32, scalar)",
lp="2513.5,238", lp="2512.5,238",
pos="e,2327.7,208.31 2457.7,263.92 2442.7,252.69 2421.6,238.53 2401,230 2381.1,221.75 2359,215.37 2337.5,210.46"]; pos="e,2326.7,208.31 2456.7,263.92 2441.7,252.69 2420.6,238.53 2400,230 2380.1,221.75 2358,215.37 2336.5,210.46"];
n63 [fillcolor=limegreen, n63 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=y TensorType(float32, scalar)", label="name=y TensorType(float32, scalar)",
pos="2240,282", pos="2239,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n63 -> n61 [label="1 TensorType(float32, scalar)", n63 -> n61 [label="1 TensorType(float32, scalar)",
lp="2317.5,238", lp="2316.5,238",
pos="e,2232.7,212.04 2236.6,263.98 2235.5,258.29 2234.6,251.89 2234,246 2233.3,238.24 2232.9,229.79 2232.8,222.04"]; pos="e,2231.7,212.04 2235.6,263.98 2234.5,258.29 2233.6,251.89 2233,246 2232.3,238.24 2231.9,229.79 2231.8,222.04"];
n64 [fillcolor=limegreen, n64 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=z TensorType(float32, scalar)", label="name=z TensorType(float32, scalar)",
pos="2001,282", pos="2000,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0556]; width=3.0556];
n64 -> n61 [label="2 TensorType(float32, scalar)", n64 -> n61 [label="2 TensorType(float32, scalar)",
lp="2146.5,238", lp="2145.5,238",
pos="e,2131,207.64 2017.3,263.77 2029,252.46 2045.6,238.29 2063,230 2081.1,221.35 2101.3,214.83 2121.3,209.92"]; pos="e,2130,207.64 2016.3,263.77 2028,252.46 2044.6,238.29 2062,230 2080.1,221.35 2100.3,214.83 2120.3,209.92"];
} }
n1 [height=0.5, n1 [height=0.5,
label="theano.compile.builders.OpFromGraph object at 0x1100c70d0", label="theano.compile.builders.OpFromGraph object at 0x110c3e110",
pos="239,194", pos="238,194",
shape=ellipse, shape=ellipse,
subg=cluster_n1, subg=cluster_n1,
subg_map_inputs="[['n2', 'n12'], ['n3', 'n13'], ['n3', 'n14']]", subg_map_inputs="[['n2', 'n12'], ['n3', 'n13'], ['n3', 'n14']]",
subg_map_outputs="[['n15', 'n5']]", subg_map_outputs="[['n15', 'n5']]",
width=6.6414]; width=6.6185];
n5 [fillcolor="#FFAABB", n5 [fillcolor="#FFAABB",
height=0.5, height=0.5,
label="Elemwise{Add}[(0, 0)]", label="Elemwise{Add}[(0, 0)]",
pos="554,106", pos="553,106",
shape=ellipse, shape=ellipse,
style=filled, style=filled,
type=colored, type=colored,
width=2.6784]; width=2.6784];
n1 -> n5 [label="1 TensorType(float32, scalar)", n1 -> n5 [label="1 TensorType(float32, scalar)",
lp="508.5,150", lp="507.5,150",
pos="e,501.93,121.21 299.36,176.52 354.72,161.41 436.35,139.12 492.17,123.88"]; pos="e,500.93,121.21 298.36,176.52 353.72,161.41 435.35,139.12 491.17,123.88"];
n2 [fillcolor=limegreen, n2 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=z TensorType(float32, scalar)", label="name=z TensorType(float32, scalar)",
pos="675,282", pos="674,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0556]; width=3.0556];
n2 -> n1 [label="0 TensorType(float32, scalar)", n2 -> n1 [label="0 TensorType(float32, scalar)",
lp="685.5,238", lp="684.5,238",
pos="e,431.16,204.72 634.61,263.87 623.72,258.66 612.15,252.56 602,246 592.73,240.01 593.17,234.31 583,230 556.22,218.66 500.43,210.89 \ pos="e,430.16,204.72 633.61,263.87 622.72,258.66 611.15,252.56 601,246 591.73,240.01 592.17,234.31 582,230 555.22,218.66 499.43,210.89 \
441.43,205.61"]; 440.43,205.61"];
n6 [height=0.5, n6 [height=0.5,
label="theano.compile.builders.OpFromGraph object at 0x1100c70d0 id=1", label="theano.compile.builders.OpFromGraph object at 0x110c3e110 id=1",
pos="781,194", pos="780,194",
shape=ellipse, shape=ellipse,
subg=cluster_n6, subg=cluster_n6,
subg_map_inputs="[['n7', 'n62'], ['n3', 'n63'], ['n2', 'n64']]", subg_map_inputs="[['n7', 'n62'], ['n3', 'n63'], ['n2', 'n64']]",
subg_map_outputs="[['n65', 'n5']]", subg_map_outputs="[['n65', 'n5']]",
width=7.167]; width=7.1441];
n2 -> n6 [label="2 TensorType(float32, scalar)", n2 -> n6 [label="2 TensorType(float32, scalar)",
lp="864.5,238", lp="863.5,238",
pos="e,782.5,212.41 750.62,263.79 759.11,259.2 766.89,253.37 773,246 778.39,239.5 780.89,230.87 781.91,222.57"]; pos="e,781.5,212.41 749.62,263.79 758.11,259.2 765.89,253.37 772,246 777.39,239.5 779.89,230.87 780.91,222.57"];
n3 [fillcolor=limegreen, n3 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=y TensorType(float32, scalar)", label="name=y TensorType(float32, scalar)",
pos="225,282", pos="224,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n3 -> n1 [label="1 TensorType(float32, scalar)", n3 -> n1 [label="1 TensorType(float32, scalar)",
lp="309.5,238", lp="308.5,238",
pos="e,231.34,212.12 223.91,263.85 223.64,253.89 223.89,241.14 226,230 226.51,227.29 227.22,224.51 228.03,221.76"]; pos="e,230.34,212.12 222.91,263.85 222.64,253.89 222.89,241.14 225,230 225.51,227.29 226.22,224.51 227.03,221.76"];
n3 -> n1 [label="2 TensorType(float32, scalar)", n3 -> n1 [label="2 TensorType(float32, scalar)",
lp="137.5,238", lp="136.5,238",
pos="e,102.68,208.9 114.52,277.73 68.058,272.21 29.738,259.28 54,230 60.527,222.12 74.92,216.01 92.944,211.26"]; pos="e,102.14,208.8 113.52,277.73 67.058,272.21 28.738,259.28 53,230 59.571,222.07 74.117,215.92 92.313,211.16"];
n3 -> n6 [label="1 TensorType(float32, scalar)", n3 -> n6 [label="1 TensorType(float32, scalar)",
lp="495.5,238", lp="494.5,238",
pos="e,569.49,204.32 335.59,266.1 355.29,261.19 375.18,254.66 393,246 402.93,241.17 401.82,234.27 412,230 440.03,218.24 497.65,210.39 \ pos="e,568.49,204.32 334.59,266.1 354.29,261.19 374.18,254.66 392,246 401.93,241.17 400.82,234.27 411,230 439.03,218.24 496.65,210.39 \
559.18,205.17"]; 558.18,205.17"];
n6 -> n5 [color=red, n6 -> n5 [color=red,
label="0 TensorType(float32, scalar)", label="0 TensorType(float32, scalar)",
lp="771.5,150", lp="770.5,150",
pos="e,594.76,122.44 736.69,176.21 698.67,161.81 643.89,141.06 604.24,126.03"]; pos="e,593.76,122.44 735.69,176.21 697.67,161.81 642.89,141.06 603.24,126.03"];
n7 [fillcolor=limegreen, n7 [fillcolor=limegreen,
height=0.5, height=0.5,
label="name=x TensorType(float32, scalar)", label="name=x TensorType(float32, scalar)",
pos="985,282", pos="984,282",
shape=box, shape=box,
style=filled, style=filled,
width=3.0625]; width=3.0625];
n7 -> n6 [label="0 TensorType(float32, scalar)", n7 -> n6 [label="0 TensorType(float32, scalar)",
lp="1051.5,238", lp="1050.5,238",
pos="e,909.79,209.62 978.09,263.71 972.67,252.39 964.02,238.21 952,230 942.03,223.19 931.02,217.65 919.54,213.16"]; pos="e,908.79,209.62 977.09,263.71 971.67,252.39 963.02,238.21 951,230 941.03,223.19 930.02,217.65 918.54,213.16"];
n9 [fillcolor=dodgerblue, n9 [fillcolor=dodgerblue,
height=0.5, height=0.5,
label="TensorType(float32, scalar) id=5", label="TensorType(float32, scalar) id=5",
pos="554,18", pos="553,18",
shape=box, shape=box,
style=filled, style=filled,
width=2.7847]; width=2.7847];
n5 -> n9 [label="TensorType(float32, scalar)", n5 -> n9 [label="TensorType(float32, scalar)",
lp="632,62", lp="631,62",
pos="e,554,36.084 554,87.597 554,75.746 554,59.817 554,46.292"]; pos="e,553,36.084 553,87.597 553,75.746 553,59.817 553,46.292"];
} }
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
var isProfiled = false; var isProfiled = false;
var colorProfile = false; var colorProfile = false;
var fixedDefault = true;
var maxProfilePer = 0; var maxProfilePer = 0;
var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"]; var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"];
......
...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
'id': child.id, 'id': child.id,
'value': child, 'value': child,
'index': nodes.length, 'index': nodes.length,
'fixed': true, 'fixed': fixedDefault,
'group': group, 'group': group,
'isParent': child.showChilds, 'isParent': child.showChilds,
'parent': parent 'parent': parent
...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
} else { } else {
group.nodes.push(node); group.nodes.push(node);
} }
group.childs = [];
for (var i = group.id + 1; i < groups.length; ++i) {
group.childs.push(groups[i].id);
}
} }
} }
...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) {
graph.nodesd[node.id] = node; graph.nodesd[node.id] = node;
} }
graph.groupsd = {};
for (var i in graph.groups) {
var group = graph.groups[i];
graph.groupsd[group.id] = group;
}
graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;}); graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;});
graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;}); graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;});
...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) {
if (exists(prevParent)) { if (exists(prevParent)) {
group.pos = [prevParent.x, prevParent.y]; group.pos = [prevParent.x, prevParent.y];
} else { } else {
group.pos = parent.pos.slice(0); group.pos = parent.value.pos.slice(0);
} }
group.pos[0] += parent.value.cx; group.pos[0] += parent.value.cx;
group.pos[1] += parent.value.cy; group.pos[1] += parent.value.cy;
...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) {
} }
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
node.x = group.pos[0];
node.y = group.pos[1];
} else {
node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0]; node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0];
node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1]; node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1];
} }
...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) { ...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) {
var points = []; var points = [];
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
points.push([node.x, node.y]);
} else {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]); points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]); points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]); points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]); points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
} }
} }
for (var k in group.childs) {
var nodes = graph.groupsd[group.childs[k]].nodes;
for (var j in nodes) {
var node = nodes[j];
if (!node.isParent) {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
}
}
}
hulls.push({group: i, path: d3.geom.hull(points)}); hulls.push({group: i, path: d3.geom.hull(points)});
} }
return hulls; return hulls;
...@@ -314,6 +331,42 @@ function setupGraph() { ...@@ -314,6 +331,42 @@ function setupGraph() {
var isEdgeOver = false; var isEdgeOver = false;
var isEdgeLabelOver = false; var isEdgeLabelOver = false;
var dragHulls = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault();
layout.stop();
})
.on("drag", function dragged(d) {
var group = graph.groups[d.group];
for (var i in group.nodes) {
var node = group.nodes[i];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
}
group.pos[0] += d3.event.dx;
group.pos[1] += d3.event.dy;
for (var k in group.childs) {
var cgroup = graph.groupsd[group.childs[k]];
var nodes = cgroup.nodes;
for (var j in nodes) {
var node = nodes[j];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
cgroup.pos[0] += d3.event.dx;
cgroup.pos[1] += d3.event.dy;
}
}
updateGraph();
})
.on('dragend', function(d) {layout.resume();});
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls = pane.selectAll('#hulls').remove(); hulls = pane.selectAll('#hulls').remove();
hulls = pane.append('g').attr('id', 'hulls') hulls = pane.append('g').attr('id', 'hulls')
...@@ -321,12 +374,18 @@ function setupGraph() { ...@@ -321,12 +374,18 @@ function setupGraph() {
.data(graph.hulls).enter() .data(graph.hulls).enter()
.append('path') .append('path')
.attr('class', 'hull') .attr('class', 'hull')
.attr('d', drawCluster); .attr('d', drawCluster)
.call(dragHulls);
hulls.on('dblclick', function(d) { hulls.on('dblclick', function(d) {
var parent = graph.groups[d.group].parent; var group = graph.groups[d.group];
parent.value.showChilds = !parent.value.showChilds; group.parent.value.showChilds = !group.parent.value.showChilds;
if (!group.parent.value.showChilds) {
for (i in group.childs) {
var child = graph.groupsd[group.childs[i]];
child.parent.value.showChilds = false;
}
}
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
setupGraph(); setupGraph();
}); });
...@@ -376,6 +435,12 @@ function setupGraph() { ...@@ -376,6 +435,12 @@ function setupGraph() {
if (d.value.hasChilds) { if (d.value.hasChilds) {
d.value.showChilds = !d.value.showChilds; d.value.showChilds = !d.value.showChilds;
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
if (!fixedDefault && d.value.showChilds) {
var n = dotGraph.neighbors(d.id);
for (i in n) {
graph.nodesd[n[i]].fixed = false;
}
}
setupGraph(); setupGraph();
} }
}); });
...@@ -422,11 +487,15 @@ function setupGraph() { ...@@ -422,11 +487,15 @@ function setupGraph() {
.nodes(graph.nodes) .nodes(graph.nodes)
.links(graph.edges) .links(graph.edges)
.size(graph.size) .size(graph.size)
.charge(-300) .linkDistance(function(d) {
.linkDistance(400) return 300;
.linkStrength(0.4) })
.gravity(0) .charge(-600)
.on('tick', updateGraph); .linkStrength(1)
.gravity(0.05)
.friction(0.5)
.on('tick', updateGraph)
.start();
// Drag behavour // Drag behavour
var drag = layout.drag() var drag = layout.drag()
...@@ -436,9 +505,6 @@ function setupGraph() { ...@@ -436,9 +505,6 @@ function setupGraph() {
d.fixed = true; d.fixed = true;
}); });
nodes.call(drag); nodes.call(drag);
// Start force layout
layout.start();
} }
function length(x1, y1, x2, y2) { function length(x1, y1, x2, y2) {
...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) { ...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) {
return p; return p;
} }
function collide(node) {
var eps = 10;
var nx1 = node.x - node.value.cx - eps;
var nx2 = node.x + node.value.cx + eps;
var ny1 = node.y - node.value.cy - eps;
var ny2 = node.y + node.value.cy + eps;
return function(quad, x1, y1, x2, y2) {
var point = quad.point;
if (point && (point != node) && !point.fixed && ! node.fixed) {
var px1 = point.x - point.value.cx;
var px2 = point.x + point.value.cx;
var py1 = point.y - point.value.cy;
var py2 = point.y + point.value.cy;
if (!(px1 > nx2 || px2 < nx1 || py1 >= ny2 || py2 <= ny1)) {
var eta = 0.1;
if (px1 < nx1) {
// move quad to left
var d = eta * (px2 - nx1);
point.x -= d;
node.x += d;
} else {
var d = eta * (nx2 - px1);
point.x += d;
node.x -= d;
}
if (py1 < ny1) {
// move quad to top
var d = eta * (py2 - ny1);
point.y -= d;
node.y += d;
} else {
var d = eta * (ny2 - py1);
point.y += d;
node.y -= d;
}
}
}
return x1 > nx2 || x2 < nx1 || y1 >= ny2 || y2 <= ny1;
};
}
function updateGraph() { function updateGraph() {
var q = d3.geom.quadtree(graph.nodes);
for (var i in graph.nodes) {
q.visit(collide(graph.nodes[i]));
}
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls.data(graph.hulls) hulls.data(graph.hulls)
.attr('d', drawCluster); .attr('d', drawCluster);
......
...@@ -45,7 +45,7 @@ digraph G { ...@@ -45,7 +45,7 @@ digraph G {
pos="e,1645.8,223.99 1616.5,279.94 1613.1,269.27 1611.1,255.75 1618,246 1623,238.94 1629.5,233.29 1636.9,228.78"]; pos="e,1645.8,223.99 1616.5,279.94 1613.1,269.27 1611.1,255.75 1618,246 1623,238.94 1629.5,233.29 1636.9,228.78"];
} }
n11 [height=0.5, n11 [height=0.5,
label="theano.compile.builders.OpFromGraph object at 0x1105b0c50", label="theano.compile.builders.OpFromGraph object at 0x11117c650",
pos="1258,210", pos="1258,210",
shape=ellipse, shape=ellipse,
subg=cluster_n11, subg=cluster_n11,
...@@ -106,7 +106,7 @@ digraph G { ...@@ -106,7 +106,7 @@ digraph G {
pos="e,1003.2,139.58 918.79,191.8 940.57,178.33 971.02,159.49 994.55,144.93"]; pos="e,1003.2,139.58 918.79,191.8 940.57,178.33 971.02,159.49 994.55,144.93"];
} }
n1 [height=0.5, n1 [height=0.5,
label="theano.compile.builders.OpFromGraph object at 0x1105a91d0", label="theano.compile.builders.OpFromGraph object at 0x11117cbd0",
pos="524,210", pos="524,210",
shape=ellipse, shape=ellipse,
subg=cluster_n1, subg=cluster_n1,
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
var isProfiled = false; var isProfiled = false;
var colorProfile = false; var colorProfile = false;
var fixedDefault = true;
var maxProfilePer = 0; var maxProfilePer = 0;
var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"]; var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"];
......
...@@ -86,17 +86,6 @@ ...@@ -86,17 +86,6 @@
"[Open](./example1/index.html)" "[Open](./example1/index.html)"
] ]
}, },
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"topo = f.maker.fgraph.toposort()"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
...@@ -106,7 +95,7 @@ ...@@ -106,7 +95,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 6,
"metadata": { "metadata": {
"collapsed": false "collapsed": false
}, },
...@@ -123,7 +112,7 @@ ...@@ -123,7 +112,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 7,
"metadata": { "metadata": {
"collapsed": false "collapsed": false
}, },
......
...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -108,7 +108,7 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
'id': child.id, 'id': child.id,
'value': child, 'value': child,
'index': nodes.length, 'index': nodes.length,
'fixed': true, 'fixed': fixedDefault,
'group': group, 'group': group,
'isParent': child.showChilds, 'isParent': child.showChilds,
'parent': parent 'parent': parent
...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) { ...@@ -119,6 +119,10 @@ function traverseChilds(dotGraph, nodes, groups, parent) {
} else { } else {
group.nodes.push(node); group.nodes.push(node);
} }
group.childs = [];
for (var i = group.id + 1; i < groups.length; ++i) {
group.childs.push(groups[i].id);
}
} }
} }
...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -148,6 +152,12 @@ function forceGraph(dotGraph, prevGraph) {
graph.nodesd[node.id] = node; graph.nodesd[node.id] = node;
} }
graph.groupsd = {};
for (var i in graph.groups) {
var group = graph.groups[i];
graph.groupsd[group.id] = group;
}
graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;}); graph.nodesp = graph.nodes.filter(function(d) {return d.isParent;});
graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;}); graph.nodesn = graph.nodes.filter(function(d) {return !d.isParent;});
...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -160,7 +170,7 @@ function forceGraph(dotGraph, prevGraph) {
if (exists(prevParent)) { if (exists(prevParent)) {
group.pos = [prevParent.x, prevParent.y]; group.pos = [prevParent.x, prevParent.y];
} else { } else {
group.pos = parent.pos.slice(0); group.pos = parent.value.pos.slice(0);
} }
group.pos[0] += parent.value.cx; group.pos[0] += parent.value.cx;
group.pos[1] += parent.value.cy; group.pos[1] += parent.value.cy;
...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) { ...@@ -177,10 +187,7 @@ function forceGraph(dotGraph, prevGraph) {
} }
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
node.x = group.pos[0];
node.y = group.pos[1];
} else {
node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0]; node.x = group.pos[0] - group.size[0] / 2 + node.value.pos[0] - min[0];
node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1]; node.y = group.pos[1] - group.size[1] / 2 + node.value.pos[1] - min[1];
} }
...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) { ...@@ -276,15 +283,25 @@ function convexHulls(graph, offset) {
var points = []; var points = [];
for (var j in group.nodes) { for (var j in group.nodes) {
var node = group.nodes[j]; var node = group.nodes[j];
if (node.isParent) { if (!node.isParent) {
points.push([node.x, node.y]);
} else {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]); points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]); points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]); points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]); points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
} }
} }
for (var k in group.childs) {
var nodes = graph.groupsd[group.childs[k]].nodes;
for (var j in nodes) {
var node = nodes[j];
if (!node.isParent) {
points.push([node.x - node.value.cx - offset, node.y - node.value.cy - offset]);
points.push([node.x - node.value.cx - offset, node.y + node.value.cy + offset]);
points.push([node.x + node.value.cx + offset, node.y - node.value.cy - offset]);
points.push([node.x + node.value.cx + offset, node.y + node.value.cy + offset]);
}
}
}
hulls.push({group: i, path: d3.geom.hull(points)}); hulls.push({group: i, path: d3.geom.hull(points)});
} }
return hulls; return hulls;
...@@ -314,6 +331,42 @@ function setupGraph() { ...@@ -314,6 +331,42 @@ function setupGraph() {
var isEdgeOver = false; var isEdgeOver = false;
var isEdgeLabelOver = false; var isEdgeLabelOver = false;
var dragHulls = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault();
layout.stop();
})
.on("drag", function dragged(d) {
var group = graph.groups[d.group];
for (var i in group.nodes) {
var node = group.nodes[i];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
}
group.pos[0] += d3.event.dx;
group.pos[1] += d3.event.dy;
for (var k in group.childs) {
var cgroup = graph.groupsd[group.childs[k]];
var nodes = cgroup.nodes;
for (var j in nodes) {
var node = nodes[j];
node.x += d3.event.dx;
node.y += d3.event.dy;
node.px += d3.event.dx;
node.py += d3.event.dy;
cgroup.pos[0] += d3.event.dx;
cgroup.pos[1] += d3.event.dy;
}
}
updateGraph();
})
.on('dragend', function(d) {layout.resume();});
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls = pane.selectAll('#hulls').remove(); hulls = pane.selectAll('#hulls').remove();
hulls = pane.append('g').attr('id', 'hulls') hulls = pane.append('g').attr('id', 'hulls')
...@@ -321,12 +374,18 @@ function setupGraph() { ...@@ -321,12 +374,18 @@ function setupGraph() {
.data(graph.hulls).enter() .data(graph.hulls).enter()
.append('path') .append('path')
.attr('class', 'hull') .attr('class', 'hull')
.attr('d', drawCluster); .attr('d', drawCluster)
.call(dragHulls);
hulls.on('dblclick', function(d) { hulls.on('dblclick', function(d) {
var parent = graph.groups[d.group].parent; var group = graph.groups[d.group];
parent.value.showChilds = !parent.value.showChilds; group.parent.value.showChilds = !group.parent.value.showChilds;
if (!group.parent.value.showChilds) {
for (i in group.childs) {
var child = graph.groupsd[group.childs[i]];
child.parent.value.showChilds = false;
}
}
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
setupGraph(); setupGraph();
}); });
...@@ -376,6 +435,12 @@ function setupGraph() { ...@@ -376,6 +435,12 @@ function setupGraph() {
if (d.value.hasChilds) { if (d.value.hasChilds) {
d.value.showChilds = !d.value.showChilds; d.value.showChilds = !d.value.showChilds;
graph = forceGraph(dotGraph, graph); graph = forceGraph(dotGraph, graph);
if (!fixedDefault && d.value.showChilds) {
var n = dotGraph.neighbors(d.id);
for (i in n) {
graph.nodesd[n[i]].fixed = false;
}
}
setupGraph(); setupGraph();
} }
}); });
...@@ -422,11 +487,15 @@ function setupGraph() { ...@@ -422,11 +487,15 @@ function setupGraph() {
.nodes(graph.nodes) .nodes(graph.nodes)
.links(graph.edges) .links(graph.edges)
.size(graph.size) .size(graph.size)
.charge(-300) .linkDistance(function(d) {
.linkDistance(400) return 300;
.linkStrength(0.4) })
.gravity(0) .charge(-600)
.on('tick', updateGraph); .linkStrength(1)
.gravity(0.05)
.friction(0.5)
.on('tick', updateGraph)
.start();
// Drag behavour // Drag behavour
var drag = layout.drag() var drag = layout.drag()
...@@ -436,9 +505,6 @@ function setupGraph() { ...@@ -436,9 +505,6 @@ function setupGraph() {
d.fixed = true; d.fixed = true;
}); });
nodes.call(drag); nodes.call(drag);
// Start force layout
layout.start();
} }
function length(x1, y1, x2, y2) { function length(x1, y1, x2, y2) {
...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) { ...@@ -452,7 +518,53 @@ function pathPos(x1, y1, x2, y2, c) {
return p; return p;
} }
function collide(node) {
var eps = 10;
var nx1 = node.x - node.value.cx - eps;
var nx2 = node.x + node.value.cx + eps;
var ny1 = node.y - node.value.cy - eps;
var ny2 = node.y + node.value.cy + eps;
return function(quad, x1, y1, x2, y2) {
var point = quad.point;
if (point && (point != node) && !point.fixed && ! node.fixed) {
var px1 = point.x - point.value.cx;
var px2 = point.x + point.value.cx;
var py1 = point.y - point.value.cy;
var py2 = point.y + point.value.cy;
if (!(px1 > nx2 || px2 < nx1 || py1 >= ny2 || py2 <= ny1)) {
var eta = 0.1;
if (px1 < nx1) {
// move quad to left
var d = eta * (px2 - nx1);
point.x -= d;
node.x += d;
} else {
var d = eta * (nx2 - px1);
point.x += d;
node.x -= d;
}
if (py1 < ny1) {
// move quad to top
var d = eta * (py2 - ny1);
point.y -= d;
node.y += d;
} else {
var d = eta * (ny2 - py1);
point.y += d;
node.y -= d;
}
}
}
return x1 > nx2 || x2 < nx1 || y1 >= ny2 || y2 <= ny1;
};
}
function updateGraph() { function updateGraph() {
var q = d3.geom.quadtree(graph.nodes);
for (var i in graph.nodes) {
q.visit(collide(graph.nodes[i]));
}
graph.hulls = convexHulls(graph); graph.hulls = convexHulls(graph);
hulls.data(graph.hulls) hulls.data(graph.hulls)
.attr('d', drawCluster); .attr('d', drawCluster);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
var isProfiled = false; var isProfiled = false;
var colorProfile = false; var colorProfile = false;
var fixedDefault = true;
var maxProfilePer = 0; var maxProfilePer = 0;
var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"]; var profileColors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15"];
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论