🗺️ 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
+1
View File
@@ -22,6 +22,7 @@ Refonte complète (v2) : passage d'une SPA Vite+Svelte 4 à un site **11ty** sta
2. **Alias `/src`** : `eleventy-plugin-vite` fait tourner Vite avec pour racine une copie du dossier de **sortie** (`_site`), pas la racine du projet. Toute référence absolue à un fichier source (`/src/styles/app.css`, `/src/islands/.../mount.js`) nécessite l'alias `resolve.alias["/src"]` défini dans `eleventy.config.js`.
3. **Dates ISO sans heure** : `new Date("2026-07-22")` est interprété en UTC ; formaté en heure locale Guadeloupe (UTC-4), ça peut reculer d'un jour. Toujours parser les composants (`year, month, day`) et construire la date en local — voir le filtre `formatDate` et `PredictionsCalculator.svelte`.
4. **Slinkity est abandonné** (son créateur travaille sur Astro) : ne pas l'utiliser pour l'intégration 11ty+Svelte, `eleventy-plugin-vite` (officiel) est la voie robuste.
5. **Service worker et cache obsolète** : la stratégie stale-while-revalidate de `public/sw.js` peut servir une version périmée des îlots (vécu pendant le debug de la carte : un visiteur déjà passé sur le site voyait l'ancien composant malgré un déploiement). **Toujours incrémenter `CACHE_NAME` dans `sw.js`** quand un îlot ou un asset critique change, sinon les visiteurs récurrents restent bloqués sur l'ancienne version jusqu'à revalidation.
## 🔄 Améliorations possibles
+1 -1
View File
@@ -192,7 +192,7 @@
"globe_title": "The wave phenomenon",
"globe_p1": "The heliacal rising of Sirius does not happen simultaneously across the Earth. Like a cosmic wave, it moves from East to West, first reaching Réunion in late June, then sweeping across Africa, before finally reaching the Caribbean in July.",
"globe_p2": "This animation shows the progression of this \"planetary wave\", following Earth's rotation and the position of Sirius in the sky. Each place experiences this sacred moment on a precise date, forming a natural cosmic calendar that has guided civilisations for millennia.",
"globe_controls_hint": "Drag to rotate · scroll to zoom",
"globe_controls_hint": "Drag to pan · scroll to zoom",
"globe_timeline_title": "Timeline of the wave",
"associations_title": "Associations celebrating Wep Ronpet",
+1 -1
View File
@@ -192,7 +192,7 @@
"globe_title": "Le phénomène de la vague",
"globe_p1": "Le lever héliaque de Sirius ne se produit pas simultanément sur toute la Terre. Telle une vague cosmique, il progresse d'Est en Ouest, touchant d'abord La Réunion fin juin, puis traversant l'Afrique, pour finalement atteindre les Caraïbes en juillet.",
"globe_p2": "Cette animation montre la progression de cette « vague planétaire » qui suit la rotation terrestre et la position de Sirius dans le ciel. Chaque lieu expérimente ce moment sacré à une date précise, créant un calendrier cosmique naturel qui a guidé les civilisations pendant des millénaires.",
"globe_controls_hint": "Glisser pour tourner · molette pour zoomer",
"globe_controls_hint": "Glisser pour déplacer · molette pour zoomer",
"globe_timeline_title": "Chronologie de la vague",
"associations_title": "Associations qui fêtent le Wep Ronpet",
+1 -1
View File
@@ -75,7 +75,7 @@
"observer_tips_title": "Konsèy pratik",
"globe_title": "Fenomèn vag la",
"globe_controls_hint": "Trennen pou vire · molèt pou zoome",
"globe_controls_hint": "Trennen pou deplase · molèt pou zoome",
"associations_title": "Asosyasyon ki fete Wep Ronpet",
"associations_subtitle": "Dekouvri evènman ak kominote ki selebre Nouvèl An Kamit la",
+1 -1
View File
@@ -1,6 +1,6 @@
// Service worker minimal : résilience réseau (3G/4G irrégulier) et usage
// hors-ligne des pages déjà visitées. Stratégie stale-while-revalidate.
const CACHE_NAME = "gwada-sirius-v1";
const CACHE_NAME = "gwada-sirius-v2";
self.addEventListener("install", (event) => {
self.skipWaiting();
+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);
}