From ac2f5bc431991ebc80cf1d85c5d5644eb715e619 Mon Sep 17 00:00:00 2001 From: syoul Date: Mon, 23 Mar 2026 22:25:26 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20vrai=20crossfade=20simultan=C3=A9=20?= =?UTF-8?q?=E2=80=94=20canvas=20fade-in=20+=20overlay=20fade-out=20en=20m?= =?UTF-8?q?=C3=AAme=20temps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/components/HeatMap.tsx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/HeatMap.tsx b/src/components/HeatMap.tsx index 86831f2..03cf5b5 100644 --- a/src/components/HeatMap.tsx +++ b/src/components/HeatMap.tsx @@ -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(() => { if (!heatRef.current || !mapRef.current) return; @@ -91,7 +91,7 @@ export function HeatMap({ transactions }: HeatMapProps) { return; } - // 1. Freeze previous frame in overlay (canvas still at opacity 1) + // 1. Capture old frame into overlay try { overlay.src = canvas.toDataURL(); } catch { @@ -99,18 +99,27 @@ export function HeatMap({ transactions }: HeatMapProps) { return; } - // 2. Snap overlay visible — cancel any running transition first + // 2. Snap overlay to visible, cancel any running transition overlay.style.transition = 'none'; - void overlay.offsetWidth; // flush 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(); - // 4. After Leaflet redraws: dissolve overlay away, revealing new frame + // 5. Simultaneously: canvas fades in, overlay fades out → true crossfade const raf = 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'; }); });