fix: cancel previous give-up animation when new give-up starts

When clicking Give Up multiple times quickly, the previous animation's
requestAnimationFrame calls would continue running, causing the highlight
to show on the wrong region (the new one) while the zoom was still
calculated for the old region.

Now properly cancels:
- Previous requestAnimationFrame callbacks
- Pending setTimeout callbacks
- Sets isCancelled flag to stop animation loop

This prevents the "Swaziland shown at Cape Verde's location" bug.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-25 18:54:53 -06:00
parent baf0fdaf81
commit c01cb7f384
2 changed files with 32 additions and 7 deletions

View File

@ -584,6 +584,11 @@ export function MapRenderer({
return
}
// Track if this effect has been cleaned up (prevents stale animations)
let isCancelled = false
let animationFrameId: number | null = null
let timeoutId: ReturnType<typeof setTimeout> | null = null
// Start animation
setIsGiveUpAnimating(true)
console.log('[GiveUp Zoom] giveUpReveal triggered:', giveUpReveal)
@ -647,6 +652,12 @@ export function MapRenderer({
const startTime = Date.now()
const animate = () => {
// Check if this animation has been cancelled (new give-up started)
if (isCancelled) {
console.log('[GiveUp Zoom] Animation cancelled - new give-up started')
return
}
const elapsed = Date.now() - startTime
const progress = Math.min(elapsed / duration, 1)
@ -655,22 +666,36 @@ export function MapRenderer({
setGiveUpFlashProgress(pulseProgress)
if (progress < 1) {
requestAnimationFrame(animate)
animationFrameId = requestAnimationFrame(animate)
} else {
// Animation complete - zoom back out to default
console.log('[GiveUp Zoom] Zooming back out to default')
setGiveUpZoomTarget({ scale: 1, translateX: 0, translateY: 0 })
// Clear reveal state after a short delay to let zoom-out start
setTimeout(() => {
setGiveUpFlashProgress(0)
setIsGiveUpAnimating(false)
setSavedButtonPosition(null)
timeoutId = setTimeout(() => {
if (!isCancelled) {
setGiveUpFlashProgress(0)
setIsGiveUpAnimating(false)
setSavedButtonPosition(null)
}
}, 100)
}
}
requestAnimationFrame(animate)
animationFrameId = requestAnimationFrame(animate)
// Cleanup: cancel animation if giveUpReveal changes before animation completes
return () => {
isCancelled = true
if (animationFrameId !== null) {
cancelAnimationFrame(animationFrameId)
}
if (timeoutId !== null) {
clearTimeout(timeoutId)
}
console.log('[GiveUp Zoom] Cleanup - cancelling previous animation')
}
}, [giveUpReveal?.timestamp]) // Re-run when timestamp changes
// Shift key listener - show magnifier when Shift is held

View File

@ -14,7 +14,7 @@ export interface CropOverrides {
export const customCrops: CropOverrides = {
world: {
'north-america': '-14.59 139.66 378.17 314.90',
europe: '402.41 97.98 233.00 266.05',
}
}