Skip to content

Instantly share code, notes, and snippets.

@lptr
Created February 1, 2016 16:36
Show Gist options
  • Save lptr/94ce025a2a34cdec7e13 to your computer and use it in GitHub Desktop.
Save lptr/94ce025a2a34cdec7e13 to your computer and use it in GitHub Desktop.
Second try
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font-size: 8pt;
font-family: monospace;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<input id="time" type="range" width="100%"/>
<script src="d3.v3.js"></script>
<script src="underscore.js"></script>
<script>
var width = 600,
height = 400;
var color = d3.scale.category20();
var stateIndexByName = {
Registered: 1,
Discovered: 2,
Created: 3,
DefaultsApplied: 4,
Initialized: 5,
Mutated: 6,
Finalized: 7,
SelfClosed: 8,
GraphClosed: 9,
};
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force();
var nodes = force.nodes(),
links = force.links();
d3.json("sample.json", function(error, events) {
if (error) throw error;
var commands = processEvents(events);
var time = 0;
var timeInput = document.getElementById("time");
timeInput.min = 0;
timeInput.max = events.length;
timeInput.value = 0;
var redrawUntil = function (targetTime) {
if (time < targetTime) {
while (time < targetTime) {
commands[time].forward();
time++;
}
} else {
while (time > targetTime) {
time--;
commands[time + 1].backward();
}
}
repaint();
}
timeInput.addEventListener("input", function (element) {
var value = parseInt(element.target.value);
console.log("Redrawing", value);
redrawUntil(value);
});
// redrawUntil(events.length / 2);
});
function repaint() {
var link = svg.selectAll(".link")
.data(links);
link.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
link.exit().remove();
var node = svg.selectAll(".node")
.data(nodes);
var nodeGroup = node.enter()
.append("g")
.call(force.drag);
var nodeCircle = nodeGroup.append("circle")
.attr("class", "node")
.attr("r", 15)
.style("fill", function(d) { return color(d.state); })
var nodeText = nodeGroup.append("text")
.text(function(d) { return d.name; })
.style("fill", "#000000");
node.exit().remove();
force.on("tick", function () {
node
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
link
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
});
// Restart the force layout.
force
.charge(-120)
.linkDistance(80)
.size([width, height])
.start();
}
var findNodeIndex = function (path) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].name == path) {
return i;
}
};
};
// Add and remove elements on the graph object
var addNode = function (path) {
nodes.push({
"name": path,
"status": "Registered"
});
};
var removeNode = function (path) {
var i = 0;
var nodeIndex = findNodeIndex(path);
var node = nodes[nodeIndex];
while (i < links.length) {
if ((links[i]['source'] == node) || (links[i]['target'] == node)) {
links.splice(i, 1);
}
else i++;
}
nodes.splice(nodeIndex, 1);
};
var addLink = function (source, target, value) {
var sourceIdx = findNodeIndex(source);
var sourceNode = nodes[sourceIdx];
if (!sourceNode) {
throw "No source node for " + source;
}
var targetIdx = findNodeIndex(target);
var targetNode = nodes[targetIdx];
if (!targetNode) {
throw "No target node for " + target;
}
links.push({"source": sourceNode, "target": targetNode, "value": value});
};
var removeLink = function (source, target) {
for (var i = 0; i < links.length; i++) {
if (links[i].source.id == source && links[i].target.id == target) {
links.splice(i, 1);
break;
}
}
};
var setState = function (path, state) {
var node = nodes[findNodeIndex(path)];
node.state = state;
}
function processEvents(events) {
var existingNodes = {};
var commands = [];
events.forEach(function (event) {
var existingNode = existingNodes[event.path];
if (existingNode) {
var previousState = existingNode.state;
commands.push({
forward: function () {
console.log("-> " + event.path + " -> " + event.state);
setState(event.path, event.state);
},
backward: function () {
console.log("<- " + event.path + " -> " + event.state);
setState(event.path, previousState);
}
});
existingNode.state = event.state;
} else {
commands.push({
forward: function () {
console.log("++ " + event.path);
addNode(event.path);
if (event.path) {
var idx = event.path.lastIndexOf('.');
var parentPath = idx === -1 ? "" : event.path.substring(0, idx);
addLink(event.path, parentPath, 1);
}
},
backward: function () {
console.log("-- " + event.path);
removeNode(event.path);
}
});
existingNodes[event.path] = {
path: event.path,
state: event.state
};
}
});
return commands;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment