diff --git a/packages/sankey/index.d.ts b/packages/sankey/index.d.ts
index 624def5cd..227966273 100644
--- a/packages/sankey/index.d.ts
+++ b/packages/sankey/index.d.ts
@@ -40,6 +40,8 @@ declare module '@nivo/sankey' {
| 'color'
| 'luminosity'
+ export type SankeySortFunction = (nodeA: SankeyDataNode, nodeB: SankeyDataNode) => number
+
export type SankeyProps = Partial<{
align: 'center' | 'justify' | 'left' | 'right'
@@ -77,7 +79,7 @@ declare module '@nivo/sankey' {
legends: LegendProps[]
- sort?: (nodeA: SankeyDataNode, nodeB: SankeyDataNode) => number
+ sort: 'auto' | 'input' | 'ascending' | 'descending' | SankeySortFunction
}>
interface Dimensions {
diff --git a/packages/sankey/package.json b/packages/sankey/package.json
index 6abc5d46c..404b1b5ea 100644
--- a/packages/sankey/package.json
+++ b/packages/sankey/package.json
@@ -25,7 +25,7 @@
"dependencies": {
"@nivo/core": "0.53.0",
"@nivo/legends": "0.53.0",
- "d3-sankey": "0.12.1",
+ "d3-sankey": "^0.12.1",
"lodash": "^4.17.4",
"react-motion": "^0.5.2",
"recompose": "^0.30.0"
diff --git a/packages/sankey/src/Sankey.js b/packages/sankey/src/Sankey.js
index 2b4ee2b31..66d662f16 100644
--- a/packages/sankey/src/Sankey.js
+++ b/packages/sankey/src/Sankey.js
@@ -24,6 +24,7 @@ const Sankey = ({
data: _data,
align,
+ sortFunction,
margin,
width,
@@ -74,12 +75,10 @@ const Sankey = ({
tooltipFormat,
legends,
-
- sort,
}) => {
const sankey = d3Sankey()
- .nodeSort(sort)
.nodeAlign(sankeyAlignmentFromProp(align))
+ .nodeSort(sortFunction)
.nodeWidth(nodeWidth)
.nodePadding(nodePaddingY)
.size([width, height])
diff --git a/packages/sankey/src/enhance.js b/packages/sankey/src/enhance.js
index b65b26f58..f06d66b4f 100644
--- a/packages/sankey/src/enhance.js
+++ b/packages/sankey/src/enhance.js
@@ -38,5 +38,17 @@ export default Component =>
withPropsOnChange(['label', 'labelFormat'], ({ label, labelFormat }) => ({
getLabel: getLabelGenerator(label, labelFormat),
})),
+ withPropsOnChange(['sort'], ({ sort }) => {
+ let sortFunction
+ if (sort === 'input') {
+ sortFunction = null
+ } else if (sort === 'ascending') {
+ sortFunction = (a, b) => a.value - b.value
+ } else if (sort === 'descending') {
+ sortFunction = (a, b) => b.value - a.value
+ }
+
+ return { sortFunction }
+ }),
pure
)(Component)
diff --git a/packages/sankey/src/props.js b/packages/sankey/src/props.js
index 4ae8f481f..72c3b9f54 100644
--- a/packages/sankey/src/props.js
+++ b/packages/sankey/src/props.js
@@ -40,6 +40,10 @@ export const SankeyPropTypes = {
}).isRequired,
align: sankeyAlignmentPropType.isRequired,
+ sort: PropTypes.oneOfType([
+ PropTypes.oneOf(['auto', 'input', 'ascending', 'descending']),
+ PropTypes.func,
+ ]).isRequired,
nodeOpacity: PropTypes.number.isRequired,
nodeHoverOpacity: PropTypes.number.isRequired,
@@ -79,6 +83,7 @@ export const SankeyPropTypes = {
export const SankeyDefaultProps = {
align: 'center',
+ sort: 'auto',
nodeOpacity: 0.75,
nodeHoverOpacity: 1,
diff --git a/website/src/components/charts/sankey/Sankey.js b/website/src/components/charts/sankey/Sankey.js
index 797b634e2..31f97e04b 100644
--- a/website/src/components/charts/sankey/Sankey.js
+++ b/website/src/components/charts/sankey/Sankey.js
@@ -6,10 +6,10 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-import React, { Component } from 'react'
+import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import MediaQuery from 'react-responsive'
-import { ResponsiveSankey, SankeyDefaultProps as defaults } from '@nivo/sankey'
+import { ResponsiveSankey, SankeyDefaultProps } from '@nivo/sankey'
import ChartHeader from '../../ChartHeader'
import ChartTabs from '../../ChartTabs'
import SankeyControls from './SankeyControls'
@@ -20,193 +20,166 @@ import config from '../../../config'
import nivoTheme from '../../../nivoTheme'
import propsMapper from './propsMapper'
-export default class Sankey extends Component {
- state = {
- settings: {
- margin: {
- top: 40,
- right: 160,
- bottom: 40,
- left: 50,
- },
+const initialSettings = {
+ margin: {
+ top: 40,
+ right: 160,
+ bottom: 40,
+ left: 50,
+ },
- align: 'justify',
- colors: 'category10',
+ align: 'justify',
+ sort: 'auto',
+ colors: 'category10',
- // nodes
- nodeOpacity: 1,
- nodeHoverOpacity: 1,
- nodeWidth: 18,
- nodePaddingX: 0,
- nodePaddingY: 12,
- nodeBorderWidth: 1,
- nodeBorderColor: {
- type: 'inherit:darker',
- gamma: 0.8,
- },
+ nodeOpacity: 1,
+ nodeHoverOpacity: 1,
+ nodeWidth: 18,
+ nodePaddingX: 0,
+ nodePaddingY: 12,
+ nodeBorderWidth: 1,
+ nodeBorderColor: {
+ type: 'inherit:darker',
+ gamma: 0.8,
+ },
- // links
- linkOpacity: 0.25,
- linkHoverOpacity: 0.6,
- linkHoverOthersOpacity: 0.1,
- linkContract: 0,
- linkBlendMode: 'multiply',
- enableLinkGradient: true,
+ linkOpacity: 0.25,
+ linkHoverOpacity: 0.6,
+ linkHoverOthersOpacity: 0.1,
+ linkContract: 0,
+ linkBlendMode: 'multiply',
+ enableLinkGradient: true,
- // labels
- enableLabels: true,
- labelPosition: 'outside',
- labelOrientation: 'vertical',
- labelPadding: 16,
- labelTextColor: {
- type: 'inherit:darker',
- gamma: 1,
- },
+ enableLabels: true,
+ labelPosition: 'outside',
+ labelOrientation: 'vertical',
+ labelPadding: 16,
+ labelTextColor: {
+ type: 'inherit:darker',
+ gamma: 1,
+ },
- // motion
- animate: true,
- motionStiffness: 120,
- motionDamping: 11,
+ animate: true,
+ motionStiffness: 120,
+ motionDamping: 11,
- // interactivity
- isInteractive: true,
+ isInteractive: true,
- legends: [
+ legends: [
+ {
+ anchor: 'bottom-right',
+ direction: 'column',
+ translateX: 130,
+ itemWidth: 100,
+ itemHeight: 14,
+ itemDirection: 'right-to-left',
+ itemsSpacing: 2,
+ itemTextColor: '#999',
+ symbolSize: 14,
+ onClick: d => {
+ alert(JSON.stringify(d, null, ' '))
+ },
+ effects: [
{
- anchor: 'bottom-right',
- direction: 'column',
- translateX: 130,
- itemWidth: 100,
- itemHeight: 14,
- itemDirection: 'right-to-left',
- itemsSpacing: 2,
- itemTextColor: '#999',
- symbolSize: 14,
- onClick: d => {
- alert(JSON.stringify(d, null, ' '))
+ on: 'hover',
+ style: {
+ itemTextColor: '#000',
},
- effects: [
- {
- on: 'hover',
- style: {
- itemTextColor: '#000',
- },
- },
- ],
},
],
},
- }
+ ],
+}
- handleSettingsUpdate = settings => {
- this.setState({ settings })
- }
+const Sankey = ({ data, randomizeLinkValues }) => {
+ const [settings, setSettings] = useState(initialSettings)
- render() {
- const { data, randomizeLinkValues } = this.props
- const { settings } = this.state
+ const mappedSettings = propsMapper(settings)
- const mappedSettings = propsMapper(settings)
+ const code = generateCode('ResponsiveSankey', mappedSettings, {
+ pkg: '@nivo/sankey',
+ defaults: SankeyDefaultProps,
+ })
- const code = generateCode('ResponsiveSankey', mappedSettings, {
- pkg: '@nivo/sankey',
- defaults,
- })
+ const header =
+ Computes a sankey diagram from nodes and links, built on top of{' '}
+
+ d3-sankey
+
+ . The responsive alternative of this component is ResponsiveSankey
.
+
+ Please be careful with the data you use for this chart as it does not support cyclic
+ dependencies.
+
+ For example, something like A —> A
or A —> B —> C —> A
{' '}
+ will crash.
+
+ This component is available in the{' '} + + nivo-api + + , see{' '} + + sample + {' '} + or try it using the API client. You can also see more + example usages in{' '} + + the storybook + + . +
++ See the dedicated guide on how to setup legends + for this component. +
+
- Computes a sankey diagram from nodes and links, uses{' '}
-
- d3-sankey
-
- , see{' '}
-
- this block
-
- . The responsive alternative of this component is ResponsiveSankey
.
-
- Please be careful with the data you use for this chart as it does not support
- cyclic dependencies.
-
- For example, something like A —> A
or A —> B —> C —> A
{' '}
- will crash.
-
- This component is available in the{' '} - - nivo-api - - , see{' '} - - sample - {' '} - or try it using the API client. You can also see - more example usages in{' '} - - the storybook - - . -
-- See the dedicated guide on how to setup - legends for this component. -
+ return ( +'auto'
order of nodes within each
+ column is determined automatically by the layout.
+ 'input'
order is fixed by the input.
+ 'ascending'
node with lower values on
+ top.
+ 'descending'
node with higher values on
+ top.
+ (nodeA, nodeB) => number
+ mix-blend-mode
property for links, see{' '}
@@ -330,7 +381,7 @@ export default [
},
{
key: 'enableLinkGradient',
- scopes: '*',
+ scopes: ['Sankey'],
description: 'Enable/disable gradient from source/target nodes instead of plain color.',
type: '{boolean}',
required: false,
diff --git a/yarn.lock b/yarn.lock
index c11c11814..e44925e01 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -897,7 +897,7 @@
dependencies:
regenerator-runtime "^0.12.0"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.4":
version "7.4.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.2.tgz#f5ab6897320f16decd855eed70b705908a313fe8"
integrity sha512-7Bl2rALb7HpvXFL7TETNzKSAeBVCPHELzc0C//9FCxN8nsiueWSJBqaF+2oIJScyILStASR/Cx5WMkXGYTiJFA==
@@ -10809,7 +10809,7 @@ react-docgen@^3.0.0:
node-dir "^0.1.10"
recast "^0.16.0"
-react-dom@^16.8.1, react-dom@^16.8.4:
+react-dom@16.8.4, react-dom@^16.8.1, react-dom@^16.8.4:
version "16.8.4"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48"
integrity sha512-Ob2wK7XG2tUDt7ps7LtLzGYYB6DXMCLj0G5fO6WeEICtT4/HdpOi7W/xLzZnR6RCG1tYza60nMdqtxzA8FaPJQ==
@@ -10970,13 +10970,6 @@ react-select@^2.3.0:
react-input-autosize "^2.2.1"
react-transition-group "^2.2.1"
-react-spring@^8.0.18:
- version "8.0.18"
- resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.18.tgz#f6fa09ab5acdeb37618c0e340d59830171b95c33"
- integrity sha512-gb1Rtsnez2gxIHtbrbwQsAjE4ir/62m+gI+eT+1E0Uky5L1PbLccbywRIdIpK3W5jiNmU6OlEazVk0tfI8pZrA==
- dependencies:
- "@babel/runtime" "^7.3.1"
-
react-syntax-highlighter@^8.0.1:
version "8.1.0"
resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-8.1.0.tgz#59103ff17a828a27ed7c8f035ae2558f09b6b78c"
@@ -11016,7 +11009,7 @@ react-transition-group@^2.2.1:
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
-react@^16.8.1, react@^16.8.4:
+react@16.8.4, react@^16.8.1, react@^16.8.4:
version "16.8.4"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.4.tgz#fdf7bd9ae53f03a9c4cd1a371432c206be1c4768"
integrity sha512-0GQ6gFXfUH7aZcjGVymlPOASTuSjlQL4ZtVC5YKH+3JL6bBLCVO21DknzmaPlI90LN253ojj02nsapy+j7wIjg==
@@ -13073,7 +13066,7 @@ unzip-response@^2.0.1:
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
-upath@^1.1.0:
+upath@1.1.0, upath@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==