perf: cache polygon conversions to fix performance regression

CRITICAL PERFORMANCE FIX: Converting SVG paths to Polygons on every mouse
move was causing severe lag. Cache the polygons per region ID.

Problem:
- pathToPolygon() samples 50 points using getTotalLength() + getPointAtLength()
- This was being called for EVERY region on EVERY mouse move
- For world map with ~200 regions, this was 200 expensive conversions per frame
- Completely unusable performance

Solution:
- Cache Polygon objects in a Map<regionId, Polygon>
- Only compute polygon once per region, reuse on subsequent detections
- Clear cache when map data changes (continent/map selection)

Performance improvement:
- Before: ~200 polygon conversions per mouse move
- After: ~200 polygon conversions total (one-time cost), 0 per mouse move
- Detection now runs at full frame rate

🤖 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 07:08:42 -06:00
parent 743adae92d
commit 348ce8f314
1 changed files with 15 additions and 3 deletions

View File

@ -15,7 +15,7 @@
* bounding boxes. This prevents false positives from irregularly shaped regions.
*/
import { useState, useCallback, type RefObject } from 'react'
import { useState, useCallback, useRef, useEffect, type RefObject } from 'react'
import type { MapData } from '../types'
import { Polygon, Box, point as Point } from '@flatten-js/core'
@ -120,6 +120,14 @@ export function useRegionDetection(options: UseRegionDetectionOptions): UseRegio
const [hoveredRegion, setHoveredRegion] = useState<string | null>(null)
// Cache polygons to avoid expensive recomputation on every mouse move
const polygonCache = useRef<Map<string, Polygon>>(new Map())
// Clear cache when map data changes
useEffect(() => {
polygonCache.current.clear()
}, [mapData])
/**
* Detect regions at the given cursor position.
*
@ -218,8 +226,12 @@ export function useRegionDetection(options: UseRegionDetectionOptions): UseRegio
// For overlap detection, use flatten-js for precise geometric intersection
try {
// Convert region path to Polygon (in SVG coordinates)
const regionPolygon = pathToPolygon(regionPath)
// Get or create cached polygon for this region
let regionPolygon = polygonCache.current.get(region.id)
if (!regionPolygon) {
regionPolygon = pathToPolygon(regionPath)
polygonCache.current.set(region.id, regionPolygon)
}
// Convert detection box to SVG coordinates
const boxTopLeft = svgElement.createSVGPoint()