<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.8/p5.js"></script>
body {margin:0px; padding:0px; overflow: hidden}
let msec = 0, prevInitMsec = 0, prevNow = 0;
let plotMode = -1, plotLabels = ["position(y)", "velocity(y)", "acceleration(y)"];
let plotStartMsec = 0, plotData = [];
const gravity = 9.8;
const plotScale = 20;
const timeScale = 3;
let apple;
function setup() {
createCanvas(windowWidth, windowHeight);
// Initialize the Body object with a mass of 1 (like an apple)
apple = new Body(1);
}
function draw() {
clear();
background(247, 227, 218);
ellapseTime();
let minWH = min(width, height);
// Render the apple's current position
push();
translate(min((width - minWH) / 2 + 32, width / 4), 32);
fill(250, 170, 165);
stroke(0);
ellipse(0, apple.position.y * plotScale, 24, 24);
line(0, apple.position.y * plotScale - 8, 0, apple.position.y * plotScale - 16);
pop();
// Plot the graph showing either position, velocity, or acceleration
let graphW = minWH - 64;
plotGraph(plotData, (width - graphW) / 2 + 32, 32, graphW, height - 64, 0, 8000, -(height - 64), 0, "time", plotLabels[plotMode]);
}
function ellapseTime() {
// Calculate the elapsed time since the last frame
let ellapsedMsec = (window.performance.now() - prevNow) * timeScale;
prevNow = window.performance.now();
// Update the simulation based on elapsed time
updateSimulation(ellapsedMsec / 2000);
msec += ellapsedMsec;
if (msec > prevInitMsec + 4000) {
apple = new Body(1);
plotData = [];
prevInitMsec += 4000;
}
// Store data for the graph
if (plotData.length == 0) {
plotStartMsec = msec;
plotMode = (plotMode + 1) % 3;
}
let protMsec = msec - plotStartMsec;
switch(plotMode) {
case 0:
plotData.push({x:protMsec * 2.5, y: -apple.position.y * plotScale});
break;
case 1:
plotData.push({x:protMsec * 2.5, y: -apple.velocity.y * plotScale});
break;
case 2:
plotData.push({x:protMsec * 2.5, y: -gravity * plotScale});
break;
}
}
function updateSimulation(t) {
// Apply gravitational force to the apple and update its state
apple.applyForce(getForce(apple), t);
apple.update(t);
}
function getForce(o) {
// Calculate the gravitational force acting on an object
// F = m * g
return createVector(0, gravity).mult(o.mass);
}
function plotGraph(data, ox, oy, w, h, minX, maxX, minY, maxY, xLabel, yLabel) {
let left = ox - minX / (maxX - minX) * w;
let top = oy - maxY / (maxY - minY) * h;
let labelLeft = abs(left - ox) > abs(left + w - ox);
let labelTop = abs(top - oy) > abs(top + h - oy);
push();
noFill(); stroke(0);
line(left, oy, left + w, oy);
line(ox, top, ox, top + h);
beginShape();
for (let i = 0; i < data.length; i ++) {
let x = ox + data[i].x / (maxX - minX) * w;
let y = oy - data[i].y / (maxY - minY) * h;
vertex(x, y);
}
endShape();
fill(0);
drawLabel(labelLeft ? left : left + w, oy + (labelTop ? 16 : -8), xLabel, labelLeft ? LEFT : RIGHT);
drawLabel(ox, labelTop ? top : top + h, yLabel, labelLeft ? RIGHT : LEFT);
pop();
}
class Body { // Newtonian Physics Object
constructor(m) {
this.position = createVector(0, 0, 0);
this.velocity = createVector(0, 0, 0);
this.mass = m;
}
applyForce(f, t) {
this.velocity.add(f.copy().mult(t / this.mass));
}
update(t) {
this.position.add(this.velocity.copy().mult(t))
}
draw() {
ellipse(this.position.x, this.position.y, 8, 8);
}
}
function drawCircleMarker(p, size) {
ellipse(p.x, p.y, size * 2, size * 2);
}
function drawLabel(x, y, label, align = CENTER) {
push();
strokeWeight(0);
textFont("monospace");
textSize(14);
textAlign(align);
if (align == LEFT) {x += 6;}
if (align == RIGHT) {x -= 6;}
text(label, x, y);
pop();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.