D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
enjalot
Full window
Github gist
basic particle interaction
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <style> body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; font-family: Helvetica; } svg { width:100%; height: 100% } .controls { position: absolute; top: 30px; left: 20px; } input.steps { } .num { margin: 5px; } .current { width: 50px; } </style> </head> <body> <script> // Feel free to change or delete any of the code you see! var svg = d3.select("body").append("svg"); var dt = 0.05; var numSteps = 60; var a = { index: 0, radius: 40, // initial position x: 152, y: 206, // initial velocity vx: 61, vy: 0, // initial acceleration ax: 8, ay: 0 } var b = { index: 1, radius: 40, // initial position x: 457, y: 251, // initial velocity vx: -69, vy: 0, // initial acceleration ax: 32, ay: -6 } var nodes = [a,b]; var steps = [nodes]; // the collection of states function step(nodes) { var newNodes = []; nodes.forEach(function(node) { // copy the node var newNode = { index: node.index, radius: node.radius } var ax = node.ax; var ay = node.ay; // go through all the neighbors and update vx and other properties // update the velocity using latest accelerations var vx = node.vx + ax * dt; var vy = node.vy + ay * dt; var x = node.x + vx * dt; var y = node.y + vy * dt; // copy the updated state into the new node newNode.x = x; newNode.y = y; newNode.vx = vx; newNode.vy = vy; newNode.ax = ax; newNode.ay = ay; // we do collision detection on the positions directly nodes.forEach(function(neighbor){ var xx = newNode.x - neighbor.x; var yy = newNode.y - neighbor.y; var dist = Math.sqrt(xx * xx + yy * yy); var r = node.radius + neighbor.radius; //console.log(dist, r) if (dist < r) { dist = (dist - r) / dist * dt; //don't quite understand this newNode.x -= xx *= dist; newNode.y -= yy *= dist; neighbor.x += xx; neighbor.y += yy; } }) newNodes.push(newNode) }) return newNodes; } d3.range(numSteps).forEach(function(i) { var lastState = steps[steps.length-1]; console.log("lastState", i, lastState) var nextState = step(lastState); steps.push(nextState) }) console.log("steps", steps) var gstep = svg.selectAll("g.step").data(steps) gstep.enter().append("g").classed("step", true) .style({ "stroke-opacity": function(d,i) { return 1 - i/numSteps } }) .selectAll("circle.node").data(function(d) { return d }) .enter().append("circle").classed("node", true) .attr({ r: function(d) { return d.radius }, cx: function(d) { return d.x }, cy: function(d) { return d.y }, fill: "none", stroke: "#111", //"stroke-dasharray": "4 4" }) var current = svg.append("g").classed("current", true); var controls = d3.select("body").append("div") .classed("controls", true) var curText = controls.append("div").text("step: ") .append("span").classed("current", true).text(0) controls .append("input") .classed("steps", true) .attr({ type: "range", value: 0, min: 0, max: numSteps }) .on("input", slide) .on("change", slide) var numText = controls.append("span").classed("num", true).text(numSteps) function slide() { var i = +this.value || 0; console.log(i); var state = steps[i]; var circles = current.selectAll("circle.node").data(state) circles.enter().append("circle").classed("node", true) circles.attr({ r: function(d) { return d.radius }, cx: function(d) { return d.x }, cy: function(d) { return d.y }, fill: "#fff", "fill-opacity": 0.5, stroke: "#b41717", }) curText.text(i) } slide(); </script> </body>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js