fix: vrai crossfade simultané — canvas fade-in + overlay fade-out en même temps
ci/woodpecker/push/woodpecker Pipeline was successful

Avant : overlay se dissout mais le canvas apparaît instantanément en dessous.
Maintenant : canvas part à opacity 0, les deux transitions démarrent en même temps
→ ancienne frame fade out pendant que la nouvelle fade in simultanément.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
syoul
2026-03-23 22:25:26 +01:00
parent 2debc3587a
commit ac2f5bc431
+16 -7
View File
@@ -65,7 +65,7 @@ export function HeatMap({ transactions }: HeatMapProps) {
}; };
}, []); }, []);
// Crossfade: capture current heatmap → update underneath → fade out overlay // True crossfade: old frame (overlay) fades out WHILE new frame (canvas) fades in simultaneously
useEffect(() => { useEffect(() => {
if (!heatRef.current || !mapRef.current) return; if (!heatRef.current || !mapRef.current) return;
@@ -91,7 +91,7 @@ export function HeatMap({ transactions }: HeatMapProps) {
return; return;
} }
// 1. Freeze previous frame in overlay (canvas still at opacity 1) // 1. Capture old frame into overlay
try { try {
overlay.src = canvas.toDataURL(); overlay.src = canvas.toDataURL();
} catch { } catch {
@@ -99,18 +99,27 @@ export function HeatMap({ transactions }: HeatMapProps) {
return; return;
} }
// 2. Snap overlay visible cancel any running transition first // 2. Snap overlay to visible, cancel any running transition
overlay.style.transition = 'none'; overlay.style.transition = 'none';
void overlay.offsetWidth; // flush
overlay.style.opacity = '1'; overlay.style.opacity = '1';
// 3. Update canvas underneath (canvas always at opacity 1, covered by overlay) // 3. Hide canvas (new frame will fade in from here)
canvas.style.transition = 'none';
canvas.style.opacity = '0';
// flush both
void overlay.offsetWidth;
// 4. Draw new data onto canvas (invisible at opacity 0)
update(); update();
// 4. After Leaflet redraws: dissolve overlay away, revealing new frame // 5. Simultaneously: canvas fades in, overlay fades out → true crossfade
const raf = requestAnimationFrame(() => { const raf = requestAnimationFrame(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
overlay.style.transition = 'opacity 0.5s ease-in-out'; const DURATION = '0.55s ease-in-out';
canvas.style.transition = `opacity ${DURATION}`;
canvas.style.opacity = '1';
overlay.style.transition = `opacity ${DURATION}`;
overlay.style.opacity = '0'; overlay.style.opacity = '0';
}); });
}); });