🗺️ 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:
@@ -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: '© <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}
|
||||
|
||||
{/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>
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user