Globe: Add more props settings, Randomly position globe to a continent

- Add a little delay before restarting the rotation when hovering a marker
This commit is contained in:
2020-04-19 16:49:10 +02:00
parent 4fb2c4e93a
commit 302af713d0
4 changed files with 44 additions and 29 deletions

View File

@@ -7,7 +7,7 @@ import { Container, Mesh, Material, Texture, SphereGeometryBuffer, PlaneGeometry
import GlobeVS from './globe-vs' import GlobeVS from './globe-vs'
import GlobeFS from './globe-fs' import GlobeFS from './globe-fs'
const FOV = 1;//camera Field of view; we use 1 to prevent strong perspective effect on the globe const FOV = 1 // Camera Field of view; we use 1 to prevent strong perspective effect on the globe
/** get 3D position on a sphere from longitute lattitude */ /** get 3D position on a sphere from longitute lattitude */
const lonLatToVector3 = (lng, lat) => { const lonLatToVector3 = (lng, lat) => {
@@ -19,9 +19,8 @@ const lonLatToVector3 = (lng, lat) => {
return [x,y,z] return [x,y,z]
} }
function degToRad(deg) { // Convert degrees to radians
return deg * Math.PI/180 const degToRad = deg => deg * Math.PI / 180
}
class WebglGlobe { class WebglGlobe {
@@ -162,9 +161,9 @@ class WebglGlobe {
let p = lonLatToVector3(markers[i].lng, markers[i].lat) let p = lonLatToVector3(markers[i].lng, markers[i].lat)
// Scale marker position to fit globe size // Scale marker position to fit globe size
p[0] *= this.referenceHeight/2; p[0] *= this.referenceHeight / 2
p[1] *= this.referenceHeight/2; p[1] *= this.referenceHeight / 2
p[2] *= this.referenceHeight/2; p[2] *= this.referenceHeight / 2
// Wrap marker in link // Wrap marker in link
let el = document.createElement('a') let el = document.createElement('a')
@@ -200,11 +199,15 @@ class WebglGlobe {
// Add class on hover // Add class on hover
el.addEventListener('mouseenter', () => { el.addEventListener('mouseenter', () => {
this._isHoverMarker = true
el.classList.add('hover') el.classList.add('hover')
// Stop globe rotation
this._isHoverMarker = true
// Clear timeout to be sure
clearTimeout(this.hoverTimeout)
}) })
el.addEventListener('mouseleave', () => { el.addEventListener('mouseleave', () => {
this._isHoverMarker = false // Restart rotation after a little delay
this.hoverTimeout = setTimeout(() => this._isHoverMarker = false, 400)
}) })
el.addEventListener('animationend', () => { el.addEventListener('animationend', () => {
el.classList.remove('hover') el.classList.remove('hover')
@@ -239,14 +242,14 @@ class WebglGlobe {
this.camera.updateProjectionMatrix() this.camera.updateProjectionMatrix()
// Distance to put the camera when rotating around the globe // Distance to put the camera when rotating around the globe
this.camera._cameraDistance = (this.referenceHeight * this.options.cameraDistance) / 2 / Math.tan(Math.PI * FOV / 360); this.camera._cameraDistance = (this.referenceHeight * this.options.cameraDistance) / 2 / Math.tan(Math.PI * FOV / 360)
this.camera.update(true) this.camera.update(true)
/** /**
* When markers are behind the globe, clamp their position * When markers are behind the globe, clamp their position
* to this size to make them move along the circle edge * to this size to make them move along the circle edge
*/ */
this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance); this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance)
} }
/** /**
@@ -254,7 +257,7 @@ class WebglGlobe {
* Instead, we move the globe vertex inside the vertex shadder after compute the project on screen, so we pass the 'scroll' position to a uniform * Instead, we move the globe vertex inside the vertex shadder after compute the project on screen, so we pass the 'scroll' position to a uniform
*/ */
updateCameraPos (y, scrollDiff) { updateCameraPos (y, scrollDiff) {
this.globeScrollOffset = y; this.globeScrollOffset = y
this.markersScrollOffset = scrollDiff this.markersScrollOffset = scrollDiff
// Avoid jump due to smoothing when setting it for first time as the inital values are 0 // Avoid jump due to smoothing when setting it for first time as the inital values are 0
@@ -267,7 +270,7 @@ class WebglGlobe {
} }
} }
// Destroy
destroy() { destroy() {
this.disable()//stop render loop this.disable()//stop render loop
document.body.removeChild( this.$markerWrapper ) document.body.removeChild( this.$markerWrapper )

View File

@@ -1,7 +1,7 @@
<script> <script>
import { onMount, onDestroy } from 'svelte' import { onMount, onDestroy } from 'svelte'
import { continents, locations } from 'utils/store' import { continents, locations } from 'utils/store'
import { getPosition } from 'utils/functions' import { getPosition, getRandomArrayItem } from 'utils/functions'
// Dependencies // Dependencies
import ScrollOut from 'scroll-out' import ScrollOut from 'scroll-out'
import Lazy from 'svelte-lazy' import Lazy from 'svelte-lazy'
@@ -9,10 +9,12 @@
// Props // Props
export let type = '' export let type = ''
export let size = 0.575 export let size = 0.575
export let autoRotate = true
let scope let scope
let globe let globe
let containerTop = 0 let containerTop = 0
let containerHeight = 0 let containerHeight = 0
$: randomRotationPosition = getRandomArrayItem($continents.filter(continent => continent.countries)).rotation_position
/* /*
@@ -42,23 +44,20 @@
} }
onDestroy(async ()=>{
globe && globe.destroy()
})
/* /*
** Run code when mounted ** Run code when mounted
*/ */
onMount(async () => { onMount(async () => {
let InteractiveGlobe
// Import libraries and code // Import libraries and code
let InteractiveGlobe
await import('globe/index').then(module => InteractiveGlobe = module.default) await import('globe/index').then(module => InteractiveGlobe = module.default)
// Init the globe from library // Init the globe from library
globe = new InteractiveGlobe({ globe = new InteractiveGlobe({
el: scope, el: scope,
cameraDistance: size, // Smaller number == larger globe cameraDistance: size, // Smaller number == larger globe
autoRotationSpeed: -0.0025, autoRotationSpeed: autoRotate ? -0.0025 : 0,
rotationStart: 90, //in degrees rotationStart: randomRotationPosition, // In degrees
scrollSmoothing: 0.5, scrollSmoothing: 0.5,
texture: `/img/globe/map-${window.innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'}.png`, texture: `/img/globe/map-${window.innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'}.png`,
markers: [ ...$locations.map(location => { markers: [ ...$locations.map(location => {
@@ -72,25 +71,29 @@
className: location.close ? 'is-close' : '', className: location.close ? 'is-close' : '',
} }
}) ], }) ],
centerPositions: [ ...$continents.map(continent => continent.countries) ],
onLinkClicked: () => { } onLinkClicked: () => { }
}) })
// Run the globe // Run the globe
onResize() onResize()
update() update()
onScroll()
// Enable the globe only when shown // Enable/Disable the globe when shown/hidden
const globeScroll = ScrollOut({ const globeScroll = ScrollOut({
once: false,
targets: scope, targets: scope,
onShown: () => { onShown: () => globe.enable(),
globe.enable()
onScroll()
},
onHidden: () => globe.disable() onHidden: () => globe.disable()
}) })
}) })
/*
** Destroy when unmounted
*/
onDestroy(() => {
globe && globe.destroy()
})
</script> </script>
<svelte:window on:resize={onResize} on:scroll={onScroll} /> <svelte:window on:resize={onResize} on:scroll={onScroll} />

View File

@@ -23,7 +23,7 @@
data { data {
id id
name name
coordinates rotation_position
} }
} }
countries { countries {

View File

@@ -87,6 +87,15 @@ export const randomString = (length = 6, type = 'A') => {
} }
/*
** Get random array item
*/
export const getRandomArrayItem = array => {
const randomIndex = Math.floor(Math.random() * array.length)
return array[randomIndex]
}
/* /*
** Date related ** Date related
*/ */