diff --git a/src/components/organisms/InteractiveGlobe.svelte b/src/components/organisms/InteractiveGlobe.svelte
new file mode 100644
index 0000000..04790aa
--- /dev/null
+++ b/src/components/organisms/InteractiveGlobe.svelte
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+ {#if type === 'cropped'}
+
+ {:else}
+
+ {/if}
+
\ No newline at end of file
diff --git a/src/modules/globe/index.js b/src/modules/globe/index.js
index 238b920..a4538b5 100644
--- a/src/modules/globe/index.js
+++ b/src/modules/globe/index.js
@@ -24,7 +24,6 @@ const degToRad = deg => deg * Math.PI / 180
class WebglGlobe {
-
// Constructor
constructor (options) {
this.$el = options.el // The DOM reference node
@@ -34,7 +33,7 @@ class WebglGlobe {
this.options.cameraDistance = 1 // this.options.cameraDistance || 1 // A multiplier to move camera backward or forward
this.options.opacity = this.options.opacity || 1
- this.cities = options.markers // List of cities with their options
+ this.locations = options.markers // List of locations with their options
this._canUpdate = false
this.hasUpdateCameraPos = false
this.referenceHeight = 1 // Used to set camera distance from globe where referenceHeight == window height
@@ -157,7 +156,7 @@ class WebglGlobe {
* Create DOM nodes for markers and 3D positions
*/
this.markers = []
- let markers = this.cities
+ let markers = this.locations
// Instance all markers
for (let i = 0; i < markers.length; i++) {
@@ -362,7 +361,7 @@ class WebglGlobe {
vec2.set(dir, x, y)
let center = vec2.create()
vec2.set(center, this.width/2, this.height/2)
- let dir2d = vec2.clone(dir, dir)
+ let dir2d = vec2.clone(dir) // vec2.clone(dir, dir)
vec2.subtract(dir2d, dir2d, center)
vec2.normalize(dir2d, dir2d)
vec2.scale(dir2d, dir2d, this.circleScreenSize)
diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte
index 951e563..ca269bd 100644
--- a/src/routes/__layout.svelte
+++ b/src/routes/__layout.svelte
@@ -28,6 +28,7 @@
location {
name
slug
+ coordinates
country {
name
slug
@@ -58,6 +59,7 @@
continent {
name
slug
+ rotation
countries {
slug
}
diff --git a/src/routes/index.svelte b/src/routes/index.svelte
index 89d7f57..b04be02 100644
--- a/src/routes/index.svelte
+++ b/src/routes/index.svelte
@@ -53,6 +53,8 @@
+
+
diff --git a/src/style/_animations.scss b/src/style/_animations.scss
index 905ca1d..126ba00 100644
--- a/src/style/_animations.scss
+++ b/src/style/_animations.scss
@@ -1,119 +1,3 @@
-/* ==========================================================================
- PAGE TRANSITION
-========================================================================== */
-.transition {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 400;
- overflow: hidden;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: wait;
-
- &, * {
- will-change: transform, opacity;
- }
-
- // Content
- &__loader {
- position: relative;
- z-index: 2;
- }
-
- // Background
- &__background {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: $color-primary;
- transform-origin: 50% 0;
- }
-
- // Hidden
- &.hidden {
- display: none;
- }
-}
-
-
-
-/* ==========================================================================
- REVEAL ANIMATIONS
-========================================================================== */
-.anim-mask {
- display: block;
- overflow: hidden;
- white-space: nowrap;
-
- span {
- display: inline-block;
- }
-}
-
-
-
-/* ==========================================================================
- KEYFRAMES ANIMATIONS
-========================================================================== */
-// Rotate button dashes
-@keyframes rotateDashes {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-
-/*
-** Spinning globe
-*/
-@keyframes moveContinents {
- 0% { transform: translate(0,0); }
- 100% { transform: translate(-80.26px, 28.2px); }
-}
-.anim-spinGlobe {
- animation: moveContinents 1.7s linear infinite;
- animation-play-state: paused;
-}
-// Small
-@keyframes moveContinentsSmall {
- 0% { transform: translate(0,0); }
- 100% { transform: translate(-96.95px, 0); }
-}
-.anim-spinGlobeSmall {
- animation: moveContinentsSmall 1.5s linear infinite;
- animation-play-state: paused;
-}
-
-
-/*
-** Layout
-*/
-// List
-@keyframes layoutListOdd {
- 0% { transform: translateX(0); }
- 50% { transform: translateX(2px); }
-}
-@keyframes layoutListEven {
- 0% { transform: translateX(0); }
- 50% { transform: translateX(-4px); }
-}
-
-// Grid
-@keyframes layoutGridOdd {
- 0% { transform: translateY(0); }
- 50% { transform: translateY(2px); }
-}
-@keyframes layoutGridEven {
- 0% { transform: translateY(0); }
- 50% { transform: translateY(-3px); }
-}
-
-
/*
** Globe
*/
diff --git a/src/style/modules/_globe.scss b/src/style/modules/_globe.scss
new file mode 100644
index 0000000..d8b82b2
--- /dev/null
+++ b/src/style/modules/_globe.scss
@@ -0,0 +1,187 @@
+// Globe
+.globe {
+ position: relative;
+ z-index: 2;
+ width: 1315px;
+ height: clamp(700px, 100vw, 1315px);
+ overflow: hidden;
+ cursor: grab;
+ user-select: none;
+
+ @include bp (sm) {
+ // height: 130vw;
+ }
+ @include bp (md) {
+ // height: 112vw;
+ }
+ @include bp (xl) {
+ // height: 100vw;
+ }
+
+ // DEBUG //
+ // background: rgba(red, 0.2);
+ // &:after {
+ // content: "";
+ // display: block;
+ // position: absolute;
+ // top: 50%;
+ // left: 0;
+ // background: blue;
+ // width: 100%;
+ // height: 2px;
+ // margin-top: -1px;
+ // }
+ // END DEBUG //
+
+ /*
+ ** Cropped globe
+ */
+ &--cropped {
+ overflow: hidden;
+ height: clamp(300px, 30vw, 500px);
+ }
+
+ /*
+ ** Markers
+ */
+ &__markers {
+ z-index: 210;
+
+ // When dragging
+ &.is-grabbing {
+ cursor: grabbing;
+ }
+
+ // Marker
+ .marker {
+ position: absolute;
+ z-index: 2;
+ cursor: pointer;
+ display: block;
+ top: -4px;
+ left: -4px;
+ padding: 4px;
+ opacity: 1;
+ will-change: transform;
+
+ // Dot
+ &:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 8px;
+ height: 8px;
+ background: $color-secondary;
+ border-radius: 100%;
+ }
+
+ span {
+ transition: color 0.4s $ease-quart, opacity 0.3s $ease-inout;
+ }
+
+ // Hover glow effect
+ &.hover {
+ &:before {
+ animation: globeMarkerPulse 1s;
+ }
+ }
+
+ // Label
+ &__label {
+ position: absolute;
+ bottom: -16px;
+ left: 16px;
+ color: transparent;
+ }
+ // Location city
+ &__city {
+ font-family: $font-serif;
+ font-size: rem(18px);
+ line-height: 1;
+
+ @include bp (sm) {
+ font-size: rem(24px);
+ }
+ }
+ // Location country
+ &__country {
+ display: block;
+ opacity: 0.8;
+ font-family: $font-sans;
+ font-size: rem(8px);
+ line-height: 1;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+
+ @include bp (sm) {
+ font-size: rem(10px);
+ }
+ }
+
+ // Active
+ &.is-active {
+ &, span {
+ opacity: 1;
+ }
+ .marker {
+ &__city {
+ color: $color-secondary;
+ }
+ &__country {
+ color: $color-text;
+ }
+ }
+ }
+
+ // Is light
+ &.is-light {
+ &.is-active {
+ .marker {
+ &__city {
+ color: #fff;
+ }
+ &__country {
+ color: #d2b7e4;
+ }
+ }
+ }
+ }
+
+ // Left positioned
+ &.is-left {
+ .marker {
+ &__label {
+ left: auto;
+ right: 32px;
+ }
+ &__country {
+ text-align: right;
+ }
+ }
+ }
+
+ // Marker is close to another one
+ // Show the marker infos only on hover
+ &.is-close {
+ // Dot
+ &:before {
+ width: 7px;
+ height: 7px;
+ }
+ // Label
+ .marker__label {
+ opacity: 0;
+ }
+
+ // Show labels on hover
+ &:hover {
+ .marker__label {
+ opacity: 1;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/style/style.scss b/src/style/style.scss
index c0fc64a..cc74ed4 100644
--- a/src/style/style.scss
+++ b/src/style/style.scss
@@ -22,6 +22,9 @@
// Pages
@import "pages/homepage";
+// Modules
+@import "modules/globe";
+
// Atomic Design System
// Atoms
@@ -46,4 +49,4 @@
// @import "pages/page";
// Misc
-// @import "animations";
\ No newline at end of file
+@import "animations";
\ No newline at end of file
diff --git a/src/utils/functions.ts b/src/utils/functions.ts
index fe9ebc0..94f2aa8 100644
--- a/src/utils/functions.ts
+++ b/src/utils/functions.ts
@@ -3,4 +3,31 @@
*/
export const lerp = (start: number, end: number, amt: number): number => {
return (1 - amt) * start + amt * end
+}
+
+
+/**
+ * Return a random element from an array
+ */
+export const getRandomElement = (array: any[]): any => {
+ return ~~(array.length * Math.random())
+}
+
+
+/**
+ * Get a DOM element's position
+ */
+export const getPosition = (node, scope?: HTMLElement) => {
+ 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
+ }
}
\ No newline at end of file