diff --git a/frontend/src/components/Chart.tsx b/frontend/src/components/Chart.tsx
new file mode 100644
index 0000000..c021323
--- /dev/null
+++ b/frontend/src/components/Chart.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import ReactEChartsCore from 'echarts-for-react/lib/core';
+
+import * as echarts from 'echarts/core';
+
+import {
+ // LineChart,
+ BarChart,
+ // PieChart,
+ // ScatterChart,
+ // RadarChart,
+ // MapChart,
+ // TreeChart,
+ // TreemapChart,
+ // GraphChart,
+ // GaugeChart,
+ // FunnelChart,
+ // ParallelChart,
+ // SankeyChart,
+ // BoxplotChart,
+ // CandlestickChart,
+ // EffectScatterChart,
+ // LinesChart,
+ // HeatmapChart,
+ // PictorialBarChart,
+ // ThemeRiverChart,
+ // SunburstChart,
+ // CustomChart,
+} from 'echarts/charts';
+
+// import components, all suffixed with Component
+import {
+ // GridSimpleComponent,
+ GridComponent,
+ // PolarComponent,
+ // RadarComponent,
+ // GeoComponent,
+ // SingleAxisComponent,
+ // ParallelComponent,
+ // CalendarComponent,
+ // GraphicComponent,
+ // ToolboxComponent,
+ TooltipComponent,
+ // AxisPointerComponent,
+ // BrushComponent,
+ TitleComponent,
+ // TimelineComponent,
+ // MarkPointComponent,
+ // MarkLineComponent,
+ // MarkAreaComponent,
+ // LegendComponent,
+ // LegendScrollComponent,
+ // LegendPlainComponent,
+ // DataZoomComponent,
+ // DataZoomInsideComponent,
+ // DataZoomSliderComponent,
+ // VisualMapComponent,
+ // VisualMapContinuousComponent,
+ // VisualMapPiecewiseComponent,
+ // AriaComponent,
+ // TransformComponent,
+ DatasetComponent,
+} from 'echarts/components';
+
+// Import renderer, note that introducing the CanvasRenderer or SVGRenderer is a required step
+import {
+ CanvasRenderer,
+ // SVGRenderer,
+} from 'echarts/renderers';
+
+// Register the required components
+echarts.use(
+ [TitleComponent, TooltipComponent, GridComponent, BarChart, CanvasRenderer]
+);
+
+// The usage of ReactEChartsCore are same with above.
+export default function Chart(props) {
+ return
+}
diff --git a/frontend/src/components/index.js b/frontend/src/components/index.js
index a7ed811..6764bf9 100644
--- a/frontend/src/components/index.js
+++ b/frontend/src/components/index.js
@@ -8,3 +8,4 @@ export {default as Map} from './Map'
export {default as Page} from './Page'
export {default as Stats} from './Stats'
export {default as StripMarkdown} from './StripMarkdown'
+export {default as Chart} from './Chart'
diff --git a/frontend/src/pages/MapPage/RoadInfo.tsx b/frontend/src/pages/MapPage/RoadInfo.tsx
index ebbf07b..5d2758e 100644
--- a/frontend/src/pages/MapPage/RoadInfo.tsx
+++ b/frontend/src/pages/MapPage/RoadInfo.tsx
@@ -5,11 +5,24 @@ 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 api from 'api'
+import {colorByDistance} from 'mapstyles'
import styles from './styles.module.less'
+function selectFromColorMap(colormap, value) {
+ let last = null
+ for (let i = 0; i < colormap.length; i += 2) {
+ if (colormap[i + 1] > value) {
+ return colormap[i]
+ }
+ }
+ return colormap[colormap.length - 1]
+}
+
const UNITS = {distanceOvertaker: 'm', distanceStationary: 'm', speed: 'km/h'}
const LABELS = {
distanceOvertaker: 'Left',
@@ -62,6 +75,41 @@ function RoadStatsTable({data}) {
)
}
+function HistogramChart({bins, counts}) {
+ const diff = bins[1] - bins[0]
+ const data = _.zip(
+ bins.slice(0, bins.length - 1).map((v) => v + diff / 2),
+ counts
+ ).map((value) => ({
+ value,
+ itemStyle: {color: selectFromColorMap(colorByDistance()[3].slice(2), value[0])},
+ }))
+
+ return (
+ `${Math.round(v * 100)} cm`},
+ min: 0,
+ max: 2.5,
+ },
+ yAxis: {},
+ series: [
+ {
+ type: 'bar',
+ data,
+
+ barMaxWidth: 20,
+ },
+ ],
+ }}
+ />
+ )
+}
+
export default function RoadInfo({clickLocation}) {
const [direction, setDirection] = useState('forwards')
@@ -138,6 +186,13 @@ export default function RoadInfo({clickLocation}) {
)}
{info?.[direction] && }
+
+ {info?.[direction]?.distanceOvertaker?.histogram && (
+ <>
+ Overtaker distance distribution
+
+ >
+ )}
>
)
diff --git a/frontend/src/utils.js b/frontend/src/utils.js
index 5213493..25d2977 100644
--- a/frontend/src/utils.js
+++ b/frontend/src/utils.js
@@ -7,3 +7,18 @@ export function findInput(register) {
register(found)
}
}
+
+// Generates pairs from the input iterable
+export function* pairwise(it) {
+ let lastValue
+ let firstRound = true
+
+ for (const i of it) {
+ if (firstRound) {
+ firstRound = false
+ } else {
+ yield [lastValue, i]
+ }
+ lastValue = i
+ }
+}