Files
housesof/src/components/organisms/InteractiveGlobe.svelte
Félix Péault cdabe6935b 🔥 Huge style refactoring by using SvelteKit built-in style tag
It's been tricky but got there finally! Hello `:global`
- Avoid using one global CSS file containing everything
- Import the component SCSS file in a script tag from the component file to allow style scoping and including it only when used
2022-06-22 23:26:00 +02:00

136 lines
3.7 KiB
Svelte

<style lang="scss">
@import "../../style/modules/globe";
</style>
<script lang="ts">
import { onMount, onDestroy, getContext } from 'svelte'
import { getPosition, getRandomItem } from '$utils/functions'
export let type: string = undefined
export let autoRotate: boolean = true
export let scrollSmooth: number = 0.5
export let opacity: number = 1
let globeEl: HTMLElement
let observer: IntersectionObserver
let globe: any
let innerWidth: number
let innerHeight: number
let containerTop = 0
let containerHeight = 0
$: globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'
const { continents, locations } = getContext('global')
const randomContinent: any = getRandomItem(continents.filter((cont: any) => cont.countries))
const markers = locations.map(({ name, slug, country, globe_close: isClose, coordinates: { coordinates }}: any) => ({
name,
slug,
countryName: country.name,
countrySlug: country.slug,
lat: coordinates[1],
lng: coordinates[0],
className: isClose ? 'is-close' : '',
}))
/*
** Functions
*/
// Globe update
const update = () => {
requestAnimationFrame(update)
globe.update()
}
// On scroll
const handleScroll = () => {
let scrollDiff = (containerTop + innerHeight + (containerHeight - innerHeight) / 2) - document.documentElement.scrollTop
let scrollRatio = (1 - (scrollDiff / innerHeight)) * 2
if (globe) {
globe.updateCameraPos(scrollRatio, scrollDiff - innerHeight)
}
}
// On resize
const handleResize = () => {
if (globeEl) {
containerTop = getPosition(globeEl).top
containerHeight = globeEl.clientHeight
}
if (globe) {
globe.resize()
globe.update()
}
handleScroll()
}
/*
** Run code when mounted
*/
onMount(async () => {
// Import libraries and code
const { default: InteractiveGlobe } = await import('$modules/globe')
// Init the globe from library
globe = new InteractiveGlobe({
el: globeEl,
//cameraDistance: size, // Smaller number == larger globe
autoRotationSpeed: autoRotate ? -0.0025 : 0,
rotationStart: randomContinent.rotation, // In degrees
scrollSmoothing: scrollSmooth,
opacity: opacity,
texture: `/images/globe-map-${globeResolution}.png`,
markers,
onLinkClicked: () => {}
})
// Run the globe
update()
handleResize()
// Enable/Disable the globe when shown/hidden
observer = new IntersectionObserver(entries => {
entries.forEach(({ isIntersecting }: IntersectionObserverEntry) => {
if (isIntersecting) {
globe.enable()
console.log('globe: IO enable')
} else {
globe.disable()
console.log('globe: IO disable')
}
})
}, {
threshold: 0,
rootMargin: '0px 0px 0px'
})
observer.observe(globeEl)
})
/*
** Destroy when unmounted
*/
onDestroy(() => {
globe && globe.destroy()
})
</script>
<svelte:window
on:scroll={handleScroll}
on:resize={handleResize}
bind:innerHeight
bind:innerWidth
/>
<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>