<script src="https://anuraghazra.github.io/CanvasFun/src/lib/Vector.js"></script>
<canvas id="c">
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
let canvas = document.getElementById("c");
let ctx = canvas.getContext("2d");
let CANVAS_WIDTH = window.innerWidth-5;
let CANVAS_HEIGHT = window.innerHeight-5;
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
class Dot {
constructor(x, y, vx, vy) {
this.pos = new Vector(x, y);
this.oldpos = new Vector(x + (vx||0), y + (vy||0)); // velocity x, y
this.friction = 0.97;
this.groundFriction = 0.7;
this.gravity = new Vector(0, 1);
this.radius = 5;
this.color = "#e62a4f";
this.mass = 1;
}
update() {
let vel = Vector.sub(this.pos, this.oldpos);
vel.mult(this.friction);
// if the point touches the ground set groundFriction
if (this.pos.y >= CANVAS_HEIGHT - this.radius && vel.magSq() > 0.000001) {
var m = vel.mag();
vel.x /= m;
vel.y /= m;
vel.mult(m * this.groundFriction);
}
this.oldpos.setXY(this.pos.x, this.pos.y);
this.pos.add(vel);
this.pos.add(this.gravity);
}
constrain() {
if (this.pos.x > CANVAS_WIDTH - this.radius) {
this.pos.x = CANVAS_WIDTH - this.radius;
}
if (this.pos.x < this.radius) {
this.pos.x = this.radius;
}
if (this.pos.y > CANVAS_HEIGHT - this.radius) {
this.pos.y = CANVAS_HEIGHT - this.radius;
}
if (this.pos.y < this.radius) {
this.pos.y = this.radius;
}
};
render(ctx) {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.pos.x, this.pos.y, this.radius, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
class Stick {
constructor(p1, p2, length) {
this.startPoint = p1;
this.endPoint = p2;
this.stiffness = 2;
this.color = '#f5476a';
// if the length is not given then calculate the distance based on position
if (!length) {
this.length = this.startPoint.pos.dist(this.endPoint.pos);
} else {
this.length = length;
}
}
update() {
// calculate the distance between two dots
let dx = this.endPoint.pos.x - this.startPoint.pos.x;
let dy = this.endPoint.pos.y - this.startPoint.pos.y;
// pythagoras theorem
let dist = Math.sqrt(dx * dx + dy * dy);
// calculate the resting distance betwen the dots
let diff = (this.length - dist) / dist * this.stiffness;
// getting the offset of the points
let offsetx = dx * diff * 0.5;
let offsety = dy * diff * 0.5;
// calculate mass
let m1 = this.startPoint.mass + this.endPoint.mass;
let m2 = this.startPoint.mass / m1;
m1 = this.endPoint.mass / m1;
// and finally apply the offset with calculated mass
if (!this.startPoint.pinned) {
this.startPoint.pos.x -= offsetx * m1;
this.startPoint.pos.y -= offsety * m1;
}
if (!this.endPoint.pinned) {
this.endPoint.pos.x += offsetx * m2;
this.endPoint.pos.y += offsety * m2;
}
}
render(ctx) {
ctx.beginPath();
ctx.strokeStyle = this.color;
ctx.moveTo(this.startPoint.pos.x, this.startPoint.pos.y);
ctx.lineTo(this.endPoint.pos.x, this.endPoint.pos.y);
ctx.stroke();
ctx.closePath();
}
}
let dots = [];
let sticks = [];
dots.push(new Dot(100, 100, (Math.random() - 0.5) * 100.0));
dots.push(new Dot(200, 100));
dots.push(new Dot(200, 200));
dots.push(new Dot(100, 200));
sticks.push(new Stick(dots[0], dots[1]))
sticks.push(new Stick(dots[1], dots[2]))
sticks.push(new Stick(dots[2], dots[3]))
sticks.push(new Stick(dots[3], dots[0]))
sticks.push(new Stick(dots[3], dots[1]))
const ITERATION = 100;
function animate() {
ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
// update
for (let i = 0; i < ITERATION; i++) {
for (let d of dots) {
d.constrain();
}
for (let s of sticks) {
s.update();
}
}
for (let d of dots) {
d.update();
d.render(ctx);
}
for (let s of sticks) {
s.update();
s.render(ctx);
}
requestAnimationFrame(animate);
}
animate();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.