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:
@@ -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 )
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
data {
|
data {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
coordinates
|
rotation_position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
countries {
|
countries {
|
||||||
|
|||||||
@@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user