-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move ColorScale and Map component in lib
- Convert the following components to typescript: - Map/index.tsx - Map/OlMap/index.tsx - Map/HeatmapLayer/index.tsx - ColorScale/index.tsx - NOTE: Both lib and storybook are broken - Add dependencies for Map component - Remove eslint check for require-default-props
- Loading branch information
1 parent
e1c0fdb
commit 6fb07ec
Showing
55 changed files
with
3,891 additions
and
3,264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import React from 'react'; | ||
import { scalePow } from 'd3'; | ||
import { _cs } from '@togglecorp/fujs'; | ||
import * as d3ColorScale from 'd3-scale-chromatic'; | ||
|
||
import styles from './styles.module.css'; | ||
|
||
// FIXME: We have removed the default behavior for colorScale and colorScaleType | ||
export type Props = { | ||
steps?: number; | ||
pow?: number; | ||
containerClass?: string; // FIXME: why are we using this style | ||
inverted?: boolean; | ||
} & ({ | ||
colorScale: 'BrBG' | 'PRGn' | 'PiYG' | 'PuOr' | 'RdBu' | 'RdGy' | 'RdYlBu' | 'RdYlGn' | 'Spectral' | 'Blues' | 'Greens' | 'Greys' | 'Oranges' | 'Purples' | 'Reds' | 'BuPu' | 'GnBu' | 'OrRd' | 'PuBuGn' | 'PuBu' | 'PuRd' | 'RdPu' | 'YlGnBu' | 'YlGn' | 'YlOrBr' | 'YlOrRd'; | ||
colorScaleType: 'continuous' | 'steps'; | ||
} | { | ||
colorScale: 'Category10' | 'Accent' | 'Dark2' | 'Paired' | 'Pastel1' | 'Pastel2' | 'Set1' | 'Set2' | 'Set3' | 'Tableau10'; | ||
colorScaleType: 'categorised'; | ||
}) | ||
|
||
function ColorScale(props: Props) { | ||
const { | ||
steps = 12, | ||
pow = 1, | ||
containerClass = 'colorScaleDiv', | ||
inverted = false, | ||
} = props; | ||
|
||
let numSteps = steps; | ||
// eslint-disable-next-line react/destructuring-assignment | ||
if (props.colorScaleType === 'continuous') { | ||
numSteps = 50; | ||
} | ||
|
||
let colorsArray: readonly string[]; | ||
// eslint-disable-next-line react/destructuring-assignment | ||
if (props.colorScaleType === 'categorised') { | ||
// eslint-disable-next-line react/destructuring-assignment | ||
colorsArray = d3ColorScale[`scheme${props.colorScale}`]; | ||
} else { | ||
// eslint-disable-next-line react/destructuring-assignment | ||
const interpolator = d3ColorScale[`interpolate${props.colorScale}`]; | ||
colorsArray = Array.from( | ||
{ length: numSteps }, | ||
(_, i) => interpolator(i * (1 / (numSteps))), | ||
); | ||
} | ||
|
||
let fillPow = pow; | ||
// eslint-disable-next-line react/destructuring-assignment | ||
if (props.colorScaleType === 'steps' || props.colorScaleType === 'categorised') { | ||
fillPow = 1; | ||
} | ||
|
||
if (inverted) { | ||
colorsArray = [...colorsArray].reverse(); | ||
} | ||
|
||
const colorsArrayPow = scalePow() | ||
.exponent(fillPow) | ||
.domain([0, numSteps]); | ||
|
||
const colorStrPow = colorsArray.map((_, i) => { | ||
const colorIndex = Math.ceil(colorsArrayPow(i) * (numSteps)); | ||
return colorsArray[colorIndex]; | ||
}); | ||
|
||
const colorsString = colorStrPow.join(', '); | ||
const cssGradient = { | ||
background: `linear-gradient(90deg, ${colorsString})`, | ||
}; | ||
|
||
return ( | ||
<div | ||
// FIXME: use _cs | ||
className={_cs(styles.colorScaleContainer, styles[containerClass])} | ||
> | ||
{/* eslint-disable-next-line react/destructuring-assignment */} | ||
{(props.colorScaleType === 'steps' || props.colorScaleType === 'categorised') && ( | ||
<div className={styles.colorScale}> | ||
{colorStrPow.map((color, index) => ( | ||
<div | ||
key={`${index + color}`} | ||
className={styles.steps} | ||
> | ||
<div style={{ backgroundColor: color }} /> | ||
</div> | ||
))} | ||
</div> | ||
)} | ||
{/* eslint-disable-next-line react/destructuring-assignment */} | ||
{props.colorScaleType === 'continuous' && ( | ||
<div | ||
className={styles.colorScale} | ||
style={cssGradient} | ||
role="presentation" | ||
/> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
export default ColorScale; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { Map as MapFromLib } from 'ol'; | ||
import { Heatmap } from 'ol/layer'; | ||
import Feature from 'ol/Feature'; | ||
import Point from 'ol/geom/Point'; | ||
import { fromLonLat } from 'ol/proj'; | ||
import * as d3ColorScale from 'd3-scale-chromatic'; | ||
import { scaleLog } from 'd3-scale'; | ||
|
||
import { HeatMapLayer, HeatMapLayerProperty } from '../index'; | ||
import { vector } from '../helpers'; | ||
|
||
interface Props extends Pick<HeatMapLayer, 'data' | 'zIndex' | 'opacity' | 'blur' | 'radius' | 'fillPalette' | 'weighted' | 'scaleDataMax'> | ||
{ | ||
map: MapFromLib | undefined; | ||
} | ||
|
||
function HeatmapLayer(props: Props) { | ||
const { | ||
map, | ||
data, | ||
zIndex = 1, | ||
opacity = 1, | ||
blur, | ||
radius, | ||
fillPalette, | ||
weighted = false, | ||
scaleDataMax = 350, | ||
} = props; | ||
|
||
const [heatmapLayer, setHeatmapLayer] = useState<Heatmap | undefined>(undefined); | ||
|
||
const scaleWeight = scaleLog() | ||
.domain([1, scaleDataMax]) | ||
.range([0.4, 1]); | ||
|
||
useEffect( | ||
() => { | ||
if (!map) { | ||
return undefined; | ||
} | ||
|
||
let properties: HeatMapLayerProperty[]; | ||
if (Array.isArray(data)) { | ||
properties = data; | ||
} else { | ||
properties = data.features.map((datum) => ({ | ||
...datum.properties, | ||
lon: datum.geometry.coordinates[0], | ||
lat: datum.geometry.coordinates[1], | ||
})); | ||
} | ||
|
||
const features = properties.map((item) => { | ||
const feature = new Feature( | ||
new Point(fromLonLat([item.lon, item.lat])), | ||
); | ||
feature.setProperties(item); | ||
return feature; | ||
}); | ||
|
||
if (map && heatmapLayer) { | ||
map.removeLayer(heatmapLayer); | ||
} | ||
|
||
const interpolator = d3ColorScale[`interpolate${fillPalette}`]; | ||
const numSteps = 5; | ||
// eslint-disable-next-line | ||
const colors = Array.from({ length: numSteps }, (_, i) => interpolator(i * (1 / numSteps))); | ||
|
||
const vectorLayer = new Heatmap({ | ||
source: vector<Point>({ features }), | ||
blur, | ||
radius, | ||
gradient: colors, | ||
weight: (feature) => { | ||
if (weighted) { | ||
const w = scaleWeight(parseFloat(feature.get('fatalities'))) || 0; | ||
return w; | ||
} | ||
return 0.7; | ||
}, | ||
}); | ||
map.addLayer(vectorLayer); | ||
setHeatmapLayer(vectorLayer); | ||
|
||
return () => { | ||
if (map) { | ||
map.removeLayer(vectorLayer); | ||
} | ||
}; | ||
}, | ||
// FIXME: for the missing dependencies, we can store them in intial | ||
// values using useState or useRef | ||
// For reference, check other libraries like toggle-form or re-map | ||
[map, fillPalette, weighted], | ||
); | ||
|
||
useEffect( | ||
() => { | ||
if (!heatmapLayer) { | ||
return; | ||
} | ||
|
||
let properties: HeatMapLayerProperty[]; | ||
if (Array.isArray(data)) { | ||
properties = data; | ||
} else { | ||
properties = data.features.map((datum) => ({ | ||
...datum.properties, | ||
lon: datum.geometry.coordinates[0], | ||
lat: datum.geometry.coordinates[1], | ||
exclude_from_heatmap: Boolean(datum.properties?.exclude_from_heatmap), | ||
})); | ||
} | ||
|
||
const features = properties.filter((item) => !item.exclude_from_heatmap).map((item) => { | ||
const feature = new Feature( | ||
new Point(fromLonLat([item.lon, item.lat])), | ||
); | ||
feature.setProperties(item); | ||
return feature; | ||
}); | ||
|
||
// FIXME: should we return instead | ||
const source = heatmapLayer.getSource(); | ||
source?.clear(); | ||
source?.addFeatures(features); | ||
}, | ||
// FIXME: We might not need to use JSON.stringify | ||
[heatmapLayer, JSON.stringify(data)], | ||
Check warning on line 131 in lib/src/components/Map/Layers/HeatmapLayer.tsx GitHub Actions / build
|
||
); | ||
|
||
useEffect( | ||
() => { | ||
if (!heatmapLayer) { | ||
return; | ||
} | ||
heatmapLayer.setOpacity(opacity); | ||
}, | ||
[heatmapLayer, opacity], | ||
); | ||
|
||
useEffect( | ||
() => { | ||
if (!heatmapLayer) { | ||
return; | ||
} | ||
heatmapLayer.setZIndex(zIndex); | ||
}, | ||
[heatmapLayer, zIndex], | ||
); | ||
|
||
useEffect(() => { | ||
if (!heatmapLayer) return; | ||
heatmapLayer.setBlur(blur); | ||
}, [heatmapLayer, blur]); | ||
|
||
useEffect( | ||
() => { | ||
if (!heatmapLayer) { | ||
return; | ||
} | ||
heatmapLayer.setRadius(radius); | ||
}, | ||
[heatmapLayer, radius], | ||
); | ||
|
||
return null; | ||
} | ||
|
||
export default HeatmapLayer; |
Oops, something went wrong.