mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-10 04:22:18 +00:00
correct spots
This commit is contained in:
21
src/lib/actions/animate-in-view.ts
Normal file
21
src/lib/actions/animate-in-view.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { inView, type InViewOptions } from 'motion';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const useAnimateInView = ({ options }: { options?: InViewOptions }) => {
|
||||
let animate = writable<boolean>(false);
|
||||
|
||||
const action = (node: HTMLElement) => {
|
||||
inView(
|
||||
node,
|
||||
() => {
|
||||
animate.set(true);
|
||||
},
|
||||
{ ...options }
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
animate,
|
||||
action
|
||||
};
|
||||
};
|
||||
34
src/lib/actions/mouse-position.ts
Normal file
34
src/lib/actions/mouse-position.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { inView } from 'motion';
|
||||
import { type Writable, writable } from 'svelte/store';
|
||||
|
||||
export const useMousePosition = () => {
|
||||
let position = writable<{ x: number; y: number }>({
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
|
||||
const action = (node: HTMLElement) => {
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
position.set({
|
||||
x: event.clientX,
|
||||
y: event.clientY
|
||||
});
|
||||
};
|
||||
|
||||
inView(
|
||||
node,
|
||||
() => {
|
||||
node.addEventListener('mousemove', handleMouseMove);
|
||||
},
|
||||
{ amount: 'all' }
|
||||
);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
node.removeEventListener('mousemove', handleMouseMove);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return { action, position };
|
||||
};
|
||||
605
src/lib/components/appwrite-network/data/pins.ts
Normal file
605
src/lib/components/appwrite-network/data/pins.ts
Normal file
@@ -0,0 +1,605 @@
|
||||
export const pins = {
|
||||
'pop-locations': [
|
||||
{
|
||||
lat: 39.04,
|
||||
lng: -77.49,
|
||||
city: 'Ashburn',
|
||||
code: 'ASH',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 33.75,
|
||||
lng: -84.39,
|
||||
city: 'Atlanta',
|
||||
code: 'ATL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.36,
|
||||
lng: -71.06,
|
||||
city: 'Boston',
|
||||
code: 'BOS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 51.05,
|
||||
lng: -114.07,
|
||||
city: 'Calgary',
|
||||
code: 'CAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 41.88,
|
||||
lng: -87.63,
|
||||
city: 'Chicago',
|
||||
code: 'CHI',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.96,
|
||||
lng: -82.99,
|
||||
city: 'Columbus',
|
||||
code: 'COL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 32.78,
|
||||
lng: -96.8,
|
||||
city: 'Dallas',
|
||||
code: 'DAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.74,
|
||||
lng: -104.99,
|
||||
city: 'Denver',
|
||||
code: 'DEN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.33,
|
||||
lng: -83.05,
|
||||
city: 'Detroit',
|
||||
code: 'DET',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 21.31,
|
||||
lng: -157.86,
|
||||
city: 'Honolulu',
|
||||
code: 'HNL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 29.76,
|
||||
lng: -95.37,
|
||||
city: 'Houston',
|
||||
code: 'HOU',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 30.33,
|
||||
lng: -81.66,
|
||||
city: 'Jacksonville',
|
||||
code: 'JAX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.1,
|
||||
lng: -94.58,
|
||||
city: 'Kansas City',
|
||||
code: 'KC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 34.05,
|
||||
lng: -118.24,
|
||||
city: 'Los Angeles',
|
||||
code: 'LA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.77,
|
||||
lng: -80.19,
|
||||
city: 'Miami',
|
||||
code: 'MIA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 44.98,
|
||||
lng: -93.27,
|
||||
city: 'Minneapolis',
|
||||
code: 'MIN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.5,
|
||||
lng: -73.57,
|
||||
city: 'Montreal',
|
||||
code: 'MTL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 40.71,
|
||||
lng: -74.01,
|
||||
city: 'New York',
|
||||
code: 'NYC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 33.45,
|
||||
lng: -112.07,
|
||||
city: 'Phoenix',
|
||||
code: 'PHX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.52,
|
||||
lng: -122.68,
|
||||
city: 'Portland',
|
||||
code: 'PDX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 37.34,
|
||||
lng: -121.89,
|
||||
city: 'San Jose',
|
||||
code: 'SJ',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 47.61,
|
||||
lng: -122.33,
|
||||
city: 'Seattle',
|
||||
code: 'SEA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.63,
|
||||
lng: -90.2,
|
||||
city: 'St Louis',
|
||||
code: 'STL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 43.65,
|
||||
lng: -79.38,
|
||||
city: 'Toronto',
|
||||
code: 'TOR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 49.28,
|
||||
lng: -123.12,
|
||||
city: 'Vancouver',
|
||||
code: 'VAN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 4.71,
|
||||
lng: -74.07,
|
||||
city: 'Bogota',
|
||||
code: 'BOG',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -34.61,
|
||||
lng: -58.38,
|
||||
city: 'Buenos Aires',
|
||||
code: 'BUE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -25.43,
|
||||
lng: -49.27,
|
||||
city: 'Curitiba',
|
||||
code: 'CUR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -3.73,
|
||||
lng: -38.52,
|
||||
city: 'Fortaleza',
|
||||
code: 'FOR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -12.05,
|
||||
lng: -77.04,
|
||||
city: 'Lima',
|
||||
code: 'LIM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -23.55,
|
||||
lng: -46.63,
|
||||
city: 'São Paulo',
|
||||
code: 'SAO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.45,
|
||||
lng: -70.67,
|
||||
city: 'Santiago',
|
||||
code: 'SCL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -22.91,
|
||||
lng: -43.17,
|
||||
city: 'Rio de Janeiro',
|
||||
code: 'RIO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 52.37,
|
||||
lng: 4.89,
|
||||
city: 'Amsterdam',
|
||||
code: 'AMS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 55.68,
|
||||
lng: 12.57,
|
||||
city: 'Copenhagen',
|
||||
code: 'CPH',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 50.85,
|
||||
lng: 4.35,
|
||||
city: 'Brussels',
|
||||
code: 'BRU',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 53.35,
|
||||
lng: -6.26,
|
||||
city: 'Dublin',
|
||||
code: 'DUB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 50.11,
|
||||
lng: 8.68,
|
||||
city: 'Frankfurt',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 60.17,
|
||||
lng: 24.94,
|
||||
city: 'Helsinki',
|
||||
code: 'HEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.72,
|
||||
lng: -9.14,
|
||||
city: 'Lisbon',
|
||||
code: 'LIS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 51.51,
|
||||
lng: -0.13,
|
||||
city: 'London',
|
||||
code: 'LON',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 40.42,
|
||||
lng: -3.7,
|
||||
city: 'Madrid',
|
||||
code: 'MAD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 53.48,
|
||||
lng: -2.24,
|
||||
city: 'Manchester',
|
||||
code: 'MAN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 43.3,
|
||||
lng: 5.37,
|
||||
city: 'Marseille',
|
||||
code: 'MRS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.46,
|
||||
lng: 9.19,
|
||||
city: 'Milan',
|
||||
code: 'MIL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.14,
|
||||
lng: 11.58,
|
||||
city: 'Munich',
|
||||
code: 'MUN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 59.91,
|
||||
lng: 10.75,
|
||||
city: 'Oslo',
|
||||
code: 'OSL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.12,
|
||||
lng: 13.36,
|
||||
city: 'Palermo',
|
||||
code: 'PAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'PAR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 41.9,
|
||||
lng: 12.5,
|
||||
city: 'Rome',
|
||||
code: 'ROM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.7,
|
||||
lng: 23.32,
|
||||
city: 'Sofia',
|
||||
code: 'SOF',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 59.33,
|
||||
lng: 18.07,
|
||||
city: 'Stockholm',
|
||||
code: 'STO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.21,
|
||||
lng: 16.37,
|
||||
city: 'Vienna',
|
||||
code: 'VIE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 5.56,
|
||||
lng: -0.2,
|
||||
city: 'Accra',
|
||||
code: 'ACC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.93,
|
||||
lng: 18.42,
|
||||
city: 'Cape Town',
|
||||
code: 'CPT',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -26.2,
|
||||
lng: 28.05,
|
||||
city: 'Johannesburg',
|
||||
code: 'JHB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 13.75,
|
||||
lng: 100.5,
|
||||
city: 'Bangkok',
|
||||
code: 'BKK',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 13.08,
|
||||
lng: 80.28,
|
||||
city: 'Chennai',
|
||||
code: 'CHE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.27,
|
||||
lng: 55.3,
|
||||
city: 'Dubai',
|
||||
code: 'DXB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.12,
|
||||
lng: 56.33,
|
||||
city: 'Fujairah',
|
||||
code: 'FUJ',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 22.32,
|
||||
lng: 114.17,
|
||||
city: 'Hong Kong',
|
||||
code: 'HK',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 17.38,
|
||||
lng: 78.48,
|
||||
city: 'Hyderabad',
|
||||
code: 'HYD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 22.57,
|
||||
lng: 88.36,
|
||||
city: 'Kolkata',
|
||||
code: 'KOL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 3.14,
|
||||
lng: 101.69,
|
||||
city: 'Kuala Lumpur',
|
||||
code: 'KL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 14.6,
|
||||
lng: 120.98,
|
||||
city: 'Manila',
|
||||
code: 'MNL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 19.08,
|
||||
lng: 72.88,
|
||||
city: 'Mumbai',
|
||||
code: 'MUM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 28.61,
|
||||
lng: 77.21,
|
||||
city: 'New Delhi',
|
||||
code: 'DEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 34.69,
|
||||
lng: 135.5,
|
||||
city: 'Osaka',
|
||||
code: 'OSA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 37.57,
|
||||
lng: 126.98,
|
||||
city: 'Seoul',
|
||||
code: 'SEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 1.35,
|
||||
lng: 103.82,
|
||||
city: 'Singapore',
|
||||
code: 'SIN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 35.69,
|
||||
lng: 139.69,
|
||||
city: 'Tokyo',
|
||||
code: 'TYO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -34.93,
|
||||
lng: 138.6,
|
||||
city: 'Adelaide',
|
||||
code: 'ADL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -36.85,
|
||||
lng: 174.76,
|
||||
city: 'Auckland',
|
||||
code: 'AKL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -27.47,
|
||||
lng: 153.03,
|
||||
city: 'Brisbane',
|
||||
code: 'BNE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -43.53,
|
||||
lng: 172.64,
|
||||
city: 'Christchurch',
|
||||
code: 'CHC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -37.81,
|
||||
lng: 144.96,
|
||||
city: 'Melbourne',
|
||||
code: 'MEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -31.95,
|
||||
lng: 115.85,
|
||||
city: 'Perth',
|
||||
code: 'PER',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'SYD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -41.29,
|
||||
lng: 174.78,
|
||||
city: 'Wellington',
|
||||
code: 'WLG',
|
||||
available: true
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
lat: 37.77,
|
||||
lng: -122.42,
|
||||
city: 'San Francisco',
|
||||
code: 'SFO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'AUS',
|
||||
available: true
|
||||
}
|
||||
],
|
||||
regions: [
|
||||
{
|
||||
lat: 37.77,
|
||||
lng: -122.42,
|
||||
city: 'San Francisco',
|
||||
code: 'SFO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'AUS',
|
||||
available: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export type PinSegment = keyof typeof pins;
|
||||
@@ -19,7 +19,6 @@
|
||||
class?: string;
|
||||
animate?: boolean;
|
||||
isOpen: boolean;
|
||||
showDebugInfo?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -32,8 +31,7 @@
|
||||
available = false,
|
||||
class: className = '',
|
||||
animate = false,
|
||||
isOpen = false,
|
||||
showDebugInfo = false
|
||||
isOpen = false
|
||||
}: Props = $props();
|
||||
|
||||
let open = $state(isOpen);
|
||||
@@ -95,13 +93,3 @@
|
||||
{/if}
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
|
||||
{#if showDebugInfo}
|
||||
<div
|
||||
class="absolute z-50 rounded bg-black/50 p-1 text-xs text-white"
|
||||
style="left:{x}%; top:calc({y}% + 12px); transform: translateX(-50%);"
|
||||
>
|
||||
<div>Lat: {lat.toFixed(2)}, Lng: {lng.toFixed(2)}</div>
|
||||
<div>Position: {x.toFixed(2)}%, {y.toFixed(2)}%</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,710 +1,34 @@
|
||||
<script lang="ts" module>
|
||||
export const MAP_BOUNDS = $state({
|
||||
west: -132,
|
||||
east: 178,
|
||||
north: 65,
|
||||
south: -65
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { inView } from 'motion';
|
||||
import MapMarker from './map-marker.svelte';
|
||||
import { slugify } from '$lib/utils/slugify';
|
||||
import { classNames } from '$lib/utils/classnames';
|
||||
import { Tooltip } from 'bits-ui';
|
||||
import MapNav from './map-nav.svelte';
|
||||
|
||||
const showDebugInfo = false;
|
||||
|
||||
type Coordinates = {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
};
|
||||
|
||||
type PixelPosition = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
import { useMousePosition } from '$lib/actions/mouse-position';
|
||||
import { useAnimateInView } from '$lib/actions/animate-in-view';
|
||||
import { pins, type PinSegment } from './data/pins';
|
||||
import { latLongToSvgPosition } from './utils/projections';
|
||||
|
||||
let height: number = $state(0);
|
||||
let width: number = $state(0);
|
||||
|
||||
const MAP_BOUNDS = $state({
|
||||
west: -117,
|
||||
east: 207,
|
||||
north: 67, // Reduced from 70 to exclude north pole
|
||||
south: -83 // Increased from -55 to exclude Antarctica
|
||||
});
|
||||
|
||||
// Vertical scaling factor due to Y-axis compression
|
||||
const verticalScale = 0.65;
|
||||
|
||||
function latLongToSvgPosition({ latitude, longitude }: Coordinates): PixelPosition {
|
||||
// Handle longitude wrapping
|
||||
let adjustedLongitude = longitude;
|
||||
if (adjustedLongitude < MAP_BOUNDS.west) {
|
||||
adjustedLongitude += 360; // Wrap around for coordinates like -170
|
||||
}
|
||||
|
||||
// Calculate X position - note the order is important here
|
||||
// We need to normalize from west to east (the visible portion)
|
||||
const normalizedLong =
|
||||
(adjustedLongitude - MAP_BOUNDS.west) / (MAP_BOUNDS.east - MAP_BOUNDS.west);
|
||||
const x = normalizedLong * width;
|
||||
|
||||
// For Y position, we need to invert the normalization since SVG Y increases downward
|
||||
const normalizedLat = (MAP_BOUNDS.north - latitude) / (MAP_BOUNDS.north - MAP_BOUNDS.south);
|
||||
|
||||
// Apply the vertical scaling factor to compress the Y axis
|
||||
const y = normalizedLat * height * verticalScale + (height * (1 - verticalScale)) / 2;
|
||||
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
const pins = $state({
|
||||
'pop-locations': [
|
||||
{
|
||||
lat: 39.04,
|
||||
lng: -77.49,
|
||||
city: 'Ashburn',
|
||||
code: 'ASH',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 33.75,
|
||||
lng: -84.39,
|
||||
city: 'Atlanta',
|
||||
code: 'ATL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.36,
|
||||
lng: -71.06,
|
||||
city: 'Boston',
|
||||
code: 'BOS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 51.05,
|
||||
lng: -114.07,
|
||||
city: 'Calgary',
|
||||
code: 'CAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 41.88,
|
||||
lng: -87.63,
|
||||
city: 'Chicago',
|
||||
code: 'CHI',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.96,
|
||||
lng: -82.99,
|
||||
city: 'Columbus',
|
||||
code: 'COL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 32.78,
|
||||
lng: -96.8,
|
||||
city: 'Dallas',
|
||||
code: 'DAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.74,
|
||||
lng: -104.99,
|
||||
city: 'Denver',
|
||||
code: 'DEN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.33,
|
||||
lng: -83.05,
|
||||
city: 'Detroit',
|
||||
code: 'DET',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 21.31,
|
||||
lng: -157.86,
|
||||
city: 'Honolulu',
|
||||
code: 'HNL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 29.76,
|
||||
lng: -95.37,
|
||||
city: 'Houston',
|
||||
code: 'HOU',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 30.33,
|
||||
lng: -81.66,
|
||||
city: 'Jacksonville',
|
||||
code: 'JAX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 39.1,
|
||||
lng: -94.58,
|
||||
city: 'Kansas City',
|
||||
code: 'KC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 34.05,
|
||||
lng: -118.24,
|
||||
city: 'Los Angeles',
|
||||
code: 'LA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.77,
|
||||
lng: -80.19,
|
||||
city: 'Miami',
|
||||
code: 'MIA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 44.98,
|
||||
lng: -93.27,
|
||||
city: 'Minneapolis',
|
||||
code: 'MIN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.5,
|
||||
lng: -73.57,
|
||||
city: 'Montreal',
|
||||
code: 'MTL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 40.71,
|
||||
lng: -74.01,
|
||||
city: 'New York',
|
||||
code: 'NYC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 33.45,
|
||||
lng: -112.07,
|
||||
city: 'Phoenix',
|
||||
code: 'PHX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.52,
|
||||
lng: -122.68,
|
||||
city: 'Portland',
|
||||
code: 'PDX',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 37.34,
|
||||
lng: -121.89,
|
||||
city: 'San Jose',
|
||||
code: 'SJ',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 47.61,
|
||||
lng: -122.33,
|
||||
city: 'Seattle',
|
||||
code: 'SEA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.63,
|
||||
lng: -90.2,
|
||||
city: 'St Louis',
|
||||
code: 'STL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 43.65,
|
||||
lng: -79.38,
|
||||
city: 'Toronto',
|
||||
code: 'TOR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 49.28,
|
||||
lng: -123.12,
|
||||
city: 'Vancouver',
|
||||
code: 'VAN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 4.71,
|
||||
lng: -74.07,
|
||||
city: 'Bogota',
|
||||
code: 'BOG',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -34.61,
|
||||
lng: -58.38,
|
||||
city: 'Buenos Aires',
|
||||
code: 'BUE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -25.43,
|
||||
lng: -49.27,
|
||||
city: 'Curitiba',
|
||||
code: 'CUR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -3.73,
|
||||
lng: -38.52,
|
||||
city: 'Fortaleza',
|
||||
code: 'FOR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -12.05,
|
||||
lng: -77.04,
|
||||
city: 'Lima',
|
||||
code: 'LIM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -23.55,
|
||||
lng: -46.63,
|
||||
city: 'São Paulo',
|
||||
code: 'SAO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.45,
|
||||
lng: -70.67,
|
||||
city: 'Santiago',
|
||||
code: 'SCL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -22.91,
|
||||
lng: -43.17,
|
||||
city: 'Rio de Janeiro',
|
||||
code: 'RIO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 52.37,
|
||||
lng: 4.89,
|
||||
city: 'Amsterdam',
|
||||
code: 'AMS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 55.68,
|
||||
lng: 12.57,
|
||||
city: 'Copenhagen',
|
||||
code: 'CPH',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 50.85,
|
||||
lng: 4.35,
|
||||
city: 'Brussels',
|
||||
code: 'BRU',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 53.35,
|
||||
lng: -6.26,
|
||||
city: 'Dublin',
|
||||
code: 'DUB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 50.11,
|
||||
lng: 8.68,
|
||||
city: 'Frankfurt',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 60.17,
|
||||
lng: 24.94,
|
||||
city: 'Helsinki',
|
||||
code: 'HEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.72,
|
||||
lng: -9.14,
|
||||
city: 'Lisbon',
|
||||
code: 'LIS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 51.51,
|
||||
lng: -0.13,
|
||||
city: 'London',
|
||||
code: 'LON',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 40.42,
|
||||
lng: -3.7,
|
||||
city: 'Madrid',
|
||||
code: 'MAD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 53.48,
|
||||
lng: -2.24,
|
||||
city: 'Manchester',
|
||||
code: 'MAN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 43.3,
|
||||
lng: 5.37,
|
||||
city: 'Marseille',
|
||||
code: 'MRS',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 45.46,
|
||||
lng: 9.19,
|
||||
city: 'Milan',
|
||||
code: 'MIL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.14,
|
||||
lng: 11.58,
|
||||
city: 'Munich',
|
||||
code: 'MUN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 59.91,
|
||||
lng: 10.75,
|
||||
city: 'Oslo',
|
||||
code: 'OSL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 38.12,
|
||||
lng: 13.36,
|
||||
city: 'Palermo',
|
||||
code: 'PAL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'PAR',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 41.9,
|
||||
lng: 12.5,
|
||||
city: 'Rome',
|
||||
code: 'ROM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 42.7,
|
||||
lng: 23.32,
|
||||
city: 'Sofia',
|
||||
code: 'SOF',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 59.33,
|
||||
lng: 18.07,
|
||||
city: 'Stockholm',
|
||||
code: 'STO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.21,
|
||||
lng: 16.37,
|
||||
city: 'Vienna',
|
||||
code: 'VIE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 5.56,
|
||||
lng: -0.2,
|
||||
city: 'Accra',
|
||||
code: 'ACC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.93,
|
||||
lng: 18.42,
|
||||
city: 'Cape Town',
|
||||
code: 'CPT',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -26.2,
|
||||
lng: 28.05,
|
||||
city: 'Johannesburg',
|
||||
code: 'JHB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 13.75,
|
||||
lng: 100.5,
|
||||
city: 'Bangkok',
|
||||
code: 'BKK',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 13.08,
|
||||
lng: 80.28,
|
||||
city: 'Chennai',
|
||||
code: 'CHE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.27,
|
||||
lng: 55.3,
|
||||
city: 'Dubai',
|
||||
code: 'DXB',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 25.12,
|
||||
lng: 56.33,
|
||||
city: 'Fujairah',
|
||||
code: 'FUJ',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 22.32,
|
||||
lng: 114.17,
|
||||
city: 'Hong Kong',
|
||||
code: 'HK',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 17.38,
|
||||
lng: 78.48,
|
||||
city: 'Hyderabad',
|
||||
code: 'HYD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 22.57,
|
||||
lng: 88.36,
|
||||
city: 'Kolkata',
|
||||
code: 'KOL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 3.14,
|
||||
lng: 101.69,
|
||||
city: 'Kuala Lumpur',
|
||||
code: 'KL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 14.6,
|
||||
lng: 120.98,
|
||||
city: 'Manila',
|
||||
code: 'MNL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 19.08,
|
||||
lng: 72.88,
|
||||
city: 'Mumbai',
|
||||
code: 'MUM',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 28.61,
|
||||
lng: 77.21,
|
||||
city: 'New Delhi',
|
||||
code: 'DEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 34.69,
|
||||
lng: 135.5,
|
||||
city: 'Osaka',
|
||||
code: 'OSA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 37.57,
|
||||
lng: 126.98,
|
||||
city: 'Seoul',
|
||||
code: 'SEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 1.35,
|
||||
lng: 103.82,
|
||||
city: 'Singapore',
|
||||
code: 'SIN',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 35.69,
|
||||
lng: 139.69,
|
||||
city: 'Tokyo',
|
||||
code: 'TYO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -34.93,
|
||||
lng: 138.6,
|
||||
city: 'Adelaide',
|
||||
code: 'ADL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -36.85,
|
||||
lng: 174.76,
|
||||
city: 'Auckland',
|
||||
code: 'AKL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -27.47,
|
||||
lng: 153.03,
|
||||
city: 'Brisbane',
|
||||
code: 'BNE',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -43.53,
|
||||
lng: 172.64,
|
||||
city: 'Christchurch',
|
||||
code: 'CHC',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -37.81,
|
||||
lng: 144.96,
|
||||
city: 'Melbourne',
|
||||
code: 'MEL',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -31.95,
|
||||
lng: 115.86,
|
||||
city: 'Perth',
|
||||
code: 'PER',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'SYD',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -41.29,
|
||||
lng: 174.78,
|
||||
city: 'Wellington',
|
||||
code: 'WLG',
|
||||
available: true
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
lat: 37.77,
|
||||
lng: -122.42,
|
||||
city: 'San Francisco',
|
||||
code: 'SFO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'AUS',
|
||||
available: true
|
||||
}
|
||||
],
|
||||
regions: [
|
||||
{
|
||||
lat: 37.77,
|
||||
lng: -122.42,
|
||||
city: 'San Francisco',
|
||||
code: 'SFO',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: 48.86,
|
||||
lng: 2.35,
|
||||
city: 'Paris',
|
||||
code: 'FRA',
|
||||
available: true
|
||||
},
|
||||
{
|
||||
lat: -33.87,
|
||||
lng: 151.21,
|
||||
city: 'Sydney',
|
||||
code: 'AUS',
|
||||
available: true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
type PinSegment = keyof typeof pins;
|
||||
|
||||
let mouse = $state({ x: 0, y: 0 });
|
||||
let animate = $state(true);
|
||||
let activeRegion = $state<string | null>(null);
|
||||
let hasActiveMarker = $state(false);
|
||||
let activeMarker: HTMLElement | null = null;
|
||||
|
||||
let activeSegment = $state<string>('pop-locations');
|
||||
|
||||
$effect(() => {
|
||||
console.log(pins[activeSegment as PinSegment]);
|
||||
});
|
||||
const { action: mousePosition, position } = useMousePosition();
|
||||
const { action: inView, animate } = useAnimateInView({});
|
||||
|
||||
const useMousePosition = (node: HTMLElement) => {
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
mouse = {
|
||||
x: event.clientX,
|
||||
y: event.clientY
|
||||
};
|
||||
};
|
||||
|
||||
inView(
|
||||
node,
|
||||
() => {
|
||||
node.addEventListener('mousemove', handleMouseMove);
|
||||
},
|
||||
{ amount: 'all' }
|
||||
);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
node.removeEventListener('mousemove', handleMouseMove);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const useInView = (node: HTMLElement) => {
|
||||
inView(
|
||||
node,
|
||||
() => {
|
||||
animate = true;
|
||||
},
|
||||
{ amount: 'all' }
|
||||
);
|
||||
};
|
||||
|
||||
const scrollMarkerIntoView = (marker: HTMLElement): Promise<void> => {
|
||||
const scrollMarkerIntoView = (marker: HTMLElement) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
marker.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
@@ -726,19 +50,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
// Handle marker click
|
||||
const handleSetActiveMarker = async (city: string) => {
|
||||
const citySlug = slugify(city);
|
||||
|
||||
// Toggle off if already active
|
||||
if (activeRegion === citySlug) {
|
||||
hasActiveMarker = false;
|
||||
activeMarker = null;
|
||||
activeRegion = null;
|
||||
return;
|
||||
}
|
||||
|
||||
hasActiveMarker = true;
|
||||
activeMarker = document.querySelector(`[data-region="${citySlug}"]`);
|
||||
|
||||
if (activeMarker) {
|
||||
@@ -748,22 +68,22 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="absolute">
|
||||
<div class="absolute top-20 left-0 flex flex-col gap-4">
|
||||
{#each Object.entries(MAP_BOUNDS) as [bound, value]}
|
||||
<input
|
||||
{value}
|
||||
type="number"
|
||||
step="1"
|
||||
class="w-full"
|
||||
name="val"
|
||||
onchange={(e) =>
|
||||
(MAP_BOUNDS[bound as 'north' | 'south' | 'east' | 'west'] =
|
||||
e.currentTarget.valueAsNumber)}
|
||||
onchange={(e) => {
|
||||
MAP_BOUNDS[bound as keyof typeof MAP_BOUNDS] = e.currentTarget.valueAsNumber;
|
||||
}}
|
||||
{value}
|
||||
/>
|
||||
<label for="val">{bound}: {value}</label>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<pre>
|
||||
{JSON.stringify(MAP_BOUNDS, null, 4)}
|
||||
</pre>
|
||||
|
||||
<div class="w-full overflow-scroll [scrollbar-width:none]">
|
||||
<div
|
||||
class="sticky left-0 z-10 mb-8 flex w-screen gap-2 overflow-scroll px-8 [scrollbar-width:none] md:hidden"
|
||||
@@ -787,9 +107,8 @@
|
||||
|
||||
<div
|
||||
class="relative container mx-auto flex h-full w-[250vw] flex-col justify-center overflow-scroll py-10 transition-all delay-250 duration-250 md:w-fit md:flex-row md:overflow-auto md:py-0"
|
||||
use:useMousePosition
|
||||
use:useInView
|
||||
data-active-marker={hasActiveMarker}
|
||||
use:inView
|
||||
use:mousePosition
|
||||
>
|
||||
<div
|
||||
class="map relative w-full origin-bottom overflow-scroll transition-all [scrollbar-width:none]"
|
||||
@@ -805,16 +124,16 @@
|
||||
'from-accent bg-radial-[circle_at_center] via-white/70 to-white/70',
|
||||
'transform-[translate3d(calc(var(--mouse-x,_-100%)_*_1_-_16rem),_calc(var(--mouse-y,_-100%)_*_1_-_28rem),0)]'
|
||||
)}
|
||||
style:--mouse-x="{mouse.x}px"
|
||||
style:--mouse-y="{mouse.y}px"
|
||||
style:--mouse-x="{$position.x}px"
|
||||
style:--mouse-y="{$position.y}px"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<img src="/images/regions/map.svg" class="opacity-10" alt="Map of the world" />
|
||||
|
||||
<Tooltip.Provider delayDuration={0} skipDelayDuration={500} disableCloseOnTriggerClick>
|
||||
{#each pins[activeSegment as PinSegment].map( (pin) => ({ ...pin, isOpen: activeRegion === slugify(pin.city), position: latLongToSvgPosition( { latitude: pin.lat, longitude: pin.lng } ) }) ) as pin, index}
|
||||
<MapMarker {...pin} {animate} {index} bounds={MAP_BOUNDS} {showDebugInfo} />
|
||||
{#each pins[activeSegment as PinSegment].map( (pin) => ({ ...pin, isOpen: activeRegion === slugify(pin.city), position: latLongToSvgPosition( { latitude: pin.lat, longitude: pin.lng, width, height } ) }) ) as pin, index}
|
||||
<MapMarker {...pin} animate={$animate} {index} bounds={MAP_BOUNDS} />
|
||||
{/each}
|
||||
</Tooltip.Provider>
|
||||
</div>
|
||||
|
||||
48
src/lib/components/appwrite-network/utils/projections.ts
Normal file
48
src/lib/components/appwrite-network/utils/projections.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { MAP_BOUNDS } from '../map.svelte';
|
||||
|
||||
type Coordinates = {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
};
|
||||
|
||||
type PixelPosition = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
export const latLongToSvgPosition = ({
|
||||
latitude,
|
||||
longitude,
|
||||
width,
|
||||
height
|
||||
}: Coordinates & { width: number; height: number }) => {
|
||||
let adjustedLong = longitude;
|
||||
if (longitude < MAP_BOUNDS.west) {
|
||||
adjustedLong += 360;
|
||||
} else if (longitude > MAP_BOUNDS.east) {
|
||||
adjustedLong -= 360;
|
||||
}
|
||||
|
||||
const x = ((adjustedLong - MAP_BOUNDS.west) / (MAP_BOUNDS.east - MAP_BOUNDS.west)) * width;
|
||||
const latRatio = (MAP_BOUNDS.north - latitude) / (MAP_BOUNDS.north - MAP_BOUNDS.south);
|
||||
|
||||
const adjustedLatRatio = Math.pow(latRatio, 0.95) * 0.96 + latRatio * 0.04;
|
||||
const y = adjustedLatRatio * height;
|
||||
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
export const svgPositionToLatLong = ({
|
||||
width,
|
||||
height,
|
||||
...position
|
||||
}: PixelPosition & { width: number; height: number }) => {
|
||||
const longitude = MAP_BOUNDS.west + (position.x / width) * (MAP_BOUNDS.east - MAP_BOUNDS.west);
|
||||
const normalizedY = position.y / height;
|
||||
const latRatio =
|
||||
normalizedY > 0.5 ? normalizedY * 1.02 - 0.01 : Math.pow(normalizedY / 0.96, 1 / 0.95);
|
||||
|
||||
const latitude = MAP_BOUNDS.north - latRatio * (MAP_BOUNDS.north - MAP_BOUNDS.south);
|
||||
|
||||
return { latitude, longitude };
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
.prose {
|
||||
/* .prose {
|
||||
--prose-color: var(--color-gray-700);
|
||||
--prose-heading-color: var(--color-gray-950);
|
||||
--prose-strong-color: var(--color-gray-950);
|
||||
@@ -301,4 +301,4 @@
|
||||
max-width: calc(100% + calc(var(--spacing) * 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
Reference in New Issue
Block a user