auto zoom and center of servers map

This commit is contained in:
2025-07-22 10:18:50 -05:00
parent 2537609aea
commit 4c10a05d20
+71 -1
View File
@@ -4,11 +4,80 @@ import Server from '@/types/server';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { MapPin } from 'lucide-react'; import { MapPin } from 'lucide-react';
import ServerComponent from '../dashboard/server'; import ServerComponent from '../dashboard/server';
import { useEffect, useMemo, useRef, useState } from 'react';
export default function ServerMap({ servers }: { servers: Server[] }) { export default function ServerMap({ servers }: { servers: Server[] }) {
const mapContainerRef = useRef<HTMLDivElement>(null);
const [viewport, setViewport] = useState({ width: 800, height: 600 });
// 1. Get bounding coordinates
const coords = useMemo(() => servers
.map(s => s.coordinates)
.filter((c): c is [number, number] => !!c), [servers]);
const center = useMemo(() => {
if (coords.length === 0) return { longitude: 0, latitude: 0 };
const lngSum = coords.reduce((sum, c) => sum + c[0], 0);
const latSum = coords.reduce((sum, c) => sum + c[1], 0);
return {
longitude: lngSum / coords.length,
latitude: latSum / coords.length,
};
}, [coords]);
const bounds = useMemo(() => {
if (coords.length === 0) return null;
const lons = coords.map(c => c[0]);
const lats = coords.map(c => c[1]);
return {
minLon: Math.min(...lons),
maxLon: Math.max(...lons),
minLat: Math.min(...lats),
maxLat: Math.max(...lats),
};
}, [coords]);
// 2. Measure viewport size on mount
useEffect(() => {
const handleResize = () => {
if (mapContainerRef.current) {
setViewport({
width: mapContainerRef.current.offsetWidth,
height: mapContainerRef.current.offsetHeight,
});
}
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
// 3. Estimate zoom level
const zoom = useMemo(() => {
if (!bounds) return 2;
const TILE_SIZE = 256;
const WORLD_DIM = { width: viewport.width, height: viewport.height };
const ZOOM_MAX = 20;
const lngDelta = bounds.maxLon - bounds.minLon;
const latDelta = bounds.maxLat - bounds.minLat;
const latZoom = Math.log2(WORLD_DIM.height * 360 / (TILE_SIZE * latDelta));
const lngZoom = Math.log2(WORLD_DIM.width * 360 / (TILE_SIZE * lngDelta));
return Math.max(1, Math.min(Math.min(latZoom, lngZoom) - 2, ZOOM_MAX));
}, [bounds, viewport]);
return ( return (
<div ref={mapContainerRef} style={{ width: '100%', height: 'calc(100% - 20px)' }}>
<Map <Map
style={{width: "100%", height: "100%"}} initialViewState={{
latitude: center.latitude,
longitude: center.longitude,
zoom: zoom || 1
}}
style={{ width: '100%', height: '100%' }}
mapStyle="/map_style.json" mapStyle="/map_style.json"
> >
{ {
@@ -26,5 +95,6 @@ export default function ServerMap({ servers }: { servers: Server[] }) {
)) ))
} }
</Map> </Map>
</div>
); );
} }