Add animation

This commit is contained in:
Jérémy Munsch 2024-02-02 10:34:55 +01:00
parent 7720230013
commit 65dd624c09
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
5 changed files with 164 additions and 2 deletions

17
app.vue
View file

@ -21,13 +21,14 @@
<template v-else>
{{ t('loading') }}
</template>
<ChickenRun :run-animation="chickenRun" />
</div>
</template>
<script lang="ts">
// import Modal from "bootstrap/js/dist/modal";
// import KonamiCode from "konami-code-js";
import KonamiCode from "konami-code-js";
// import Swal from "sweetalert2";
import { defineComponent } from "vue";
import type { RouteLocationNormalizedLoaded } from "vue-router";
@ -43,13 +44,17 @@ export default defineComponent({
route: RouteLocationNormalizedLoaded;
activeBrand: TypeBrand|null;
activeRange: TypeRange|null;
chickenRun: boolean;
konami: KonamiCode|null;
} {
return {
timeout: undefined,
loading: true,
route: useRoute(),
activeBrand: null,
activeRange: null
activeRange: null,
chickenRun: false,
konami: null,
};
},
computed: {
@ -80,6 +85,14 @@ export default defineComponent({
dataJson.fonts.forEach(font => this.injectFontFace(font.font_name, font.font));
});
},
mounted() {
this.konami = new KonamiCode(() => {
this.$nextTick(() => {
this.chickenRun = true;
setTimeout(() => {this.chickenRun = false;}, 12000);
});
});
},
beforeUnmount() {
clearTimeout(this.timeout);
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

149
components/ChickenRun.vue Normal file
View file

@ -0,0 +1,149 @@
<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>