From d7fef466f3c2bf0178f3e17bbc610a6fed1ef4e5 Mon Sep 17 00:00:00 2001 From: syoul Date: Mon, 23 Mar 2026 22:00:42 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20vrai=20crossfade=20simultan=C3=A9=20?= =?UTF-8?q?=E2=80=94=20canvas=20masqu=C3=A9=20puis=20fade=20in+out=20en=20?= =?UTF-8?q?parall=C3=A8le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Canvas caché (opacity 0) avant update → overlay (frame A) fade out et canvas (frame B) fade in simultanément sur 500ms. Co-Authored-By: Claude Sonnet 4.6 --- src/components/HeatMap.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/HeatMap.tsx b/src/components/HeatMap.tsx index 98db3e7..9c67cd7 100644 --- a/src/components/HeatMap.tsx +++ b/src/components/HeatMap.tsx @@ -91,25 +91,33 @@ export function HeatMap({ transactions }: HeatMapProps) { return; } - // Freeze current frame in the overlay + // 1. Hide canvas instantly (no transition) + canvas.style.transition = 'none'; + canvas.style.opacity = '0'; + + // 2. Freeze current frame in the overlay try { overlay.src = canvas.toDataURL(); } catch { // canvas tainted (shouldn't happen with heatmap-only canvas) + canvas.style.opacity = '1'; update(); return; } overlay.style.transition = 'none'; overlay.style.opacity = '1'; - // Update heatmap underneath immediately + // 3. Update heatmap (invisible: canvas still at opacity 0) update(); - // Then dissolve the overlay away + // 4. Simultaneous crossfade: overlay fades out, canvas fades in const raf = requestAnimationFrame(() => { requestAnimationFrame(() => { - overlay.style.transition = 'opacity 0.5s ease-in-out'; + const DURATION = '0.5s ease-in-out'; + overlay.style.transition = `opacity ${DURATION}`; overlay.style.opacity = '0'; + canvas.style.transition = `opacity ${DURATION}`; + canvas.style.opacity = '1'; }); });