149 lines
3.5 KiB
Vue
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>
|