From 62644b0a8375e2e308fc8d48a4742d6a6873df93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Benitte?= Date: Wed, 10 Apr 2019 22:20:58 +0900 Subject: [PATCH] feat(colors): init @nivo/colors package --- .gitignore | 3 - .nvmrc | 1 + Makefile | 4 +- api/package.json | 2 +- packages/axes/package.json | 2 +- packages/bar/index.d.ts | 2 + packages/bar/package.json | 5 +- packages/bar/src/enhance.js | 16 +- packages/bar/src/props.js | 3 + packages/bar/stories/bar.stories.js | 4 +- packages/bullet/package.json | 5 +- packages/bullet/src/BulletMarkers.js | 5 +- packages/bullet/src/BulletRects.js | 5 +- packages/calendar/package.json | 2 +- packages/chord/package.json | 3 +- packages/chord/src/ChordArcs.js | 4 +- packages/chord/src/ChordRibbons.js | 17 +- packages/chord/src/enhance.js | 15 +- packages/chord/src/props.js | 5 +- packages/chord/stories/chord.stories.js | 2 +- packages/circle-packing/package.json | 3 +- packages/circle-packing/src/Bubble.js | 9 +- packages/circle-packing/src/BubbleHtml.js | 9 +- packages/circle-packing/src/enhance.js | 20 +- packages/circle-packing/src/motion.js | 6 +- packages/circle-packing/src/props.js | 26 +-- packages/colors/LICENSE.md | 19 ++ packages/colors/README.md | 3 + packages/colors/index.d.ts | 82 ++++++++ packages/colors/package.json | 32 +++ packages/colors/src/index.js | 12 ++ packages/colors/src/motion.js | 45 ++++ packages/colors/src/ordinalColorScale.js | 103 +++++++++ packages/colors/src/props.js | 22 ++ packages/colors/src/schemes.js | 197 ++++++++++++++++++ packages/colors/tests/.eslintrc.yml | 2 + .../colors => colors/tests}/motion.test.js | 8 +- .../colors/tests/ordinalColorScale.test.js | 124 +++++++++++ packages/core/package.json | 6 +- packages/core/src/components/Container.js | 2 +- packages/core/src/hocs/index.js | 1 - packages/core/src/hocs/withColors.js | 41 ---- packages/core/src/lib/colors/index.js | 59 +----- packages/core/src/lib/colors/motion.js | 49 ----- packages/core/tests/lib/colors/colors.test.js | 30 +-- packages/generators/package.json | 2 +- packages/geo/package.json | 2 +- packages/heatmap/package.json | 5 +- packages/heatmap/src/HeatMap.js | 11 +- packages/legends/package.json | 2 +- packages/line/index.d.ts | 2 + packages/line/package.json | 5 +- packages/line/src/Line.js | 6 +- packages/line/src/props.js | 5 +- packages/line/stories/line.stories.js | 2 +- packages/parallel-coordinates/package.json | 3 +- packages/parallel-coordinates/src/enhance.js | 14 +- packages/parallel-coordinates/src/props.js | 5 +- packages/pie/index.d.ts | 3 +- packages/pie/package.json | 3 +- packages/pie/src/PieLayout.js | 7 +- packages/pie/src/props.js | 3 + packages/pie/tests/PieLayout.test.js | 7 +- packages/radar/package.json | 5 +- packages/radar/src/Radar.js | 17 +- packages/sankey/index.d.ts | 2 + packages/sankey/package.json | 3 +- packages/sankey/src/SankeyLabels.js | 5 +- packages/sankey/src/SankeyNodes.js | 5 +- packages/sankey/src/enhance.js | 12 +- packages/sankey/src/props.js | 5 + packages/sankey/stories/sankey.stories.js | 2 +- packages/scales/package.json | 4 +- packages/scales/src/compute.js | 18 +- packages/scatterplot/index.d.ts | 2 + packages/scatterplot/package.json | 5 +- packages/scatterplot/src/enhance.js | 8 +- packages/scatterplot/src/props.js | 5 +- .../stories/ScatterPlot.stories.js | 8 +- .../stories/ScatterPlotCanvas.stories.js | 8 +- packages/stream/package.json | 5 +- packages/stream/src/Stream.js | 6 +- packages/stream/src/enhance.js | 4 +- packages/stream/src/props.js | 5 +- packages/sunburst/package.json | 3 +- packages/sunburst/src/Sunburst.js | 16 +- packages/treemap/package.json | 3 +- packages/treemap/src/TreeMap.js | 9 +- packages/treemap/src/TreeMapHtml.js | 4 +- packages/treemap/src/enhance.js | 21 +- packages/treemap/src/motion.js | 6 +- packages/treemap/src/props.js | 11 +- packages/voronoi/package.json | 2 +- packages/waffle/package.json | 1 + packages/waffle/src/enhance.js | 15 +- packages/waffle/src/props.js | 4 +- .../waffle/stories/waffle-canvas.stories.js | 6 +- .../waffle/stories/waffle-html.stories.js | 4 +- packages/waffle/stories/waffle.stories.js | 4 +- website/package.json | 1 + .../src/components/controls/ColorsControl.js | 7 +- .../src/components/controls/ControlsGroup.js | 11 + .../controls/OrdinalColorsControl.js | 110 ++++++++++ .../guides/colors/ColorsIllustrations.js | 16 +- .../components/guides/colors/ColorsRanges.js | 58 +++++- .../gradients/GradientsIllustrations.js | 18 +- .../guides/patterns/PatternsIllustrations.js | 12 +- website/src/data/components/bar/mapper.js | 18 -- website/src/data/components/bar/props.js | 34 +-- website/src/data/components/bubble/mapper.js | 4 - website/src/data/components/bubble/props.js | 37 +--- website/src/data/components/chord/props.js | 4 +- website/src/data/components/line/defaults.js | 3 +- website/src/data/components/line/mapper.js | 4 - website/src/data/components/line/props.js | 25 +-- .../components/parallel-coordinates/mapper.js | 16 +- .../components/parallel-coordinates/props.js | 2 +- website/src/data/components/pie/props.js | 29 +-- website/src/data/components/radar/props.js | 31 +-- website/src/data/components/sankey/props.js | 6 +- .../src/data/components/scatterplot/mapper.js | 27 --- .../src/data/components/scatterplot/props.js | 30 +-- .../src/data/components/stream/defaults.js | 2 +- website/src/data/components/stream/mapper.js | 4 - website/src/data/components/stream/props.js | 2 +- .../data/components/sunburst/SunburstPage.js | 50 ----- .../src/data/components/sunburst/mapper.js | 4 - website/src/data/components/sunburst/props.js | 30 +-- website/src/data/components/treemap/mapper.js | 4 - website/src/data/components/treemap/props.js | 45 +--- website/src/data/components/waffle/mapper.js | 17 -- website/src/data/components/waffle/props.js | 27 +-- website/src/data/nav.js | 13 ++ website/src/pages/bar/api.js | 3 +- website/src/pages/bar/canvas.js | 7 +- website/src/pages/bar/index.js | 3 +- website/src/pages/bubble/api.js | 2 - website/src/pages/bubble/canvas.js | 3 +- website/src/pages/bubble/html.js | 3 +- website/src/pages/bubble/index.js | 3 +- website/src/pages/chord/api.js | 3 - website/src/pages/chord/canvas.js | 2 +- website/src/pages/chord/index.js | 2 +- website/src/pages/pie/api.js | 7 - website/src/pages/pie/canvas.js | 3 +- website/src/pages/pie/index.js | 3 +- website/src/pages/radar/api.js | 2 - website/src/pages/radar/index.js | 3 +- website/src/pages/sankey/api.js | 1 - website/src/pages/sankey/index.js | 2 +- website/src/pages/scatterplot/canvas.js | 64 +----- website/src/pages/scatterplot/index.js | 3 +- website/src/pages/sunburst/api.js | 2 - website/src/pages/sunburst/index.js | 3 +- website/src/pages/treemap/api.js | 3 - website/src/pages/treemap/canvas.js | 10 +- website/src/pages/treemap/html.js | 3 +- website/src/pages/treemap/index.js | 3 +- website/src/pages/waffle/canvas.js | 3 +- website/src/pages/waffle/html.js | 3 +- website/src/pages/waffle/index.js | 3 +- website/src/styles/guides.css | 13 -- website/src/styles/index.css | 1 - website/src/styles/table.css | 22 -- website/src/theming/GlobalStyle.js | 14 ++ website/src/theming/nivo.js | 6 +- yarn.lock | 85 ++++++-- 167 files changed, 1296 insertions(+), 1043 deletions(-) create mode 100644 .nvmrc create mode 100644 packages/colors/LICENSE.md create mode 100644 packages/colors/README.md create mode 100644 packages/colors/index.d.ts create mode 100644 packages/colors/package.json create mode 100644 packages/colors/src/index.js create mode 100644 packages/colors/src/motion.js create mode 100644 packages/colors/src/ordinalColorScale.js create mode 100644 packages/colors/src/props.js create mode 100644 packages/colors/src/schemes.js create mode 100644 packages/colors/tests/.eslintrc.yml rename packages/{core/tests/lib/colors => colors/tests}/motion.test.js (83%) create mode 100644 packages/colors/tests/ordinalColorScale.test.js delete mode 100644 packages/core/src/hocs/withColors.js delete mode 100644 packages/core/src/lib/colors/motion.js create mode 100644 website/src/components/controls/OrdinalColorsControl.js delete mode 100644 website/src/data/components/sunburst/SunburstPage.js delete mode 100644 website/src/styles/table.css diff --git a/.gitignore b/.gitignore index ba9e4b11f..022800ab8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,3 @@ build /packages/*/dist *.lerna_backup - -_website - diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..af8df1f67 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v10 \ No newline at end of file diff --git a/Makefile b/Makefile index c3a5bcb9d..dbbe4e3f3 100644 --- a/Makefile +++ b/Makefile @@ -127,6 +127,7 @@ packages-tslint: ##@1 packages run tslint on all packages ./packages/axes/index.d.ts \ ./packages/bar/index.d.ts \ ./packages/calendar/index.d.ts \ + ./packages/colors/index.d.ts \ ./packages/core/index.d.ts \ ./packages/geo/index.d.ts \ ./packages/heatmap/index.d.ts \ @@ -163,8 +164,7 @@ packages-build: ##@1 packages build all packages package-build-%: ##@1 packages build a package @echo "${YELLOW}Building package ${WHITE}@nivo/${*}${RESET}" - @rm -rf ./packages/${*}/cjs - @rm -rf ./packages/${*}/umd + @rm -rf ./packages/${*}/dist @export PACKAGE=${*}; ./node_modules/.bin/rollup -c conf/rollup.config.js packages-screenshots: ##@1 packages generate screenshots for packages readme (website dev server must be running) diff --git a/api/package.json b/api/package.json index 3c427a009..bb11af0d3 100644 --- a/api/package.json +++ b/api/package.json @@ -48,7 +48,7 @@ "express": "^4.15.4", "express-winston": "^2.4.0", "joi": "^14.3.0", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react": "^16.8.4", "react-dom": "^16.8.4", "uuid": "^3.1.0", diff --git a/packages/axes/package.json b/packages/axes/package.json index aaaa4567e..672e4ecde 100644 --- a/packages/axes/package.json +++ b/packages/axes/package.json @@ -24,7 +24,7 @@ "@nivo/core": "0.55.0", "d3-format": "^1.3.2", "d3-time-format": "^2.1.3", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/bar/index.d.ts b/packages/bar/index.d.ts index dc3857360..3022262b0 100644 --- a/packages/bar/index.d.ts +++ b/packages/bar/index.d.ts @@ -9,6 +9,7 @@ import { SvgDefsAndFill, CartesianMarkerProps, } from '@nivo/core' +import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' declare module '@nivo/bar' { @@ -106,6 +107,7 @@ declare module '@nivo/bar' { labelSkipHeight: number labelTextColor: string | GetColor + colors: OrdinalColorsInstruction borderRadius: number borderWidth: number theme: Theme diff --git a/packages/bar/package.json b/packages/bar/package.json index bc3d736a4..b59868634 100644 --- a/packages/bar/package.json +++ b/packages/bar/package.json @@ -24,11 +24,12 @@ ], "dependencies": { "@nivo/axes": "0.55.0", + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-shape": "^1.2.2", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/bar/src/enhance.js b/packages/bar/src/enhance.js index f9416b8aa..facc8aa5d 100644 --- a/packages/bar/src/enhance.js +++ b/packages/bar/src/enhance.js @@ -10,18 +10,26 @@ import { compose } from 'recompose' import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' -import { withTheme, withColors, withDimensions, withMotion } from '@nivo/core' -import { getInheritedColorGenerator } from '@nivo/core' -import { getAccessorFor, getLabelGenerator } from '@nivo/core' +import { + withTheme, + withDimensions, + withMotion, + getInheritedColorGenerator, + getAccessorFor, + getLabelGenerator, +} from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { BarDefaultProps } from './props' export default Component => compose( defaultProps(BarDefaultProps), withTheme(), - withColors(), withDimensions(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + })), withPropsOnChange(['indexBy'], ({ indexBy }) => ({ getIndex: getAccessorFor(indexBy), })), diff --git a/packages/bar/src/props.js b/packages/bar/src/props.js index 350e58fdb..e02770332 100644 --- a/packages/bar/src/props.js +++ b/packages/bar/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { noop, defsPropTypes } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' import { LegendPropShape } from '@nivo/legends' import BarItem from './BarItem' @@ -55,6 +56,7 @@ export const BarPropTypes = { labelLinkColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, getLabelLinkColor: PropTypes.func.isRequired, // computed + colors: ordinalColorsPropType.isRequired, borderRadius: PropTypes.number.isRequired, getColor: PropTypes.func.isRequired, // computed ...defsPropTypes, @@ -110,6 +112,7 @@ export const BarDefaultProps = { labelLinkColor: 'theme', labelTextColor: 'theme', + colors: { scheme: 'nivo' }, defs: [], fill: [], borderRadius: 0, diff --git a/packages/bar/stories/bar.stories.js b/packages/bar/stories/bar.stories.js index 2487bf2ae..319f74e82 100644 --- a/packages/bar/stories/bar.stories.js +++ b/packages/bar/stories/bar.stories.js @@ -56,8 +56,8 @@ stories.add('with marker', () => ( /> )) -stories.add('using custom colorBy', () => ( - data[`${id}Color`]} /> +stories.add('using custom color', () => ( + data[`${id}Color`]} /> )) const divergingData = range(9).map(i => { diff --git a/packages/bullet/package.json b/packages/bullet/package.json index f58ac4b27..002d97c6f 100644 --- a/packages/bullet/package.json +++ b/packages/bullet/package.json @@ -23,10 +23,11 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", - "d3-scale": "^2.1.2", - "lodash": "^4.17.4", + "d3-scale": "^3.0.0", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/bullet/src/BulletMarkers.js b/packages/bullet/src/BulletMarkers.js index 38de7a494..7998d086c 100644 --- a/packages/bullet/src/BulletMarkers.js +++ b/packages/bullet/src/BulletMarkers.js @@ -9,7 +9,8 @@ import React, { Component, Fragment } from 'react' import PropTypes from 'prop-types' import { TransitionMotion, spring } from 'react-motion' -import { motionPropTypes, colorMotionSpring, getInterpolatedColor } from '@nivo/core' +import { motionPropTypes } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import partial from 'lodash/partial' const getPositionGenerator = ({ layout, reverse, scale, height, markerSize }) => { @@ -118,7 +119,7 @@ export default class BulletMarkers extends Component { y: spring(position.y, springConfig), size: spring(position.size, springConfig), rotation: spring(position.rotation, springConfig), - ...colorMotionSpring(marker.color, springConfig), + ...interpolateColor(marker.color, springConfig), }, } })} diff --git a/packages/bullet/src/BulletRects.js b/packages/bullet/src/BulletRects.js index 7ac53792a..ccdda2687 100644 --- a/packages/bullet/src/BulletRects.js +++ b/packages/bullet/src/BulletRects.js @@ -13,7 +13,8 @@ import { TransitionMotion, spring } from 'react-motion' import compose from 'recompose/compose' import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' -import { motionPropTypes, colorMotionSpring, getInterpolatedColor } from '@nivo/core' +import { motionPropTypes } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import { computeRects } from './compute' class BulletRects extends Component { @@ -106,7 +107,7 @@ class BulletRects extends Component { y: spring(rect.y, springConfig), width: spring(rect.width, springConfig), height: spring(rect.height, springConfig), - ...colorMotionSpring(rect.data.color, springConfig), + ...interpolateColor(rect.data.color, springConfig), }, }))} > diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 198c5268d..41ab407e7 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -25,7 +25,7 @@ "dependencies": { "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-time": "^1.0.10", "d3-time-format": "^2.1.3", "lodash.isdate": "^4.0.1", diff --git a/packages/chord/package.json b/packages/chord/package.json index 285580fec..b910a5b20 100644 --- a/packages/chord/package.json +++ b/packages/chord/package.json @@ -22,12 +22,13 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "d3-chord": "^1.0.6", "d3-format": "^1.3.2", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/chord/src/ChordArcs.js b/packages/chord/src/ChordArcs.js index 72592d90c..0c1f8bae6 100644 --- a/packages/chord/src/ChordArcs.js +++ b/packages/chord/src/ChordArcs.js @@ -10,7 +10,7 @@ import React from 'react' import PropTypes from 'prop-types' import { TransitionMotion, spring } from 'react-motion' import pure from 'recompose/pure' -import { colorMotionSpring, getInterpolatedColor } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import ChordArcTooltip from './ChordArcTooltip' import { motionPropTypes } from '@nivo/core' @@ -88,7 +88,7 @@ const ChordArcs = ({ startAngle: spring(arc.startAngle, springConfig), endAngle: spring(arc.endAngle, springConfig), opacity: spring(getOpacity(arc), springConfig), - ...colorMotionSpring(arc.color, springConfig), + ...interpolateColor(arc.color, springConfig), }, } })} diff --git a/packages/chord/src/ChordRibbons.js b/packages/chord/src/ChordRibbons.js index bca199df3..de06232a0 100644 --- a/packages/chord/src/ChordRibbons.js +++ b/packages/chord/src/ChordRibbons.js @@ -15,15 +15,8 @@ import { format as d3Format } from 'd3-format' import compose from 'recompose/compose' import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' -import { - colorMotionSpring, - getInterpolatedColor, - blendModePropType, - midAngle, - TableTooltip, - Chip, - motionPropTypes, -} from '@nivo/core' +import { blendModePropType, midAngle, TableTooltip, Chip, motionPropTypes } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' /** * Used to get ribbon angles, instead of using source and target arcs, @@ -76,13 +69,13 @@ const getRibbonAngles = ({ source, target }, useMiddleAngle, springConfig) => { const ribbonWillEnter = ({ data: ribbon }) => ({ ...getRibbonAngles(ribbon, true), opacity: 0, - ...colorMotionSpring(ribbon.source.color), + ...interpolateColor(ribbon.source.color), }) const ribbonWillLeave = springConfig => ({ data: ribbon }) => ({ ...getRibbonAngles(ribbon, true, springConfig), opacity: 0, - ...colorMotionSpring(ribbon.source.color, springConfig), + ...interpolateColor(ribbon.source.color, springConfig), }) const ChordRibbons = ({ @@ -178,7 +171,7 @@ const ChordRibbons = ({ style: { ...getRibbonAngles(ribbon, false, springConfig), opacity: spring(getOpacity(ribbon), springConfig), - ...colorMotionSpring(ribbon.source.color, springConfig), + ...interpolateColor(ribbon.source.color, springConfig), }, } })} diff --git a/packages/chord/src/enhance.js b/packages/chord/src/enhance.js index 6ee0c3d00..2092b652f 100644 --- a/packages/chord/src/enhance.js +++ b/packages/chord/src/enhance.js @@ -13,9 +13,14 @@ import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' import { arc as d3Arc } from 'd3-shape' import { chord as d3Chord, ribbon as d3Ribbon } from 'd3-chord' -import { getInheritedColorGenerator, getColorRange } from '@nivo/core' -import { getLabelGenerator } from '@nivo/core' -import { withMotion, withTheme, withDimensions } from '@nivo/core' +import { + getInheritedColorGenerator, + getLabelGenerator, + withMotion, + withTheme, + withDimensions, +} from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { ChordDefaultProps } from './props' export default Component => @@ -36,11 +41,11 @@ export default Component => getLabelTextColor: getInheritedColorGenerator(labelTextColor, 'labels.textColor'), })), withPropsOnChange(['colors', 'keys'], ({ colors, keys }) => { - const color = getColorRange(colors) + const getColor = getOrdinalColorScale(colors, 'key') return { colorById: keys.reduce((acc, key) => { - acc[key] = color(key) + acc[key] = getColor({ key }) return acc }, {}), } diff --git a/packages/chord/src/props.js b/packages/chord/src/props.js index 902a4ef03..5889ae374 100644 --- a/packages/chord/src/props.js +++ b/packages/chord/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { blendModePropType } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape } from '@nivo/legends' export const ChordPropTypes = { @@ -37,7 +38,7 @@ export const ChordPropTypes = { labelTextColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, getLabelTextColor: PropTypes.func.isRequired, // computed - colors: PropTypes.any.isRequired, + colors: ordinalColorsPropType.isRequired, isInteractive: PropTypes.bool.isRequired, arcHoverOpacity: PropTypes.number.isRequired, @@ -71,7 +72,7 @@ export const ChordDefaultProps = { labelRotation: 0, labelTextColor: 'inherit:darker(1)', - colors: 'nivo', + colors: { scheme: 'nivo' }, isInteractive: true, arcHoverOpacity: 1, diff --git a/packages/chord/stories/chord.stories.js b/packages/chord/stories/chord.stories.js index 7a1ef226f..c4877b697 100644 --- a/packages/chord/stories/chord.stories.js +++ b/packages/chord/stories/chord.stories.js @@ -36,7 +36,7 @@ stories.add('alternative colors', () => ( labelRotation={-90} padAngle={0.02} innerRadiusOffset={0.02} - colors="category10" + colors={{ scheme: 'category10' }} /> )) diff --git a/packages/circle-packing/package.json b/packages/circle-packing/package.json index 16dee4944..a7b85aac7 100644 --- a/packages/circle-packing/package.json +++ b/packages/circle-packing/package.json @@ -22,9 +22,10 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "d3-hierarchy": "^1.1.8", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/circle-packing/src/Bubble.js b/packages/circle-packing/src/Bubble.js index 7f42ef92e..33ae89ee1 100644 --- a/packages/circle-packing/src/Bubble.js +++ b/packages/circle-packing/src/Bubble.js @@ -10,8 +10,8 @@ import React from 'react' import { TransitionMotion, spring } from 'react-motion' import pick from 'lodash/pick' -import { colorMotionSpring, getInterpolatedColor } from '@nivo/core' import { Container, SvgWrapper } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import enhance from './enhance' import { nodeWillEnter, nodeWillLeave } from './motion' import { getNodeHandlers } from './interactivity' @@ -20,26 +20,21 @@ const Bubble = ({ nodes, nodeComponent, - // dimensions margin, outerWidth, outerHeight, - // styling theme, borderWidth, getBorderColor, defs, - // labels getLabelTextColor, - // motion animate, motionStiffness, motionDamping, - // interactivity isInteractive, onClick, tooltipFormat, @@ -107,7 +102,7 @@ const Bubble = ({ x: spring(node.x, springConfig), y: spring(node.y, springConfig), opacity: spring(1, springConfig), - ...colorMotionSpring(node.color, springConfig), + ...interpolateColor(node.color, springConfig), }, }))} > diff --git a/packages/circle-packing/src/BubbleHtml.js b/packages/circle-packing/src/BubbleHtml.js index 32e7d6ec4..af1487d5b 100644 --- a/packages/circle-packing/src/BubbleHtml.js +++ b/packages/circle-packing/src/BubbleHtml.js @@ -10,8 +10,8 @@ import React from 'react' import { TransitionMotion, spring } from 'react-motion' import pick from 'lodash/pick' -import { colorMotionSpring, getInterpolatedColor } from '@nivo/core' import { Container } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import enhance from './enhance' import { nodeWillEnter, nodeWillLeave } from './motion' import { getNodeHandlers } from './interactivity' @@ -20,25 +20,20 @@ const BubbleHtml = ({ nodes, nodeComponent, - // dimensions margin, outerWidth, outerHeight, - // styling theme, borderWidth, getBorderColor, - // labels getLabelTextColor, - // motion animate, motionStiffness, motionDamping, - // interactivity isInteractive, onClick, isZoomable, @@ -104,7 +99,7 @@ const BubbleHtml = ({ x: spring(node.x, springConfig), y: spring(node.y, springConfig), opacity: spring(1, springConfig), - ...colorMotionSpring(node.color, springConfig), + ...interpolateColor(node.color, springConfig), }, }))} > diff --git a/packages/circle-packing/src/enhance.js b/packages/circle-packing/src/enhance.js index 52a446404..c0813894f 100644 --- a/packages/circle-packing/src/enhance.js +++ b/packages/circle-packing/src/enhance.js @@ -12,10 +12,17 @@ import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' import withStateHandlers from 'recompose/withStateHandlers' import pure from 'recompose/pure' -import { withHierarchy, withDimensions, withTheme, withMotion, withColors } from '@nivo/core' -import { getAccessorFor, getLabelGenerator } from '@nivo/core' -import { getInheritedColorGenerator } from '@nivo/core' -import { bindDefs } from '@nivo/core' +import { + withHierarchy, + withDimensions, + withTheme, + withMotion, + getAccessorFor, + getLabelGenerator, + getInheritedColorGenerator, + bindDefs, +} from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { computeNodes, computeZoom } from './compute' import * as props from './props' @@ -23,8 +30,9 @@ const commonEnhancers = [ withHierarchy(), withDimensions(), withTheme(), - withColors({ defaultColorBy: 'depth' }), - + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'depth'), + })), withPropsOnChange(['width', 'height', 'padding'], ({ width, height, padding }) => ({ pack: pack() .size([width, height]) diff --git a/packages/circle-packing/src/motion.js b/packages/circle-packing/src/motion.js index ad5e15a57..c5b70cca9 100644 --- a/packages/circle-packing/src/motion.js +++ b/packages/circle-packing/src/motion.js @@ -7,14 +7,14 @@ * file that was distributed with this source code. */ import { spring } from 'react-motion' -import { colorMotionSpring } from '@nivo/core' +import { interpolateColor } from '@nivo/colors' export const nodeWillEnter = ({ data }) => ({ scale: 0, r: 0, x: data.x, y: data.y, - ...colorMotionSpring(data.color), + ...interpolateColor(data.color), }) export const nodeWillLeave = springConfig => ({ data }) => ({ @@ -22,5 +22,5 @@ export const nodeWillLeave = springConfig => ({ data }) => ({ r: spring(0, springConfig), x: spring(data.x, springConfig), y: spring(data.y, springConfig), - ...colorMotionSpring(data.color, springConfig), + ...interpolateColor(data.color, springConfig), }) diff --git a/packages/circle-packing/src/props.js b/packages/circle-packing/src/props.js index 7ac933f71..5046a4dee 100644 --- a/packages/circle-packing/src/props.js +++ b/packages/circle-packing/src/props.js @@ -7,17 +7,11 @@ * file that was distributed with this source code. */ import PropTypes from 'prop-types' -import { noop } from '@nivo/core' -import { defsPropTypes } from '@nivo/core' +import { noop, defsPropTypes } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import BubbleNode from './BubbleNode' import BubbleHtmlNode from './BubbleHtmlNode' -/*————————————————————————————————————————————————————————————————————————————— - - Prop types - -—————————————————————————————————————————————————————————————————————————————*/ - const commonPropTypes = { // data // `root` managed by `withHierarchy()` HOC @@ -25,25 +19,21 @@ const commonPropTypes = { // dimensions managed by `withDimensions()` HOC - // styling // theme managed by `withTheme()` HOC - // colors managed by `withColors()` HOC + colors: ordinalColorsPropType.isRequired, leavesOnly: PropTypes.bool.isRequired, padding: PropTypes.number.isRequired, - // border borderWidth: PropTypes.number.isRequired, borderColor: PropTypes.any.isRequired, - // labels enableLabel: PropTypes.bool.isRequired, label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, labelFormat: PropTypes.string, labelTextColor: PropTypes.any.isRequired, labelSkipRadius: PropTypes.number.isRequired, - // interactivity isInteractive: PropTypes.bool.isRequired, onClick: PropTypes.func.isRequired, isZoomable: PropTypes.bool.isRequired, @@ -67,29 +57,21 @@ export const BubbleCanvasPropTypes = { pixelRatio: PropTypes.number.isRequired, } -/*————————————————————————————————————————————————————————————————————————————— - - Default props - -—————————————————————————————————————————————————————————————————————————————*/ - const commonDefaultProps = { identity: 'id', leavesOnly: false, padding: 1, - // border + colors: { scheme: 'nivo' }, borderWidth: 0, borderColor: 'inherit', - // labels enableLabel: true, label: 'id', labelTextColor: 'inherit:darker(1)', labelSkipRadius: 8, - // interactivity isInteractive: true, onClick: noop, isZoomable: true, diff --git a/packages/colors/LICENSE.md b/packages/colors/LICENSE.md new file mode 100644 index 000000000..faa45389e --- /dev/null +++ b/packages/colors/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) Raphaël Benitte + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/colors/README.md b/packages/colors/README.md new file mode 100644 index 000000000..06f168844 --- /dev/null +++ b/packages/colors/README.md @@ -0,0 +1,3 @@ +# `@nivo/colors` + +[![version](https://img.shields.io/npm/v/@nivo/colors.svg?style=flat-square)](https://www.npmjs.com/package/@nivo/colors) diff --git a/packages/colors/index.d.ts b/packages/colors/index.d.ts new file mode 100644 index 000000000..ab4bb3ec2 --- /dev/null +++ b/packages/colors/index.d.ts @@ -0,0 +1,82 @@ +import * as React from 'react' + +declare module '@nivo/colors' { + export type CategoricalColorSchemeId = + | 'nivo' + | 'category10' + | 'accent' + | 'dark2' + | 'paired' + | 'pastel1' + | 'pastel2' + | 'set1' + | 'set2' + | 'set3' + + export type DivergingColorSchemeId = + | 'brown_blueGreen' + | 'purpleRed_green' + | 'pink_yellowGreen' + | 'purple_orange' + | 'red_blue' + | 'red_grey' + | 'red_yellow_blue' + | 'red_yellow_green' + | 'spectral' + + export type SequentialColorSchemeId = + // single hue + | 'blues' + | 'greens' + | 'greys' + | 'oranges' + | 'purples' + | 'reds' + // multi hue + | 'blue_green' + | 'blue_purple' + | 'green_blue' + | 'orange_red' + | 'purple_blue_green' + | 'purple_blue' + | 'purple_red' + | 'red_purple' + | 'yellow_green_blue' + | 'yellow_green' + | 'yellow_orange_brown' + | 'yellow_orange_red' + + export type ColorSchemeId = + | CategoricalColorSchemeId + | DivergingColorSchemeId + | SequentialColorSchemeId + + export interface DatumColorInstruction { + datum: string + } + export interface SchemeColorInstruction { + scheme: ColorSchemeId + // size is useful for diverging & sequential + // colors, as they are array of array, + // whereas categorical colors are simple arrays + // if the size isn't specified, the bigger array + // will be selected, this means 11 for diverging + // colors and 9 for sequential ones. + size?: number + } + export type CustomColorFunction = (datum: D) => string + + export type OrdinalColorsInstruction = + | DatumColorInstruction + | SchemeColorInstruction + | CustomColorFunction + | string[] + | string + + export type OrdinalColorScale = (datum: D) => string + + export function getOrdinalColorScale( + instruction: OrdinalColorsInstruction, + identity: string + ): OrdinalColorScale +} diff --git a/packages/colors/package.json b/packages/colors/package.json new file mode 100644 index 000000000..bfd46e6ba --- /dev/null +++ b/packages/colors/package.json @@ -0,0 +1,32 @@ +{ + "name": "@nivo/colors", + "version": "0.55.0", + "license": "MIT", + "author": { + "name": "Raphaël Benitte", + "url": "https://github.com/plouc" + }, + "main": "./dist/nivo-colors.cjs.js", + "module": "./dist/nivo-colors.esm.js", + "files": [ + "README.md", + "LICENSE.md", + "index.d.ts", + "dist/" + ], + "dependencies": { + "d3-color": "^1.2.3", + "d3-scale": "^3.0.0", + "d3-scale-chromatic": "^1.3.3", + "lodash.get": "^4.4.2", + "lodash.isplainobject": "^4.6.0", + "react-motion": "^0.5.2" + }, + "peerDependencies": { + "prop-types": ">= 15.5.10 < 16.0.0", + "react": ">= 16.8.4 < 17.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/colors/src/index.js b/packages/colors/src/index.js new file mode 100644 index 000000000..a23d47948 --- /dev/null +++ b/packages/colors/src/index.js @@ -0,0 +1,12 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +export * from './schemes' +export * from './ordinalColorScale' +export * from './props' +export * from './motion' diff --git a/packages/colors/src/motion.js b/packages/colors/src/motion.js new file mode 100644 index 000000000..3147c22be --- /dev/null +++ b/packages/colors/src/motion.js @@ -0,0 +1,45 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import { spring } from 'react-motion' +import { rgb } from 'd3-color' + +/** + * Decompose a color to be used with react-motion. + */ +export const interpolateColor = (color, springConfig) => { + const colorComponents = rgb(color) + + if (!springConfig) { + return { + colorR: colorComponents.r, + colorG: colorComponents.g, + colorB: colorComponents.b, + } + } + + const configWithPrecision = { + ...springConfig, + precision: 1, + } + + return { + colorR: spring(colorComponents.r, configWithPrecision), + colorG: spring(colorComponents.g, configWithPrecision), + colorB: spring(colorComponents.b, configWithPrecision), + } +} + +/** + * Re-assemble interpolated color components, + * should be used to assign a color after react-motion interpolation. + */ +export const getInterpolatedColor = ({ colorR, colorG, colorB }) => + `rgb(${Math.round(Math.max(colorR, 0))},${Math.round(Math.max(colorG, 0))},${Math.round( + Math.max(colorB, 0) + )})` diff --git a/packages/colors/src/ordinalColorScale.js b/packages/colors/src/ordinalColorScale.js new file mode 100644 index 000000000..911130c7e --- /dev/null +++ b/packages/colors/src/ordinalColorScale.js @@ -0,0 +1,103 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import { useMemo } from 'react' +import get from 'lodash.get' +import isPlainObject from 'lodash.isplainobject' +import { scaleOrdinal } from 'd3-scale' +import { + colorSchemes, + isCategoricalColorScheme, + isSequentialColorScheme, + isDivergingColorScheme, +} from './schemes' + +/** + * Compute an ordinal color scale + */ +export const getOrdinalColorScale = (instruction, identity) => { + // user defined function + if (typeof instruction === 'function') return instruction + + if (Array.isArray(instruction)) { + const scale = scaleOrdinal(instruction) + const generator = d => scale(get(d, identity)) + generator.scale = scale + + return generator + } + + if (isPlainObject(instruction)) { + // use color from current datum + if (instruction.datum !== undefined) { + return datum => get(datum, instruction.datum) + } + + // ordinal scale from predefined scheme + if (instruction.scheme !== undefined) { + // categorical color scheme + if (isCategoricalColorScheme(instruction.scheme)) { + const scale = scaleOrdinal(colorSchemes[instruction.scheme]) + const generator = d => scale(get(d, identity)) + generator.scale = scale + + return generator + } + + // Diverging color schemes support a size k ranging from 3 to 11 + if (isDivergingColorScheme(instruction.scheme)) { + if ( + instruction.size !== undefined && + (instruction.size < 3 || instruction.size > 11) + ) { + throw new Error( + `Invalid size '${instruction.size}' for diverging color scheme '${ + instruction.scheme + }', must be between 3~11` + ) + } + + const scale = scaleOrdinal(colorSchemes[instruction.scheme][instruction.size || 11]) + const generator = d => scale(get(d, identity)) + generator.scale = scale + + return generator + } + + // Sequential, single-hue color schemes support a size k ranging from 3 to 9. + // Sequential, multi-hue color schemes support a size k ranging from 3 to 9. + if (isSequentialColorScheme(instruction.scheme)) { + if ( + instruction.size !== undefined && + (instruction.size < 3 || instruction.size > 9) + ) { + throw new Error( + `Invalid size '${instruction.size}' for sequential color scheme '${ + instruction.scheme + }', must be between 3~9` + ) + } + + const scale = scaleOrdinal(colorSchemes[instruction.scheme][instruction.size || 9]) + const generator = d => scale(get(d, identity)) + generator.scale = scale + + return generator + } + } + + throw new Error( + `Invalid colors, when using an object, you should either pass a 'datum' or a 'scheme' property` + ) + } + + return () => instruction +} + +export const useOrdinalColorScale = (instruction, identity) => + useMemo(() => getOrdinalColorScale(instruction, identity), [instruction, identity]) diff --git a/packages/colors/src/props.js b/packages/colors/src/props.js new file mode 100644 index 000000000..34ef40326 --- /dev/null +++ b/packages/colors/src/props.js @@ -0,0 +1,22 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import PropTypes from 'prop-types' +import { colorSchemeIds } from './schemes' + +export const ordinalColorsPropType = PropTypes.oneOfType([ + PropTypes.func, + PropTypes.arrayOf(PropTypes.string), + PropTypes.shape({ + scheme: PropTypes.oneOf(colorSchemeIds).isRequired, + size: PropTypes.number, + }), + PropTypes.shape({ + datum: PropTypes.string.isRequired, + }), +]) diff --git a/packages/colors/src/schemes.js b/packages/colors/src/schemes.js new file mode 100644 index 000000000..294815ec4 --- /dev/null +++ b/packages/colors/src/schemes.js @@ -0,0 +1,197 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import { + // categorical + schemeCategory10, + schemeAccent, + schemeDark2, + schemePaired, + schemePastel1, + schemePastel2, + schemeSet1, + schemeSet2, + schemeSet3, + // diverging + interpolateBrBG, + schemeBrBG, + interpolatePRGn, + schemePRGn, + interpolatePiYG, + schemePiYG, + interpolatePuOr, + schemePuOr, + interpolateRdBu, + schemeRdBu, + interpolateRdGy, + schemeRdGy, + interpolateRdYlBu, + schemeRdYlBu, + interpolateRdYlGn, + schemeRdYlGn, + interpolateSpectral, + schemeSpectral, + // sequential single hue + interpolateBlues, + schemeBlues, + interpolateGreens, + schemeGreens, + interpolateGreys, + schemeGreys, + interpolateOranges, + schemeOranges, + interpolatePurples, + schemePurples, + interpolateReds, + schemeReds, + // sequential multi hue + interpolateViridis, + interpolateInferno, + interpolateMagma, + interpolatePlasma, + interpolateWarm, + interpolateCool, + interpolateCubehelixDefault, + interpolateBuGn, + schemeBuGn, + interpolateBuPu, + schemeBuPu, + interpolateGnBu, + schemeGnBu, + interpolateOrRd, + schemeOrRd, + interpolatePuBuGn, + schemePuBuGn, + interpolatePuBu, + schemePuBu, + interpolatePuRd, + schemePuRd, + interpolateRdPu, + schemeRdPu, + interpolateYlGnBu, + schemeYlGnBu, + interpolateYlGn, + schemeYlGn, + interpolateYlOrBr, + schemeYlOrBr, + interpolateYlOrRd, + schemeYlOrRd, + // cyclical + interpolateRainbow, + interpolateSinebow, +} from 'd3-scale-chromatic' + +// Categorical color schemes +export const categoricalColorSchemes = { + nivo: ['#e8c1a0', '#f47560', '#f1e15b', '#e8a838', '#61cdbb', '#97e3d5'], + category10: schemeCategory10, + accent: schemeAccent, + dark2: schemeDark2, + paired: schemePaired, + pastel1: schemePastel1, + pastel2: schemePastel2, + set1: schemeSet1, + set2: schemeSet2, + set3: schemeSet3, +} +export const categoricalColorSchemeIds = Object.keys(categoricalColorSchemes) +export const isCategoricalColorScheme = scheme => categoricalColorSchemeIds.includes(scheme) + +// Diverging color schemes support a size k ranging from 3 to 11 +export const divergingColorSchemes = { + brown_blueGreen: schemeBrBG, + purpleRed_green: schemePRGn, + pink_yellowGreen: schemePiYG, + purple_orange: schemePuOr, + red_blue: schemeRdBu, + red_grey: schemeRdGy, + red_yellow_blue: schemeRdYlBu, + red_yellow_green: schemeRdYlGn, + spectral: schemeSpectral, +} +export const divergingColorSchemeIds = Object.keys(divergingColorSchemes) +export const isDivergingColorScheme = scheme => divergingColorSchemeIds.includes(scheme) + +// Sequential, single-hue color schemes support a size k ranging from 3 to 9 +// Sequential, multi-hue color schemes support a size k ranging from 3 to 9 +export const sequentialColorSchemes = { + // single hue + blues: schemeBlues, + greens: schemeGreens, + greys: schemeGreys, + oranges: schemeOranges, + purples: schemePurples, + reds: schemeReds, + // multi hue + blue_green: schemeBuGn, + blue_purple: schemeBuPu, + green_blue: schemeGnBu, + orange_red: schemeOrRd, + purple_blue_green: schemePuBuGn, + purple_blue: schemePuBu, + purple_red: schemePuRd, + red_purple: schemeRdPu, + yellow_green_blue: schemeYlGnBu, + yellow_green: schemeYlGn, + yellow_orange_brown: schemeYlOrBr, + yellow_orange_red: schemeYlOrRd, +} +export const sequentialColorSchemeIds = Object.keys(sequentialColorSchemes) +export const isSequentialColorScheme = scheme => sequentialColorSchemeIds.includes(scheme) + +export const colorSchemes = { + ...categoricalColorSchemes, + ...divergingColorSchemes, + ...sequentialColorSchemes, +} +export const colorSchemeIds = Object.keys(colorSchemes) + +export const colorInterpolators = { + // diverging + brown_blueGreen: interpolateBrBG, + purpleRed_green: interpolatePRGn, + pink_yellowGreen: interpolatePiYG, + purple_orange: interpolatePuOr, + red_blue: interpolateRdBu, + red_grey: interpolateRdGy, + red_yellow_blue: interpolateRdYlBu, + red_yellow_green: interpolateRdYlGn, + spectral: interpolateSpectral, + // sequential single hue + blues: interpolateBlues, + greens: interpolateGreens, + greys: interpolateGreys, + oranges: interpolateOranges, + purples: interpolatePurples, + reds: interpolateReds, + // sequential multi hue + viridis: interpolateViridis, + inferno: interpolateInferno, + magma: interpolateMagma, + plasma: interpolatePlasma, + warm: interpolateWarm, + cool: interpolateCool, + cubehelixDefault: interpolateCubehelixDefault, + blue_green: interpolateBuGn, + blue_purple: interpolateBuPu, + green_blue: interpolateGnBu, + orange_red: interpolateOrRd, + purple_blue_green: interpolatePuBuGn, + purple_blue: interpolatePuBu, + purple_red: interpolatePuRd, + red_purple: interpolateRdPu, + yellow_green_blue: interpolateYlGnBu, + yellow_green: interpolateYlGn, + yellow_orange_brown: interpolateYlOrBr, + yellow_orange_red: interpolateYlOrRd, + // cyclical + rainbow: interpolateRainbow, + sinebow: interpolateSinebow, +} + +export const colorInterpolatorIds = Object.keys(colorInterpolators) diff --git a/packages/colors/tests/.eslintrc.yml b/packages/colors/tests/.eslintrc.yml new file mode 100644 index 000000000..2f8de9aea --- /dev/null +++ b/packages/colors/tests/.eslintrc.yml @@ -0,0 +1,2 @@ +env: + jest: true diff --git a/packages/core/tests/lib/colors/motion.test.js b/packages/colors/tests/motion.test.js similarity index 83% rename from packages/core/tests/lib/colors/motion.test.js rename to packages/colors/tests/motion.test.js index f77d7ff9f..b9d4a2f24 100644 --- a/packages/core/tests/lib/colors/motion.test.js +++ b/packages/colors/tests/motion.test.js @@ -6,11 +6,11 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import { colorMotionSpring, getInterpolatedColor } from '../../../src/lib/colors/motion' +import { interpolateColor, getInterpolatedColor } from '../src' -describe('colorMotionSpring()', () => { +describe('interpolateColor()', () => { it('should return decomposed color', () => { - expect(colorMotionSpring('#F00')).toEqual({ + expect(interpolateColor('#F00')).toEqual({ colorR: 255, colorG: 0, colorB: 0, @@ -18,7 +18,7 @@ describe('colorMotionSpring()', () => { }) it('should return decomposed color with corresponding spring if config provided', () => { - expect(colorMotionSpring('#F0F', { stifness: 120, damping: 15 })).toEqual({ + expect(interpolateColor('#F0F', { stifness: 120, damping: 15 })).toEqual({ colorR: { damping: 15, precision: 1, diff --git a/packages/colors/tests/ordinalColorScale.test.js b/packages/colors/tests/ordinalColorScale.test.js new file mode 100644 index 000000000..8600d66c7 --- /dev/null +++ b/packages/colors/tests/ordinalColorScale.test.js @@ -0,0 +1,124 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import { + getOrdinalColorScale, + colorSchemes, + categoricalColorSchemeIds, + divergingColorSchemeIds, + sequentialColorSchemeIds, +} from '../src' + +it(`should accept user defined function`, () => { + const userFunction = () => 'red' + const colorScale = getOrdinalColorScale(userFunction) + + expect(colorScale).toBe(userFunction) + expect(colorScale()).toBe('red') +}) + +it(`should be able to generate a generator which use data color`, () => { + const colorScale = getOrdinalColorScale({ datum: 'color' }) + + expect(colorScale({ color: 'green' })).toBe('green') +}) + +it(`should accept user defined color array`, () => { + const colors = ['purple', 'green', 'blue'] + const colorScale = getOrdinalColorScale(colors, 'id') + + expect(colorScale.scale.range()).toEqual(colors) + expect(colorScale({ id: 'whatever' })).toBe('purple') +}) + +categoricalColorSchemeIds.forEach(scheme => { + it(`should be able to generate a scale from categorical colors (${scheme})`, () => { + const colorScale = getOrdinalColorScale({ scheme }, 'id') + + expect(colorScale.scale.range()).toEqual(colorSchemes[scheme]) + expect(colorScale({ id: 'whatever' })).toBe(colorSchemes[scheme][0]) + }) +}) + +divergingColorSchemeIds.forEach(scheme => { + it(`should be able to generate a scale from diverging colors (${scheme})`, () => { + const colorScale = getOrdinalColorScale({ scheme }, 'id') + + expect(colorScale.scale.range()).toEqual(colorSchemes[scheme][11]) + expect(colorScale({ id: 'whatever' })).toBe(colorSchemes[scheme][11][0]) + }) +}) +divergingColorSchemeIds.forEach(scheme => { + it(`should be able to generate a scale from diverging colors with a specific size (${scheme})`, () => { + const colorScale = getOrdinalColorScale({ scheme, size: 5 }) + + expect(colorScale.scale.range()).toEqual(colorSchemes[scheme][5]) + expect(colorScale('whatever')).toBe(colorSchemes[scheme][5][0]) + }) +}) +it(`should throw if trying to generate a scale from diverging colors with a size lower than 3`, () => { + expect(() => { + getOrdinalColorScale({ scheme: divergingColorSchemeIds[0], size: 2 }) + }).toThrow( + `Invalid size '2' for diverging color scheme '${ + divergingColorSchemeIds[0] + }', must be between 3~11` + ) +}) +it(`should throw if trying to generate a scale from diverging colors with a size greater than 11`, () => { + expect(() => { + getOrdinalColorScale({ scheme: divergingColorSchemeIds[0], size: 13 }) + }).toThrow( + `Invalid size '13' for diverging color scheme '${ + divergingColorSchemeIds[0] + }', must be between 3~11` + ) +}) + +sequentialColorSchemeIds.forEach(scheme => { + it(`should be able to generate a scale from sequential colors (${scheme})`, () => { + const colorScale = getOrdinalColorScale({ scheme }) + + expect(colorScale.scale.range()).toEqual(colorSchemes[scheme][9]) + expect(colorScale('whatever')).toBe(colorSchemes[scheme][9][0]) + }) +}) +sequentialColorSchemeIds.forEach(scheme => { + it(`should be able to generate a scale from sequential colors with a specific size (${scheme})`, () => { + const colorScale = getOrdinalColorScale({ scheme, size: 5 }) + + expect(colorScale.scale.range()).toEqual(colorSchemes[scheme][5]) + expect(colorScale('whatever')).toBe(colorSchemes[scheme][5][0]) + }) +}) +it(`should throw if trying to generate a scale from sequential colors with a size lower than 3`, () => { + expect(() => { + getOrdinalColorScale({ scheme: sequentialColorSchemeIds[0], size: 2 }) + }).toThrow( + `Invalid size '2' for sequential color scheme '${ + sequentialColorSchemeIds[0] + }', must be between 3~9` + ) +}) +it(`should throw if trying to generate a scale from sequential colors with a size greater than 9`, () => { + expect(() => { + getOrdinalColorScale({ scheme: sequentialColorSchemeIds[0], size: 11 }) + }).toThrow( + `Invalid size '11' for sequential color scheme '${ + sequentialColorSchemeIds[0] + }', must be between 3~9` + ) +}) + +it(`should throw if an object is given but doesn't match datum or scheme`, () => { + expect(() => { + getOrdinalColorScale({}) + }).toThrow( + `Invalid colors, when using an object, you should either pass a 'datum' or a 'scheme' property` + ) +}) diff --git a/packages/core/package.json b/packages/core/package.json index 5acd961c6..1fe32293b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -15,15 +15,15 @@ "dist/" ], "dependencies": { - "d3-color": "^1.0.3", + "d3-color": "^1.2.3", "d3-format": "^1.3.2", "d3-hierarchy": "^1.1.8", "d3-interpolate": "^1.3.2", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-scale-chromatic": "^1.3.3", "d3-shape": "^1.3.5", "d3-time-format": "^2.1.3", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-measure": "^2.2.4", "react-motion": "^0.5.2", "recompose": "^0.30.0" diff --git a/packages/core/src/components/Container.js b/packages/core/src/components/Container.js index 1c2d911b6..bc23c18d0 100644 --- a/packages/core/src/components/Container.js +++ b/packages/core/src/components/Container.js @@ -100,7 +100,7 @@ const Container = ({ children, theme, isInteractive = true }) => { Container.propTypes = { children: PropTypes.func.isRequired, - isInteractive: PropTypes.bool.isRequired, + isInteractive: PropTypes.bool, theme: PropTypes.object.isRequired, } diff --git a/packages/core/src/hocs/index.js b/packages/core/src/hocs/index.js index 84c608ed6..9aaa503d6 100644 --- a/packages/core/src/hocs/index.js +++ b/packages/core/src/hocs/index.js @@ -6,7 +6,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -export { default as withColors } from './withColors' export { default as withCurve } from './withCurve' export { default as withDimensions } from './withDimensions' export { default as withHierarchy } from './withHierarchy' diff --git a/packages/core/src/hocs/withColors.js b/packages/core/src/hocs/withColors.js deleted file mode 100644 index a3900dde3..000000000 --- a/packages/core/src/hocs/withColors.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import PropTypes from 'prop-types' -import compose from 'recompose/compose' -import setPropTypes from 'recompose/setPropTypes' -import defaultProps from 'recompose/defaultProps' -import withPropsOnChange from 'recompose/withPropsOnChange' -import { getColorsGenerator } from '../lib/colors' - -/** - * This HOC watch colors related props change - * and returns the corresponding color generator function. - * Using it prevent from having a new ref each time - * we pass through the component, useful for shallow comparison. - */ -export default ({ - colorsKey = 'colors', - colorByKey = 'colorBy', - destKey = 'getColor', - defaultColors = 'nivo', - defaultColorBy = 'id', -} = {}) => - compose( - defaultProps({ - [colorsKey]: defaultColors, - [colorByKey]: defaultColorBy, - }), - setPropTypes({ - [colorsKey]: PropTypes.any.isRequired, - [colorByKey]: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), - }), - withPropsOnChange([colorsKey, colorByKey], props => ({ - [destKey]: getColorsGenerator(props[colorsKey], props[colorByKey]), - })) - ) diff --git a/packages/core/src/lib/colors/index.js b/packages/core/src/lib/colors/index.js index 9fc98e384..5850f7833 100644 --- a/packages/core/src/lib/colors/index.js +++ b/packages/core/src/lib/colors/index.js @@ -6,9 +6,7 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import get from 'lodash/get' import last from 'lodash/last' -import isFunction from 'lodash/isFunction' import isArray from 'lodash/isArray' import isString from 'lodash/isString' import { scaleOrdinal, scaleSequential } from 'd3-scale' @@ -93,7 +91,7 @@ import { } from 'd3-scale-chromatic' // used for ordinal color scales -export const colorSchemes = { +const colorSchemes = { nivo: ['#e8c1a0', '#f47560', '#f1e15b', '#e8a838', '#61cdbb', '#97e3d5'], // categorical category10: schemeCategory10, @@ -268,37 +266,9 @@ export const colorInterpolatorIds = [ 'sinebow', ] -const ordinalColorScales = { - category10: scaleOrdinal(schemeCategory10), - accent: scaleOrdinal(schemeAccent), - dark2: scaleOrdinal(schemeDark2), - paired: scaleOrdinal(schemePaired), - pastel1: scaleOrdinal(schemePastel1), - pastel2: scaleOrdinal(schemePastel2), - set1: scaleOrdinal(schemeSet1), - set2: scaleOrdinal(schemeSet2), - set3: scaleOrdinal(schemeSet3), -} - export const nivoCategoricalColors = () => scaleOrdinal(['#e8c1a0', '#f47560', '#f1e15b', '#e8a838', '#61cdbb', '#97e3d5']) -const dataColor = d => d.color || d.data.color - -export const getColorRange = instruction => { - if (instruction === 'data') return dataColor - - if (instruction === 'nivo') return nivoCategoricalColors() - - if (isFunction(instruction)) return instruction - - if (ordinalColorScales[instruction]) return ordinalColorScales[instruction] - - if (isArray(instruction)) return scaleOrdinal(instruction) - - return () => instruction -} - export const getColorScale = (colors, dataScale) => { if (isString(colors)) { const scheme = colorSchemes[colors] @@ -332,32 +302,5 @@ export const getColorScale = (colors, dataScale) => { return () => colors } -export const getColorsGenerator = (colors, colorBy) => { - // skip range, color should be bound to data - if (isFunction(colorBy)) return colorBy - - let scale - let getColorId = d => get(d, colorBy) - - if (isString(colors) && colorSchemes[colors] !== undefined) { - scale = scaleOrdinal(colorSchemes[colors]) - scale.type = 'ordinal' - } else if (isArray(colors)) { - // user defined color range - scale = scaleOrdinal(colors) - scale.type = 'ordinal' - } else { - // just use provided value, - // all elements will have identical color - return () => colors - } - - const colorGenerator = d => scale(getColorId(d)) - colorGenerator.type = scale.type - - return colorGenerator -} - export * from './inherit' -export * from './motion' export * from './quantize' diff --git a/packages/core/src/lib/colors/motion.js b/packages/core/src/lib/colors/motion.js deleted file mode 100644 index 5f9986919..000000000 --- a/packages/core/src/lib/colors/motion.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { spring } from 'react-motion' -import { rgb } from 'd3-color' - -/** - * Decompose a color for use with react-motion. - * - * @param {string} _color - * @param {Object} [_config] - * @return {Object} - */ -export const colorMotionSpring = (_color, _config) => { - const color = rgb(_color) - - if (!_config) - return { - colorR: color.r, - colorG: color.g, - colorB: color.b, - } - - const config = Object.assign({}, _config, { precision: 1 }) - - return { - colorR: spring(color.r, config), - colorG: spring(color.g, config), - colorB: spring(color.b, config), - } -} - -/** - * Re-assemble interpolated color components for easy use. - * - * @param {number} colorR - * @param {number} colorG - * @param {number} colorB - * @return {string} - */ -export const getInterpolatedColor = ({ colorR, colorG, colorB }) => - `rgb(${Math.round(Math.max(colorR, 0))},${Math.round(Math.max(colorG, 0))},${Math.round( - Math.max(colorB, 0) - )})` diff --git a/packages/core/tests/lib/colors/colors.test.js b/packages/core/tests/lib/colors/colors.test.js index 226e2f396..29aba8e2c 100644 --- a/packages/core/tests/lib/colors/colors.test.js +++ b/packages/core/tests/lib/colors/colors.test.js @@ -7,7 +7,7 @@ * file that was distributed with this source code. */ import { rgb } from 'd3-color' -import { getInheritedColorGenerator, getColorsGenerator } from '../../../src/lib/colors' +import { getInheritedColorGenerator } from '../../../src/lib/colors' describe('getInheritedColorGenerator()', () => { it(`should return 'none' if 'none' provided`, () => { @@ -78,31 +78,3 @@ describe('getInheritedColorGenerator()', () => { expect(colorGenerator()).toBe(color) }) }) - -describe('getColorsGenerator()', () => { - it(`should just use value returned by 'colorBy' if it's a function`, () => { - expect(getColorsGenerator('nivo', d => d.color)({ color: 'whatever' })).toBe('whatever') - }) - - it(`should allow to pick specific property from datum`, () => { - expect(getColorsGenerator('nivo', 'custom')({ custom: 'custom' })).toBe('#e8c1a0') - }) - - it(`should allow to use an array of colors`, () => { - const generator = getColorsGenerator(['#F00', '#0F0'], 'id') - expect(generator({ id: 'first' })).toBe('#F00') - expect(generator({ id: 'second' })).toBe('#0F0') - }) - - it(`should allow to use a predefined color range`, () => { - const generator = getColorsGenerator('pastel1', 'id') - expect(generator({ id: 'first' })).toBe('#fbb4ae') - expect(generator({ id: 'second' })).toBe('#b3cde3') - }) - - it(`should return given 'colors' value otherwise`, () => { - const generator = getColorsGenerator('#F0F') - expect(generator({ id: 'first' })).toBe('#F0F') - expect(generator({ id: 'second' })).toBe('#F0F') - }) -}) diff --git a/packages/generators/package.json b/packages/generators/package.json index 4173e0250..7b29f6d2b 100644 --- a/packages/generators/package.json +++ b/packages/generators/package.json @@ -26,7 +26,7 @@ "dependencies": { "d3-time": "^1.0.10", "d3-time-format": "^2.1.3", - "lodash": "^4.17.4" + "lodash": "^4.17.11" }, "publishConfig": { "access": "public" diff --git a/packages/geo/package.json b/packages/geo/package.json index 5f75948e4..d7ee8fb54 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -28,7 +28,7 @@ "@nivo/legends": "0.55.0", "d3-format": "^1.3.2", "d3-geo": "^1.11.3", - "lodash": "^4.17.4" + "lodash": "^4.17.11" }, "peerDependencies": { "prop-types": ">= 15.5.10 < 16.0.0", diff --git a/packages/heatmap/package.json b/packages/heatmap/package.json index 89c4a37f6..003c0a387 100644 --- a/packages/heatmap/package.json +++ b/packages/heatmap/package.json @@ -24,9 +24,10 @@ ], "dependencies": { "@nivo/axes": "0.55.0", + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", - "d3-scale": "^2.1.2", - "lodash": "^4.17.4", + "d3-scale": "^3.0.0", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/heatmap/src/HeatMap.js b/packages/heatmap/src/HeatMap.js index 60c240ade..748ead5fb 100644 --- a/packages/heatmap/src/HeatMap.js +++ b/packages/heatmap/src/HeatMap.js @@ -9,7 +9,8 @@ import React, { Component } from 'react' import partial from 'lodash/partial' import { TransitionMotion } from 'react-motion' -import { colorMotionSpring, getInterpolatedColor, Container, SvgWrapper, Grid } from '@nivo/core' +import { Container, SvgWrapper, Grid } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import { Axes } from '@nivo/axes' import setDisplayName from 'recompose/setDisplayName' import { HeatMapPropTypes } from './props' @@ -54,12 +55,10 @@ class HeatMap extends Component { outerWidth, outerHeight, - // cells cellShape, cellBorderWidth, getCellBorderColor, - // axes & grid axisTop, axisRight, axisBottom, @@ -67,20 +66,16 @@ class HeatMap extends Component { enableGridX, enableGridY, - // labels enableLabels, getLabelTextColor, - // theming theme, - // motion animate, motionStiffness, motionDamping, boundSpring, - // interactivity isInteractive, onClick, } = this.props @@ -173,7 +168,7 @@ class HeatMap extends Component { width: boundSpring(node.width), height: boundSpring(node.height), opacity: boundSpring(node.opacity), - ...colorMotionSpring(node.color, { + ...interpolateColor(node.color, { damping: motionDamping, stiffness: motionStiffness, }), diff --git a/packages/legends/package.json b/packages/legends/package.json index af180fac1..e159c2bb3 100644 --- a/packages/legends/package.json +++ b/packages/legends/package.json @@ -18,7 +18,7 @@ ], "dependencies": { "@nivo/core": "0.55.0", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "recompose": "^0.30.0" }, "peerDependencies": { diff --git a/packages/line/index.d.ts b/packages/line/index.d.ts index c551e9d59..0e8ddad10 100644 --- a/packages/line/index.d.ts +++ b/packages/line/index.d.ts @@ -1,5 +1,6 @@ import * as React from 'react' import { Dimensions, Box, Theme, MotionProps, ColorProps, CartesianMarkerProps } from '@nivo/core' +import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' import { Scale, ScaleFunc } from '@nivo/scales' import { AxisProps } from '@nivo/axes' @@ -93,6 +94,7 @@ declare module '@nivo/line' { | 'stepAfter' lineWidth?: number + colors?: OrdinalColorsInstruction theme?: Theme axisTop?: AxisProps | null diff --git a/packages/line/package.json b/packages/line/package.json index fe381bd5c..d5265bb88 100644 --- a/packages/line/package.json +++ b/packages/line/package.json @@ -24,13 +24,14 @@ ], "dependencies": { "@nivo/axes": "0.55.0", + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "@nivo/scales": "0.55.0", "d3-format": "^1.3.2", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/line/src/Line.js b/packages/line/src/Line.js index 2912b65c3..5246de26d 100644 --- a/packages/line/src/Line.js +++ b/packages/line/src/Line.js @@ -16,7 +16,6 @@ import { curveFromProp, getInheritedColorGenerator, withTheme, - withColors, withDimensions, withMotion, Container, @@ -24,6 +23,7 @@ import { CartesianMarkers, Grid, } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { Axes } from '@nivo/axes' import { computeXYScalesForSeries, computeYSlices } from '@nivo/scales' import { BoxLegendSvg } from '@nivo/legends' @@ -250,9 +250,11 @@ Line.propTypes = LinePropTypes const enhance = compose( defaultProps(LineDefaultProps), withTheme(), - withColors(), withDimensions(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + })), withPropsOnChange(['curve'], ({ curve }) => ({ lineGenerator: line() .defined(d => d.x !== null && d.y !== null) diff --git a/packages/line/src/props.js b/packages/line/src/props.js index b4de2c10f..46b726f35 100644 --- a/packages/line/src/props.js +++ b/packages/line/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { lineCurvePropType, blendModePropType } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' import { scalePropType } from '@nivo/scales' import { LegendPropShape } from '@nivo/legends' @@ -93,6 +94,7 @@ export const LinePropTypes = { }) ), + colors: ordinalColorsPropType.isRequired, getColor: PropTypes.func.isRequired, enableArea: PropTypes.bool.isRequired, areaOpacity: PropTypes.number.isRequired, @@ -142,8 +144,7 @@ export const LineDefaultProps = { dotBorderColor: 'inherit', enableDotLabel: false, - colors: 'nivo', - colorBy: 'id', + colors: { scheme: 'nivo' }, enableArea: false, areaBaselineValue: 0, areaOpacity: 0.2, diff --git a/packages/line/stories/line.stories.js b/packages/line/stories/line.stories.js index 7037a6f5a..d456f7a3c 100644 --- a/packages/line/stories/line.stories.js +++ b/packages/line/stories/line.stories.js @@ -384,7 +384,7 @@ stories.add('using data colors', () => ( stacked: boolean('stacked', true), }} curve={select('curve', curveOptions, 'linear')} - colorBy={d => d.color} + colors={{ datum: 'color' }} enableDotLabel={true} dotSize={10} dotBorderColor="#fff" diff --git a/packages/parallel-coordinates/package.json b/packages/parallel-coordinates/package.json index e6548d1cb..4df85f4cd 100644 --- a/packages/parallel-coordinates/package.json +++ b/packages/parallel-coordinates/package.json @@ -24,8 +24,9 @@ ], "dependencies": { "@nivo/axes": "0.55.0", + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-shape": "^1.3.5", "react-motion": "^0.5.2", "recompose": "^0.30.0" diff --git a/packages/parallel-coordinates/src/enhance.js b/packages/parallel-coordinates/src/enhance.js index a5e0c521a..4dd05d16d 100644 --- a/packages/parallel-coordinates/src/enhance.js +++ b/packages/parallel-coordinates/src/enhance.js @@ -6,19 +6,17 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import { withDimensions, withTheme, withColors, curveFromProp } from '@nivo/core' -import * as props from './props' -import withPropsOnChange from 'recompose/withPropsOnChange' import { line } from 'd3-shape' +import { withDimensions, withTheme, curveFromProp } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' +import withPropsOnChange from 'recompose/withPropsOnChange' export const commonEnhancers = [ withDimensions(), - withColors({ - defaultColors: props.commonDefaultProps.colors, - defaultColorBy: props.commonDefaultProps.colorBy, - destKey: 'getLineColor', - }), withTheme(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getLineColor: getOrdinalColorScale(colors, 'index'), + })), withPropsOnChange(['curve'], ({ curve }) => ({ lineGenerator: line() .x(d => d.x) diff --git a/packages/parallel-coordinates/src/props.js b/packages/parallel-coordinates/src/props.js index 90915d635..0477b5de6 100644 --- a/packages/parallel-coordinates/src/props.js +++ b/packages/parallel-coordinates/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { themePropType, lineCurvePropType } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' const commonVariablePropTypes = { key: PropTypes.string.isRequired, @@ -56,14 +57,14 @@ export const commonPropTypes = { lineOpacity: PropTypes.number.isRequired, axesPlan: PropTypes.oneOf(['foreground', 'background']).isRequired, axesTicksPosition: PropTypes.oneOf(['before', 'after']).isRequired, + colors: ordinalColorsPropType.isRequired, theme: themePropType.isRequired, } export const commonDefaultProps = { layout: 'horizontal', curve: 'linear', - colors: 'yellow_orange_red', - colorBy: 'index', + colors: { scheme: 'yellow_orange_red' }, strokeWidth: 2, lineOpacity: 0.35, axesPlan: 'foreground', diff --git a/packages/pie/index.d.ts b/packages/pie/index.d.ts index e188ce9e3..2e58b637e 100644 --- a/packages/pie/index.d.ts +++ b/packages/pie/index.d.ts @@ -8,6 +8,7 @@ import { GetColor, SvgDefsAndFill, } from '@nivo/core' +import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' declare module '@nivo/pie' { @@ -30,7 +31,6 @@ declare module '@nivo/pie' { } export type CommonPieProps = MotionProps & - ColorProps & Partial<{ margin: Box sortByValue: boolean @@ -43,6 +43,7 @@ declare module '@nivo/pie' { // border // styling + colors: OrdinalColorsInstruction theme: Theme borderWidth: number borderColor: string | GetColor diff --git a/packages/pie/package.json b/packages/pie/package.json index fc179070e..df9b92494 100644 --- a/packages/pie/package.json +++ b/packages/pie/package.json @@ -23,10 +23,11 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/pie/src/PieLayout.js b/packages/pie/src/PieLayout.js index 82e69d573..abc563651 100644 --- a/packages/pie/src/PieLayout.js +++ b/packages/pie/src/PieLayout.js @@ -14,7 +14,8 @@ import compose from 'recompose/compose' import pure from 'recompose/pure' import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' -import { withColors, degreesToRadians, radiansToDegrees, computeArcBoundingBox } from '@nivo/core' +import { degreesToRadians, radiansToDegrees, computeArcBoundingBox } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' class PieLayout extends Component { static propTypes = { @@ -96,7 +97,9 @@ export const PieLayoutDefaultProps = { export const enhance = Component => compose( defaultProps(PieLayoutDefaultProps), - withColors(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + })), withPropsOnChange( ['width', 'height', 'innerRadius', 'startAngle', 'endAngle', 'fit', 'cornerRadius'], ({ diff --git a/packages/pie/src/props.js b/packages/pie/src/props.js index b83ee4d65..f26f64522 100644 --- a/packages/pie/src/props.js +++ b/packages/pie/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { noop, radiansToDegrees } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape } from '@nivo/legends' export const arcPropType = PropTypes.shape({ @@ -62,6 +63,7 @@ export const PiePropTypes = { slicesLabelsTextColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), // styling + colors: ordinalColorsPropType.isRequired, defs: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, @@ -126,6 +128,7 @@ export const PieDefaultProps = { slicesLabelsTextColor: 'theme', // styling + colors: { scheme: 'nivo' }, defs: [], fill: [], diff --git a/packages/pie/tests/PieLayout.test.js b/packages/pie/tests/PieLayout.test.js index c50a15b17..7d3cdcd0c 100644 --- a/packages/pie/tests/PieLayout.test.js +++ b/packages/pie/tests/PieLayout.test.js @@ -11,7 +11,12 @@ it('should compute pie layout properties to pass down to render function', () => } renderer.create( - + {render} ) diff --git a/packages/radar/package.json b/packages/radar/package.json index 407b2e2ab..23febee42 100644 --- a/packages/radar/package.json +++ b/packages/radar/package.json @@ -22,12 +22,13 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "d3-format": "^1.3.2", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/radar/src/Radar.js b/packages/radar/src/Radar.js index 34fde387c..d6f3d3b19 100644 --- a/packages/radar/src/Radar.js +++ b/packages/radar/src/Radar.js @@ -17,7 +17,6 @@ import { scaleLinear } from 'd3-scale' import { closedCurvePropType, withTheme, - withColors, withCurve, withDimensions, withMotion, @@ -25,6 +24,7 @@ import { Container, SvgWrapper, } from '@nivo/core' +import { getOrdinalColorScale, ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape, BoxLegendSvg } from '@nivo/legends' import RadarShapes from './RadarShapes' import RadarGrid from './RadarGrid' @@ -218,8 +218,9 @@ Radar.propTypes = { dotLabelYOffset: PropTypes.number, // theming + colors: ordinalColorsPropType.isRequired, + colorByKey: PropTypes.object.isRequired, getColor: PropTypes.func.isRequired, // computed - colorByKey: PropTypes.object.isRequired, // computed fillOpacity: PropTypes.number.isRequired, // interactivity @@ -234,22 +235,18 @@ export const RadarDefaultProps = { curve: 'linearClosed', - // border borderWidth: 2, borderColor: 'inherit', - // grid gridLevels: 5, gridShape: 'circular', gridLabelOffset: 16, - // dots enableDots: true, - // theming + colors: { scheme: 'nivo' }, fillOpacity: 0.15, - // interactivity isInteractive: true, legends: [], @@ -258,12 +255,12 @@ export const RadarDefaultProps = { const enhance = compose( defaultProps(RadarDefaultProps), withTheme(), - withColors({ - defaultColorBy: 'key', - }), withCurve(), withDimensions(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'key'), + })), withPropsOnChange(['indexBy'], ({ indexBy }) => ({ getIndex: getAccessorFor(indexBy), })), diff --git a/packages/sankey/index.d.ts b/packages/sankey/index.d.ts index aae2152d6..6109df9f2 100644 --- a/packages/sankey/index.d.ts +++ b/packages/sankey/index.d.ts @@ -1,5 +1,6 @@ import * as React from 'react' import { Theme } from '@nivo/core' +import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' declare module '@nivo/sankey' { @@ -76,6 +77,7 @@ declare module '@nivo/sankey' { nodeTooltip: any linkTooltip: any + colors: OrdinalColorsInstruction theme: Theme legends: LegendProps[] diff --git a/packages/sankey/package.json b/packages/sankey/package.json index e837920b5..ffff9ba21 100644 --- a/packages/sankey/package.json +++ b/packages/sankey/package.json @@ -23,11 +23,12 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "d3-sankey": "^0.12.1", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/sankey/src/SankeyLabels.js b/packages/sankey/src/SankeyLabels.js index eef9359e0..c2206ff6e 100644 --- a/packages/sankey/src/SankeyLabels.js +++ b/packages/sankey/src/SankeyLabels.js @@ -10,7 +10,8 @@ import React, { Fragment } from 'react' import PropTypes from 'prop-types' import pure from 'recompose/pure' import { TransitionMotion, spring } from 'react-motion' -import { colorMotionSpring, getInterpolatedColor, motionPropTypes } from '@nivo/core' +import { motionPropTypes } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' const SankeyLabels = ({ nodes, @@ -119,7 +120,7 @@ const SankeyLabels = ({ x: spring(label.x, springProps), y: spring(label.y, springProps), rotation: spring(labelRotation, springProps), - ...colorMotionSpring(label.color, springProps), + ...interpolateColor(label.color, springProps), }, } })} diff --git a/packages/sankey/src/SankeyNodes.js b/packages/sankey/src/SankeyNodes.js index 6928be879..773fe354b 100644 --- a/packages/sankey/src/SankeyNodes.js +++ b/packages/sankey/src/SankeyNodes.js @@ -10,7 +10,8 @@ import React, { Fragment } from 'react' import PropTypes from 'prop-types' import pure from 'recompose/pure' import { TransitionMotion, spring } from 'react-motion' -import { colorMotionSpring, getInterpolatedColor, motionPropTypes } from '@nivo/core' +import { motionPropTypes } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import SankeyNodesItem from './SankeyNodesItem' const SankeyNodes = ({ @@ -89,7 +90,7 @@ const SankeyNodes = ({ width: spring(node.width, springProps), height: spring(node.height, springProps), opacity: spring(getOpacity(node), springProps), - ...colorMotionSpring(node.color, springProps), + ...interpolateColor(node.color, springProps), }, } })} diff --git a/packages/sankey/src/enhance.js b/packages/sankey/src/enhance.js index ed4129e87..d3cee5340 100644 --- a/packages/sankey/src/enhance.js +++ b/packages/sankey/src/enhance.js @@ -12,11 +12,11 @@ import { sankey as d3Sankey } from 'd3-sankey' import { getLabelGenerator, getInheritedColorGenerator, - withColors, withTheme, withDimensions, withMotion, } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { SankeyDefaultProps, sankeyAlignmentFromProp } from './props' const getId = d => d.id @@ -26,15 +26,13 @@ export default Component => defaultProps(SankeyDefaultProps), withState('currentNode', 'setCurrentNode', null), withState('currentLink', 'setCurrentLink', null), - withColors(), - withColors({ - colorByKey: 'linkColorBy', - destKey: 'getLinkColor', - defaultColorBy: 'source.id', - }), withTheme(), withDimensions(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + getLinkColor: getOrdinalColorScale(colors, 'source.id'), + })), withPropsOnChange(['nodeBorderColor'], ({ nodeBorderColor }) => ({ getNodeBorderColor: getInheritedColorGenerator(nodeBorderColor), })), diff --git a/packages/sankey/src/props.js b/packages/sankey/src/props.js index 67fb50c3a..d09e34c88 100644 --- a/packages/sankey/src/props.js +++ b/packages/sankey/src/props.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types' import { sankeyCenter, sankeyJustify, sankeyLeft, sankeyRight } from 'd3-sankey' import { noop, blendModePropType } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape } from '@nivo/legends' export const sankeyAlignmentPropMapping = { @@ -46,6 +47,8 @@ export const SankeyPropTypes = { PropTypes.func, ]).isRequired, + colors: ordinalColorsPropType.isRequired, + nodeOpacity: PropTypes.number.isRequired, nodeHoverOpacity: PropTypes.number.isRequired, nodeHoverOthersOpacity: PropTypes.number.isRequired, @@ -87,6 +90,8 @@ export const SankeyDefaultProps = { align: 'center', sort: 'auto', + colors: { scheme: 'nivo' }, + nodeOpacity: 0.75, nodeHoverOpacity: 1, nodeHoverOthersOpacity: 0.15, diff --git a/packages/sankey/stories/sankey.stories.js b/packages/sankey/stories/sankey.stories.js index 203b1e767..504faad40 100644 --- a/packages/sankey/stories/sankey.stories.js +++ b/packages/sankey/stories/sankey.stories.js @@ -9,7 +9,7 @@ const commonProperties = { height: 400, margin: { top: 0, right: 80, bottom: 0, left: 80 }, data: sankeyData, - colors: 'category10', + colors: { scheme: 'category10' }, } const stories = storiesOf('Sankey', module) diff --git a/packages/scales/package.json b/packages/scales/package.json index 6c3c7d445..0c41f25b2 100644 --- a/packages/scales/package.json +++ b/packages/scales/package.json @@ -15,9 +15,9 @@ "dist/" ], "dependencies": { - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-time-format": "^2.1.3", - "lodash": "^4.17.4" + "lodash": "^4.17.11" }, "peerDependencies": { "prop-types": ">= 15.5.10 < 16.0.0" diff --git a/packages/scales/src/compute.js b/packages/scales/src/compute.js index db6665882..fe1e2b84e 100644 --- a/packages/scales/src/compute.js +++ b/packages/scales/src/compute.js @@ -86,18 +86,28 @@ export const generateSeriesXY = (series, xScaleSpec, yScaleSpec) => ({ * Normalize data according to scale type, (time => Date, linear => Number) * compute sorted unique values and min/max. */ -export const generateSeriesAxis = (series, axis, scaleSpec) => { +export const generateSeriesAxis = ( + series, + axis, + scaleSpec, + { + getValue = d => d.data[axis], + setValue = (d, v) => { + d.data[axis] = v + }, + } = {} +) => { if (scaleSpec.type === 'linear') { series.forEach(serie => { serie.data.forEach(d => { - d.data[axis] = d.data[axis] === null ? null : parseFloat(d.data[axis]) + setValue(d, getValue(d) === null ? null : parseFloat(getValue(d))) }) }) } else if (scaleSpec.type === 'time' && scaleSpec.format !== 'native') { const parseTime = createDateNormalizer(scaleSpec) series.forEach(serie => { serie.data.forEach(d => { - d.data[axis] = d.data[axis] === null ? null : parseTime(d.data[axis]) + setValue(d, getValue(d) === null ? null : parseTime(getValue(d))) }) }) } @@ -105,7 +115,7 @@ export const generateSeriesAxis = (series, axis, scaleSpec) => { let all = [] series.forEach(serie => { serie.data.forEach(d => { - all.push(d.data[axis]) + all.push(getValue(d)) }) }) diff --git a/packages/scatterplot/index.d.ts b/packages/scatterplot/index.d.ts index 75a228e99..218287526 100644 --- a/packages/scatterplot/index.d.ts +++ b/packages/scatterplot/index.d.ts @@ -1,5 +1,6 @@ import * as React from 'react' import { Dimensions, Box, Theme, MotionProps, CartesianMarkerProps } from '@nivo/core' +import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' import { AxisProps } from '@nivo/axes' import { Scale } from '@nivo/scales' @@ -34,6 +35,7 @@ declare module '@nivo/scatterplot' { xScale?: Scale yScale?: Scale + colors?: OrdinalColorsInstruction theme?: Theme margin?: Box diff --git a/packages/scatterplot/package.json b/packages/scatterplot/package.json index c7d5f7208..8fe23b9bb 100644 --- a/packages/scatterplot/package.json +++ b/packages/scatterplot/package.json @@ -24,13 +24,14 @@ ], "dependencies": { "@nivo/axes": "0.55.0", + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "@nivo/scales": "0.55.0", "@nivo/voronoi": "0.55.0", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/scatterplot/src/enhance.js b/packages/scatterplot/src/enhance.js index be5e45611..7578d8d75 100644 --- a/packages/scatterplot/src/enhance.js +++ b/packages/scatterplot/src/enhance.js @@ -11,18 +11,20 @@ import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' import setDisplayName from 'recompose/setDisplayName' -import { withTheme, withColors, withDimensions, withMotion } from '@nivo/core' +import { withTheme, withDimensions, withMotion, getAccessorOrValue } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { computeXYScalesForSeries } from '@nivo/scales' -import { getAccessorOrValue } from '@nivo/core' import { computeMeshPoints, computeMesh } from '@nivo/voronoi' import { ScatterPlotDefaultProps } from './props' const commonEnhancers = [ defaultProps(ScatterPlotDefaultProps), withTheme(), - withColors(), withDimensions(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'serie.id'), + })), withPropsOnChange(['symbolSize'], ({ symbolSize }) => ({ getSymbolSize: getAccessorOrValue(symbolSize), })), diff --git a/packages/scatterplot/src/props.js b/packages/scatterplot/src/props.js index 3903f455f..6bace6c4f 100644 --- a/packages/scatterplot/src/props.js +++ b/packages/scatterplot/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { noop } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' import { LegendPropShape } from '@nivo/legends' import { scalePropType } from '@nivo/scales' @@ -67,6 +68,7 @@ export const ScatterPlotPropTypes = { }) ), + colors: ordinalColorsPropType.isRequired, getColor: PropTypes.func.isRequired, isInteractive: PropTypes.bool.isRequired, @@ -108,8 +110,7 @@ export const ScatterPlotDefaultProps = { symbolSize: 6, symbolShape: 'circle', - colors: 'nivo', - colorBy: 'serie.id', + colors: { scheme: 'nivo' }, isInteractive: true, useMesh: false, diff --git a/packages/scatterplot/stories/ScatterPlot.stories.js b/packages/scatterplot/stories/ScatterPlot.stories.js index 4a9a5680b..6e1ab45ca 100644 --- a/packages/scatterplot/stories/ScatterPlot.stories.js +++ b/packages/scatterplot/stories/ScatterPlot.stories.js @@ -152,7 +152,9 @@ stories.add('default', () => ) -stories.add('alternative colors', () => ) +stories.add('alternative colors', () => ( + +)) stories.add('using time scales', () => ( ) -stories.add('alternative colors', () => ) +stories.add('alternative colors', () => ( + +)) stories.add('using time scales', () => ( { - const enhancedLayers = layers.map((points, i) => { + const enhancedLayers = layers.map((points, layerIndex) => { const layer = points.map((point, i) => ({ index: i, x: xScale(i), @@ -77,10 +77,10 @@ const Stream = ({ })) return { - id: keys[i], + id: keys[layerIndex], layer, path: areaGenerator(layer), - color: getColor(i), + color: getColor({ index: layerIndex }), } }) diff --git a/packages/stream/src/enhance.js b/packages/stream/src/enhance.js index 01252b635..2fa07a912 100644 --- a/packages/stream/src/enhance.js +++ b/packages/stream/src/enhance.js @@ -21,9 +21,9 @@ import { withCurve, withDimensions, withMotion, - getColorRange, getInheritedColorGenerator, } from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import { StreamDefaultProps } from './props' const stackMin = layers => @@ -46,7 +46,7 @@ export default Component => .curve(curveInterpolator), })), withPropsOnChange(['colors'], ({ colors }) => ({ - getColor: getColorRange(colors), + getColor: getOrdinalColorScale(colors, 'index'), })), withPropsOnChange(['borderColor'], ({ borderColor }) => ({ getBorderColor: getInheritedColorGenerator(borderColor), diff --git a/packages/stream/src/props.js b/packages/stream/src/props.js index 794437f55..dbbc6ee68 100644 --- a/packages/stream/src/props.js +++ b/packages/stream/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { areaCurvePropType, stackOrderPropType, stackOffsetPropType } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape } from '@nivo/legends' import StreamDotsItem from './StreamDotsItem' @@ -31,7 +32,7 @@ export const StreamPropTypes = { enableGridX: PropTypes.bool.isRequired, enableGridY: PropTypes.bool.isRequired, - colors: PropTypes.any.isRequired, + colors: ordinalColorsPropType.isRequired, fillOpacity: PropTypes.number.isRequired, getColor: PropTypes.func.isRequired, // computed defs: PropTypes.arrayOf( @@ -82,7 +83,7 @@ export const StreamDefaultProps = { borderWidth: 0, borderColor: 'inherit:darker(1)', - colors: 'nivo', + colors: { scheme: 'nivo' }, fillOpacity: 1, defs: [], fill: [], diff --git a/packages/sunburst/package.json b/packages/sunburst/package.json index b3694c39f..95f39071d 100644 --- a/packages/sunburst/package.json +++ b/packages/sunburst/package.json @@ -22,10 +22,11 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "d3-hierarchy": "^1.1.8", "d3-shape": "^1.3.5", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/sunburst/src/Sunburst.js b/packages/sunburst/src/Sunburst.js index b6251b43e..d587441ce 100644 --- a/packages/sunburst/src/Sunburst.js +++ b/packages/sunburst/src/Sunburst.js @@ -21,11 +21,11 @@ import { getInheritedColorGenerator, withTheme, withDimensions, - withColors, getAccessorFor, Container, SvgWrapper, } from '@nivo/core' +import { getOrdinalColorScale, ordinalColorsPropType } from '@nivo/colors' import SunburstArc from './SunburstArc' const getAncestor = node => { @@ -37,7 +37,6 @@ const getAncestor = node => { const Sunburst = ({ nodes, - // dimensions margin, // eslint-disable-line react/prop-types centerX, centerY, @@ -46,14 +45,11 @@ const Sunburst = ({ arcGenerator, - // border borderWidth, borderColor, - // theming theme, // eslint-disable-line react/prop-types - // interactivity isInteractive, }) => { return ( @@ -99,13 +95,12 @@ Sunburst.propTypes = { centerX: PropTypes.number.isRequired, // computed centerY: PropTypes.number.isRequired, // computed - // border + colors: ordinalColorsPropType.isRequired, borderWidth: PropTypes.number.isRequired, borderColor: PropTypes.string.isRequired, childColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, - // interactivity isInteractive: PropTypes.bool, } @@ -115,13 +110,12 @@ export const SunburstDefaultProps = { cornerRadius: 0, - // border + colors: { scheme: 'nivo' }, borderWidth: 1, borderColor: 'white', childColor: 'inherit', - // interactivity isInteractive: true, } @@ -129,7 +123,9 @@ const enhance = compose( defaultProps(SunburstDefaultProps), withTheme(), withDimensions(), - withColors(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + })), withProps(({ width, height }) => { const radius = Math.min(width, height) / 2 diff --git a/packages/treemap/package.json b/packages/treemap/package.json index cf089068e..1394337ae 100644 --- a/packages/treemap/package.json +++ b/packages/treemap/package.json @@ -22,9 +22,10 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "d3-hierarchy": "^1.1.8", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "react-motion": "^0.5.2", "recompose": "^0.30.0" }, diff --git a/packages/treemap/src/TreeMap.js b/packages/treemap/src/TreeMap.js index 4091fbe53..2b87d567a 100644 --- a/packages/treemap/src/TreeMap.js +++ b/packages/treemap/src/TreeMap.js @@ -8,8 +8,8 @@ */ import React from 'react' import { TransitionMotion, spring } from 'react-motion' -import { colorMotionSpring, getInterpolatedColor } from '@nivo/core' import { Container, SvgWrapper } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import { TreeMapPropTypes } from './props' import enhance from './enhance' import { nodeWillEnter, nodeWillLeave } from './motion' @@ -19,27 +19,22 @@ const TreeMap = ({ nodes, nodeComponent, - // dimensions margin, outerWidth, outerHeight, - // styling theme, borderWidth, getBorderColor, defs, - // labels getLabelTextColor, orientLabel, - // motion animate, motionStiffness, motionDamping, - // interactivity isInteractive, onClick, tooltipFormat, @@ -107,7 +102,7 @@ const TreeMap = ({ y: spring(node.y, springConfig), width: spring(node.width, springConfig), height: spring(node.height, springConfig), - ...colorMotionSpring(node.color, springConfig), + ...interpolateColor(node.color, springConfig), }, }))} > diff --git a/packages/treemap/src/TreeMapHtml.js b/packages/treemap/src/TreeMapHtml.js index cf9bac35c..7c3e7bc79 100644 --- a/packages/treemap/src/TreeMapHtml.js +++ b/packages/treemap/src/TreeMapHtml.js @@ -8,8 +8,8 @@ */ import React from 'react' import { TransitionMotion, spring } from 'react-motion' -import { colorMotionSpring, getInterpolatedColor } from '@nivo/core' import { Container } from '@nivo/core' +import { interpolateColor, getInterpolatedColor } from '@nivo/colors' import { TreeMapHtmlPropTypes } from './props' import enhance from './enhance' import { getNodeHandlers } from './interactivity' @@ -104,7 +104,7 @@ const TreeMapHtml = ({ y: spring(node.y, springConfig), width: spring(node.width, springConfig), height: spring(node.height, springConfig), - ...colorMotionSpring(node.color, springConfig), + ...interpolateColor(node.color, springConfig), }, }))} > diff --git a/packages/treemap/src/enhance.js b/packages/treemap/src/enhance.js index 95b59e304..1eeb5c6ab 100644 --- a/packages/treemap/src/enhance.js +++ b/packages/treemap/src/enhance.js @@ -12,11 +12,18 @@ import compose from 'recompose/compose' import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' -import { withHierarchy, withDimensions, withTheme, withMotion, withColors } from '@nivo/core' -import { getAccessorFor, getLabelGenerator } from '@nivo/core' -import { treeMapTileFromProp } from '@nivo/core' -import { getInheritedColorGenerator } from '@nivo/core' -import { bindDefs } from '@nivo/core' +import { + withHierarchy, + withDimensions, + withTheme, + withMotion, + getAccessorFor, + getLabelGenerator, + treeMapTileFromProp, + getInheritedColorGenerator, + bindDefs, +} from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import * as props from './props' const computeNodePath = (node, getIdentity) => @@ -28,9 +35,11 @@ const computeNodePath = (node, getIdentity) => const commonEnhancers = [ withHierarchy(), withDimensions(), - withColors({ defaultColorBy: 'depth' }), withTheme(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'depth'), + })), withPropsOnChange(['identity'], ({ identity }) => ({ getIdentity: getAccessorFor(identity), })), diff --git a/packages/treemap/src/motion.js b/packages/treemap/src/motion.js index b3647f6cd..b032e58c7 100644 --- a/packages/treemap/src/motion.js +++ b/packages/treemap/src/motion.js @@ -7,14 +7,14 @@ * file that was distributed with this source code. */ import { spring } from 'react-motion' -import { colorMotionSpring } from '@nivo/core' +import { interpolateColor } from '@nivo/colors' export const nodeWillEnter = ({ data: node }) => ({ x: node.x, y: node.y, width: node.width, height: node.height, - ...colorMotionSpring(node.color), + ...interpolateColor(node.color), }) export const nodeWillLeave = springConfig => ({ data: node }) => ({ @@ -22,5 +22,5 @@ export const nodeWillLeave = springConfig => ({ data: node }) => ({ y: spring(node.y + node.height / 2, springConfig), width: spring(0, springConfig), height: spring(0, springConfig), - ...colorMotionSpring(node.color, springConfig), + ...interpolateColor(node.color, springConfig), }) diff --git a/packages/treemap/src/props.js b/packages/treemap/src/props.js index da2b1fffc..d611af560 100644 --- a/packages/treemap/src/props.js +++ b/packages/treemap/src/props.js @@ -7,8 +7,8 @@ * file that was distributed with this source code. */ import PropTypes from 'prop-types' -import { noop } from '@nivo/core' -import { treeMapTilePropType, defsPropTypes } from '@nivo/core' +import { noop, treeMapTilePropType, defsPropTypes } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import TreeMapNode from './TreeMapNode' import TreeMapHtmlNode from './TreeMapHtmlNode' @@ -27,7 +27,7 @@ const commonPropTypes = { // styling // theme managed by `withTheme()` HOC - // colors managed by `withColors()` HOC + colors: ordinalColorsPropType.isRequired, leavesOnly: PropTypes.bool.isRequired, tile: treeMapTilePropType.isRequired, @@ -74,13 +74,13 @@ export const TreeMapCanvasPropTypes = { —————————————————————————————————————————————————————————————————————————————*/ const commonDefaultProps = { - // data identity: 'id', tile: 'squarify', leavesOnly: false, - // labels + colors: { scheme: 'nivo' }, + enableLabel: true, label: 'id', labelSkipSize: 0, @@ -93,7 +93,6 @@ const commonDefaultProps = { borderWidth: 0, borderColor: 'inherit', - // interactivity isInteractive: true, onClick: noop, } diff --git a/packages/voronoi/package.json b/packages/voronoi/package.json index 34a127bb5..9a1e85a3a 100644 --- a/packages/voronoi/package.json +++ b/packages/voronoi/package.json @@ -26,7 +26,7 @@ "dependencies": { "@nivo/core": "0.55.0", "d3-delaunay": "^4.1.5", - "d3-scale": "^2.1.2", + "d3-scale": "^3.0.0", "recompose": "^0.30.0" }, "peerDependencies": { diff --git a/packages/waffle/package.json b/packages/waffle/package.json index 04b1fc152..fd5a996f4 100644 --- a/packages/waffle/package.json +++ b/packages/waffle/package.json @@ -23,6 +23,7 @@ "dist/" ], "dependencies": { + "@nivo/colors": "0.55.0", "@nivo/core": "0.55.0", "@nivo/legends": "0.55.0", "lodash.partial": "^4.2.1", diff --git a/packages/waffle/src/enhance.js b/packages/waffle/src/enhance.js index f65475700..f3a4d7898 100644 --- a/packages/waffle/src/enhance.js +++ b/packages/waffle/src/enhance.js @@ -11,17 +11,24 @@ import defaultProps from 'recompose/defaultProps' import withPropsOnChange from 'recompose/withPropsOnChange' import withState from 'recompose/withState' import pure from 'recompose/pure' -import { withDimensions, withTheme, withMotion, withColors } from '@nivo/core' -import { getInheritedColorGenerator } from '@nivo/core' -import { bindDefs } from '@nivo/core' +import { + withDimensions, + withTheme, + withMotion, + getInheritedColorGenerator, + bindDefs, +} from '@nivo/core' +import { getOrdinalColorScale } from '@nivo/colors' import * as props from './props' import { computeGrid } from './compute' const commonEnhancers = [ withDimensions(), - withColors({ defaultColorBy: 'id' }), withTheme(), withMotion(), + withPropsOnChange(['colors'], ({ colors }) => ({ + getColor: getOrdinalColorScale(colors, 'id'), + })), withPropsOnChange(['borderColor'], ({ borderColor }) => ({ getBorderColor: getInheritedColorGenerator(borderColor), })), diff --git a/packages/waffle/src/props.js b/packages/waffle/src/props.js index 163588dd5..20ae96d1a 100644 --- a/packages/waffle/src/props.js +++ b/packages/waffle/src/props.js @@ -8,6 +8,7 @@ */ import PropTypes from 'prop-types' import { defsPropTypes, noop } from '@nivo/core' +import { ordinalColorsPropType } from '@nivo/colors' import { LegendPropShape } from '@nivo/legends' import WaffleCell from './WaffleCell' import WaffleCellHtml from './WaffleCellHtml' @@ -32,6 +33,7 @@ const commonPropTypes = { padding: PropTypes.number.isRequired, // styling + colors: ordinalColorsPropType.isRequired, emptyColor: PropTypes.string.isRequired, emptyOpacity: PropTypes.number.isRequired, borderWidth: PropTypes.number.isRequired, @@ -78,11 +80,11 @@ const commonDefaultProps = { padding: 1, // styling + colors: { scheme: 'nivo' }, emptyColor: '#cccccc', emptyOpacity: 1, borderWidth: 0, borderColor: 'inherit:darker(1)', - colors: 'nivo', defs: [], fill: [], diff --git a/packages/waffle/stories/waffle-canvas.stories.js b/packages/waffle/stories/waffle-canvas.stories.js index 84311f72c..a30578a49 100644 --- a/packages/waffle/stories/waffle-canvas.stories.js +++ b/packages/waffle/stories/waffle-canvas.stories.js @@ -31,9 +31,11 @@ const stories = storiesOf('WaffleCanvas', module) stories.add('default', () => ) -stories.add('colors', () => ) +stories.add('colors', () => ) -stories.add('using data color', () => d.color} />) +stories.add('using data color', () => ( + +)) stories.add('fill direction', () => ( ) -stories.add('colors', () => ) +stories.add('colors', () => ) -stories.add('using data color', () => d.color} />) +stories.add('using data color', () => ) stories.add('fill direction', () => ( ) -stories.add('colors', () => ) +stories.add('colors', () => ) -stories.add('using data color', () => d.color} />) +stories.add('using data color', () => ) stories.add('patterns', () => ( { @@ -197,6 +198,16 @@ const ControlChoser = memo(({ groupName, property, settings, onChange }) => { /> ) + case 'ordinalColors': + return ( + + ) + case 'color': return ( theme.fontFamilyMono}; + margin: 10px 0 5px; + font-size: 0.8rem; + line-height: 1.7; +` + +const options = colorSchemeIds.map(scheme => { + let colors = [] + if (isCategoricalColorScheme(scheme)) { + colors = colorSchemes[scheme] + } else if (isDivergingColorScheme(scheme)) { + colors = colorSchemes[scheme][11] + } else if (isSequentialColorScheme(scheme)) { + colors = colorSchemes[scheme][9] + } + + return { + label: scheme, + value: scheme, + colors, + } +}) + +const SingleValue = props => { + return ( + + + + ) +} + +const Option = props => { + return ( + + + + ) +} + +const OrdinalColorsControl = ({ property, value, onChange }) => { + const selectedOption = options.find(o => o.value === value.scheme) + const handleChange = useCallback( + option => { + onChange({ scheme: option.value }) + }, + [onChange] + ) + + return ( + + +