Translate MapPage
This commit is contained in:
parent
a977e2d1c3
commit
248f8b4a6f
|
@ -1,53 +1,66 @@
|
|||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
import {List, Select, Input, Divider, Label, Checkbox, Header} from 'semantic-ui-react'
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
List,
|
||||
Select,
|
||||
Input,
|
||||
Divider,
|
||||
Label,
|
||||
Checkbox,
|
||||
Header,
|
||||
} from "semantic-ui-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
MapConfig,
|
||||
setMapConfigFlag as setMapConfigFlagAction,
|
||||
initialState as defaultMapConfig,
|
||||
} from 'reducers/mapConfig'
|
||||
import {colorByDistance, colorByCount, viridisSimpleHtml} from 'mapstyles'
|
||||
import {ColorMapLegend, DiscreteColorMapLegend} from 'components'
|
||||
} from "reducers/mapConfig";
|
||||
import { colorByDistance, colorByCount, viridisSimpleHtml } from "mapstyles";
|
||||
import { ColorMapLegend, DiscreteColorMapLegend } from "components";
|
||||
|
||||
const BASEMAP_STYLE_OPTIONS = [
|
||||
{value: 'positron', key: 'positron', text: 'Positron'},
|
||||
{value: 'bright', key: 'bright', text: 'OSM Bright'},
|
||||
]
|
||||
const BASEMAP_STYLE_OPTIONS = ["positron", "bright"];
|
||||
|
||||
const ROAD_ATTRIBUTE_OPTIONS = [
|
||||
{value: 'distance_overtaker_mean', key: 'distance_overtaker_mean', text: 'Overtaker distance mean'},
|
||||
{value: 'distance_overtaker_min', key: 'distance_overtaker_min', text: 'Overtaker distance minimum'},
|
||||
{value: 'distance_overtaker_max', key: 'distance_overtaker_max', text: 'Overtaker distance maximum'},
|
||||
{value: 'distance_overtaker_median', key: 'distance_overtaker_median', text: 'Overtaker distance median'},
|
||||
{value: 'overtaking_event_count', key: 'overtaking_event_count', text: 'Event count'},
|
||||
{value: 'usage_count', key: 'usage_count', text: 'Usage count'},
|
||||
{value: 'zone', key: 'zone', text: 'Overtaking distance zone'}
|
||||
]
|
||||
"distance_overtaker_mean",
|
||||
"distance_overtaker_min",
|
||||
"distance_overtaker_max",
|
||||
"distance_overtaker_median",
|
||||
"overtaking_event_count",
|
||||
"usage_count",
|
||||
"zone",
|
||||
];
|
||||
|
||||
function LayerSidebar({
|
||||
mapConfig,
|
||||
setMapConfigFlag,
|
||||
}: {
|
||||
mapConfig: MapConfig
|
||||
setMapConfigFlag: (flag: string, value: unknown) => void
|
||||
mapConfig: MapConfig;
|
||||
setMapConfigFlag: (flag: string, value: unknown) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
baseMap: {style},
|
||||
obsRoads: {show: showRoads, showUntagged, attribute, maxCount},
|
||||
obsEvents: {show: showEvents},
|
||||
} = mapConfig
|
||||
baseMap: { style },
|
||||
obsRoads: { show: showRoads, showUntagged, attribute, maxCount },
|
||||
obsEvents: { show: showEvents },
|
||||
} = mapConfig;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<List relaxed>
|
||||
<List.Item>
|
||||
<List.Header>Basemap Style</List.Header>
|
||||
<List.Header>{t("MapPage.sidebar.baseMap.style.label")}</List.Header>
|
||||
<Select
|
||||
options={BASEMAP_STYLE_OPTIONS}
|
||||
options={BASEMAP_STYLE_OPTIONS.map((value) => ({
|
||||
value,
|
||||
key: value,
|
||||
text: t(`MapPage.sidebar.baseMap.style.${value}`),
|
||||
}))}
|
||||
value={style}
|
||||
onChange={(_e, {value}) => setMapConfigFlag('baseMap.style', value)}
|
||||
onChange={(_e, { value }) =>
|
||||
setMapConfigFlag("baseMap.style", value)
|
||||
}
|
||||
/>
|
||||
</List.Item>
|
||||
<Divider />
|
||||
|
@ -56,12 +69,12 @@ function LayerSidebar({
|
|||
toggle
|
||||
size="small"
|
||||
id="obsRoads.show"
|
||||
style={{float: 'right'}}
|
||||
style={{ float: "right" }}
|
||||
checked={showRoads}
|
||||
onChange={() => setMapConfigFlag('obsRoads.show', !showRoads)}
|
||||
onChange={() => setMapConfigFlag("obsRoads.show", !showRoads)}
|
||||
/>
|
||||
<label htmlFor="obsRoads.show">
|
||||
<Header as="h4">Road segments</Header>
|
||||
<Header as="h4">{t("MapPage.sidebar.obsRoads.title")}</Header>
|
||||
</label>
|
||||
</List.Item>
|
||||
{showRoads && (
|
||||
|
@ -69,49 +82,80 @@ function LayerSidebar({
|
|||
<List.Item>
|
||||
<Checkbox
|
||||
checked={showUntagged}
|
||||
onChange={() => setMapConfigFlag('obsRoads.showUntagged', !showUntagged)}
|
||||
label="Include roads without data"
|
||||
onChange={() =>
|
||||
setMapConfigFlag("obsRoads.showUntagged", !showUntagged)
|
||||
}
|
||||
label={t("MapPage.sidebar.obsRoads.showUntagged.label")}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<List.Header>Color based on</List.Header>
|
||||
<List.Header>
|
||||
{t("MapPage.sidebar.obsRoads.attribute.label")}
|
||||
</List.Header>
|
||||
<Select
|
||||
fluid
|
||||
options={ROAD_ATTRIBUTE_OPTIONS}
|
||||
options={ROAD_ATTRIBUTE_OPTIONS.map((value) => ({
|
||||
value,
|
||||
key: value,
|
||||
text: t(`MapPage.sidebar.obsRoads.attribute.${value}`),
|
||||
}))}
|
||||
value={attribute}
|
||||
onChange={(_e, {value}) => setMapConfigFlag('obsRoads.attribute', value)}
|
||||
onChange={(_e, { value }) =>
|
||||
setMapConfigFlag("obsRoads.attribute", value)
|
||||
}
|
||||
/>
|
||||
</List.Item>
|
||||
{attribute.endsWith('_count') ? (
|
||||
<>
|
||||
{attribute.endsWith("_count") ? (
|
||||
<>
|
||||
<List.Item>
|
||||
<List.Header>
|
||||
{t("MapPage.sidebar.obsRoads.maxCount.label")}
|
||||
</List.Header>
|
||||
<Input
|
||||
fluid
|
||||
type="number"
|
||||
value={maxCount}
|
||||
onChange={(_e, { value }) =>
|
||||
setMapConfigFlag("obsRoads.maxCount", value)
|
||||
}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<ColorMapLegend
|
||||
map={_.chunk(
|
||||
colorByCount(
|
||||
"obsRoads.maxCount",
|
||||
mapConfig.obsRoads.maxCount,
|
||||
viridisSimpleHtml
|
||||
).slice(3),
|
||||
2
|
||||
)}
|
||||
twoTicks
|
||||
/>
|
||||
</List.Item>
|
||||
</>
|
||||
) : (
|
||||
<List.Item>
|
||||
<List.Header>Maximum value</List.Header>
|
||||
<Input
|
||||
fluid
|
||||
type="number"
|
||||
value={maxCount}
|
||||
onChange={(_e, {value}) => setMapConfigFlag('obsRoads.maxCount', value)}
|
||||
<DiscreteColorMapLegend
|
||||
map={colorByDistance("distance_overtaker")[3].slice(2)}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<ColorMapLegend map={_.chunk(colorByCount('obsRoads.maxCount', mapConfig.obsRoads.maxCount, viridisSimpleHtml ).slice(3), 2)} twoTicks />
|
||||
</List.Item></>
|
||||
) :
|
||||
attribute.endsWith('zone') ? (
|
||||
<>
|
||||
<List.Item>
|
||||
<Label size="small" style={{background: "blue",color:"white"}}>urban (1.5 m)</Label>
|
||||
<Label size="small" style={{background: "cyan", color:"black"}}>rural (2 m)</Label>
|
||||
<Label size="small" style={{background: "blue",color:"white"}}>{t("general.urban")} (1.5 m)</Label>
|
||||
<Label size="small" style={{background: "cyan", color:"black"}}>{t("general.rural")}(2 m)</Label>
|
||||
</List.Item></>
|
||||
) :
|
||||
(
|
||||
<>
|
||||
<List.Item>
|
||||
<List.Header>Urban</List.Header>
|
||||
<List.Header>{_.startCase(t("general.urban"))}</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][5].slice(2)} />
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<List.Header>Rural</List.Header>
|
||||
<List.Header>{_.startCase(t("general.rural"))}</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][3].slice(2)} />
|
||||
</List.Item>
|
||||
</>
|
||||
|
@ -124,29 +168,29 @@ function LayerSidebar({
|
|||
toggle
|
||||
size="small"
|
||||
id="obsEvents.show"
|
||||
style={{float: 'right'}}
|
||||
style={{ float: "right" }}
|
||||
checked={showEvents}
|
||||
onChange={() => setMapConfigFlag('obsEvents.show', !showEvents)}
|
||||
onChange={() => setMapConfigFlag("obsEvents.show", !showEvents)}
|
||||
/>
|
||||
<label htmlFor="obsEvents.show">
|
||||
<Header as="h4">Event points</Header>
|
||||
<Header as="h4">{t("MapPage.sidebar.obsEvents.title")}</Header>
|
||||
</label>
|
||||
</List.Item>
|
||||
{showEvents && (
|
||||
<>
|
||||
<List.Item>
|
||||
<List.Header>Urban</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][5].slice(2)} />
|
||||
</List.Item>
|
||||
<List.Header>{_.startCase(t('general.urban'))}</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][5].slice(2)} />
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<List.Header>Rural</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][3].slice(2)} />
|
||||
<List.Header>{_.startCase(t('general.rural'))}</List.Header>
|
||||
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][3].slice(2)} />
|
||||
</List.Item>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
|
@ -158,6 +202,6 @@ export default connect(
|
|||
//
|
||||
),
|
||||
}),
|
||||
{setMapConfigFlag: setMapConfigFlagAction}
|
||||
{ setMapConfigFlag: setMapConfigFlagAction }
|
||||
//
|
||||
)(LayerSidebar)
|
||||
)(LayerSidebar);
|
||||
|
|
|
@ -1,83 +1,95 @@
|
|||
import React, {useState, useCallback} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Segment, Menu, Header, Label, Icon, Table} from 'semantic-ui-react'
|
||||
import {Layer, Source} from 'react-map-gl'
|
||||
import {of, from, concat} from 'rxjs'
|
||||
import {useObservable} from 'rxjs-hooks'
|
||||
import {switchMap, distinctUntilChanged} from 'rxjs/operators'
|
||||
import {Chart} from 'components'
|
||||
import {pairwise} from 'utils'
|
||||
import React, { useState, useCallback } from "react";
|
||||
import _ from "lodash";
|
||||
import { Segment, Menu, Header, Label, Icon, Table } from "semantic-ui-react";
|
||||
import { Layer, Source } from "react-map-gl";
|
||||
import { of, from, concat } from "rxjs";
|
||||
import { useObservable } from "rxjs-hooks";
|
||||
import { switchMap, distinctUntilChanged } from "rxjs/operators";
|
||||
import { Chart } from "components";
|
||||
import { pairwise } from "utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import api from 'api'
|
||||
import {colorByDistance, borderByZone} from 'mapstyles'
|
||||
|
||||
import styles from './styles.module.less'
|
||||
import styles from "./styles.module.less";
|
||||
|
||||
function selectFromColorMap(colormap, value) {
|
||||
let last = null
|
||||
let last = null;
|
||||
for (let i = 0; i < colormap.length; i += 2) {
|
||||
if (colormap[i + 1] > value) {
|
||||
return colormap[i]
|
||||
return colormap[i];
|
||||
}
|
||||
}
|
||||
return colormap[colormap.length - 1]
|
||||
return colormap[colormap.length - 1];
|
||||
}
|
||||
|
||||
const UNITS = {distanceOvertaker: 'm', distanceStationary: 'm', speed: 'km/h'}
|
||||
const LABELS = {
|
||||
distanceOvertaker: 'Left',
|
||||
distanceStationary: 'Right',
|
||||
speed: 'Speed',
|
||||
count: 'No. of Measurements',
|
||||
min: 'Minimum',
|
||||
median: 'Median',
|
||||
max: 'Maximum',
|
||||
mean: 'Average',
|
||||
}
|
||||
const ZONE_COLORS = {urban: 'blue', rural: 'cyan', motorway: 'purple'}
|
||||
const CARDINAL_DIRECTIONS = ['north', 'north-east', 'east', 'south-east', 'south', 'south-west', 'west', 'north-west']
|
||||
const getCardinalDirection = (bearing) =>
|
||||
bearing == null
|
||||
? 'unknown'
|
||||
: CARDINAL_DIRECTIONS[
|
||||
Math.floor(((bearing / 360.0) * CARDINAL_DIRECTIONS.length + 0.5) % CARDINAL_DIRECTIONS.length)
|
||||
] + ' bound'
|
||||
const UNITS = {
|
||||
distanceOvertaker: "m",
|
||||
distanceStationary: "m",
|
||||
speed: "km/h",
|
||||
};
|
||||
const ZONE_COLORS = { urban: "blue", rural: "cyan", motorway: "purple" };
|
||||
const CARDINAL_DIRECTIONS = [
|
||||
"north",
|
||||
"northEast",
|
||||
"east",
|
||||
"southEast",
|
||||
"south",
|
||||
"southWest",
|
||||
"west",
|
||||
"northWest",
|
||||
];
|
||||
const getCardinalDirection = (t, bearing) => {
|
||||
if (bearing == null) {
|
||||
return t("MapPage.roadInfo.cardinalDirections.unknown");
|
||||
} else {
|
||||
const n = CARDINAL_DIRECTIONS.length;
|
||||
const i = Math.floor(((bearing / 360.0) * n + 0.5) % n);
|
||||
const name = CARDINAL_DIRECTIONS[i];
|
||||
return t(`MapPage.roadInfo.cardinalDirections.${name}`);
|
||||
}
|
||||
};
|
||||
|
||||
function RoadStatsTable({data}) {
|
||||
function RoadStatsTable({ data }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Table size="small" compact>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell textAlign="right"></Table.HeaderCell>
|
||||
{['distanceOvertaker', 'distanceStationary', 'speed'].map((prop) => (
|
||||
{["distanceOvertaker", "distanceStationary", "speed"].map((prop) => (
|
||||
<Table.HeaderCell key={prop} textAlign="right">
|
||||
{LABELS[prop]}
|
||||
{t(`MapPage.roadInfo.${prop}`)}
|
||||
</Table.HeaderCell>
|
||||
))}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{['count', 'min', 'median', 'max', 'mean'].map((stat) => (
|
||||
{["count", "min", "median", "max", "mean"].map((stat) => (
|
||||
<Table.Row key={stat}>
|
||||
<Table.Cell>{LABELS[stat]}</Table.Cell>
|
||||
{['distanceOvertaker', 'distanceStationary', 'speed'].map((prop) => (
|
||||
<Table.Cell key={prop} textAlign="right">
|
||||
{(data[prop]?.statistics?.[stat] * (prop === `speed` && stat != 'count' ? 3.6 : 1)).toFixed(
|
||||
stat === 'count' ? 0 : 2
|
||||
)}
|
||||
{stat !== 'count' && ` ${UNITS[prop]}`}
|
||||
</Table.Cell>
|
||||
))}
|
||||
<Table.Cell> {t(`MapPage.roadInfo.${stat}`)}</Table.Cell>
|
||||
{["distanceOvertaker", "distanceStationary", "speed"].map(
|
||||
(prop) => (
|
||||
<Table.Cell key={prop} textAlign="right">
|
||||
{(
|
||||
data[prop]?.statistics?.[stat] *
|
||||
(prop === `speed` && stat != "count" ? 3.6 : 1)
|
||||
).toFixed(stat === "count" ? 0 : 2)}
|
||||
{stat !== "count" && ` ${UNITS[prop]}`}
|
||||
</Table.Cell>
|
||||
)
|
||||
)}
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function HistogramChart({bins, counts, zone}) {
|
||||
function HistogramChart({ bins, counts, zone }) {
|
||||
const diff = bins[1] - bins[0]
|
||||
const colortype = zone=="rural" ? 3:5;
|
||||
const colortype = zone === "rural" ? 3 : 5;
|
||||
const data = _.zip(
|
||||
bins.slice(0, bins.length - 1).map((v) => v + diff / 2),
|
||||
counts
|
||||
|
@ -88,19 +100,19 @@ function HistogramChart({bins, counts, zone}) {
|
|||
|
||||
return (
|
||||
<Chart
|
||||
style={{height: 240}}
|
||||
style={{ height: 240 }}
|
||||
option={{
|
||||
grid: {top: 30, bottom: 30, right: 30, left: 30},
|
||||
grid: { top: 30, bottom: 30, right: 30, left: 30 },
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {formatter: (v) => `${Math.round(v * 100)} cm`},
|
||||
type: "value",
|
||||
axisLabel: { formatter: (v) => `${Math.round(v * 100)} cm` },
|
||||
min: 0,
|
||||
max: 2.5,
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
type: "bar",
|
||||
data,
|
||||
|
||||
barMaxWidth: 20,
|
||||
|
@ -108,20 +120,21 @@ function HistogramChart({bins, counts, zone}) {
|
|||
],
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function RoadInfo({clickLocation}) {
|
||||
const [direction, setDirection] = useState('forwards')
|
||||
export default function RoadInfo({ clickLocation }) {
|
||||
const { t } = useTranslation();
|
||||
const [direction, setDirection] = useState("forwards");
|
||||
|
||||
const onClickDirection = useCallback(
|
||||
(e, {name}) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setDirection(name)
|
||||
(e, { name }) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDirection(name);
|
||||
},
|
||||
[setDirection]
|
||||
)
|
||||
);
|
||||
|
||||
const info = useObservable(
|
||||
(_$, inputs$) =>
|
||||
|
@ -132,7 +145,7 @@ export default function RoadInfo({clickLocation}) {
|
|||
? concat(
|
||||
of(null),
|
||||
from(
|
||||
api.get('/mapdetails/road', {
|
||||
api.get("/mapdetails/road", {
|
||||
query: {
|
||||
...location,
|
||||
radius: 100,
|
||||
|
@ -145,43 +158,60 @@ export default function RoadInfo({clickLocation}) {
|
|||
),
|
||||
null,
|
||||
[clickLocation]
|
||||
)
|
||||
);
|
||||
|
||||
if (!clickLocation) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const loading = info == null
|
||||
const loading = info == null;
|
||||
|
||||
const offsetDirection = info?.road?.oneway ? 0 : direction === 'forwards' ? 1 : -1 // TODO: change based on left-hand/right-hand traffic
|
||||
const offsetDirection = info?.road?.oneway
|
||||
? 0
|
||||
: direction === "forwards"
|
||||
? 1
|
||||
: -1; // TODO: change based on left-hand/right-hand traffic
|
||||
|
||||
const content =
|
||||
!loading && !info.road ? (
|
||||
'No road found.'
|
||||
"No road found."
|
||||
) : (
|
||||
<>
|
||||
<Header as="h3">{loading ? '...' : info?.road.name || 'Unnamed way'}</Header>
|
||||
<Header as="h3">
|
||||
{loading
|
||||
? "..."
|
||||
: info?.road.name || t("MapPage.roadInfo.unnamedWay")}
|
||||
</Header>
|
||||
|
||||
{info?.road.zone && (
|
||||
<Label size="small" color={ZONE_COLORS[info?.road.zone]}>
|
||||
{info?.road.zone}
|
||||
{t(`MapPage.roadInfo.zone.${info.road.zone}`)}
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{info?.road.oneway && (
|
||||
<Label size="small" color="blue">
|
||||
<Icon name="long arrow alternate right" fitted /> oneway
|
||||
<Icon name="long arrow alternate right" fitted />{" "}
|
||||
{t("MapPage.roadInfo.oneway")}
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{info?.road.oneway ? null : (
|
||||
<Menu size="tiny" fluid secondary>
|
||||
<Menu.Item header>Direction</Menu.Item>
|
||||
<Menu.Item name="forwards" active={direction === 'forwards'} onClick={onClickDirection}>
|
||||
{getCardinalDirection(info?.forwards?.bearing)}
|
||||
<Menu.Item header>{t("MapPage.roadInfo.direction")}</Menu.Item>
|
||||
<Menu.Item
|
||||
name="forwards"
|
||||
active={direction === "forwards"}
|
||||
onClick={onClickDirection}
|
||||
>
|
||||
{getCardinalDirection(t, info?.forwards?.bearing)}
|
||||
</Menu.Item>
|
||||
<Menu.Item name="backwards" active={direction === 'backwards'} onClick={onClickDirection}>
|
||||
{getCardinalDirection(info?.backwards?.bearing)}
|
||||
<Menu.Item
|
||||
name="backwards"
|
||||
active={direction === "backwards"}
|
||||
onClick={onClickDirection}
|
||||
>
|
||||
{getCardinalDirection(t, info?.backwards?.bearing)}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
)}
|
||||
|
@ -190,12 +220,16 @@ export default function RoadInfo({clickLocation}) {
|
|||
|
||||
{info?.[direction]?.distanceOvertaker?.histogram && (
|
||||
<>
|
||||
<Header as="h5">Overtaker distance distribution</Header>
|
||||
<HistogramChart {...info[direction]?.distanceOvertaker?.histogram} />
|
||||
<Header as="h5">
|
||||
{t("MapPage.roadInfo.overtakerDistanceDistribution")}
|
||||
</Header>
|
||||
<HistogramChart
|
||||
{...info[direction]?.distanceOvertaker?.histogram}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -205,14 +239,22 @@ export default function RoadInfo({clickLocation}) {
|
|||
id="route"
|
||||
type="line"
|
||||
paint={{
|
||||
'line-width': ['interpolate', ['linear'], ['zoom'], 14, 6, 17, 12],
|
||||
'line-color': '#18FFFF',
|
||||
'line-opacity': 0.5,
|
||||
"line-width": [
|
||||
"interpolate",
|
||||
["linear"],
|
||||
["zoom"],
|
||||
14,
|
||||
6,
|
||||
17,
|
||||
12,
|
||||
],
|
||||
"line-color": "#18FFFF",
|
||||
"line-opacity": 0.5,
|
||||
...{
|
||||
'line-offset': [
|
||||
'interpolate',
|
||||
['exponential', 1.5],
|
||||
['zoom'],
|
||||
"line-offset": [
|
||||
"interpolate",
|
||||
["exponential", 1.5],
|
||||
["zoom"],
|
||||
12,
|
||||
offsetDirection,
|
||||
19,
|
||||
|
@ -230,5 +272,5 @@ export default function RoadInfo({clickLocation}) {
|
|||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
general:
|
||||
loading: Lädt
|
||||
unnamedTrack: Unbenannte Fahrt
|
||||
urban: innerorts
|
||||
rural: außerorts
|
||||
public: Öffentlich
|
||||
private: Privat
|
||||
show: Anzeigen
|
||||
|
@ -116,3 +118,64 @@ NotFoundPage:
|
|||
title: Seite nicht gefunden
|
||||
description: Den Fehler kennst du sicher...
|
||||
goBack: Zurückgehen
|
||||
|
||||
|
||||
MapPage:
|
||||
sidebar:
|
||||
baseMap:
|
||||
style:
|
||||
label: Stil der Basiskarte
|
||||
positron: Positron
|
||||
bright: OSM Bright
|
||||
|
||||
obsRoads:
|
||||
title: Straßenabschnitte
|
||||
showUntagged:
|
||||
label: Abschnitte ohne Daten anzeigen
|
||||
attribute:
|
||||
label: Einfärben nach...
|
||||
distance_overtaker_mean: Durchschnitt Überholabstand
|
||||
distance_overtaker_min: Minimum Überholabstand
|
||||
distance_overtaker_max: Maximum Überholabstand
|
||||
distance_overtaker_median: Median Überholabstand
|
||||
overtaking_event_count: Anzahl Überholvorgänge
|
||||
usage_count: Anzahl Befahrungen
|
||||
zone: Überholabstands-Zone
|
||||
maxCount:
|
||||
label: Maximalwert für Farbskala
|
||||
|
||||
obsEvents:
|
||||
title: Überholvorgänge
|
||||
|
||||
|
||||
roadInfo:
|
||||
unnamedWay: Unbenannter Weg
|
||||
oneway: Einbahnstraße
|
||||
direction: Richtung
|
||||
|
||||
zone:
|
||||
rural: außerorts
|
||||
urban: innerorts
|
||||
motorway: Autobahn
|
||||
|
||||
distanceOvertaker: Links
|
||||
distanceStationary: Rechts
|
||||
speed: Geschwindigkeit
|
||||
count: Anzahl Messungen
|
||||
min: Minimum
|
||||
median: Median
|
||||
max: Maximum
|
||||
mean: Durchschnitt
|
||||
|
||||
overtakerDistanceDistribution: Verteilung der Überholabstände
|
||||
|
||||
cardinalDirections:
|
||||
unknown: unbekannt
|
||||
north: nordwärts
|
||||
northEast: nordostwärts
|
||||
east: ostwärts
|
||||
southEast: südostwärts
|
||||
south: südwärts
|
||||
southWest: südwestwärts
|
||||
west: westwärts
|
||||
northWest: nordwestwärts
|
||||
|
|
|
@ -5,6 +5,8 @@ locales:
|
|||
general:
|
||||
loading: Loading
|
||||
unnamedTrack: Unnamed track
|
||||
urban: urban
|
||||
rural: rural
|
||||
public: Public
|
||||
private: Private
|
||||
show: Show
|
||||
|
@ -121,3 +123,63 @@ NotFoundPage:
|
|||
title: Page not found
|
||||
description: You know what that means...
|
||||
goBack: Go back
|
||||
|
||||
|
||||
MapPage:
|
||||
sidebar:
|
||||
baseMap:
|
||||
style:
|
||||
label: Basemap Style
|
||||
positron: Positron
|
||||
bright: OSM Bright
|
||||
|
||||
obsRoads:
|
||||
title: Road segments
|
||||
showUntagged:
|
||||
label: Include roads without data
|
||||
attribute:
|
||||
label: Color based on...
|
||||
distance_overtaker_mean: Overtaker distance mean
|
||||
distance_overtaker_min: Overtaker distance minimum
|
||||
distance_overtaker_max: Overtaker distance maximum
|
||||
distance_overtaker_median: Overtaker distance median
|
||||
overtaking_event_count: Event count
|
||||
usage_count: Usage count
|
||||
zone: Overtaking distance zone
|
||||
maxCount:
|
||||
label: Maximum value for color scale
|
||||
|
||||
obsEvents:
|
||||
title: Event points
|
||||
|
||||
roadInfo:
|
||||
unnamedWay: Unnamed way
|
||||
oneway: oneway
|
||||
direction: Direction
|
||||
|
||||
zone:
|
||||
rural: Rural
|
||||
urban: Urban
|
||||
motorway: Motorway
|
||||
|
||||
distanceOvertaker: Left
|
||||
distanceStationary: Right
|
||||
speed: Speed
|
||||
count: No. of Measurements
|
||||
min: Minimum
|
||||
median: Median
|
||||
max: Maximum
|
||||
mean: Average
|
||||
|
||||
overtakerDistanceDistribution: Overtaker distance distribution
|
||||
|
||||
cardinalDirections:
|
||||
unknown: unknown
|
||||
north: north bound
|
||||
northEast: north-east bound
|
||||
east: east bound
|
||||
southEast: south-east bound
|
||||
south: south bound
|
||||
southWest: south-west bound
|
||||
west: west bound
|
||||
northWest: north-west bound
|
||||
|
|
Loading…
Reference in a new issue