From be1a8afae9492861b20941a5bc583061b9e86359 Mon Sep 17 00:00:00 2001 From: plouc Date: Sat, 8 Jan 2022 05:20:07 +0900 Subject: [PATCH] feat(heatmap): restore support for empty values and empty color --- packages/heatmap/src/HeatMap.tsx | 10 ++++-- packages/heatmap/src/HeatMapCellCircle.tsx | 5 ++- packages/heatmap/src/defaults.ts | 2 +- packages/heatmap/src/index.ts | 1 + packages/static/src/mappings/heatmap.ts | 34 +++++++++----------- packages/static/src/samples/index.ts | 12 ++----- website/src/data/components/heatmap/meta.yml | 8 ++--- website/src/data/components/heatmap/props.ts | 24 ++++++++++++-- website/src/pages/heatmap/canvas.tsx | 24 ++++++-------- website/src/pages/heatmap/index.tsx | 6 ++-- 10 files changed, 69 insertions(+), 57 deletions(-) diff --git a/packages/heatmap/src/HeatMap.tsx b/packages/heatmap/src/HeatMap.tsx index c73d83f076..d446c09ab2 100644 --- a/packages/heatmap/src/HeatMap.tsx +++ b/packages/heatmap/src/HeatMap.tsx @@ -7,7 +7,8 @@ import { HeatMapDatum, HeatMapCommonProps, HeatMapSvgProps, - LayerId, CustomLayerProps, + LayerId, + CustomLayerProps, } from './types' import { useHeatMap } from './hooks' import { svgDefaultProps } from './defaults' @@ -74,7 +75,10 @@ const InnerHeatMap = ({ partialMargin ) - const { xScale, yScale, cells, colorScale, activeCell, setActiveCell } = useHeatMap({ + const { xScale, yScale, cells, colorScale, activeCell, setActiveCell } = useHeatMap< + Datum, + ExtraProps + >({ data, valueFormat, width: innerWidth, @@ -180,7 +184,7 @@ const InnerHeatMap = ({ const customLayerProps: CustomLayerProps = { cells, activeCell, - setActiveCell + setActiveCell, } return ( diff --git a/packages/heatmap/src/HeatMapCellCircle.tsx b/packages/heatmap/src/HeatMapCellCircle.tsx index 210f11a85c..269ae49f18 100644 --- a/packages/heatmap/src/HeatMapCellCircle.tsx +++ b/packages/heatmap/src/HeatMapCellCircle.tsx @@ -33,7 +33,10 @@ const NonMemoizedHeatMapCellCircle = ({ transform={to([animatedProps.x, animatedProps.y], (x, y) => `translate(${x}, ${y})`)} > Math.min(width, height) / 2 + )} fill={animatedProps.color} fillOpacity={animatedProps.opacity} strokeWidth={borderWidth} diff --git a/packages/heatmap/src/defaults.ts b/packages/heatmap/src/defaults.ts index 5bfd3f61b4..8c6510e6f1 100644 --- a/packages/heatmap/src/defaults.ts +++ b/packages/heatmap/src/defaults.ts @@ -44,7 +44,7 @@ export const commonDefaultProps: Omit< type: 'sequential', scheme: 'brown_blueGreen', }, - emptyColor: '#00000000', + emptyColor: '#000000', legends: [], annotations: [], diff --git a/packages/heatmap/src/index.ts b/packages/heatmap/src/index.ts index bd3a78a025..7ad7f8d3ee 100644 --- a/packages/heatmap/src/index.ts +++ b/packages/heatmap/src/index.ts @@ -4,3 +4,4 @@ export * from './HeatMapCanvas' export * from './ResponsiveHeatMapCanvas' export * from './hooks' export * from './defaults' +export * from './types' diff --git a/packages/static/src/mappings/heatmap.ts b/packages/static/src/mappings/heatmap.ts index 36c323d4d6..77d1f82b92 100644 --- a/packages/static/src/mappings/heatmap.ts +++ b/packages/static/src/mappings/heatmap.ts @@ -1,43 +1,41 @@ import { FunctionComponent } from 'react' import Joi from 'joi' -import { Dimensions } from '@nivo/core' -import { HeatMap, HeatMapSvgProps } from '@nivo/heatmap' +import { DefaultHeatMapDatum, HeatMap, HeatMapDatum, HeatMapSvgProps } from '@nivo/heatmap' import { custom } from './common' import { dimensions } from './commons/dimensions' import { inheritedColor } from './commons/colors' import { axes } from './common' import { OmitStrict } from '../types' -export type HeatMapApiProps = OmitStrict< - HeatMapSvgProps & Dimensions, - | 'isInteractive' - | 'onClick' - | 'hoverTarget' - | 'cellHoverOpacity' - | 'cellHoverOthersOpacity' - | 'animate' +export type HeatMapApiProps< + Datum extends HeatMapDatum = DefaultHeatMapDatum, + ExtraProps extends object = Record +> = OmitStrict< + HeatMapSvgProps, + 'isInteractive' | 'onClick' | 'hoverTarget' | 'activeOpacity' | 'inactiveOpacity' | 'animate' > export const heatmapMapping = { component: HeatMap as unknown as FunctionComponent, schema: Joi.object().keys({ data: custom.array().min(1).required(), - indexBy: Joi.string(), - keys: Joi.array().sparse(false).min(1).unique(), minValue: Joi.alternatives().try(Joi.any().valid('auto'), Joi.number()).required(), maxValue: Joi.alternatives().try(Joi.any().valid('auto'), Joi.number()).required(), forceSquare: Joi.boolean(), sizeVariation: Joi.number().min(0).max(1), - padding: Joi.number().min(0), + xOuterPadding: Joi.number().min(0).max(1), + xInnerPadding: Joi.number().min(0).max(1), + yOuterPadding: Joi.number().min(0).max(1), + yInnerPadding: Joi.number().min(0).max(1), width: dimensions.width, height: dimensions.height, margin: dimensions.margin, - cellShape: Joi.any().valid('rect', 'circle'), - colors: Joi.string(), - cellOpacity: Joi.number().min(0).max(1), - cellBorderWidth: Joi.number().min(0), - cellBorderColor: inheritedColor, + cellComponent: Joi.any().valid('rect', 'circle'), + colors: Joi.object(), + opacity: Joi.number().min(0).max(1), + borderWidth: Joi.number().min(0), + borderColor: inheritedColor, enableLabels: Joi.boolean(), labelTextColor: inheritedColor, diff --git a/packages/static/src/samples/index.ts b/packages/static/src/samples/index.ts index 5a05da8286..8632b565ab 100644 --- a/packages/static/src/samples/index.ts +++ b/packages/static/src/samples/index.ts @@ -68,17 +68,11 @@ export const samples: Record< width: 900, height: 600, data: generateCountriesData(moreKeys, { size: 9, min: 0, max: 100 }), - keys: moreKeys, - indexBy: 'country', forceSquare: true, - cellShape: 'circle', - cellBorderWidth: 2, - cellBorderColor: 'inherit:darker(0.4)', - padding: 4, - sizeVariation: 0.5, - enableGridY: true, + cellComponent: 'rect', + borderWidth: 2, + borderColor: 'inherit:darker(0.4)', labelTextColor: 'inherit:darker(2.4)', - colors: 'PuOr', }, }, line: { diff --git a/website/src/data/components/heatmap/meta.yml b/website/src/data/components/heatmap/meta.yml index 8d68fea7f3..3d71e63906 100644 --- a/website/src/data/components/heatmap/meta.yml +++ b/website/src/data/components/heatmap/meta.yml @@ -17,9 +17,9 @@ HeatMap: - label: Custom tooltip link: heatmap-custom-tooltip description: | - An heat map matrix, you can chose between various colors scales - or pass yours, you also have the ability to change the cell shape - for rectangle or circle and even use a custom rendering function. + An heat map matrix, you can chose between various colors scales, + you also have the ability to change the cell shape + for rectangle or circle and even use a custom component. The responsive alternative of this component is `ResponsiveHeatMap`. @@ -35,7 +35,7 @@ HeatMapCanvas: - canvas stories: [] description: | - A variation around the [HeatMap](self:/heatmap) component. + A variation around the [HeatMap](self:/heatmap/) component. Well suited for large data sets as it does not impact DOM tree depth, however you'll lose the isomorphic ability and transitions. diff --git a/website/src/data/components/heatmap/props.ts b/website/src/data/components/heatmap/props.ts index be3409396f..63028b5d04 100644 --- a/website/src/data/components/heatmap/props.ts +++ b/website/src/data/components/heatmap/props.ts @@ -19,6 +19,19 @@ const props: ChartProperty[] = [ help: 'Chart data.', type: 'HeatMapSerie[]', required: true, + description: ` + The default expected type is: + + \`\`\` + { + id: string + data: { + x: string | number + y: number | null + }[] + }[] + \`\`\` + ` }, { key: 'minValue', @@ -155,6 +168,14 @@ const props: ChartProperty[] = [ type: 'continuous_colors', }, }, + { + key: 'emptyColor', + group: 'Style', + help: 'Color to use for cells not having a value.', + type: 'string', + defaultValue: defaults.emptyColor, + control: { type: 'colorPicker' }, + }, { key: 'opacity', group: 'Style', @@ -190,7 +211,6 @@ const props: ChartProperty[] = [ { key: 'borderWidth', group: 'Style', - help: 'Cell border width.', defaultValue: defaults.borderWidth, type: 'number', control: { type: 'lineWidth' }, @@ -198,7 +218,6 @@ const props: ChartProperty[] = [ { key: 'borderColor', group: 'Style', - help: 'Method to compute cell border color.', description: ` how to compute cell border color, [see dedicated documentation](self:/guides/colors). @@ -224,7 +243,6 @@ const props: ChartProperty[] = [ }, { key: 'labelTextColor', - help: 'Method to compute label text color.', description: ` how to compute label text color, [see dedicated documentation](self:/guides/colors). diff --git a/website/src/pages/heatmap/canvas.tsx b/website/src/pages/heatmap/canvas.tsx index 642ce1ad63..9ce82526b8 100644 --- a/website/src/pages/heatmap/canvas.tsx +++ b/website/src/pages/heatmap/canvas.tsx @@ -1,10 +1,7 @@ import React from 'react' import { graphql, useStaticQuery } from 'gatsby' import isFunction from 'lodash/isFunction' -import { - ResponsiveHeatMapCanvas, - canvasDefaultProps as defaults, -} from '@nivo/heatmap' +import { ResponsiveHeatMapCanvas, canvasDefaultProps as defaults } from '@nivo/heatmap' import { generateXYSeries, sets } from '@nivo/generators' import { ComponentTemplate } from '../../components/components/ComponentTemplate' import meta from '../../data/components/heatmap/meta.yml' @@ -47,16 +44,8 @@ const initialProperties = { yOuterPadding: defaults.yOuterPadding, yInnerPadding: defaults.yInnerPadding, - colors: { - type: 'diverging', - scheme: 'red_yellow_blue', - divergeAt: 0.5, - minValue: -100_000, - maxValue: 100_000, - }, - enableGridX: false, - enableGridY: true, + enableGridY: false, axisTop: { enable: true, orient: 'top', @@ -98,10 +87,17 @@ const initialProperties = { }, renderCell: 'rect', + colors: { + type: 'diverging', + scheme: 'red_yellow_blue', + divergeAt: 0.5, + minValue: -100_000, + maxValue: 100_000, + }, + emptyColor: '#555555', opacity: defaults.opacity, activeOpacity: defaults.activeOpacity, inactiveOpacity: defaults.inactiveOpacity, - borderRadius: defaults.borderRadius, borderWidth: defaults.borderWidth, borderColor: defaults.borderColor, diff --git a/website/src/pages/heatmap/index.tsx b/website/src/pages/heatmap/index.tsx index 03068fb316..af373c3c4a 100644 --- a/website/src/pages/heatmap/index.tsx +++ b/website/src/pages/heatmap/index.tsx @@ -1,10 +1,7 @@ import React from 'react' import { graphql, useStaticQuery } from 'gatsby' import isFunction from 'lodash/isFunction' -import { - ResponsiveHeatMap, - svgDefaultProps as defaults, -} from '@nivo/heatmap' +import { ResponsiveHeatMap, svgDefaultProps as defaults } from '@nivo/heatmap' import { generateXYSeries } from '@nivo/generators' import { ComponentTemplate } from '../../components/components/ComponentTemplate' import meta from '../../data/components/heatmap/meta.yml' @@ -93,6 +90,7 @@ const initialProperties = { minValue: -100_000, maxValue: 100_000, }, + emptyColor: '#555555', cellComponent: 'rect', opacity: defaults.opacity, activeOpacity: defaults.activeOpacity,