| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- <!doctype html>
- <meta charset="utf-8">
- <title>Dagre D3 Renderer Demo</title>
- <script src="../../node_modules/graphlibrary/dist/graphlib.js"></script>
- <script src="../../node_modules/d3/build/d3.js"></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 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);
- document.addEventListener("DOMContentLoaded", draw);
- </script>
|