dagre-d3 & HTML label

by lborgman

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div class="live map">
        <svg><g/></svg>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.3/jquery.tipsy.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dagre-d3/0.6.1/dagre-d3.min.js"></script>
</body>
</html>

CSS

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 div.node {
    width: 2.062726176115803rem;
    height: 3.618817852834741rem;
    display: grid;
    grid-auto-columns: 8% 42% 42% 8%;
    grid-auto-rows: 70% 30%;
    font: 0.05em 'Courier New', Courier, monospace;
    color: white;
}

.live.map .node rect {
    stroke-width: 1.5px;
    stroke: #bbb;
    fill: #666;
}

.live.map .node>.run-status {
    grid-column: 1;
    grid-row: 1 / 3;
    border-top-left-radius: 5px;
    border-bottom-left-radius: 5px;
}

.live.map .node>.name {
    grid-column: 2 / 4;
    grid-row: 1;
    font-size: 16px;
}

.live.map .node>.start {
    grid-column: 2;
    grid-row: 2;
}

.live.map .node>.elapsed {
    grid-column: 3;
    grid-row: 2;
    text-align: end;
}

.live.map .node>.quality-status {
    grid-column: 4;
    grid-row: 1 / 3;
    border-top-right-radius: 5px;
    border-bottom-right-radius: 5px;
}

.live.map .node p {
    margin: 0;
    padding: 3px;
}

.live.map .r-completed .run-status,
.live.map .q-completed .quality-status {
    background-color: #7f7;
}


.live.map .r-running .run-status,
.live.map .q-running .quality-status {
    background-color: #ffed68;
}

.live.map .r-error .run-status,
.live.map .q-error .quality-status...

JavaScript

function FlowGenerator() {
    var self = this;

    var svg;
    var inner;
    var render;
    var zoom;
    var g;
    var gNodes;

    var transform = {
        translateX: 0,
        translateY: 0,
        scale: 1
    }

    let allNodes = [];
    let runningNodes = [];
    let idCount = 6;

    self.initChart = function () {
        svg = d3.select("svg");
        inner = svg.select("g");
        render = new dagreD3.render();
        g = new dagreD3.graphlib.Graph();
        g.setGraph({
            nodesep: 70,
            ranksep: 50,
            rankdir: "LR",
            marginx: 20,
            marginy: 20
        });
        g.setDefaultEdgeLabel(function () { return {}; });
        zoom = d3.zoom().on("zoom", function () {
            inner.attr("transform", d3.event.transform);
            if (d3.event.sourceEvent != undefined) {
                if (d3.event.sourceEvent instanceof WheelEvent) {
                    transform.translateX = d3.event.transform.x;
                    transform.translateY = d3.event.transform.y;
                    transform.scale = d3.event.transform.k;
                }
                if (d3.event.sourceEvent instanceof MouseEvent) {
                    transform.translateX = d3.event.transform.x;
                    transform.translateY = d3.event.transform.y;
                }
            }
        });

        svg.call(zoom);
    }

    self.updateChart = function (nodes) {
        let node;
        let html;
        let className;
        for (let i = 0, x = nodes.length; i < x; ++i) {
            node = nodes[i];
            g.setNode(node.id, createNodeObject(node));
            allNodes.push(node);
        }

        for (let i = 0, x = nodes.length; i < x; ++i) {
            node = nodes[i];
            if (node.hasOwnProperty('prev_id')) {
                g.setEdge(node.prev_id, node.id);
            }
        }

        renderGraph(true);
    }

    function createNodeObject(node) {
        let html;
       ...