mirror of
https://github.com/ArthurDanjou/artsite.git
synced 2026-01-14 15:54:13 +01:00
Replaced nuxt-visitors module with a custom WebSocket implementation for location tracking. Removed redundant code and comments in `useVisitors` composable and introduced the `location.server` plugin to manage user location. Updated dependencies and configurations to reflect these changes, streamlining the approach.
141 lines
3.3 KiB
Vue
141 lines
3.3 KiB
Vue
<script lang="ts" setup>
|
|
import type { COBEOptions } from 'cobe'
|
|
import createGlobe from 'cobe'
|
|
import { useSpring } from 'vue-use-spring'
|
|
|
|
interface GlobeProps {
|
|
class?: string
|
|
config?: Partial<COBEOptions>
|
|
mass?: number
|
|
tension?: number
|
|
friction?: number
|
|
precision?: number
|
|
locations?: Array<{ latitude: number, longitude: number }>
|
|
myLocation?: { latitude: number, longitude: number }
|
|
}
|
|
|
|
const props = withDefaults(defineProps<GlobeProps>(), {
|
|
mass: 1,
|
|
tension: 280,
|
|
friction: 100,
|
|
precision: 0.001,
|
|
})
|
|
|
|
const DEFAULT_CONFIG: COBEOptions = {
|
|
width: 400,
|
|
height: 400,
|
|
onRender: () => {},
|
|
devicePixelRatio: 2,
|
|
phi: 0,
|
|
theta: 0.3,
|
|
dark: 0,
|
|
diffuse: 0.4,
|
|
mapSamples: 20000,
|
|
mapBrightness: 1,
|
|
baseColor: [0.8, 0.8, 0.8],
|
|
opacity: 0.7,
|
|
markerColor: [160 / 255, 160 / 255, 160 / 255],
|
|
glowColor: [1, 1, 1],
|
|
markers: [],
|
|
}
|
|
|
|
const globeCanvasRef = ref<HTMLCanvasElement>()
|
|
const phi = ref(0)
|
|
const width = ref(0)
|
|
const pointerInteracting = ref()
|
|
const pointerInteractionMovement = ref()
|
|
|
|
let globe: ReturnType<typeof createGlobe> | null = null
|
|
|
|
const spring = useSpring(
|
|
{
|
|
r: 0,
|
|
},
|
|
{
|
|
mass: props.mass,
|
|
tension: props.tension,
|
|
friction: props.friction,
|
|
precision: props.precision,
|
|
},
|
|
)
|
|
|
|
function updatePointerInteraction(clientX: number | null) {
|
|
if (clientX !== null) {
|
|
pointerInteracting.value = clientX - (pointerInteractionMovement.value ?? clientX)
|
|
}
|
|
else {
|
|
pointerInteracting.value = null
|
|
}
|
|
|
|
if (globeCanvasRef.value) {
|
|
globeCanvasRef.value.style.cursor = clientX ? 'grabbing' : 'grab'
|
|
}
|
|
}
|
|
|
|
function updateMovement(clientX: number) {
|
|
if (pointerInteracting.value !== null) {
|
|
const delta = clientX - (pointerInteracting.value ?? clientX)
|
|
pointerInteractionMovement.value = delta
|
|
spring.r = delta / 200
|
|
}
|
|
}
|
|
|
|
function onRender(state: Record<string, unknown>) {
|
|
if (!pointerInteracting.value) {
|
|
phi.value += 0.005
|
|
}
|
|
|
|
state.phi = phi.value + spring.r
|
|
state.width = width.value * 2
|
|
state.height = width.value * 2
|
|
state.markers = props.locations?.map(location => ({
|
|
location: [location.latitude, location.longitude],
|
|
size: props.myLocation?.latitude === location.latitude && props.myLocation?.longitude === location.longitude ? 0.1 : 0.05,
|
|
}))
|
|
}
|
|
|
|
function onResize() {
|
|
if (globeCanvasRef.value) {
|
|
width.value = globeCanvasRef.value.offsetWidth
|
|
}
|
|
}
|
|
|
|
function createGlobeOnMounted() {
|
|
const config = { ...DEFAULT_CONFIG, ...props.config }
|
|
|
|
globe = createGlobe(globeCanvasRef.value!, {
|
|
...config,
|
|
width: width.value,
|
|
height: width.value,
|
|
onRender,
|
|
})
|
|
}
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('resize', onResize)
|
|
onResize()
|
|
createGlobeOnMounted()
|
|
|
|
setTimeout(() => (globeCanvasRef.value!.style.opacity = '1'))
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
globe?.destroy()
|
|
window.removeEventListener('resize', onResize)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="props.class">
|
|
<canvas
|
|
ref="globeCanvasRef"
|
|
class="size-full opacity-0 transition-opacity duration-1000 ease-in-out [contain:layout_paint_size]"
|
|
@pointerdown="(e) => updatePointerInteraction(e.clientX)"
|
|
@pointerup="updatePointerInteraction(null)"
|
|
@pointerout="updatePointerInteraction(null)"
|
|
@mousemove="(e) => updateMovement(e.clientX)"
|
|
@touchmove="(e) => e.touches[0] && updateMovement(e.touches[0].clientX)"
|
|
/>
|
|
</div>
|
|
</template>
|