commit 87f9311d7053376c336574f87179c6dd0fdaa9f3
parent 39893899dadbd897716e96d4633f1ffd841223be
Author: AsherMorgan <59518073+AsherMorgan@users.noreply.github.com>
Date: Tue, 2 Mar 2021 19:02:55 -0800
Add horizontal motion simulation
Diffstat:
3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/index.html b/index.html
@@ -17,6 +17,7 @@
<ul>
<li><a title="Atwood Machine Simulation" href="simulations/atwood-machine.html">Atwood Machine Simulation</a></li>
<li><a title="Circular Motion Simulation" href="simulations/circular-motion.html">Circular Motion Simulation</a></li>
+ <li><a title="Horizontal Motion Simulation" href="simulations/horizontal-motion.html">Horizontal Motion Simulation</a></li>
</ul>
</body>
</html>
diff --git a/simulations/horizontal-motion.html b/simulations/horizontal-motion.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <title>Horizontal Motion Simulation</title>
+ <meta name="Description" content="Horizontal motion physics simulation and calculator">
+ <meta name="viewport" content="width=device-width">
+ <script src="https://cdn.jsdelivr.net/npm/vue@3.0.6"></script>
+ <link rel="stylesheet" href="styles.css">
+ <script src="horizontal-motion.js"></script>
+ </head>
+ <body onload="createApp()">
+ <div id="app">
+ <header>
+ <a title="Home" href="../" class="icon"><img alt="" src="../images/home.svg"></a>
+ <h1>Horizontal Motion Simulation</h1>
+ </header>
+
+ <noscript>
+ <p>This simulation requires JavaScript</p>
+ </noscript>
+
+ <div id="input" hidden>
+ <section>
+ <label for="massInput"><b>Mass:</b> {{ mass.toFixed(1) }} Kg</label>
+ <input type="range" min="1" max="10" step="0.1" v-model.number="mass" @input="reset" :disabled="active" id="massInput">
+ </section>
+ <section>
+ <label for="initialVelocityInput"><b>Initial Velocity:</b> {{ initialVelocity.toFixed(1) }} m/s</label>
+ <input type="range" min="-10" max="10" step="0.1" v-model.number="initialVelocity" @input="reset" :disabled="active" id="initialVelocityInput">
+ </section>
+ <section>
+ <label for="forceInput"><b>Applied Force:</b> {{ force.toFixed(1) }} N</label>
+ <input type="range" min="-10" max="10" step="0.1" v-model.number="force" @input="reset" :disabled="active" id="forceInput">
+ </section>
+ <button @click="toggle" class="icon" :title="active ? 'Pause' : (time === 0 ? 'Start' : 'Resume')">
+ <img alt="" :src="active ? '../images/pause.svg' : '../images/play.svg'">
+ </button>
+ <button @click="reset" class="icon" title="Reset">
+ <img alt="" src="../images/reset.svg">
+ </button>
+ </div>
+
+ <div id="output" hidden>
+ <svg width="800px" viewBox="0 0 10 2">
+ <!-- Ruler marks -->
+ <line v-for="(_,n) in 101" :x1="references[1] + n*0.1" y1="1.7" :x2="references[1] + n*0.1" y2="1.9" stroke-width="0.01" stroke="#000000"></line>
+ <line v-for="(_,n) in 11" :x1="references[0] + n" y1="1.6" :x2="references[0] + n" y2="2.0" stroke-width="0.02" stroke="#000000"></line>
+
+ <!-- Force vector -->
+ <line x1="5" :y1="1.2 - 0.05*mass+0.1" :x2="5+0.3*force" :y2="1.2 - 0.05*mass+0.1" stroke-width="0.1" stroke="#808080"></line>
+ <path v-show="force>0" :d="`M${5+0.3*force} ${1.3 - 0.05*mass+0.1} L${5.1+0.3*force} ${1.2 - 0.05*mass+0.1} L${5+0.3*force} ${1.1 - 0.05*mass+0.1} Z`" stroke="#808080" stroke-width="0.025" fill="#808080"/>
+ <path v-show="force<0" :d="`M${5+0.3*force} ${1.3 - 0.05*mass+0.1} L${4.9+0.3*force} ${1.2 - 0.05*mass+0.1} L${5+0.3*force} ${1.1 - 0.05*mass+0.1} Z`" stroke="#808080" stroke-width="0.025" fill="#808080"/>
+
+ <!-- Object -->
+ <circle cx="5" :cy="1.2 - 0.05*mass+0.1" :r="0.05*mass+0.1" fill="#ff0000"></circle>
+ </svg>
+ </div>
+
+ <div id="data" hidden>
+ <label><b>Time:</b> {{ time.toFixed(2) }} s</label>
+ <label><b>Position:</b> {{ position.toFixed(2) }} m</label>
+ <label><b>Velocity:</b> {{ velocity.toFixed(2) }} m/s</label>
+ <label><b>Acceleration:</b> {{ acceleration.toFixed(2) }} m/s<sup>2</sup></label>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/simulations/horizontal-motion.js b/simulations/horizontal-motion.js
@@ -0,0 +1,82 @@
+const App = {
+ data: function() {
+ return {
+ mass: 5, // The object's mass (Kg)
+ initialVelocity: 1, // The object's initial velocity (m/s)
+ force: 0, // The force acting on the object (N)
+ time: 0, // The time (s)
+ active: false, // Whether the simulation is active
+ refreshRate: 0.01, // The simulation refresh rate (s)
+ intervalId: null, // The value returned by setInterval
+ }
+ },
+ computed: {
+ /**
+ * The acceleration of the object
+ */
+ acceleration: function() {
+ return this.force / this.mass;
+ },
+
+ /**
+ * The velocity of the object
+ */
+ velocity: function() {
+ return this.initialVelocity + (this.acceleration * this.time);
+ },
+
+ /**
+ * The position of the object
+ */
+ position: function() {
+ return (this.initialVelocity * this.time) + (0.5 * this.acceleration * this.time * this.time);
+ },
+
+ /**
+ * The position of reference frame indicators
+ */
+ references: function() {
+ return [
+ (-1 * this.position) % 1, // 1m
+ (-1 * this.position) % 0.1, // 0.1m
+ ];
+ },
+ },
+ methods: {
+ /**
+ * Toggle whether the simulation is active
+ */
+ toggle: function() {
+ this.active = !this.active;
+ if (this.active) this.intervalID = setInterval(this.update, this.refreshRate * 1000);
+ else clearInterval(this.intervalID);
+ },
+
+ /**
+ * Reset the simulation
+ */
+ reset: function() {
+ this.time = 0;
+ },
+
+ /**
+ * Update the simulation output
+ */
+ update: function() {
+ this.time += this.refreshRate;
+ },
+ },
+}
+
+
+
+// Create Vue app
+function createApp() {
+ // Create app
+ Vue.createApp(App).mount("#app");
+
+ // Unhide app divs
+ document.getElementById("input").hidden = false;
+ document.getElementById("output").hidden = false;
+ document.getElementById("data").hidden = false;
+}