|
<!DOCTYPE html> |
|
<svg width="960" height="500"></svg> |
|
<script src="https://d3js.org/d3.v4.js"></script> |
|
<script> |
|
|
|
var mocks = { |
|
// linear |
|
"linear-to-branch" : [ |
|
// a comes online |
|
{"id":"a", "action":"online"}, |
|
// b comes online |
|
{"id":"b", "action":"online"}, |
|
// b listens to a |
|
{"id":"b", "action":"listen", "target":"a"}, |
|
// c comes online |
|
{"id":"c", "action":"online"}, |
|
// c listens to b |
|
{"id":"c", "action":"listen", "target":"b"}, |
|
// d comes online |
|
{"id":"d", "action":"online"}, |
|
// d listens to c |
|
{"id":"d", "action":"listen", "target":"c"}, |
|
// e comes online |
|
{"id":"e", "action":"online"}, |
|
// e listens to d |
|
{"id":"e", "action":"listen", "target":"d"}, |
|
// f comes online |
|
{"id":"f", "action":"online"}, |
|
// f listens to e |
|
{"id":"f", "action":"listen", "target":"e"}, |
|
// g comes online |
|
{"id":"g", "action":"online"}, |
|
// g listens to f |
|
{"id":"g", "action":"listen", "target":"f"}, |
|
// linear to tree |
|
// a listens to d |
|
{"id":"a", "action":"listen", "target":"d"}, |
|
// implies c becomes choose (no longer listener) |
|
{"id":"d", "action":"unlisten", "target":"c"} |
|
], |
|
"online-offline" : [ |
|
{"id":"a", "action":"online"}, |
|
{"id":"b", "action":"online"}, |
|
{"id":"c", "action":"online"}, |
|
{"id":"d", "action":"online"}, |
|
{"id":"e", "action":"online"}, |
|
{"id":"f", "action":"online"}, |
|
{"id":"g", "action":"online"}, |
|
{"id":"g", "action":"offline"}, |
|
{"id":"f", "action":"offline"}, |
|
{"id":"c", "action":"offline"}, |
|
{"id":"e", "action":"offline"}, |
|
{"id":"d", "action":"offline"}, |
|
{"id":"b", "action":"offline"}, |
|
{"id":"a", "action":"offline"}, |
|
] |
|
}; |
|
|
|
// |
|
var svg = d3.select("svg"), |
|
width = +svg.attr("width"), |
|
height = +svg.attr("height"), |
|
color = d3.scaleOrdinal(d3.schemeCategory10); |
|
// var a = {id: "a"}, |
|
// b = {id: "b"}, |
|
// c = {id: "c"}, |
|
// d = {id: "d"}, |
|
// e = {id: "e"}, |
|
// f = {id: "f"}, |
|
// g = {id: "g"}, |
|
var nodes = [], |
|
links = []; |
|
var simulation = d3.forceSimulation(nodes) |
|
.force("charge", d3.forceManyBody().strength(-1000)) |
|
.force("link", d3.forceLink(links).distance(200)) |
|
.force("x", d3.forceX()) |
|
.force("y", d3.forceY()) |
|
.alphaTarget(1) |
|
.on("tick", ticked); |
|
var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"), |
|
link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"), |
|
node = g.append("g").attr("stroke", "#fff").attr("stroke-width", 1.5).selectAll(".node"); |
|
restart(); |
|
|
|
function online (id) { |
|
nodes.push({id: id}); |
|
} |
|
|
|
function offline (id) { |
|
nodes.slice(nodes.indexOf({id: id}),1); |
|
} |
|
|
|
function listen (listener, broadcaster) { |
|
links.push({source:listener, target:broadcaster}); |
|
} |
|
|
|
function unlisten (listener, broadcaster) { |
|
links.splice(links.indexOf({source:listener, target:broadcaster}), 1); |
|
} |
|
|
|
d3.interval(function() { |
|
// if (mocks["linear-to-branch"].length > 0) { |
|
// var instruction = mocks["linear-to-branch"].shift(); |
|
// if (instruction.action == "online") { |
|
// online(instruction.id); |
|
// } else if (instruction.action == "listen") { |
|
// listen(instruction.id, instruction.target); |
|
// } |
|
restart(); |
|
// } |
|
}, 2000, d3.now()+1000); |
|
|
|
|
|
function restart() { |
|
// Apply the general update pattern to the nodes. |
|
node = node.data(nodes, function(d) { return d.id;}); |
|
node.exit().remove(); |
|
node = node.enter().append("circle").attr("fill", function(d) { return color(d.id); }).attr("r", 8).merge(node); |
|
// Apply the general update pattern to the links. |
|
link = link.data(links, function(d) { return d.source.id + "-" + d.target.id; }); |
|
link.exit().remove(); |
|
link = link.enter().append("line").merge(link); |
|
// Update and restart the simulation. |
|
simulation.nodes(nodes); |
|
simulation.force("link").links(links); |
|
simulation.alpha(1).restart(); |
|
} |
|
function ticked() { |
|
node.attr("cx", function(d) { return d.x; }) |
|
.attr("cy", function(d) { return 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; }); |
|
} |
|
</script> |