feat: put map page viewport into URL
This commit is contained in:
parent
9c7b1bc662
commit
15dfb2dc3b
|
@ -2,13 +2,42 @@ import React from 'react'
|
||||||
|
|
||||||
import {Page} from 'components'
|
import {Page} from 'components'
|
||||||
import {useConfig, Config} from 'config'
|
import {useConfig, Config} from 'config'
|
||||||
|
import {useHistory, useLocation} from 'react-router-dom'
|
||||||
import ReactMapGl, {AttributionControl } from 'react-map-gl'
|
import ReactMapGl, {AttributionControl } from 'react-map-gl'
|
||||||
|
|
||||||
import styles from './MapPage.module.less'
|
import styles from './MapPage.module.less'
|
||||||
|
|
||||||
import {obsRoads, basemap } from '../mapstyles'
|
import {obsRoads, basemap } from '../mapstyles'
|
||||||
|
|
||||||
function CustomMapInner({mapSource, config, mode, children}: {mapSource: string, config: Config, mode?: 'roads'}) {
|
function parseHash(v) {
|
||||||
|
if (!v) return null
|
||||||
|
const m = v.match(/^#([0-9\.]+)\/([0-9\.]+)\/([0-9\.]+)$/)
|
||||||
|
if (!m) return null
|
||||||
|
return {
|
||||||
|
zoom: Number.parseFloat(m[1]),
|
||||||
|
latitude: Number.parseFloat(m[2]),
|
||||||
|
longitude: Number.parseFloat(m[3]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const EMPTY_VIEWPORT = {longitude: 0, latitude: 0, zoom: 0}
|
||||||
|
|
||||||
|
function buildHash(v) {
|
||||||
|
return `${v.zoom.toFixed(2)}/${v.latitude}/${v.longitude}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function useViewportFromUrl() {
|
||||||
|
const history = useHistory()
|
||||||
|
const location = useLocation()
|
||||||
|
const value = React.useMemo(() => parseHash(location.hash), [location.hash])
|
||||||
|
const setter = React.useCallback((v) => {
|
||||||
|
history.replace({
|
||||||
|
hash: buildHash(v)
|
||||||
|
})
|
||||||
|
}, [history])
|
||||||
|
return [value || EMPTY_VIEWPORT, setter]
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomMapInner({viewportFromUrl, mapSource, config, mode, children}: {viewportFromUrl?: boolean, mapSource: string, config: Config, mode?: 'roads'}) {
|
||||||
const mapStyle = React.useMemo(() => {
|
const mapStyle = React.useMemo(() => {
|
||||||
if (mode === 'roads') {
|
if (mode === 'roads') {
|
||||||
return mapSource && obsRoads(mapSource)
|
return mapSource && obsRoads(mapSource)
|
||||||
|
@ -17,14 +46,13 @@ function CustomMapInner({mapSource, config, mode, children}: {mapSource: string,
|
||||||
}
|
}
|
||||||
}, [mapSource, mode])
|
}, [mapSource, mode])
|
||||||
|
|
||||||
const [viewport, setViewport] = React.useState({
|
const [viewportState, setViewportState] = React.useState(EMPTY_VIEWPORT)
|
||||||
longitude: 0,
|
const [viewportUrl, setViewportUrl] = useViewportFromUrl()
|
||||||
latitude: 0,
|
|
||||||
zoom: 0,
|
const [viewport, setViewport] = viewportFromUrl ? [viewportUrl, setViewportUrl] : [viewportState, setViewportState]
|
||||||
})
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (config?.mapHome) {
|
if (config?.mapHome && viewport.zoom === 0) {
|
||||||
setViewport(config.mapHome)
|
setViewport(config.mapHome)
|
||||||
}
|
}
|
||||||
}, [config])
|
}, [config])
|
||||||
|
@ -62,7 +90,7 @@ export default function MapPage() {
|
||||||
return (
|
return (
|
||||||
<Page fullScreen>
|
<Page fullScreen>
|
||||||
<div className={styles.mapContainer}>
|
<div className={styles.mapContainer}>
|
||||||
<CustomMap mode='roads' />
|
<CustomMap mode='roads' viewportFromUrl />
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue