auto zoom and center of servers map

This commit is contained in:
2025-07-22 10:18:50 -05:00
parent 2537609aea
commit 4c10a05d20
+89 -19
View File
@@ -4,27 +4,97 @@ 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[] }) {
return ( const mapContainerRef = useRef<HTMLDivElement>(null);
<Map const [viewport, setViewport] = useState({ width: 800, height: 600 });
style={{width: "100%", height: "100%"}}
mapStyle="/map_style.json" // 1. Get bounding coordinates
> const coords = useMemo(() => servers
{ .map(s => s.coordinates)
servers.filter(s => s.coordinates).map((s, i) => ( .filter((c): c is [number, number] => !!c), [servers]);
<Marker longitude={s.coordinates?.[0] || 0} latitude={s.coordinates?.[1] || 0} color="red" key={i}>
<Popover> const center = useMemo(() => {
<PopoverTrigger> if (coords.length === 0) return { longitude: 0, latitude: 0 };
<MapPin /> const lngSum = coords.reduce((sum, c) => sum + c[0], 0);
</PopoverTrigger> const latSum = coords.reduce((sum, c) => sum + c[1], 0);
<PopoverContent className='w-96'> return {
<ServerComponent server={s} index={i} session={null} /> longitude: lngSum / coords.length,
</PopoverContent> latitude: latSum / coords.length,
</Popover> };
</Marker> }, [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,
});
} }
</Map> };
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 (
<div ref={mapContainerRef} style={{ width: '100%', height: 'calc(100% - 20px)' }}>
<Map
initialViewState={{
latitude: center.latitude,
longitude: center.longitude,
zoom: zoom || 1
}}
style={{ width: '100%', height: '100%' }}
mapStyle="/map_style.json"
>
{
servers.filter(s => s.coordinates).map((s, i) => (
<Marker longitude={s.coordinates?.[0] || 0} latitude={s.coordinates?.[1] || 0} color="red" key={i}>
<Popover>
<PopoverTrigger>
<MapPin />
</PopoverTrigger>
<PopoverContent className='w-96'>
<ServerComponent server={s} index={i} session={null} />
</PopoverContent>
</Popover>
</Marker>
))
}
</Map>
</div>
); );
} }