Skip to content

Commit

Permalink
feat(geo): add abillity to customize label & format value
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte authored and Raphaël Benitte committed Mar 27, 2019
1 parent 12415ac commit ef49979
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/geo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
],
"dependencies": {
"@nivo/core": "0.54.0",
"d3-format": "^1.3.2",
"d3-geo": "^1.11.3",
"lodash": "^4.17.4",
"react-motion": "^0.5.2",
Expand Down
9 changes: 8 additions & 1 deletion packages/geo/src/ChoroplethTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ import { BasicTooltip } from '@nivo/core'
const ChoroplethTooltip = memo(({ feature }) => {
if (feature.data === undefined) return null

return <BasicTooltip id={feature.id} color={feature.color} enableChip={true} />
return (
<BasicTooltip
id={feature.label}
color={feature.color}
enableChip={true}
value={feature.formattedValue}
/>
)
})

ChoroplethTooltip.propTypes = {
Expand Down
24 changes: 22 additions & 2 deletions packages/geo/src/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
import { useMemo } from 'react'
import { isFunction, get } from 'lodash'
import { format } from 'd3-format'
import {
geoPath,
geoAzimuthalEqualArea,
Expand Down Expand Up @@ -89,7 +90,16 @@ export const useGeoMap = ({
}
}

export const useChoropleth = ({ features, data, match, value, colors, unknownColor }) => {
export const useChoropleth = ({
features,
data,
match,
label,
value,
valueFormat,
colors,
unknownColor,
}) => {
const findMatchingDatum = useMemo(() => {
if (isFunction(match)) return match
return (feature, datum) => {
Expand All @@ -99,9 +109,17 @@ export const useChoropleth = ({ features, data, match, value, colors, unknownCol
return featureKey && featureKey === datumKey
}
}, [match])
const getLabel = useMemo(() => (isFunction(label) ? label : datum => get(datum, label)), [
label,
])
const getValue = useMemo(() => (isFunction(value) ? value : datum => get(datum, value)), [
value,
])
const valueFormatter = useMemo(() => {
if (valueFormat === undefined) return d => d
if (isFunction(valueFormat)) return valueFormat
return format(valueFormat)
}, [valueFormat])
const getFillColor = useMemo(() => {
const colorScale = guessQuantizeColorScale(colors).domain([0, 1000000])

Expand All @@ -121,15 +139,17 @@ export const useChoropleth = ({ features, data, match, value, colors, unknownCol
...feature,
data: datum,
value: datumValue,
formattedValue: valueFormatter(datumValue),
}
featureWithData.color = getFillColor(featureWithData)
featureWithData.label = getLabel(featureWithData)

return featureWithData
}

return feature
}),
[features, data, findMatchingDatum, getValue, getFillColor]
[features, data, findMatchingDatum, getValue, valueFormatter, getFillColor]
)

return {
Expand Down
3 changes: 3 additions & 0 deletions packages/geo/src/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ export const GeoMapCanvasPropTypes = {
const commonChoroplethPropTypes = {
data: PropTypes.arrayOf(PropTypes.object).isRequired,
match: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
valueFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
colors: quantizeColorScalePropType.isRequired,
unknownColor: PropTypes.string.isRequired,
}
Expand Down Expand Up @@ -108,6 +110,7 @@ export const GeoMapCanvasDefaultProps = {

const commonChoroplethDefaultProps = {
match: 'id',
label: 'id',
value: 'value',
colors: 'PuBuGn',
unknownColor: '#999',
Expand Down
4 changes: 4 additions & 0 deletions website/src/components/charts/geo/Choropleth.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const initialSettings = {
colors: 'YlGnBu',
unknownColor: '#152538',

label: 'properties.name',
value: 'value',
valueFormat: '.2s',

projectionType: 'mercator',
projectionScale: 100,
projectionTranslation: [0.5, 0.5],
Expand Down
4 changes: 4 additions & 0 deletions website/src/components/charts/geo/ChoroplethCanvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const initialSettings = {
colors: 'PiYG',
unknownColor: '#101b42',

label: 'properties.name',
value: 'value',
valueFormat: '.2s',

projectionType: 'mercator',
projectionScale: 100,
projectionTranslation: [0.5, 0.5],
Expand Down
63 changes: 62 additions & 1 deletion website/src/components/charts/geo/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
import React from 'react'
import { GeoMapDefaultProps } from '@nivo/geo'
import { GeoMapDefaultProps, ChoroplethDefaultProps } from '@nivo/geo'
import { marginProperties, defsProperties } from '../../../lib/componentProperties'

export default [
Expand Down Expand Up @@ -175,6 +175,67 @@ export default [
max: 400,
},
},
{
key: 'layers',
scopes: ['Choropleth', 'ChoroplethCanvas'],
type: `Array<'graticule' | 'features' | Function>`,
required: false,
description: (
<div>
Defines the order of layers, available layers are:
<code>graticule</code>, <code>features</code>.<br />
You can also use this to insert extra layers to the chart, this extra layer must be
a function which will receive the chart computed data and must return a valid SVG
element for the SVG implementation or receive a Canvas 2d context for the canvas
one. Custom layers will also receive the computed data/projection.
</div>
),
default: GeoMapDefaultProps.layers,
},
{
key: 'label',
scopes: ['Choropleth', 'ChoroplethCanvas'],
type: '{string|Function}',
required: false,
description: (
<div>
Accessor to label, if a string is provided, the value will be retrieved using it as
a key, if it's a function, it's its responsibility to return the label.
</div>
),
default: ChoroplethDefaultProps.label,
},
{
key: 'value',
scopes: ['Choropleth', 'ChoroplethCanvas'],
type: '{string|Function}',
required: false,
description: (
<div>
Accessor to data value, if a string is provided, the value will be retrieved using
it as a key, if it's a function, it's its responsibility to return the value.
</div>
),
default: ChoroplethDefaultProps.value,
},
{
key: 'valueFormat',
scopes: ['Choropleth', 'ChoroplethCanvas'],
type: '{string|Function}',
required: false,
description: (
<div>
Optional formatting of values, if provided, it will be used for labels/tooltips. You
can either pass a function which will receive the node's data and must return the
formatted value, or a string which will be used as a directive for{' '}
<a href="https://github.com/d3/d3-format" target="_blank" rel="noopener noreferrer">
d3-format
</a>
.
</div>
),
default: ChoroplethDefaultProps.value,
},
{
key: 'colors',
scopes: ['Choropleth', 'ChoroplethCanvas'],
Expand Down

0 comments on commit ef49979

Please sign in to comment.