multi cards
This commit is contained in:
@@ -6,10 +6,13 @@
|
||||
<b v-else>normal</b>
|
||||
</button>
|
||||
<button @click="Rewind">
|
||||
rewind
|
||||
Rewind
|
||||
</button>
|
||||
<button @click="Wind">
|
||||
Wind
|
||||
</button>
|
||||
<!-- <div>{{ progressPercentage }}</div> -->
|
||||
<div>{{ currentSpeed }}</div>
|
||||
<div>{{ (currentSpeed).toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="disc" ref="discRef" id="disc">
|
||||
<div class="bobine" :style="{
|
||||
@@ -31,6 +34,7 @@ import type { Card } from '~~/types/types'
|
||||
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from 'vue'
|
||||
import Disc from '~/utils/platine/disc'
|
||||
import Sampler from '~/utils/platine/sampler'
|
||||
import { duration } from 'drizzle-orm/gel-core';
|
||||
|
||||
const props = defineProps<{ card?: Card, autoplay?: boolean }>()
|
||||
const autoplay = props.autoplay ?? false
|
||||
@@ -184,9 +188,97 @@ const Reverse = () => {
|
||||
|
||||
const Rewind = async () => {
|
||||
if (!disc.value || !sampler.value) return
|
||||
Reverse()
|
||||
play()
|
||||
|
||||
// Sauvegarder l'état actuel
|
||||
disc.value.isStopped() ? play() : null
|
||||
const wasPlaying = !disc.value.isStopped()
|
||||
const currentSpeed = disc.value.playbackSpeed
|
||||
|
||||
// Fonction pour l'effet de scratch/pull up
|
||||
const scratchEffect = async () => {
|
||||
// Ralentir progressivement
|
||||
const slowDownDuration = 300 // ms
|
||||
const startTime = performance.now()
|
||||
const startSpeed = wasPlaying ? currentSpeed : 0.1
|
||||
|
||||
const slowDown = (timestamp: number) => {
|
||||
const elapsed = timestamp - startTime
|
||||
const progress = Math.min(elapsed / slowDownDuration, 1)
|
||||
|
||||
// Courbe d'accélération pour un effet plus naturel
|
||||
const easeOut = 1 - Math.pow(1 - progress, 2)
|
||||
|
||||
// Ralentir progressivement jusqu'à presque l'arrêt
|
||||
const newSpeed = startSpeed * (1 - easeOut) + 0.05
|
||||
sampler.value?.setPlaybackRate(newSpeed)
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(slowDown)
|
||||
} else {
|
||||
// Une fois ralenti, effectuer le rembobinage
|
||||
performRewind()
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(slowDown)
|
||||
}
|
||||
|
||||
const performRewind = () => {
|
||||
// Mettre en pause la lecture actuelle
|
||||
if (wasPlaying) {
|
||||
sampler.value?.pause()
|
||||
}
|
||||
|
||||
// Remettre à zéro la position
|
||||
sampler.value?.play(0)
|
||||
disc.value?.setAngle(0)
|
||||
|
||||
// Effet de scratch rapide
|
||||
const scratchDuration = 200 // ms
|
||||
const scratchStart = performance.now()
|
||||
|
||||
const scratch = (timestamp: number) => {
|
||||
const elapsed = timestamp - scratchStart
|
||||
const progress = Math.min(elapsed / scratchDuration, 1)
|
||||
|
||||
// Créer un effet de scratch en variant la vitesse
|
||||
if (progress < 0.5) {
|
||||
// Phase de scratch vers l'arrière
|
||||
const scratchProgress = progress * 2
|
||||
const scratchSpeed = 1 - (scratchProgress * 1.8) // Ralenti jusqu'à -0.8
|
||||
sampler.value?.setPlaybackRate(scratchSpeed)
|
||||
} else {
|
||||
// Phase de pull up
|
||||
const pullProgress = (progress - 0.5) * 2
|
||||
const pullSpeed = -0.8 + (pullProgress * 1.8) // Accélère de -0.8 à 1.0
|
||||
sampler.value?.setPlaybackRate(pullSpeed)
|
||||
}
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(scratch)
|
||||
} else {
|
||||
// Remettre la vitesse normale à la fin
|
||||
sampler.value?.setPlaybackRate(1)
|
||||
|
||||
// Si c'était en lecture avant, relancer la lecture
|
||||
if (wasPlaying) {
|
||||
setTimeout(() => {
|
||||
sampler.value?.play(0)
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(scratch)
|
||||
}
|
||||
|
||||
// Démarrer l'effet
|
||||
scratchEffect()
|
||||
}
|
||||
|
||||
const Wind = () => {
|
||||
disc.value.secondsPlayed = duration
|
||||
sampler.value.secondsPlayed = duration
|
||||
}
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
@@ -237,7 +329,7 @@ watch(() => props.card, (newCard) => {
|
||||
|
||||
.disc {
|
||||
pointer-events: auto;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
|
||||
85
app/components/PlayingCard.vue
Normal file
85
app/components/PlayingCard.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<section class="playing-card" :class="{ 'playing-card--platine-open': platineOpen }">
|
||||
<Card :card="props.card!" :is-face-up="props.isFaceUp" @click="clickOnCard" :role="platineOpen ? 'img' : 'button'"
|
||||
showPlayButtonFaceUp />
|
||||
<Platine v-if="platineOpen && card" :card="card" autoplay />
|
||||
<CloseButton v-if="platineOpen" @click="platineOpen = false" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Card } from '~~/types/types'
|
||||
|
||||
const props = defineProps<{ card: Card, isFaceUp: boolean }>()
|
||||
|
||||
const platineOpen = ref(false)
|
||||
|
||||
const clickOnCard = () => {
|
||||
platineOpen.value = !platineOpen.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$open-speed: 0.4s;
|
||||
|
||||
.playing-card {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
:deep(.card) {
|
||||
transition: width $open-speed, height $open-speed, transform 0.1s;
|
||||
position: absolute;
|
||||
|
||||
.face-up,
|
||||
.pochette {
|
||||
transition: border-radius $open-speed, box-shadow $open-speed;
|
||||
|
||||
&:active {
|
||||
.play-button {
|
||||
@apply scale-90;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--platine-open {
|
||||
.card {
|
||||
pointer-events: none;
|
||||
|
||||
&:focus {
|
||||
@apply z-auto scale-100;
|
||||
}
|
||||
}
|
||||
|
||||
.card,
|
||||
.platine {
|
||||
width: 100vmin;
|
||||
height: 100vmin;
|
||||
}
|
||||
|
||||
&:deep(.card) {
|
||||
.face-up {
|
||||
border-radius: 999px;
|
||||
@apply shadow-xl;
|
||||
|
||||
.pochette {
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.rank,
|
||||
.play-button {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.play-button,
|
||||
.card-body,
|
||||
.face-down {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user