Skip to content

Instantly share code, notes, and snippets.

@lilgreenland
Last active September 11, 2017 02:59
Show Gist options
  • Save lilgreenland/56811b37617a584bab5dc48189dbb174 to your computer and use it in GitHub Desktop.
Save lilgreenland/56811b37617a584bab5dc48189dbb174 to your computer and use it in GitHub Desktop.
2-D ballistics calculator (vue.js)
<!--
https://vuejs.org/
https://github.com/NightCatSama/vue-slider-component
https://nightcatsama.github.io/vue-slider-component/example/#demo3
https://vuejs.org/v2/guide/components.html
-->
<div id="values">
<table>
<tr>
<td colspan="2">
<div>
<vue-slider v-model="t" v-on:input="calcT" event-type="auto" width="auto" :height="6" :dot-size="20" :min="-5" :max="30" :interval="0.1"></vue-slider>
</div>
<div class='center'>Δt = <input v-on:input="calcT" v-model.number="t" type="number"> s</div>
</td>
</tr>
<!-- <tr>
<td>
horizontal
</td>
<td>
vertical
</td>
</tr> -->
<tr>
<td>
<!-- Δx = <input v-on:input="calcX" v-model.number="x" type="number"> m -->
↔ Δx = {{x}} m
</td>
<td>
<!-- Δy = <input v-on:input="calc" v-model.number="y" type="number"> m -->
↕ Δy = {{y}} m
</td>
</tr>
<tr>
<td class = 'cyan'>
↔ u = <input v-on:input="calcX" v-model.number="ux" type="number"> m/s
</td>
<td class = 'pink'>
↕ u = <input v-on:input="calc" v-model.number="uy" type="number"> m/s
</td>
</tr>
<tr>
<td class = 'cyan'>↔ v = {{vx}} m/s</td>
<td class = 'pink'>↕ v = {{vy}} m/s</td>
</tr>
<tr>
<td >
↔ a = <input v-on:input="calcX" v-model.number="ax" type="number"> m/s²
</td>
<td>
↕ a = <input v-on:input="calc" v-model.number="ay" type="number"> m/s²
</td>
</tr>
</table>
</div>
<svg id='plot' class='graph' width="600" height="400" xmlns="http://www.w3.org/2000/svg">
<!-- acceleration vectors -->
<text text-anchor="middle" alignment-baseline="middle" x="550" y="40" font-size='20px' fill ='#bbb'>a</text>
<polygon id = 'a' transform='translate(200 100) rotate(0)' points="2,0 -6,4 -6,-4" fill = "#bbb" />
<line id = 'a_line' x1="550" y1="50" x2="0" y2="0" stroke = "#bbb" stroke-width ="2"/>
<!-- initial velocity vectors-->
<line id = 'v_ux' x1="50" y1="200" x2="0" y2="200" stroke = "rgba(150,220,220,0.8)" stroke-width ="5"/>
<line id = 'v_uy' x1="50" y1="200" x2="50" y2="0" stroke = "rgba(250,150,150,0.7)" stroke-width ="5"/>
<!-- final velocity vectors-->
<line id = 'v_vx' x1="0" y1="0" x2="0" y2="0" stroke = "rgba(150,220,220,0.8)" stroke-width ="5"/>
<line id = 'v_vy' x1="0" y1="0" x2="0" y2="0" stroke = "rgba(250,150,150,0.7)" stroke-width ="5"/>
<!-- trajectory -->
<path id ='b-path-full' d="" stroke="#888" stroke-width="1" fill = 'none' stroke-linejoin="round" stroke-linecap="round"/>
<path id ='b-path' d="" stroke="#000" stroke-width="2" fill = 'none' stroke-linejoin="round" stroke-linecap="round"/>
<circle id ='b_path_start' cx="50" cy="200" r="5" fill ='#000' OPACITY = '0.6'/>
<circle id ='b_path_end' cx="100" cy="100" r="5" fill ='#000' OPACITY = '0.6'/>
<!-- v-bind:style="{cx: cxEnd}" -->
<!-- axis -->
<path d="M0 200 h600 M50 0 v1000" stroke="#888" stroke-width="1" fill = 'none' stroke-dasharray="5, 5"/>
</svg>
let round = function(input) {
return Math.round(input * 100) / 100;
};
Vue.component(
"vueSlider",
{
// options
}
);
var ballistic1 = new Vue({
el: "#values",
components: {
vueSlider: window["vue-slider-component"]
},
data: {
t: 0,
x: 0,
ux: 30,
vx: 0,
ax: 0,
y: 0,
uy: 30,
vy: 0,
ay: -9.8,
value: 10
},
methods: {
calc: function() {
// if (this.ay > 0) this.ay = 0;
this.vy = round(-Math.sqrt(this.uy * this.uy + 2 * this.ay * this.y));
this.t = round((this.vy - this.uy) / this.ay);
this.x = round(this.t * this.ux + this.ax * this.t * this.t / 2);
this.vx = round(this.ux + this.ax * this.t);
this.drawSVG();
},
calcX: function() {
this.vx = round(Math.sqrt(this.ux * this.ux + 2 * this.ax * this.x));
this.t = round(2 * this.x / (this.vx + this.ux));
this.y = round(this.t * this.uy + this.ay * this.t * this.t / 2);
this.vy = round(-Math.sqrt(this.uy * this.uy + 2 * this.ay * this.y));
// document.getElementById("plot").style.visibility = hidden
this.drawSVG();
},
calcT: function() {
//x side
this.x = round(this.ux * this.t + 0.5 * this.ax * this.t * this.t);
this.vx = round(this.ux + this.ax * this.t);
//y side
this.y = round(this.uy * this.t + 0.5 * this.ay * this.t * this.t);
this.vy = round(this.uy + this.ay * this.t);
this.drawSVG();
},
drawSVG: function() {
const xOff = 50;
const yOff = 200;
const SCALE = 2;
//set path of projectile
let d = " M" + (xOff + this.ux * -100 + 0.5 * this.ax * -100 * -100) * SCALE + " " + (yOff - (this.uy * -100 + 0.5 * this.ay * -100 * -100)) * SCALE;
for (let t = -100, len = 1000; t < len; t += 0.2) {
d += " L" + (xOff + (this.ux * t + 0.5 * this.ax * t * t) * SCALE) + " " + (yOff - (this.uy * t + 0.5 * this.ay * t * t) * SCALE);
}
document.getElementById("b-path-full").setAttribute("d", d);
//partial path
d = " M" + xOff + " " + yOff;
for (let t = 0, len = this.t; t < len; t += 0.01) {
d += " L" + (xOff + (this.ux * t + 0.5 * this.ax * t * t) * SCALE) + " " + (yOff - (this.uy * t + 0.5 * this.ay * t * t) * SCALE);
}
document.getElementById("b-path").setAttribute("d", d);
//move circle to end of trajectory
if (!isNaN(this.x) && !isNaN(this.y)) {
document.getElementById("b_path_end").style.display = "inline";
document.getElementById("b_path_end").setAttribute("cx", xOff + this.x * SCALE);
document.getElementById("b_path_end").setAttribute("cy", yOff - this.y * SCALE);
} else {
document.getElementById("b_path_end").style.display = "none";
}
//change initial velocity vectors
document.getElementById("v_ux").setAttribute("x2", xOff + this.ux * 2);
document.getElementById("v_uy").setAttribute("y2", yOff - this.uy * 2);
//change final velocity vectors
document.getElementById("v_vx").setAttribute("x1", xOff + this.x * SCALE);
document.getElementById("v_vx").setAttribute("y1", yOff - this.y * SCALE);
document.getElementById("v_vx").setAttribute("y2", yOff - this.y * SCALE);
document.getElementById("v_vx").setAttribute("x2", xOff + this.x * SCALE + this.vx * 2);
document.getElementById("v_vy").setAttribute("x1", xOff + this.x * SCALE);
document.getElementById("v_vy").setAttribute("y1", yOff - this.y * SCALE);
document.getElementById("v_vy").setAttribute("x2", xOff + this.x * SCALE);
document.getElementById("v_vy").setAttribute("y2", yOff - this.y * SCALE - this.vy * 2);
//change acceleration vectors
const Vx = 550 + this.ax * 4;
const Vy = 50 - this.ay * 4;
document
.getElementById("a")
.setAttribute(
"transform",
`translate(${Vx} ${Vy}) rotate(${Math.atan2(-this.ay, this.ax) *
180 /
Math.PI} )`
);
document.getElementById("a_line").setAttribute("x2", Vx);
document.getElementById("a_line").setAttribute("y2", Vy);
//hide arrow if vector is small
if (this.ax * this.ax + this.ay * this.ay < 1) {
document.getElementById("a").style.display = "none";
} else {
document.getElementById("a").style.display = "inline";
}
}
}
});
ballistic1.calc();
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/464612/vueslider.js"></script>
body {
font-family: "Arial", sans-serif;
margin: 0 auto;
max-width: 600px;
font-size: 150%;
}
input {
font-size: 100%;
width: 80px;
background: #eee;
border: 10px;
margin: 0.2em;
}
input:focus {
outline: 0;
}
.graph {
margin 0;
padding 0;
border: 1px solid #ccc;
}
.center {
text-align: center;
padding: 0;
margin: auto;
display: block;
}
table {
margin: 25px 0px -1px 0px;
padding 0;
border-collapse: collapse;
border: 1px solid #ccc;
/*border-bottom: 2px solid #222;*/
width: 602px;
}
table th, table td {
color: #555;
border: 1px solid #ccc;
padding: 12px 20px;
border-collapse: collapse;
}
table th {
background: #444;
color: #fff;
text-transform: uppercase;
font-size: 0.85em;
}
table th.last {
border-right: none;
}
.pink {
background-color: #fffbff;
/* border-left: 2px solid rgba(250,150,150,0.7); */
border-right: 2px solid #fbb;
border-bottom: 2px solid #fbb;
border-top: 2px solid #fbb;
}
.cyan {
background-color: #fbffff;
border-left: 2px solid #bdd;
/* border-right: 2px solid rgba(150,220,220,0.8); */
border-bottom: 2px solid #bdd;
border-top: 2px solid #bdd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment