mirror of
https://github.com/seemueller-io/yachtpit.git
synced 2025-09-08 22:46:45 +00:00
Refactor MapNext
to GeoMap
, streamline code, and integrate optimized GeoJSON-based port rendering.
This commit is contained in:
96
crates/base-map/map/src/GeoMap.tsx
Normal file
96
crates/base-map/map/src/GeoMap.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import {useMemo, useCallback, useRef} from 'react';
|
||||
import Map, {
|
||||
Source, Layer,
|
||||
NavigationControl, FullscreenControl, ScaleControl, GeolocateControl,
|
||||
type MapRef
|
||||
} from 'react-map-gl/mapbox';
|
||||
import {Box} from '@chakra-ui/react';
|
||||
import type {Feature, FeatureCollection, Point} from 'geojson';
|
||||
import PORTS from './test_data/nautical-base-data.json';
|
||||
import type {VesselData} from './ais-provider';
|
||||
|
||||
export interface Geolocation {
|
||||
clearWatch(watchId: number): void;
|
||||
getCurrentPosition(
|
||||
successCallback: PositionCallback,
|
||||
errorCallback?: PositionErrorCallback | null,
|
||||
options?: PositionOptions
|
||||
): void;
|
||||
watchPosition(
|
||||
successCallback: PositionCallback,
|
||||
errorCallback?: PositionErrorCallback | null,
|
||||
options?: PositionOptions
|
||||
): number;
|
||||
}
|
||||
|
||||
interface MapNextProps {
|
||||
mapboxPublicKey: string;
|
||||
geolocation: Geolocation;
|
||||
vesselPosition?: any;
|
||||
layer?: any;
|
||||
mapView?: any;
|
||||
aisVessels?: VesselData[];
|
||||
onVesselClick?: (vessel: VesselData) => void;
|
||||
vesselPopup?: VesselData | null;
|
||||
onVesselPopupClose?: () => void;
|
||||
}
|
||||
|
||||
export default function GeoMap(props: MapNextProps) {
|
||||
const mapRef = useRef<MapRef | null>(null);
|
||||
|
||||
const portsGeoJSON = useMemo<FeatureCollection<Point>>(() => ({
|
||||
type: 'FeatureCollection',
|
||||
features: PORTS.map(port => ({
|
||||
type: 'Feature',
|
||||
geometry: {type: 'Point', coordinates: [port.longitude, port.latitude]},
|
||||
properties: {city: port.city, state: port.state}
|
||||
} as Feature<Point>))
|
||||
}), []);
|
||||
|
||||
const handleGeolocate = useCallback((pos: GeolocationPosition) => {
|
||||
console.log('User location loaded:', pos);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Map
|
||||
ref={mapRef}
|
||||
initialViewState={{
|
||||
latitude: props.mapView?.latitude ?? 40,
|
||||
longitude: props.mapView?.longitude ?? -100,
|
||||
zoom: props.mapView?.zoom ?? 3.5,
|
||||
bearing: 0,
|
||||
pitch: 0
|
||||
}}
|
||||
key={`${props.mapView?.latitude}-${props.mapView?.longitude}-${props.mapView?.zoom}`}
|
||||
mapStyle={props.layer?.value ?? 'mapbox://styles/mapbox/standard'}
|
||||
mapboxAccessToken={props.mapboxPublicKey}
|
||||
style={{ position: 'fixed', inset: 0 }}
|
||||
>
|
||||
<Source id="ports" type="geojson" data={portsGeoJSON}>
|
||||
<Layer
|
||||
id="ports-layer"
|
||||
type="circle"
|
||||
paint={{
|
||||
'circle-radius': 6,
|
||||
'circle-color': '#007bff',
|
||||
'circle-stroke-width': 1,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
}}
|
||||
/>
|
||||
</Source>
|
||||
|
||||
<GeolocateControl
|
||||
showUserHeading={true}
|
||||
showUserLocation={true}
|
||||
geolocation={props.geolocation}
|
||||
position="top-left"
|
||||
onGeolocate={handleGeolocate}
|
||||
/>
|
||||
<FullscreenControl position="top-left" />
|
||||
<NavigationControl position="top-left" />
|
||||
<ScaleControl />
|
||||
</Map>
|
||||
</Box>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user