- Adds cleanup timer for globe arcs to prevent accumulation - Conditionally renders chart header when stats are available - Improves event handling in AnimatedList by passing props - Fixes traffic event animation by clearing previous timeouts These changes improve visualization performance and user experience by preventing memory leaks from accumulated arcs and ensuring smoother animations.
99 lines
2.1 KiB
Vue
99 lines
2.1 KiB
Vue
<script lang="ts" setup>
|
|
import { cn } from '@/lib/utils'
|
|
import { computed, onMounted, ref, useSlots } from 'vue'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
class?: string
|
|
delay?: number
|
|
}>(), {
|
|
delay: 1000,
|
|
})
|
|
|
|
const emit = defineEmits(['update:items'])
|
|
|
|
const slots = useSlots()
|
|
const index = ref(0)
|
|
const slotsArray = ref<any>([])
|
|
const maxShowItems = 100
|
|
|
|
const itemsToShow = computed(() => {
|
|
const start = index.value - maxShowItems < 0 ? 0 : index.value - maxShowItems
|
|
return slotsArray.value.slice(start, index.value)
|
|
})
|
|
|
|
watch([itemsToShow], () => {
|
|
emit('update:items', itemsToShow.value.at(-1), props)
|
|
})
|
|
|
|
async function loadComponents() {
|
|
slotsArray.value = slots.default ? slots.default()?.[0]?.children : []
|
|
|
|
while (index.value < slotsArray.value.length) {
|
|
index.value++
|
|
await delay(props.delay)
|
|
}
|
|
}
|
|
|
|
async function delay(ms: number) {
|
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
}
|
|
|
|
function getInitial(idx: number) {
|
|
return idx === index.value - 1
|
|
? {
|
|
scale: 0,
|
|
opacity: 0,
|
|
}
|
|
: undefined
|
|
}
|
|
function getEnter(idx: number) {
|
|
return idx === index.value - 1
|
|
? {
|
|
scale: 1,
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
type: 'spring',
|
|
stiffness: 250,
|
|
damping: 40,
|
|
},
|
|
}
|
|
: undefined
|
|
}
|
|
|
|
function getLeave() {
|
|
return {
|
|
scale: 0,
|
|
opacity: 0,
|
|
y: 0,
|
|
transition: {
|
|
type: 'spring',
|
|
stiffness: 350,
|
|
damping: 40,
|
|
},
|
|
}
|
|
};
|
|
|
|
onMounted(() => loadComponents())
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="cn('overflow-auto', $props.class)">
|
|
<transition-group name="list" tag="div" class="flex flex-col-reverse items-center p-2" move-class="move">
|
|
<div
|
|
v-for="(item, idx) in itemsToShow"
|
|
:key="item.props.key"
|
|
v-motion :initial="getInitial(idx)" :enter="getEnter(idx)" :leave="getLeave()"
|
|
:class="cn('mx-auto w-full')"
|
|
>
|
|
<component :is="item" />
|
|
</div>
|
|
</transition-group>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.move {
|
|
transition: transform 0.4s ease-out;
|
|
}
|
|
</style>
|