diff options
author | Simon Rettberg | 2019-01-29 16:06:26 +0100 |
---|---|---|
committer | Simon Rettberg | 2019-01-29 16:06:26 +0100 |
commit | 1e8ef96e022883f056610d55055622fb22016c0c (patch) | |
tree | e932d9a1320181e11c264905eaf91babb9dba115 /static/status-dnbd3.html | |
parent | Small labeling change (diff) | |
download | dnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.tar.gz dnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.tar.xz dnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.zip |
Make colors more good and less bad
Diffstat (limited to 'static/status-dnbd3.html')
-rw-r--r-- | static/status-dnbd3.html | 624 |
1 files changed, 0 insertions, 624 deletions
diff --git a/static/status-dnbd3.html b/static/status-dnbd3.html deleted file mode 100644 index 0fe1a09..0000000 --- a/static/status-dnbd3.html +++ /dev/null @@ -1,624 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<html> -<head> - <script src="d3.v3.min.js"></script> - <script type="text/javascript" src="jquery-1.7.1.min.js"></script> - <script src="smoothie.js"></script> - <style type="text/css"> - #graph, #statistics, #traffic {position: absolute } - .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; } - </style> -</head> -<body> -<div id="graph"></div> -<div id="statistics"><div id="debug"></div></div> -<div> <canvas id="traffic" width="100%" height="150"></canvas></div> -</body> -<script type="text/javascript"> - -// Initialize the statistics chart at the bottom. -var smoothie = new SmoothieChart({'millisPerPixel': 300, 'grid': {'millisPerLine': 30000}, timestampFormatter:SmoothieChart.timeFormatter, yMaxFormatter: bytesToString, yMinFormatter: bytesToString, valueTransformFunction: logarithmicScaling, minValue: 0, maxValue: 262144000, labels: {fontSize: 13}}); -smoothie.streamTo(document.getElementById("traffic"), 2000); - -// For coloring the servers and the chart-lines. -var colorList = d3.scale.category10(); - -// Max intensity ~ 50MB/s -var maxIntensity = 50000; - -var pendingLinks = []; -var intLinks = []; -var newLinks = []; -var links = {}; -var nodes = {}; - -// color for links -// idle links (blue) -var idleColor = { "r": 85, "g": 102, "b": 255}; -// active links (green) -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, "-"); -} - -// Log scaling for the traffic graph -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; - - // Add/update and remove elements on the graph object - this.updateNode = function (id) { - var title = id; - var id = makeId("a", id); - - var node = findNode(id); - - // Add node, if it doesn't exist - if (!node) { - var len = Math.min(5, nodes.length); - var nx = 0, ny = 0, i; - if (len > 0) { - for (i = 0; i < len; ++i) { - nx += nodes[i].x; - ny += nodes[i].y; - } - nx /= len; - ny /= len; - } - nodes.push(node = {"id": id, "title": title, "x": nx, "y":ny, "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("stroke-width", "3px"); - } - } - node.lifetime = 2; - } - - // Remove nodes/edges that haven't reported for a while. - this.decay = function () { - for (var i = nodes.length - 1; i >= 0; --i) { - if ( nodes[i].lifetime <= 0 ) { - for (var j = links.length - 1; j >= 0; --j) { - if ((links[j].source === nodes[i]) || (links[j].target === nodes[i])) links.splice(j,1); - } - nodes.splice(i, 1); - changed = true; - continue; - } - nodes[i].lifetime--; - } - for (var i = links.length - 1; i >= 0; --i) { - if (links[i].lifetime <= 0) { - links.splice(i, 1); - changed = true; - continue; - } - links[i].lifetime--; - } - } - - // Add/update links in the graph - this.updateLink = function (edge, timestamp) { - var sourceId = edge.source; - var targetId = edge.target; - var width = '2.5px'; - - // Change color to red for links between servers - if (servers[sourceId] && servers[targetId]) width = '3.5px'; - - sourceId = makeId("a", sourceId); - targetId = makeId("a", targetId); - var sourceNode = findNode(sourceId); - var targetNode = findNode(targetId); - - if ((typeof(sourceNode) !== 'undefined') && (typeof(targetNode) !== 'undefined')) { - var link = findLink(sourceNode, targetNode); - // Add non existing links - if (!link) { - var index = $.inArray(sourceId + targetId, pendingLinks); - if (index !== -1) { - links.push({"id": sourceId + "-" + targetId ,"source": sourceNode, "target": targetNode, "lifetime":2, "color": idleColor, "downloadRate" : 0, "lastReceived": 0, "lastTimestamp": 0, "lastUptime": 0, "colorIntensity": 0, "width": width }); - changed = true; - } else { - newLinks.push(sourceId + targetId); - } - } else { - link.lifetime = 2; - - // Calculate download rate for clients and color links. - if (link.lastTimestamp != 0) { - if(timestamp - lastTime > 0) { - // Download rate in KB/s - link.downloadRate = ((edge.received - link.lastReceived) / (timestamp - lastTime)) * 4 * 1000; - // Clients may have multiple connections with different received data -> prevent negative download rate... - if(link.downloadRate < 0) link.downloadRate = 0; - - // only need fiddle with colors if needed. - if (link.downloadRate > 0) { - increasColorIntensity(link); - colorLink(link); - updateLinkColor(link); - } - } - } else { - link['downloadRate'] = 0; - } - link['lastReceived'] = edge.received; - link['lastTimestamp'] = timestamp; - } - } - } - - // Color a link according to its intensity, does not apply the color in the svg! Use updateLinkColor function for that. - function colorLink(link) { - var red, green, blue; - // Green colors between 0 - 1 MB/s - if( link.colorIntensity <= 1000 ) { - // Blending idle (blue) and active (green) color - var factor = link.colorIntensity / 1000; - var cFactor = 1 - factor; - - red = Math.sqrt(cFactor * Math.pow(idleColor.r, 2) + factor * Math.pow(activeColor.r, 2)); - green = Math.sqrt(cFactor * Math.pow(idleColor.g, 2) + factor * Math.pow(activeColor.g, 2)); - blue = Math.sqrt(cFactor * Math.pow(idleColor.b, 2) + factor * Math.pow(activeColor.b, 2)); - - } else { // Red over 1MB/s - // Blending active (green) and peak (red) color - var factor = (link.colorIntensity - 1000)/ (maxIntensity - 1000); - var cFactor = 1 - factor; - - red = Math.sqrt(cFactor * Math.pow(activeColor.r, 2) + factor * Math.pow(peakColor.r, 2)); - green = Math.sqrt(cFactor * Math.pow(activeColor.g, 2) + factor * Math.pow(peakColor.g, 2)); - blue = Math.sqrt(cFactor * Math.pow(activeColor.b, 2) + factor * Math.pow(peakColor.b, 2)); - } - link.color = "rgb("+ Math.floor(red) + ", " + Math.floor(green) + ", " + Math.floor(blue) + ")"; - } - - // Update the color of a link in the svg. - function updateLinkColor(link) { - // Prevent future searches for links to improve performance. - if(!link.visObject) { - link.visObject = vis.select("#" + link.source.id + "-" + link.target.id); - } - var visLink = link.visObject; - visLink.style({stroke: function(d) { return d.color; }}); - } - - // Interval for fading out the color of active links - function decayLinkColor() { - for (var i = 0; i < links.length ; i++) { - var link = links[i]; - // Do nothing if there is no intensity to decay. - if(link.colorIntensity > 0) { - // Fading rate of colored links - var fadingValue = (link.colorIntensity * 0.15) + 10; - link.colorIntensity -= fadingValue; - if (link.colorIntensity < 0) { - link.colorIntensity = 0; - } else if (link.colorIntensity < link.downloadRate) { - link.colorIntensity = link.downloadRate; - } - colorLink(link); - updateLinkColor(link); - } - } - } - window.setInterval(decayLinkColor, 500); - window.setInterval(function() { - if (force.alpha() == 0) { - force.alpha(0.015); - force.tick(); - force.stop(); - } - }, 125); - - - // Set the color intensity of link according to its download rate. - function increasColorIntensity(link) { - if (link.colorIntensity < link.downloadRate) { - link.colorIntensity = link.downloadRate; - } - if (link.colorIntensity >= maxIntensity) { - link.colorIntensity = maxIntensity; - } - } - - function findLink(sourceId, targetId) { - for (var i = 0; i < links.length; ++i) { - if ( (links[i].source === sourceId && links[i].target === targetId) - || (links[i].source === targetId && links[i].target === sourceId) ) - return links[i]; - } - } - - var findNode = function (id) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].id === id) - return nodes[i]; - } - } - - - var findNodeIndex = function (id) { - for (var i=0; i < nodes.length; i++) { - if (nodes[i].id === id) - return i; - }; - } - - var w = 100, h = 100; - var lastW = -1, lastH = -1; - - var updateBounds = function() { - var width = window.innerWidth; - // Chart needs to fit under the graph and the statistics - h = window.innerHeight - 150; - // Width for the graph and the statistics div - w = width/3*2; - if (lastW === w && lastH === h) return; - lastW = w; - lastH = h; - vis.attr("width", w); - vis.attr("height", h); - force.size([w, h]); - $(el).attr("width", w); - $(el).attr("height", h); - // Positions for statistics and the traffic graph - $("#statistics").attr("width", w/2).css("width", w/2 + "px").css("left", w + "px"); - $("#statistics").attr("height", h).css("height", h + "px"); - $("#traffic").attr("width", width).css("top", h + "px"); - } - - var vis = this.vis = d3.select(el).append("svg:svg") - .attr("width", w) - .attr("height", h); - - // Settings for movement of the graph - var force = d3.layout.force() - // Force of center gravitation - .gravity(.12) - // 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.5) - // Force with which all nodes attract each other - .charge(function(bla) { return bla.isServer ? -3.5 : -0.9; }) - // Friction for the graph nodes - .friction(0.4) - .theta(0.75) - .size([w, h]); - - nodes = force.nodes(); - links = force.links(); - - - var updateCounter = 0; - this.update = function () { - if(changed) { - update(); - } - if (++updateCounter < 10) force.alpha(force.alpha() + 0.05); - } - - // Update the complete svg. - var svgNodes = []; - var svgLinks = []; - function update() { - changed = false; - - svgNodes = vis.selectAll("g.node") - .data(nodes, function(d) { return d.id; }); - - var nodeEnter = svgNodes.enter().append("g") - .attr("class", "node") - .attr("id", function(d) { return d.id; }) - .on("mouseover", function(d) { - // Highlight statistics div - var statDiv = document.getElementById(makeId("b", d.title)); - if (statDiv){ - statDiv.setAttribute("style", "background-color:blue; color:white;"); - } - - // Increase line width of server in traffic chart - var s = servers[d.title]; - if (!s) return; - smoothie.seriesSet[s.index].options.lineWidth = 4; - }) - .on("mouseout", function(d) { - // Make statistics div normal again - var statDiv = document.getElementById(makeId("b", d.title)); - if (statDiv){ - statDiv.setAttribute("style", "background-color:white; color:black;"); - } - - // Reset line width - var s = servers[d.title]; - if (!s) return; - smoothie.seriesSet[s.index].options.lineWidth = 2; - }); - - nodeEnter.append("circle") - .attr("class", "circle") - .attr("r", 4); - - nodeEnter.append("text") - .attr("class", "nodetext") - .attr("dx", -32) - .attr("dy", "-1em") - .text(function(d) {return d.title}); - - svgNodes.exit().remove(); - - svgLinks = vis.selectAll("line.link") - .data(links, function(d) { return d.source.id + "-" + d.target.id; }); - - svgLinks.enter().insert("line") - .attr("class", "link") - .attr("id", function(d) {return d.id; }) - .style({stroke: function(d) { return d.color }, "stroke-width": function(d) { return d.width } }); - - svgLinks.exit().remove(); - - // 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); - - updateBounds(); - force.start(); - } - - var lastScale = false; - // Render function - 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 < 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 desiredScale; - var offX = 0, offY = 0; - if ( (width / w) > (height / h) ) { - desiredScale = (w - 40) / width; - } else { - desiredScale = (h - 40) / height; - } - if (lastScale === false) lastScale = desiredScale; - var absDiff = Math.abs(desiredScale - lastScale); - - var newScale = desiredScale; - if (false) { - newScale = desiredScale; - } else if (desiredScale < lastScale) { - newScale = Math.min(lastScale * 0.99, lastScale - absDiff * 0.001); - if (newScale < desiredScale) newScale = desiredScale; - } else if (desiredScale > lastScale) { - newScale = Math.max(lastScale * 1.01, lastScale + absDiff * 0.001); - if (newScale > desiredScale) newScale = desiredScale; - } - lastScale = newScale; - if ( (width / w) > (height / h) ) { - offY = (h - (height * newScale + 20)) / 2; - } else { - offX = (w - (width * newScale + 20)) / 2; - } - - var fixX = function(x) { - return (x - lx) * newScale + 20 + offX; - } - var fixY = function(y) { - return (y - ly) * newScale + 20 + offY; - } - svgLinks.attr("x1", function(d) { return fixX(d.source.x); }) - .attr("y1", function(d) { return fixY(d.source.y); }) - .attr("x2", function(d) { return fixX(d.target.x); }) - .attr("y2", function(d) { return fixY(d.target.y); }); - - svgNodes.attr("transform", function(d) { - return "translate(" + fixX(d.x) + "," + fixY(d.y) + ")"; - }); - }; - - window.onresize = update; - update(); -} - -graph = new myGraph("#graph"); - -var servers = {}; -var serverCount = 0; -var lastTime = 0; - -// Get new data -setInterval( function() { - $.get('/data.json', function(data) { - if (data.timestamp < lastTime) lastTime = data.timestamp; - if(data.timestamp === lastTime) return; - var g = data.graph; - var stats = data.servers; - updateGraph(g, data); - // updateTrafficGraph has to be called before updateTextStatistics to populate servers - updateTrafficGraph(stats, data); - updateTextStatistics(stats); - lastTime = data.timestamp; -}, 'json').always(function() { - graph.decay(); - graph.update(); - }); -}, 2000); - - -// Update data of the graph -function updateGraph(g, data) { - if (g) { - for (var i = 0; i < g.nodes.length; ++i) { - graph.updateNode(g.nodes[i].name); - } - for (var i = 0; i < g.edges.length; ++i) { - graph.updateLink(g.edges[i], data.timestamp); - } - pendingLinks = intLinks; - intLinks = newLinks; - newLinks = []; - } -} - - -// Convert bytes to GiB or TiB and return a string in form "10,23 GiB" -function bytesToString( bytes ) { - var convertedValue; - var unit; - if (bytes >= 1099511627776 ) { - convertedValue = Math.round( (bytes / 1099511627776) * 100 ) / 100 ; - unit = " TiB"; - } else if (bytes >= 1073741824 ) { - convertedValue = Math.round( (bytes / 1073741824) * 100 ) / 100 ; - unit = " GiB"; - } else if (bytes >= 1048576 ) { - convertedValue = Math.round( (bytes / 1048576) * 100 ) / 100 ; - unit = " MiB"; - } else if ( bytes >= 1024 ) { - convertedValue = Math.round( (bytes / 1024) * 100 ) / 100 ; - unit = " KiB"; - } else { - convertedValue = Math.round(bytes); - unit = " B"; - } - return convertedValue + unit; -} - -// Update data of the statistics divs -function updateTextStatistics(stats) { - var glob = $('#gstats'); - if (glob.length === 0) { - $('#statistics').append('<div id="gstats"></div>'); - glob = $('#gstats'); - } - glob.html('<p><b>Global</b><br>' - + 'Upload: ' + bytesToString(globalUploadRate) + '/s<br>' - + 'Upload Peak: ' + bytesToString(globalUploadMax) + '/s<p>'); - if (stats) { - for (var i = 0; i < stats.length; ++i) { - var divId = makeId("b", stats[i].address); - var server = $('#' + divId); - if (server.length === 0) { - $("#statistics").append('<div id="' + makeId ("b", stats[i].address) + '"></div>'); - server = $("#" + divId); - } - - var upload = servers[stats[i].address].uploadRate; - upload = upload ? upload : 0; - // Generate the HTML string - server.html( "<p><b> Server: " + stats[i].address + "</b><br>" - + "Number of clients: " - + stats[i].clientCount + "<br>" - + "uptime: " + Math.floor(stats[i].uptime / (3600 * 24)) + "d " - + Math.floor(stats[i].uptime / 3600) % 24 + "h " + Math.floor((stats[i].uptime) / 60) % 60 + "min" + "<br>" - + "Sent: " + bytesToString(stats[i].bytesSent) + "<br>" - + "Received: " + bytesToString(stats[i].bytesReceived) + "<br>" - + "Upload: " + bytesToString(servers[stats[i].address].uploadRate) + "/s<br>" - + "Upload Peak: " + bytesToString(servers[stats[i].address].uploadPeak) + "/s" + "</p>" - ); - } - } -} - -var globalUploadRate = 0, globalUploadMax = 0; - -// Update the traffic graph -function updateTrafficGraph(stats, data) { - if (stats) { - globalUploadRate = 0; - for (var i = 0; i < stats.length; ++i) { - var server = servers[stats[i].address]; - if (!server) { - servers[stats[i].address] = server = { 'lastUptime': 0, 'lastTimestamp': 0, 'lastSent': 0, 'line': new TimeSeries({logarithmicScale: true}), 'index': serverCount++ , 'uploadRate': 0, 'downloadRate': 0, 'uploadPeak': 0 } - server.color = colorList(stats[i].address); - smoothie.addTimeSeries(server['line'], {lineWidth:2, strokeStyle: server.color}); - } - // Server seems to have rebootet, redo values but add no point to chart. - if (server['lastUptime'] > stats[i].uptime) { - server['lastUptime'] = 0; - } - - // Add points to graph and set the upload rate for the statistics - if (server['lastUptime'] != 0) { - // Upload rate in bytes/s - server['uploadRate'] = (stats[i].bytesSent - server['lastSent'])/(stats[i].timestamp - server.lastTimestamp) * 1000; - if (server['uploadRate'] > server['uploadPeak']) server['uploadPeak'] = server['uploadRate']; - // Rate in MiB/s - server['line'].append(new Date().getTime(), server['uploadRate']); - } else { - server['uploadRate'] = 0; - } - - server['lastUptime'] = stats[i].uptime; - server['lastSent'] = stats[i].bytesSent; - server['lastTimestamp'] = stats[i].timestamp; - globalUploadRate += server['uploadRate']; - } - if (globalUploadRate > globalUploadMax) globalUploadMax = globalUploadRate; - } -} - -</script> |