+type Samples = {
+ [P in ChartType]?: {
+ type: P
+ props: ChartProps
}
-> = {
+}
+
+export const samples: Samples = {
bar: {
type: 'bar',
props: {
@@ -73,7 +74,7 @@ export const samples: Record<
borderWidth: 2,
borderColor: 'inherit:darker(0.4)',
labelTextColor: 'inherit:darker(2.4)',
- },
+ } as ChartProps<'heatmap'>,
},
line: {
type: 'line',
@@ -119,7 +120,7 @@ export const samples: Record<
enableMarkersLabel: true,
},
generateWinesTastes()
- ),
+ ) as ChartProps<'radar'>,
},
sankey: {
type: 'sankey',
@@ -148,7 +149,20 @@ export const samples: Record<
enableArcLabels: true,
arcLabelsSkipAngle: 10,
arcLabelsTextColor: { from: 'color', modifiers: [['darker', 1.4]] },
- },
+ } as ChartProps<'sunburst'>,
+ },
+ icicles: {
+ type: 'icicles',
+ props: {
+ width: 800,
+ height: 800,
+ data: generateLibTree(),
+ id: 'name',
+ value: 'loc',
+ childColor: { from: 'color', modifiers: [['brighter', 0.1]] },
+ enableRectLabels: true,
+ rectLabelsTextColor: { from: 'color', modifiers: [['darker', 1.4]] },
+ } as ChartProps<'icicles'>,
},
treemap: {
type: 'treemap',
diff --git a/tsconfig.monorepo.json b/tsconfig.monorepo.json
index 99343d876..971365ed7 100644
--- a/tsconfig.monorepo.json
+++ b/tsconfig.monorepo.json
@@ -3,45 +3,111 @@
"references": [
// Core first because everything needs it
// { "path": "./packages/core" },
-
// Shared next because charts need them
- { "path": "./packages/annotations" },
- { "path": "./packages/scales" },
- { "path": "./packages/axes" },
- { "path": "./packages/colors" },
- { "path": "./packages/legends" },
- { "path": "./packages/tooltip" },
- { "path": "./packages/arcs" },
- { "path": "./packages/polar-axes" },
- { "path": "./packages/voronoi" },
-
+ {
+ "path": "./packages/annotations"
+ },
+ {
+ "path": "./packages/scales"
+ },
+ {
+ "path": "./packages/axes"
+ },
+ {
+ "path": "./packages/colors"
+ },
+ {
+ "path": "./packages/legends"
+ },
+ {
+ "path": "./packages/tooltip"
+ },
+ {
+ "path": "./packages/arcs"
+ },
+ {
+ "path": "./packages/rects"
+ },
+ {
+ "path": "./packages/polar-axes"
+ },
+ {
+ "path": "./packages/voronoi"
+ },
// Utility packages
- { "path": "./packages/generators" },
- { "path": "./packages/recompose" },
-
+ {
+ "path": "./packages/generators"
+ },
+ {
+ "path": "./packages/recompose"
+ },
// Charts now
- { "path": "./packages/bar" },
- { "path": "./packages/bullet" },
- { "path": "./packages/bump" },
- { "path": "./packages/calendar" },
- { "path": "./packages/chord" },
- { "path": "./packages/circle-packing" },
- { "path": "./packages/funnel" },
- { "path": "./packages/heatmap" },
- { "path": "./packages/marimekko" },
- { "path": "./packages/network" },
- { "path": "./packages/pie" },
- { "path": "./packages/radar" },
- { "path": "./packages/radial-bar" },
- { "path": "./packages/sankey" },
- { "path": "./packages/scatterplot" },
- { "path": "./packages/sunburst" },
- { "path": "./packages/stream" },
- { "path": "./packages/swarmplot" },
- { "path": "./packages/treemap" },
-
+ {
+ "path": "./packages/bar"
+ },
+ {
+ "path": "./packages/bullet"
+ },
+ {
+ "path": "./packages/bump"
+ },
+ {
+ "path": "./packages/calendar"
+ },
+ {
+ "path": "./packages/chord"
+ },
+ {
+ "path": "./packages/circle-packing"
+ },
+ {
+ "path": "./packages/funnel"
+ },
+ {
+ "path": "./packages/heatmap"
+ },
+ {
+ "path": "./packages/icicles"
+ },
+ {
+ "path": "./packages/marimekko"
+ },
+ {
+ "path": "./packages/network"
+ },
+ {
+ "path": "./packages/pie"
+ },
+ {
+ "path": "./packages/radar"
+ },
+ {
+ "path": "./packages/radial-bar"
+ },
+ {
+ "path": "./packages/sankey"
+ },
+ {
+ "path": "./packages/scatterplot"
+ },
+ {
+ "path": "./packages/sunburst"
+ },
+ {
+ "path": "./packages/stream"
+ },
+ {
+ "path": "./packages/swarmplot"
+ },
+ {
+ "path": "./packages/treemap"
+ },
// Static rendering and express middleware
- { "path": "./packages/static" },
- { "path": "./packages/express" }
+ {
+ "path": "./packages/static"
+ },
+ {
+ "path": "./packages/express"
+ }
]
-}
+}
\ No newline at end of file
diff --git a/website/package.json b/website/package.json
index 88e136c84..9774fd4a4 100644
--- a/website/package.json
+++ b/website/package.json
@@ -17,6 +17,7 @@
"@nivo/generators": "0.79.0",
"@nivo/geo": "0.79.1",
"@nivo/heatmap": "0.79.1",
+ "@nivo/icicles": "0.79.1",
"@nivo/legends": "0.79.1",
"@nivo/line": "0.79.1",
"@nivo/marimekko": "0.79.1",
@@ -25,6 +26,7 @@
"@nivo/pie": "0.79.1",
"@nivo/radar": "0.79.1",
"@nivo/radial-bar": "0.79.1",
+ "@nivo/rects": "0.79.1",
"@nivo/sankey": "0.79.1",
"@nivo/scatterplot": "0.79.1",
"@nivo/stream": "0.79.1",
@@ -64,4 +66,4 @@
"engines": {
"node": "16.x"
}
-}
+}
\ No newline at end of file
diff --git a/website/src/@types/file_types.d.ts b/website/src/@types/file_types.d.ts
index 96576d8f1..8f7de105c 100644
--- a/website/src/@types/file_types.d.ts
+++ b/website/src/@types/file_types.d.ts
@@ -5,7 +5,7 @@ type ChartMetaFlavors = {
path: string
}[]
-declare module '*area-bump/meta.yml' {
+declare module '*/area-bump/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
AreaBump: ChartMeta
@@ -14,7 +14,7 @@ declare module '*area-bump/meta.yml' {
export default meta
}
-declare module '*bar/meta.yml' {
+declare module '*/bar/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Bar: ChartMeta
@@ -24,7 +24,7 @@ declare module '*bar/meta.yml' {
export default meta
}
-declare module '*bullet/meta.yml' {
+declare module '*/bullet/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Bullet: ChartMeta
@@ -33,7 +33,7 @@ declare module '*bullet/meta.yml' {
export default meta
}
-declare module '*bump/meta.yml' {
+declare module '*/bump/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Bump: ChartMeta
@@ -42,7 +42,7 @@ declare module '*bump/meta.yml' {
export default meta
}
-declare module '*calendar/meta.yml' {
+declare module '*/calendar/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Calendar: ChartMeta
@@ -52,7 +52,7 @@ declare module '*calendar/meta.yml' {
export default meta
}
-declare module '*calendar/meta.yml' {
+declare module '*/calendar/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Calendar: ChartMeta
@@ -62,7 +62,7 @@ declare module '*calendar/meta.yml' {
export default meta
}
-declare module '*chord/meta.yml' {
+declare module '*/chord/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Chord: ChartMeta
@@ -72,7 +72,7 @@ declare module '*chord/meta.yml' {
export default meta
}
-declare module '*choropleth/meta.yml' {
+declare module '*/choropleth/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Choropleth: ChartMeta
@@ -82,7 +82,7 @@ declare module '*choropleth/meta.yml' {
export default meta
}
-declare module '*circle-packing/meta.yml' {
+declare module '*/circle-packing/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
CirclePacking: ChartMeta
@@ -93,7 +93,7 @@ declare module '*circle-packing/meta.yml' {
export default meta
}
-declare module '*funnel/meta.yml' {
+declare module '*/funnel/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Funnel: ChartMeta
@@ -102,7 +102,16 @@ declare module '*funnel/meta.yml' {
export default meta
}
-declare module '*heatmap/meta.yml' {
+declare module '*/geomap/meta.yml' {
+ const meta: {
+ flavors: ChartMetaFlavors
+ GeoMap: ChartMeta
+ }
+
+ export default meta
+}
+
+declare module '*/heatmap/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
HeatMap: ChartMeta
@@ -112,7 +121,16 @@ declare module '*heatmap/meta.yml' {
export default meta
}
-declare module '*line/meta.yml' {
+declare module '*/icicles/meta.yml' {
+ const meta: {
+ flavors: ChartMetaFlavors
+ Icicles: ChartMeta
+ }
+
+ export default meta
+}
+
+declare module '*/line/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Line: ChartMeta
@@ -122,7 +140,7 @@ declare module '*line/meta.yml' {
export default meta
}
-declare module '*marimekko/meta.yml' {
+declare module '*/marimekko/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Marimekko: ChartMeta
@@ -131,7 +149,7 @@ declare module '*marimekko/meta.yml' {
export default meta
}
-declare module '*network/meta.yml' {
+declare module '*/network/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Network: ChartMeta
@@ -141,7 +159,7 @@ declare module '*network/meta.yml' {
export default meta
}
-declare module '*parallel-coordinates/meta.yml' {
+declare module '*/parallel-coordinates/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
ParallelCoordinates: ChartMeta
@@ -151,7 +169,7 @@ declare module '*parallel-coordinates/meta.yml' {
export default meta
}
-declare module '*pie/meta.yml' {
+declare module '*/pie/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Pie: ChartMeta
@@ -161,7 +179,7 @@ declare module '*pie/meta.yml' {
export default meta
}
-declare module '*radar/meta.yml' {
+declare module '*/radar/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Radar: ChartMeta
@@ -170,7 +188,7 @@ declare module '*radar/meta.yml' {
export default meta
}
-declare module '*radial-bar/meta.yml' {
+declare module '*/radial-bar/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
RadialBar: ChartMeta
@@ -179,7 +197,7 @@ declare module '*radial-bar/meta.yml' {
export default meta
}
-declare module '*sankey/meta.yml' {
+declare module '*/sankey/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Sankey: ChartMeta
@@ -188,7 +206,7 @@ declare module '*sankey/meta.yml' {
export default meta
}
-declare module '*scatterplot/meta.yml' {
+declare module '*/scatterplot/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
ScatterPlot: ChartMeta
@@ -198,7 +216,7 @@ declare module '*scatterplot/meta.yml' {
export default meta
}
-declare module '*stream/meta.yml' {
+declare module '*/stream/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Stream: ChartMeta
@@ -207,7 +225,7 @@ declare module '*stream/meta.yml' {
export default meta
}
-declare module '*sunburst/meta.yml' {
+declare module '*/sunburst/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Sunburst: ChartMeta
@@ -216,7 +234,7 @@ declare module '*sunburst/meta.yml' {
export default meta
}
-declare module '*swarmplot/meta.yml' {
+declare module '*/swarmplot/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
SwarmPlot: ChartMeta
@@ -226,7 +244,7 @@ declare module '*swarmplot/meta.yml' {
export default meta
}
-declare module '*time-range/meta.yml' {
+declare module '*/time-range/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
TimeRange: ChartMeta
@@ -235,7 +253,7 @@ declare module '*time-range/meta.yml' {
export default meta
}
-declare module '*treemap/meta.yml' {
+declare module '*/treemap/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
TreeMap: ChartMeta
@@ -246,7 +264,7 @@ declare module '*treemap/meta.yml' {
export default meta
}
-declare module '*voronoi/meta.yml' {
+declare module '*/voronoi/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Voronoi: ChartMeta
@@ -255,7 +273,7 @@ declare module '*voronoi/meta.yml' {
export default meta
}
-declare module '*waffle/meta.yml' {
+declare module '*/waffle/meta.yml' {
const meta: {
flavors: ChartMetaFlavors
Waffle: ChartMeta
diff --git a/website/src/components/home/Home.tsx b/website/src/components/home/Home.tsx
index ed0ca8979..3c31c2372 100644
--- a/website/src/components/home/Home.tsx
+++ b/website/src/components/home/Home.tsx
@@ -19,6 +19,7 @@ import radialBar from '../../assets/captures/home/radial-bar.png'
import voronoi from '../../assets/captures/home/voronoi.png'
import treemap from '../../assets/captures/home/treemap.png'
import sunburst from '../../assets/captures/home/sunburst.png'
+import icicles from '../../assets/captures/home/sunburst.png'
import sankey from '../../assets/captures/home/sankey.png'
import swarmplot from '../../assets/captures/home/swarmplot.png'
import marimekko from '../../assets/captures/home/marimekko.png'
@@ -55,7 +56,7 @@ const Home = () => {
-
+
)
diff --git a/website/src/components/home/HomeIciclesDemo.tsx b/website/src/components/home/HomeIciclesDemo.tsx
new file mode 100644
index 000000000..e35301d82
--- /dev/null
+++ b/website/src/components/home/HomeIciclesDemo.tsx
@@ -0,0 +1,28 @@
+import React, { useMemo } from 'react'
+import { generateLibTree } from '@nivo/generators'
+import { Icicles } from '@nivo/icicles'
+import { useHomeTheme } from './theme'
+import { dimensions } from './dimensions'
+
+export const HomeIciclesDemo = () => {
+ const { colors, nivoTheme } = useHomeTheme()
+ const data = useMemo(() => generateLibTree(), [])
+
+ return (
+
+
+
+ )
+}
diff --git a/website/src/components/home/index.ts b/website/src/components/home/index.ts
index 13dafeff0..d2420182a 100644
--- a/website/src/components/home/index.ts
+++ b/website/src/components/home/index.ts
@@ -12,6 +12,7 @@ export * from './HomeRadialBarDemo'
export * from './HomeSankeyDemo'
export * from './HomeStreamDemo'
export * from './HomeSunburstDemo'
+export * from './HomeIciclesDemo'
export * from './HomeSwarmPlotDemo'
export * from './HomeTreeMapDemo'
export * from './HomeVoronoiDemo'
diff --git a/website/src/components/icons/IciclesIcon.tsx b/website/src/components/icons/IciclesIcon.tsx
new file mode 100644
index 000000000..40a24aa4d
--- /dev/null
+++ b/website/src/components/icons/IciclesIcon.tsx
@@ -0,0 +1,132 @@
+import React from 'react'
+import { arc as Arc } from 'd3-shape'
+import { degreesToRadians } from '@nivo/core'
+import sunburstLightNeutralImg from '../../assets/icons/sunburst-grey.png'
+import sunburstLightColoredImg from '../../assets/icons/sunburst-red.png'
+import sunburstDarkNeutralImg from '../../assets/icons/sunburst-dark-neutral.png'
+import sunburstDarkColoredImg from '../../assets/icons/sunburst-dark-colored.png'
+import { ICON_SIZE, Icon, colors, IconImg } from './styled'
+import { IconType } from './types'
+
+const arc = Arc().padAngle(degreesToRadians(2))
+
+const IciclesIconItem = ({ type }: { type: IconType }) => (
+
+
+
+)
+
+export const IciclesIcon = () => (
+ <>
+
+
+
+
+
+
+
+
+ >
+)
diff --git a/website/src/components/icons/Icons.tsx b/website/src/components/icons/Icons.tsx
index 936a3559c..9d986c5d6 100644
--- a/website/src/components/icons/Icons.tsx
+++ b/website/src/components/icons/Icons.tsx
@@ -24,6 +24,7 @@ import { SankeyIcon } from './SankeyIcon'
import { ScatterPlotIcon } from './ScatterPlotIcon'
import { StreamIcon } from './StreamIcon'
import { SunburstIcon } from './SunburstIcon'
+import { IciclesIcon } from './IciclesIcon'
import { SwarmPlotIcon } from './SwarmPlotIcon'
import { TimeRangeIcon } from './TimeRangeIcon'
import { TreeMapIcon } from './TreeMapIcon'
@@ -87,6 +88,7 @@ export const Icons = () => (
+
diff --git a/website/src/data/components/icicles/mapper.tsx b/website/src/data/components/icicles/mapper.tsx
new file mode 100644
index 000000000..32807b6b2
--- /dev/null
+++ b/website/src/data/components/icicles/mapper.tsx
@@ -0,0 +1,72 @@
+import React from 'react'
+import styled from 'styled-components'
+import { patternLinesDef } from '@nivo/core'
+import { mapFormat, settingsMapper } from '../../../lib/settings'
+
+const TooltipWrapper = styled.div`
+ display: grid;
+ background: #fff;
+ grid-template-columns: 1fr 1fr;
+ grid-column-gap: 12px;
+ font-size: 12px;
+ border-radius: 2px;
+ box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.15);
+`
+const TooltipKey = styled.span`
+ font-weight: 600;
+`
+const TooltipValue = styled.span``
+
+const CustomTooltip = node => {
+ return (
+
+ id
+ {node.id}
+ value
+ {node.value}
+ percentage
+ {Math.round(node.percentage * 100) / 100}%
+ color
+ {node.color}
+
+ )
+}
+
+export default settingsMapper(
+ {
+ valueFormat: mapFormat,
+ rectLabel: value => {
+ if (value === `d => \`\${d.id} (\${d.value})\``) return d => `${d.id} (${d.value})`
+ return value
+ },
+ tooltip: (value, values) => {
+ if (!values['custom tooltip example']) return undefined
+
+ return CustomTooltip
+ },
+ defs: (value, values) => {
+ if (!values['showcase pattern usage']) return
+
+ return [
+ patternLinesDef('lines', {
+ background: 'rgba(0, 0, 0, 0)',
+ color: 'inherit',
+ rotation: -45,
+ lineWidth: 4,
+ spacing: 8,
+ }),
+ ]
+ },
+ fill: (value, values) => {
+ if (!values['showcase pattern usage']) return
+
+ return [
+ { match: { id: 'set' }, id: 'lines' },
+ { match: { id: 'misc' }, id: 'lines' },
+ ]
+ },
+ },
+ {
+ exclude: ['custom tooltip example', 'showcase pattern usage'],
+ }
+)
diff --git a/website/src/data/components/icicles/meta.yml b/website/src/data/components/icicles/meta.yml
new file mode 100644
index 000000000..32866f6b4
--- /dev/null
+++ b/website/src/data/components/icicles/meta.yml
@@ -0,0 +1,35 @@
+flavors:
+ - flavor: svg
+ path: /icicles/
+ - flavor: api
+ path: /icicles/api/
+
+Icicles:
+ package: "@nivo/icicles"
+ tags:
+ - hierarchy
+ - flat
+ stories:
+ - label: with child color modifier
+ link: icicles--with-child-color-modifier
+ - label: with child color independent of parent
+ link: icicles--with-child-colors-independent-of-parent
+ - label: with custom colors
+ link: icicles--with-custom-colors
+ - label: with formatted tooltip value
+ link: icicles--with-formatted-tooltip-value
+ - label: with custom tooltip
+ link: icicles--custom-tooltip
+ - label: with enter and leave actions
+ link: icicles--enter-leave-check-actions
+ - label: with wheel and contextmenu actions
+ link: icicles--wheel-contextmenu-check-actions
+ - label: with patterns and gradients
+ link: icicles--patterns-gradients
+ - label: drill down to children
+ link: icicles--children-drill-down
+ - label: with different direction
+ link: icicles--change-direction
+ description: |
+ The responsive alternative of this component is
+ `ResponsiveIcicles`.
diff --git a/website/src/data/components/icicles/props.ts b/website/src/data/components/icicles/props.ts
new file mode 100644
index 000000000..1c6bded68
--- /dev/null
+++ b/website/src/data/components/icicles/props.ts
@@ -0,0 +1,443 @@
+import { defaultProps, IciclesDirection } from '@nivo/icicles'
+import {
+ groupProperties,
+ defsProperties,
+ motionProperties,
+ themeProperty,
+} from '../../../lib/componentProperties'
+import { chartDimensions, ordinalColors, isInteractive } from '../../../lib/chart-properties'
+import { ChartProperty, Flavor } from '../../../types'
+
+const allFlavors: Flavor[] = ['svg', 'api']
+
+const directions: IciclesDirection[] = ['top', 'right', 'bottom', 'left'];
+
+const props: ChartProperty[] = [
+ {
+ key: 'data',
+ group: 'Base',
+ flavors: allFlavors,
+ help: 'Chart data, which should be immutable.',
+ description: `
+ Chart data, which must conform to this structure
+ if using the default \`id\` and \`value\` accessors:
+
+ \`\`\`
+ {
+ // must be unique for the whole dataset
+ id: string | number
+ value: number
+ children: {
+ id: string | number
+ value: number
+ children: ...
+ }[]
+ }
+ \`\`\`
+
+ If using a different data structure, you must make sure
+ to adjust both \`id\` and \`value\`. Meaning you can provide
+ a completely different data structure as long as \`id\` and \`value\`
+ return the appropriate values.
+
+ Immutability of the data is important as re-computations
+ depends on it.
+ `,
+ type: 'object',
+ required: true,
+ },
+ {
+ key: 'id',
+ group: 'Base',
+ flavors: allFlavors,
+ help: 'Id accessor.',
+ description: `
+ define id accessor, if string given,
+ will use \`node[value]\`,
+ if function given, it will be invoked
+ for each node and will receive the node as
+ first argument, it must return the node
+ id (string | number).
+ `,
+ type: 'string | Function',
+ required: false,
+ defaultValue: defaultProps.id,
+ },
+ {
+ key: 'value',
+ group: 'Base',
+ flavors: allFlavors,
+ help: 'Value accessor',
+ description: `
+ define value accessor, if string given,
+ will use \`node[value]\`,
+ if function given, it will be invoked
+ for each node and will receive the node as
+ first argument, it must return the node
+ value (number).
+ `,
+ type: 'string | Function',
+ required: false,
+ defaultValue: defaultProps.value,
+ },
+ {
+ key: 'direction',
+ group: 'Base',
+ flavors: allFlavors,
+ help: 'Optional chart direction.',
+ description: `
+ Change the reading direction of the chart.
+ `,
+ required: false,
+ type: directions.map(d => `'${d}'`).join(' | '),
+ control: {
+ type: 'radio',
+ choices: directions.map(d => ({
+ label: d,
+ value: d
+ }))
+ },
+ },
+ {
+ key: 'valueFormat',
+ group: 'Base',
+ flavors: allFlavors,
+ help: 'Optional formatter for values.',
+ description: `
+ The formatted value can then be used for labels & tooltips.
+
+ Under the hood, nivo uses [d3-format](https://github.com/d3/d3-format),
+ please have a look at it for available formats, you can also pass a function
+ which will receive the raw value and should return the formatted one.
+ `,
+ required: false,
+ type: 'string | (value: number) => string | number',
+ control: { type: 'valueFormat' },
+ },
+ ...chartDimensions(allFlavors),
+ themeProperty(['svg', 'api']),
+ ordinalColors({
+ flavors: allFlavors,
+ defaultValue: defaultProps.colors,
+ }),
+ {
+ key: 'colorBy',
+ help: `Define the property to use to assign a color to rects.`,
+ flavors: allFlavors,
+ description: `
+ When using \`id\`, each node will get a new color,
+ and when using \`depth\` the nodes' color will depend on their depth.
+ `,
+ type: `'id' | 'depth'`,
+ required: false,
+ defaultValue: defaultProps.colorBy,
+ group: 'Style',
+ control: {
+ type: 'radio',
+ choices: [
+ { label: 'id', value: 'id' },
+ { label: 'depth', value: 'depth' },
+ ],
+ },
+ },
+ {
+ key: 'inheritColorFromParent',
+ help: 'Inherit color from parent node starting from 2nd level.',
+ flavors: allFlavors,
+ type: 'boolean',
+ required: false,
+ defaultValue: defaultProps.inheritColorFromParent,
+ control: { type: 'switch' },
+ group: 'Style',
+ },
+ {
+ key: 'childColor',
+ help: 'Defines how to compute child nodes color.',
+ flavors: allFlavors,
+ type: 'string | object | Function',
+ required: false,
+ defaultValue: defaultProps.childColor,
+ control: { type: 'inheritedColor' },
+ group: 'Style',
+ },
+ {
+ key: 'borderWidth',
+ help: 'Node border width.',
+ flavors: allFlavors,
+ type: 'number',
+ required: false,
+ defaultValue: defaultProps.borderWidth,
+ control: { type: 'lineWidth' },
+ group: 'Style',
+ },
+ {
+ key: 'borderColor',
+ help: 'Defines how to compute rects border color.',
+ flavors: allFlavors,
+ type: 'string | object | Function',
+ required: false,
+ defaultValue: defaultProps.borderColor,
+ control: { type: 'inheritedColor' },
+ group: 'Style',
+ },
+ ...defsProperties('Style', ['svg', 'api']),
+ {
+ key: 'showcase pattern usage',
+ flavors: ['svg'],
+ help: 'Patterns.',
+ description: `
+ You can use \`defs\` and \`fill\` properties
+ to use patterns, see
+ [dedicated guide](self:/guides/patterns)
+ for further information.
+ `,
+ required: false,
+ type: 'boolean',
+ control: { type: 'switch' },
+ group: 'Style',
+ },
+ {
+ key: 'enableRectLabels',
+ help: 'Enable/disable rect labels.',
+ flavors: allFlavors,
+ type: 'boolean',
+ required: false,
+ defaultValue: defaultProps.enableRectLabels,
+ control: { type: 'switch' },
+ group: 'Rect labels',
+ },
+ {
+ key: 'rectLabel',
+ help: 'Defines how to get label text, can be a string (used to access current node data property) or a function which will receive the actual node data.',
+ flavors: allFlavors,
+ type: 'string | Function',
+ required: false,
+ defaultValue: defaultProps.rectLabel,
+ group: 'Rect labels',
+ control: {
+ type: 'choices',
+ choices: ['id', 'value', 'formattedValue', `d => \`\${d.id} (\${d.value})\``].map(
+ choice => ({
+ label: choice,
+ value: choice,
+ })
+ ),
+ },
+ },
+ {
+ key: 'rectLabelsOffset',
+ help: `
+ Define the ratio offset when centering a label.
+ The offset affects the vertical postion.
+ `,
+ flavors: allFlavors,
+ type: 'number',
+ required: false,
+ defaultValue: defaultProps.rectLabelsOffset,
+ group: 'Rect labels',
+ control: {
+ type: 'range',
+ min: 0.5,
+ max: 2,
+ step: 0.05,
+ },
+ },
+ {
+ key: 'rectLabelsSkipLength',
+ help: `
+ Skip label if corresponding rect's length is lower than provided value.
+ "Length" is determined by width when direction is top or bottom,
+ and by height when direction is left or right.
+ `,
+ flavors: allFlavors,
+ type: 'number',
+ required: false,
+ defaultValue: defaultProps.rectLabelsSkipLength,
+ group: 'Rect labels',
+ control: {
+ type: 'range',
+ unit: 'px',
+ min: 0,
+ max: 900,
+ step: 1,
+ },
+ },
+ {
+ key: 'rectLabelsSkipPercentage',
+ help: `
+ Skip label if corresponding rect's relative size is lower than provided value.
+ The size is relative to the root node considered as 100%.
+ This value is a percentage.
+ `,
+ flavors: allFlavors,
+ type: 'number',
+ required: false,
+ defaultValue: defaultProps.rectLabelsSkipPercentage,
+ group: 'Rect labels',
+ control: {
+ type: 'range',
+ min: 0,
+ max: 100,
+ step: 1,
+ },
+ },
+ {
+ key: 'rectLabelsTextColor',
+ help: 'Defines how to compute rect label text color.',
+ flavors: allFlavors,
+ type: 'string | object | Function',
+ required: false,
+ defaultValue: defaultProps.rectLabelsTextColor,
+ control: { type: 'inheritedColor' },
+ group: 'Rect labels',
+ },
+ {
+ key: 'layers',
+ group: 'Customization',
+ help: 'Defines the order of layers and add custom layers.',
+ flavors: ['svg'],
+ description: `
+ You can also use this to insert extra layers
+ to the chart, the extra layer must be a function.
+
+ The layer component which will receive the chart's
+ context & computed data and must return a valid SVG element
+ for the \`Icicles\` component.
+
+ The context passed to layers has the following structure:
+
+ \`\`\`
+ {
+ nodes: ComputedDatum[]
+ baseOffsetLeft: number
+ baseOffsetTop: number
+ }
+ \`\`\`
+ `,
+ required: false,
+ type: 'Array',
+ defaultValue: defaultProps.layers,
+ },
+ isInteractive({
+ flavors: ['svg'],
+ defaultValue: defaultProps.isInteractive,
+ }),
+ ...motionProperties(['svg'], defaultProps, 'react-spring'),
+ {
+ key: 'tooltip',
+ flavors: ['svg'],
+ group: 'Interactivity',
+ type: 'Function',
+ required: false,
+ help: 'Tooltip custom component',
+ description: `
+ A function allowing complete tooltip customisation,
+ it must return a valid HTML element and will receive
+ the following data:
+ \`\`\`
+ {
+ id: string | number,
+ value: number,
+ depth: number,
+ color: string,
+ name: string
+ loc: number
+ percentage: number
+ // the parent datum
+ ancestor: object
+ }
+ \`\`\`
+ You can also customize the style of the tooltip
+ using the \`theme.tooltip\` object.
+ `,
+ },
+ {
+ key: 'custom tooltip example',
+ flavors: ['svg'],
+ group: 'Interactivity',
+ required: false,
+ help: 'Showcase custom tooltip component.',
+ type: 'boolean',
+ control: { type: 'switch' },
+ },
+ {
+ key: 'onClick',
+ flavors: ['svg'],
+ group: 'Interactivity',
+ type: 'Function',
+ required: false,
+ help: 'onClick handler',
+ description: `
+ onClick handler, will receive node data as first argument
+ & event as second one. The node data has the following shape:
+
+ \`\`\`
+ {
+ id: string | number,
+ value: number,
+ depth: number,
+ color: string,
+ name: string
+ loc: number
+ percentage: number
+ // the parent datum
+ ancestor: object
+ }
+ \`\`\`
+ `,
+ },
+ {
+ key: 'onWheel',
+ flavors: ['svg'],
+ group: 'Interactivity',
+ type: 'Function',
+ required: false,
+ help: 'onWheel handler',
+ description: `
+ onWheel handler, will receive node data as first argument
+ & event as second one. The node data has the following shape:
+
+ \`\`\`
+ {
+ id: string | number,
+ value: number,
+ depth: number,
+ color: string,
+ name: string
+ loc: number
+ percentage: number
+ // the parent datum
+ ancestor: object
+ }
+ \`\`\`
+ `,
+ },
+ {
+ key: 'onContextMenu',
+ flavors: ['svg'],
+ group: 'Interactivity',
+ type: 'Function',
+ required: false,
+ help: 'onContextMenu handler',
+ description: `
+ onContextMenu handler, will receive node data as first argument
+ & event as second one. The node data has the following shape:
+
+ \`\`\`
+ {
+ id: string | number,
+ value: number,
+ depth: number,
+ color: string,
+ name: string
+ loc: number
+ percentage: number
+ // the parent datum
+ ancestor: object
+ }
+ \`\`\`
+ `,
+ },
+]
+
+export const groups = groupProperties(props)
diff --git a/website/src/data/nav.ts b/website/src/data/nav.ts
index c15bdea4e..75f17266c 100644
--- a/website/src/data/nav.ts
+++ b/website/src/data/nav.ts
@@ -10,6 +10,7 @@ import funnel from './components/funnel/meta.yml'
import geomap from './components/geomap/meta.yml'
import heatmap from './components/heatmap/meta.yml'
import line from './components/line/meta.yml'
+import icicles from './components/icicles/meta.yml'
import marimekko from './components/marimekko/meta.yml'
import network from './components/network/meta.yml'
import parallelCoordinates from './components/parallel-coordinates/meta.yml'
@@ -129,6 +130,15 @@ export const components: ChartNavData[] = [
api: true,
},
},
+ {
+ name: 'Icicles',
+ id: 'icicles',
+ tags: icicles.Icicles.tags,
+ flavors: {
+ svg: true,
+ api: true,
+ },
+ },
{
name: 'Line',
id: 'line',
diff --git a/website/src/pages/icicles/api.tsx b/website/src/pages/icicles/api.tsx
new file mode 100644
index 000000000..6b917b2de
--- /dev/null
+++ b/website/src/pages/icicles/api.tsx
@@ -0,0 +1,81 @@
+import React from 'react'
+import { generateLibTree } from '@nivo/generators'
+import { Seo } from '../../components/Seo'
+import { ApiClient } from '../../components/components/api-client/ApiClient'
+import { groups } from '../../data/components/icicles/props'
+import mapper from '../../data/components/icicles/mapper'
+import meta from '../../data/components/icicles/meta.yml'
+import { graphql, useStaticQuery } from 'gatsby'
+
+const data = generateLibTree()
+
+const IciclesApi = () => {
+ const {
+ image: {
+ childImageSharp: { gatsbyImageData: image },
+ },
+ // TODO: change with icicles capture
+ } = useStaticQuery(graphql`
+ query {
+ image: file(absolutePath: { glob: "**/src/assets/captures/sunburst.png" }) {
+ childImageSharp {
+ gatsbyImageData(layout: FIXED, width: 700, quality: 100)
+ }
+ }
+ }
+ `)
+
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export default IciclesApi
diff --git a/website/src/pages/icicles/index.js b/website/src/pages/icicles/index.js
new file mode 100644
index 000000000..d15f91f56
--- /dev/null
+++ b/website/src/pages/icicles/index.js
@@ -0,0 +1,113 @@
+import React from 'react'
+import { defaultProps, ResponsiveIcicles } from '@nivo/icicles'
+import { generateLibTree } from '@nivo/generators'
+import { omit } from 'lodash'
+import { ComponentTemplate } from '../../components/components/ComponentTemplate'
+import meta from '../../data/components/icicles/meta.yml'
+import mapper from '../../data/components/icicles/mapper'
+import { groups } from '../../data/components/icicles/props'
+import { graphql, useStaticQuery } from 'gatsby'
+
+const Tooltip = () => {
+ /* return custom tooltip */
+}
+
+const generateData = () => generateLibTree()
+
+const initialProperties = {
+ margin: {
+ top: 10,
+ right: 10,
+ bottom: 10,
+ left: 10,
+ },
+ id: 'name',
+ value: 'loc',
+ valueFormat: { format: '', enabled: false },
+ borderWidth: 1,
+ borderColor: { theme: 'background' },
+ colors: { scheme: 'nivo' },
+ colorBy: 'id',
+ inheritColorFromParent: true,
+ childColor: {
+ from: 'color',
+ modifiers: [['brighter', 0.1]],
+ },
+ enableRectLabels: true,
+ rectLabel: 'formattedValue',
+ rectLabelsTextColor: {
+ from: 'color',
+ modifiers: [['darker', 1.4]],
+ },
+ animate: defaultProps.animate,
+ motionConfig: defaultProps.motionConfig,
+ defs: [],
+ fill: [],
+ isInteractive: true,
+ 'custom tooltip example': false,
+ tooltip: null,
+ 'showcase pattern usage': false,
+ direction: 'bottom',
+ rectLabelsSkipLength: defaultProps.rectLabelsSkipLength,
+ rectLabelsSkipPercentage: defaultProps.rectLabelsSkipPercentage,
+ rectLabelsOffset: defaultProps.rectLabelsOffset,
+}
+
+const Icicles = () => {
+ const {
+ image: {
+ childImageSharp: { gatsbyImageData: image },
+ },
+ // TODO: change with icicles capture
+ } = useStaticQuery(graphql`
+ query {
+ image: file(absolutePath: { glob: "**/src/assets/captures/sunburst.png" }) {
+ childImageSharp {
+ gatsbyImageData(layout: FIXED, width: 700, quality: 100)
+ }
+ }
+ }
+ `)
+
+ return (
+
+ {(properties, data, theme, logAction) => {
+ return (
+
+ logAction({
+ type: 'click',
+ label: `[icicles] ${node.id} - ${node.value}: ${
+ Math.round(node.percentage * 100) / 100
+ }%`,
+ color: node.color,
+ // prevent cyclic dependency
+ data: {
+ ...omit(node, ['parent']),
+ parent: omit(node.parent, ['data', 'parent', 'children']),
+ },
+ })
+ }
+ />
+ )
+ }}
+
+ )
+}
+
+export default Icicles
diff --git a/website/src/pages/internal/home-demos.tsx b/website/src/pages/internal/home-demos.tsx
index 966f266f2..860e6b655 100644
--- a/website/src/pages/internal/home-demos.tsx
+++ b/website/src/pages/internal/home-demos.tsx
@@ -15,7 +15,7 @@ import {
HomeRadialBarDemo,
HomeSankeyDemo,
HomeStreamDemo,
- HomeSunburstDemo,
+ HomeIciclesDemo,
HomeSwarmPlotDemo,
HomeTreeMapDemo,
HomeVoronoiDemo,
@@ -38,7 +38,7 @@ const HomeDemosPage = () => (
-
+