Commit 704c98c2 authored by Franca's avatar Franca
Browse files

feat: add confetti and improve layout for suitcase


Co-authored-by: satan's avatarSebastian Speitel <sebastian.speitel@outlook.de>
parent 0e3c1cfa
<template>
<div id="case">
<Lock v-model="pin" :dial-count="3" @enter="checkPin" :state="state" />
</div>
<div id="title">
<h1 class="text-center" v-if="state !== 'correct'">
Bitte L&ouml;sungsziffern eingeben!
......@@ -12,7 +15,7 @@
<p class="text-center">Hier wartet deine Belohnung auf dich:</p>
<p class="text-center">
<a
href="https://maps.world.fem-net.de/events/ewo2021w/gamenight/Bilder/Urkunde.pdf"
:href="`https://maps.world.fem-net.de/events/ewo2021w/gamenight/Bilder/${path}`"
>
<img src="diploma.png" alt="Diploma" width="100" />
</a>
......@@ -21,27 +24,17 @@
Alternativer Link zum Kopieren:
<br />
<a
href="https://maps.world.fem-net.de/events/ewo2021w/gamenight/Bilder/Urkunde.pdf"
:href="`https://maps.world.fem-net.de/events/ewo2021w/gamenight/Bilder/${path}`"
>
https://maps.world.fem-net.de/events/ewo2021w/gamenight/Bilder/Urkunde.pdf
Urkunde.pdf
</a>
</p>
</div>
</div>
<div>
<div class="centered-flex text-center">
<img
src="suitcase.png"
alt="Suitcase"
style="position: absolute; top: 30%"
/>
<div style="position: absolute; top: 50%">
<Lock v-model="pin" :dial-count="3" @enter="checkPin" :state="state" />
</div>
</div>
</div>
<Confetti v-if="state === 'correct'" />
</template>
<script lang="ts">
import { ref, unref, watchEffect } from "vue";
......@@ -70,6 +63,10 @@ function equals<T extends Uint16Array>(a: T, b: T): boolean {
<script setup lang="ts">
import Lock from "./components/Lock.vue";
import Confetti from "./components/Confetti.vue";
const path = "Urkunde.pdf";
const pin = ref<string>("");
const state = ref<"default" | "correct" | "incorrect">("default");
const correct = ref(false);
......
......@@ -8,6 +8,22 @@
body {
background-color: #292826;
color: #E3E3E3;
overflow-x: hidden;
}
#case{
position: absolute;
top: 0;
width: 100vw;
height: 100vh;
background-image: url(./suitcase.png);
background-repeat: no-repeat;
background-size: contain;
background-position: center;
display: grid;
justify-content: space-around;
align-content: space-evenly;
z-index: -1;
}
h1, h2 {
......
<template>
<canvas class="confetti" ref="canvas"></canvas>
</template>
<script setup lang="ts">
// From: https://www.codehim.com/animation-effects/javascript-confetti-explosion-effect/
import {ref,reactive,onMounted,computed,onUnmounted} from 'vue'
const canvas = ref<HTMLCanvasElement>(null)
const ctx = computed(() => canvas.value?.getContext('2d'))
const size = reactive({
x: 0,
y: 0,
});
let confetti = [];
const confettiCount = 300;
const gravity = 0.5;
const terminalVelocity = 5;
const drag = 0.075;
const colors = [
{ front: 'red', back: 'darkred' },
{ front: 'green', back: 'darkgreen' },
{ front: 'blue', back: 'darkblue' },
{ front: 'yellow', back: 'darkyellow' },
{ front: 'orange', back: 'darkorange' },
{ front: 'pink', back: 'darkpink' },
{ front: 'purple', back: 'darkpurple' },
{ front: 'turquoise', back: 'darkturquoise' }
];
const active = ref(false)
onMounted(()=>{
active.value = true
canvas.value.width = window.innerWidth;
canvas.value.height = window.innerHeight;
size.x = ctx.value.canvas.width / 2;
size.y = ctx.value.canvas.height / 2;
initConfetti();
render();
});
onUnmounted(()=>{
active.value = false
})
//-----------Functions--------------
function resizeCanvas() {
canvas.value.width = window.innerWidth;
canvas.value.height = window.innerHeight;
size.x = ctx.value.canvas.width / 2;
size.y = ctx.value.canvas.height / 2;
};
const randomRange = (min, max) => Math.random() * (max - min) + min;
const initConfetti = () => {
for (let i = 0; i < confettiCount; i++) {
confetti.push({
color: colors[Math.floor(randomRange(0, colors.length))],
dimensions: {
x: randomRange(10, 20),
y: randomRange(10, 30) },
position: {
x: randomRange(0, canvas.value.width),
y: canvas.value.height - 1 },
rotation: randomRange(0, 2 * Math.PI),
scale: {
x: 1,
y: 1 },
velocity: {
x: randomRange(-25, 25),
y: randomRange(0, -50) } });
}
};
//---------Render-----------
const render = () => {
if(!active.value) return
ctx.value.clearRect(0, 0, canvas.value.width, canvas.value.height);
confetti.forEach((confetto, index) => {
const width = confetto.dimensions.x * confetto.scale.x;
const height = confetto.dimensions.y * confetto.scale.y;
// Move canvas to position and rotate
ctx.value.translate(confetto.position.x, confetto.position.y);
ctx.value.rotate(confetto.rotation);
// Apply forces to velocity
confetto.velocity.x -= confetto.velocity.x * drag;
confetto.velocity.y = Math.min(confetto.velocity.y + gravity, terminalVelocity);
confetto.velocity.x += Math.random() > 0.5 ? Math.random() : -Math.random();
// Set position
confetto.position.x += confetto.velocity.x;
confetto.position.y += confetto.velocity.y;
// Delete confetti when out of frame
if (confetto.position.y >= canvas.value.height) confetti.splice(index, 1);
// Loop confetto x position
if (confetto.position.x > canvas.value.width) confetto.position.x = 0;
if (confetto.position.x < 0) confetto.position.x = canvas.value.width;
// Spin confetto by scaling y
confetto.scale.y = Math.cos(confetto.position.y * 0.1);
ctx.value.fillStyle = confetto.scale.y > 0 ? confetto.color.front : confetto.color.back;
// Draw confetti
ctx.value.fillRect(-width / 2, -height / 2, width, height);
// Reset transform matrix
ctx.value.setTransform(1, 0, 0, 1, 0, 0);
});
// Fire off another round of confetti
if (confetti.length <= 10) initConfetti();
window.requestAnimationFrame(render);
};
//---------Execution--------
//----------Resize----------
window.addEventListener('resize', resizeCanvas);
//------------Click------------
// window.addEventListener('click', initConfetti);
</script>
<style scoped>
.confetti {
position: absolute;
top:0;
width: 100vw;
height: 100vh;
/* max-width: 640px; */
display: block;
/* margin: 0 auto; */
user-select: none;
pointer-events: none;
z-index: 100;
}
</style>
\ No newline at end of file
<template>
<div class="myCenter">
<div id="lock" ref="lock" class="myLock" :class="state">
<div class="lockInset">
<div class="lockLine"></div>
<div class="lockWrapper">
<div class="dial" v-for="(digit, dial) in selection">
<ol
@click="dialMove(dial)"
@wheel="dialMove(dial, { change: Math.sign($event.deltaY) })"
>
<template v-for="d in generateDigits(digit)" :key="d">
<li v-text="d" />
</template>
</ol>
</div>
<div class="shadow"></div>
<div ref="lock" class="myLock" :class="state">
<div class="lockInset">
<div class="lockLine"></div>
<div class="lockWrapper">
<div class="dial" v-for="(digit, dial) in selection">
<ol
@click="dialMove(dial)"
@wheel="dialMove(dial, { change: Math.sign($event.deltaY) })"
>
<template v-for="d in generateDigits(digit)" :key="d">
<li v-text="d" />
</template>
</ol>
</div>
<div class="shadow"></div>
</div>
<div class="btnEnter button" @click="emits('enter', combo)">Enter</div>
</div>
<div class="btnEnter button" @click="emits('enter', combo)">Öffnen</div>
</div>
</template>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment