Appearance
Projectile motion
This example combines interaction and animation to show the freefall trajectory of a launched object. Some regular, HTML <button>
s are used to start and stop the animation.
Code
vue
<script setup lang="ts">
import { Mafs, Point, Parametric, Vector, Polygon, MovablePoint, useStopwatch, useMovablePoint } from "mafs-vue"
import { computed, watch } from 'vue'
const xSpan = 1.75
const ySpan = 1.75
const initialVelocity = useMovablePoint([0.5, 1.5])
const vectorScale = 4
const g = 9.8
const xVelocity = computed(() => initialVelocity.point[0] * vectorScale)
const yVelocity = computed(() => initialVelocity.point[1] * vectorScale)
const timeOfFlight = computed(() => {
const velocityAngle = Math.atan(yVelocity.value / xVelocity.value)
const velocityMag = Math.sqrt(
xVelocity.value ** 2 + yVelocity.value ** 2
)
return Math.abs(2 * velocityMag * Math.sin(velocityAngle)) / g
})
function positionAtTime(t: number): [number, number] {
return [xVelocity.value * t, yVelocity.value * t - 0.5 * g * t ** 2]
}
const position = computed(() => positionAtTime(timeOfFlight.value))
const { time: t, start, stop } = useStopwatch({
endTime: timeOfFlight
})
watch([position], () => {
stop()
})
</script>
<template>
<div>
<Mafs :viewBox="{ x: [1 - xSpan, 1 + xSpan], y: [1 - ySpan, 1 + ySpan] }">
<Polygon :points="[
[-100, 0],
[100, 0],
[100, -100],
[-100, -100],
]" :filled="{ color: 'green' }" />
<Vector :tip="[
xVelocity / vectorScale,
yVelocity / vectorScale]" />
<Parametric v-if="yVelocity > 0" :xy="positionAtTime" :t="[0, timeOfFlight]"
:stroked="{ opacity: 0.4, strokeStyle: 'dashed' }" />
<Point v-if="yVelocity > 0" :x="position[0]" :y="position[1]" :opacity="0.5" />
<Point :x="positionAtTime(t)[0]" :y="positionAtTime(t)[1]" />
<text :x="10" :y="30" :fontSize="20" className="transform-to-center" fill="white">
t = {{ t.toFixed(2) }}/{{ yVelocity > 0 ? timeOfFlight.toFixed(2) : "—" }}{{ " " }}
seconds
</text>
<MovablePoint :ctx="initialVelocity" />
</Mafs>
<div class="group">
<button class="btn" @click="start" :disabled="yVelocity <= 0">
Start
</button>
<button class="btn" @click="stop">
Reset
</button>
</div>
</div>
</template>
<style scoped>
.group {
padding: 1rem;
background-color: black;
border-color: #0f172a;
}
.btn {
border-radius: 0.125rem;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
margin-left: 0.5rem;
margin-right: 0.5rem;
background-color: #e5e7eb;
font-weight: 700;
color: black;
}
</style>