ldc-showroom/components/ChickenRun.vue
Jérémy Munsch 65dd624c09
Add animation
2024-02-02 10:34:55 +01:00

149 lines
3.5 KiB
Vue

<template>
<div
ref="container"
:class="{
'chicken-run position-absolute top-0 left-0 h-100 w-100': true,
'd-none': !runAnimation.runAnimation
}"
>
<div ref="chickenA">
<img
v-for="(i) of data.chickenMultiplier"
:key="i"
src="assets/pictures/chicken_run/chicken1.png"
alt="Poulet 1"
class="img-fluid chicken"
>
</div>
<div ref="chickenB">
<img
v-for="(i) of data.chickenMultiplier"
:key="i"
src="assets/pictures/chicken_run/chicken2.png"
alt="Poulet 2"
class="img-fluid chicken"
>
</div>
<div ref="chickenC">
<img
v-for="(i) of data.chickenMultiplier"
:key="i"
src="assets/pictures/chicken_run/chicken3.png"
alt="Poulet 3"
class="img-fluid chicken"
>
</div>
</div>
</template>
<script setup lang="ts">
function makeNewPosition() {
const containerRect = container.value!.getBoundingClientRect();
// Get viewport dimensions (remove the dimension of the div)
const h = containerRect.height - 10;
const w = containerRect.width - 10;
const nh = Math.floor(Math.random() * h);
const nw = Math.floor(Math.random() * w);
return [nh, nw];
}
function animateDiv(target: HTMLElement) {
const newq = makeNewPosition();
const oldq = target.getBoundingClientRect();
const speed = calcSpeed([oldq.top, oldq.left], newq);
const promise = Promise.all([target.animate({
top: `${newq[0]}px`,
left: `${newq[1]}px`
}, speed).finished]);
if(runAnimation.runAnimation) {
promise.then(() => animateDiv(target));
} else {
data.runningAnimation = false;
}
}
function calcSpeed(prev: number[], next:number[]) {
const x = Math.abs(prev[1] - next[1]);
const y = Math.abs(prev[0] - next[0]);
const greatest = x > y ? x : y;
const speed = Math.ceil(greatest / data.speedModifier);
return speed;
}
function setRandomStartCoord(container: DOMRect, el: HTMLElement) {
el.style.setProperty("top", `${Math.floor(Math.random() * container.height)}px`);
el.style.setProperty("left", `${Math.floor(Math.random() * container.width)}px`);
}
function animateElements(elements: NodeListOf<ChildNode>) {
const containerRect = container.value!.getBoundingClientRect();
(Array.from(elements))
.filter((el) => el.nodeType !== Node.TEXT_NODE)
.forEach((el) => {
setRandomStartCoord(containerRect, el as HTMLElement);
animateDiv(el as HTMLElement);
});
}
const data = reactive<{
runningAnimation: boolean;
speedModifier: number;
chickenMultiplier: number;
}>({
runningAnimation: false,
speedModifier: 0.6,
chickenMultiplier: 1,
});
const runAnimation = defineProps({
runAnimation: {
type:Boolean,
required: true
}
});
const container = ref<HTMLDivElement>();
const chickenA = ref<HTMLDivElement>();
const chickenB = ref<HTMLDivElement>();
const chickenC = ref<HTMLDivElement>();
const animate = () => {
if(!data.runningAnimation) {
data.runningAnimation = true;
data.chickenMultiplier = Math.floor(Math.random() * 4) + 1;
nextTick(() => {
animateElements(chickenA.value!.childNodes);
animateElements(chickenB.value!.childNodes);
animateElements(chickenC.value!.childNodes);
});
}
};
if(runAnimation.runAnimation) {
animate();
}
watch(runAnimation, () => {
if (runAnimation.runAnimation) {
animate();
}
});
</script>
<style lang="scss">
.chicken-run {
.chicken {
width: 5vw;
height: auto;
position:fixed;
top: 5rem;
left: 5rem;
}
}
</style>