UNPKG

dagre-d3

Version:

A D3-based renderer for Dagre

287 lines (245 loc) 6.05 kB
<!doctype html> <meta charset="utf-8"> <title>Dagre D3 Renderer Demo</title> <script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script> <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.zoom().on("zoom", function() { inner.attr("transform", d3.event.transform); }); 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 translateX = (width / 2) - ((graphWidth * zoomScale) / 2) var translateY = (height / 2) - ((graphHeight * zoomScale) / 2); var svgZoom = isUpdate ? svg.transition().duration(500) : svg; svgZoom.call(zoom.transform, d3.zoomIdentity.translate(translateX, translateY).scale(zoomScale)); } // 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); // Initial draw, once the DOM is ready document.addEventListener("DOMContentLoaded", draw); </script> </body> </html>