diff --git a/packages/core/src/components/Container.js b/packages/core/src/components/Container.js index 25a18f39d..eac71195e 100644 --- a/packages/core/src/components/Container.js +++ b/packages/core/src/components/Container.js @@ -56,7 +56,7 @@ Container.propTypes = { children: PropTypes.element.isRequired, isInteractive: PropTypes.bool, renderWrapper: PropTypes.bool, - theme: PropTypes.object.isRequired, + theme: PropTypes.object, animate: PropTypes.bool, motionStiffness: PropTypes.number, motionDamping: PropTypes.number, diff --git a/packages/marimekko/src/props.ts b/packages/marimekko/src/props.ts index 3fe7a9a6e..14549028f 100644 --- a/packages/marimekko/src/props.ts +++ b/packages/marimekko/src/props.ts @@ -1,7 +1,8 @@ -import { LayerId, Layout } from './types' +import { LayerId, Layout, OffsetId } from './types' export const defaultProps = { layout: 'vertical' as Layout, + offset: 'none' as OffsetId, layers: ['grid', 'axes', 'bars', 'legends'] as LayerId[], diff --git a/packages/marimekko/src/types.ts b/packages/marimekko/src/types.ts index 98b1bc339..d85f2a426 100644 --- a/packages/marimekko/src/types.ts +++ b/packages/marimekko/src/types.ts @@ -1,4 +1,11 @@ import * as React from 'react' +import { + stackOffsetDiverging, + stackOffsetExpand, + stackOffsetNone, + stackOffsetSilhouette, + stackOffsetWiggle, +} from 'd3-shape' import { Box, Dimensions, Theme, SvgDefsAndFill, ModernMotionProps } from '@nivo/core' import { OrdinalColorScaleConfig, InheritedColorConfig } from '@nivo/colors' import { LegendProps } from '@nivo/legends' @@ -70,11 +77,32 @@ export interface TooltipProps { export type Layout = 'horizontal' | 'vertical' +export const offsetById = { + // Applies a zero baseline and normalizes the values + // for each point such that the topline is always one. + expand: stackOffsetExpand, + // Positive values are stacked above zero, negative values + // are stacked below zero, and zero values are stacked at zero. + diverging: stackOffsetDiverging, + // Applies a zero baseline. + none: stackOffsetNone, + // Shifts the baseline down such that the center of the streamgraph + // is always at zero. + silouhette: stackOffsetSilhouette, + // Shifts the baseline so as to minimize the weighted wiggle of layers. + // This offset is recommended for streamgraphs in conjunction with the inside-out order. + // See Stacked Graphs—Geometry & Aesthetics by Bryon & Wattenberg for more information. + wiggle: stackOffsetWiggle, +} + +export type OffsetId = keyof typeof offsetById + export type CommonProps = { valueFormat?: string | ValueFormatter margin: Box layout: Layout + offset: OffsetId // colors, theme and border colors: OrdinalColorScaleConfig, 'color' | 'fill'>> diff --git a/packages/marimekko/stories/marimekko.stories.js b/packages/marimekko/stories/marimekko.stories.js deleted file mode 100644 index ed3efc8a5..000000000 --- a/packages/marimekko/stories/marimekko.stories.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react' -import { storiesOf } from '@storybook/react' -import { withKnobs } from '@storybook/addon-knobs' -import { Marimekko } from '../src' - -const commonProps = { - width: 900, - height: 500, -} - -const stories = storiesOf('Marimekko', module) - -stories.addDecorator(withKnobs) - -stories.add('default', () => ( - -)) diff --git a/packages/marimekko/stories/marimekko.stories.tsx b/packages/marimekko/stories/marimekko.stories.tsx new file mode 100644 index 000000000..d89c29227 --- /dev/null +++ b/packages/marimekko/stories/marimekko.stories.tsx @@ -0,0 +1,116 @@ +import React from 'react' +import { storiesOf } from '@storybook/react' +import { withKnobs } from '@storybook/addon-knobs' +import { Marimekko, Layout } from '../src' + +const commonProps = { + width: 900, + height: 500, + id: 'id', + value: 'value', + layout: 'vertical' as Layout, + dimensions: [ + { + id: 'cool stuff', + value: 'cool', + }, + { + id: 'not cool stuff', + value: 'notCool', + }, + { + id: 'YABAI!', + value: 'yabai', + }, + ], + data: [ + { + id: 'A', + value: 42, + cool: 9, + notCool: 13, + yabai: 32, + }, + { + id: 'B', + value: 7, + cool: 12, + notCool: 24, + yabai: 17, + }, + { + id: 'C', + value: 15, + cool: 21, + notCool: 8, + yabai: 12, + }, + ], +} + +const stories = storiesOf('Marimekko', module) + +stories.addDecorator(withKnobs) + +stories.add('default', () => ) + +stories.add('using arrays for data', () => { + type RawDatum = [string, number, number, number, number] + + const data: RawDatum[] = [ + ['A', 42, 9, 3, 31], + ['B', 21, 13, 21, 9], + ['C', 34, 7, 12, 32], + ] + + return ( + + {...commonProps} + data={data} + id={0} + value={1} + dimensions={[ + { + id: 'cool stuff', + value: 2, + }, + { + id: 'not cool stuff', + value: 3, + }, + { + id: 'YABAI!', + value: 4, + }, + ]} + /> + ) +}) + +stories.add('diverging', () => { + const data = [ + { + id: 'A', + value: 42, + cool: 9, + notCool: -13, + yabai: 32, + }, + { + id: 'B', + value: 7, + cool: 12, + notCool: -24, + yabai: 17, + }, + { + id: 'C', + value: 15, + cool: 21, + notCool: -8, + yabai: 12, + }, + ] + + return +}) diff --git a/website/src/data/components/marimekko/meta.yml b/website/src/data/components/marimekko/meta.yml index 6487f2bb6..60749889c 100644 --- a/website/src/data/components/marimekko/meta.yml +++ b/website/src/data/components/marimekko/meta.yml @@ -7,7 +7,11 @@ Marimekko: tags: - svg - isomorphic - stories: [] + stories: + - label: using arrays for data + link: marimekko--using-arrays-for-data + - label: diverging chart + link: marimekko--diverging description: | The `Marimekko` component is somehow similar to a bar chart, but it allows you to use an extra dimension to compute the diff --git a/website/src/data/components/marimekko/props.js b/website/src/data/components/marimekko/props.js index 0f6044237..1bfa60cf3 100644 --- a/website/src/data/components/marimekko/props.js +++ b/website/src/data/components/marimekko/props.js @@ -65,13 +65,28 @@ const props = [ type: 'string | (value: number) => string | number', controlType: 'valueFormat', }, + { + key: 'layout', + help: `How to display bars.`, + type: 'string', + required: false, + defaultValue: defaults.layout, + controlType: 'radio', + group: 'Base', + controlOptions: { + choices: [ + { label: 'horizontal', value: 'horizontal' }, + { label: 'vertical', value: 'vertical' }, + ], + }, + }, { key: 'width', enableControlForFlavors: ['api'], help: 'Chart width.', description: ` not required if using - \`\`. + \`\`. `, type: 'number', required: true, @@ -90,7 +105,7 @@ const props = [ help: 'Chart height.', description: ` not required if using - \`\`. + \`\`. `, type: 'number', required: true, @@ -111,21 +126,6 @@ const props = [ controlType: 'margin', group: 'Base', }, - { - key: 'layout', - help: `How to display bars.`, - type: 'string', - required: false, - defaultValue: defaults.layout, - controlType: 'radio', - group: 'Base', - controlOptions: { - choices: [ - { label: 'horizontal', value: 'horizontal' }, - { label: 'vertical', value: 'vertical' }, - ], - }, - }, themeProperty, { key: 'colors', @@ -195,7 +195,7 @@ const props = [ }, { key: 'isInteractive', - flavors: ['svg', 'canvas'], + flavors: ['svg'], group: 'Interactivity', help: 'Enable/disable interactivity.', type: 'boolean', @@ -205,7 +205,7 @@ const props = [ }, { key: 'onClick', - flavors: ['svg', 'canvas'], + flavors: ['svg'], group: 'Interactivity', help: 'onClick handler, it receives target bar data and mouse event.', type: '(bar: BarDatum, event: MouseEvent) => void', @@ -213,7 +213,7 @@ const props = [ }, { key: 'onMouseEnter', - flavors: ['svg', 'canvas'], + flavors: ['svg'], group: 'Interactivity', help: 'onMouseEnter handler, it receives target bar data and mouse event.', type: '(bar: BarDatum, event: MouseEvent) => void', @@ -221,7 +221,7 @@ const props = [ }, { key: 'onMouseMove', - flavors: ['svg', 'canvas'], + flavors: ['svg'], group: 'Interactivity', help: 'onMouseMove handler, it receives target bar data and mouse event.', type: '(bar: BarDatum, event: MouseEvent) => void', @@ -229,7 +229,7 @@ const props = [ }, { key: 'onMouseLeave', - flavors: ['svg', 'canvas'], + flavors: ['svg'], group: 'Interactivity', help: 'onMouseLeave handler, it receives target bar data and mouse event.', type: '(bar: BarDatum, event: MouseEvent) => void', @@ -237,7 +237,6 @@ const props = [ }, { key: 'tooltip', - flavors: ['svg', 'canvas'], group: 'Interactivity', type: 'Component', required: false, @@ -249,7 +248,7 @@ const props = [ \`\`\` { - datum: PieComputedDatum + bar: BarDatum } \`\`\` @@ -259,7 +258,6 @@ const props = [ }, { key: 'custom tooltip example', - flavors: ['svg', 'canvas'], help: 'Showcase custom tooltip.', type: 'boolean', controlType: 'switch', @@ -268,13 +266,13 @@ const props = [ ...motionProperties(['svg'], defaults, 'react-spring'), { key: 'legends', - flavors: ['svg', 'canvas'], + flavors: ['svg'], type: 'Legend[]', help: `Optional chart's legends.`, group: 'Legends', controlType: 'array', controlOptions: { - props: getLegendsProps(['svg', 'canvas']), + props: getLegendsProps(['svg']), shouldCreate: true, addLabel: 'add legend', shouldRemove: true,