summaryrefslogtreecommitdiffstats
path: root/static
diff options
context:
space:
mode:
authorSimon Rettberg2016-06-13 15:21:50 +0200
committerSimon Rettberg2016-06-13 15:21:50 +0200
commit047a7c2592b633bb2ee2014414cbd56e0e2f18d4 (patch)
tree66f5e7729b544eb3147dac70c7e136c53f504b24 /static
parentFix CPU spinning in NanoHTTPd (diff)
downloaddnbd3-status-047a7c2592b633bb2ee2014414cbd56e0e2f18d4.tar.gz
dnbd3-status-047a7c2592b633bb2ee2014414cbd56e0e2f18d4.tar.xz
dnbd3-status-047a7c2592b633bb2ee2014414cbd56e0e2f18d4.zip
Clustering in graph
Diffstat (limited to 'static')
-rw-r--r--static/status-dnbd3.html70
1 files changed, 54 insertions, 16 deletions
diff --git a/static/status-dnbd3.html b/static/status-dnbd3.html
index 184521d..6afbd80 100644
--- a/static/status-dnbd3.html
+++ b/static/status-dnbd3.html
@@ -7,7 +7,8 @@
<script src="smoothie.js"></script>
<style type="text/css">
#graph, #statistics, #traffic {position: absolute }
- .circle, .link { stroke: #56f; stroke-width: 3px; stroke-opacity: 0.75; }
+ .link { stroke-opacity: 0.75; stroke: #56f; }
+ .circle { stroke: #56f; stroke-width: 1px; }
.nodetext { pointer-events: none; font: 10px sans-serif; }
body { width:100%; height:100%; margin:0; padding:0; overflow: hidden; }
svg, div, canvas { margin:0; padding:0; }
@@ -44,6 +45,8 @@ var activeColor = { "r": 0, "g": 230, "b": 20};
// peaking links (red)
var peakColor = { "r": 255, "g": 40, "b": 30};
+var clusterDirections = [];
+
// IDs need to begin with a letter.
function makeId(prefix, text) {
return prefix + text.replace(/\./g, "-");
@@ -54,6 +57,27 @@ function logarithmicScaling(value) {
return Math.log(value/1000000+1);
}
+function getCluster(ip) {
+ var p = ip.split('.', 4);
+ var i;
+ if (p.length !== 4) return false;
+ p = p[0] + '-' + p[1] + '-' + p[2];
+ for (i = 0; i < clusterDirections.length; ++i) {
+ if (clusterDirections[i].id === p)
+ return function() { return clusterDirections[i] };
+ }
+ clusterDirections.push({'id':p});
+ var len = clusterDirections.length;
+ var col = len > 10 ? d3.scale.category20() : d3.scale.category10();
+ for (i = 0; i < len; ++i) {
+ clusterDirections[i].x = Math.sin(2*(i/clusterDirections.length)*3.14159);
+ clusterDirections[i].y = Math.cos(2*(i/clusterDirections.length)*3.14159);
+ clusterDirections[i].color = col(clusterDirections[i].id);
+ }
+ i = clusterDirections.length - 1;
+ return function() { return clusterDirections[i] };
+}
+
function myGraph(el) {
var changed = false;
@@ -66,16 +90,18 @@ function myGraph(el) {
// Add node, if it doesn't exist
if (!node) {
- nodes.push(node = {"id": id, "title": title, "x": w/2, "y":h/2});
+ nodes.push(node = {"id": id, "title": title, "x": w/2, "y":h/2, "cluster":getCluster(title)});
changed = true;
} else if (!node.isServer && servers[title]) {
node.isServer = true;
+ node.cluster = false;
+ node.color = servers[title].color;
// Change color and radius if server.
var visNode = vis.select("#" + id);
if (visNode) {
visNode.select("circle")
.attr("r", 15)
- .style("fill", servers[title].color);
+ .style("stroke-width", "3px");
}
}
node.lifetime = 2;
@@ -287,11 +313,11 @@ function myGraph(el) {
// Desired distance of the links
.distance(function(bla) { if (bla.source.isServer && bla.target.isServer) return 10; return 4; })
// Strength of the links (how strongly the distance is enforced) (0-1)
- .linkStrength(0.3)
+ .linkStrength(0.5)
// Force with which all nodes attract each other
- .charge(function(bla) { return -0.9; })
+ .charge(function(bla) { return bla.isServer ? -3.5 : -0.9; })
// Friction for the graph nodes
- .friction(0.5)
+ .friction(0.4)
.theta(0.75)
.size([w, h]);
@@ -299,12 +325,12 @@ function myGraph(el) {
links = force.links();
+ var updateCounter = 0;
this.update = function () {
if(changed) {
- var first = svgLinks.length === 0;
update();
- if (first) force.alpha(0.9);
}
+ if (++updateCounter < 10) force.alpha(force.alpha() + 0.05);
}
// Update the complete svg.
@@ -346,7 +372,7 @@ function myGraph(el) {
nodeEnter.append("circle")
.attr("class", "circle")
- .attr("r", 4).style("fill", "#00f");
+ .attr("r", 4);
nodeEnter.append("text")
.attr("class", "nodetext")
@@ -369,7 +395,7 @@ function myGraph(el) {
// Put all nodes on top again by adding them again
var jGraph = $('#graph').find('svg');
vis.selectAll('g.node').forEach(function(e){jGraph.append(e)});
-
+ svgNodes.selectAll('circle').style({ "fill": function(d) { return d.color ? d.color : d.cluster().color } });
force.on("tick", renderTick);
@@ -378,13 +404,25 @@ function myGraph(el) {
}
// Render function
- function renderTick() {
+ function renderTick(e) {
+ var k = 1 * e.alpha;
+ nodes.forEach(function(o, i) {
+ if (typeof(o.cluster) === 'function') {
+ var c = o.cluster();
+ o.x += k * c.x;
+ o.y += k * c.y;
+ }
+ });
var lx = 1000000, ly = 1000000, ux = -1000000, uy = -1000000;
- for (var i = 0; i < nodes.length; ++i) {
- if (nodes[i].x < lx) lx = nodes[i].x;
- if (nodes[i].x > ux) ux = nodes[i].x;
- if (nodes[i].y < ly) ly = nodes[i].y;
- if (nodes[i].y > uy) uy = nodes[i].y;
+ for (var i = 0; i < links.length; ++i) { // Use links not nodes so we ignore orphans
+ if (links[i].source.x < lx) lx = links[i].source.x;
+ if (links[i].source.x > ux) ux = links[i].source.x;
+ if (links[i].source.y < ly) ly = links[i].source.y;
+ if (links[i].source.y > uy) uy = links[i].source.y;
+ if (links[i].target.x < lx) lx = links[i].target.x;
+ if (links[i].target.x > ux) ux = links[i].target.x;
+ if (links[i].target.y < ly) ly = links[i].target.y;
+ if (links[i].target.y > uy) uy = links[i].target.y;
}
var width = (ux - lx), height = (uy - ly);
var scale;