Use discrete colors for distances, with greens only above 1.5m

This commit is contained in:
Paul Bienkowski 2022-03-21 22:20:08 +01:00
parent 6893d7b56f
commit 1c52ce7de9
4 changed files with 64 additions and 9 deletions

View file

@ -1,9 +1,64 @@
import {useMemo} from "react";
import React, {useMemo} from "react";
type ColorMap = [number, string][]
import styles from './ColorMapLegend.module.less'
function* pairs(arr) {
for (let i = 1; i < arr.length; i++) {
yield [arr[i - 1], arr[i]];
}
}
function* zip(...arrs) {
const l = Math.min(...arrs.map(a => a.length));
for (let i = 0; i < l; i++) {
yield arrs.map(a => a[i]);
}
}
export function DiscreteColorMapLegend({map}: {map: ColorMap}) {
const colors: string[] = map.filter((x, i) => i % 2 == 0) as any
const stops: number[] = map.filter((x, i) => i % 2 == 1) as any
let min = stops[0]
let max = stops[stops.length - 1]
const buffer = (max - min) / (stops.length - 1) / 2
min -= buffer
max += buffer
const normalizeValue = (v) => (v - min) / (max - min)
const stopPairs = Array.from(pairs([min, ...stops, max]));
const gradientId = useMemo(() => `gradient${Math.floor(Math.random() * 1000000)}`, []);
const gradientUrl = `url(#${gradientId})`;
const parts = Array.from(zip(stopPairs, colors))
return (
<div className={styles.colorMapLegend}>
<svg width="100%" height="20" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id={gradientId} x1="0" x2="1" y1="0" y2="0">
{parts.map(([[left, right], color]) => (
<React.Fragment key={left}>
<stop offset={normalizeValue(left) * 100 + '%'} stopColor={color} />
<stop offset={normalizeValue(right) * 100 + '%'} stopColor={color} />
</React.Fragment>
))}
</linearGradient>
</defs>
<rect id="rect1" x="0" y="0" width="100%" height="100%" fill={gradientUrl} />
</svg>
{stops.map((value) => (
<span className={styles.tick} key={value} style={{left: normalizeValue(value) * 100 + '%'}}>
{value.toFixed(2)}
</span>
))}
</div>
)
}
export default function ColorMapLegend({map, twoTicks = false}: {map: ColorMap, twoTicks?: boolean}) {
const min = map[0][0]
const max = map[map.length - 1][0]

View file

@ -1,5 +1,5 @@
export {default as Avatar} from './Avatar'
export {default as ColorMapLegend} from './ColorMapLegend'
export {default as ColorMapLegend, DiscreteColorMapLegend} from './ColorMapLegend'
export {default as FileDrop} from './FileDrop'
export {default as FileUploadField} from './FileUploadField'
export {default as FormattedDate} from './FormattedDate'

View file

@ -53,13 +53,13 @@ export function colorByDistance(attribute = 'distance_overtaker_mean', fallback
['!', ['to-boolean', ['get', attribute]]],
fallback,
[
'interpolate-hcl',
['linear'],
'step',
['get', attribute],
1,
'rgba(150, 0, 0, 1)',
1.1,
'rgba(255, 0, 0, 1)',
1.3,
'rgba(255, 200, 0, 1)',
'rgba(255, 220, 0, 1)',
1.5,
'rgba(67, 200, 0, 1)',
1.7,

View file

@ -9,7 +9,7 @@ import {
initialState as defaultMapConfig,
} from 'reducers/mapConfig'
import {colorByDistance, colorByCount, viridisSimpleHtml} from 'mapstyles'
import {ColorMapLegend} from 'components'
import {ColorMapLegend, DiscreteColorMapLegend} from 'components'
const BASEMAP_STYLE_OPTIONS = [
{value: 'positron', key: 'positron', text: 'Positron'},
@ -98,7 +98,7 @@ function LayerSidebar({
) :
(
<List.Item>
<ColorMapLegend map={_.chunk(colorByDistance('distance_overtaker')[3].slice(3), 2)} />
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3].slice(2)} />
</List.Item>
)}
</>
@ -120,7 +120,7 @@ function LayerSidebar({
{showEvents && (
<>
<List.Item>
<ColorMapLegend map={_.chunk(colorByDistance('distance_overtaker')[3].slice(3), 2)} />
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3].slice(2)} />
</List.Item>
</>
)}