Skip to content

Instantly share code, notes, and snippets.

@jdutta
Last active February 9, 2016 00:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdutta/3a9c506661877bd538c3 to your computer and use it in GitHub Desktop.
Save jdutta/3a9c506661877bd538c3 to your computer and use it in GitHub Desktop.
network-share-sim
{"description":"network-share-sim","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"s_action.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"inlet.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"c_ip.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"chart_data.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"ajax-caching":true,"thumbnail":"http://i.imgur.com/ELBizEx.gif"}
// Testing of force graph without edges.
// Charge function idea from: http://vallandingham.me/bubble_charts_in_d3.html
// Multi-foci idea: http://bl.ocks.org/mbostock/1021841
// Tip: for no overlap, use this: http://bl.ocks.org/mbostock/3231298
// Configurable params
// Click on the number and see a magic slider appears to tweak it.
var config = {
width: 700,
height: 600,
nodeRadius: 3,
linkColor: '#ccc',
nodeColor: '#999',
toVisitNodeColor: '#ffbb42',
visitedNodeColor: '#ff3300'
};
// [0, n)
function getRandInt(n) {
return Math.floor(Math.random() * n);
}
function generateNodes(n) {
var nodes = [];
for (var i=0; i<n; i++) {
nodes.push({
id: i,
conn: [],
payload: {}
});
}
return nodes;
}
function generateLinks(nodes, maxLinksPerNode) {
var links = [];
var n = nodes.length;
for (var i=0; i<n; i++) {
var node = nodes[i];
if (node.conn.length < maxLinksPerNode) {
var numLinks = getRandInt(maxLinksPerNode-node.conn.length) + 1;
for (var j=0; j<numLinks; j++) {
var connNodeId = getRandInt(n);
while (connNodeId === node.id || node.conn.indexOf(connNodeId) > -1) {
connNodeId = getRandInt(n);
}
if (nodes[connNodeId].conn.length < maxLinksPerNode) {
node.conn.push(connNodeId);
nodes[connNodeId].conn.push(node.id);
links.push({
source: node,
target: nodes[connNodeId]
});
}
}
}
}
return links;
}
var nodes = generateNodes(100);
var links = generateLinks(nodes, 3);
var shareSim = shareSimulation(nodes);
d3.select("body").on("mousedown", shareSim.toggle);
visualize(nodes);
function visualize(nodes) {
var svg = d3.select('svg');
var gRoot = svg.append('svg:g')
.attr('transform', 'translate(0, 50)');
var node = gRoot.selectAll('.node');
var link = gRoot.selectAll('.link');
var line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([config.width, config.height])
.gravity(0.15)
.charge(function (d, i) {
return -100;
})
.on('tick', tick)
.start();
link = link.data(links)
.enter()
.append('svg:line')
.classed('link', true)
.style('stroke', config.linkColor)
.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 = node.data(nodes)
.data(nodes)
.enter()
.append('svg:g')
.attr('class', 'node')
.attr('transform', function (d) { return 'translate('+[d.x, d.y] +')'; })
.call(force.drag)
node.append('svg:circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', function (d) {
return config.nodeRadius;
});
node.style('fill', function (d) {
if (!d.id) {
return config.visitedNodeColor;
}
return config.nodeColor;
})
.style('stroke-width', 3);
function tick(e) {
if (e.alpha < 0.001) {
force.stop();
return;
}
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; });
}
function updateSimProgress(nodesToVisitNow, visitedNodes) {
console.log('update sim progress', nodesToVisitNow);
node.style('stroke', function (d) {
if (nodesToVisitNow[d.id]) {
return config.toVisitNodeColor;
}
});
node.style('fill', function (d) {
if (visitedNodes[d.id]) {
return config.visitedNodeColor;
}
return config.nodeColor;
});
link.style('stroke', function (d) {
if ((nodesToVisitNow[d.target.id] && visitedNodes[d.source.id]) || (nodesToVisitNow[d.source.id]) && visitedNodes[d.target.id]) {
return config.toVisitNodeColor;
} else if (visitedNodes[d.target.id] || visitedNodes[d.source.id]) {
return config.visitedNodeColor;
}
return config.linkColor;
});
}
function resetSim() {
node.style('fill', function (d) {
if (!d.id) {
return config.visitedNodeColor;
}
return config.nodeColor;
});
link.style('stroke', config.linkColor);
}
shareSim.addUpdateCallback(updateSimProgress);
shareSim.addResetCallback(resetSim);
}
function shareSimulation(nodes) {
var running = false;
var timer = null;
var updateCallbackFn = function () {};
var resetCallbackFn = function () {};
var visitedNodes = {};
var nodesToVisitNow = {0: true};
function oneStep() {
var toVisitNext = {};
for (var nodeId in nodesToVisitNow) {
visitedNodes[nodeId] = true;
nodes[nodeId].conn.forEach(function (connNodeId) {
if (!visitedNodes[connNodeId] && !nodesToVisitNow[connNodeId] && !toVisitNext[connNodeId]) {
toVisitNext[connNodeId] = true;
}
});
}
nodesToVisitNow = toVisitNext;
//console.log('to visit next', toVisitNext, visitedNodes);
}
function reset() {
visitedNodes = {};
nodesToVisitNow = {0: true};
}
// toggle function
return {
addUpdateCallback: function (fn) {
updateCallbackFn = fn;
},
addResetCallback: function (fn) {
resetCallbackFn = fn;
},
toggle: function() {
running = !running;
if (running) {
if (!Object.keys(nodesToVisitNow).length) {
reset();
resetCallbackFn();
}
timer = setInterval(function () {
oneStep();
updateCallbackFn(nodesToVisitNow, visitedNodes);
if (!Object.keys(nodesToVisitNow).length) {
clearTimeout(timer);
}
}, 500);
} else {
clearTimeout(timer);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment