From ef49979962609091ef404839524e2fb278bf839b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Benitte?= Date: Wed, 27 Mar 2019 15:20:00 +0900 Subject: [PATCH] feat(geo): add abillity to customize label & format value --- packages/geo/package.json | 1 + packages/geo/src/ChoroplethTooltip.js | 9 ++- packages/geo/src/hooks.js | 24 ++++++- packages/geo/src/props.js | 3 + .../src/components/charts/geo/Choropleth.js | 4 ++ .../components/charts/geo/ChoroplethCanvas.js | 4 ++ website/src/components/charts/geo/props.js | 63 ++++++++++++++++++- 7 files changed, 104 insertions(+), 4 deletions(-) diff --git a/packages/geo/package.json b/packages/geo/package.json index 70d18a50e..a543e1c41 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -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", diff --git a/packages/geo/src/ChoroplethTooltip.js b/packages/geo/src/ChoroplethTooltip.js index 266ef3226..cfb20da6c 100644 --- a/packages/geo/src/ChoroplethTooltip.js +++ b/packages/geo/src/ChoroplethTooltip.js @@ -13,7 +13,14 @@ import { BasicTooltip } from '@nivo/core' const ChoroplethTooltip = memo(({ feature }) => { if (feature.data === undefined) return null - return + return ( + + ) }) ChoroplethTooltip.propTypes = { diff --git a/packages/geo/src/hooks.js b/packages/geo/src/hooks.js index c2b73c583..9f636d12e 100644 --- a/packages/geo/src/hooks.js +++ b/packages/geo/src/hooks.js @@ -8,6 +8,7 @@ */ import { useMemo } from 'react' import { isFunction, get } from 'lodash' +import { format } from 'd3-format' import { geoPath, geoAzimuthalEqualArea, @@ -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) => { @@ -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]) @@ -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 { diff --git a/packages/geo/src/props.js b/packages/geo/src/props.js index 0ea613171..23d511aa1 100644 --- a/packages/geo/src/props.js +++ b/packages/geo/src/props.js @@ -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, } @@ -108,6 +110,7 @@ export const GeoMapCanvasDefaultProps = { const commonChoroplethDefaultProps = { match: 'id', + label: 'id', value: 'value', colors: 'PuBuGn', unknownColor: '#999', diff --git a/website/src/components/charts/geo/Choropleth.js b/website/src/components/charts/geo/Choropleth.js index 9a589cab1..022d228de 100644 --- a/website/src/components/charts/geo/Choropleth.js +++ b/website/src/components/charts/geo/Choropleth.js @@ -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], diff --git a/website/src/components/charts/geo/ChoroplethCanvas.js b/website/src/components/charts/geo/ChoroplethCanvas.js index 3fd1cdb88..f0aa1a7d5 100644 --- a/website/src/components/charts/geo/ChoroplethCanvas.js +++ b/website/src/components/charts/geo/ChoroplethCanvas.js @@ -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], diff --git a/website/src/components/charts/geo/props.js b/website/src/components/charts/geo/props.js index 98951d4cc..4398cc79b 100644 --- a/website/src/components/charts/geo/props.js +++ b/website/src/components/charts/geo/props.js @@ -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 [ @@ -175,6 +175,67 @@ export default [ max: 400, }, }, + { + key: 'layers', + scopes: ['Choropleth', 'ChoroplethCanvas'], + type: `Array<'graticule' | 'features' | Function>`, + required: false, + description: ( +
+ Defines the order of layers, available layers are: + graticule, features.
+ 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. +
+ ), + default: GeoMapDefaultProps.layers, + }, + { + key: 'label', + scopes: ['Choropleth', 'ChoroplethCanvas'], + type: '{string|Function}', + required: false, + description: ( +
+ 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. +
+ ), + default: ChoroplethDefaultProps.label, + }, + { + key: 'value', + scopes: ['Choropleth', 'ChoroplethCanvas'], + type: '{string|Function}', + required: false, + description: ( +
+ 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. +
+ ), + default: ChoroplethDefaultProps.value, + }, + { + key: 'valueFormat', + scopes: ['Choropleth', 'ChoroplethCanvas'], + type: '{string|Function}', + required: false, + description: ( +
+ 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{' '} + + d3-format + + . +
+ ), + default: ChoroplethDefaultProps.value, + }, { key: 'colors', scopes: ['Choropleth', 'ChoroplethCanvas'],