fix: crossfade simplifié — canvas toujours visible, seul l'overlay se dissout
ci/woodpecker/push/woodpecker Pipeline was successful

Le canvas reste toujours à opacity 1. Quand les transactions changent :
1. Capture le canvas dans l'overlay img (snap à opacity 1 sans transition)
2. Met à jour le canvas en dessous
3. Double rAF pour laisser Leaflet.heat redessiner
4. Dissout l'overlay de 1→0 en 500ms via CSS transition

Élimine le double-affichage et les conflits de transition canvas/overlay.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
syoul
2026-03-23 22:18:15 +01:00
parent 8a31b60716
commit 2debc3587a
+7 -15
View File
@@ -91,12 +91,7 @@ export function HeatMap({ transactions }: HeatMapProps) {
return; return;
} }
// 1. Cancel any running overlay transition instantly (flush only the overlay) // 1. Freeze previous frame in overlay (canvas still at opacity 1)
overlay.style.transition = 'none';
overlay.style.opacity = '0';
void overlay.offsetWidth; // flush overlay only — avoids double-paint with canvas
// 2. Capture current frame (canvas still visible at opacity 1)
try { try {
overlay.src = canvas.toDataURL(); overlay.src = canvas.toDataURL();
} catch { } catch {
@@ -104,22 +99,19 @@ export function HeatMap({ transactions }: HeatMapProps) {
return; return;
} }
// 3. In one paint batch: hide canvas + show overlay (Frame A moves from canvas to overlay) // 2. Snap overlay visible — cancel any running transition first
canvas.style.transition = 'none'; overlay.style.transition = 'none';
canvas.style.opacity = '0'; void overlay.offsetWidth; // flush
overlay.style.opacity = '1'; overlay.style.opacity = '1';
// 4. Update heatmap (invisible: canvas at opacity 0) // 3. Update canvas underneath (canvas always at opacity 1, covered by overlay)
update(); update();
// 5. Simultaneous crossfade: overlay fades out, canvas fades in // 4. After Leaflet redraws: dissolve overlay away, revealing new frame
const raf = requestAnimationFrame(() => { const raf = requestAnimationFrame(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
const DURATION = '0.5s ease-in-out'; overlay.style.transition = 'opacity 0.5s ease-in-out';
overlay.style.transition = `opacity ${DURATION}`;
overlay.style.opacity = '0'; overlay.style.opacity = '0';
canvas.style.transition = `opacity ${DURATION}`;
canvas.style.opacity = '1';
}); });
}); });