Files
housesof/src/components/organisms/InteractiveGlobe.svelte

130 lines
3.5 KiB
Svelte

<script lang="ts">
import { onMount, getContext } from 'svelte'
import { getPosition, getRandomElement } from '$utils/functions'
export let type: string = undefined
export let autoRotate: boolean = true
export let scrollSmooth: number = 0.5
export let opacity: number = 1
const { continents, locations } = getContext('global')
let globe: any
let Globe: any
let globeEl: HTMLElement
let windowHeight: number, windowWidth: number
let containerTop: number = 0, containerHeight: number = 0
let observer: IntersectionObserver
const randomContinent = getRandomElement(continents.filter(cont => cont.countries))
const globeResolution = windowWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'
const markers = locations.map(({ name, slug, country, coordinates: { coordinates }}: any) => ({
name,
slug,
countryName: country.name,
countrySlug: country.slug,
lat: coordinates[1],
lng: coordinates[0],
// className: location.close ? 'is-close' : '',
}))
/**
* Globe update
*/
const update = () => {
requestAnimationFrame(update)
globe.update()
}
/**
* When scrolling
*/
const handleScroll = () => {
let scrollDiff = (containerTop + windowHeight + (containerHeight - windowHeight) / 2) - document.documentElement.scrollTop
let scrollRatio = (1 - (scrollDiff / windowHeight)) * 2
if (globe) {
globe.updateCameraPos(scrollRatio, scrollDiff - windowHeight)
}
}
/**
* When resizing
*/
const handleResize = () => {
if (globeEl) {
containerTop = getPosition(globeEl).top
containerHeight = globeEl.clientHeight
}
if (globe) {
globe.resize()
globe.update()
}
handleScroll()
}
onMount(async () => {
// Load globe library
Globe = await import('$modules/globe')
// Instantiate globe
globe = new Globe.default({
el: globeEl,
//cameraDistance: size, // Smaller number == larger globe
autoRotationSpeed: autoRotate ? -0.0025 : 0,
rotationStart: randomContinent.rotation, // In degrees
scrollSmoothing: scrollSmooth,
opacity,
texture: `/images/globe-map-${globeResolution}.png`,
markers,
onLinkClicked: () => {}
})
// Observe the globe
observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
globe.enable()
} else {
globe.disable()
}
})
}, {
threshold: 0,
rootMargin: '0px 0px 0px'
})
observer.observe(globeEl)
// Run the globe
update()
handleResize()
// Destroy
return () => {
if (globe) {
globe.destroy()
observer.disconnect()
}
}
})
</script>
<svelte:window
bind:innerHeight={windowHeight}
bind:innerWidth={windowWidth}
on:scroll={handleScroll}
on:resize={handleResize}
/>
<section id="globe">
{#if type === 'cropped'}
<div class="globe--cropped">
<div class="globe" bind:this={globeEl} />
</div>
{:else}
<div class="globe" bind:this={globeEl} />
{/if}
</section>