UNPKG

@nivo/sankey

Version:
1 lines 64.6 kB
{"version":3,"file":"nivo-sankey.mjs","sources":["../src/SankeyNodeTooltip.tsx","../src/SankeyLinkTooltip.tsx","../src/props.ts","../src/hooks.ts","../src/SankeyNodesItem.tsx","../src/SankeyNodes.tsx","../src/SankeyLinkGradient.tsx","../src/SankeyLinksItem.tsx","../src/SankeyLinks.tsx","../src/links.ts","../src/SankeyLabels.tsx","../src/Sankey.tsx","../src/ResponsiveSankey.tsx"],"sourcesContent":["import { BasicTooltip } from '@nivo/tooltip'\nimport { DefaultLink, DefaultNode, SankeyNodeDatum } from './types'\n\nexport interface SankeyNodeTooltipProps<N extends DefaultNode, L extends DefaultLink> {\n node: SankeyNodeDatum<N, L>\n}\n\nexport const SankeyNodeTooltip = <N extends DefaultNode, L extends DefaultLink>({\n node,\n}: SankeyNodeTooltipProps<N, L>) => (\n <BasicTooltip id={node.label} enableChip={true} color={node.color} />\n)\n","import { BasicTooltip, Chip } from '@nivo/tooltip'\nimport { DefaultLink, DefaultNode, SankeyLinkDatum } from './types'\n\nconst tooltipStyles = {\n container: {\n display: 'flex',\n alignItems: 'center',\n },\n sourceChip: {\n marginRight: 7,\n },\n targetChip: {\n marginLeft: 7,\n marginRight: 7,\n },\n}\n\nexport interface SankeyLinkTooltipProps<N extends DefaultNode, L extends DefaultLink> {\n link: SankeyLinkDatum<N, L>\n}\n\nexport const SankeyLinkTooltip = <N extends DefaultNode, L extends DefaultLink>({\n link,\n}: SankeyLinkTooltipProps<N, L>) => (\n <BasicTooltip\n id={\n <span style={tooltipStyles.container}>\n <Chip color={link.source.color} style={tooltipStyles.sourceChip} />\n <strong>{link.source.label}</strong>\n {' > '}\n <strong>{link.target.label}</strong>\n <Chip color={link.target.color} style={tooltipStyles.targetChip} />\n <strong>{link.formattedValue}</strong>\n </span>\n }\n />\n)\n","import { sankeyCenter, sankeyJustify, sankeyLeft, sankeyRight } from 'd3-sankey'\nimport { SankeyLayerId, SankeyNodeDatum, SankeyAlignType } from './types'\nimport { InheritedColorConfig } from '@nivo/colors'\nimport { Text } from '@nivo/text'\nimport { SankeyNodeTooltip } from './SankeyNodeTooltip'\nimport { SankeyLinkTooltip } from './SankeyLinkTooltip'\n\nexport const sankeyAlignmentPropMapping = {\n center: sankeyCenter,\n justify: sankeyJustify,\n start: sankeyLeft,\n end: sankeyRight,\n}\n\nexport const sankeyAlignmentPropKeys = Object.keys(sankeyAlignmentPropMapping) as SankeyAlignType[]\n\nexport const sankeyAlignmentFromProp = (prop: SankeyAlignType) => sankeyAlignmentPropMapping[prop]\n\nexport const svgDefaultProps = {\n layout: 'horizontal' as const,\n align: 'center' as const,\n sort: 'auto' as const,\n\n colors: { scheme: 'nivo' as const },\n\n nodeOpacity: 0.75,\n nodeHoverOpacity: 1,\n nodeHoverOthersOpacity: 0.15,\n nodeThickness: 12,\n nodeSpacing: 12,\n nodeInnerPadding: 0,\n nodeBorderWidth: 1,\n nodeBorderColor: { from: 'color', modifiers: [['darker', 0.5]] } as InheritedColorConfig<\n SankeyNodeDatum<any, any>\n >,\n nodeBorderRadius: 0,\n\n linkOpacity: 0.25,\n linkHoverOpacity: 0.6,\n linkHoverOthersOpacity: 0.15,\n linkContract: 0,\n linkBlendMode: 'multiply' as const,\n enableLinkGradient: false,\n\n enableLabels: true,\n label: 'id',\n labelPosition: 'inside' as const,\n labelPadding: 9,\n labelOrientation: 'horizontal' as const,\n labelTextColor: { from: 'color', modifiers: [['darker', 0.8]] } as InheritedColorConfig<\n SankeyNodeDatum<any, any>\n >,\n labelComponent: Text,\n\n isInteractive: true,\n nodeTooltip: SankeyNodeTooltip,\n linkTooltip: SankeyLinkTooltip,\n\n legends: [],\n\n layers: ['links', 'nodes', 'labels', 'legends'] as SankeyLayerId[],\n\n role: 'img',\n\n animate: true,\n motionConfig: 'gentle',\n}\n","import { useState, useMemo } from 'react'\nimport cloneDeep from 'lodash/cloneDeep.js'\nimport { sankey as d3Sankey } from 'd3-sankey'\nimport { usePropertyAccessor, useValueFormatter } from '@nivo/core'\nimport { useTheme } from '@nivo/theming'\nimport { useOrdinalColorScale, useInheritedColor } from '@nivo/colors'\nimport { sankeyAlignmentFromProp } from './props'\nimport {\n DefaultLink,\n DefaultNode,\n SankeyAlignFunction,\n SankeyCommonProps,\n SankeyDataProps,\n SankeyLinkDatum,\n SankeyNodeDatum,\n SankeySortFunction,\n} from './types'\n\nconst getId = <N extends DefaultNode>(node: N) => node.id\n\nexport const computeNodeAndLinks = <N extends DefaultNode, L extends DefaultLink>({\n data: _data,\n formatValue,\n layout,\n alignFunction,\n sortFunction,\n linkSortMode,\n nodeThickness,\n nodeSpacing,\n nodeInnerPadding,\n width,\n height,\n getColor,\n getLabel,\n}: {\n data: SankeyDataProps<N, L>['data']\n formatValue: (value: number) => string\n layout: SankeyCommonProps<N, L>['layout']\n alignFunction: SankeyAlignFunction\n sortFunction: null | undefined | SankeySortFunction<N, L>\n linkSortMode: null | undefined\n nodeThickness: SankeyCommonProps<N, L>['nodeThickness']\n nodeSpacing: SankeyCommonProps<N, L>['nodeSpacing']\n nodeInnerPadding: SankeyCommonProps<N, L>['nodeInnerPadding']\n width: number\n height: number\n getColor: (node: Omit<SankeyNodeDatum<N, L>, 'color' | 'label'>) => string\n getLabel: (node: Omit<SankeyNodeDatum<N, L>, 'color' | 'label'>) => string\n}) => {\n const sankey = d3Sankey()\n .nodeAlign(alignFunction)\n // @ts-expect-error: this method signature is incorrect in current @types/d3-sankey\n .nodeSort(sortFunction)\n // @ts-expect-error: this method is not available in current @types/d3-sankey\n .linkSort(linkSortMode)\n .nodeWidth(nodeThickness)\n .nodePadding(nodeSpacing)\n .size(layout === 'horizontal' ? [width, height] : [height, width])\n .nodeId(getId)\n\n // deep clone is required as the sankey diagram mutates data\n // we need a different identity for correct updates\n const data = cloneDeep(_data) as unknown as {\n nodes: SankeyNodeDatum<N, L>[]\n links: SankeyLinkDatum<N, L>[]\n }\n sankey(data)\n\n data.nodes.forEach(node => {\n node.color = getColor(node)\n node.label = getLabel(node)\n node.formattedValue = formatValue(node.value)\n\n if (layout === 'horizontal') {\n node.x = node.x0 + nodeInnerPadding\n node.y = node.y0\n node.width = Math.max(node.x1 - node.x0 - nodeInnerPadding * 2, 0)\n node.height = Math.max(node.y1 - node.y0, 0)\n } else {\n node.x = node.y0\n node.y = node.x0 + nodeInnerPadding\n node.width = Math.max(node.y1 - node.y0, 0)\n node.height = Math.max(node.x1 - node.x0 - nodeInnerPadding * 2, 0)\n\n const oldX0 = node.x0\n const oldX1 = node.x1\n\n node.x0 = node.y0\n node.x1 = node.y1\n node.y0 = oldX0\n node.y1 = oldX1\n }\n })\n\n data.links.forEach(link => {\n link.formattedValue = formatValue(link.value)\n link.color = link.source.color\n // @ts-expect-error: @types/d3-sankey\n link.pos0 = link.y0\n // @ts-expect-error: @types/d3-sankey\n link.pos1 = link.y1\n // @ts-expect-error: @types/d3-sankey\n link.thickness = link.width\n // @ts-expect-error: @types/d3-sankey\n delete link.y0\n // @ts-expect-error: @types/d3-sankey\n delete link.y1\n // @ts-expect-error: @types/d3-sankey\n delete link.width\n })\n\n return data\n}\n\nexport const useSankey = <N extends DefaultNode, L extends DefaultLink>({\n data,\n valueFormat,\n layout,\n width,\n height,\n sort,\n align,\n colors,\n nodeThickness,\n nodeSpacing,\n nodeInnerPadding,\n nodeBorderColor,\n label,\n labelTextColor,\n}: {\n data: SankeyDataProps<N, L>['data']\n valueFormat?: SankeyCommonProps<N, L>['valueFormat']\n layout: SankeyCommonProps<N, L>['layout']\n width: number\n height: number\n sort: SankeyCommonProps<N, L>['sort']\n align: SankeyCommonProps<N, L>['align']\n colors: SankeyCommonProps<N, L>['colors']\n nodeThickness: SankeyCommonProps<N, L>['nodeThickness']\n nodeSpacing: SankeyCommonProps<N, L>['nodeSpacing']\n nodeInnerPadding: SankeyCommonProps<N, L>['nodeInnerPadding']\n nodeBorderColor: SankeyCommonProps<N, L>['nodeBorderColor']\n label: SankeyCommonProps<N, L>['label']\n labelTextColor: SankeyCommonProps<N, L>['labelTextColor']\n}) => {\n const [currentNode, setCurrentNode] = useState<SankeyNodeDatum<N, L> | null>(null)\n const [currentLink, setCurrentLink] = useState<SankeyLinkDatum<N, L> | null>(null)\n\n const sortFunction = useMemo(() => {\n if (sort === 'auto') return undefined\n if (sort === 'input') return null\n if (sort === 'ascending') {\n return (a: SankeyNodeDatum<N, L>, b: SankeyNodeDatum<N, L>) => a.value - b.value\n }\n if (sort === 'descending') {\n return (a: SankeyNodeDatum<N, L>, b: SankeyNodeDatum<N, L>) => b.value - a.value\n }\n\n return sort\n }, [sort])\n\n // If \"input\" sorting is used, apply this setting to links, too.\n // (In d3, `null` means input sorting and `undefined` is the default)\n const linkSortMode = sort === 'input' ? null : undefined\n\n const alignFunction = useMemo(() => {\n if (typeof align === 'function') return align\n return sankeyAlignmentFromProp(align)\n }, [align])\n\n const theme = useTheme()\n\n const getColor = useOrdinalColorScale(colors, 'id')\n const getNodeBorderColor = useInheritedColor(nodeBorderColor, theme)\n\n const getLabel = usePropertyAccessor<Omit<SankeyNodeDatum<N, L>, 'color' | 'label'>, string>(\n label\n )\n const getLabelTextColor = useInheritedColor(labelTextColor, theme)\n const formatValue = useValueFormatter<number>(valueFormat)\n\n const { nodes, links } = useMemo(\n () =>\n computeNodeAndLinks<N, L>({\n data,\n formatValue,\n layout,\n alignFunction,\n sortFunction,\n linkSortMode,\n nodeThickness,\n nodeSpacing,\n nodeInnerPadding,\n width,\n height,\n getColor,\n getLabel,\n }),\n [\n data,\n formatValue,\n layout,\n alignFunction,\n sortFunction,\n linkSortMode,\n nodeThickness,\n nodeSpacing,\n nodeInnerPadding,\n width,\n height,\n getColor,\n getLabel,\n ]\n )\n\n const legendData = useMemo(\n () =>\n nodes.map(node => ({\n id: node.id,\n label: node.label,\n color: node.color,\n })),\n [nodes]\n )\n\n return {\n nodes,\n links,\n legendData,\n getNodeBorderColor,\n currentNode,\n setCurrentNode,\n currentLink,\n setCurrentLink,\n getLabelTextColor,\n }\n}\n","import { createElement, useCallback, MouseEvent } from 'react'\nimport { useSpring, animated } from '@react-spring/web'\nimport { useMotionConfig } from '@nivo/core'\nimport { useTooltip } from '@nivo/tooltip'\nimport { DefaultLink, DefaultNode, SankeyCommonProps, SankeyNodeDatum } from './types'\n\ninterface SankeyNodesItemProps<N extends DefaultNode, L extends DefaultLink> {\n node: SankeyNodeDatum<N, L>\n x: number\n y: number\n width: number\n height: number\n color: string\n opacity: number\n borderWidth: SankeyCommonProps<N, L>['nodeBorderWidth']\n borderColor: string\n borderRadius: SankeyCommonProps<N, L>['nodeBorderRadius']\n setCurrent: (node: SankeyNodeDatum<N, L> | null) => void\n isInteractive: SankeyCommonProps<N, L>['isInteractive']\n onClick?: SankeyCommonProps<N, L>['onClick']\n tooltip: SankeyCommonProps<N, L>['nodeTooltip']\n}\n\nexport const SankeyNodesItem = <N extends DefaultNode, L extends DefaultLink>({\n node,\n x,\n y,\n width,\n height,\n color,\n opacity,\n borderWidth,\n borderColor,\n borderRadius,\n setCurrent,\n isInteractive,\n onClick,\n tooltip,\n}: SankeyNodesItemProps<N, L>) => {\n const { animate, config: springConfig } = useMotionConfig()\n const animatedProps = useSpring({\n x,\n y,\n width,\n height,\n opacity,\n color,\n config: springConfig,\n immediate: !animate,\n })\n\n const { showTooltipFromEvent, hideTooltip } = useTooltip()\n\n const handleMouseEnter = useCallback(\n (event: MouseEvent<SVGRectElement>) => {\n setCurrent(node)\n showTooltipFromEvent(createElement(tooltip, { node }), event, 'left')\n },\n [setCurrent, node, showTooltipFromEvent, tooltip]\n )\n\n const handleMouseMove = useCallback(\n (event: MouseEvent<SVGRectElement>) => {\n showTooltipFromEvent(createElement(tooltip, { node }), event, 'left')\n },\n [showTooltipFromEvent, node, tooltip]\n )\n\n const handleMouseLeave = useCallback(() => {\n setCurrent(null)\n hideTooltip()\n }, [setCurrent, hideTooltip])\n\n const handleClick = useCallback(\n (event: MouseEvent<SVGRectElement>) => {\n onClick?.(node, event)\n },\n [onClick, node]\n )\n\n return (\n <animated.rect\n x={animatedProps.x}\n y={animatedProps.y}\n rx={borderRadius}\n ry={borderRadius}\n width={animatedProps.width.to(v => Math.max(v, 0))}\n height={animatedProps.height.to(v => Math.max(v, 0))}\n fill={animatedProps.color}\n fillOpacity={animatedProps.opacity}\n strokeWidth={borderWidth}\n stroke={borderColor}\n strokeOpacity={opacity}\n onMouseEnter={isInteractive ? handleMouseEnter : undefined}\n onMouseMove={isInteractive ? handleMouseMove : undefined}\n onMouseLeave={isInteractive ? handleMouseLeave : undefined}\n onClick={isInteractive ? handleClick : undefined}\n />\n )\n}\n","import {\n DefaultLink,\n DefaultNode,\n SankeyCommonProps,\n SankeyLinkDatum,\n SankeyNodeDatum,\n} from './types'\nimport { SankeyNodesItem } from './SankeyNodesItem'\n\ninterface SankeyNodesProps<N extends DefaultNode, L extends DefaultLink> {\n nodes: SankeyNodeDatum<N, L>[]\n nodeOpacity: SankeyCommonProps<N, L>['nodeOpacity']\n nodeHoverOpacity: SankeyCommonProps<N, L>['nodeHoverOpacity']\n nodeHoverOthersOpacity: SankeyCommonProps<N, L>['nodeHoverOthersOpacity']\n borderWidth: SankeyCommonProps<N, L>['nodeBorderWidth']\n getBorderColor: (node: SankeyNodeDatum<N, L>) => string\n borderRadius: SankeyCommonProps<N, L>['nodeBorderRadius']\n setCurrentNode: (node: SankeyNodeDatum<N, L> | null) => void\n currentNode: SankeyNodeDatum<N, L> | null\n currentLink: SankeyLinkDatum<N, L> | null\n isCurrentNode: (node: SankeyNodeDatum<N, L>) => boolean\n isInteractive: SankeyCommonProps<N, L>['isInteractive']\n onClick?: SankeyCommonProps<N, L>['onClick']\n tooltip: SankeyCommonProps<N, L>['nodeTooltip']\n}\n\nexport const SankeyNodes = <N extends DefaultNode, L extends DefaultLink>({\n nodes,\n nodeOpacity,\n nodeHoverOpacity,\n nodeHoverOthersOpacity,\n borderWidth,\n getBorderColor,\n borderRadius,\n setCurrentNode,\n currentNode,\n currentLink,\n isCurrentNode,\n isInteractive,\n onClick,\n tooltip,\n}: SankeyNodesProps<N, L>) => {\n const getOpacity = (node: SankeyNodeDatum<N, L>) => {\n if (!currentNode && !currentLink) return nodeOpacity\n if (isCurrentNode(node)) return nodeHoverOpacity\n return nodeHoverOthersOpacity\n }\n\n return (\n <>\n {nodes.map(node => (\n <SankeyNodesItem<N, L>\n key={node.id}\n node={node}\n x={node.x}\n y={node.y}\n width={node.width}\n height={node.height}\n color={node.color}\n opacity={getOpacity(node)}\n borderWidth={borderWidth}\n borderColor={getBorderColor(node)}\n borderRadius={borderRadius}\n setCurrent={setCurrentNode}\n isInteractive={isInteractive}\n onClick={onClick}\n tooltip={tooltip}\n />\n ))}\n </>\n )\n}\n","import { SankeyCommonProps } from './types'\n\ninterface SankeyLinkGradientProps {\n id: string\n layout: SankeyCommonProps<any, any>['layout']\n startColor: string\n endColor: string\n}\n\nexport const SankeyLinkGradient = ({\n id,\n layout,\n startColor,\n endColor,\n}: SankeyLinkGradientProps) => {\n let gradientProps: {\n x1: string\n x2: string\n y1: string\n y2: string\n }\n if (layout === 'horizontal') {\n gradientProps = {\n x1: '0%',\n x2: '100%',\n y1: '0%',\n y2: '0%',\n }\n } else {\n gradientProps = {\n x1: '0%',\n x2: '0%',\n y1: '0%',\n y2: '100%',\n }\n }\n\n return (\n <linearGradient id={id} spreadMethod=\"pad\" {...gradientProps}>\n <stop offset=\"0%\" stopColor={startColor} />\n <stop offset=\"100%\" stopColor={endColor} />\n </linearGradient>\n )\n}\n","import { createElement, useCallback, MouseEvent } from 'react'\nimport { useSpring, animated } from '@react-spring/web'\nimport { useAnimatedPath, useMotionConfig } from '@nivo/core'\nimport { useTooltip } from '@nivo/tooltip'\nimport { SankeyLinkGradient } from './SankeyLinkGradient'\nimport { DefaultLink, DefaultNode, SankeyCommonProps, SankeyLinkDatum } from './types'\n\ninterface SankeyLinksItemProps<N extends DefaultNode, L extends DefaultLink> {\n link: SankeyLinkDatum<N, L>\n layout: SankeyCommonProps<N, L>['layout']\n path: string\n color: string\n opacity: number\n blendMode: SankeyCommonProps<N, L>['linkBlendMode']\n enableGradient: SankeyCommonProps<N, L>['enableLinkGradient']\n setCurrent: (link: SankeyLinkDatum<N, L> | null) => void\n isInteractive: SankeyCommonProps<N, L>['isInteractive']\n onClick?: SankeyCommonProps<N, L>['onClick']\n tooltip: SankeyCommonProps<N, L>['linkTooltip']\n}\n\nexport const SankeyLinksItem = <N extends DefaultNode, L extends DefaultLink>({\n link,\n layout,\n path,\n color,\n opacity,\n blendMode,\n enableGradient,\n setCurrent,\n tooltip,\n isInteractive,\n onClick,\n}: SankeyLinksItemProps<N, L>) => {\n const linkId = `${link.source.id}.${link.target.id}.${link.index}`\n\n const { animate, config: springConfig } = useMotionConfig()\n const animatedPath = useAnimatedPath(path)\n const animatedProps = useSpring({\n color,\n opacity,\n config: springConfig,\n immediate: !animate,\n })\n\n const { showTooltipFromEvent, hideTooltip } = useTooltip()\n\n const handleMouseEnter = useCallback(\n (event: MouseEvent<SVGPathElement>) => {\n setCurrent(link)\n showTooltipFromEvent(createElement(tooltip, { link }), event, 'left')\n },\n [setCurrent, link, showTooltipFromEvent, tooltip]\n )\n\n const handleMouseMove = useCallback(\n (event: MouseEvent<SVGPathElement>) => {\n showTooltipFromEvent(createElement(tooltip, { link }), event, 'left')\n },\n [showTooltipFromEvent, link, tooltip]\n )\n\n const handleMouseLeave = useCallback(() => {\n setCurrent(null)\n hideTooltip()\n }, [setCurrent, hideTooltip])\n\n const handleClick = useCallback(\n (event: MouseEvent<SVGPathElement>) => {\n onClick?.(link, event)\n },\n [onClick, link]\n )\n\n return (\n <>\n {enableGradient && (\n <SankeyLinkGradient\n id={linkId}\n layout={layout}\n startColor={link.startColor || link.source.color}\n endColor={link.endColor || link.target.color}\n />\n )}\n <animated.path\n fill={enableGradient ? `url(\"#${encodeURI(linkId)}\")` : animatedProps.color}\n d={animatedPath}\n fillOpacity={animatedProps.opacity}\n onMouseEnter={isInteractive ? handleMouseEnter : undefined}\n onMouseMove={isInteractive ? handleMouseMove : undefined}\n onMouseLeave={isInteractive ? handleMouseLeave : undefined}\n onClick={isInteractive ? handleClick : undefined}\n style={{ mixBlendMode: blendMode }}\n />\n </>\n )\n}\n","import { sankeyLinkHorizontal, sankeyLinkVertical } from './links'\nimport {\n DefaultLink,\n DefaultNode,\n SankeyCommonProps,\n SankeyLinkDatum,\n SankeyNodeDatum,\n} from './types'\nimport { SankeyLinksItem } from './SankeyLinksItem'\nimport { useMemo } from 'react'\n\ninterface SankeyLinksProps<N extends DefaultNode, L extends DefaultLink> {\n layout: SankeyCommonProps<N, L>['layout']\n links: SankeyLinkDatum<N, L>[]\n linkOpacity: SankeyCommonProps<N, L>['linkOpacity']\n linkHoverOpacity: SankeyCommonProps<N, L>['linkHoverOpacity']\n linkHoverOthersOpacity: SankeyCommonProps<N, L>['linkHoverOthersOpacity']\n linkContract: SankeyCommonProps<N, L>['linkContract']\n linkBlendMode: SankeyCommonProps<N, L>['linkBlendMode']\n enableLinkGradient: SankeyCommonProps<N, L>['enableLinkGradient']\n tooltip: SankeyCommonProps<N, L>['linkTooltip']\n setCurrentLink: (link: SankeyLinkDatum<N, L> | null) => void\n currentLink: SankeyLinkDatum<N, L> | null\n currentNode: SankeyNodeDatum<N, L> | null\n isCurrentLink: (link: SankeyLinkDatum<N, L>) => boolean\n isInteractive: SankeyCommonProps<N, L>['isInteractive']\n onClick?: SankeyCommonProps<N, L>['onClick']\n}\n\nexport const SankeyLinks = <N extends DefaultNode, L extends DefaultLink>({\n links,\n layout,\n linkOpacity,\n linkHoverOpacity,\n linkHoverOthersOpacity,\n linkContract,\n linkBlendMode,\n enableLinkGradient,\n setCurrentLink,\n currentLink,\n currentNode,\n isCurrentLink,\n isInteractive,\n onClick,\n tooltip,\n}: SankeyLinksProps<N, L>) => {\n const getOpacity = (link: SankeyLinkDatum<N, L>) => {\n if (!currentNode && !currentLink) return linkOpacity\n if (isCurrentLink(link)) return linkHoverOpacity\n return linkHoverOthersOpacity\n }\n\n const getLinkPath = useMemo(\n () => (layout === 'horizontal' ? sankeyLinkHorizontal() : sankeyLinkVertical()),\n [layout]\n )\n\n return (\n <>\n {links.map(link => (\n <SankeyLinksItem<N, L>\n key={`${link.source.id}.${link.target.id}.${link.index}`}\n link={link}\n layout={layout}\n path={getLinkPath(link, linkContract)}\n color={link.color}\n opacity={getOpacity(link)}\n blendMode={linkBlendMode}\n enableGradient={enableLinkGradient}\n setCurrent={setCurrentLink}\n isInteractive={isInteractive}\n onClick={onClick}\n tooltip={tooltip}\n />\n ))}\n </>\n )\n}\n","import { line, curveMonotoneX, curveMonotoneY } from 'd3-shape'\nimport { DefaultLink, DefaultNode, SankeyLinkDatum } from './types'\n\nexport const sankeyLinkHorizontal = <N extends DefaultNode, L extends DefaultLink>() => {\n const lineGenerator = line().curve(curveMonotoneX)\n\n return (link: SankeyLinkDatum<N, L>, contract: number) => {\n const thickness = Math.max(1, link.thickness - contract * 2)\n const halfThickness = thickness / 2\n const linkLength = link.target.x0 - link.source.x1\n const padLength = linkLength * 0.12\n\n const dots: [number, number][] = [\n [link.source.x1, link.pos0 - halfThickness],\n [link.source.x1 + padLength, link.pos0 - halfThickness],\n [link.target.x0 - padLength, link.pos1 - halfThickness],\n [link.target.x0, link.pos1 - halfThickness],\n [link.target.x0, link.pos1 + halfThickness],\n [link.target.x0 - padLength, link.pos1 + halfThickness],\n [link.source.x1 + padLength, link.pos0 + halfThickness],\n [link.source.x1, link.pos0 + halfThickness],\n [link.source.x1, link.pos0 - halfThickness],\n ]\n\n return lineGenerator(dots) + 'Z'\n }\n}\n\nexport const sankeyLinkVertical = <N extends DefaultNode, L extends DefaultLink>() => {\n const lineGenerator = line().curve(curveMonotoneY)\n\n return (link: SankeyLinkDatum<N, L>, contract: number) => {\n const thickness = Math.max(1, link.thickness - contract * 2)\n const halfThickness = thickness / 2\n const linkLength = link.target.y0 - link.source.y1\n const padLength = linkLength * 0.12\n\n const dots: [number, number][] = [\n [link.pos0 + halfThickness, link.source.y1],\n [link.pos0 + halfThickness, link.source.y1 + padLength],\n [link.pos1 + halfThickness, link.target.y0 - padLength],\n [link.pos1 + halfThickness, link.target.y0],\n [link.pos1 - halfThickness, link.target.y0],\n [link.pos1 - halfThickness, link.target.y0 - padLength],\n [link.pos0 - halfThickness, link.source.y1 + padLength],\n [link.pos0 - halfThickness, link.source.y1],\n [link.pos0 + halfThickness, link.source.y1],\n ]\n\n return lineGenerator(dots) + 'Z'\n }\n}\n","import { useSprings } from '@react-spring/web'\nimport { useMotionConfig } from '@nivo/core'\nimport { useTheme } from '@nivo/theming'\nimport { DefaultLink, DefaultNode, SankeyCommonProps, SankeyNodeDatum } from './types'\n\ninterface SankeyLabelsProps<N extends DefaultNode, L extends DefaultLink> {\n nodes: SankeyNodeDatum<N, L>[]\n layout: SankeyCommonProps<N, L>['layout']\n width: number\n height: number\n labelComponent: SankeyCommonProps<N, L>['labelComponent']\n labelPosition: SankeyCommonProps<N, L>['labelPosition']\n labelPadding: SankeyCommonProps<N, L>['labelPadding']\n labelOrientation: SankeyCommonProps<N, L>['labelOrientation']\n getLabelTextColor: (node: SankeyNodeDatum<N, L>) => string\n}\n\nexport const SankeyLabels = <N extends DefaultNode, L extends DefaultLink>({\n nodes,\n layout,\n width,\n height,\n labelPosition,\n labelPadding,\n labelOrientation,\n getLabelTextColor,\n labelComponent: LabelComponent,\n}: SankeyLabelsProps<N, L>) => {\n const theme = useTheme()\n\n const labelRotation = labelOrientation === 'vertical' ? -90 : 0\n const labels = nodes.map(node => {\n let x\n let y\n let textAnchor: 'middle' | 'start' | 'end' | undefined\n if (layout === 'horizontal') {\n y = node.y + node.height / 2\n if (node.x < width / 2) {\n if (labelPosition === 'inside') {\n x = node.x1 + labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'middle' : 'start'\n } else {\n x = node.x - labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'middle' : 'end'\n }\n } else {\n if (labelPosition === 'inside') {\n x = node.x - labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'middle' : 'end'\n } else {\n x = node.x1 + labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'middle' : 'start'\n }\n }\n } else if (layout === 'vertical') {\n x = node.x + node.width / 2\n if (node.y < height / 2) {\n if (labelPosition === 'inside') {\n y = node.y1 + labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'end' : 'middle'\n } else {\n y = node.y - labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'start' : 'middle'\n }\n } else {\n if (labelPosition === 'inside') {\n y = node.y - labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'start' : 'middle'\n } else {\n y = node.y1 + labelPadding\n textAnchor = labelOrientation === 'vertical' ? 'end' : 'middle'\n }\n }\n }\n\n return {\n id: node.id,\n label: node.label,\n x,\n y,\n textAnchor,\n color: getLabelTextColor(node),\n }\n })\n\n const { animate, config: springConfig } = useMotionConfig()\n const springs = useSprings(\n labels.length,\n labels.map(label => ({\n transform: `translate(${label.x}, ${label.y}) rotate(${labelRotation})`,\n color: label.color,\n config: springConfig,\n immediate: !animate,\n }))\n )\n\n return (\n <>\n {springs.map((animatedProps, index) => {\n const label = labels[index]\n\n return (\n <LabelComponent\n key={label.id}\n dominantBaseline=\"central\"\n textAnchor={label.textAnchor}\n transform={animatedProps.transform}\n style={{\n ...theme.labels.text,\n fill: animatedProps.color,\n pointerEvents: 'none',\n }}\n node={nodes[index]}\n >\n {label.label}\n </LabelComponent>\n )\n })}\n </>\n )\n}\n","import {\n createElement,\n ForwardedRef,\n forwardRef,\n Fragment,\n ReactElement,\n ReactNode,\n Ref,\n useMemo,\n} from 'react'\nimport uniq from 'lodash/uniq.js'\nimport { SvgWrapper, useDimensions, Container } from '@nivo/core'\nimport { BoxLegendSvg } from '@nivo/legends'\nimport { svgDefaultProps } from './props'\nimport { useSankey } from './hooks'\nimport { SankeyNodes } from './SankeyNodes'\nimport { SankeyLinks } from './SankeyLinks'\nimport { SankeyLabels } from './SankeyLabels'\nimport {\n DefaultLink,\n DefaultNode,\n SankeyLayerId,\n SankeyLinkDatum,\n SankeyNodeDatum,\n SankeySvgProps,\n} from './types'\n\ntype InnerSankeyProps<N extends DefaultNode, L extends DefaultLink> = Omit<\n SankeySvgProps<N, L>,\n 'animate' | 'motionConfig' | 'renderWrapper' | 'theme'\n>\n\nconst InnerSankey = <N extends DefaultNode, L extends DefaultLink>({\n data,\n valueFormat,\n layout = svgDefaultProps.layout,\n sort = svgDefaultProps.sort,\n align = svgDefaultProps.align,\n width,\n height,\n margin: partialMargin,\n colors = svgDefaultProps.colors,\n nodeThickness = svgDefaultProps.nodeThickness,\n nodeSpacing = svgDefaultProps.nodeThickness,\n nodeInnerPadding = svgDefaultProps.nodeInnerPadding,\n nodeBorderColor = svgDefaultProps.nodeBorderColor,\n nodeOpacity = svgDefaultProps.nodeOpacity,\n nodeHoverOpacity = svgDefaultProps.nodeHoverOpacity,\n nodeHoverOthersOpacity = svgDefaultProps.nodeHoverOthersOpacity,\n nodeBorderWidth = svgDefaultProps.nodeBorderWidth,\n nodeBorderRadius = svgDefaultProps.nodeBorderRadius,\n linkOpacity = svgDefaultProps.linkOpacity,\n linkHoverOpacity = svgDefaultProps.linkHoverOpacity,\n linkHoverOthersOpacity = svgDefaultProps.linkHoverOthersOpacity,\n linkContract = svgDefaultProps.linkContract,\n linkBlendMode = svgDefaultProps.linkBlendMode,\n enableLinkGradient = svgDefaultProps.enableLinkGradient,\n enableLabels = svgDefaultProps.enableLabels,\n labelComponent = svgDefaultProps.labelComponent,\n labelPosition = svgDefaultProps.labelPosition,\n labelPadding = svgDefaultProps.labelPadding,\n labelOrientation = svgDefaultProps.labelOrientation,\n label = svgDefaultProps.label,\n labelTextColor = svgDefaultProps.labelTextColor,\n nodeTooltip = svgDefaultProps.nodeTooltip,\n linkTooltip = svgDefaultProps.linkTooltip,\n isInteractive = svgDefaultProps.isInteractive,\n onClick,\n legends = svgDefaultProps.legends,\n layers = svgDefaultProps.layers,\n role = svgDefaultProps.role,\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy,\n forwardedRef,\n}: InnerSankeyProps<N, L> & {\n forwardedRef: Ref<SVGSVGElement>\n}) => {\n const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(\n width,\n height,\n partialMargin\n )\n\n const {\n nodes,\n links,\n legendData,\n getNodeBorderColor,\n currentNode,\n setCurrentNode,\n currentLink,\n setCurrentLink,\n getLabelTextColor,\n } = useSankey<N, L>({\n data,\n valueFormat,\n layout,\n width: innerWidth,\n height: innerHeight,\n sort,\n align,\n colors,\n nodeThickness,\n nodeSpacing,\n nodeInnerPadding,\n nodeBorderColor,\n label,\n labelTextColor,\n })\n\n const { isCurrentNode, isCurrentLink } = useMemo(() => {\n let isCurrentNode: (node: SankeyNodeDatum<N, L>) => boolean = () => false\n let isCurrentLink: (link: SankeyLinkDatum<N, L>) => boolean = () => false\n\n if (currentLink) {\n isCurrentNode = ({ id }) => id === currentLink.source.id || id === currentLink.target.id\n isCurrentLink = ({ source, target }) =>\n source.id === currentLink.source.id && target.id === currentLink.target.id\n }\n\n if (currentNode) {\n let currentNodeIds = [currentNode.id]\n links\n .filter(\n ({ source, target }) =>\n source.id === currentNode.id || target.id === currentNode.id\n )\n .forEach(({ source, target }) => {\n currentNodeIds.push(source.id)\n currentNodeIds.push(target.id)\n })\n currentNodeIds = uniq(currentNodeIds)\n\n isCurrentNode = ({ id }) => currentNodeIds.includes(id)\n isCurrentLink = ({ source, target }) =>\n source.id === currentNode.id || target.id === currentNode.id\n }\n\n return {\n isCurrentNode,\n isCurrentLink,\n }\n }, [currentLink, currentNode, links])\n\n const layerProps = useMemo(\n () => ({\n links,\n nodes,\n margin,\n width,\n height,\n outerWidth,\n outerHeight,\n currentNode,\n isCurrentNode,\n setCurrentNode,\n currentLink,\n isCurrentLink,\n setCurrentLink,\n isInteractive,\n }),\n [\n links,\n nodes,\n margin,\n width,\n height,\n outerWidth,\n outerHeight,\n currentNode,\n isCurrentNode,\n setCurrentNode,\n currentLink,\n isCurrentLink,\n setCurrentLink,\n isInteractive,\n ]\n )\n\n const layerById: Record<SankeyLayerId, ReactNode> = {\n links: null,\n nodes: null,\n labels: null,\n legends: null,\n }\n\n if (layers.includes('links')) {\n layerById.links = (\n <SankeyLinks<N, L>\n key=\"links\"\n links={links}\n layout={layout}\n linkContract={linkContract}\n linkOpacity={linkOpacity}\n linkHoverOpacity={linkHoverOpacity}\n linkHoverOthersOpacity={linkHoverOthersOpacity}\n linkBlendMode={linkBlendMode}\n enableLinkGradient={enableLinkGradient}\n setCurrentLink={setCurrentLink}\n currentNode={currentNode}\n currentLink={currentLink}\n isCurrentLink={isCurrentLink}\n isInteractive={isInteractive}\n onClick={onClick}\n tooltip={linkTooltip}\n />\n )\n }\n\n if (layers.includes('nodes')) {\n layerById.nodes = (\n <SankeyNodes<N, L>\n key=\"nodes\"\n nodes={nodes}\n nodeOpacity={nodeOpacity}\n nodeHoverOpacity={nodeHoverOpacity}\n nodeHoverOthersOpacity={nodeHoverOthersOpacity}\n borderWidth={nodeBorderWidth}\n borderRadius={nodeBorderRadius}\n getBorderColor={getNodeBorderColor}\n setCurrentNode={setCurrentNode}\n currentNode={currentNode}\n currentLink={currentLink}\n isCurrentNode={isCurrentNode}\n isInteractive={isInteractive}\n onClick={onClick}\n tooltip={nodeTooltip}\n />\n )\n }\n\n if (layers.includes('labels') && enableLabels) {\n layerById.labels = (\n <SankeyLabels<N, L>\n key=\"labels\"\n nodes={nodes}\n layout={layout}\n width={innerWidth}\n height={innerHeight}\n labelPosition={labelPosition}\n labelPadding={labelPadding}\n labelOrientation={labelOrientation}\n getLabelTextColor={getLabelTextColor}\n labelComponent={labelComponent}\n />\n )\n }\n\n if (layers.includes('legends')) {\n layerById.legends = (\n <Fragment key=\"legends\">\n {legends.map((legend, i) => (\n <BoxLegendSvg\n key={`legend${i}`}\n {...legend}\n containerWidth={innerWidth}\n containerHeight={innerHeight}\n data={legendData}\n />\n ))}\n </Fragment>\n )\n }\n\n return (\n <SvgWrapper\n width={outerWidth}\n height={outerHeight}\n margin={margin}\n role={role}\n ariaLabel={ariaLabel}\n ariaLabelledBy={ariaLabelledBy}\n ariaDescribedBy={ariaDescribedBy}\n ref={forwardedRef}\n >\n {layers.map((layer, i) => {\n if (typeof layer === 'function') {\n return <Fragment key={i}>{createElement(layer, layerProps)}</Fragment>\n }\n\n return layerById?.[layer] ?? null\n })}\n </SvgWrapper>\n )\n}\n\nexport const Sankey = forwardRef(\n <N extends DefaultNode = DefaultNode, L extends DefaultLink = DefaultLink>(\n {\n isInteractive = svgDefaultProps.isInteractive,\n animate = svgDefaultProps.animate,\n motionConfig = svgDefaultProps.motionConfig,\n theme,\n renderWrapper,\n ...props\n }: SankeySvgProps<N, L>,\n ref: Ref<SVGSVGElement>\n ) => (\n <Container\n {...{\n animate,\n isInteractive,\n motionConfig,\n renderWrapper,\n theme,\n }}\n >\n <InnerSankey<N, L> isInteractive={isInteractive} {...props} forwardedRef={ref} />\n </Container>\n )\n) as <N extends DefaultNode = DefaultNode, L extends DefaultLink = DefaultLink>(\n props: SankeySvgProps<N, L> & {\n ref?: ForwardedRef<SVGSVGElement>\n }\n) => ReactElement\n","import { forwardRef, Ref, ReactElement } from 'react'\nimport { ResponsiveWrapper, ResponsiveProps, WithChartRef } from '@nivo/core'\nimport { DefaultLink, DefaultNode, SankeySvgProps } from './types'\nimport { Sankey } from './Sankey'\n\nexport const ResponsiveSankey = forwardRef(\n <N extends DefaultNode = DefaultNode, L extends DefaultLink = DefaultLink>(\n {\n defaultWidth,\n defaultHeight,\n onResize,\n debounceResize,\n ...props\n }: ResponsiveProps<SankeySvgProps<N, L>>,\n ref: Ref<SVGSVGElement>\n ) => (\n <ResponsiveWrapper\n defaultWidth={defaultWidth}\n defaultHeight={defaultHeight}\n onResize={onResize}\n debounceResize={debounceResize}\n >\n {({ width, height }) => (\n <Sankey<N, L> width={width} height={height} {...props} ref={ref} />\n )}\n </ResponsiveWrapper>\n )\n) as <N extends DefaultNode = DefaultNode, L extends DefaultLink = DefaultLink>(\n props: WithChartRef<ResponsiveProps<SankeySvgProps<N, L>>, SVGSVGElement>\n) => ReactElement\n"],"names":["tooltipStyles","container","display","alignItems","sourceChip","marginRight","targetChip","marginLeft","sankeyAlignmentPropMapping","center","sankeyCenter","justify","sankeyJustify","start","sankeyLeft","end","sankeyRight","sankeyAlignmentPropKeys","Object","keys","sankeyAlignmentFromProp","prop","svgDefaultProps","layout","align","sort","colors","scheme","nodeOpacity","nodeHoverOpacity","nodeHoverOthersOpacity","nodeThickness","nodeSpacing","nodeInnerPadding","nodeBorderWidth","nodeBorderColor","from","modifiers","nodeBorderRadius","linkOpacity","linkHoverOpacity","linkHoverOthersOpacity","linkContract","linkBlendMode","enableLinkGradient","enableLabels","label","labelPosition","labelPadding","labelOrientation","labelTextColor","labelComponent","Text","isInteractive","nodeTooltip","_ref","node","_jsx","BasicTooltip","id","enableChip","color","linkTooltip","link","_jsxs","style","children","Chip","source","target","formattedValue","legends","layers","role","animate","motionConfig","getId","useSankey","_ref2","data","valueFormat","width","height","_useState","useState","currentNode","setCurrentNode","_useState2","currentLink","setCurrentLink","sortFunction","useMemo","a","b","value","linkSortMode","undefined","alignFunction","theme","useTheme","getColor","useOrdinalColorScale","getNodeBorderColor","useInheritedColor","getLabel","usePropertyAccessor","getLabelTextColor","formatValue","useValueFormatter","_useMemo","_data","sankey","d3Sankey","nodeAlign","nodeSort","linkSort","nodeWidth","nodePadding","size","nodeId","cloneDeep","nodes","forEach","x","x0","y","y0","Math","max","x1","y1","oldX0","oldX1","links","pos0","pos1","thickness","computeNodeAndLinks","legendData","map","SankeyNodesItem","opacity","borderWidth","borderColor","borderRadius","setCurrent","onClick","tooltip","_useMotionConfig","useMotionConfig","springConfig","config","animatedProps","useSpring","immediate","_useTooltip","useTooltip","showTooltipFromEvent","hideTooltip","handleMouseEnter","useCallback","event","createElement","handleMouseMove","handleMouseLeave","handleClick","animated","rect","rx","ry","to","v","fill","fillOpacity","strokeWidth","stroke","strokeOpacity","onMouseEnter","onMouseMove","onMouseLeave","SankeyNodes","getBorderColor","isCurrentNode","getOpacity","_Fragment","SankeyLinkGradient","startColor","endColor","_extends","spreadMethod","x2","y2","offset","stopColor","SankeyLinksItem","path","blendMode","enableGradient","linkId","index","animatedPath","useAnimatedPath","encodeURI","d","mixBlendMode","SankeyLinks","isCurrentLink","getLinkPath","lineGenerator","line","curve","curveMonotoneX","contract","halfThickness","padLength","dots","curveMonotoneY","sankeyLinkVertical","SankeyLabels","LabelComponent","labelRotation","labels","textAnchor","springs","useSprings","length","transform","dominantBaseline","text","pointerEvents","InnerSankey","_ref$layout","_ref$sort","_ref$align","partialMargin","margin","_ref$colors","_ref$nodeThickness","_ref$nodeSpacing","_ref$nodeInnerPadding","_ref$nodeBorderColor","_ref$nodeOpacity","_ref$nodeHoverOpacity","_ref$nodeHoverOthersO","_ref$nodeBorderWidth","_ref$nodeBorderRadius","_ref$linkOpacity","_ref$linkHoverOpacity","_ref$linkHoverOthersO","_ref$linkContract","_ref$linkBlendMode","_ref$enableLinkGradie","_ref$enableLabels","_ref$labelComponent","_ref$labelPosition","_ref$labelPadding","_ref$labelOrientation","_ref$label","_ref$labelTextColor","_ref$nodeTooltip","_ref$linkTooltip","_ref$isInteractive","_ref$legends","_ref$layers","_ref$role","ariaLabel","ariaLabelledBy","ariaDescribedBy","forwardedRef","_useDimensions","useDimensions","innerWidth","innerHeight","outerWidth","outerHeight","_useSankey","_ref3","currentNodeIds","filter","_ref4","_ref5","push","uniq","_ref6","includes","_ref7","layerProps","layerById","Fragment","legend","i","BoxLegendSvg","containerWidth","containerHeight","SvgWrapper","ref","layer","_layerById$layer","Sankey","forwardRef","_ref8","_ref8$isInteractive","_ref8$animate","_ref8$motionConfig","renderWrapper","props","_objectWithoutPropertiesLoose","_excluded","Container","ResponsiveSankey","defaultWidth","defaultHeight","onResize","debounceResize","ResponsiveWrapper"],"mappings":"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