🗺️ Fix: Convertit aussi le globe (vague planétaire) en Leaflet

Même problème que la carte d'observation : le globe des 13 villes de la
diaspora dessinait des continents à main levée sur un canvas vide. Remplacé
par la même carte Leaflet + OSM, marqueurs colorés (or pour la Caraïbe,
turquoise ailleurs), popup nom + date au clic. Le chunk Leaflet est partagé
entre les deux îlots (un seul téléchargement).

Supprime les polygones de continents simplifiés devenus inutiles
(src/islands/globe/world.js) et la classe CSS .island-canvas orpheline.
Corrige aussi le texte d'aide ("glisser pour tourner" → "glisser pour
déplacer", plus juste pour une carte plate que pour un globe 3D).

Bump CACHE_NAME du service worker (v1 → v2) : découvert pendant le debug
que la stratégie stale-while-revalidate servait l'ancien composant aux
visiteurs déjà passés sur le site malgré le nouveau déploiement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sucupira
2026-07-06 20:15:10 -04:00
parent 4af585d778
commit 142bc0c9df
8 changed files with 70 additions and 162 deletions
+65 -91
View File
@@ -1,107 +1,81 @@
<script>
import { onMount } from "svelte";
import { worldData, waveCities } from "./world.js";
import { onMount, onDestroy } from "svelte";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { waveCities } from "./world.js";
let canvas = $state();
let activeCity = $state(null);
let mapContainer = $state();
let map;
function project(lon, lat, width, height) {
const x = ((lon + 180) / 360) * width;
const y = ((90 - lat) / 180) * height;
return { x, y };
}
function draw() {
if (!canvas) return;
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio || 1;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
canvas.width = width * dpr;
canvas.height = height * dpr;
ctx.scale(dpr, dpr);
ctx.clearRect(0, 0, width, height);
const styles = getComputedStyle(canvas);
const gold = styles.getPropertyValue("--gold-surface").trim() || "#e8c766";
const teal = styles.getPropertyValue("--caribbean-teal").trim() || "#3a9088";
const border = styles.getPropertyValue("--border").trim() || "#333";
ctx.fillStyle = border;
worldData.features.forEach((feature) => {
ctx.beginPath();
feature.geometry.coordinates[0].forEach(([lon, lat], i) => {
const { x, y } = project(lon, lat, width, height);
if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
});
ctx.closePath();
ctx.fill();
function markerIcon(active) {
return L.divIcon({
className: "wave-marker" + (active ? " wave-marker-active" : ""),
iconSize: active ? [20, 20] : [14, 14],
iconAnchor: active ? [10, 10] : [7, 7],
});
waveCities.forEach((city) => {
const { x, y } = project(city.lon, city.lat, width, height);
ctx.beginPath();
ctx.arc(x, y, city.name === activeCity?.name ? 7 : 4, 0, Math.PI * 2);
ctx.fillStyle = city.name === "Guadeloupe" || city.name === "Martinique" ? gold : teal;
ctx.fill();
});
}
function pickCity(clientX, clientY) {
const rect = canvas.getBoundingClientRect();
const x = clientX - rect.left;
const y = clientY - rect.top;
let closest = null;
let closestDist = Infinity;
waveCities.forEach((city) => {
const p = project(city.lon, city.lat, rect.width, rect.height);
const dist = Math.hypot(p.x - x, p.y - y);
if (dist < closestDist) {
closestDist = dist;
closest = city;
}
});
activeCity = closestDist < 30 ? closest : null;
draw();
}
onMount(() => {
draw();
const onResize = () => draw();
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
map = L.map(mapContainer, { scrollWheelZoom: false });
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18,
}).addTo(map);
const markers = waveCities.map((city) => {
const isCaribbean = city.name === "Guadeloupe" || city.name === "Martinique";
const marker = L.marker([city.lat, city.lon], {
icon: markerIcon(isCaribbean),
}).addTo(map);
marker.bindPopup(`<strong>${city.name}</strong><br>${city.date}`);
marker.on("popupopen", () => marker.setIcon(markerIcon(true)));
marker.on("popupclose", () => marker.setIcon(markerIcon(isCaribbean)));
return marker;
});
const group = L.featureGroup(markers);
map.fitBounds(group.getBounds().pad(0.15));
});
onDestroy(() => {
map?.remove();
});
</script>
<div class="sirius-globe">
<canvas
bind:this={canvas}
class="island-canvas"
aria-label="Carte de la progression du lever héliaque à travers l'Afrique et les Caraïbes, touchez une ville pour voir sa date"
tabindex="0"
onmousemove={(e) => pickCity(e.clientX, e.clientY)}
onmouseleave={() => { activeCity = null; draw(); }}
onclick={(e) => pickCity(e.clientX, e.clientY)}
></canvas>
<p class="globe-caption" aria-live="polite">
{#if activeCity}
<strong>{activeCity.name}</strong>{activeCity.date}
{:else}
&nbsp;
{/if}
</p>
</div>
<div
bind:this={mapContainer}
class="wave-map"
role="group"
aria-label="Carte de la progression du lever héliaque à travers l'Afrique et les Caraïbes"
></div>
<style>
.island-canvas {
cursor: crosshair;
.wave-map {
width: 100%;
height: 22rem;
border-radius: var(--radius-md);
overflow: hidden;
}
.globe-caption {
text-align: center;
min-height: 1.5em;
color: var(--gold);
font-weight: 600;
:global(.wave-marker) {
background: var(--caribbean-teal);
border: 2px solid oklch(20% 0.03 265);
border-radius: 50%;
box-shadow: var(--shadow-sm);
}
:global(.wave-marker-active) {
background: var(--gold-surface);
}
:global(.leaflet-popup-content-wrapper) {
background: var(--surface-raised);
color: var(--ink);
border-radius: var(--radius-sm);
}
:global(.leaflet-popup-tip) {
background: var(--surface-raised);
}
</style>
-60
View File
@@ -1,63 +1,3 @@
// Continents simplifiés (issus de Natural Earth, tracé approximatif) —
// utilisés uniquement comme repère visuel derrière la vague du lever héliaque.
export const worldData = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: { name: "Africa" },
geometry: {
type: "Polygon",
coordinates: [[
[-17.5, 35], [-5, 36], [10, 37], [35, 30], [42, 15],
[51, 12], [51, -2], [41, -12], [35, -25], [28, -33],
[20, -35], [18, -35], [12, -18], [10, -5], [8, 5],
[-5, 5], [-17, 15], [-17.5, 35],
]],
},
},
{
type: "Feature",
properties: { name: "Europe" },
geometry: {
type: "Polygon",
coordinates: [[
[-10, 36], [-5, 43], [0, 50], [10, 54], [20, 59],
[30, 60], [40, 55], [30, 45], [20, 40], [10, 45],
[0, 40], [-10, 36],
]],
},
},
{
type: "Feature",
properties: { name: "North America" },
geometry: {
type: "Polygon",
coordinates: [[
[-170, 65], [-165, 68], [-150, 70], [-130, 70], [-100, 70],
[-80, 68], [-65, 60], [-55, 50], [-65, 45], [-75, 40],
[-80, 35], [-85, 30], [-90, 25], [-95, 20], [-105, 20],
[-110, 25], [-115, 30], [-120, 35], [-125, 40], [-130, 45],
[-135, 50], [-140, 55], [-150, 58], [-160, 60], [-170, 65],
]],
},
},
{
type: "Feature",
properties: { name: "South America" },
geometry: {
type: "Polygon",
coordinates: [[
[-35, -5], [-38, -15], [-40, -20], [-48, -25], [-58, -35],
[-65, -45], [-70, -55], [-68, -55], [-73, -45], [-72, -35],
[-70, -25], [-75, -15], [-78, -5], [-80, 0], [-77, 5],
[-75, 10], [-70, 12], [-60, 8], [-50, 5], [-35, -5],
]],
},
},
],
};
// Progression du lever héliaque à travers la diaspora africaine et caribéenne
// (fin juin à mi-août), du plus oriental au plus occidental.
export const waveCities = [
-7
View File
@@ -8,10 +8,3 @@
[data-island].is-enhanced .island-fallback {
display: none;
}
.island-canvas {
width: 100%;
height: 22rem;
border-radius: var(--radius-md);
background: var(--surface-sunk);
}