This got a little weird.
forked from veltman's block: Particle tentacles
forked from Thanaporn-sk's block: Particle tentacles
license: mit |
This got a little weird.
forked from veltman's block: Particle tentacles
forked from Thanaporn-sk's block: Particle tentacles
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
</head> | |
<body> | |
<canvas width="960" height="500"></canvas> | |
<canvas width="960" height="500" class="offscreen" style="display: none;"></canvas> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
var width = 960, | |
height = 500; | |
var canvas = document.querySelector("canvas"), | |
context = canvas.getContext("2d"), | |
offscreen = document.querySelector(".offscreen"), | |
offscreenContext = offscreen.getContext("2d"); | |
offscreenContext.globalAlpha = 0.8; | |
var numDots = 1200; | |
var points = d3.range(numDots).map(function(d, i){ | |
return { | |
position: new Vec2(Math.random() * width, Math.random() * height), | |
velocity: new Vec2(Math.random() * 3, Math.random() * 3) | |
}; | |
}); | |
d3.shuffle(points); | |
points.forEach(function(p, i){ | |
p.target = points[i + 1] || points[0]; | |
p.color = d3.interpolateRainbow(i / numDots); | |
}); | |
var maxVelocity = 3, | |
maxForce = 0.4; | |
d3.timer(function(t){ | |
points.forEach(function(p){ | |
var destination = p.target.position.clone(), | |
desiredVelocity = destination.subtract(p.position).normalize().scale(maxVelocity), | |
steering = desiredVelocity.subtract(p.velocity).truncate(maxForce); | |
p.velocity.add(steering).truncate(maxVelocity); | |
}); | |
offscreenContext.clearRect(0, 0, width, height); | |
offscreenContext.drawImage(canvas, 0, 0, width, height); | |
context.clearRect(0, 0, width, height); | |
context.drawImage(offscreen, 0, 0, width, height); | |
points.forEach(function(p, i){ | |
// Wall bounces | |
if (p.position.x + p.velocity.x < 0 || p.position.x + p.velocity.x >= width) { | |
p.velocity.x = -p.velocity.x; | |
} | |
if (p.position.y + p.velocity.y < 0 || p.position.y + p.velocity.y >= height) { | |
p.velocity.y = -p.velocity.y; | |
} | |
p.position.add(p.velocity); | |
context.beginPath(); | |
context.fillStyle = p.color; | |
context.arc(p.position.x, p.position.y, 2, 0, 2 * Math.PI); | |
context.fill(); | |
}); | |
}); | |
function Vec2(x, y) { | |
this.x = x || 0; | |
this.y = y || 0; | |
return this; | |
}; | |
Vec2.prototype.add = function(v) { | |
this.x += v.x; | |
this.y += v.y; | |
return this; | |
}; | |
Vec2.prototype.clone = function() { | |
return new Vec2(this.x, this.y); | |
}; | |
Vec2.prototype.subtract = function(v) { | |
this.x -= v.x; | |
this.y -= v.y; | |
return this; | |
}; | |
Vec2.prototype.scale = function(s) { | |
this.x = this.x * s; | |
this.y = this.y * s; | |
return this; | |
}; | |
Vec2.prototype.normalize = function() { | |
var length = this.length(); | |
this.x = this.x / length; | |
this.y = this.y / length; | |
return this; | |
}; | |
Vec2.prototype.length = function() { | |
return Math.sqrt(this.x * this.x + this.y * this.y); | |
}; | |
Vec2.prototype.truncate = function(max) { | |
var length = this.length(); | |
if (length > max) { | |
this.x = this.x * max / length; | |
this.y = this.y * max / length; | |
} | |
return this; | |
}; | |
Vec2.prototype.dot = function(v) { | |
return this.x * v.x + this.y * v.y; | |
}; | |
</script> |
�PNG | |