diff options
Diffstat (limited to 'src/map/MapRoutePoints.js')
-rw-r--r-- | src/map/MapRoutePoints.js | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/map/MapRoutePoints.js b/src/map/MapRoutePoints.js new file mode 100644 index 00000000..e329da81 --- /dev/null +++ b/src/map/MapRoutePoints.js @@ -0,0 +1,77 @@ +import { useId, useCallback, useEffect } from 'react'; +import { map } from './core/MapView'; + +const MapRoutePoints = ({ positions, onClick }) => { + const id = useId(); + + const onMouseEnter = () => map.getCanvas().style.cursor = 'pointer'; + const onMouseLeave = () => map.getCanvas().style.cursor = ''; + + const onMarkerClick = useCallback((event) => { + event.preventDefault(); + const feature = event.features[0]; + if (onClick) { + onClick(feature.properties.id, feature.properties.index); + } + }, [onClick]); + + useEffect(() => { + map.addSource(id, { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [], + }, + }); + map.addLayer({ + id, + type: 'symbol', + source: id, + layout: { + 'icon-image': 'arrow', + 'icon-allow-overlap': true, + 'icon-rotate': ['get', 'rotation'], + 'icon-rotation-alignment': 'map', + }, + }); + + map.on('mouseenter', id, onMouseEnter); + map.on('mouseleave', id, onMouseLeave); + map.on('click', id, onMarkerClick); + + return () => { + map.off('mouseenter', id, onMouseEnter); + map.off('mouseleave', id, onMouseLeave); + map.off('click', id, onMarkerClick); + + if (map.getLayer(id)) { + map.removeLayer(id); + } + if (map.getSource(id)) { + map.removeSource(id); + } + }; + }, [onMarkerClick]); + + useEffect(() => { + map.getSource(id)?.setData({ + type: 'FeatureCollection', + features: positions.map((position, index) => ({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [position.longitude, position.latitude], + }, + properties: { + index, + id: position.id, + rotation: position.course, + }, + })), + }); + }, [onMarkerClick, positions]); + + return null; +}; + +export default MapRoutePoints; |