Region/district select; proper Map tabs
This commit is contained in:
@ -10,12 +10,12 @@ import { customMapSource, googleMapsSatelliteSource, yandexMapsSatelliteSource }
|
|||||||
import { Geometry, SimpleGeometry } from 'ol/geom'
|
import { Geometry, SimpleGeometry } from 'ol/geom'
|
||||||
import { fromExtent } from 'ol/geom/Polygon'
|
import { fromExtent } from 'ol/geom/Polygon'
|
||||||
import { Coordinate } from 'ol/coordinate'
|
import { Coordinate } from 'ol/coordinate'
|
||||||
import { addInteractions, handleImageDrop, loadFeatures, processFigure, processLine } from './mapUtils'
|
import { addInteractions, getFeatureByEntityId, handleImageDrop, loadFeatures, processFigure, processLine, zoomToFeature } from './mapUtils'
|
||||||
import useSWR, { SWRConfiguration } from 'swr'
|
import useSWR, { SWRConfiguration } from 'swr'
|
||||||
import { fetcher } from '../../http/axiosInstance'
|
import { fetcher } from '../../http/axiosInstance'
|
||||||
import { BASE_URL } from '../../constants'
|
import { BASE_URL } from '../../constants'
|
||||||
import { IconBoxMultiple, IconBoxPadding, IconChevronLeft, IconPlus, IconUpload, } from '@tabler/icons-react'
|
import { IconBoxMultiple, IconBoxPadding, IconChevronLeft, IconPlus, IconUpload, IconX, } from '@tabler/icons-react'
|
||||||
import { ICitySettings, IFigure, ILine } from '../../interfaces/gis'
|
import { ICitySettings, IDistrict, IFigure, ILine } from '../../interfaces/gis'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import MapToolbar from './MapToolbar/MapToolbar'
|
import MapToolbar from './MapToolbar/MapToolbar'
|
||||||
import MapStatusbar from './MapStatusbar/MapStatusbar'
|
import MapStatusbar from './MapStatusbar/MapStatusbar'
|
||||||
@ -33,9 +33,11 @@ import GisService from '../../services/GisService'
|
|||||||
import MapMode from './MapMode'
|
import MapMode from './MapMode'
|
||||||
import { satMapsProviders, schemas } from '../../constants/map'
|
import { satMapsProviders, schemas } from '../../constants/map'
|
||||||
import MapPrint from './MapPrint/MapPrint'
|
import MapPrint from './MapPrint/MapPrint'
|
||||||
import { Field, Menu, MenuButton, MenuList, MenuPopover, MenuTrigger, Combobox, Option, Button, Divider, Spinner, Portal, Dropdown } from '@fluentui/react-components'
|
import { Field, Menu, MenuButton, MenuList, MenuPopover, MenuTrigger, Combobox, Option, Button, Divider, Spinner, Portal, Dropdown, Tooltip, Drawer, DrawerHeader, DrawerBody, Text, Link } from '@fluentui/react-components'
|
||||||
import { IRegion } from '../../interfaces/fuel'
|
import { IRegion } from '../../interfaces/fuel'
|
||||||
import { useAppStore } from '../../store/app'
|
import { useAppStore } from '../../store/app'
|
||||||
|
import { getDistrictData, getRegionData, setDistrictsData, setRegionsData } from '../../store/regions'
|
||||||
|
import { ArrowLeft24Regular } from '@fluentui/react-icons'
|
||||||
|
|
||||||
const swrOptions: SWRConfiguration = {
|
const swrOptions: SWRConfiguration = {
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
@ -70,8 +72,8 @@ const MapComponent = ({
|
|||||||
polygonExtent, rectCoords, draw, snap, translate,
|
polygonExtent, rectCoords, draw, snap, translate,
|
||||||
drawingLayerSource,
|
drawingLayerSource,
|
||||||
satLayer, staticMapLayer, figuresLayer, linesLayer,
|
satLayer, staticMapLayer, figuresLayer, linesLayer,
|
||||||
regionsLayer, districtBoundLayer, baseLayer,
|
regionsLayer, districtBoundLayer, baseLayer, districtsLayer,
|
||||||
printAreaDraw,
|
printAreaDraw, statusText, statusTextPosition, regionSelect, districtSelect
|
||||||
} = useMapStore().id[id]
|
} = useMapStore().id[id]
|
||||||
|
|
||||||
// Tab settings
|
// Tab settings
|
||||||
@ -103,7 +105,7 @@ const MapComponent = ({
|
|||||||
if (regionsLayer && regionBoundsData) {
|
if (regionsLayer && regionBoundsData) {
|
||||||
if (Array.isArray(regionBoundsData)) {
|
if (Array.isArray(regionBoundsData)) {
|
||||||
regionBoundsData.map(bound => {
|
regionBoundsData.map(bound => {
|
||||||
const geoJson = new GeoJSON({ featureProjection: 'EPSG:3857' })
|
const geoJson = new GeoJSON() //new GeoJSON({ featureProjection: 'EPSG:3857' })
|
||||||
const geometry = geoJson.readGeometry(bound) as Geometry
|
const geometry = geoJson.readGeometry(bound) as Geometry
|
||||||
|
|
||||||
const feature = new Feature(geometry)
|
const feature = new Feature(geometry)
|
||||||
@ -111,8 +113,15 @@ const MapComponent = ({
|
|||||||
|
|
||||||
regionsLayer.getSource()?.addFeature(feature)
|
regionsLayer.getSource()?.addFeature(feature)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
const extent = regionsLayer.getSource()?.getExtent()
|
||||||
|
|
||||||
|
if (extent) {
|
||||||
|
map.getView().fit(fromExtent(extent))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//regionsLayer.current.getSource()?.addFeature()
|
|
||||||
}
|
}
|
||||||
}, [regionBoundsData])
|
}, [regionBoundsData])
|
||||||
|
|
||||||
@ -126,7 +135,7 @@ const MapComponent = ({
|
|||||||
districtBoundLayer.setSource(bounds)
|
districtBoundLayer.setSource(bounds)
|
||||||
|
|
||||||
bounds.on('featuresloadend', function () {
|
bounds.on('featuresloadend', function () {
|
||||||
// map.current?.setView(new View({
|
// map?.setView(new View({
|
||||||
// extent: bounds.getExtent()
|
// extent: bounds.getExtent()
|
||||||
// }))
|
// }))
|
||||||
})
|
})
|
||||||
@ -275,9 +284,15 @@ const MapComponent = ({
|
|||||||
}
|
}
|
||||||
}, [currentObjectId])
|
}, [currentObjectId])
|
||||||
|
|
||||||
const { data: regionsData } = useSWR(`/general/regions`, (url) => fetcher(url, BASE_URL.ems), swrOptions)
|
const { data: regionsData } = useSWR(`/general/regions`, (url) => fetcher(url, BASE_URL.ems).then(res => {
|
||||||
|
setRegionsData(res)
|
||||||
|
return res
|
||||||
|
}), swrOptions)
|
||||||
|
|
||||||
const { data: districtsData } = useSWR(selectedRegion ? `/general/districts/?region_id=${selectedRegion}` : null, (url) => fetcher(url, BASE_URL.ems), swrOptions)
|
const { data: districtsData } = useSWR(selectedRegion ? `/general/districts/?region_id=${selectedRegion}` : null, (url) => fetcher(url, BASE_URL.ems).then(res => {
|
||||||
|
setDistrictsData(res)
|
||||||
|
return res
|
||||||
|
}), swrOptions)
|
||||||
|
|
||||||
const { data: searchData } = useSWR(
|
const { data: searchData } = useSWR(
|
||||||
throttledSearchObject !== "" && selectedDistrict && selectedYear ? `/general/search/objects?q=${throttledSearchObject}&id_city=${selectedDistrict}&year=${selectedYear}` : null,
|
throttledSearchObject !== "" && selectedDistrict && selectedYear ? `/general/search/objects?q=${throttledSearchObject}&id_city=${selectedDistrict}&year=${selectedYear}` : null,
|
||||||
@ -384,7 +399,7 @@ const MapComponent = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedRegion) {
|
if (!selectedRegion) {
|
||||||
setSelectedRegion(id, undefined)
|
setSelectedRegion(id, null)
|
||||||
setSelectedYear(id, null)
|
setSelectedYear(id, null)
|
||||||
}
|
}
|
||||||
}, [selectedRegion, selectedDistrict, id])
|
}, [selectedRegion, selectedDistrict, id])
|
||||||
@ -466,8 +481,94 @@ const MapComponent = ({
|
|||||||
}
|
}
|
||||||
}, [mode, map, printAreaDraw])
|
}, [mode, map, printAreaDraw])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (districtsData && Array.isArray(districtsData)) {
|
||||||
|
const list: Number[] = []
|
||||||
|
districtsData.map(district => {
|
||||||
|
list.push(district.id as Number)
|
||||||
|
})
|
||||||
|
|
||||||
|
fetch(`${BASE_URL.ems}/gis/bounds/city`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ list })
|
||||||
|
}).then(async response => {
|
||||||
|
const data = await response.json()
|
||||||
|
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
data.map(bound => {
|
||||||
|
const geoJson = new GeoJSON() //new GeoJSON({ featureProjection: 'EPSG:3857' })
|
||||||
|
const geometry = geoJson.readGeometry(bound) as Geometry
|
||||||
|
|
||||||
|
const feature = new Feature(geometry)
|
||||||
|
feature.setProperties(bound.properties)
|
||||||
|
|
||||||
|
districtsLayer.getSource()?.addFeature(feature)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [districtsData])
|
||||||
|
|
||||||
|
const mapTooltipRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mapTooltipRef.current) {
|
||||||
|
const leftOffset = 30
|
||||||
|
const topOffset = -30
|
||||||
|
mapTooltipRef.current.style.left = (statusTextPosition[0] + leftOffset).toString() + 'px'
|
||||||
|
mapTooltipRef.current.style.top = (statusTextPosition[1] + topOffset).toString() + 'px'
|
||||||
|
}
|
||||||
|
}, [statusTextPosition, mapTooltipRef])
|
||||||
|
|
||||||
|
// zoom on region select
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedRegion && !selectedDistrict) {
|
||||||
|
const feature = getFeatureByEntityId(selectedRegion, regionsLayer)
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
regionSelect.getFeatures().push(feature)
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomToFeature(id, feature)
|
||||||
|
}
|
||||||
|
}, [selectedRegion, selectedDistrict])
|
||||||
|
|
||||||
|
// zoom on district select
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedDistrict) {
|
||||||
|
const feature = getFeatureByEntityId(selectedDistrict, districtsLayer)
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
districtSelect.getFeatures().push(feature)
|
||||||
|
|
||||||
|
regionsLayer.setOpacity(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomToFeature(id, feature)
|
||||||
|
}
|
||||||
|
}, [selectedDistrict])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedYear) {
|
||||||
|
regionsLayer.setOpacity(0)
|
||||||
|
districtsLayer.setOpacity(0)
|
||||||
|
}
|
||||||
|
}, [selectedYear])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div style={{ display: 'flex', flexDirection: 'column', position: 'relative', width: '100%', height: '100%' }}>
|
||||||
|
|
||||||
|
{statusText && active && !selectedYear &&
|
||||||
|
<Tooltip hideDelay={0} showDelay={0} content={statusText} relationship='description' visible>
|
||||||
|
<div style={{ position: 'absolute', zIndex: 9999, userSelect: 'none', pointerEvents: 'none' }} ref={mapTooltipRef}>
|
||||||
|
{/* {statusText} */}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
<MapPrint id={id} mapElement={mapElement} />
|
<MapPrint id={id} mapElement={mapElement} />
|
||||||
|
|
||||||
{active &&
|
{active &&
|
||||||
@ -499,7 +600,7 @@ const MapComponent = ({
|
|||||||
: null}
|
: null}
|
||||||
</Combobox>
|
</Combobox>
|
||||||
|
|
||||||
<Combobox
|
{/* <Combobox
|
||||||
placeholder="Регион"
|
placeholder="Регион"
|
||||||
clearable
|
clearable
|
||||||
// 👇 show label instead of id
|
// 👇 show label instead of id
|
||||||
@ -512,7 +613,7 @@ const MapComponent = ({
|
|||||||
if (data.optionValue) {
|
if (data.optionValue) {
|
||||||
setSelectedRegion(id, Number(data.optionValue));
|
setSelectedRegion(id, Number(data.optionValue));
|
||||||
} else {
|
} else {
|
||||||
setSelectedRegion(id, undefined);
|
setSelectedRegion(id, null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{ minWidth: 'auto' }}
|
style={{ minWidth: 'auto' }}
|
||||||
@ -524,9 +625,9 @@ const MapComponent = ({
|
|||||||
</Option>
|
</Option>
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
</Combobox>
|
</Combobox> */}
|
||||||
|
|
||||||
<Combobox
|
{/* <Combobox
|
||||||
placeholder="Населённый пункт"
|
placeholder="Населённый пункт"
|
||||||
clearable
|
clearable
|
||||||
value={
|
value={
|
||||||
@ -554,28 +655,7 @@ const MapComponent = ({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
</Combobox>
|
</Combobox> */}
|
||||||
|
|
||||||
|
|
||||||
<Combobox
|
|
||||||
placeholder="Схема"
|
|
||||||
clearable
|
|
||||||
style={{ minWidth: 'auto' }}
|
|
||||||
value={selectedYear ? selectedYear.toString() : ""}
|
|
||||||
onOptionSelect={(_ev, data) => {
|
|
||||||
if (data.optionValue) {
|
|
||||||
setSelectedYear(id, Number(data.optionValue));
|
|
||||||
} else {
|
|
||||||
setSelectedYear(id, null);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{schemas.map((el) => (
|
|
||||||
<Option key={el} value={el}>
|
|
||||||
{el}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Combobox>
|
|
||||||
|
|
||||||
|
|
||||||
<Button icon={<IconBoxPadding />} appearance={alignMode ? 'primary' : 'transparent'} onClick={() => setAlignMode(id, !alignMode)} />
|
<Button icon={<IconBoxPadding />} appearance={alignMode ? 'primary' : 'transparent'} onClick={() => setAlignMode(id, !alignMode)} />
|
||||||
@ -621,41 +701,141 @@ const MapComponent = ({
|
|||||||
</MenuList>
|
</MenuList>
|
||||||
</MenuPopover>
|
</MenuPopover>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
{/* <Menu position="bottom-end" transitionProps={{ transition: 'pop-top-right' }}>
|
|
||||||
<Menu.Target>
|
|
||||||
<Button variant='transparent'>
|
|
||||||
<Group gap={7} wrap='nowrap' style={{ flexShrink: 0 }} title='Слои'>
|
|
||||||
<IconBoxMultiple style={{ width: rem(20), height: rem(20) }} />
|
|
||||||
<IconChevronDown style={{ width: rem(12), height: rem(12) }} stroke={1.5} />
|
|
||||||
</Group>
|
|
||||||
</Button>
|
|
||||||
</Menu.Target>
|
|
||||||
<Menu.Dropdown miw={300}>
|
|
||||||
<Menu.Label>{'Настройка видимости слоёв'}</Menu.Label>
|
|
||||||
|
|
||||||
<Flex p='sm' direction='column' gap='xs'>
|
|
||||||
<Flex align='center' direction='row' gap='sm'>
|
|
||||||
<MantineSelect value={satMapsProvider} data={satMapsProviders} onChange={(value) => setSatMapsProvider(id, value as SatelliteMapsProvider)} />
|
|
||||||
</Flex>
|
|
||||||
<Flex direction='row'>
|
|
||||||
<ActionIcon size='lg' variant='transparent' onClick={() => submitOverlay(file, polygonExtent, rectCoords)}>
|
|
||||||
<IconUpload style={{ width: rem(20), height: rem(20) }} />
|
|
||||||
</ActionIcon>
|
|
||||||
|
|
||||||
<ActionIcon size='lg' variant='transparent' title='Добавить подложку'>
|
|
||||||
<IconPlus style={{ width: rem(20), height: rem(20) }} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Flex>
|
|
||||||
<MapLayers map={map} />
|
|
||||||
</Flex>
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu> */}
|
|
||||||
</div>
|
</div>
|
||||||
</Portal >
|
</Portal >
|
||||||
}
|
}
|
||||||
|
|
||||||
<div style={{ position: 'absolute', width: '100%', height: '100%' }}>
|
<div style={{ position: 'absolute', width: '100%', height: '100%' }}>
|
||||||
|
{!selectedRegion &&
|
||||||
|
<Drawer style={{ position: 'absolute', height: '100%', zIndex: 9999 }} open={!selectedRegion} type='inline'>
|
||||||
|
{/* <DrawerHeader style={{ flexDirection: 'row' }}>
|
||||||
|
<Text weight='bold' size={500}></Text>
|
||||||
|
</DrawerHeader> */}
|
||||||
|
|
||||||
|
<DrawerBody>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
||||||
|
{regionsData && regionsData.map((region: IRegion) => (
|
||||||
|
<Link key={region.id} onClick={() => setSelectedRegion(id, region.id)}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
const feature = getFeatureByEntityId(region.id, regionsLayer)
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
regionSelect.getFeatures().push(feature)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
regionSelect.getFeatures().clear()
|
||||||
|
}}
|
||||||
|
>{region.name}</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DrawerBody>
|
||||||
|
</Drawer>}
|
||||||
|
|
||||||
|
<Drawer style={{ position: 'absolute', height: '100%', zIndex: 9999 }} open={!!selectedRegion && !selectedYear} type='inline'>
|
||||||
|
<DrawerHeader style={{ flexDirection: 'row' }}>
|
||||||
|
<Button icon={<ArrowLeft24Regular />} appearance='subtle' onClick={() => {
|
||||||
|
if (selectedDistrict) {
|
||||||
|
setSelectedDistrict(id, null)
|
||||||
|
districtSelect.getFeatures().clear()
|
||||||
|
regionsLayer.setOpacity(1)
|
||||||
|
} else {
|
||||||
|
setSelectedRegion(id, null)
|
||||||
|
regionSelect.getFeatures().clear()
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
const extent = regionsLayer.getSource()?.getExtent()
|
||||||
|
|
||||||
|
if (extent) {
|
||||||
|
map.getView().fit(fromExtent(extent), { duration: 100 })
|
||||||
|
regionsLayer.setOpacity(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}} />
|
||||||
|
|
||||||
|
{selectedDistrict ?
|
||||||
|
<Text weight='bold' size={500}>{getDistrictData(selectedDistrict)?.name}</Text>
|
||||||
|
:
|
||||||
|
<Text weight='bold' size={500}>{selectedRegion && getRegionData(selectedRegion)?.name}</Text>}
|
||||||
|
|
||||||
|
<Button appearance='subtle' style={{ marginLeft: 'auto' }} icon={<IconX />} onClick={() => {
|
||||||
|
setSelectedYear(id, null)
|
||||||
|
setSelectedDistrict(id, null)
|
||||||
|
setSelectedRegion(id, null)
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
const extent = regionsLayer.getSource()?.getExtent()
|
||||||
|
|
||||||
|
if (extent) {
|
||||||
|
map.getView().fit(fromExtent(extent), { duration: 100 })
|
||||||
|
regionsLayer.setOpacity(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}} />
|
||||||
|
</DrawerHeader>
|
||||||
|
|
||||||
|
<DrawerBody>
|
||||||
|
<div key={selectedRegion} style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
||||||
|
{selectedDistrict ?
|
||||||
|
selectedRegion && Object.entries(getRegionData(selectedRegion) as IRegion).map(([key, value]) => (
|
||||||
|
<div key={key} style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<span>{key}</span>
|
||||||
|
<span>{value}</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
:
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
||||||
|
<div>
|
||||||
|
{selectedRegion && Object.entries(getRegionData(selectedRegion) as IRegion).map(([key, value]) => (
|
||||||
|
<div key={key} style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<span>{key}</span>
|
||||||
|
<span>{value}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{districtsData && districtsData.map((district: IDistrict) => (
|
||||||
|
<Link key={district.id} onClick={() => setSelectedDistrict(id, district.id)}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
const feature = getFeatureByEntityId(district.id, districtsLayer)
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
districtSelect.getFeatures().push(feature)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
districtSelect.getFeatures().clear()
|
||||||
|
}}
|
||||||
|
>{district.name}</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{selectedDistrict && <Combobox
|
||||||
|
placeholder="Схема"
|
||||||
|
clearable
|
||||||
|
style={{ minWidth: 'auto' }}
|
||||||
|
value={selectedYear ? selectedYear.toString() : ""}
|
||||||
|
onOptionSelect={(_ev, data) => {
|
||||||
|
if (data.optionValue) {
|
||||||
|
setSelectedYear(id, Number(data.optionValue));
|
||||||
|
} else {
|
||||||
|
setSelectedYear(id, null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{schemas.map((el) => (
|
||||||
|
<Option key={el} value={el}>
|
||||||
|
{el}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Combobox>}
|
||||||
|
</div>
|
||||||
|
</DrawerBody>
|
||||||
|
</Drawer>
|
||||||
|
|
||||||
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>
|
||||||
<div style={{ display: 'flex', height: '94%', padding: '0.5rem', flexGrow: 1 }}>
|
<div style={{ display: 'flex', height: '94%', padding: '0.5rem', flexGrow: 1 }}>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', maxWidth: '380px' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', maxWidth: '380px' }}>
|
||||||
@ -699,7 +879,7 @@ const MapComponent = ({
|
|||||||
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center' }} >
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center' }} >
|
||||||
<div style={{ ...mapControlsStyle, display: 'flex', flexDirection: 'column', width: 'fit-content' }}>
|
<div style={{ ...mapControlsStyle, display: 'flex', flexDirection: 'column', width: 'fit-content' }}>
|
||||||
<MapMode map_id={id} />
|
{selectedDistrict && selectedYear && <MapMode map_id={id} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -714,16 +894,11 @@ const MapComponent = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', width: '100%' }}>
|
|
||||||
<MapStatusbar
|
|
||||||
map_id={id}
|
|
||||||
mapControlsStyle={mapControlsStyle}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ position: 'absolute', width: '100%', height: '100%', maxHeight: '100%' }} ref={mapElement} onDragOver={(e) => e.preventDefault()} onDrop={(e) => handleImageDrop(e, id)}>
|
<div id={id} key={id} style={{ position: 'relative', width: '100%', height: '100%', maxHeight: '100%' }} ref={mapElement} onDragOver={(e) => e.preventDefault()} onDrop={(e) => handleImageDrop(e, id)}>
|
||||||
<div ref={tooltipRef}></div>
|
<div ref={tooltipRef}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -743,7 +918,13 @@ const MapComponent = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</>
|
<div style={{ display: 'flex', bottom: '0', width: '100%' }}>
|
||||||
|
<MapStatusbar
|
||||||
|
map_id={id}
|
||||||
|
mapControlsStyle={mapControlsStyle}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
|
|||||||
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map";
|
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map";
|
||||||
import Collection from "ol/Collection";
|
import Collection from "ol/Collection";
|
||||||
import { SketchCoordType } from "ol/interaction/Draw";
|
import { SketchCoordType } from "ol/interaction/Draw";
|
||||||
|
import VectorImageLayer from "ol/layer/VectorImage";
|
||||||
|
import VectorSource from "ol/source/Vector";
|
||||||
|
|
||||||
const calculateAngle = (coords: [number, number][]) => {
|
const calculateAngle = (coords: [number, number][]) => {
|
||||||
const [start, end] = coords;
|
const [start, end] = coords;
|
||||||
@ -482,7 +484,8 @@ export const addInteractions = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const zoomToFeature = (map_id: string, feature: Feature) => {
|
export const zoomToFeature = (map_id: string, feature: Feature | undefined) => {
|
||||||
|
if (feature) {
|
||||||
const geometry = feature.getGeometry()
|
const geometry = feature.getGeometry()
|
||||||
const extent = geometry?.getExtent()
|
const extent = geometry?.getExtent()
|
||||||
|
|
||||||
@ -493,6 +496,12 @@ export const zoomToFeature = (map_id: string, feature: Feature) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFeatureByEntityId = (entity_id: number, layer: VectorImageLayer<Feature<Geometry>, VectorSource<Feature<Geometry>>>) => {
|
||||||
|
console.log(entity_id, layer.getSource()?.getFeatures())
|
||||||
|
return layer.getSource()?.getFeatures().find(feature => feature.getProperties().entity_id === entity_id)
|
||||||
|
}
|
||||||
|
|
||||||
// Function to save features to localStorage
|
// Function to save features to localStorage
|
||||||
export const saveFeatures = (map_id: string) => {
|
export const saveFeatures = (map_id: string) => {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
import { Tab, TabList } from "@fluentui/react-tabs";
|
import { Tab, TabList } from "@fluentui/react-tabs";
|
||||||
import MapComponent from "../components/map/MapComponent";
|
import MapComponent from "../components/map/MapComponent";
|
||||||
|
|
||||||
@ -7,76 +5,49 @@ import {
|
|||||||
useAppStore,
|
useAppStore,
|
||||||
setCurrentTab,
|
setCurrentTab,
|
||||||
deleteMapTab,
|
deleteMapTab,
|
||||||
|
addMapTab,
|
||||||
} from "../store/app";
|
} from "../store/app";
|
||||||
import { initializeMapState, useMapStore } from "../store/map";
|
import { initializeMapState, useMapStore } from "../store/map";
|
||||||
import { initializeObjectsState } from "../store/objects";
|
import { initializeObjectsState } from "../store/objects";
|
||||||
|
import { Button } from "@fluentui/react-components";
|
||||||
|
import { Add12Filled, Dismiss12Filled, Map16Regular } from "@fluentui/react-icons";
|
||||||
|
|
||||||
function MapTest() {
|
function MapTest() {
|
||||||
const { mapTab, currentTab } = useAppStore();
|
const { mapTab, currentTab } = useAppStore()
|
||||||
const { id } = useMapStore();
|
const { id } = useMapStore()
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{
|
|
||||||
id: uuidv4(),
|
|
||||||
year: 2018,
|
|
||||||
region: 11,
|
|
||||||
district: 146,
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// id: uuidv4(),
|
|
||||||
// year: 2023,
|
|
||||||
// region: 11,
|
|
||||||
// district: 146,
|
|
||||||
// },
|
|
||||||
];
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
tabs.forEach((tab) => {
|
|
||||||
useAppStore.setState((state) => {
|
|
||||||
initializeObjectsState(tab.id, tab.region, tab.district, null, tab.year);
|
|
||||||
initializeMapState(tab.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
mapTab: {
|
|
||||||
...state.mapTab,
|
|
||||||
[tab.id]: {
|
|
||||||
year: tab.year,
|
|
||||||
region: tab.region,
|
|
||||||
district: tab.district,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setCurrentTab(tabs[0].id);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
tabs.forEach((tab) => deleteMapTab(tab.id));
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", width: "100%", position: "relative" }}>
|
<div style={{ height: "100%", width: "100%", position: "relative" }}>
|
||||||
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
|
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
|
||||||
<TabList
|
<TabList
|
||||||
|
size='small'
|
||||||
selectedValue={currentTab}
|
selectedValue={currentTab}
|
||||||
onTabSelect={(_, data) => setCurrentTab(data.value as string)}
|
onTabSelect={(_, data) => setCurrentTab(data.value as string)}
|
||||||
|
style={{ borderBottom: '1px solid var(--colorNeutralShadowKey)' }}
|
||||||
>
|
>
|
||||||
{Object.entries(mapTab).map(([key]) => (
|
{Object.entries(mapTab).map(([key]) => (
|
||||||
<Tab value={key} key={key}>
|
<Tab key={key} value={key} icon={<Map16Regular />}>
|
||||||
{id[key]?.mapLabel ?? `Tab ${key}`}
|
{id[key]?.mapLabel ?? `Tab ${key}`}
|
||||||
|
|
||||||
|
<Button style={{ marginLeft: '0.5rem' }} size='small' icon={<Dismiss12Filled />} appearance='subtle' onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
deleteMapTab(key)
|
||||||
|
}} />
|
||||||
</Tab>
|
</Tab>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<Button icon={<Add12Filled />} title="Открыть новую вкладку" appearance='subtle' onClick={() => {
|
||||||
|
const newId = addMapTab();
|
||||||
|
initializeObjectsState(newId, null, null, null, null);
|
||||||
|
initializeMapState(newId);
|
||||||
|
}} />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<div style={{ flexGrow: 1, position: "relative" }}>
|
<div style={{ flexGrow: 1, position: "relative" }}>
|
||||||
{Object.entries(mapTab).map(([key]) =>
|
{Object.entries(mapTab).map(([key]) =>
|
||||||
currentTab === key ? (
|
(<div key={key} style={{ height: "100%", position: "relative", display: currentTab === key ? 'unset' : 'none' }}>
|
||||||
<div key={key} style={{ height: "100%", position: "relative" }}>
|
<MapComponent key={key} id={key} active={currentTab === key} />
|
||||||
<MapComponent key={key} id={key} active={true} />
|
</div>)
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,38 +1,52 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { initializeObjectsState } from './objects'
|
||||||
|
import { initializeMapState } from './map'
|
||||||
|
|
||||||
export type Mode = 'edit' | 'view'
|
export type Mode = 'edit' | 'view'
|
||||||
|
|
||||||
export type ColorScheme = 'light' | 'dark' | 'auto'
|
export type ColorScheme = 'light' | 'dark' | 'auto'
|
||||||
|
|
||||||
|
export interface MapTabState {
|
||||||
|
year: number | null
|
||||||
|
region: number | null
|
||||||
|
district: number | null
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
colorScheme: ColorScheme,
|
colorScheme: ColorScheme,
|
||||||
mapTab: Record<string, {
|
mapTab: Record<string, MapTabState>,
|
||||||
year: number | null,
|
|
||||||
region: number | null,
|
|
||||||
district: number | null
|
|
||||||
}>,
|
|
||||||
currentTab: string | null;
|
currentTab: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppStore = create<AppState>(() => ({
|
export const useAppStore = create<AppState>(() => {
|
||||||
colorScheme: 'auto',
|
const firstId = uuidv4()
|
||||||
currentTab: null,
|
|
||||||
mapTab: {}
|
|
||||||
}))
|
|
||||||
|
|
||||||
const getColorScheme = () => {
|
initializeObjectsState(firstId, null, null, null, null);
|
||||||
|
initializeMapState(firstId)
|
||||||
|
|
||||||
|
return {
|
||||||
|
colorScheme: "auto",
|
||||||
|
currentTab: firstId,
|
||||||
|
mapTab: {
|
||||||
|
[firstId]: { year: null, region: null, district: null },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getColorScheme = () => {
|
||||||
useAppStore.getState().colorScheme
|
useAppStore.getState().colorScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
const setColorScheme = (colorScheme: ColorScheme) => {
|
export const setColorScheme = (colorScheme: ColorScheme) => {
|
||||||
useAppStore.setState(() => ({ colorScheme: colorScheme }))
|
useAppStore.setState(() => ({ colorScheme: colorScheme }))
|
||||||
localStorage.setItem('colorScheme', colorScheme.toString())
|
localStorage.setItem('colorScheme', colorScheme.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCurrentTab = () => useAppStore.getState().currentTab
|
export const getCurrentTab = () => useAppStore.getState().currentTab
|
||||||
const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id }))
|
export const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id }))
|
||||||
|
|
||||||
const setMapTabYear = (id: string, year: number | null) =>
|
export const setMapTabYear = (id: string, year: number | null) =>
|
||||||
useAppStore.setState((state) => {
|
useAppStore.setState((state) => {
|
||||||
return {
|
return {
|
||||||
mapTab: {
|
mapTab: {
|
||||||
@ -42,17 +56,31 @@ const setMapTabYear = (id: string, year: number | null) =>
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const deleteMapTab = (id: string) =>
|
export const deleteMapTab = (id: string) =>
|
||||||
useAppStore.setState((state) => {
|
useAppStore.setState((state) => {
|
||||||
const { [id]: _, ...remainingTabs } = state.mapTab;
|
const { [id]: _, ...remainingTabs } = state.mapTab;
|
||||||
return { mapTab: remainingTabs };
|
const keys = Object.keys(remainingTabs);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mapTab: remainingTabs,
|
||||||
|
currentTab: keys.length > 0 ? keys[keys.length - 1] : null,
|
||||||
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
export {
|
export const addMapTab = () => {
|
||||||
deleteMapTab,
|
const id = uuidv4();
|
||||||
getCurrentTab,
|
|
||||||
setCurrentTab,
|
useAppStore.setState((state) => ({
|
||||||
setMapTabYear,
|
mapTab: {
|
||||||
getColorScheme,
|
...state.mapTab,
|
||||||
setColorScheme
|
[id]: {
|
||||||
|
year: null,
|
||||||
|
region: null,
|
||||||
|
district: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
currentTab: id, // optionally switch to this new tab
|
||||||
|
}));
|
||||||
|
|
||||||
|
return id; // so you can use the new id in your components
|
||||||
}
|
}
|
@ -21,11 +21,12 @@ import { VectorImage } from 'ol/layer';
|
|||||||
import { click, pointerMove } from 'ol/events/condition';
|
import { click, pointerMove } from 'ol/events/condition';
|
||||||
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
|
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
|
||||||
import MapBrowserEvent from 'ol/MapBrowserEvent';
|
import MapBrowserEvent from 'ol/MapBrowserEvent';
|
||||||
import { transform } from 'ol/proj';
|
import { get, transform } from 'ol/proj';
|
||||||
import { applyTransformations, calculateTransformations, fixedAspectRatioBox, zoomToFeature } from '../components/map/mapUtils';
|
import { applyTransformations, calculateTransformations, fixedAspectRatioBox, getGridCellPosition, zoomToFeature } from '../components/map/mapUtils';
|
||||||
import { setCurrentObjectId, setSelectedRegion } from './objects';
|
import { getSelectedRegion, setCurrentObjectId, setSelectedDistrict, setSelectedRegion } from './objects';
|
||||||
import View from 'ol/View';
|
import View from 'ol/View';
|
||||||
import { getPrintOrientation } from './print';
|
import { getPrintOrientation } from './print';
|
||||||
|
import { getDistrictsData, getRegionsData } from './regions';
|
||||||
|
|
||||||
export type Mode = 'edit' | 'view' | 'print'
|
export type Mode = 'edit' | 'view' | 'print'
|
||||||
|
|
||||||
@ -45,7 +46,8 @@ interface MapState {
|
|||||||
currentX: number | undefined;
|
currentX: number | undefined;
|
||||||
currentY: number | undefined;
|
currentY: number | undefined;
|
||||||
currentCoordinate: Coordinate | null;
|
currentCoordinate: Coordinate | null;
|
||||||
statusText: string;
|
statusText: string | null;
|
||||||
|
statusTextPosition: [number, number];
|
||||||
satMapsProvider: SatelliteMapsProvider;
|
satMapsProvider: SatelliteMapsProvider;
|
||||||
selectedObjectType: number | null;
|
selectedObjectType: number | null;
|
||||||
alignMode: boolean;
|
alignMode: boolean;
|
||||||
@ -72,7 +74,7 @@ interface MapState {
|
|||||||
figuresLayer: VectorLayer<VectorSource>;
|
figuresLayer: VectorLayer<VectorSource>;
|
||||||
linesLayer: VectorLayer<VectorSource>;
|
linesLayer: VectorLayer<VectorSource>;
|
||||||
regionsLayer: VectorImage;
|
regionsLayer: VectorImage;
|
||||||
citiesLayer: VectorLayer;
|
districtsLayer: VectorImage;
|
||||||
districtBoundLayer: VectorImage;
|
districtBoundLayer: VectorImage;
|
||||||
imageLayer: ImageLayer<ImageStatic>;
|
imageLayer: ImageLayer<ImageStatic>;
|
||||||
selectedArea: Feature | null;
|
selectedArea: Feature | null;
|
||||||
@ -81,6 +83,7 @@ interface MapState {
|
|||||||
measureModify: Modify;
|
measureModify: Modify;
|
||||||
overlayLayer: VectorLayer;
|
overlayLayer: VectorLayer;
|
||||||
regionSelect: Select;
|
regionSelect: Select;
|
||||||
|
districtSelect: Select;
|
||||||
lineSelect: Select;
|
lineSelect: Select;
|
||||||
previousView: View | undefined | null;
|
previousView: View | undefined | null;
|
||||||
printArea: Extent | null;
|
printArea: Extent | null;
|
||||||
@ -115,6 +118,8 @@ export const initializeMapState = (
|
|||||||
// Region select
|
// Region select
|
||||||
const regionSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'region' })
|
const regionSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'region' })
|
||||||
|
|
||||||
|
const districtSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'district' })
|
||||||
|
|
||||||
// Line select
|
// Line select
|
||||||
const lineSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })
|
const lineSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })
|
||||||
lineSelect.on('select', (e) => {
|
lineSelect.on('select', (e) => {
|
||||||
@ -183,7 +188,7 @@ export const initializeMapState = (
|
|||||||
|
|
||||||
const districtBoundLayer = new VectorImage({ style: new Style({ stroke: new Stroke({ color: 'red', width: 2 }), }) })
|
const districtBoundLayer = new VectorImage({ style: new Style({ stroke: new Stroke({ color: 'red', width: 2 }), }) })
|
||||||
|
|
||||||
const citiesLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Города' } })
|
const districtsLayer = new VectorImage({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Населенные пункты', type: 'district' } })
|
||||||
|
|
||||||
const linesLayer = new VectorLayer({
|
const linesLayer = new VectorLayer({
|
||||||
source: new VectorSource(),
|
source: new VectorSource(),
|
||||||
@ -266,10 +271,10 @@ export const initializeMapState = (
|
|||||||
baseLayer,
|
baseLayer,
|
||||||
satLayer,
|
satLayer,
|
||||||
staticMapLayer,
|
staticMapLayer,
|
||||||
regionsLayer,
|
|
||||||
districtBoundLayer,
|
|
||||||
citiesLayer,
|
|
||||||
linesLayer,
|
linesLayer,
|
||||||
|
districtsLayer,
|
||||||
|
districtBoundLayer,
|
||||||
|
regionsLayer,
|
||||||
figuresLayer,
|
figuresLayer,
|
||||||
drawingLayer,
|
drawingLayer,
|
||||||
imageLayer,
|
imageLayer,
|
||||||
@ -282,30 +287,48 @@ export const initializeMapState = (
|
|||||||
})
|
})
|
||||||
|
|
||||||
map.addInteraction(regionSelect)
|
map.addInteraction(regionSelect)
|
||||||
|
map.addInteraction(districtSelect)
|
||||||
map.addInteraction(lineSelect)
|
map.addInteraction(lineSelect)
|
||||||
map.addInteraction(lineHover)
|
map.addInteraction(lineHover)
|
||||||
map.addInteraction(figureSelect)
|
map.addInteraction(figureSelect)
|
||||||
map.addInteraction(figureHover)
|
map.addInteraction(figureHover)
|
||||||
|
|
||||||
// map.on('pointermove', function (e: MapBrowserEvent<UIEvent>) {
|
const pointerHandler = (e: MapBrowserEvent<UIEvent>) => {
|
||||||
// setCurrentCoordinate(id, e.coordinate)
|
setCurrentCoordinate(id, e.coordinate)
|
||||||
// const currentExtent = get('EPSG:3857')?.getExtent() as Extent
|
const currentExtent = get('EPSG:3857')?.getExtent() as Extent
|
||||||
// const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0)))
|
const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0)))
|
||||||
// setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0)))
|
setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0)))
|
||||||
// setCurrentX(id, tileX)
|
setCurrentX(id, tileX)
|
||||||
// setCurrentY(id, tileY)
|
setCurrentY(id, tileY)
|
||||||
|
|
||||||
// const pixel = map?.getEventPixel(e.originalEvent)
|
const pixel = map?.getEventPixel(e.originalEvent)
|
||||||
// if (pixel) {
|
if (pixel) {
|
||||||
// map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
|
let found = false;
|
||||||
// if (layer.get('type') === 'region') {
|
map?.forEachFeatureAtPixel(pixel, (feature, layer) => {
|
||||||
// if (feature.get('entity_id')) {
|
if (layer.get("type") === "region" && feature.get("entity_id")) {
|
||||||
// setStatusText(id, feature.get('entity_id'))
|
found = true
|
||||||
// }
|
|
||||||
// }
|
const name = getRegionsData()?.find(region => region.id === feature.get("entity_id"))?.name || feature.get("entity_id") || ""
|
||||||
// })
|
setStatusText(id, name);
|
||||||
// }
|
setStatusTextPosition(id, pixel[0], pixel[1]);
|
||||||
// })
|
}
|
||||||
|
|
||||||
|
if (layer.get("type") === "district" && feature.get("entity_id")) {
|
||||||
|
found = true
|
||||||
|
|
||||||
|
const name = getDistrictsData()?.find(district => district.id === feature.get("entity_id"))?.name || feature.get("entity_id") || ""
|
||||||
|
setStatusText(id, name);
|
||||||
|
setStatusTextPosition(id, pixel[0], pixel[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
setStatusText(id, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.on('pointermove', pointerHandler)
|
||||||
|
|
||||||
map.on('click', function (e: MapBrowserEvent<UIEvent>) {
|
map.on('click', function (e: MapBrowserEvent<UIEvent>) {
|
||||||
if (getAlignMode(id)) {
|
if (getAlignMode(id)) {
|
||||||
@ -332,11 +355,22 @@ export const initializeMapState = (
|
|||||||
if (pixel) {
|
if (pixel) {
|
||||||
map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
|
map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
|
||||||
if (layer) {
|
if (layer) {
|
||||||
if (layer.get('type') === 'region') {
|
if (layer.get('type') === 'region' && layer.getOpacity() !== 0) {
|
||||||
zoomToFeature(id, feature as Feature)
|
zoomToFeature(id, feature as Feature)
|
||||||
|
|
||||||
if (feature.get('entity_id')) {
|
if (feature.get('entity_id')) {
|
||||||
setSelectedRegion(id, feature.get('entity_id'))
|
setSelectedRegion(id, feature.get('entity_id'))
|
||||||
|
|
||||||
|
//regionsLayer.setVisible(false)
|
||||||
|
regionsLayer.setOpacity(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer.get('type') === 'district' && layer.getOpacity() !== 0) {
|
||||||
|
zoomToFeature(id, feature as Feature)
|
||||||
|
|
||||||
|
if (feature.get('entity_id')) {
|
||||||
|
setSelectedDistrict(id, feature.get('entity_id'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,7 +394,9 @@ export const initializeMapState = (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
regionsLayer.setVisible(!isViewCovered)
|
if (!getSelectedRegion(id)) {
|
||||||
|
regionsLayer.setOpacity(isViewCovered ? 0 : 1)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
map.setView(
|
map.setView(
|
||||||
@ -386,7 +422,8 @@ export const initializeMapState = (
|
|||||||
currentX: undefined,
|
currentX: undefined,
|
||||||
currentY: undefined,
|
currentY: undefined,
|
||||||
currentCoordinate: null,
|
currentCoordinate: null,
|
||||||
statusText: '',
|
statusText: null,
|
||||||
|
statusTextPosition: [0, 0],
|
||||||
satMapsProvider: 'google',
|
satMapsProvider: 'google',
|
||||||
selectedObjectType: null,
|
selectedObjectType: null,
|
||||||
alignMode: false,
|
alignMode: false,
|
||||||
@ -411,8 +448,8 @@ export const initializeMapState = (
|
|||||||
staticMapLayer: staticMapLayer,
|
staticMapLayer: staticMapLayer,
|
||||||
figuresLayer: figuresLayer,
|
figuresLayer: figuresLayer,
|
||||||
linesLayer: linesLayer,
|
linesLayer: linesLayer,
|
||||||
|
districtsLayer: districtsLayer,
|
||||||
regionsLayer: regionsLayer,
|
regionsLayer: regionsLayer,
|
||||||
citiesLayer: citiesLayer,
|
|
||||||
districtBoundLayer: districtBoundLayer,
|
districtBoundLayer: districtBoundLayer,
|
||||||
imageLayer: imageLayer,
|
imageLayer: imageLayer,
|
||||||
selectedArea: null,
|
selectedArea: null,
|
||||||
@ -421,6 +458,7 @@ export const initializeMapState = (
|
|||||||
measureModify: measureModify,
|
measureModify: measureModify,
|
||||||
nodeLayer: nodeLayer,
|
nodeLayer: nodeLayer,
|
||||||
overlayLayer: overlayLayer,
|
overlayLayer: overlayLayer,
|
||||||
|
districtSelect: districtSelect,
|
||||||
regionSelect: regionSelect,
|
regionSelect: regionSelect,
|
||||||
lineSelect: lineSelect,
|
lineSelect: lineSelect,
|
||||||
previousView: null,
|
previousView: null,
|
||||||
@ -644,7 +682,16 @@ export const setCurrentCoordinate = (id: string, c: Coordinate | null) => useMap
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const setStatusText = (id: string, t: string) => useMapStore.setState((state) => {
|
export const setStatusTextPosition = (id: string, left: number, top: number) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], statusTextPosition: [left, top] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setStatusText = (id: string, t: string | null) => useMapStore.setState((state) => {
|
||||||
return {
|
return {
|
||||||
id: {
|
id: {
|
||||||
...state.id,
|
...state.id,
|
||||||
|
@ -2,7 +2,7 @@ import { create } from 'zustand';
|
|||||||
|
|
||||||
interface ObjectsState {
|
interface ObjectsState {
|
||||||
id: Record<string, {
|
id: Record<string, {
|
||||||
selectedRegion: number | undefined;
|
selectedRegion: number | null;
|
||||||
selectedDistrict: number | null;
|
selectedDistrict: number | null;
|
||||||
selectedCity: number | null;
|
selectedCity: number | null;
|
||||||
selectedYear: number | null;
|
selectedYear: number | null;
|
||||||
@ -16,7 +16,7 @@ export const useObjectsStore = create<ObjectsState>(() => ({
|
|||||||
|
|
||||||
export const initializeObjectsState = (
|
export const initializeObjectsState = (
|
||||||
id: string,
|
id: string,
|
||||||
selectedRegion: number | undefined,
|
selectedRegion: number | null,
|
||||||
selectedDistrict: number | null,
|
selectedDistrict: number | null,
|
||||||
selectedCity: number | null,
|
selectedCity: number | null,
|
||||||
selectedYear: number | null,
|
selectedYear: number | null,
|
||||||
@ -46,7 +46,7 @@ export const setSelectedCity = (id: string, city: number | null) => useObjectsSt
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const getSelectedRegion = (id: string) => useObjectsStore.getState().id[id].selectedRegion
|
export const getSelectedRegion = (id: string) => useObjectsStore.getState().id[id].selectedRegion
|
||||||
export const setSelectedRegion = (id: string, region: number | undefined) => useObjectsStore.setState((state) => {
|
export const setSelectedRegion = (id: string, region: number | null) => useObjectsStore.setState((state) => {
|
||||||
return {
|
return {
|
||||||
id: {
|
id: {
|
||||||
...state.id,
|
...state.id,
|
||||||
|
36
client/src/store/regions.ts
Normal file
36
client/src/store/regions.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { IDistrict, IRegion } from '../interfaces/gis';
|
||||||
|
|
||||||
|
export interface RegionsState {
|
||||||
|
regionsData: IRegion[],
|
||||||
|
districtsData: IDistrict[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRegionsStore = create<RegionsState>(() => ({
|
||||||
|
regionsData: [],
|
||||||
|
districtsData: []
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const getRegionData = (id: number) => {
|
||||||
|
return useRegionsStore.getState().regionsData.find(region => region.id === id)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRegionsData = () => {
|
||||||
|
return useRegionsStore.getState().regionsData
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setRegionsData = (regionsData: any) => {
|
||||||
|
useRegionsStore.setState(() => ({ regionsData: regionsData }))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDistrictData = (id: number) => {
|
||||||
|
return useRegionsStore.getState().districtsData.find(district => district.id === id)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDistrictsData = () => {
|
||||||
|
return useRegionsStore.getState().districtsData
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setDistrictsData = (districtsData: any) => {
|
||||||
|
useRegionsStore.setState(() => ({ districtsData: districtsData }))
|
||||||
|
}
|
Reference in New Issue
Block a user