save current state.

This commit is contained in:
gluap 2022-06-24 18:52:59 +02:00
parent 3a7929cf8a
commit a6725cdc1a
No known key found for this signature in database
2 changed files with 84 additions and 92 deletions

View file

@ -1,12 +1,7 @@
import React from "react"; import React from "react";
import _ from "lodash"; import _ from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { import {List, Select, Input, Divider, Label,
List,
Select,
Input,
Divider,
Label,
Checkbox, Checkbox,
Header, Header,
} from "semantic-ui-react"; } from "semantic-ui-react";
@ -23,18 +18,13 @@ import { ColorMapLegend, DiscreteColorMapLegend } from "components";
const BASEMAP_STYLE_OPTIONS = ["positron", "bright"]; const BASEMAP_STYLE_OPTIONS = ["positron", "bright"];
const ROAD_ATTRIBUTE_OPTIONS = [ const ROAD_ATTRIBUTE_OPTIONS = [
"distance_overtaker_mean", {value: 'distance_overtaker_mean', key: 'distance_overtaker_mean', text: 'Overtaker distance mean'},
"distance_overtaker_min", {value: 'distance_overtaker_min', key: 'distance_overtaker_min', text: 'Overtaker distance minimum'},
"distance_overtaker_max", {value: 'distance_overtaker_max', key: 'distance_overtaker_max', text: 'Overtaker distance maximum'},
"distance_overtaker_median", {value: 'distance_overtaker_median', key: 'distance_overtaker_median', text: 'Overtaker distance median'},
"overtaking_event_count", {value: 'overtaking_event_count', key: 'overtaking_event_count', text: 'Event count'},
"usage_count", {value: 'usage_count', key: 'usage_count', text: 'Usage count'},
"zone", ]
];
const DATE_FILTER_MODES = ["none", "range", "threshold"];
type User = Object;
function LayerSidebar({ function LayerSidebar({
mapConfig, mapConfig,

View file

@ -1,50 +1,47 @@
import React, {useState, useCallback, useMemo, useRef} from 'react' import React, { useState, useCallback, useMemo, useRef } from "react";
import _ from 'lodash' import _ from "lodash";
import { connect } from "react-redux"; import { Button } from "semantic-ui-react";
import { Layer, Source } from "react-map-gl";
import {Button} from 'semantic-ui-react' import produce from "immer";
import {Layer, Source} from 'react-map-gl'
import produce from 'immer'
import classNames from "classnames";
import api from "api"; import api from "api";
import { Page, Map } from "components"; import { Page, Map } from "components";
import { useConfig } from "config"; import { useConfig } from "config";
import { colorByDistance, borderByZone, colorByCount, reds, isValidAttribute } from "mapstyles"; import { colorByDistance, borderByZone, colorByCount, reds, getRegionLayers, isValidAttribute } from "mapstyles";
import { useMapConfig } from "reducers/mapConfig"; import { useMapConfig } from "reducers/mapConfig";
import RoadInfo from "./RoadInfo"; import RoadInfo from './RoadInfo'
import RegionInfo from "./RegionInfo"; import RegionInfo from "./RegionInfo";
import LayerSidebar from "./LayerSidebar"; import LayerSidebar from './LayerSidebar'
import styles from "./styles.module.less"; import styles from './styles.module.less'
const untaggedRoadsLayer = { const untaggedRoadsLayer = {
id: "obs_roads_untagged", id: 'obs_roads_untagged',
type: "line", type: 'line',
source: "obs", source: 'obs',
"source-layer": "obs_roads", 'source-layer': 'obs_roads',
minzoom: 12, minzoom: 12,
filter: ["!", ["to-boolean", ["get", "distance_overtaker_mean"]]], filter: ['!', ['to-boolean', ['get', 'distance_overtaker_mean']]],
layout: { layout: {
"line-cap": "round", 'line-cap': 'round',
"line-join": "round", 'line-join': 'round',
}, },
paint: { paint: {
"line-width": ["interpolate", ["exponential", 1.5], ["zoom"], 12, 2, 17, 2], 'line-width': ['interpolate', ['exponential', 1.5], ['zoom'], 12, 2, 17, 2],
"line-color": "#ABC", 'line-color': '#ABC',
'line-opacity': ['interpolate', ['linear'], ['zoom'], 14, 0, 15, 1], 'line-opacity': ['interpolate', ['linear'], ['zoom'], 14, 0, 15, 1],
"line-offset": [ 'line-offset': [
"interpolate", 'interpolate',
["exponential", 1.5], ['exponential', 1.5],
["zoom"], ['zoom'],
12, 12,
["get", "offset_direction"], ['get', 'offset_direction'],
19, 19,
["*", ["get", "offset_direction"], 8], ['*', ['get', 'offset_direction'], 8],
], ],
}, },
minzoom: 12, minzoom: 12,
}; }
const getUntaggedRoadsLayer = (colorAttribute, maxCount) => const getUntaggedRoadsLayer = (colorAttribute, maxCount) =>
produce(untaggedRoadsLayer, (draft) => { produce(untaggedRoadsLayer, (draft) => {
@ -59,7 +56,7 @@ const getRoadsLayer = (colorAttribute, maxCount) =>
draft.paint["line-width"][6] = 6; // scale bigger on zoom draft.paint["line-width"][6] = 6; // scale bigger on zoom
draft.paint["line-color"] = colorAttribute.startsWith("distance_") draft.paint["line-color"] = colorAttribute.startsWith("distance_")
? colorByDistance(colorAttribute) ? colorByDistance(colorAttribute)
: colorAttribute.endsWith("_count") : colorAttribute.endsWith('_count')
? colorByCount(colorAttribute, maxCount) ? colorByCount(colorAttribute, maxCount)
: colorAttribute.endsWith("zone") : colorAttribute.endsWith("zone")
? borderByZone() ? borderByZone()
@ -69,42 +66,44 @@ const getRoadsLayer = (colorAttribute, maxCount) =>
}); });
const getEventsLayer = () => ({ const getEventsLayer = () => ({
id: "obs_events", id: 'obs_events',
type: "circle", type: 'circle',
source: "obs", source: 'obs',
"source-layer": "obs_events", 'source-layer': 'obs_events',
paint: { paint: {
"circle-radius": ["interpolate", ["linear"], ["zoom"], 14, 3, 17, 8], 'circle-radius': ['interpolate', ['linear'], ['zoom'], 14, 3, 17, 8],
"circle-color": colorByDistance("distance_overtaker"), 'circle-color': colorByDistance('distance_overtaker'),
'circle-stroke-color': borderByZone(),
'circle-stroke-width':['interpolate', ['linear'], ['zoom'], 14, 1, 17, 4],
}, },
minzoom: 11, minzoom: 11,
}); })
const getEventsTextLayer = () => ({ const getEventsTextLayer = () => ({
id: "obs_events_text", id: 'obs_events_text',
type: "symbol", type: 'symbol',
minzoom: 18, minzoom: 18,
source: "obs", source: 'obs',
"source-layer": "obs_events", 'source-layer': 'obs_events',
layout: { layout: {
"text-field": [ 'text-field': [
"number-format", 'number-format',
["get", "distance_overtaker"], ['get', 'distance_overtaker'],
{ "min-fraction-digits": 2, "max-fraction-digits": 2 }, {'min-fraction-digits': 2, 'max-fraction-digits': 2},
], ],
"text-allow-overlap": true, 'text-allow-overlap': true,
"text-font": ["Open Sans Bold", "Arial Unicode MS Regular"], 'text-font': ['Open Sans Bold', 'Arial Unicode MS Regular'],
"text-size": 14, 'text-size': 14,
"text-keep-upright": false, 'text-keep-upright': false,
"text-anchor": "left", 'text-anchor': 'left',
"text-radial-offset": 1, 'text-radial-offset': 1,
"text-rotate": ["-", 90, ["*", ["get", "course"], 180 / Math.PI]], 'text-rotate': ['-', 90, ['*', ['get', 'course'], 180 / Math.PI]],
"text-rotation-alignment": "map", 'text-rotation-alignment': 'map',
}, },
paint: { paint: {
"text-halo-color": "rgba(255, 255, 255, 1)", 'text-halo-color': 'rgba(255, 255, 255, 1)',
"text-halo-width": 1, 'text-halo-width': 1,
"text-opacity": ["interpolate", ["linear"], ["zoom"], 15, 0, 15.3, 1], 'text-opacity': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.3, 1],
}, },
}); });
@ -153,11 +152,14 @@ type Details =
| { type: "region"; region: RegionInfo }; | { type: "region"; region: RegionInfo };
function MapPage({ login }) { function MapPage({ login }) {
const { obsMapSource, banner } = useConfig() || {}; const {obsMapSource, banner } = useConfig() || {}
const [details, setDetails] = useState<null | Details>(null); const [details, setDetails] = useState<null | Details>(null);
const [clickLocation, setClickLocation] = useState<{longitude: number; latitude: number} | null>(null)
const onCloseDetails = useCallback(() => setDetails(null), [setDetails]); const onCloseDetails = useCallback(() => setDetails(null), [setDetails]);
const mapConfig = useMapConfig(); const mapConfig = useMapConfig();
const viewportRef = useRef(); const viewportRef = useRef();
@ -179,11 +181,12 @@ function MapPage({ login }) {
node?.classList?.contains(className) node?.classList?.contains(className)
) )
) { ) {
return; return
} }
node = node.parentNode; node = node.parentNode
} }
setClickLocation({longitude: e.lngLat[0], latitude: e.lngLat[1]})
const { zoom } = viewportRef.current; const { zoom } = viewportRef.current;
if (zoom < 10) { if (zoom < 10) {
@ -206,26 +209,23 @@ function MapPage({ login }) {
setClickLocation(null); setClickLocation(null);
}, [setClickLocation]); }, [setClickLocation]);
const [layerSidebar, setLayerSidebar] = useState(true); const [layerSidebar, setLayerSidebar] = useState(true)
const { const {
obsRoads: { attribute, maxCount }, obsRoads: {attribute, maxCount},
} = mapConfig; } = mapConfig
const layers = []; const layers = []
const untaggedRoadsLayerCustom = useMemo( const untaggedRoadsLayerCustom = useMemo(
() => getUntaggedRoadsLayer(attribute), () => getUntaggedRoadsLayer(attribute),
[attribute] [attribute]
); );
if (mapConfig.obsRoads.show && mapConfig.obsRoads.showUntagged) { if (mapConfig.obsRoads.show && mapConfig.obsRoads.showUntagged) {
layers.push(untaggedRoadsLayerCustom); layers.push(untaggedRoadsLayerCustom)
} }
const roadsLayer = useMemo( const roadsLayer = useMemo(() => getRoadsLayer(attribute, maxCount), [attribute, maxCount])
() => getRoadsLayer(attribute, maxCount),
[attribute, maxCount]
);
if (mapConfig.obsRoads.show) { if (mapConfig.obsRoads.show) {
layers.push(roadsLayer); layers.push(roadsLayer);
} }
@ -235,11 +235,11 @@ function MapPage({ login }) {
layers.push(...regionLayers); layers.push(...regionLayers);
} }
const eventsLayer = useMemo(() => getEventsLayer(), []); const eventsLayer = useMemo(() => getEventsLayer(), [])
const eventsTextLayer = useMemo(() => getEventsTextLayer(), []); const eventsTextLayer = useMemo(() => getEventsTextLayer(), [])
if (mapConfig.obsEvents.show) { if (mapConfig.obsEvents.show) {
layers.push(eventsLayer); layers.push(eventsLayer)
layers.push(eventsTextLayer); layers.push(eventsTextLayer)
} }
const onToggleLayerSidebarButtonClick = useCallback( const onToggleLayerSidebarButtonClick = useCallback(
@ -253,7 +253,7 @@ function MapPage({ login }) {
); );
if (!obsMapSource) { if (!obsMapSource) {
return null; return null
} }
const tiles = obsMapSource?.tiles?.map((tileUrl: string) => { const tiles = obsMapSource?.tiles?.map((tileUrl: string) => {
@ -301,7 +301,7 @@ function MapPage({ login }) {
</div> </div>
)} )}
<div className={styles.map}> <div className={styles.map}>
<Map viewportFromUrl onClick={onClick} onViewportChange={onViewportChange} hasToolbar> <Map viewportFromUrl onClick={onClick} onViewportChange={onViewportChange}hasToolbar>
<Button <Button
style={{ style={{
position: 'absolute', position: 'absolute',
@ -333,11 +333,13 @@ function MapPage({ login }) {
onClose={onCloseDetails} onClose={onCloseDetails}
/> />
)} )}
<RoadInfo {...{clickLocation}} />
</Map> </Map>
</div> </div>
</div> </div>
</Page> </Page>
); )
} }
export default connect((state) => ({ login: state.login }))(MapPage); export default connect((state) => ({ login: state.login }))(MapPage);