- Added visible continents to options
This commit is contained in:
@@ -23,17 +23,15 @@ class WebglGlobe {
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
|
this.$el = options.el // The DOM reference node
|
||||||
this.$el = options.el//the Dom reference node
|
|
||||||
this.options = options
|
this.options = options
|
||||||
this.options.autoRotationSpeed = this.options.autoRotationSpeed || 0
|
this.options.autoRotationSpeed = this.options.autoRotationSpeed || 0
|
||||||
this.options.scrollSmoothing = this.options.scrollSmoothing || 0.5 // smooth the globe position to avoid janks on scroll(lower==smoother)
|
this.options.scrollSmoothing = this.options.scrollSmoothing || 0.5 // Smooth the globe position to avoid janks on scroll (lower == smoother)
|
||||||
this.options.cameraDistance = this.options.cameraDistance || 1 //a multiplier to move camera backward or forward
|
this.options.cameraDistance = this.options.cameraDistance || 1 // A multiplier to move camera backward or forward
|
||||||
this.cities = options.markers//list of cities with their options
|
this.cities = options.markers // List of cities with their options
|
||||||
|
|
||||||
this._canUpdate = false
|
this._canUpdate = false
|
||||||
this.hasUpdateCameraPos = false
|
this.hasUpdateCameraPos = false
|
||||||
this.referenceHeight = 1;//used to set camera distance from globe where referenceHeight == window height
|
this.referenceHeight = 1 // Used to set camera distance from globe where referenceHeight == window height
|
||||||
this.currMarkerScrollOffset = 0
|
this.currMarkerScrollOffset = 0
|
||||||
this.markersScrollOffset = 0
|
this.markersScrollOffset = 0
|
||||||
this.globeScrollOffset = 0
|
this.globeScrollOffset = 0
|
||||||
@@ -54,11 +52,10 @@ class WebglGlobe {
|
|||||||
|
|
||||||
// Build
|
// Build
|
||||||
buildWebglScene () {
|
buildWebglScene () {
|
||||||
|
|
||||||
this.renderer = new Renderer({
|
this.renderer = new Renderer({
|
||||||
//to allow transparent background on webgl canvas
|
// To allow transparent background on webgl canvas
|
||||||
alpha: true,
|
alpha: true,
|
||||||
//only enable antialiasing if screen is small with no retina(for performances reasons)
|
// Enable antialiasing only if screen is small with no retina (for performances reasons)
|
||||||
antialias: window.innerWidth < 768 || window.devicePixelRatio == 1 ? true : false,
|
antialias: window.innerWidth < 768 || window.devicePixelRatio == 1 ? true : false,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -75,7 +72,7 @@ class WebglGlobe {
|
|||||||
// The markers DOM nodes wrapper
|
// The markers DOM nodes wrapper
|
||||||
// this wrapper is added just next to the canvas, at the end of body tag
|
// this wrapper is added just next to the canvas, at the end of body tag
|
||||||
this.$markerWrapper = document.createElement('div')
|
this.$markerWrapper = document.createElement('div')
|
||||||
this.$markerWrapper.classList.add('markerWrapper')
|
this.$markerWrapper.classList.add('globe__markers')
|
||||||
this.$markerWrapper.style.position = 'fixed'
|
this.$markerWrapper.style.position = 'fixed'
|
||||||
this.$markerWrapper.style.top = 0
|
this.$markerWrapper.style.top = 0
|
||||||
this.$markerWrapper.style.left = 0
|
this.$markerWrapper.style.left = 0
|
||||||
@@ -157,7 +154,7 @@ class WebglGlobe {
|
|||||||
// Position marker
|
// Position marker
|
||||||
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;
|
||||||
@@ -211,7 +208,6 @@ class WebglGlobe {
|
|||||||
|
|
||||||
// Resize method
|
// Resize method
|
||||||
resize () {
|
resize () {
|
||||||
|
|
||||||
if (!this.supportWebgl) {
|
if (!this.supportWebgl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -219,15 +215,15 @@ class WebglGlobe {
|
|||||||
this.width = window ? window.innerWidth : 0
|
this.width = window ? window.innerWidth : 0
|
||||||
this.height = window ? window.innerHeight : 0
|
this.height = window ? window.innerHeight : 0
|
||||||
|
|
||||||
//remove retina on small screen(aka mobile) to boost perfs
|
// Remove retina on small screen (aka mobile) to boost perfs
|
||||||
this.renderer.setPixelRatio( window.innerWidth < 768 ? 1 : window.devicePixelRatio)
|
this.renderer.setPixelRatio( window.innerWidth < 768 ? 1 : window.devicePixelRatio)
|
||||||
this.renderer.resize(this.width , this.height)
|
this.renderer.resize(this.width , this.height)
|
||||||
|
|
||||||
//update camera aspect ratio
|
// Update camera aspect ratio
|
||||||
this.camera.aspect = this.width / this.height
|
this.camera.aspect = this.width / this.height
|
||||||
this.camera.updateProjectionMatrix()
|
this.camera.updateProjectionMatrix()
|
||||||
|
|
||||||
//at which distance to put the camera when rotating arounf 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)
|
||||||
|
|
||||||
@@ -242,11 +238,11 @@ class WebglGlobe {
|
|||||||
* As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe
|
* As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe
|
||||||
* 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
|
||||||
if (!this.hasUpdateCameraPos) {
|
if (!this.hasUpdateCameraPos) {
|
||||||
this.hasUpdateCameraPos = true
|
this.hasUpdateCameraPos = true
|
||||||
if (this.globeMesh.material.uniforms.uCameraOffsetY) {
|
if (this.globeMesh.material.uniforms.uCameraOffsetY) {
|
||||||
@@ -260,17 +256,16 @@ class WebglGlobe {
|
|||||||
* Flag to stop rendering the webgl if the globe isnt visible
|
* Flag to stop rendering the webgl if the globe isnt visible
|
||||||
* This helps saving perfs and battery
|
* This helps saving perfs and battery
|
||||||
*/
|
*/
|
||||||
enable() {
|
enable () {
|
||||||
this._canUpdate = true
|
this._canUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable () {
|
||||||
this._canUpdate = false
|
this._canUpdate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update () {
|
update () {
|
||||||
|
|
||||||
if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded || !this.hasUpdateCameraPos) {
|
if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded || !this.hasUpdateCameraPos) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -281,44 +276,41 @@ class WebglGlobe {
|
|||||||
|
|
||||||
this.currMarkerScrollOffset += (this.markersScrollOffset - this.currMarkerScrollOffset) * this.options.scrollSmoothing
|
this.currMarkerScrollOffset += (this.markersScrollOffset - this.currMarkerScrollOffset) * this.options.scrollSmoothing
|
||||||
|
|
||||||
//compute the camera view-projection matrix to use it on the markers
|
// Compute the camera view-projection matrix to use it on the markers
|
||||||
this.camera.update()
|
this.camera.update()
|
||||||
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14])
|
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14])
|
||||||
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix)
|
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix)
|
||||||
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix)
|
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix)
|
||||||
|
|
||||||
//Auto rotate the globe
|
// Auto rotate the globe
|
||||||
this.globeMesh.rotation[1] += this.options.autoRotationSpeed
|
this.globeMesh.rotation[1] += this.options.autoRotationSpeed
|
||||||
this.globeMesh.updateMatrix()
|
this.globeMesh.updateMatrix()
|
||||||
this.globeMesh.updateWorldMatrix()
|
this.globeMesh.updateWorldMatrix()
|
||||||
|
|
||||||
let screenPos = vec3.create()
|
let screenPos = vec3.create()
|
||||||
this.markers.forEach((marker, i) => {
|
this.markers.forEach((marker, i) => {
|
||||||
|
// Get marker 3D position and project it on screen to get 2D position
|
||||||
//get marker 3D position and project it on screen to get 2D position
|
|
||||||
vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2])
|
vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2])
|
||||||
vec3.transformMat4(screenPos, screenPos, this.globeMesh.worldMatrix)
|
vec3.transformMat4(screenPos, screenPos, this.globeMesh.worldMatrix)
|
||||||
vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix)
|
vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix)
|
||||||
|
|
||||||
//marker 2D screen position (starting from top left corner of screen)
|
// Marker 2D screen position (starting from top left corner of screen)
|
||||||
let x = ((screenPos[0] + 1) / 2) * this.width
|
let x = ((screenPos[0] + 1) / 2) * this.width
|
||||||
let y = (1. - (screenPos[1] + 1) / 2) * this.height
|
let y = (1. - (screenPos[1] + 1) / 2) * this.height
|
||||||
|
|
||||||
//compute marker Normal
|
// Compute marker Normal
|
||||||
let N = vec3.create()
|
let N = vec3.create()
|
||||||
vec3.set(N, marker.position[0], marker.position[1], marker.position[2])
|
vec3.set(N, marker.position[0], marker.position[1], marker.position[2])
|
||||||
vec3.transformMat4(N, N, this.globeMesh.worldMatrix)
|
vec3.transformMat4(N, N, this.globeMesh.worldMatrix)
|
||||||
vec3.normalize(N, N)
|
vec3.normalize(N, N)
|
||||||
|
|
||||||
//compute view vector (camera direction)
|
// Compute view vector (camera direction)
|
||||||
let V = vec3.create()
|
let V = vec3.create()
|
||||||
vec3.set(V, marker.position[0], marker.position[1], marker.position[2])
|
vec3.set(V, marker.position[0], marker.position[1], marker.position[2])
|
||||||
vec3.subtract(V, V, this.cameraPosition)
|
vec3.subtract(V, V, this.cameraPosition)
|
||||||
vec3.normalize(V, V)
|
vec3.normalize(V, V)
|
||||||
|
|
||||||
|
// Marker is behind the globe: clamp it to the globe edge
|
||||||
|
|
||||||
//the marker is behind the globe: clamp it to the globe edge
|
|
||||||
if (vec3.dot(V, N) * -1 < 0) {
|
if (vec3.dot(V, N) * -1 < 0) {
|
||||||
let dir = vec2.create()
|
let dir = vec2.create()
|
||||||
vec2.set(dir, x, y)
|
vec2.set(dir, x, y)
|
||||||
@@ -334,7 +326,7 @@ class WebglGlobe {
|
|||||||
marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`
|
marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`
|
||||||
marker.el.classList.remove('is-active')
|
marker.el.classList.remove('is-active')
|
||||||
}
|
}
|
||||||
//marker is in front of the globe; update 2D position
|
// Marker is in front of the globe; update 2D position
|
||||||
else {
|
else {
|
||||||
y += this.currMarkerScrollOffset
|
y += this.currMarkerScrollOffset
|
||||||
marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`
|
marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`
|
||||||
@@ -342,8 +334,8 @@ class WebglGlobe {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//render webgl frame
|
// Render WebGL frame
|
||||||
this.renderer.clearColor(0,0,0,0)//[RGBA] alpha is set to 0 to have a transparent background on the webgl
|
this.renderer.clearColor(0,0,0,0) //[RGBA] alpha is set to 0 to have a transparent background on the webgl
|
||||||
this.renderer.clear()
|
this.renderer.clear()
|
||||||
this.renderer.render(this.scene, this.camera)
|
this.renderer.render(this.scene, this.camera)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +1,62 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { locations } from 'utils/store'
|
import { continents, locations } from 'utils/store'
|
||||||
|
import { getPosition } from 'utils/functions'
|
||||||
|
// Dependencies
|
||||||
import ScrollOut from 'scroll-out'
|
import ScrollOut from 'scroll-out'
|
||||||
|
import Lazy from 'svelte-lazy'
|
||||||
function getPosition (node, scope) {
|
|
||||||
var root = scope || document;
|
|
||||||
var offsetTop = node.offsetTop;
|
|
||||||
var offsetLeft = node.offsetLeft;
|
|
||||||
while (node && node.offsetParent && node.offsetParent != document && node !== root && root !== node.offsetParent ) {
|
|
||||||
offsetTop += node.offsetParent.offsetTop;
|
|
||||||
offsetLeft += node.offsetParent.offsetLeft;
|
|
||||||
node = node.offsetParent;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
top: offsetTop,
|
|
||||||
left: offsetLeft
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
export let type = ''
|
export let type = ''
|
||||||
|
export let size = 0.575
|
||||||
let scope
|
let scope
|
||||||
let globe
|
let globe
|
||||||
let containerTop = 0
|
let containerTop = 0
|
||||||
let containerHeight = 0
|
let containerHeight = 0
|
||||||
let winHeight = window ? window.innerHeight : 0
|
|
||||||
|
|
||||||
const resize = () => {
|
|
||||||
winHeight = window ? window.innerHeight : 0
|
/*
|
||||||
|
** Functions
|
||||||
|
*/
|
||||||
|
// Globe update
|
||||||
|
const update = () => {
|
||||||
|
requestAnimationFrame(update)
|
||||||
|
globe.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
// On resize
|
||||||
|
const onResize = () => {
|
||||||
if (scope) {
|
if (scope) {
|
||||||
containerTop = getPosition( scope ).top
|
containerTop = getPosition(scope).top
|
||||||
containerHeight = scope.clientHeight
|
containerHeight = scope.clientHeight
|
||||||
}
|
}
|
||||||
globe.resize()
|
globe.resize()
|
||||||
globe.update()
|
globe.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = () => {
|
// On scroll
|
||||||
requestAnimationFrame(update)
|
const onScroll = () => {
|
||||||
globe.update()
|
let scrollDiff = (containerTop + window.innerHeight + (containerHeight - window.innerHeight) / 2) - document.documentElement.scrollTop
|
||||||
|
let scrollRatio = (1 - (scrollDiff / window.innerHeight)) * 2
|
||||||
|
globe && globe.updateCameraPos(scrollRatio, scrollDiff - window.innerHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onScroll = (e)=> {
|
|
||||||
let scrollDiff = (containerTop + window.innerHeight + (containerHeight - window.innerHeight) /2 ) - document.documentElement.scrollTop
|
|
||||||
let scrollRatio = (1 - ( scrollDiff / window.innerHeight ) ) * 2
|
|
||||||
globe && globe.updateCameraPos( scrollRatio, scrollDiff - window.innerHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Run code when mounted
|
** Run code when mounted
|
||||||
*/
|
*/
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
|
||||||
const globeScroll = ScrollOut({
|
|
||||||
once: false,
|
|
||||||
targets: scope,
|
|
||||||
// threshold: 1,
|
|
||||||
onShown: () => {
|
|
||||||
globe.enable()
|
|
||||||
},
|
|
||||||
onHidden: () => {
|
|
||||||
globe.disable()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
let InteractiveGlobe
|
let InteractiveGlobe
|
||||||
if (process.browser) {
|
|
||||||
// Import libraries and code
|
// Import libraries and code
|
||||||
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: 0.5,//smaller number == larger globe
|
cameraDistance: size, // Smaller number == larger globe
|
||||||
autoRotationSpeed: -0.0025,
|
// autoRotationSpeed: -0.0025,
|
||||||
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 => {
|
||||||
return {
|
return {
|
||||||
name: location.name,
|
name: location.name,
|
||||||
slug: location.slug,
|
slug: location.slug,
|
||||||
@@ -84,23 +64,31 @@
|
|||||||
countrySlug: location.country.slug,
|
countrySlug: location.country.slug,
|
||||||
lat: location.coordinates.lat,
|
lat: location.coordinates.lat,
|
||||||
lng: location.coordinates.lng,
|
lng: location.coordinates.lng,
|
||||||
className: location.slug === 'marseille' ? 'is-left' : '',
|
className: location.close ? 'is-close' : '',
|
||||||
}
|
}
|
||||||
})],
|
}) ],
|
||||||
|
centerPositions: [ ...$continents.map(continent => continent.countries) ],
|
||||||
onLinkClicked: () => {}
|
onLinkClicked: () => {}
|
||||||
})
|
})
|
||||||
|
console.log(globe.options.centerPositions)
|
||||||
|
|
||||||
// Run the globe
|
// Run the globe
|
||||||
resize()
|
onResize()
|
||||||
update()
|
update()
|
||||||
}
|
|
||||||
|
// Enable the globe only when shown
|
||||||
|
const globeScroll = ScrollOut({
|
||||||
|
once: false,
|
||||||
|
targets: scope,
|
||||||
|
onShown: () => {
|
||||||
|
globe.enable()
|
||||||
|
onScroll()
|
||||||
|
},
|
||||||
|
onHidden: () => globe.disable()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:resize={resize} on:scroll={onScroll} />
|
<svelte:window on:resize={onResize} on:scroll={onScroll} />
|
||||||
|
|
||||||
{#if type === 'part'}
|
<div class="globe" class:globe--part={type === 'part'} bind:this={scope} />
|
||||||
<div class="globe globe--cut" bind:this={scope} />
|
|
||||||
{:else}
|
|
||||||
<div class="globe" bind:this={scope} />
|
|
||||||
{/if}
|
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
data {
|
data {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
coordinates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
countries {
|
countries {
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
region
|
region
|
||||||
country { id }
|
country { id }
|
||||||
description
|
description
|
||||||
|
close
|
||||||
coordinates
|
coordinates
|
||||||
illu_desktop { full_url }
|
illu_desktop { full_url }
|
||||||
illu_desktop_2x { full_url }
|
illu_desktop_2x { full_url }
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
pageReady,
|
pageReady,
|
||||||
pageAnimation
|
pageAnimation
|
||||||
} from 'utils/store'
|
} from 'utils/store'
|
||||||
|
// Dependencies
|
||||||
|
import Lazy from 'svelte-lazy'
|
||||||
// Components
|
// Components
|
||||||
import IconArrow from 'atoms/IconArrow'
|
import IconArrow from 'atoms/IconArrow'
|
||||||
import TitleSite from 'atoms/TitleSite'
|
import TitleSite from 'atoms/TitleSite'
|
||||||
@@ -65,7 +67,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if process.browser}
|
||||||
|
<Lazy offset={window.innerHeight}>
|
||||||
<InteractiveGlobe />
|
<InteractiveGlobe />
|
||||||
|
</Lazy>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Locations />
|
<Locations />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { stores } from '@sapper/app'
|
import { stores } from '@sapper/app'
|
||||||
import { site, pageReady } from 'utils/store'
|
import { site, pageReady, pageAnimation } from 'utils/store'
|
||||||
|
// Dependencies
|
||||||
|
import Lazy from 'svelte-lazy'
|
||||||
// Components
|
// Components
|
||||||
import IconArrow from 'atoms/IconArrow'
|
import IconArrow from 'atoms/IconArrow'
|
||||||
import TitleSite from 'atoms/TitleSite'
|
import TitleSite from 'atoms/TitleSite'
|
||||||
@@ -76,7 +78,11 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if process.browser}
|
||||||
|
<Lazy offset={window.innerHeight}>
|
||||||
<InteractiveGlobe type="part" />
|
<InteractiveGlobe type="part" />
|
||||||
|
</Lazy>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -31,34 +31,46 @@
|
|||||||
height: 2000px;
|
height: 2000px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut
|
|
||||||
&--cut {
|
|
||||||
opacity: 0.5;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100vw;
|
|
||||||
height: 35vw;
|
|
||||||
min-height: 400px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marker
|
/*
|
||||||
.marker {
|
** Partial globe
|
||||||
|
*/
|
||||||
|
&--part {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 30vw;
|
||||||
|
min-height: 300px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Markers
|
||||||
|
*/
|
||||||
|
&__markers {
|
||||||
|
// When dragging
|
||||||
|
&.is-grabbing {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marker
|
||||||
|
.marker {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
top: 0;
|
top: -4px;
|
||||||
left: 0;
|
left: -4px;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
|
padding: 4px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background: #ff6c89;
|
background: #ff6c89;
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
transition: color 0.4s $ease-quart;
|
transition: color 0.4s $ease-quart, opacity 0.4s $ease-quart;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hover glow effect
|
// Hover glow effect
|
||||||
@@ -69,8 +81,8 @@
|
|||||||
// Label
|
// Label
|
||||||
&__label {
|
&__label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -230%;
|
bottom: -16px;
|
||||||
left: 230%;
|
left: 16px;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
// Location city
|
// Location city
|
||||||
@@ -103,30 +115,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Left positioned
|
||||||
.marker.is-left {
|
&.is-left {
|
||||||
.marker__label {
|
.marker {
|
||||||
|
&__label {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 360%;
|
right: 32px;
|
||||||
}
|
}
|
||||||
.marker__country {
|
&__country {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Grabbing
|
|
||||||
.markerWrapper.is-grabbing {
|
// Marker is close to another one
|
||||||
cursor: grabbing;
|
// Show the marker infos only on hover
|
||||||
}
|
&.is-close {
|
||||||
|
.marker__label {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
// Part globe
|
}
|
||||||
.globe--part {
|
|
||||||
overflow: hidden;
|
// Show labels on hover
|
||||||
height: 30vw;
|
&:hover {
|
||||||
min-height: 300px;
|
.marker__label {
|
||||||
opacity: 0.5;
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Globe
|
// Globe
|
||||||
// .globe__cut {
|
// .globe {
|
||||||
// margin-top: 8vw;
|
// margin-top: 8vw;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,22 @@ export function throttle (fn, delay) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get a DOM element's position
|
||||||
|
*/
|
||||||
|
export const getPosition = (node, scope) => {
|
||||||
|
const root = scope || document
|
||||||
|
let offsetTop = node.offsetTop
|
||||||
|
let offsetLeft = node.offsetLeft
|
||||||
|
while (node && node.offsetParent && node.offsetParent != document && node !== root && root !== node.offsetParent) {
|
||||||
|
offsetTop += node.offsetParent.offsetTop
|
||||||
|
offsetLeft += node.offsetParent.offsetLeft
|
||||||
|
node = node.offsetParent
|
||||||
|
}
|
||||||
|
return { top: offsetTop, left: offsetLeft }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Wrap string's each letters into a span
|
** Wrap string's each letters into a span
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user