forked from VinokurovVE/tests
176 lines
6.1 KiB
TypeScript
176 lines
6.1 KiB
TypeScript
import { useEffect, useRef, useState } from 'react'
|
|
import GeoJSON from 'ol/format/GeoJSON'
|
|
import 'ol/ol.css'
|
|
import Map from 'ol/Map'
|
|
import View from 'ol/View'
|
|
import { Draw, Modify, Snap } from 'ol/interaction'
|
|
import { OSM, Vector as VectorSource } from 'ol/source'
|
|
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
|
|
import { transform, transformExtent } from 'ol/proj'
|
|
import { Divider, IconButton, Stack } from '@mui/material'
|
|
import { Adjust, Api, CircleOutlined, RectangleOutlined, Timeline, Undo, Warning } from '@mui/icons-material'
|
|
import { Type } from 'ol/geom/Geometry'
|
|
|
|
const MapComponent = () => {
|
|
const mapElement = useRef<HTMLDivElement | null>(null)
|
|
const [currentTool, setCurrentTool] = useState<Type>('Point')
|
|
|
|
const map = useRef<Map | null>(null)
|
|
const source = useRef<VectorSource>(new VectorSource())
|
|
|
|
const draw = useRef<Draw | null>(null)
|
|
const snap = useRef<Snap | null>(null)
|
|
|
|
const drawingLayer = useRef<VectorLayer | null>(null)
|
|
|
|
const addInteractions = () => {
|
|
draw.current = new Draw({
|
|
source: source.current,
|
|
type: currentTool,
|
|
})
|
|
map?.current?.addInteraction(draw.current)
|
|
snap.current = new Snap({ source: source.current })
|
|
map?.current?.addInteraction(snap.current)
|
|
}
|
|
|
|
// Function to save features to localStorage
|
|
const saveFeatures = () => {
|
|
const features = drawingLayer.current?.getSource()?.getFeatures()
|
|
if (features && features.length > 0) {
|
|
const geoJSON = new GeoJSON()
|
|
const featuresJSON = geoJSON.writeFeatures(features)
|
|
localStorage.setItem('savedFeatures', featuresJSON)
|
|
}
|
|
}
|
|
|
|
// Function to load features from localStorage
|
|
const loadFeatures = () => {
|
|
const savedFeatures = localStorage.getItem('savedFeatures')
|
|
if (savedFeatures) {
|
|
const geoJSON = new GeoJSON()
|
|
const features = geoJSON.readFeatures(savedFeatures, {
|
|
featureProjection: 'EPSG:4326', // Ensure the projection is correct
|
|
})
|
|
source.current?.addFeatures(features) // Add features to the vector source
|
|
//drawingLayer.current?.getSource()?.changed()
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
const geoLayer = new VectorLayer({
|
|
background: '#1a2b39',
|
|
source: new VectorSource({
|
|
url: 'https://openlayers.org/data/vector/ecoregions.json',
|
|
format: new GeoJSON(),
|
|
}),
|
|
style: {
|
|
'fill-color': ['string', ['get', 'COLOR'], '#eee'],
|
|
},
|
|
})
|
|
|
|
const raster = new TileLayer({
|
|
source: new OSM(),
|
|
})
|
|
|
|
drawingLayer.current = new VectorLayer({
|
|
source: source.current,
|
|
style: {
|
|
'fill-color': 'rgba(255, 255, 255, 0.2)',
|
|
'stroke-color': '#ffcc33',
|
|
'stroke-width': 2,
|
|
'circle-radius': 7,
|
|
'circle-fill-color': '#ffcc33',
|
|
},
|
|
})
|
|
|
|
// Center coordinates of Yakutia in EPSG:3857
|
|
const center = transform([129.7694, 66.9419], 'EPSG:4326', 'EPSG:3857')
|
|
|
|
// Extent for Yakutia in EPSG:4326
|
|
const extent4326 = [105.0, 55.0, 170.0, 75.0] // Approximate bounding box
|
|
// Transform extent to EPSG:3857
|
|
const extent = transformExtent(extent4326, 'EPSG:4326', 'EPSG:3857')
|
|
|
|
map.current = new Map({
|
|
layers: [geoLayer, raster, drawingLayer.current],
|
|
target: mapElement.current as HTMLDivElement,
|
|
view: new View({
|
|
center,
|
|
zoom: 4,
|
|
extent,
|
|
}),
|
|
})
|
|
|
|
const modify = new Modify({ source: source.current })
|
|
map.current.addInteraction(modify)
|
|
|
|
addInteractions()
|
|
|
|
loadFeatures()
|
|
|
|
return () => {
|
|
map?.current?.setTarget(undefined)
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (currentTool) {
|
|
if (draw.current) map?.current?.removeInteraction(draw.current)
|
|
if (snap.current) map?.current?.removeInteraction(snap.current)
|
|
addInteractions()
|
|
}
|
|
}, [currentTool])
|
|
|
|
return (
|
|
<div>
|
|
<Stack my={1} spacing={1} direction='row' divider={<Divider orientation='vertical' flexItem />}>
|
|
<IconButton onClick={() => {
|
|
fetch(`${import.meta.env.VITE_API_EMS_URL}/hello`, { method: 'GET' }).then(res => console.log(res))
|
|
}}>
|
|
<Api />
|
|
</IconButton>
|
|
|
|
<IconButton onClick={() => {
|
|
saveFeatures()
|
|
}}>
|
|
<Warning />
|
|
</IconButton>
|
|
|
|
<IconButton
|
|
onClick={() => {
|
|
draw.current?.removeLastPoint()
|
|
}}>
|
|
<Undo />
|
|
</IconButton>
|
|
|
|
<IconButton
|
|
sx={{ backgroundColor: currentTool === 'Point' ? 'Highlight' : 'transparent' }}
|
|
onClick={() => setCurrentTool('Point')}>
|
|
<Adjust />
|
|
</IconButton>
|
|
|
|
<IconButton
|
|
sx={{ backgroundColor: currentTool === 'LineString' ? 'Highlight' : 'transparent' }}
|
|
onClick={() => setCurrentTool('LineString')}>
|
|
<Timeline />
|
|
</IconButton>
|
|
|
|
<IconButton
|
|
sx={{ backgroundColor: currentTool === 'Polygon' ? 'Highlight' : 'transparent' }}
|
|
onClick={() => setCurrentTool('Polygon')}>
|
|
<RectangleOutlined />
|
|
</IconButton>
|
|
|
|
<IconButton
|
|
sx={{ backgroundColor: currentTool === 'Circle' ? 'Highlight' : 'transparent' }}
|
|
onClick={() => setCurrentTool('Circle')}>
|
|
<CircleOutlined />
|
|
</IconButton>
|
|
</Stack>
|
|
<div ref={mapElement} style={{ width: '100%', height: '400px' }}></div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MapComponent
|