|
|
@@ -0,0 +1,120 @@
|
|
|
+<script>
|
|
|
+ import { onMount } from 'svelte';
|
|
|
+ import 'mapbox-gl/dist/mapbox-gl.css';
|
|
|
+
|
|
|
+ let { data } = $props();
|
|
|
+
|
|
|
+ let mapEl = $state();
|
|
|
+ let webglError = $state(false);
|
|
|
+
|
|
|
+ function webgl2Available() {
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ canvas.width = 1;
|
|
|
+ canvas.height = 1;
|
|
|
+ return Boolean(canvas.getContext('webgl2'));
|
|
|
+ }
|
|
|
+
|
|
|
+ onMount(() => {
|
|
|
+ let map;
|
|
|
+ let observer;
|
|
|
+ let cancelled = false;
|
|
|
+
|
|
|
+ (async () => {
|
|
|
+ if (!data.mapboxKey || !mapEl) return;
|
|
|
+
|
|
|
+ const mod = await import('mapbox-gl');
|
|
|
+ const mapboxgl = mod.default?.Map ? mod.default : globalThis.mapboxgl;
|
|
|
+ const workerMod = await import('mapbox-gl/dist/mapbox-gl-csp-worker.js?worker');
|
|
|
+ if (cancelled || !mapEl || !mapboxgl?.Map) return;
|
|
|
+
|
|
|
+ if (!webgl2Available()) {
|
|
|
+ webglError = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ mapboxgl.workerClass = workerMod.default;
|
|
|
+ mapboxgl.accessToken = data.mapboxKey;
|
|
|
+
|
|
|
+ map = new mapboxgl.Map({
|
|
|
+ container: mapEl,
|
|
|
+ style: 'mapbox://styles/mapbox/dark-v11',
|
|
|
+ center: [-79.048, 33.553],
|
|
|
+ zoom: 10,
|
|
|
+ failIfMajorPerformanceCaveat: false
|
|
|
+ });
|
|
|
+
|
|
|
+ const resize = () => map?.resize();
|
|
|
+ map.on('load', resize);
|
|
|
+ requestAnimationFrame(resize);
|
|
|
+ observer = new ResizeObserver(resize);
|
|
|
+ observer.observe(mapEl);
|
|
|
+ })();
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ cancelled = true;
|
|
|
+ observer?.disconnect();
|
|
|
+ map?.remove();
|
|
|
+ };
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<svelte:head>
|
|
|
+ <title>Gallery — Lee Morgan</title>
|
|
|
+ <meta name="description" content="Photo galleries on a map." />
|
|
|
+</svelte:head>
|
|
|
+
|
|
|
+<div class="gallery">
|
|
|
+ <h1 class="sr-only">Gallery</h1>
|
|
|
+ {#if webglError}
|
|
|
+ <p class="missing">This browser could not start WebGL, which the map needs to draw.</p>
|
|
|
+ {:else if data.mapboxKey}
|
|
|
+ <div class="map" bind:this={mapEl}></div>
|
|
|
+ {:else}
|
|
|
+ <p class="missing">Set the MAPBOX_KEY environment variable to load the map.</p>
|
|
|
+ {/if}
|
|
|
+</div>
|
|
|
+
|
|
|
+<style>
|
|
|
+ .gallery {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .map {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .map :global(.mapboxgl-canvas-container),
|
|
|
+ .map :global(.mapboxgl-canvas) {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .map :global(.mapboxgl-ctrl-attrib) {
|
|
|
+ background: transparent;
|
|
|
+ color: var(--muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .map :global(.mapboxgl-ctrl-attrib a) {
|
|
|
+ color: var(--muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .sr-only {
|
|
|
+ position: absolute;
|
|
|
+ width: 1px;
|
|
|
+ height: 1px;
|
|
|
+ padding: 0;
|
|
|
+ margin: -1px;
|
|
|
+ overflow: hidden;
|
|
|
+ clip: rect(0, 0, 0, 0);
|
|
|
+ white-space: nowrap;
|
|
|
+ border: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .missing {
|
|
|
+ margin: 0;
|
|
|
+ padding: 2rem;
|
|
|
+ color: var(--muted);
|
|
|
+ }
|
|
|
+</style>
|