Skip to content

Instantly share code, notes, and snippets.

@FHell
Last active June 20, 2017 10:31
Show Gist options
  • Save FHell/70f4ea7e93bdc4349fce35929d653dad to your computer and use it in GitHub Desktop.
Save FHell/70f4ea7e93bdc4349fce35929d653dad to your computer and use it in GitHub Desktop.
Scratchpad for networks
{
"nodes": [
{
"id": 1,
"name": "A"
},
{
"id": 2,
"name": "B"
},
{
"id": 3,
"name": "C"
},
{
"id": 4,
"name": "D"
},
{
"id": 5,
"name": "E"
},
{
"id": 6,
"name": "F"
},
{
"id": 7,
"name": "G"
},
{
"id": 8,
"name": "H"
},
{
"id": 9,
"name": "I"
},
{
"id": 10,
"name": "J"
}
],
"links": [
{
"source": 1,
"target": 2
},
{
"source": 1,
"target": 5
},
{
"source": 1,
"target": 6
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 7
}
,
{
"source": 3,
"target": 4
},
{
"source": 8,
"target": 3
}
,
{
"source": 4,
"target": 5
}
,
{
"source": 4,
"target": 9
},
{
"source": 5,
"target": 10
}
]
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<div id="option">
<input name="toggleButton"
type="button"
value="Toggle"
onclick="toggle()" />
</div>
<script>
var simWorker = new Worker('simulation.js');
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)
var width = +svg.attr("width")
var height = +svg.attr("height")
var state
var index
toggle_text = svg.append("text")
.text("Forces On")
.attr("y", 30)
.attr("x", 30)
.style("font-size", 36)
.style("font-family", "monospace")
loading_text = svg.append("text")
.text("Loading...")
.attr("y", 60)
.attr("x", 30)
.style("font-size", 36)
.style("font-family", "monospace")
worker_text = svg.append("text")
.text("Loading...")
.attr("y", 90)
.attr("x", 30)
.style("font-size", 36)
.style("font-family", "monospace")
linkForce = d3.forceLink().id(function(d) { return d.id; })
manyBodyForce = d3.forceManyBody().strength(-400)
centerForce = d3.forceCenter(width / 2, height / 2)
simulation = d3.forceSimulation()
.force("link", linkForce)
.force("charge", manyBodyForce)
.force("center", centerForce);
d3.json("data.json", function(e, d) {simulate_graph(d)})
function simulate_graph(graph_loaded){
graph = graph_loaded
index = new Object()
graph.nodes.forEach(function(node, i) {index[node.id] = i})
loading_text.text("JSON loaded and processing")
var link = svg.append("g")
.style("stroke", "#aaa")
.selectAll("line")
.data(graph.links)
.enter().append("line");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 6)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", clicked);
node
.attr("r", 20)
.style("fill", "#d9d9d9")
.style("stroke", "#969696")
.style("stroke-width", "1px")
data = {
m_type: "network",
graph: graph
};
simWorker.postMessage(data)
simWorker.onmessage = e => {
states = e.data
node.style("fill", function(d) { return d3.interpolateRainbow(states[index[d.id]] % 1) } )
.attr("r", function(d) {return 7 * Math.sin(states[index[d.id]]) + 10})
worker_text.text("Worker message recevied with " + states)
}
worker_text.text("Worker callback set")
simulation.nodes(graph.nodes)
simulation.force("link").links(graph.links);
simulation.on("tick", ticked);
ticks = 0
var buffer = new ArrayBuffer(graph.nodes.length * 8)
var states = new Float64Array(buffer)
var index = new Object()
graph.nodes.forEach(function(node, i) {index[node.id] = i; states[i] = 0})
function ticked() {
ticks += 1
loading_text.text("JSON loaded and tick " + ticks)
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; });
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
}
}
t = true
function dragstarted(d) {
/* I don't understand this line at all*/
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
/* I don't understand this line at all*/
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function clicked(d) {
data = {m_type: 'perturbation', perturbation: d.id}
simWorker.postMessage(data)
}
function toggle() {
if (t) {
toggle_text.text("Forces Off")
t = false
simulation
.force("link", null)
.force("charge", null)
.force("center", null);
} else {
toggle_text.text("Forces On")
t = true
simulation
.force("link", linkForce)
.force("charge", manyBodyForce)
.force("center", centerForce);
simulation.alpha(1).alphaTarget(0).restart();
}
}
</script>
</body>
var graph = null
var simulation_running = false
var simulation = null
var states
var buffer
var index
onmessage = function(e) {
switch (e.data.m_type){
case 'network':
graph = e.data.graph
initialize_simulation(graph)
break
case 'sim_on':
start_simulation()
break
case 'sim_off':
stop_simulation()
break
case 'perturbation':
perturb_simulation(e.data.perturbation)
break
}
}
function initialize_simulation(g) {
buffer = new ArrayBuffer(graph.nodes.length * 8)
states = new Float64Array(buffer)
index = new Object()
graph.nodes.forEach(function(node, i) {index[node.id] = i; states[i] = 0})
start_simulation()
}
function start_simulation(){
simulation = setInterval(function () {states[0] += 0.07; postMessage(states);}, 50)
}
function stop_simulation(){
if (simulation) {
clearInterval(simulation)
}
}
function perturb_simulation(perturbation){
if (simulation) {
states[index[perturbation]] += 0.7
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment