Skip to content

Instantly share code, notes, and snippets.

@tonyhschu
Last active September 17, 2016 18:06
Show Gist options
  • Save tonyhschu/6d83b76910e3b6273308 to your computer and use it in GitHub Desktop.
Save tonyhschu/6d83b76910e3b6273308 to your computer and use it in GitHub Desktop.
N Dogs Chasing Random Dog
license: mit
<!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; }
svg { width: 100%; height: 100%; }
</style>
</head>
<body>
<script>
var margin = {top: 20, right: 10, bottom: 20, left: 10};
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("rect")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("fill", "#111111");
var NUM_O_DOGS = 120;
var SPEED = 5;
var dogs = [];
var targets = d3.range(0, NUM_O_DOGS, 1);
targets = d3.shuffle(targets);
var radius = (height < width) ? height / 2 : width / 2;
for (var i = 0; i < NUM_O_DOGS; i++) {
var theta = 2 * Math.PI * i / NUM_O_DOGS;
var origin = {
x: Math.cos(theta) * radius + width / 2,
y: Math.sin(theta) * radius + height / 2
}
var color = d3.hsl(i / NUM_O_DOGS * 360, 0.8, 0.6).toString();
dogs.push({
target: targets[i],
steps: [origin],
color: color
});
}
// Feel free to change or delete any of the code you see!
var step = 0;
var circle = svg.selectAll("circle")
.data(dogs);
var paths = svg.selectAll("path")
.data(dogs);
paths.enter().append("path")
.attr("fill", "none")
.attr("stroke", function(d) {
return d.color;
})
.attr("stroke-width", 0.5)
.attr("opacity", 0.8);
circle.enter().append("circle")
.attr("r", 2.5)
.attr("fill", function(d) {
return d.color;
});
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
function chase(dog) {
var targetDog = dogs[dog.target];
var deltaX = targetDog.steps[step].x - dog.steps[step].x;
var deltaY = targetDog.steps[step].y - dog.steps[step].y;
var deltaLength = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (deltaLength < SPEED) {
var unitX = deltaX;
var unitY = deltaY;
} else {
var unitX = deltaX / deltaLength * SPEED;
var unitY = deltaY / deltaLength * SPEED;
}
var newCoordinates = {
x: dog.steps[step].x + unitX,
y: dog.steps[step].y + unitY
}
dog.steps.push(newCoordinates);
}
function reset() {
targets = d3.shuffle(targets);
dogs.forEach(function(dog, i) {
dog.target = targets[i];
dog.steps = dog.steps.slice(0,1);
})
}
function draw(timestamp) {
dogs.forEach(chase);
circle
.attr("cx", function(d) { return d.steps[step].x; })
.attr("cy", function(d) { return d.steps[step].y; })
.attr("r", 2.5);
paths
.attr("d", function(d) {
return lineFunction(d.steps);
})
step++;
if (step > 150) {
reset();
step = 0;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment