summaryrefslogblamecommitdiffstats
path: root/static/status-dnbd3.html
blob: 5e81657e9e80ec41048885710cc52e1b5a85a259 (plain) (tree)










































































































































































































































































































                                                                                                                                                           
<!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">
        .circle, .link { stroke: #56f; stroke-width: 3px; stroke-opacity: 0.75; }
        .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> <canvas id="traffic" width="100%" height="150"></canvas></div>
</body>
<script type="text/javascript">

var smoothie = new SmoothieChart({'millisPerPixel': 300, 'grid': {'millisPerLine': 30000}, timestampFormatter:SmoothieChart.timeFormatter});
smoothie.streamTo(document.getElementById("traffic"), 2000);

//var line1 = new TimeSeries();
//smoothie.addTimeSeries(line1);
var colorList = d3.scale.category20();

function myGraph(el) {

        var changed = false;

    // Add and remove elements on the graph object
    this.addNode = function (id, radius, color, distance, x, y) {
        title = id;
        id = 'a' + id.replace(/\./g, "-");
        if (!distance) distance = 5;
        distance *= w / 2000;
        if (!radius) radius = 5;
        var node = findNode(id);
        if (!node) {
            nodes.push({"id":id, "title": title, "distance":distance, "radius":radius, "active":2, "x":x, "y":y, "color":color});
            changed = true;
        } else {
            var visNode = vis.select("#" + id);
            if (visNode) {
                visNode.select("title").text(id);
                visNode.select("circle").attr("r", radius);
            }
            node.distance = distance;
            node.radius = radius;
            node.active = 2;
            node.color = color;
            var s = servers[title];
            if (s && visNode) {
                visNode.select("circle").style("fill", s.color);
                //visNode.select("#" + id).select("circle").style("stroke", color);
            }
        }
    }

    this.decay = function () {
        for (var i = nodes.length - 1; i >= 0; --i) {
            if ( nodes[i].active <= 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].active--;
        }
        for (var i = links.length - 1; i >= 0; --i) {
            if (links[i].active <= 0) {
                links.splice(i, 1);
                changed = true;
                continue;
            }
            links[i].active--;
        }
    }

    this.removeNode = function (id) {
        var i = 0;
        var n = findNode(id);
        while (i < links.length) {
            if ((links[i]['source'] === n)||(links[i]['target'] == n)) links.splice(i,1);
            else i++;
        }
        var index = findNodeIndex(id);
        if(index !== undefined) {
            nodes.splice(index, 1);
            changed = true;
            //update();
        }
    }

    this.addLink = function (sourceId, targetId) {
        sourceId = 'a' + sourceId.replace(/\./g, "-");
        targetId = 'a' + targetId.replace(/\./g, "-");
        var sourceNode = findNode(sourceId);
        var targetNode = findNode(targetId);

        if ((sourceNode !== undefined) && (targetNode !== undefined)) {
                var link = findLink(sourceNode, targetNode);
                if (!link) {
                    links.push({"source": sourceNode, "target": targetNode, "active":5});
                    //update();
                    changed = true;
                } else {
                        link.active = 5;
                }
        }
    }

    var findNode = function (id) {
        for (var i=0; i < nodes.length; i++) {
            if (nodes[i].id === id)
                return nodes[i]
        }
    }

    var findLink = function (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 findNodeIndex = function (id) {
        for (var i=0; i < nodes.length; i++) {
            if (nodes[i].id === id)
                return i
        };
    }

    var w = 100, h = 100;

    var updateBounds = function() {
        w = window.innerWidth;
        h = window.innerHeight - 150 - 10;
        vis.attr("width", w);
        vis.attr("height", h);
        force.size([w, h]);
        $(el).attr("width", w);
        $(el).attr("height", h);
        $("#traffic").attr("width", w);
    }

    var vis = this.vis = d3.select(el).append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    var force = d3.layout.force()
        .gravity(.02)
        .distance(function(bla) { return bla.source.distance * bla.target.distance; })
        .linkStrength(0.5)
        .charge(function(bla) { return -bla.distance * 10 * bla.distance; })
        .friction(0.6)
        .size([w, h]);

    var nodes = force.nodes(),
        links = force.links();

    this.update = function () {
            if (!changed)
                    return;
            update();
    }

    var update = function () {
        changed = false;

        var node = vis.selectAll("g.node")
            .data(nodes, function(d) { return d.id;});

        var nodeEnter = node.enter().append("g")
            .attr("class", "node")
            .attr("id", function(d) { return d.id;})
            .on("mouseover", function(d) {
                var s = servers[d.title];
                if (!s) return;
                smoothie.seriesSet[s.index].options.lineWidth = 4;
            })
            .on("mouseout", function(d) {
                var s = servers[d.title];
                if (!s) return;
                smoothie.seriesSet[s.index].options.lineWidth = 2;
            });

        nodeEnter.append("circle")
            .attr("class", "circle")
            .attr("r", function(d) { return d.radius; })
            .style("fill", function(d) { return d.color; });

        nodeEnter.append("title");

        nodeEnter.append("text")
            .attr("class", "nodetext")
            .attr("dx", -32)
            .attr("dy", "-1em")
            .text(function(d) {return d.title});

        node.exit().remove();

        var link = vis.selectAll("line.link")
            .data(links, function(d) { return d.source.id + "-" + d.target.id; });

        link.enter().insert("line")
            .attr("class", "link");

        link.exit().remove();

        vis.selectAll('g.node').forEach(function(e){$('#graph').find('svg').append(e)});

        var render = function() {
            var fixX = function(x) {
                return (x - lx) * scale + 20 + offX;
            }
            var fixY = function(y) {
                return (y - ly) * scale + 20 + offY;
            }
            var lx = 1000, ly = 1000, ux = -1000, uy = -1000;
            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;
            }
            var width = (ux - lx), height = (uy - ly);
            var scale;
            var offX = 0, offY = 0;
            if ( (width / w) > (height / h) ) {
                    scale = (w - 40) / width;
                    offY = (h - (height * scale + 20)) / 2;
            } else {
                    scale = (h - 40) / height;
                    offX = (w - (width * scale + 20)) / 2;
            }
          link.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); });

          node.attr("transform", function(d) { return "translate(" + fixX(d.x) + "," + fixY(d.y) + ")"; });
        };

        force.on("tick", render);

        updateBounds();
        force.start();
    }

    update();
    $( window ).resize( update );
}

graph = new myGraph("#graph");

var servers = {};
var serverCount = 0;

setInterval( function() {
        $.get('/data.json', function(data) {
                var g = data.graph;
                var stats = data.servers;
                if (g) {
                    for (var i = 0; i < g.nodes.length; ++i) {
                        graph.addNode(g.nodes[i].name, g.nodes[i].radius, g.nodes[i].color, g.nodes[i].distance, g.nodes[i].x, g.nodes[i].y);
                    }
                    for (var i = 0; i < g.edges.length; ++i) {
                            graph.addLink(g.edges[i].source, g.edges[i].target);
                    }
                }
                if (stats) {
                    for (var i = 0; i < stats.length; ++i) {
                        var server = servers[stats[i].address];
                        if (!server) {
                            servers[stats[i].address] = server = { 'lastTime': 0, 'lastSent': 0, 'line': new TimeSeries(), 'index': serverCount++ };
                            server.color = colorList(server.index);
                            smoothie.addTimeSeries(server['line'], {lineWidth:2, strokeStyle: server.color});
                        }
                        if (server['lastTime'] != 0) {
                            server['line'].append(new Date().getTime(), (stats[i].bytesSent - server['lastSent'])/1000/(data.timestamp - server.lastTime));
                            //smoothie.seriesSet[server.index].options.strokeStyle = 'rgba(0,255,0,0.93)';
                        }
                        server['lastTime'] = data.timestamp;
                        server['lastSent'] = stats[i].bytesSent;
                    }
                }

                }, 'json').always(function() {
                        graph.decay();
                        graph.update();
                });
        }, 2000);

</script>