From d75a3952b351778fff831e30393f13317a85e599 Mon Sep 17 00:00:00 2001 From: plouc Date: Mon, 16 Nov 2020 17:31:24 +0900 Subject: [PATCH] feat(marimekko): add support for patterns and gradients --- packages/marimekko/src/Bar.tsx | 2 +- packages/marimekko/src/Marimekko.tsx | 18 ++++++- packages/marimekko/src/hooks.ts | 49 +++++++++++++++---- packages/marimekko/src/props.ts | 6 +-- packages/marimekko/src/types.ts | 14 ++---- packages/pie/src/Pie.tsx | 1 - .../src/data/components/marimekko/mapper.js | 37 +++----------- .../src/data/components/marimekko/props.js | 28 +++++++++++ website/src/pages/marimekko/index.js | 20 ++++---- 9 files changed, 109 insertions(+), 66 deletions(-) diff --git a/packages/marimekko/src/Bar.tsx b/packages/marimekko/src/Bar.tsx index f3fec814be..5764901e62 100644 --- a/packages/marimekko/src/Bar.tsx +++ b/packages/marimekko/src/Bar.tsx @@ -72,7 +72,7 @@ export const Bar = ({ y={animatedProps.y} width={to(animatedProps.width, value => Math.max(value, 0))} height={to(animatedProps.height, value => Math.max(value, 0))} - fill={animatedProps.color} + fill={bar.fill ?? animatedProps.color} stroke={animatedProps.borderColor} strokeWidth={bar.borderWidth} onClick={isInteractive ? handleClick : undefined} diff --git a/packages/marimekko/src/Marimekko.tsx b/packages/marimekko/src/Marimekko.tsx index a4012cf763..d57c102d01 100644 --- a/packages/marimekko/src/Marimekko.tsx +++ b/packages/marimekko/src/Marimekko.tsx @@ -1,5 +1,11 @@ import React, { createElement, Fragment, ReactNode } from 'react' -import { Container, SvgWrapper, useDimensions } from '@nivo/core' +import { + // @ts-ignore + bindDefs, + Container, + SvgWrapper, + useDimensions, +} from '@nivo/core' import { Grid, Axes } from '@nivo/axes' import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors' import { SvgProps, LayerId, DimensionDatum } from './types' @@ -18,6 +24,8 @@ const InnerMarimekko = ({ margin: partialMargin, layout = defaultProps.layout, offset = defaultProps.offset, + outerPadding = defaultProps.outerPadding, + innerPadding = defaultProps.innerPadding, layers = defaultProps.layers, axisTop, axisRight, @@ -30,6 +38,8 @@ const InnerMarimekko = ({ colors = defaultProps.colors as OrdinalColorScaleConfig< Omit, 'color'> >, + defs = [], + fill = [], borderWidth = defaultProps.borderWidth, borderColor = defaultProps.borderColor as InheritedColorConfig>, isInteractive = defaultProps.isInteractive, @@ -53,6 +63,8 @@ const InnerMarimekko = ({ dimensions, layout, offset, + outerPadding, + innerPadding, colors, borderColor, borderWidth, @@ -67,6 +79,8 @@ const InnerMarimekko = ({ legends: null, } + const boundDefs = bindDefs(defs, bars, fill) + if (layers.includes('bars')) { layerById.bars = ( @@ -127,7 +141,7 @@ const InnerMarimekko = ({ width={outerWidth} height={outerHeight} margin={margin} - // defs={boundDefs} + defs={boundDefs} role={role} > {layers.map((layer, i) => { diff --git a/packages/marimekko/src/hooks.ts b/packages/marimekko/src/hooks.ts index 80786cb14b..5a9e8c70f1 100644 --- a/packages/marimekko/src/hooks.ts +++ b/packages/marimekko/src/hooks.ts @@ -119,20 +119,32 @@ export const useNormalizedData = ( }, [data, getId, getValue]) } -export const useThicknessScale = ( - data: NormalizedDatum[], - width: number, - height: number, +export const useThicknessScale = ({ + data, + width, + height, + layout, + outerPadding, + innerPadding, +}: { + data: NormalizedDatum[] + width: number + height: number layout: Layout -) => + outerPadding: number + innerPadding: number +}) => useMemo(() => { const totalValue = data.reduce((acc, datum) => acc + datum.value, 0) const thicknessScale = scaleLinear().domain([0, totalValue]) + + const totalPadding = 2 * outerPadding + (data.length - 1) * innerPadding + if (layout === 'vertical') { - thicknessScale.range([0, width]) + thicknessScale.range([0, width - totalPadding]) } else { - thicknessScale.range([0, height]) + thicknessScale.range([0, height - totalPadding]) } return thicknessScale @@ -146,6 +158,8 @@ export const useComputedData = ({ dimensionsScale, colors, layout, + outerPadding, + innerPadding, }: { data: NormalizedDatum[] stacked: Series[] @@ -154,12 +168,14 @@ export const useComputedData = ({ dimensionsScale: ScaleLinear colors: CommonProps['colors'] layout: Layout + outerPadding: number + innerPadding: number }) => { const getColor = useOrdinalColorScale, 'color'>>(colors, 'id') const computedData: ComputedDatum[] = [] - let position = 0 + let position = outerPadding data.forEach(datum => { const thickness = thicknessScale(datum.value) @@ -172,7 +188,7 @@ export const useComputedData = ({ dimensions: [], } - position += thickness + position += thickness + innerPadding dimensionIds.forEach(dimensionId => { const dimension = stacked.find(stack => stack.key === dimensionId) @@ -248,6 +264,8 @@ export const useMarimekko = ({ dimensions: rawDimensions, layout, offset, + outerPadding, + innerPadding, colors, borderColor, borderWidth, @@ -260,6 +278,8 @@ export const useMarimekko = ({ dimensions: DataProps['dimensions'] layout: Layout offset: OffsetId + outerPadding: number + innerPadding: number colors: CommonProps['colors'] borderColor: InheritedColorConfig> borderWidth: number @@ -270,7 +290,14 @@ export const useMarimekko = ({ const stack = useStack(dimensionIds, dimensions, offset) const { stacked, min, max } = useStackedData(stack, data) const normalizedData = useNormalizedData(data, id, value) - const thicknessScale = useThicknessScale(normalizedData, width, height, layout) + const thicknessScale = useThicknessScale({ + data: normalizedData, + width, + height, + layout, + outerPadding, + innerPadding, + }) const dimensionsScale = useDimensionsScale(min, max, width, height, layout) const computedData = useComputedData({ data: normalizedData, @@ -280,6 +307,8 @@ export const useMarimekko = ({ dimensionsScale, colors, layout, + outerPadding, + innerPadding, }) const bars = useBars(computedData, borderColor, borderWidth) diff --git a/packages/marimekko/src/props.ts b/packages/marimekko/src/props.ts index 70c390ff1f..40e8ae6af4 100644 --- a/packages/marimekko/src/props.ts +++ b/packages/marimekko/src/props.ts @@ -3,13 +3,11 @@ import { LayerId, Layout, OffsetId } from './types' export const defaultProps = { layout: 'vertical' as Layout, offset: 'none' as OffsetId, + outerPadding: 0, + innerPadding: 3, layers: ['grid', 'axes', 'bars', 'legends'] as LayerId[], - //axisTop: any, - //axisRight: any, - //axisBottom: any, - //axisLeft: any, enableGridX: false, enableGridY: true, diff --git a/packages/marimekko/src/types.ts b/packages/marimekko/src/types.ts index 420b86a35b..0aaa8fbdc9 100644 --- a/packages/marimekko/src/types.ts +++ b/packages/marimekko/src/types.ts @@ -55,6 +55,7 @@ export interface ComputedDatum extends NormalizedDatum { export interface BarDatum extends DimensionDatum { key: string + fill?: string borderColor: string borderWidth: number } @@ -106,6 +107,8 @@ export type CommonProps = { margin: Box layout: Layout offset: OffsetId + outerPadding: number + innerPadding: number // axes and grid axisTop?: AxisProps @@ -155,16 +158,7 @@ export type SvgProps = DataProps & Dimensions & Partial> & ModernMotionProps & - SvgDefsAndFill> & + SvgDefsAndFill> & MouseEventHandlers & { layers?: Layer[] } - -export type CompleteSvgProps = DataProps & - Dimensions & - CommonProps & - ModernMotionProps & - SvgDefsAndFill> & - MouseEventHandlers & { - layers: Layer[] - } diff --git a/packages/pie/src/Pie.tsx b/packages/pie/src/Pie.tsx index dbf7cd0fa3..91c3f849b1 100644 --- a/packages/pie/src/Pie.tsx +++ b/packages/pie/src/Pie.tsx @@ -196,7 +196,6 @@ const Pie = ({ height={outerHeight} margin={margin} defs={boundDefs} - theme={theme} role={role} > {layers.map((layer, i) => { diff --git a/website/src/data/components/marimekko/mapper.js b/website/src/data/components/marimekko/mapper.js index 7e4dbb5260..53e1568f73 100644 --- a/website/src/data/components/marimekko/mapper.js +++ b/website/src/data/components/marimekko/mapper.js @@ -47,44 +47,23 @@ export default settingsMapper( defs: (value, values) => { if (!values['showcase pattern usage']) return - /* - [ - patternDotsDef('dots', { - background: 'inherit', - color: 'rgba(255, 255, 255, 0.3)', - size: 4, - padding: 1, - stagger: true, - }), + return [ patternLinesDef('lines', { - background: 'inherit', - color: 'rgba(255, 255, 255, 0.3)', + background: 'rgba(0, 0, 0, 0)', + color: 'inherit', rotation: -45, - lineWidth: 6, - spacing: 10, + lineWidth: 4, + spacing: 8, }), ] - */ - - return }, fill: (value, values) => { if (!values['showcase pattern usage']) return - /* - [ - { match: { id: 'ruby' }, id: 'dots' }, - { match: { id: 'c' }, id: 'dots' }, - { match: { id: 'go' }, id: 'dots' }, - { match: { id: 'python' }, id: 'dots' }, - { match: { id: 'scala' }, id: 'lines' }, - { match: { id: 'lisp' }, id: 'lines' }, - { match: { id: 'elixir' }, id: 'lines' }, - { match: { id: 'javascript' }, id: 'lines' }, + return [ + { match: { id: 'agree strongly' }, id: 'lines' }, + { match: { id: 'disagree strongly' }, id: 'lines' }, ] - */ - - return }, }, { diff --git a/website/src/data/components/marimekko/props.js b/website/src/data/components/marimekko/props.js index 8133820729..6b4b862af0 100644 --- a/website/src/data/components/marimekko/props.js +++ b/website/src/data/components/marimekko/props.js @@ -96,6 +96,34 @@ const props = [ })), }, }, + { + key: 'outerPadding', + help: 'Space before the first bar and after the last one.', + type: 'number', + required: false, + defaultValue: defaults.outerPadding, + controlType: 'range', + group: 'Base', + controlOptions: { + min: 0, + max: 20, + unit: 'px', + }, + }, + { + key: 'innerPadding', + help: 'Space between bars.', + type: 'number', + required: false, + defaultValue: defaults.innerPadding, + controlType: 'range', + group: 'Base', + controlOptions: { + min: 0, + max: 20, + unit: 'px', + }, + }, { key: 'width', enableControlForFlavors: ['api'], diff --git a/website/src/pages/marimekko/index.js b/website/src/pages/marimekko/index.js index e1b5caef43..07fa153e6c 100644 --- a/website/src/pages/marimekko/index.js +++ b/website/src/pages/marimekko/index.js @@ -23,24 +23,26 @@ const initialProperties = { value: 'participation', dimensions: [ { - id: 'agree strongly', - value: 'stronglyAgree', - }, - { - id: 'agree', - value: 'agree', + id: 'disagree strongly', + value: 'stronglyDisagree', }, { id: 'disagree', value: 'disagree', }, { - id: 'disagree strongly', - value: 'stronglyDisagree', + id: 'agree', + value: 'agree', + }, + { + id: 'agree strongly', + value: 'stronglyAgree', }, ], layout: defaultProps.layout, offset: defaultProps.offset, + outerPadding: defaultProps.outerPadding, + innerPadding: 9, axisTop: { enable: false, @@ -92,7 +94,7 @@ const initialProperties = { valueFormat: { format: '', enabled: false }, - colors: { scheme: 'nivo' }, + colors: ['#ac402f', '#F47560', '#97E3D5', '#58b0a0'], borderWidth: 1, borderColor: {