JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Application</title>
<style>
/* Ensuring the canvas fills the entire window */
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
display: block;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<canvas id="render_canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
JavaScript
const canvas = document.getElementById('render_canvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
class Simulation {
constructor() {
this.bodies = [];
}
step(dt) {
// slove forces
for(const body of this.bodies) {
// v = u + f/m * t;
body.linear_velocity[0] += body.force[0] / body.mass * dt;
body.linear_velocity[1] += body.force[1] / body.mass * dt;
// zero out force
body.force = [0,0];
}
// integrate position
for(const body of this.bodies) {
// s = s + v * t;
body.pos[0] += body.linear_velocity[0] * dt;
}
}
newBody(pos, radius, density) {
const body = createBody(pos, radius, density);
this.bodies.push(body);
}
}
// create a new physics body
function createBody(pos, radius, density) {
const volume = (4/3) * Math.PI * radius * radius;
const mass = density * volume;
return {
pos: pos,
mass: mass,
radius: radius,
force: [0,0],
linear_velocity: [0, 0]
};
}
function applyForce(body, accleration) {
// f = ma;
body.force[0] = body.mass * accleration[0];
body.force[1] = body.mass * accleration[1];
}
const simulation = new Simulation();
simulation.newBody([20, 100], 20, 10);
simulation.newBody([40, 100], 20, 10);
// Animation loop
let last_time = 0;
function animate(time) {
requestAnimationFrame(animate);
// calculate frame time
const diff = time - last_time;
last_time = time;
if(diff > 100) { // handle suspend
return;
}
const dt = diff / 1000;
simulation.step(dt);
// apply foce to body 0
applyForce(simulation.bodies[0], [20, 0]);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(const body of simulation.bodies) {
ctx.beginPath();
ctx.arc(body.pos[0], body.pos[1], body.radius, 0, 2 * Math.PI);
ctx.stroke();
...