Last active
November 20, 2020 19:53
-
-
Save HarryStevens/606665118b6aca3b8a3e306b3c65f52c to your computer and use it in GitHub Desktop.
Pendulum Party
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<style> | |
body { | |
margin: 0; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas></canvas> | |
<script> | |
const vecmath = { | |
// Add vector w to vector v | |
add: (v, w) => { | |
let out = []; | |
for (let i = 0; i < v.length; i++){ | |
out[i] = v[i] + w[i]; | |
} | |
return out; | |
}, | |
// Translate position of vector v by an angle in radians and a distance in pixels | |
trans: (v, ang, dist) => [v[0] + dist * Math.cos(ang), v[1] + dist * Math.sin(ang)] | |
}; | |
// The Pendulum class | |
class Pendulum { | |
constructor(){ | |
this._acceleration = 0; | |
this._angle = Math.PI / 4; | |
this._damping = 1.0; | |
this._gravity = 0.4; | |
this._length = 200; | |
this._origin = [innerWidth / 2, 0]; | |
this._velocity = 0; | |
this._position = vecmath.trans(this._origin, this._angle, this._length); | |
return this; | |
} | |
acceleration(num){ | |
return num ? (this._acceleration = num, this) : this._acceleration; | |
} | |
angle(num){ | |
return num ? (this._angle = num, this) : this._angle; | |
} | |
damping(num){ | |
return num ? (this._damping = num, this) : this._damping; | |
} | |
gravity(num){ | |
return num ? (this._gravity = num, this) : this._gravity; | |
} | |
length(num){ | |
return num ? (this._length = num, this) : this._length; | |
} | |
origin(arr){ | |
return arr ? (this._origin = arr, this) : this._origin; | |
} | |
position(arr){ | |
return arr ? (this._position = arr, this) : this._position; | |
} | |
velocity(num){ | |
return num ? (this._velocity = num, this) : this._velocity; | |
} | |
tick(){ | |
return this | |
.acceleration((-1 * this.gravity() / this.length()) * Math.sin(this.angle())) | |
.velocity((this.velocity() + this.acceleration()) * this.damping()) | |
.angle(this.angle() + this.velocity()) | |
.position( | |
vecmath.add( | |
[this.length() * Math.sin(this.angle()), this.length() * Math.cos(this.angle())], | |
this.origin() | |
) | |
); | |
} | |
} | |
// Create the pendula | |
const pendula = []; | |
const rows = 8; | |
const cols = 10; | |
let i = 1; | |
for (let row = 0; row < rows; row++){ | |
const evenRow = row % 2 === 0; | |
for (let col = 0; col < cols; col++){ | |
if (evenRow && col === cols - 1) continue; | |
const px = innerWidth / cols; | |
const x = px / 2 + col * px + (evenRow ? px / 2 : 0); | |
const y = 10 + row * innerHeight / rows; | |
pendula.push( | |
new Pendulum() | |
.gravity(.15) | |
.length(-10 + px / 2) | |
.origin([x, y]) | |
.angle(Math.PI / 2 * (i % 2 === 0 ? 1 : -1)) | |
); | |
i++; | |
} | |
} | |
// Draw to Canvas | |
const canvas = document.querySelector("canvas"); | |
canvas.width = innerWidth; | |
canvas.height = innerHeight; | |
const ctx = canvas.getContext("2d"); | |
ctx.strokeStyle = "#aaa"; | |
function tick(){ | |
requestAnimationFrame(tick); | |
ctx.clearRect(0, 0, innerWidth, innerHeight); | |
pendula.forEach((p, i, e) => { | |
draw(p, `rgb(200, 40, ${(i + 1) / e.length * 255})`); | |
}); | |
} | |
tick(); | |
function draw(p, fill){ | |
p.tick(); | |
ctx.fillStyle = fill; | |
ctx.beginPath(); | |
ctx.moveTo(...p.origin()); | |
ctx.lineTo(...p.position()); | |
ctx.stroke(); | |
ctx.beginPath(); | |
ctx.arc(...p.origin(), 3, 0, Math.PI * 2) | |
ctx.fill(); | |
ctx.beginPath(); | |
ctx.arc(...p.position(), 10, 0, Math.PI * 2) | |
ctx.fill(); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment