make mapstyles simpler

This commit is contained in:
Paul Bienkowski 2021-11-29 18:34:58 +01:00
parent 15dfb2dc3b
commit 38b1b92210
3 changed files with 73 additions and 86 deletions

View file

@ -3,6 +3,8 @@ import _ from 'lodash'
import bright from './bright.json' import bright from './bright.json'
import positron from './positron.json' import positron from './positron.json'
export {bright, positron}
export function colorByDistance(attribute = 'distance_overtaker_mean', fallback = '#ABC') { export function colorByDistance(attribute = 'distance_overtaker_mean', fallback = '#ABC') {
return [ return [
'case', 'case',
@ -24,62 +26,58 @@ export function colorByDistance(attribute = 'distance_overtaker_mean', fallback
] ]
} }
function addRoadsStyle(style, mapSource) { export const roadsLayer = {
style.sources.obs = mapSource id: 'obs',
type: 'line',
source: 'obs',
'source-layer': 'obs_roads',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
paint: {
'line-width': [
'interpolate',
['exponential', 1.5],
['zoom'],
12,
2,
17,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 2, 6],
],
'line-color': colorByDistance(),
'line-opacity': [
'interpolate',
['linear'],
['zoom'],
12,
0,
13,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 0, 1],
14,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 0, 1],
15,
1,
],
'line-offset': [
'interpolate',
['exponential', 1.5],
['zoom'],
12,
['get', 'offset_direction'],
19,
['*', ['get', 'offset_direction'], 8],
],
},
minzoom: 12,
}
// insert before "road_oneway" layer export const trackLayer = {
let idx = style.layers.findIndex((l) => l.id === 'road_oneway') type: 'line',
if (idx === -1) { paint: {
idx = style.layers.length 'line-width': ['interpolate', ['linear'], ['zoom'], 14, 2, 17, 5],
'line-color': '#F06292',
} }
style.layers.splice(idx, 0, {
id: 'obs',
type: 'line',
source: 'obs',
'source-layer': 'obs_roads',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
paint: {
'line-width': [
'interpolate',
['exponential', 1.5],
['zoom'],
12,
2,
17,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 2, 6],
],
'line-color': colorByDistance(),
'line-opacity': [
'interpolate',
['linear'],
['zoom'],
12,
0,
13,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 0, 1],
14,
['case', ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]], 0, 1],
15,
1,
],
'line-offset': [
'interpolate',
['exponential', 1.5],
['zoom'],
12,
['get', 'offset_direction'],
19,
['*', ['get', 'offset_direction'], 8],
],
},
minzoom: 12,
})
return style
} }
export const basemap = positron export const basemap = positron
export const obsRoads = (sourceUrl) => addRoadsStyle(_.cloneDeep(basemap), sourceUrl)

View file

@ -1,13 +1,14 @@
import React from 'react' import React from 'react'
import ReactMapGl, {AttributionControl, NavigationControl, Layer, Source} from 'react-map-gl'
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 {useHistory, useLocation} from 'react-router-dom'
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 {roadsLayer, basemap} from '../mapstyles'
function parseHash(v) { function parseHash(v) {
if (!v) return null if (!v) return null
@ -37,52 +38,47 @@ function useViewportFromUrl() {
return [value || EMPTY_VIEWPORT, setter] return [value || EMPTY_VIEWPORT, setter]
} }
function CustomMapInner({viewportFromUrl, mapSource, config, mode, children}: {viewportFromUrl?: boolean, mapSource: string, config: Config, mode?: 'roads'}) { export function CustomMap({viewportFromUrl, children, boundsFromJson}: {viewportFromUrl?: boolean, children: React.ReactNode}) {
const mapStyle = React.useMemo(() => {
if (mode === 'roads') {
return mapSource && obsRoads(mapSource)
} else {
return basemap
}
}, [mapSource, mode])
const [viewportState, setViewportState] = React.useState(EMPTY_VIEWPORT) const [viewportState, setViewportState] = React.useState(EMPTY_VIEWPORT)
const [viewportUrl, setViewportUrl] = useViewportFromUrl() const [viewportUrl, setViewportUrl] = useViewportFromUrl()
const [viewport, setViewport] = viewportFromUrl ? [viewportUrl, setViewportUrl] : [viewportState, setViewportState] const [viewport, setViewport] = viewportFromUrl ? [viewportUrl, setViewportUrl] : [viewportState, setViewportState]
const config = useConfig()
React.useEffect(() => { React.useEffect(() => {
if (config?.mapHome && viewport.zoom === 0) { if (config?.mapHome && viewport.zoom === 0) {
setViewport(config.mapHome) setViewport(config.mapHome)
} }
}, [config]) }, [config])
if (!mapStyle) {
return null
}
return ( return (
<ReactMapGl mapStyle={mapStyle} width="100%" height="100%" onViewportChange={setViewport} {...viewport}> <ReactMapGl mapStyle={basemap} width="100%" height="100%" onViewportChange={setViewport} {...viewport}>
<AttributionControl style={{right: 0, bottom: 0}} customAttribution={[ <AttributionControl style={{right: 0, bottom: 0}} customAttribution={[
'<a href="https://openstreetmap.org/copyright" target="_blank" rel="nofollow noopener noreferrer">© OpenStreetMap contributors</a>', '<a href="https://openstreetmap.org/copyright" target="_blank" rel="nofollow noopener noreferrer">© OpenStreetMap contributors</a>',
'<a href="https://openmaptiles.org/" target="_blank" rel="nofollow noopener noreferrer">© OpenMapTiles</a>', '<a href="https://openmaptiles.org/" target="_blank" rel="nofollow noopener noreferrer">© OpenMapTiles</a>',
'<a href="https://openbikesensor.org/" target="_blank" rel="nofollow noopener noreferrer">© OpenBikeSensor</a>', '<a href="https://openbikesensor.org/" target="_blank" rel="nofollow noopener noreferrer">© OpenBikeSensor</a>',
]} /> ]} />
<NavigationControl style={{left: 0, top: 0}} />
{children} {children}
</ReactMapGl> </ReactMapGl>
) )
} }
export function CustomMap(props) { export function RoadsMap() {
const config = useConfig() || {} const {obsMapSource} = useConfig() || {}
if (!config) return null;
const {obsMapSource: mapSource} = config
if (!mapSource) return null; if (!obsMapSource) {
return null;
}
return ( return (
<CustomMapInner {...{mapSource, config}} {...props} /> <CustomMap viewportFromUrl>
<Source id="obs" {...obsMapSource}>
<Layer {...roadsLayer} />
</Source>
</CustomMap>
) )
} }
@ -90,7 +86,7 @@ export default function MapPage() {
return ( return (
<Page fullScreen> <Page fullScreen>
<div className={styles.mapContainer}> <div className={styles.mapContainer}>
<CustomMap mode='roads' viewportFromUrl /> <RoadsMap />
</div> </div>
</Page> </Page>
) )

View file

@ -4,7 +4,7 @@ import {Source, Layer} from 'react-map-gl'
import type {TrackData} from 'types' import type {TrackData} from 'types'
import {CustomMap} from '../MapPage' import {CustomMap} from '../MapPage'
import {colorByDistance} from '../../mapstyles' import {colorByDistance, trackLayer} from '../../mapstyles'
export default function TrackMap({ export default function TrackMap({
trackData, trackData,
@ -27,14 +27,7 @@ export default function TrackMap({
<CustomMap> <CustomMap>
{showTrack && ( {showTrack && (
<Source id="route" type="geojson" data={trackData.track}> <Source id="route" type="geojson" data={trackData.track}>
<Layer <Layer id="route" {...trackLayer} />
id="route"
type="line"
paint={{
'line-width': ['interpolate', ['linear'], ['zoom'], 14, 2, 17, 5],
'line-color': '#F06292',
}}
/>
</Source> </Source>
)} )}