Skip to content

Instantly share code, notes, and snippets.

@KristinHenry
Created October 1, 2016 19:46
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 KristinHenry/74da47847eac56dae0dc2771c988dcd1 to your computer and use it in GitHub Desktop.
Save KristinHenry/74da47847eac56dae0dc2771c988dcd1 to your computer and use it in GitHub Desktop.
particles
<!doctype html>
<meta charset="utf-8">
<head>
<title>Testing interactive svg + canvas plot</title>
<style>
body { margin: 0; }
svg {
position: absolute;
top: 0;
left: 0;
}
rect { fill: transparent; }
</style>
<script src='http://d3js.org/d3.v3.min.js'></script>
</head>
<body style="background-color: #246980">
<script type='text/javascript'>
var filler = '#eee';
var prp1 = '#7b3294';
var prp2 = '#c2a5cf';
var grn1 = '#a6dba0';
var grn2 = '#008837';
var colors = [filler, prp1, prp2, grn1, grn2];
function randomRange(min, max){
return Math.floor((Math.random() * (max - min + 1)) + min);
}
function getDir(){
if(randomRange(0,1) == 1){ return 1;}
return -1;
}
var map = {};
map.width = 1050;
map.height = 1500;
var xmin = 20;
var xmax = map.width-20;
var ymin = 20;
var ymax = map.height-20;
var s = 1;
var maxNodesCan = map.width/2; //200;
var maxNodesSVG = maxNodesCan/10; //20;
map.canvas =
d3.select('body')
.append('canvas')
.attr('width', map.width)
.attr('height', map.height)
.node().getContext('2d');
map.svg =
d3.select('body')
.append('svg')
.attr('width', map.width)
.attr('height', map.height)
.append('g');
map.svg.append('rect')
.attr('class', 'overlay')
.attr('width', map.width)
.attr('height', map.height);
/* Initialize particles */
// background molecules
var rmin = 10;
map.canvas.nodes =
d3.range(maxNodesCan).map(function(d, i) {
return {
x: randomRange(xmin,xmax),
y: randomRange(ymin,ymax),
r: randomRange(3,20) + rmin,
t: 0,
dx: getDir(),
dy: getDir()
};
});
// interactive molecules
map.svg.nodes =
d3.range(maxNodesSVG).map(function(d, i) {
var t = randomRange(1,colors.length-1);
return {
x: randomRange(xmin,xmax),
y: randomRange(ymin,ymax),
r: t*5 + 2 + rmin,
t: t,
dx: getDir(),
dy: getDir()
};
});
map.nodes = map.svg.nodes.concat( map.canvas.nodes );
var root = map.nodes[0];
root.r = 0;
root.fixed = true;
map.canvas.draw =
function() {
map.canvas.clearRect(0, 0, map.width, map.height);
map.canvas.beginPath();
var i = -1, cx, cy;
while (++i < map.canvas.nodes.length) {
d = map.canvas.nodes[i];
map.canvas.fillStyle = colors[d.t];
cx = d.x;
cy = d.y;
map.canvas.moveTo(cx, cy);
map.canvas.arc(cx, cy, d.r, 0, 2 * Math.PI);
}
map.canvas.fill();
};
map.svg.draw =
function() {
circle = map.svg.selectAll('circle')
.data(map.svg.nodes).enter()
.append('circle')
.attr('r', function(d) { return d.r; })
.attr('fill', function(d){return colors[d.t];})
.attr('transform', map.svg.transform);
};
// initial draw of molecules
map.canvas.draw();
map.svg.draw();
map.redraw = function() {
map.canvas.draw();
circle.attr('transform', map.svg.transform);
};
map.svg.transform =
function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
};
map.redraw();
map.updatePositions = function(){
var d;
var q = d3.geom.quadtree(map.nodes)
for(var i=0; i<map.canvas.nodes.length; i++){
d = map.canvas.nodes[i];
q.visit(collide(d));
testBounds(d);
}
for(var i=0; i<map.svg.nodes.length; i++){
d = map.svg.nodes[i];
q.visit(collide(d));
testBounds(d);
}
}
var timer_ret_val = false;
// Keeps a record of the elapsed time since the timer began.
var timer_elapsed = 0;
// Kick off the timer, and the action begins:
d3.timer(tickFxn);
function tickFxn(_elapsed) {
timer_elapsed = _elapsed;
map.updatePositions();
map.redraw();
var q = d3.geom.quadtree(map.nodes);
return timer_ret_val;
}
//---------------------------------------------------
function testBounds(mol){
if(mol.x <= (xmin+mol.r) ){
mol.dx = s;
} else if(mol.x >= (xmax-mol.r) ){
mol.dx = -s;
}
if(mol.y < (ymin+2*mol.r)){
mol.dy = s;
} else if(mol.y >= (ymax-2*mol.r)){
mol.dy = -s;
}
mol.x += mol.dx;
mol.y += mol.dy;
}
function collide(node) {
var b = .8;
var r = node.r + 1,
nx1 = node.x - r,
nx2 = node.x + r,
ny1 = node.y - r,
ny2 = node.y + r;
//then check nearby particles in quadtree
return function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x,
y = node.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = node.r + quad.point.r + 3;
if (l < r) {
l = (l - r) / l * b;
node.x -= x *= l;
node.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
};
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment