const G = 0.5; // Gravity constant
const trails = [];
const pendulumCount = 3;
const pendulums = [];
class Pendulum {
constructor(x, y, length, angle, velocity, mass) {
this.x = x;
this.y = y;
this.length = length;
this.angle = angle;
this.velocity = velocity;
this.mass = mass;
}
update() {
const acceleration = (-G / this.length) * Math.sin(this.angle);
this.velocity += acceleration;
this.angle += this.velocity;
this.x = pendulums[pendulums.indexOf(this) - 1]?.x || this.x + this.length * Math.sin(this.angle);
this.y = pendulums[pendulums.indexOf(this) - 1]?.y || this.y + this.length * Math.cos(this.angle);
}
draw() {
ctx.beginPath();
ctx.moveTo(pendulums[pendulums.indexOf(this) - 1]?.x || this.x, pendulums[pendulums.indexOf(this) - 1]?.y || this.y);
ctx.lineTo(this.x, this.y);
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
}
function init() {
for (let i = 0; i < pendulumCount; i++) {
const length = 100 + i * 50;
const angle = Math.PI / 4;
const velocity = 0;
const mass = 1;
const x = canvas.width / 2;
const y = canvas.height / 2;
pendulums.push(new Pendulum(x, y, length, angle, velocity, mass));
}
}
function drawTrails() {
trails.forEach((trail, index) => {
ctx.strokeStyle = `rgba(255, 255, 255, ${1 - index / trails.length})`;
ctx.beginPath();
ctx.moveTo(trail[0].x, trail[0].y);
for (let i = 1; i < trail.length; i++) {
ctx.lineTo(trail[i].x, trail[i].y);
}
ctx.stroke();
ctx.closePath();
});
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
pendulums.forEach(pendulum => {
pendulum.update();
pendulum.draw();
});
trails.push(pendulums.map(p => ({ x: p.x, y: p.y })));
if (trails.length > 100) trails.shift();
drawTrails();
requestAnimationFrame(animate);
}
init();
animate();
const G = 0.5; // Gravity constant
const trails = [];
const pendulumCount = 3;
const pendulums = [];
class Pendulum {
constructor(x, y, length, angle, velocity, mass) {
this.x = x;
this.y = y;
this.length = length;
this.angle = angle;
this.velocity = velocity;
this.mass = mass;
}
update() {
const acceleration = (-G / this.length) * Math.sin(this.angle);
this.velocity += acceleration;
this.angle += this.velocity;
this.x = pendulums[pendulums.indexOf(this) - 1]?.x || this.x + this.length * Math.sin(this.angle);
this.y = pendulums[pendulums.indexOf(this) - 1]?.y || this.y + this.length * Math.cos(this.angle);
}
draw() {
ctx.beginPath();
ctx.moveTo(pendulums[pendulums.indexOf(this) - 1]?.x || this.x, pendulums[pendulums.indexOf(this) - 1]?.y || this.y);
ctx.lineTo(this.x, this.y);
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
}
function init() {
for (let i = 0; i < pendulumCount; i++) {
const length = 100 + i * 50;
const angle = Math.PI / 4;
const velocity = 0;
const mass = 1;
const x = canvas.width / 2;
const y = canvas.height / 2;
pendulums.push(new Pendulum(x, y, length, angle, velocity, mass));
}
}
function drawTrails() {
trails.forEach((trail, index) => {
ctx.strokeStyle = `rgba(255, 255, 255, ${1 - index / trails.length})`;
ctx.beginPath();
ctx.moveTo(trail[0].x, trail[0].y);
for (let i = 1; i < trail.length; i++) {
ctx.lineTo(trail[i].x, trail[i].y);
}
ctx.stroke();
ctx.closePath();
});
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
pendulums.forEach(pendulum => {
pendulum.update();
pendulum.draw();
});
trails.push(pendulums.map(p => ({ x: p.x, y: p.y })));
if (trails.length > 100) trails.shift();
drawTrails();
requestAnimationFrame(animate);
}
init();
animate();