<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();
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.