Skip to content

Instantly share code, notes, and snippets.

@belablotski
Last active August 20, 2016 00:24
Show Gist options
  • Save belablotski/190be806cb26316b3185a891075380e2 to your computer and use it in GitHub Desktop.
Save belablotski/190be806cb26316b3185a891075380e2 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="utf-8">
<!-- Based on https://github.com/cpettitt/dagre-d3/blob/master/demo/etl-status.html -->
<!-- Sample data are here: https://gist.github.com/beloblotskiy/06583a59c3005d6225835084be35641b -->
<title>Order-Customer-Inventory Jobs Graph</title>
<script src="./js/d3/d3.min.js" charset="utf-8"></script>
<script src="./js/dagre-d3/dagre-d3.min.js" charset="utf-8"></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: #FEE;/*#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: 14px; /* 12px */
margin-top: 2px;
}
.live.map .node g div {
width: 500px;
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 id="JobGraphVis"><g/></svg>
</div>
<script>
var JobGraph_workers = {};
function JobGraph_Visualize(tblsJsDataFile) {
// Set up zoom support
var svg = d3.select("svg"),
inner = svg.select("g"),
zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
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 JobGraph_workers) {
var worker = JobGraph_workers[id];
var className = worker.consumers ? "running" : "stopped";
if (worker.isWarn) {
className += " warn";
}
var html = "<div>";
html += "<span class='status'></span>";
//html += "<span class='consumers'>"+worker.consumers+"</span>";
html += "<span class='name'>"+id+"</span><br />";
html += "<span class='queue'><span class='job-desc'>Module:&nbsp;<b>" + (worker.execModule ? worker.execModule : "N/A") + "</b>&nbsp;-&nbsp;" + worker.jobDesc + "</span></span>";
html += "</div>";
g.setNode(id, {
labelType: "html",
label: html,
rx: 5,
ry: 5,
padding: 0,
class: className
});
if (worker.parentJobs) {
for (var k = 0; k < worker.parentJobs.length; k++) {
g.setEdge(worker.parentJobs[k], id, {
label: "", // worker.inputThroughput + "/s",
width: 50
});
}
}
}
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 translate = [(width/2) - ((graphWidth*zoomScale)/2), (height/2) - ((graphHeight*zoomScale)/2)];
zoom.translate(translate);
zoom.scale(zoomScale);
zoom.event(isUpdate ? svg.transition().duration(500) : d3.select("svg"));
}
// Load JS with data
function createScriptDomElem(jsFile) {
var elm = document.createElement("script");
elm.type = "application/javascript";
elm.src = jsFile;
document.body.appendChild(elm);
}
JobGraph_workers = {};
d3.select("body").insert("p", ":first-child").attr("style", "color:gray").text("Run-up for loading " + tblsJsDataFile + " --- " + new Date())
createScriptDomElem(tblsJsDataFile)
var checkJsLoad = setInterval(function() {
try {
if (JobGraph_workers) {
var c = 0
for (var prop in JobGraph_workers) c++
if (c > 0) {
clearInterval(checkJsLoad)
d3.select("body").selectAll("p").remove()
draw()
}
}
}
catch (err) {
d3.select("body").insert("p", ":first-child").attr("style", "color:gray").text("Loading " + tblsJsDataFile + " --- " + new Date())
}
}, 1000);
}
try {
function displayCtmTablesList() {
function databasesSelectOnChange() {
d3.select("#JobGraphVis").selectAll("*").remove()
d3.select("#JobGraphVis").append("g")
var selectValue = d3.select("#databasesSelect").property("value")
JobGraph_Visualize("./data/job_graph/" + selectValue + ".js")
}
var databasesSelect = d3.select("body").insert("select", ":first-child")
.attr("id", "databasesSelect")
.on("change", databasesSelectOnChange)
databasesSelect
.selectAll("option")
.data(["ORDER_CUSTOMER_INVENTORY", "ORDER_MANAGEMENT", "TRANSACTIONS_ONLINE"])
.enter()
.append("option")
.text(function(d) {return d})
.attr("value", function(d) {return d})
d3.select("body").append("p")
}
displayCtmTablesList()
JobGraph_Visualize("./data/job_graph/ORDER_CUSTOMER_INVENTORY.js")
}
catch(e) {
if (e instanceof Error) {
alert("ERROR: " + e.name + '\n' + e.message)
} else {
alert("ERROR:\n" + err)
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment