diff --git a/src/components/RegionMap.tsx b/src/components/RegionMap.tsx index f1cd6a0..13d7d3f 100644 --- a/src/components/RegionMap.tsx +++ b/src/components/RegionMap.tsx @@ -8,7 +8,6 @@ import { useQuery } from '@tanstack/react-query'; import { getSecurityColor } from '../utils/securityColors'; const pocketbaseUrl = `https://evebase.site.quack-lab.dev/api/collections/regionview/records`; -// const pocketbaseUrl = `https://evebase.site.quack-lab.dev/api/collections/regionview/records?filter=(sysregion%3D'${encodedSystem}')`; interface SolarSystem { solarSystemName: string; @@ -31,6 +30,12 @@ interface ProcessedConnection { color: string; } +interface RegionMapProps { + regionName: string; + focusSystem?: string; + isCompact?: boolean; +} + const fetchRegionData = async (regionName: string): Promise => { const response = await fetch(`/${regionName}.json`); if (!response.ok) { @@ -52,7 +57,11 @@ const fetchRegionData = async (regionName: string): Promise => { return systems; }; -export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { +export const RegionMap: React.FC = ({ + regionName, + focusSystem, + isCompact = false +}) => { const navigate = useNavigate(); const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 1200, height: 800 }); const [isPanning, setIsPanning] = useState(false); @@ -73,19 +82,13 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { systems.forEach(system => { system.connectedSystems?.forEach(connectedSystem => { - // Create a unique key by sorting system names alphabetically const connectionKey = [system.solarSystemName, connectedSystem].sort().join('-'); - - // Skip if we've already processed this connection if (connections.has(connectionKey)) return; const fromPos = nodePositions[system.solarSystemName]; const toPos = nodePositions[connectedSystem]; - - // Skip if positions are not available if (!fromPos || !toPos) return; - // Calculate average security for the connection const toSystem = systems.find(s => s.solarSystemName === connectedSystem); if (!toSystem) return; @@ -104,7 +107,7 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { return Array.from(connections.values()); }, [systems, nodePositions]); - // Initialize node positions when data is loaded + // Initialize node positions and focus on system if specified useEffect(() => { if (systems) { const positions: Record = {}; @@ -115,8 +118,21 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { }; }); setNodePositions(positions); + + // If focusSystem is specified and we're in compact mode, center on it + if (focusSystem && isCompact) { + const focusSystemData = systems.find(s => s.solarSystemName === focusSystem); + if (focusSystemData) { + setViewBox({ + x: focusSystemData.x - 200, + y: focusSystemData.y - 150, + width: 400, + height: 300 + }); + } + } } - }, [systems]); + }, [systems, focusSystem, isCompact]); const handleSystemClick = (systemName: string) => { navigate(`/systems/${systemName}`); @@ -165,7 +181,6 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { const mouseX = e.clientX - rect.left; const mouseY = e.clientY - rect.top; - // Invert scroll direction: negative deltaY (scroll up) zooms out, positive (scroll down) zooms in const scale = e.deltaY < 0 ? 1.1 : 0.9; const newWidth = viewBox.width * scale; const newHeight = viewBox.height * scale; @@ -186,7 +201,7 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { if (isLoading) { return ( -
+
Loading {regionName} data...
); @@ -194,22 +209,103 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { if (error) { return ( -
+

Error Loading Region

Failed to load data for {regionName}

- + {!isCompact && ( + + )}
); } + // Compact mode (for system page) + if (isCompact) { + return ( +
+ + + + + + + + + + + + {/* Render connections */} + {processedConnections.map(connection => ( + + ))} + + {/* Render systems */} + {systems?.map((system) => ( + handleSystemClick(system.solarSystemName)} + type="system" + security={system.security} + signatures={system.signatures} + /> + ))} + + {/* Highlight focused system */} + {focusSystem && nodePositions[focusSystem] && ( + + + + )} + +
+ ); + } + + // Full page mode (original region page) return (
@@ -252,7 +348,7 @@ export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { - {/* Render connections first (behind nodes) */} + {/* Render connections */} {processedConnections.map(connection => ( => { - const response = await fetch(`/${regionName}.json`); - if (!response.ok) { - throw new Error('Failed to fetch region data'); - } - const systems = await response.json(); - - const regionSignatures = await fetch(`${pocketbaseUrl}?filter=(sysregion%3D'${regionName}')`); - const regionSignaturesJson = await regionSignatures.json(); - - if (regionSignaturesJson.items.length > 0) { - for (const systemSigs of regionSignaturesJson.items) { - const system = systems.find(s => s.solarSystemName === systemSigs.sysname); - if (system) { - system.signatures = systemSigs.sigcount; - } - } - } - return systems; -}; - -export const RegionOverviewMap: React.FC = ({ - regionName, - currentSystem, - className = "" -}) => { - const navigate = useNavigate(); - const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 800, height: 600 }); - const [isPanning, setIsPanning] = useState(false); - const [lastPanPoint, setLastPanPoint] = useState({ x: 0, y: 0 }); - const [nodePositions, setNodePositions] = useState>({}); - const svgRef = useRef(null); - - const { data: systems, isLoading } = useQuery({ - queryKey: ['region-overview', regionName], - queryFn: () => fetchRegionData(regionName), - }); - - // Process connections - const processedConnections = useMemo(() => { - if (!systems || !nodePositions) return []; - - const connections = new Map(); - - systems.forEach(system => { - system.connectedSystems?.forEach(connectedSystem => { - const connectionKey = [system.solarSystemName, connectedSystem].sort().join('-'); - if (connections.has(connectionKey)) return; - - const fromPos = nodePositions[system.solarSystemName]; - const toPos = nodePositions[connectedSystem]; - if (!fromPos || !toPos) return; - - const toSystem = systems.find(s => s.solarSystemName === connectedSystem); - if (!toSystem) return; - - const avgSecurity = (system.security + toSystem.security) / 2; - const connectionColor = getSecurityColor(avgSecurity); - - connections.set(connectionKey, { - key: connectionKey, - from: fromPos, - to: toPos, - color: connectionColor - }); - }); - }); - - return Array.from(connections.values()); - }, [systems, nodePositions]); - - // Initialize positions and center on current system - useEffect(() => { - if (systems) { - const positions: Record = {}; - systems.forEach(system => { - positions[system.solarSystemName] = { - x: system.x, - y: system.y - }; - }); - setNodePositions(positions); - - // Find current system and center view on it - const currentSystemData = systems.find(s => s.solarSystemName === currentSystem); - if (currentSystemData) { - setViewBox({ - x: currentSystemData.x - 200, // Center with some padding - y: currentSystemData.y - 150, - width: 400, - height: 300 - }); - } - } - }, [systems, currentSystem]); - - const handleSystemClick = (systemName: string) => { - navigate(`/systems/${systemName}`); - }; - - const handleMouseDown = useCallback((e: React.MouseEvent) => { - if (!svgRef.current) return; - setIsPanning(true); - const rect = svgRef.current.getBoundingClientRect(); - setLastPanPoint({ - x: e.clientX - rect.left, - y: e.clientY - rect.top - }); - }, []); - - const handleMouseMove = useCallback((e: React.MouseEvent) => { - if (!isPanning || !svgRef.current) return; - - const rect = svgRef.current.getBoundingClientRect(); - const currentPoint = { - x: e.clientX - rect.left, - y: e.clientY - rect.top - }; - - const deltaX = (lastPanPoint.x - currentPoint.x) * (viewBox.width / rect.width); - const deltaY = (lastPanPoint.y - currentPoint.y) * (viewBox.height / rect.height); - - setViewBox(prev => ({ - ...prev, - x: prev.x + deltaX, - y: prev.y + deltaY - })); - - setLastPanPoint(currentPoint); - }, [isPanning, lastPanPoint, viewBox.width, viewBox.height]); - - const handleMouseUp = useCallback(() => { - setIsPanning(false); - }, []); - - const handleWheel = useCallback((e: React.WheelEvent) => { - e.preventDefault(); - if (!svgRef.current) return; - - const rect = svgRef.current.getBoundingClientRect(); - const mouseX = e.clientX - rect.left; - const mouseY = e.clientY - rect.top; - - const scale = e.deltaY > 0 ? 1.1 : 0.9; // Inverted: scroll down = zoom in - const newWidth = viewBox.width * scale; - const newHeight = viewBox.height * scale; - - const mouseXInSVG = viewBox.x + (mouseX / rect.width) * viewBox.width; - const mouseYInSVG = viewBox.y + (mouseY / rect.height) * viewBox.height; - - const newX = mouseXInSVG - (mouseX / rect.width) * newWidth; - const newY = mouseYInSVG - (mouseY / rect.height) * newHeight; - - setViewBox({ - x: newX, - y: newY, - width: newWidth, - height: newHeight - }); - }, [viewBox]); - - if (isLoading) { - return ( -
-
Loading region map...
-
- ); - } - - return ( -
-
-

{regionName} Region

-

Click systems to navigate

-
- - - - - - - - - - - - - {/* Render connections */} - {processedConnections.map(connection => ( - - ))} - - {/* Render systems */} - {systems?.map((system) => ( - handleSystemClick(system.solarSystemName)} - type="system" - security={system.security} - signatures={system.signatures} - /> - ))} - - {/* Highlight current system with a ring */} - {currentSystem && nodePositions[currentSystem] && ( - - - - )} - -
- ); -}; diff --git a/src/pages/SystemView.tsx b/src/pages/SystemView.tsx index d6f663d..7af0a1c 100644 --- a/src/pages/SystemView.tsx +++ b/src/pages/SystemView.tsx @@ -2,7 +2,7 @@ import { useParams, useNavigate } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import SystemTracker from "@/components/SystemTracker"; -import { RegionOverviewMap } from "@/components/RegionOverviewMap"; +import { RegionMap } from "@/components/RegionMap"; import { findSystemRegion } from "@/utils/systemRegionMapping"; const SystemView = () => { @@ -37,11 +37,19 @@ const SystemView = () => { {/* Regional overview map */}
{regionName ? ( - +
+
+

{regionName} Region

+

Click systems to navigate • Current: {system}

+
+
+ +
+
) : (