atwood-machine.js (4334B)
1 const App = { 2 data: function() { 3 return { 4 angle: 90, // The angle of the 2nd weight (degrees) 5 mass1: 1, // The mass of the 1st weight (Kg) 6 mass2: 10, // The mass of the 2nd weight (Kg) 7 gravity: 9.8, // The acceleration due to gravity (m/s/s) 8 time: 0, // The time (s) 9 active: false, // Whether the simulation is active 10 refreshRate: 0.01, // The simulation refresh rate (s) 11 intervalId: null, // The value returned by setInterval 12 infoVisible: false, 13 } 14 }, 15 computed: { 16 /** 17 * The net force on the 2nd weight 18 */ 19 netForce: function() { 20 let gravityX = this.getO(this.angle, this.mass2 * this.gravity); 21 let netX = (this.mass1 * this.gravity) - gravityX; 22 return netX; 23 }, 24 25 /** 26 * The acceleration of the 2nd weight 27 */ 28 acceleration: function() { 29 return this.netForce / (this.mass2 + this.mass1); 30 }, 31 32 /** 33 * The velocity of the 2nd weight 34 */ 35 velocity: function() { 36 return this.acceleration * this.time; 37 }, 38 39 /** 40 * The displacement of the 2nd weight 41 */ 42 displacement: function() { 43 let result = 0.5 * this.acceleration * this.time * this.time; 44 if (result > 3) result = 3; 45 if (result < -3) result = -3; 46 if (Math.abs(result) === 3 && this.active) this.toggle(); 47 return result; 48 }, 49 50 /** 51 * The position of the 2nd weight 52 */ 53 positionVector: function() { 54 let x1 = this.getA(this.angle - 90, 1); 55 let y1 = this.getO(this.angle - 90, 1); 56 let x2 = this.getA(this.angle, - this.displacement + 3) + x1; 57 let y2 = this.getO(this.angle, - this.displacement + 3) + y1; 58 return [x1, y1, x2, y2]; 59 }, 60 }, 61 methods: { 62 /** 63 * Handle a keyup event (implements keyboard shortcuts) 64 * @param {object} e - The event args 65 */ 66 keyup: function(e) { 67 if (e.key === "Escape") { 68 if (this.infoVisible) this.infoVisible = false; 69 else window.location.href = "../"; 70 } 71 }, 72 73 /** 74 * Toggle whether the simulation is active 75 */ 76 toggle: function() { 77 this.active = !this.active; 78 if (this.active) this.intervalID = setInterval(this.update, this.refreshRate * 1000); 79 else clearInterval(this.intervalID); 80 }, 81 82 /** 83 * Reset the simulation 84 */ 85 reset: function() { 86 this.time = 0; 87 }, 88 89 /** 90 * Update the simulation output 91 */ 92 update: function() { 93 this.time += this.refreshRate; 94 }, 95 96 /** 97 * Get the length of the opposite side of a triangle 98 * @param {Number} angle The angle in degrees 99 * @param {Number} distance The length of the hypotenuse 100 * @returns {Number} The length of the opposite side 101 */ 102 getO: function(angle, distance) { 103 return Math.sin(angle / 360 * 2 * Math.PI) * distance; 104 }, 105 106 /** 107 * Get the length of the adjacent side of a triangle 108 * @param {Number} angle The angle in degrees 109 * @param {Number} distance The length of the hypotenuse 110 * @returns {Number} The length of the adjacent side 111 */ 112 getA: function(angle, distance) { 113 return Math.cos(angle / 360 * 2 * Math.PI) * distance; 114 }, 115 }, 116 created: function() { 117 // Add keyup handler 118 window.addEventListener("keyup", this.keyup); 119 }, 120 destroyed: function() { 121 // Remove keyup handler 122 window.removeEventListener("keyup", this.keyup); 123 }, 124 } 125 126 127 128 // Create Vue app 129 function createApp() { 130 // Create app 131 Vue.createApp(App).mount("#app"); 132 133 // Unhide app divs 134 document.getElementById("input").hidden = false; 135 document.getElementById("output").hidden = false; 136 document.getElementById("data").hidden = false; 137 document.getElementById("info").hidden = false; 138 }