fix: resume zoom animation when target drops below threshold

Fixed issue where zoom animation would stay paused even when auto-zoom
wanted to zoom back out below the precision mode threshold.

**Problem:**
- Animation paused when hitting 20 px/px threshold
- If user moved to larger region, target zoom would drop
- But animation stayed paused, not resuming to zoom out

**Solution:**
- Check both CURRENT zoom and TARGET zoom thresholds
- Only pause if: current at threshold AND target also at/above threshold
- Resume if: current at threshold BUT target below threshold (zooming out)

**Pause conditions:**
- `shouldPause = currentIsAtThreshold && zoomIsAnimating && targetIsAtThreshold`
- If current is at threshold but target is safe → resume and zoom out
- If current is at threshold and target also at threshold → stay paused
- Added console log when resuming due to zoom-out

**User experience:**
- Zoom pauses at threshold when trying to zoom IN further
- Zoom resumes smoothly when auto-zoom wants to zoom OUT
- No stuck animations - always responsive to target changes

🤖 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-23 20:58:24 -06:00
parent c4989b3ab0
commit e73b59d510
1 changed files with 34 additions and 4 deletions

View File

@ -380,12 +380,11 @@ export function MapRenderer({
const currentZoom = magnifierSpring.zoom.get()
const zoomIsAnimating = Math.abs(currentZoom - targetZoom) > 0.01
// Check if we're at the threshold (zoom is capped)
const isAtThreshold =
// Check if CURRENT zoom is at/above the threshold (zoom is capped)
const currentIsAtThreshold =
!pointerLocked &&
containerRef.current &&
svgRef.current &&
zoomIsAnimating &&
(() => {
const containerRect = containerRef.current.getBoundingClientRect()
const svgRect = svgRef.current.getBoundingClientRect()
@ -403,12 +402,43 @@ export function MapRenderer({
return screenPixelRatio >= PRECISION_MODE_THRESHOLD
})()
if (isAtThreshold) {
// Check if TARGET zoom would be at/above the threshold
const targetIsAtThreshold =
!pointerLocked &&
containerRef.current &&
svgRef.current &&
(() => {
const containerRect = containerRef.current.getBoundingClientRect()
const svgRect = svgRef.current.getBoundingClientRect()
const magnifierWidth = containerRect.width * 0.5
const viewBoxParts = mapData.viewBox.split(' ').map(Number)
const viewBoxWidth = viewBoxParts[2]
if (!viewBoxWidth || isNaN(viewBoxWidth)) return false
const magnifiedViewBoxWidth = viewBoxWidth / targetZoom
const magnifierScreenPixelsPerSvgUnit = magnifierWidth / magnifiedViewBoxWidth
const mainMapSvgUnitsPerScreenPixel = viewBoxWidth / svgRect.width
const screenPixelRatio = mainMapSvgUnitsPerScreenPixel * magnifierScreenPixelsPerSvgUnit
return screenPixelRatio >= PRECISION_MODE_THRESHOLD
})()
// Pause conditions:
// 1. Currently at threshold AND animating toward even higher zoom (would exceed threshold more)
// 2. OR: Currently at threshold and target is also at threshold (should stay paused)
const shouldPause = currentIsAtThreshold && zoomIsAnimating && targetIsAtThreshold
if (shouldPause) {
// Pause the zoom animation - we're waiting for precision mode
console.log('[Zoom] Pausing at threshold - waiting for precision mode')
magnifierApi.pause()
} else {
// Update spring values and ensure it's not paused
// This will resume if we were paused and now target is below threshold (zooming out)
if (currentIsAtThreshold && !targetIsAtThreshold) {
console.log('[Zoom] Resuming - target zoom is below threshold (zooming out)')
}
magnifierApi.start({
zoom: targetZoom,
opacity: targetOpacity,