diff --git a/src/pages/StormIntelPage.jsx b/src/pages/StormIntelPage.jsx index 33d886b..0f91c07 100644 --- a/src/pages/StormIntelPage.jsx +++ b/src/pages/StormIntelPage.jsx @@ -242,6 +242,35 @@ const PinDropLayer = ({ onDrop }) => { return null; }; +const FitToPins = ({ pins, pinRadius }) => { + const map = useMap(); + const prevLen = useRef(0); + + useEffect(() => { + if (pins.length === 0) { + if (prevLen.current > 0) map.flyTo(PLANO_CENTER, DEFAULT_ZOOM, { animate: true, duration: 0.6 }); + prevLen.current = 0; + return; + } + // Only zoom when a pin is added (length increased) + if (pins.length <= prevLen.current) { prevLen.current = pins.length; return; } + prevLen.current = pins.length; + try { + const radiusM = pinRadius * 1609.34; + const latOffset = radiusM / 111319; + let bounds = null; + pins.forEach(([lat, lng]) => { + const lngOffset = latOffset / Math.cos(lat * Math.PI / 180); + const pb = L.latLngBounds([lat - latOffset, lng - lngOffset], [lat + latOffset, lng + lngOffset]); + bounds = bounds ? bounds.extend(pb) : pb; + }); + if (bounds) map.fitBounds(bounds, { padding: [50, 50], maxZoom: 12, animate: true, duration: 0.6 }); + } catch { /* ignore */ } + }, [pins, pinRadius, map]); + + return null; +}; + const StormMap = memo(({ events, selectedId, pinnedIds, onSelect, theme, flyCount, selectedStorm, stormZones, isDrawing, draftPolygon, onAddPoint, onFinishPolygon, @@ -265,8 +294,9 @@ const StormMap = memo(({ /> + - {/* Storm polygons — only selected + pinned (or all if none active) */} + {/* Storm polygons — only selected + pinned events */} {events.map(storm => { const sty = SEVERITY_STYLES[storm.severity] ?? SEVERITY_STYLES.trace; const isSelected = storm.id === selectedId; @@ -993,6 +1023,7 @@ const StormIntelPage = () => { const [pins, setPins] = useState([]); // array of [lat,lng] const [pinRadius, setPinRadius] = useState(5); // applied radius (miles) const [radiusInput, setRadiusInput] = useState('5'); // draft value in input + const [showAllOnMap, setShowAllOnMap] = useState(false); const MAX_PINS = 5; const applyRadius = useCallback(() => { @@ -1042,12 +1073,15 @@ const StormIntelPage = () => { // Sidebar shows nearby events when pins exist, otherwise full filtered list const sidebarEvents = pins.length > 0 ? nearbyEvents : displayEvents; - // Map shows: when pins exist → all nearby; else → selected+pinned only (or none until pins placed) + // Map shows: if showAllOnMap → all sidebar events; else → only selected/event-pinned. + // Location pins filter the sidebar list but don't auto-render all nearby polygons — + // NWS warning polygons can be 60-80 mi across and would visually flood the map. + const mapPool = pins.length > 0 ? nearbyEvents : displayEvents; const mapEvents = useMemo(() => { - if (pins.length > 0) return nearbyEvents; - if (!selectedStorm && pinnedIds.size === 0) return []; // nothing until pin placed - return displayEvents.filter(e => pinnedIds.has(e.id) || e.id === selectedStorm?.id); - }, [displayEvents, nearbyEvents, pins, selectedStorm, pinnedIds]); + if (showAllOnMap) return mapPool; + if (!selectedStorm && pinnedIds.size === 0) return []; + return mapPool.filter(e => pinnedIds.has(e.id) || e.id === selectedStorm?.id); + }, [mapPool, showAllOnMap, selectedStorm, pinnedIds]); const handleDropPin = useCallback((latlng) => { setPins(prev => { @@ -1407,8 +1441,8 @@ const StormIntelPage = () => { - {/* Search */} -
+ {/* Search + Show all toggle */} +
{ )}
+ {/* Show all on map toggle */} +
{/* Active pins strip */}