Files
geo/apps/ops-web/src/components/login-animation/Pupil.vue
T

39 lines
1.3 KiB
Vue
Raw Normal View History

<template>
<div ref="pupilRef" class="pupil" :style="{
width: size + 'px', height: size + 'px',
backgroundColor: pupilColor,
transform: `translate(${pos.x}px, ${pos.y}px)`,
}" />
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
const props = withDefaults(defineProps<{
size?: number; maxDistance?: number; pupilColor?: string
forceLookX?: number; forceLookY?: number
}>(), { size: 12, maxDistance: 5, pupilColor: 'black' })
const mx = ref(0), my = ref(0)
const pupilRef = ref<HTMLDivElement>()
const onMove = (e: MouseEvent) => { mx.value = e.clientX; my.value = e.clientY }
onMounted(() => window.addEventListener('mousemove', onMove))
onUnmounted(() => window.removeEventListener('mousemove', onMove))
const pos = computed(() => {
if (!pupilRef.value) return { x: 0, y: 0 }
if (props.forceLookX !== undefined && props.forceLookY !== undefined)
return { x: props.forceLookX, y: props.forceLookY }
const r = pupilRef.value.getBoundingClientRect()
const dx = mx.value - (r.left + r.width / 2)
const dy = my.value - (r.top + r.height / 2)
const d = Math.min(Math.sqrt(dx ** 2 + dy ** 2), props.maxDistance)
const a = Math.atan2(dy, dx)
return { x: Math.cos(a) * d, y: Math.sin(a) * d }
})
</script>
<style scoped>
.pupil { border-radius: 50%; transition: transform 0.1s ease-out; }
</style>