@solidports/recharts 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/dist/index.d.ts +40 -2
  2. package/dist/index.js +14238 -7174
  3. package/dist/{dev.js → index.jsx} +18367 -15900
  4. package/dist/server.js +48178 -0
  5. package/package.json +36 -19
  6. package/src/animation/AnimatedItems.tsx +0 -183
  7. package/src/animation/AnimationController.ts +0 -33
  8. package/src/animation/AnimationControllerImpl.ts +0 -36
  9. package/src/animation/AnimationHandle.ts +0 -307
  10. package/src/animation/CSSTransitionAnimate.tsx +0 -170
  11. package/src/animation/JavascriptAnimate.tsx +0 -119
  12. package/src/animation/easing.ts +0 -221
  13. package/src/animation/matchBy.ts +0 -164
  14. package/src/animation/timeoutController.ts +0 -70
  15. package/src/animation/useAnimationController.tsx +0 -34
  16. package/src/animation/useAnimationStartSnapshot.ts +0 -118
  17. package/src/animation/util.ts +0 -41
  18. package/src/cartesian/Area.tsx +0 -915
  19. package/src/cartesian/AreaRevealShape.tsx +0 -190
  20. package/src/cartesian/Bar.tsx +0 -1369
  21. package/src/cartesian/BarStack.tsx +0 -152
  22. package/src/cartesian/Brush.tsx +0 -951
  23. package/src/cartesian/CartesianAxis.tsx +0 -722
  24. package/src/cartesian/CartesianGrid.tsx +0 -711
  25. package/src/cartesian/ErrorBar.tsx +0 -361
  26. package/src/cartesian/Funnel.tsx +0 -803
  27. package/src/cartesian/GraphicalItemClipPath.tsx +0 -67
  28. package/src/cartesian/Line.tsx +0 -863
  29. package/src/cartesian/LineDrawShape.tsx +0 -89
  30. package/src/cartesian/ReferenceArea.tsx +0 -331
  31. package/src/cartesian/ReferenceDot.tsx +0 -304
  32. package/src/cartesian/ReferenceLine.tsx +0 -474
  33. package/src/cartesian/Scatter.tsx +0 -888
  34. package/src/cartesian/XAxis.tsx +0 -433
  35. package/src/cartesian/YAxis.tsx +0 -443
  36. package/src/cartesian/ZAxis.tsx +0 -155
  37. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +0 -29
  38. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +0 -21
  39. package/src/cartesian/getCartesianPosition.tsx +0 -267
  40. package/src/cartesian/getEquidistantTicks.ts +0 -144
  41. package/src/cartesian/getTicks.ts +0 -225
  42. package/src/cartesian/isOutsidePosition.ts +0 -15
  43. package/src/cartesian/useAnimatedLineLength.ts +0 -54
  44. package/src/chart/AreaChart.tsx +0 -29
  45. package/src/chart/BarChart.tsx +0 -29
  46. package/src/chart/CartesianChart.tsx +0 -131
  47. package/src/chart/CategoricalChart.tsx +0 -94
  48. package/src/chart/ComposedChart.tsx +0 -29
  49. package/src/chart/FunnelChart.tsx +0 -29
  50. package/src/chart/LineChart.tsx +0 -29
  51. package/src/chart/PieChart.tsx +0 -50
  52. package/src/chart/PolarChart.tsx +0 -164
  53. package/src/chart/RadarChart.tsx +0 -70
  54. package/src/chart/RadialBarChart.tsx +0 -46
  55. package/src/chart/RechartsWrapper.tsx +0 -551
  56. package/src/chart/Sankey.tsx +0 -1534
  57. package/src/chart/ScatterChart.tsx +0 -29
  58. package/src/chart/SunburstChart.tsx +0 -504
  59. package/src/chart/Treemap.tsx +0 -1223
  60. package/src/chart/createInitialRootProps.ts +0 -24
  61. package/src/chart/types.ts +0 -53
  62. package/src/component/ActivePoints.tsx +0 -144
  63. package/src/component/Cell.tsx +0 -37
  64. package/src/component/Cursor.tsx +0 -185
  65. package/src/component/Customized.tsx +0 -50
  66. package/src/component/DefaultLegendContent.tsx +0 -348
  67. package/src/component/DefaultTooltipContent.tsx +0 -224
  68. package/src/component/Dots.tsx +0 -157
  69. package/src/component/Label.tsx +0 -636
  70. package/src/component/LabelList.tsx +0 -375
  71. package/src/component/Legend.tsx +0 -512
  72. package/src/component/ResponsiveContainer.tsx +0 -348
  73. package/src/component/Text.tsx +0 -541
  74. package/src/component/Tooltip.tsx +0 -470
  75. package/src/component/TooltipBoundingBox.tsx +0 -146
  76. package/src/component/responsiveContainerUtils.ts +0 -134
  77. package/src/container/ClipPathProvider.tsx +0 -51
  78. package/src/container/Layer.tsx +0 -38
  79. package/src/container/RootSurface.tsx +0 -120
  80. package/src/container/Surface.tsx +0 -61
  81. package/src/context/CellsContext.tsx +0 -54
  82. package/src/context/ErrorBarContext.tsx +0 -146
  83. package/src/context/GraphicalItemChildrenScope.tsx +0 -18
  84. package/src/context/PanoramaContext.tsx +0 -9
  85. package/src/context/RegisterGraphicalItemId.tsx +0 -30
  86. package/src/context/accessibilityContext.tsx +0 -6
  87. package/src/context/brushUpdateContext.tsx +0 -9
  88. package/src/context/chartDataContext.tsx +0 -97
  89. package/src/context/chartLayoutContext.tsx +0 -201
  90. package/src/context/legendPayloadContext.tsx +0 -20
  91. package/src/context/legendPortalContext.tsx +0 -12
  92. package/src/context/tooltipContext.tsx +0 -89
  93. package/src/context/tooltipPortalContext.tsx +0 -12
  94. package/src/context/useTooltipAxis.ts +0 -22
  95. package/src/hooks.ts +0 -476
  96. package/src/index.ts +0 -280
  97. package/src/polar/Pie.tsx +0 -1360
  98. package/src/polar/PolarAngleAxis.tsx +0 -616
  99. package/src/polar/PolarGrid.tsx +0 -312
  100. package/src/polar/PolarRadiusAxis.tsx +0 -547
  101. package/src/polar/Radar.tsx +0 -734
  102. package/src/polar/RadialBar.tsx +0 -917
  103. package/src/polar/defaultPolarAngleAxisProps.tsx +0 -27
  104. package/src/polar/defaultPolarRadiusAxisProps.tsx +0 -25
  105. package/src/shape/Cross.tsx +0 -89
  106. package/src/shape/Curve.tsx +0 -343
  107. package/src/shape/Dot.tsx +0 -70
  108. package/src/shape/Polygon.tsx +0 -195
  109. package/src/shape/Rectangle.tsx +0 -470
  110. package/src/shape/Sector.tsx +0 -347
  111. package/src/shape/Symbols.tsx +0 -139
  112. package/src/shape/Trapezoid.tsx +0 -280
  113. package/src/state/RechartsStateContext.tsx +0 -12
  114. package/src/state/RechartsStateProvider.tsx +0 -87
  115. package/src/state/RechartsStoreContext.tsx +0 -25
  116. package/src/state/RechartsStoreProvider.tsx +0 -35
  117. package/src/state/ReportChartProps.tsx +0 -40
  118. package/src/state/ReportEventSettings.tsx +0 -30
  119. package/src/state/ReportMainChartProps.tsx +0 -61
  120. package/src/state/ReportPolarOptions.tsx +0 -35
  121. package/src/state/SetGraphicalItem.ts +0 -79
  122. package/src/state/SetLegendPayload.ts +0 -134
  123. package/src/state/SetTooltipEntrySettings.tsx +0 -72
  124. package/src/state/actions.ts +0 -464
  125. package/src/state/brushSlice.ts +0 -13
  126. package/src/state/cartesianAxisSlice.ts +0 -141
  127. package/src/state/chartDataSlice.ts +0 -50
  128. package/src/state/chartState.ts +0 -297
  129. package/src/state/errorBarSlice.ts +0 -29
  130. package/src/state/eventSettingsSlice.ts +0 -8
  131. package/src/state/events.ts +0 -76
  132. package/src/state/externalEventsMiddleware.ts +0 -255
  133. package/src/state/graphicalItemsSlice.ts +0 -74
  134. package/src/state/hooks/useChartSelectors.tsx +0 -45
  135. package/src/state/keyboardEventsMiddleware.ts +0 -228
  136. package/src/state/layoutSlice.ts +0 -21
  137. package/src/state/legendSlice.ts +0 -57
  138. package/src/state/mouseEventsMiddleware.ts +0 -185
  139. package/src/state/optionsSlice.ts +0 -47
  140. package/src/state/polarAxisSlice.ts +0 -10
  141. package/src/state/polarOptionsSlice.ts +0 -12
  142. package/src/state/rawData.ts +0 -26
  143. package/src/state/referenceElementsSlice.ts +0 -40
  144. package/src/state/renderedTicksSlice.ts +0 -15
  145. package/src/state/rootPropsSlice.ts +0 -47
  146. package/src/state/selectors/areaSelectors.ts +0 -240
  147. package/src/state/selectors/arrayEqualityCheck.ts +0 -29
  148. package/src/state/selectors/axisSelectors.ts +0 -2157
  149. package/src/state/selectors/barSelectors.ts +0 -310
  150. package/src/state/selectors/barStackSelectors.ts +0 -77
  151. package/src/state/selectors/brushSelectors.ts +0 -33
  152. package/src/state/selectors/chartSelector.ts +0 -185
  153. package/src/state/selectors/combiners/combineActiveLabel.ts +0 -16
  154. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +0 -95
  155. package/src/state/selectors/combiners/combineAllBarPositions.ts +0 -122
  156. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +0 -16
  157. package/src/state/selectors/combiners/combineBarPosition.ts +0 -23
  158. package/src/state/selectors/combiners/combineBarSizeList.ts +0 -80
  159. package/src/state/selectors/combiners/combineCheckedDomain.ts +0 -48
  160. package/src/state/selectors/combiners/combineConfiguredScale.ts +0 -111
  161. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +0 -45
  162. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +0 -50
  163. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +0 -16
  164. package/src/state/selectors/combiners/combineRealScaleType.ts +0 -44
  165. package/src/state/selectors/combiners/combineStackedData.ts +0 -27
  166. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +0 -86
  167. package/src/state/selectors/combiners/combineTooltipPayload.ts +0 -205
  168. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +0 -58
  169. package/src/state/selectors/containerSelectors.ts +0 -12
  170. package/src/state/selectors/dataSelectors.ts +0 -88
  171. package/src/state/selectors/funnelSelectors.ts +0 -75
  172. package/src/state/selectors/graphicalItemSelectors.ts +0 -30
  173. package/src/state/selectors/legendSelectors.ts +0 -29
  174. package/src/state/selectors/lineSelectors.ts +0 -134
  175. package/src/state/selectors/numberDomainEqualityCheck.ts +0 -14
  176. package/src/state/selectors/pickAxisId.ts +0 -5
  177. package/src/state/selectors/pickAxisType.ts +0 -3
  178. package/src/state/selectors/pieSelectors.ts +0 -97
  179. package/src/state/selectors/polarAxisSelectors.ts +0 -201
  180. package/src/state/selectors/polarGridSelectors.ts +0 -28
  181. package/src/state/selectors/polarScaleSelectors.ts +0 -133
  182. package/src/state/selectors/polarSelectors.ts +0 -219
  183. package/src/state/selectors/radarSelectors.ts +0 -191
  184. package/src/state/selectors/radialBarSelectors.ts +0 -435
  185. package/src/state/selectors/rootPropsSelectors.ts +0 -25
  186. package/src/state/selectors/scatterSelectors.ts +0 -96
  187. package/src/state/selectors/selectActivePropsFromChartPointer.ts +0 -26
  188. package/src/state/selectors/selectAllAxes.ts +0 -17
  189. package/src/state/selectors/selectChartOffset.ts +0 -16
  190. package/src/state/selectors/selectChartOffsetInternal.ts +0 -136
  191. package/src/state/selectors/selectLegendArea.ts +0 -20
  192. package/src/state/selectors/selectPlotArea.ts +0 -22
  193. package/src/state/selectors/selectTooltipAxisId.ts +0 -7
  194. package/src/state/selectors/selectTooltipAxisType.ts +0 -32
  195. package/src/state/selectors/selectTooltipEventType.ts +0 -48
  196. package/src/state/selectors/selectTooltipPayloadSearcher.ts +0 -6
  197. package/src/state/selectors/selectTooltipSettings.ts +0 -39
  198. package/src/state/selectors/selectTooltipState.ts +0 -8
  199. package/src/state/selectors/selectors.ts +0 -271
  200. package/src/state/selectors/tooltipSelectors.ts +0 -578
  201. package/src/state/selectors/touchSelectors.ts +0 -31
  202. package/src/state/store.ts +0 -29
  203. package/src/state/storeIdentity.ts +0 -9
  204. package/src/state/teardownWrite.ts +0 -10
  205. package/src/state/tooltipInteraction.ts +0 -23
  206. package/src/state/tooltipSlice.ts +0 -334
  207. package/src/state/touchEventsMiddleware.ts +0 -214
  208. package/src/state/types/AnimationSettings.ts +0 -20
  209. package/src/state/types/AreaSettings.ts +0 -14
  210. package/src/state/types/BarSettings.ts +0 -15
  211. package/src/state/types/LineSettings.ts +0 -9
  212. package/src/state/types/PieSettings.ts +0 -34
  213. package/src/state/types/RadarSettings.ts +0 -5
  214. package/src/state/types/RadialBarSettings.ts +0 -10
  215. package/src/state/types/ScatterSettings.ts +0 -12
  216. package/src/state/types/StackedGraphicalItem.ts +0 -34
  217. package/src/state/useChartState.ts +0 -17
  218. package/src/state/zIndexSlice.ts +0 -39
  219. package/src/synchronisation/syncSelectors.ts +0 -7
  220. package/src/synchronisation/types.ts +0 -44
  221. package/src/synchronisation/useChartSynchronisation.tsx +0 -404
  222. package/src/theme/RechartsTheme.ts +0 -16
  223. package/src/theme/RechartsThemeContext.ts +0 -19
  224. package/src/theme/darkTheme.ts +0 -13
  225. package/src/theme/graphicalItemIdentity.ts +0 -70
  226. package/src/theme/legacyTheme.ts +0 -17
  227. package/src/theme/lightTheme.ts +0 -13
  228. package/src/types.ts +0 -54
  229. package/src/util/ActiveShapeUtils.tsx +0 -162
  230. package/src/util/BarUtils.tsx +0 -62
  231. package/src/util/BarePortal.tsx +0 -50
  232. package/src/util/CamelCaseSVGAttrs.ts +0 -34
  233. package/src/util/CartesianUtils.ts +0 -48
  234. package/src/util/ChartUtils.ts +0 -802
  235. package/src/util/Constants.ts +0 -42
  236. package/src/util/CssPrefixUtils.ts +0 -20
  237. package/src/util/DOMUtils.ts +0 -129
  238. package/src/util/DataUtils.ts +0 -216
  239. package/src/util/Events.ts +0 -16
  240. package/src/util/FunnelUtils.tsx +0 -15
  241. package/src/util/Global.ts +0 -12
  242. package/src/util/IfOverflow.ts +0 -15
  243. package/src/util/LRUCache.ts +0 -41
  244. package/src/util/LogUtils.ts +0 -22
  245. package/src/util/PolarUtils.ts +0 -132
  246. package/src/util/RadialBarUtils.tsx +0 -24
  247. package/src/util/ReactUtils.ts +0 -95
  248. package/src/util/ReduceCSSCalc.ts +0 -187
  249. package/src/util/ScatterUtils.tsx +0 -52
  250. package/src/util/ShapeElementProps.tsx +0 -87
  251. package/src/util/TickUtils.ts +0 -60
  252. package/src/util/XAxisUtils.ts +0 -48
  253. package/src/util/YAxisUtils.ts +0 -48
  254. package/src/util/axisPropsAreEqual.ts +0 -48
  255. package/src/util/createCartesianCharts.tsx +0 -150
  256. package/src/util/createEventProxy.ts +0 -20
  257. package/src/util/createPolarCharts.tsx +0 -112
  258. package/src/util/cursor/getCursorPoints.ts +0 -46
  259. package/src/util/cursor/getCursorRectangle.ts +0 -28
  260. package/src/util/cursor/getRadialCursorPoints.ts +0 -32
  261. package/src/util/excludeEventProps.ts +0 -171
  262. package/src/util/getActiveCoordinate.ts +0 -213
  263. package/src/util/getAxisTypeBasedOnLayout.ts +0 -21
  264. package/src/util/getClassNameFromUnknown.ts +0 -6
  265. package/src/util/getEveryNth.ts +0 -27
  266. package/src/util/getRadiusAndStrokeWidthFromDot.ts +0 -35
  267. package/src/util/getRelativeCoordinate.ts +0 -80
  268. package/src/util/getSliced.ts +0 -13
  269. package/src/util/hoverDedupe.ts +0 -41
  270. package/src/util/isDomainSpecifiedByUser.ts +0 -219
  271. package/src/util/isWellBehavedNumber.ts +0 -7
  272. package/src/util/pathTotalLength.ts +0 -25
  273. package/src/util/payload/getUniqPayload.ts +0 -28
  274. package/src/util/propsAreEqual.ts +0 -121
  275. package/src/util/resolveDefaultProps.ts +0 -161
  276. package/src/util/round.ts +0 -32
  277. package/src/util/scale/CartesianScaleHelper.ts +0 -72
  278. package/src/util/scale/CustomScaleDefinition.ts +0 -81
  279. package/src/util/scale/RechartsScale.ts +0 -130
  280. package/src/util/scale/createCategoricalInverse.ts +0 -72
  281. package/src/util/scale/getNiceTickValues.ts +0 -311
  282. package/src/util/scale/index.ts +0 -2
  283. package/src/util/scale/util/arithmetic.ts +0 -54
  284. package/src/util/solid-1-compat.ts +0 -310
  285. package/src/util/solidJsxCamelAugment.d.ts +0 -84
  286. package/src/util/stacks/getStackSeriesIdentifier.ts +0 -21
  287. package/src/util/stacks/stackTypes.ts +0 -60
  288. package/src/util/structurallyEqual.ts +0 -31
  289. package/src/util/svgPropertiesAndEvents.ts +0 -53
  290. package/src/util/svgPropertiesNoEvents.ts +0 -571
  291. package/src/util/tooltip/translate.ts +0 -171
  292. package/src/util/typedDataKey.ts +0 -48
  293. package/src/util/types.ts +0 -1560
  294. package/src/util/useAnimationId.ts +0 -31
  295. package/src/util/useElementOffset.ts +0 -110
  296. package/src/util/useId.ts +0 -8
  297. package/src/util/usePrefersReducedMotion.ts +0 -48
  298. package/src/util/useReportScale.ts +0 -24
  299. package/src/util/useUniqueId.ts +0 -30
  300. package/src/zIndex/DefaultZIndexes.ts +0 -84
  301. package/src/zIndex/ZIndexLayer.tsx +0 -121
  302. package/src/zIndex/ZIndexPortal.tsx +0 -79
  303. package/src/zIndex/getZIndexFromUnknown.ts +0 -14
  304. package/src/zIndex/zIndexSelectors.ts +0 -48
@@ -1,1534 +0,0 @@
1
- /* eslint-disable import/no-cycle, sort-keys */
2
- import { createMemo, For, Show, untrack } from 'solid-js';
3
- import type { WithoutRemoveFalse } from "../util/types"
4
- import type { JSX } from '@solidjs/web';
5
- import maxBy from "es-toolkit/compat/maxBy"
6
- import sumBy from "es-toolkit/compat/sumBy"
7
- import get from "es-toolkit/compat/get"
8
- import { Surface } from "../container/Surface"
9
- import { Layer } from "../container/Layer"
10
- import type { Props as RectangleProps } from "../shape/Rectangle"
11
- import { Rectangle } from "../shape/Rectangle"
12
- import { getValueByDataKey } from "../util/ChartUtils"
13
- import type {
14
- Coordinate,
15
- DataKey,
16
- EventThrottlingProps,
17
- Margin,
18
- Percent,
19
- SankeyLink,
20
- SankeyNode,
21
- } from "../util/types"
22
- import {
23
- ReportChartMargin,
24
- ReportChartSize,
25
- useChartHeight,
26
- useChartWidth,
27
- } from "../context/chartLayoutContext"
28
- import { RechartsWrapper } from "./RechartsWrapper"
29
- import { RechartsStateProvider } from "../state/RechartsStateProvider"
30
- import { createInitialLayoutState } from "../state/chartState"
31
- import { useChartStore } from "../state/RechartsStoreContext"
32
- import { useOptionalChartState } from "../state/useChartState"
33
- import type {
34
- TooltipIndex,
35
- TooltipPayloadConfiguration,
36
- TooltipPayloadSearcher,
37
- } from "../state/tooltipSlice"
38
- import { SetTooltipEntrySettings } from "../state/SetTooltipEntrySettings"
39
- import type { ChartOptions } from "../state/optionsSlice"
40
- import { ReportEventSettings } from "../state/ReportEventSettings"
41
- import { SetComputedData } from "../context/chartDataContext"
42
- import {
43
- svgPropertiesNoEvents,
44
- svgPropertiesNoEventsFromUnknown,
45
- } from "../util/svgPropertiesNoEvents"
46
- import type { RequiresDefaultProps } from "../util/resolveDefaultProps"
47
- import { resolveDefaultProps } from "../util/resolveDefaultProps"
48
- import { isPositiveNumber } from "../util/isWellBehavedNumber"
49
- import { isNotNil, noop } from "../util/DataUtils"
50
- import type { WithIdRequired } from "../util/useUniqueId"
51
- import { RegisterGraphicalItemId } from "../context/RegisterGraphicalItemId"
52
- import type { GraphicalItemId } from "../state/graphicalItemsSlice"
53
- import { initialEventSettingsState } from "../state/eventSettingsSlice"
54
-
55
- import { splitProps } from '../util/solid-1-compat';
56
- import { setTooltipInteraction } from "../state/tooltipInteraction"
57
- const interpolationGenerator = (a: number, b: number) => {
58
- const ka = +a
59
- const kb = b - ka
60
- return (t: number) => ka + kb * t
61
- }
62
-
63
- const centerY = (node: SankeyNode) => node.y + node.dy / 2
64
-
65
- const cubicValue = (start: number, control1: number, control2: number, end: number, t: number): number => {
66
- const inverseT = 1 - t
67
- return inverseT ** 3 * start + 3 * inverseT ** 2 * t * control1 + 3 * inverseT * t ** 2 * control2 + t ** 3 * end
68
- }
69
-
70
- /* TODO why is this not reading dataKey? */
71
- const getValue = (entry: LinkDataItem | SankeyNode | undefined): number =>
72
- (entry && entry.value) || 0
73
-
74
- const getSumOfIds = (links: ReadonlyArray<LinkDataItem>, ids: number[]): number =>
75
- ids.reduce((result, id) => result + getValue(links[id]), 0)
76
-
77
- const getSumWithWeightedSource = (
78
- tree: ReadonlyArray<SankeyNode>,
79
- links: ReadonlyArray<LinkDataItemDy>,
80
- ids: number[],
81
- ) =>
82
- ids.reduce((result, id) => {
83
- const link = links[id]
84
- if (link == null) {
85
- return result
86
- }
87
- const sourceNode = tree[link.source]
88
- if (sourceNode == null) {
89
- return result
90
- }
91
-
92
- return result + centerY(sourceNode) * getValue(links[id])
93
- }, 0)
94
-
95
- const getSumWithWeightedTarget = (
96
- tree: ReadonlyArray<SankeyNode>,
97
- links: ReadonlyArray<LinkDataItemDy>,
98
- ids: ReadonlyArray<number>,
99
- ): number =>
100
- ids.reduce((result: number, id: number) => {
101
- const link = links[id]
102
- if (link == null) {
103
- return result
104
- }
105
- const targetNode = tree[link.target]
106
- if (targetNode == null) {
107
- return result
108
- }
109
-
110
- return result + centerY(targetNode) * getValue(links[id])
111
- }, 0)
112
-
113
- const ascendingY = (a: { y: number }, b: { y: number }) => a.y - b.y
114
-
115
- const searchTargetsAndSources = (links: LinkDataItem[], id: number) => {
116
- const sourceNodes: number[] = []
117
- const sourceLinks: number[] = []
118
- const targetNodes: number[] = []
119
- const targetLinks: number[] = []
120
-
121
- for (let i = 0, len = links.length; i < len; i++) {
122
- const link = links[i]
123
-
124
- if (link?.source === id) {
125
- targetNodes.push(link.target)
126
- targetLinks.push(i)
127
- }
128
-
129
- if (link?.target === id) {
130
- sourceNodes.push(link.source)
131
- sourceLinks.push(i)
132
- }
133
- }
134
-
135
- return { sourceLinks, sourceNodes, targetLinks, targetNodes }
136
- }
137
-
138
- const updateDepthOfTargets = (tree: SankeyNode[], curNode: SankeyNode) => {
139
- const { targetNodes } = curNode
140
-
141
- for (let i = 0, len = targetNodes.length; i < len; i++) {
142
- const targetNode = targetNodes[i]
143
- if (targetNode == null) {
144
- continue
145
- }
146
- const target = tree[targetNode]
147
-
148
- if (target) {
149
- const newDepth = curNode.depth + 1
150
- /*
151
- * Only recurse when the depth grows. Depth is the longest path to a node, so once it stops increasing
152
- * the subtree is already up to date; without this guard every path through the graph is walked
153
- * separately, which explodes combinatorially on dense graphs.
154
- */
155
- if (newDepth > target.depth) {
156
- target.depth = newDepth
157
- updateDepthOfTargets(tree, target)
158
- }
159
- }
160
- }
161
- }
162
-
163
- const getNodesTree = (
164
- { nodes, links }: SankeyData,
165
- width: number,
166
- nodeWidth: number,
167
- align: "left" | "justify",
168
- ): { tree: SankeyNode[]; maxDepth: number } => {
169
- const tree: SankeyNode[] = nodes.map((entry: Record<string, unknown>, index: number) => {
170
- const result = searchTargetsAndSources(links, index)
171
-
172
- return {
173
- ...entry,
174
- ...result,
175
- depth: 0,
176
- value: Math.max(
177
- getSumOfIds(links, result.sourceLinks),
178
- getSumOfIds(links, result.targetLinks),
179
- ),
180
- } as SankeyNode
181
- })
182
-
183
- for (let i = 0, len = tree.length; i < len; i++) {
184
- const node = tree[i]
185
-
186
- if (node != null && node.sourceNodes.length === 0) {
187
- updateDepthOfTargets(tree, node)
188
- }
189
- }
190
- const maxDepth = maxBy(tree, (entry: SankeyNode) => entry.depth)?.depth ?? 0
191
-
192
- if (maxDepth >= 1) {
193
- const childWidth = (width - nodeWidth) / maxDepth
194
- for (let i = 0, len = tree.length; i < len; i++) {
195
- const node = tree[i]
196
- if (node == null) {
197
- continue
198
- }
199
-
200
- if (node.targetNodes.length === 0) {
201
- if (align === "justify") {
202
- node.depth = maxDepth
203
- }
204
- }
205
- node.x = node.depth * childWidth
206
- node.dx = nodeWidth
207
- }
208
- }
209
-
210
- return { maxDepth, tree }
211
- }
212
-
213
- const getDepthTree = (tree: SankeyNode[]): SankeyNode[][] => {
214
- const result: SankeyNode[][] = []
215
-
216
- for (let i = 0, len = tree.length; i < len; i++) {
217
- const node = tree[i]
218
- if (node == null) {
219
- continue
220
- }
221
-
222
- if (result[node.depth] == null) {
223
- result[node.depth] = []
224
- }
225
-
226
- result[node.depth]?.push(node)
227
- }
228
-
229
- return result
230
- }
231
-
232
- type LinkDataItemDy = LinkDataItem & { dy: number; sy?: number; ty?: number }
233
-
234
- type SankeyVerticalAlign = "justify" | "top"
235
-
236
- const updateYOfTree = (
237
- depthTree: SankeyNode[][],
238
- height: number,
239
- nodePadding: number,
240
- links: ReadonlyArray<LinkDataItem>,
241
- verticalAlign: SankeyVerticalAlign,
242
- ): Array<LinkDataItemDy> => {
243
- let yRatio: number = Math.min(
244
- ...depthTree.map((nodes) => {
245
- const value = sumBy(nodes, getValue)
246
- return value === 0 ? Infinity : (height - (nodes.length - 1) * nodePadding) / value
247
- }),
248
- )
249
- if (yRatio === Infinity) {
250
- yRatio = 0
251
- }
252
-
253
- for (let d = 0, maxDepth = depthTree.length; d < maxDepth; d++) {
254
- const nodes = depthTree[d]
255
- if (nodes == null) {
256
- continue
257
- }
258
-
259
- if (verticalAlign === "top") {
260
- let currentY = 0
261
- for (let i = 0, len = nodes.length; i < len; i++) {
262
- const node = nodes[i]
263
- if (node == null) {
264
- continue
265
- }
266
-
267
- node.dy = node.value * yRatio
268
- node.y = currentY
269
- currentY += node.dy + nodePadding
270
- }
271
- } else {
272
- for (let i = 0, len = nodes.length; i < len; i++) {
273
- const node = nodes[i]
274
- if (node == null) {
275
- continue
276
- }
277
-
278
- node.y = i
279
- node.dy = node.value * yRatio
280
- }
281
- }
282
- }
283
-
284
- return links.map(
285
- (link: LinkDataItem): LinkDataItemDy => ({ ...link, dy: getValue(link) * yRatio }),
286
- )
287
- }
288
-
289
- const resolveCollisions = (
290
- depthTree: SankeyNode[][],
291
- height: number,
292
- nodePadding: number,
293
- sort = true,
294
- ) => {
295
- for (let i = 0, len = depthTree.length; i < len; i++) {
296
- const nodes = depthTree[i]
297
- if (nodes == null) {
298
- continue
299
- }
300
- const n = nodes.length
301
-
302
- /* Sort by the value of y */
303
- if (sort) {
304
- nodes.sort(ascendingY)
305
- }
306
-
307
- let y0 = 0
308
- for (let j = 0; j < n; j++) {
309
- const node = nodes[j]
310
- if (node == null) {
311
- continue
312
- }
313
- const dy = y0 - node.y
314
-
315
- if (dy > 0) {
316
- node.y += dy
317
- }
318
-
319
- y0 = node.y + node.dy + nodePadding
320
- }
321
-
322
- y0 = height + nodePadding
323
- for (let j = n - 1; j >= 0; j--) {
324
- const node = nodes[j]
325
- if (node == null) {
326
- continue
327
- }
328
- const dy = node.y + node.dy + nodePadding - y0
329
-
330
- if (dy > 0) {
331
- node.y -= dy
332
- y0 = node.y
333
- } else {
334
- break
335
- }
336
- }
337
- }
338
- }
339
-
340
- const relaxLeftToRight = (
341
- tree: ReadonlyArray<SankeyNode>,
342
- depthTree: SankeyNode[][],
343
- links: ReadonlyArray<LinkDataItemDy>,
344
- alpha: number,
345
- ) => {
346
- for (let i = 0, maxDepth = depthTree.length; i < maxDepth; i++) {
347
- const nodes = depthTree[i]
348
- if (nodes == null) {
349
- continue
350
- }
351
-
352
- for (let j = 0, len = nodes.length; j < len; j++) {
353
- const node = nodes[j]
354
- if (node == null) {
355
- continue
356
- }
357
-
358
- if (node.sourceLinks.length) {
359
- const sourceSum = getSumOfIds(links, node.sourceLinks)
360
- const weightedSum = getSumWithWeightedSource(tree, links, node.sourceLinks)
361
- const y = sourceSum === 0 ? centerY(node) : weightedSum / sourceSum
362
-
363
- node.y += (y - centerY(node)) * alpha
364
- }
365
- }
366
- }
367
- }
368
-
369
- const relaxRightToLeft = (
370
- tree: ReadonlyArray<SankeyNode>,
371
- /*
372
- * depthTree array is modified by this method!
373
- */
374
- depthTree: SankeyNode[][],
375
- links: ReadonlyArray<LinkDataItemDy>,
376
- alpha: number,
377
- ) => {
378
- for (let i = depthTree.length - 1; i >= 0; i--) {
379
- const nodes = depthTree[i]
380
- if (nodes == null) {
381
- continue
382
- }
383
-
384
- for (let j = 0, len = nodes.length; j < len; j++) {
385
- const node = nodes[j]
386
- if (node == null) {
387
- continue
388
- }
389
-
390
- if (node.targetLinks.length) {
391
- const targetSum = getSumOfIds(links, node.targetLinks)
392
- const weightedSum = getSumWithWeightedTarget(tree, links, node.targetLinks)
393
- const y = targetSum === 0 ? centerY(node) : weightedSum / targetSum
394
-
395
- node.y += (y - centerY(node)) * alpha
396
- }
397
- }
398
- }
399
- }
400
-
401
- const updateYOfLinks = (tree: SankeyNode[], links: LinkDataItemDy[]): void => {
402
- for (let i = 0, len = tree.length; i < len; i++) {
403
- const node = tree[i]
404
- if (node == null) {
405
- continue
406
- }
407
- let sy = 0
408
- let ty = 0
409
-
410
- node.targetLinks.sort((a, b) => {
411
- const targetA = links[a]?.target
412
- const targetB = links[b]?.target
413
- if (targetA == null || targetB == null) {
414
- return 0
415
- }
416
- const yA = tree[targetA]?.y
417
- const yB = tree[targetB]?.y
418
- if (yA == null || yB == null) {
419
- return 0
420
- }
421
- return yA - yB
422
- })
423
- node.sourceLinks.sort((a, b) => {
424
- const sourceA = links[a]?.source
425
- const sourceB = links[b]?.source
426
- if (sourceA == null || sourceB == null) {
427
- return 0
428
- }
429
- const yA = tree[sourceA]?.y
430
- const yB = tree[sourceB]?.y
431
- if (yA == null || yB == null) {
432
- return 0
433
- }
434
- return yA - yB
435
- })
436
-
437
- for (let j = 0, tLen = node.targetLinks.length; j < tLen; j++) {
438
- const targetLink = node.targetLinks[j]
439
- if (targetLink == null) {
440
- continue
441
- }
442
- const link = links[targetLink]
443
-
444
- if (link) {
445
- link.sy = sy
446
- sy += link.dy
447
- }
448
- }
449
-
450
- for (let j = 0, sLen = node.sourceLinks.length; j < sLen; j++) {
451
- const sourceLink = node.sourceLinks[j]
452
- if (sourceLink == null) {
453
- continue
454
- }
455
- const link = links[sourceLink]
456
-
457
- if (link) {
458
- link.ty = ty
459
- ty += link.dy
460
- }
461
- }
462
- }
463
- }
464
-
465
- const getLinkYAtX = (sourceNode: SankeyNode, targetNode: SankeyNode, link: LinkDataItemDy, x: number): number => {
466
- const sourceX = sourceNode.x + sourceNode.dx
467
- const targetX = targetNode.x
468
- const progress = targetX === sourceX ? 0 : (x - sourceX) / (targetX - sourceX)
469
- const boundedProgress = Math.min(Math.max(progress, 0), 1)
470
- const sourceY = sourceNode.y + (link.sy ?? 0) + link.dy / 2
471
- const targetY = targetNode.y + (link.ty ?? 0) + link.dy / 2
472
-
473
- return cubicValue(sourceY, sourceY, targetY, targetY, boundedProgress)
474
- }
475
-
476
- const resolveNodeLinkCollisions = (
477
- tree: SankeyNode[],
478
- depthTree: SankeyNode[][],
479
- links: LinkDataItemDy[],
480
- height: number,
481
- nodePadding: number,
482
- ) => {
483
- const depthByNode = new Map<SankeyNode, number>()
484
-
485
- for (let depth = 0; depth < depthTree.length; depth++) {
486
- const nodes = depthTree[depth]
487
- if (nodes == null) {
488
- continue
489
- }
490
-
491
- for (const node of nodes) {
492
- depthByNode.set(node, depth)
493
- }
494
- }
495
-
496
- for (let depth = 0; depth < depthTree.length; depth++) {
497
- const nodes = depthTree[depth]
498
- if (nodes == null || nodes.length === 0) {
499
- continue
500
- }
501
-
502
- const depthX = nodes[0] == null ? undefined : nodes[0].x + nodes[0].dx / 2
503
- if (depthX == null) {
504
- continue
505
- }
506
-
507
- const fixedObstacles = links.flatMap(link => {
508
- const sourceNode = tree[link.source]
509
- const targetNode = tree[link.target]
510
- if (sourceNode == null || targetNode == null) {
511
- return []
512
- }
513
-
514
- const sourceDepth = depthByNode.get(sourceNode)
515
- const targetDepth = depthByNode.get(targetNode)
516
- if (sourceDepth == null || targetDepth == null) {
517
- return []
518
- }
519
-
520
- if (depth <= Math.min(sourceDepth, targetDepth) || depth >= Math.max(sourceDepth, targetDepth)) {
521
- return []
522
- }
523
-
524
- const y = getLinkYAtX(sourceNode, targetNode, link, depthX) - link.dy / 2
525
- return [{ y, dy: link.dy, fixed: true as const }]
526
- })
527
-
528
- const containedNodeObstacles = fixedObstacles.filter(obstacle =>
529
- nodes.some(node => node.y >= obstacle.y && node.y + node.dy <= obstacle.y + obstacle.dy),
530
- )
531
-
532
- if (containedNodeObstacles.length === 0) {
533
- continue
534
- }
535
-
536
- type CollisionItem = { node: SankeyNode; fixed: false } | { y: number; dy: number; fixed: true }
537
- const getItemY = (item: CollisionItem): number => (item.fixed ? item.y : item.node.y)
538
- const getItemHeight = (item: CollisionItem): number => (item.fixed ? item.dy : item.node.dy)
539
- let items: CollisionItem[] = [
540
- ...nodes.map(node => ({ node, fixed: false as const })),
541
- ...containedNodeObstacles,
542
- ].sort((a, b) => getItemY(a) - getItemY(b))
543
-
544
- let nextY = 0
545
- for (const item of items) {
546
- if (item.fixed) {
547
- nextY = Math.max(nextY, item.y + item.dy + nodePadding)
548
- continue
549
- }
550
-
551
- if (item.node.y < nextY) {
552
- item.node.y = nextY
553
- }
554
- nextY = item.node.y + item.node.dy + nodePadding
555
- }
556
-
557
- items = items.sort((a, b) => getItemY(a) - getItemY(b))
558
-
559
- let previousY = height + nodePadding
560
- for (let i = items.length - 1; i >= 0; i--) {
561
- const item = items[i]
562
- if (item == null) {
563
- continue
564
- }
565
-
566
- if (item.fixed) {
567
- previousY = Math.min(previousY, item.y - nodePadding)
568
- continue
569
- }
570
-
571
- /* This backward pass only keeps moved nodes within the chart bounds.
572
- It intentionally does not iterate again against fixed obstacles above,
573
- because this fix is scoped to the fully-contained skipped-depth case. */
574
- const dy = item.node.y + getItemHeight(item) + nodePadding - previousY
575
- if (dy > 0) {
576
- item.node.y -= dy
577
- }
578
- previousY = item.node.y
579
- }
580
- }
581
- }
582
-
583
- export const computeData = ({
584
- data,
585
- width,
586
- height,
587
- iterations,
588
- nodeWidth,
589
- nodePadding,
590
- sort,
591
- verticalAlign,
592
- align,
593
- }: {
594
- data: SankeyData
595
- width: number
596
- height: number
597
- iterations: number
598
- nodeWidth: number
599
- nodePadding: number
600
- sort: boolean
601
- verticalAlign: SankeyVerticalAlign
602
- align: "left" | "justify"
603
- }): {
604
- nodes: ReadonlyArray<SankeyNode>
605
- links: ReadonlyArray<SankeyLink>
606
- } => {
607
- const { links } = data
608
- const { tree } = getNodesTree(data, width, nodeWidth, align)
609
- const depthTree = getDepthTree(tree)
610
- const linksWithDy: Array<LinkDataItemDy> = updateYOfTree(
611
- depthTree,
612
- height,
613
- nodePadding,
614
- links,
615
- verticalAlign,
616
- )
617
-
618
- resolveCollisions(depthTree, height, nodePadding, sort)
619
-
620
- if (verticalAlign === "justify") {
621
- let alpha = 1
622
- for (let i = 1; i <= iterations; i++) {
623
- relaxRightToLeft(tree, depthTree, linksWithDy, (alpha *= 0.99))
624
-
625
- resolveCollisions(depthTree, height, nodePadding, sort)
626
-
627
- relaxLeftToRight(tree, depthTree, linksWithDy, alpha)
628
-
629
- resolveCollisions(depthTree, height, nodePadding, sort)
630
- }
631
- }
632
-
633
- updateYOfLinks(tree, linksWithDy)
634
- resolveNodeLinkCollisions(tree, depthTree, linksWithDy, height, nodePadding)
635
- updateYOfLinks(tree, linksWithDy)
636
-
637
- /* updateYOfLinks modifies the links array to add sy and ty in place */
638
- const newLinks: ReadonlyArray<SankeyLink> = linksWithDy as unknown as ReadonlyArray<SankeyLink>
639
-
640
- return { links: newLinks, nodes: tree }
641
- }
642
-
643
- const getNodeCoordinateOfTooltip = (item: NodeProps) => {
644
- return { x: +item.x + +item.width / 2, y: +item.y + +item.height / 2 }
645
- }
646
-
647
- const getLinkCoordinateOfTooltip = (item: LinkProps): Coordinate | undefined => {
648
- return "sourceX" in item
649
- ? {
650
- x: (item.sourceX + item.targetX) / 2,
651
- y: (item.sourceY + item.targetY) / 2,
652
- }
653
- : undefined
654
- }
655
-
656
- type SankeyTooltipPayload = { payload: SankeyNode | SankeyLink; name: unknown; value: unknown }
657
-
658
- const getPayloadOfTooltip = (
659
- item: { payload: SankeyNode | SankeyLink },
660
- type: SankeyElementType,
661
- nameKey: DataKey<SankeyLink | SankeyNode, string> | undefined,
662
- ): SankeyTooltipPayload | undefined => {
663
- const { payload } = item
664
- if (type === "node") {
665
- return {
666
- name: getValueByDataKey(payload, nameKey, ""),
667
- payload,
668
- value: getValueByDataKey(payload, "value"),
669
- }
670
- }
671
- if ("source" in payload && payload.source && payload.target) {
672
- const sourceObj = typeof payload.source === "object" ? (payload.source as SankeyNode) : null
673
- const targetObj = typeof payload.target === "object" ? (payload.target as SankeyNode) : null
674
- const sourceName = sourceObj ? getValueByDataKey(sourceObj, nameKey, "") : ""
675
- const targetName = targetObj ? getValueByDataKey(targetObj, nameKey, "") : ""
676
-
677
- return {
678
- name: `${sourceName} - ${targetName}`,
679
- payload,
680
- value: getValueByDataKey(payload, "value"),
681
- }
682
- }
683
-
684
- return undefined
685
- }
686
-
687
- export const sankeyPayloadSearcher: TooltipPayloadSearcher = (
688
- _: unknown,
689
- activeIndex: TooltipIndex,
690
- computedData?: unknown,
691
- nameKey?,
692
- ): SankeyTooltipPayload | undefined => {
693
- if (activeIndex == null || typeof activeIndex !== "string") {
694
- return undefined
695
- }
696
- if (computedData == null || typeof computedData !== "object") {
697
- return undefined
698
- }
699
- const splitIndex = activeIndex.split("-")
700
- const [targetType, index] = splitIndex
701
- const item = get(computedData, `${targetType}s[${index}]`)
702
- if (item) {
703
- const payload = getPayloadOfTooltip(
704
- item as { payload: SankeyNode | SankeyLink },
705
- targetType as SankeyElementType,
706
- nameKey as DataKey<SankeyLink | SankeyNode, string> | undefined,
707
- )
708
- return payload
709
- }
710
- return undefined
711
- }
712
-
713
- const options: ChartOptions = {
714
- chartName: "Sankey",
715
- defaultTooltipEventType: "item",
716
- eventEmitter: undefined,
717
- tooltipPayloadSearcher: sankeyPayloadSearcher,
718
- validateTooltipEventTypes: ["item"],
719
- }
720
-
721
- function SetSankeyTooltipEntrySettings(props: {
722
- dataKey: DataKey<unknown> | undefined
723
- nameKey: DataKey<unknown> | undefined
724
- stroke: string | undefined
725
- strokeWidth: number | string | undefined
726
- fill: string | undefined
727
- name: string | number | undefined
728
- data: SankeyData
729
- id: GraphicalItemId
730
- }): JSX.Element {
731
- /* GOTCHA-005: createMemo so reactive props flow into the settings object. */
732
- const tooltipEntrySettings = createMemo<TooltipPayloadConfiguration>(() => ({
733
- dataDefinedOnItem: props.data,
734
- getPosition: noop,
735
- settings: {
736
- color: props.fill,
737
- dataKey: props.dataKey,
738
- fill: props.fill,
739
- graphicalItemId: props.id,
740
- hide: false,
741
- name: props.name,
742
- nameKey: props.nameKey,
743
- stroke: props.stroke,
744
- strokeWidth: props.strokeWidth,
745
- type: undefined,
746
- unit: "",
747
- },
748
- }))
749
- return <SetTooltipEntrySettings tooltipEntrySettings={tooltipEntrySettings()} />
750
- }
751
-
752
- interface LinkDataItem {
753
- source: number
754
- target: number
755
- value: number
756
- }
757
-
758
- export interface NodeProps {
759
- height: number
760
- width: number
761
- payload: SankeyNode
762
- index: number
763
- x: number
764
- y: number
765
- [key: string]: unknown
766
- }
767
-
768
- export interface LinkProps {
769
- sourceX: number
770
- targetX: number
771
- sourceY: number
772
- targetY: number
773
- sourceControlX: number
774
- targetControlX: number
775
- sourceRelativeY: number
776
- targetRelativeY: number
777
- linkWidth: number
778
- index: number
779
- /** payload is SankeyLink except source and target are now Node objects instead of numbers */
780
- payload: Omit<SankeyLink, "source" | "target"> & { source: SankeyNode; target: SankeyNode }
781
- [key: string]: unknown
782
- }
783
-
784
- export interface SankeyData {
785
- nodes: Record<string, unknown>[]
786
- links: LinkDataItem[]
787
- }
788
-
789
- export type SankeyNodeOptions = ((props: NodeProps) => JSX.Element) | RectangleProps
790
-
791
- type SankeyLinkOptions = ((props: LinkProps) => JSX.Element) | JSX.PathSVGAttributes<SVGPathElement>
792
-
793
- interface SankeyProps extends EventThrottlingProps {
794
- /**
795
- * Tab order of the chart surface. Upstream's React `tabIndex`; the native `tabindex`
796
- * attribute is accepted too. Defaults to 0 when `accessibilityLayer` is on.
797
- */
798
- tabIndex?: number
799
- /**
800
- * Name represents each sector in the tooltip.
801
- * This allows you to extract the name from the data:
802
- *
803
- * - `string`: the name of the field in the data object;
804
- * - `number`: the index of the field in the data;
805
- * - `function`: a function that receives the data object and returns the name.
806
- *
807
- * @defaultValue name
808
- */
809
- nameKey?: DataKey<unknown>
810
- /**
811
- * dataKey prop in Sankey defines which key in the link objects represents the value of the link _in Tooltip only_.
812
- *
813
- * Unlike other charts where dataKey is used to extract values from the data array, in Sankey charts,
814
- * the value of each link is directly taken from the 'value' property of the link objects.
815
- *
816
- * @default 'value'
817
- */
818
- dataKey?: DataKey<unknown>
819
- /**
820
- * The width of chart container.
821
- * Can be a number or a percent string like "100%".
822
- *
823
- * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
824
- */
825
- width?: number | Percent
826
- /**
827
- * The height of chart container.
828
- * Can be a number or a percent string like "100%".
829
- *
830
- * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
831
- */
832
- height?: number | Percent
833
- /**
834
- * The source data, including the array of nodes, and the relationships, represented by links.
835
- *
836
- * Note that Sankey requires a specific data structure.
837
- * Each node should have a unique index in the nodes array, and each link should reference these nodes by their indices.
838
- * This is different from other chart types in Recharts, which accept arbitrary data.
839
- *
840
- * @example
841
- * nodes: [
842
- * { name: 'Visit' },
843
- * { name: 'Direct-Favourite' },
844
- * { name: 'Page-Click' },
845
- * { name: 'Detail-Favourite' },
846
- * { name: 'Lost' },
847
- * ],
848
- * links: [
849
- * { source: 0, target: 1, value: 3728.3 },
850
- * { source: 0, target: 2, value: 354170 },
851
- * { source: 2, target: 3, value: 62429 },
852
- * { source: 2, target: 4, value: 291741 },
853
- * ],
854
- */
855
- data: SankeyData
856
- /**
857
- * The padding between the nodes
858
- * @default 10
859
- */
860
- nodePadding?: number
861
- /**
862
- * The width of node
863
- * @default 10
864
- */
865
- nodeWidth?: number
866
- /**
867
- * The curvature of width
868
- * @default 0.5
869
- */
870
- linkCurvature?: number
871
- /**
872
- * The number of the iterations between the links
873
- * @default 32
874
- */
875
- iterations?: number
876
- /**
877
- * If set an object, the option is the configuration of nodes.
878
- * If set a React element, the option is the custom react element of drawing the nodes.
879
- *
880
- * @example <Sankey node={MyCustomComponent} />
881
- * @example <Sankey node={{stroke: #77c878, strokeWidth: 2}} />
882
- */
883
- node?: SankeyNodeOptions
884
- /**
885
- * If set an object, the option is the configuration of links.
886
- * If set a React element, the option is the custom react element of drawing the links.
887
- *
888
- * @example <Sankey link={MyCustomComponent} />
889
- * @example <Sankey link={{ fill: #77c878 }} />
890
- */
891
- link?: SankeyLinkOptions
892
- style?: JSX.CSSProperties
893
- class?: string
894
- children?: JSX.Element
895
- /**
896
- * Turn on accessibility support for keyboard-only and screen reader users.
897
- *
898
- * @defaultValue true
899
- */
900
- accessibilityLayer?: boolean
901
- title?: string
902
- desc?: string
903
- /**
904
- * Empty space around the container.
905
- *
906
- * @defaultValue {"top":5,"right":5,"bottom":5,"left":5}
907
- */
908
- margin?: Partial<Margin>
909
- /**
910
- * The customized event handler of click on the area in this group
911
- */
912
- onClick?: (item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
913
- /**
914
- * The customized event handler of mouseenter on the area in this group
915
- */
916
- onMouseEnter?: (item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
917
- /**
918
- * The customized event handler of mouseleave on the area in this group
919
- */
920
- onMouseLeave?: (item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
921
- /**
922
- * Whether to sort the nodes on the y axis, or to display them as user-defined.
923
- * @default true
924
- */
925
- sort?: boolean
926
- /**
927
- * Controls the vertical spacing of nodes within a depth. 'justify' distributes nodes evenly and balances link paths, while 'top' positions the group starting from the top edge of the chart.
928
- * @default 'justify'
929
- */
930
- verticalAlign?: SankeyVerticalAlign
931
- /**
932
- * If set to 'justify', the start nodes will be aligned to the left edge of the chart and the end nodes will be aligned to the right edge of the chart. If set to 'left', the start nodes will be aligned to the left edge of the chart.
933
- * @default 'justify'
934
- */
935
- align?: "left" | "justify"
936
- stroke?: string
937
- strokeWidth?: number | string
938
- fill?: string
939
- name?: string | number
940
- id?: string
941
- }
942
-
943
- export type Props = WithoutRemoveFalse<Omit<JSX.SvgSVGAttributes<SVGSVGElement>, keyof SankeyProps | "ref">> & SankeyProps
944
-
945
- export type SankeyElementType = "node" | "link"
946
-
947
- function renderLinkItem(
948
- option: SankeyLinkOptions | undefined,
949
- linkProps: LinkProps,
950
- events?: Record<string, ((e: Event) => void) | undefined>,
951
- ): JSX.Element {
952
- if (typeof option === "function") {
953
- return option(linkProps)
954
- }
955
-
956
- const {
957
- sourceX,
958
- sourceY,
959
- sourceControlX,
960
- targetX,
961
- targetY,
962
- targetControlX,
963
- linkWidth,
964
- ...others
965
- } = linkProps
966
-
967
- return (
968
- <path
969
- class="recharts-sankey-link"
970
- d={`
971
- M${sourceX},${sourceY}
972
- C${sourceControlX},${sourceY} ${targetControlX},${targetY} ${targetX},${targetY}
973
- `}
974
- fill="none"
975
- stroke="#333"
976
- stroke-width={linkWidth}
977
- stroke-opacity="0.2"
978
- {...svgPropertiesNoEvents(others)}
979
- {...(events ?? {})}
980
- />
981
- )
982
- }
983
-
984
- const buildLinkProps = ({
985
- link,
986
- nodes,
987
- left,
988
- top,
989
- i,
990
- linkContent,
991
- linkCurvature,
992
- }: {
993
- link: SankeyLink
994
- nodes: ReadonlyArray<SankeyNode>
995
- top: number
996
- left: number
997
- linkContent: SankeyLinkOptions | undefined
998
- i: number
999
- linkCurvature: number
1000
- }): LinkProps | undefined => {
1001
- const { sy: sourceRelativeY, ty: targetRelativeY, dy: linkWidth } = link
1002
- const sourceNode = nodes[link.source]
1003
- const targetNode = nodes[link.target]
1004
- if (sourceNode == null || targetNode == null) {
1005
- return undefined
1006
- }
1007
- const sourceX = sourceNode.x + sourceNode.dx + left
1008
- const targetX = targetNode.x + left
1009
- const interpolationFunc = interpolationGenerator(sourceX, targetX)
1010
- const sourceControlX = interpolationFunc(linkCurvature)
1011
- const targetControlX = interpolationFunc(1 - linkCurvature)
1012
- const sourceY = sourceNode.y + sourceRelativeY + linkWidth / 2 + top
1013
- const targetY = targetNode.y + targetRelativeY + linkWidth / 2 + top
1014
-
1015
- const linkProps: LinkProps = {
1016
- ...svgPropertiesNoEventsFromUnknown(linkContent),
1017
- index: i,
1018
- linkWidth,
1019
- payload: { ...link, source: sourceNode, target: targetNode },
1020
- sourceControlX,
1021
- sourceRelativeY,
1022
- sourceX,
1023
- sourceY,
1024
- targetControlX,
1025
- targetRelativeY,
1026
- targetX,
1027
- targetY,
1028
- }
1029
-
1030
- return linkProps
1031
- }
1032
-
1033
- function SankeyLinkElement(props: {
1034
- graphicalItemId: GraphicalItemId
1035
- props: LinkProps
1036
- i: number
1037
- linkContent: SankeyLinkOptions | undefined
1038
- onMouseEnter: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1039
- onMouseLeave: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1040
- onClick: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1041
- dataKey: DataKey<unknown>
1042
- }): JSX.Element {
1043
- /* eslint-disable solid/reactivity -- props.props and props.i are stable identifiers captured once at mount */
1044
- const linkProps = untrack(() => props.props)
1045
- const linkIndex = untrack(() => props.i)
1046
- const activeCoordinate = getLinkCoordinateOfTooltip(linkProps)
1047
- const activeIndex = `link-${linkIndex}`
1048
- /* eslint-enable solid/reactivity */
1049
-
1050
- const ctx = useChartStore()
1051
- const newCtx = useOptionalChartState()
1052
-
1053
- /* GOTCHA-016-C: bind both enter/leave AND over/out so fireEvent.mouseEnter, fireEvent.mouseOver, and user.hover all dispatch. Track per-instance entry state — `user.hover` fires mouseenter then mouseover; we dedupe by toggling once per real entry. */
1054
- let entered = false
1055
- const fireEnter = (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1056
- if (entered) return
1057
- entered = true
1058
- const hoverPayload = {
1059
- active: true,
1060
- coordinate: activeCoordinate,
1061
- dataKey: props.dataKey,
1062
- graphicalItemId: props.graphicalItemId,
1063
- index: activeIndex,
1064
- }
1065
- if (newCtx != null) setTooltipInteraction(newCtx.setState, "itemInteraction", "hover", hoverPayload)
1066
- props.onMouseEnter(linkProps, e)
1067
- }
1068
- const fireLeave = (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1069
- if (!entered) return
1070
- entered = false
1071
- newCtx?.setState("tooltip", "itemInteraction", "hover", "active", false)
1072
- props.onMouseLeave(linkProps, e)
1073
- }
1074
- const events = {
1075
- onClick: (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1076
- const clickPayload = {
1077
- active: true,
1078
- coordinate: activeCoordinate,
1079
- dataKey: props.dataKey,
1080
- graphicalItemId: props.graphicalItemId,
1081
- index: activeIndex,
1082
- }
1083
- if (newCtx != null) setTooltipInteraction(newCtx.setState, "itemInteraction", "click", clickPayload)
1084
- props.onClick(linkProps, e)
1085
- },
1086
- onMouseEnter: fireEnter,
1087
- onMouseOver: fireEnter,
1088
- onMouseLeave: fireLeave,
1089
- onMouseOut: fireLeave,
1090
- }
1091
-
1092
- return (
1093
- <Layer>
1094
- {renderLinkItem(
1095
- props.linkContent,
1096
- linkProps,
1097
- events as unknown as Record<string, ((e: Event) => void) | undefined>,
1098
- )}
1099
- </Layer>
1100
- )
1101
- }
1102
-
1103
- function AllSankeyLinkElements(props: {
1104
- graphicalItemId: GraphicalItemId
1105
- modifiedLinks: ReadonlyArray<LinkProps>
1106
- links: ReadonlyArray<SankeyLink>
1107
- linkContent: SankeyLinkOptions | undefined
1108
- onMouseEnter: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1109
- onMouseLeave: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1110
- onClick: (linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1111
- dataKey: DataKey<unknown>
1112
- }): JSX.Element {
1113
- return (
1114
- <Layer class="recharts-sankey-links">
1115
- <For each={props.links as SankeyLink[]}>
1116
- {(link: SankeyLink, i) => {
1117
- const linkPropsItem = () => props.modifiedLinks[i()]
1118
- return (
1119
- <Show when={linkPropsItem()}>
1120
- {(lp) => (
1121
- <SankeyLinkElement
1122
- graphicalItemId={props.graphicalItemId}
1123
- props={lp()}
1124
- linkContent={props.linkContent}
1125
- i={i()}
1126
- onMouseEnter={props.onMouseEnter}
1127
- onMouseLeave={props.onMouseLeave}
1128
- onClick={props.onClick}
1129
- dataKey={props.dataKey}
1130
- />
1131
- )}
1132
- </Show>
1133
- )
1134
- }}
1135
- </For>
1136
- </Layer>
1137
- )
1138
- }
1139
-
1140
- function renderNodeItem(
1141
- option: SankeyNodeOptions | undefined,
1142
- nodeProps: NodeProps,
1143
- events?: Record<string, ((e: Event) => void) | undefined>,
1144
- ): JSX.Element {
1145
- if (typeof option === "function") {
1146
- return option(nodeProps)
1147
- }
1148
-
1149
- return (
1150
- <Rectangle
1151
- class="recharts-sankey-node"
1152
- fill="#0088fe"
1153
- fill-opacity="0.8"
1154
- {...svgPropertiesNoEvents(nodeProps)}
1155
- {...(events ?? {})}
1156
- />
1157
- )
1158
- }
1159
-
1160
- const buildNodeProps = ({
1161
- node,
1162
- nodeContent,
1163
- top,
1164
- left,
1165
- i,
1166
- }: {
1167
- node: SankeyNode
1168
- nodeContent: SankeyNodeOptions | undefined
1169
- top: number
1170
- left: number
1171
- i: number
1172
- }): NodeProps => {
1173
- const { x, y, dx, dy } = node
1174
- const nodeProps: NodeProps = {
1175
- ...svgPropertiesNoEventsFromUnknown(nodeContent),
1176
- height: dy,
1177
- index: i,
1178
- payload: node,
1179
- width: dx,
1180
- x: x + left,
1181
- y: y + top,
1182
- }
1183
- return nodeProps
1184
- }
1185
-
1186
- function NodeElement(props: {
1187
- graphicalItemId: GraphicalItemId
1188
- props: NodeProps
1189
- nodeContent: SankeyNodeOptions | undefined
1190
- i: number
1191
- onMouseEnter: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1192
- onMouseLeave: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1193
- onClick: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1194
- dataKey: DataKey<unknown>
1195
- }): JSX.Element {
1196
- const ctx = useChartStore()
1197
- const newCtx = useOptionalChartState()
1198
-
1199
- /* eslint-disable solid/reactivity -- props.props and props.i are stable identifiers captured once at mount */
1200
- const nodeProps = untrack(() => props.props)
1201
- const nodeIndex = untrack(() => props.i)
1202
- const activeCoordinate = getNodeCoordinateOfTooltip(nodeProps)
1203
- const activeIndex = `node-${nodeIndex}`
1204
- /* eslint-enable solid/reactivity */
1205
-
1206
- /* GOTCHA-016-C: same pattern as SankeyLinkElement — bind both enter/leave AND over/out, dedupe via per-instance entry flag. */
1207
- let entered = false
1208
- const fireEnter = (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1209
- if (entered) return
1210
- entered = true
1211
- const hoverPayload = {
1212
- active: true,
1213
- coordinate: activeCoordinate,
1214
- dataKey: props.dataKey,
1215
- graphicalItemId: props.graphicalItemId,
1216
- index: activeIndex,
1217
- }
1218
- if (newCtx != null) setTooltipInteraction(newCtx.setState, "itemInteraction", "hover", hoverPayload)
1219
- props.onMouseEnter(nodeProps, e)
1220
- }
1221
- const fireLeave = (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1222
- if (!entered) return
1223
- entered = false
1224
- newCtx?.setState("tooltip", "itemInteraction", "hover", "active", false)
1225
- props.onMouseLeave(nodeProps, e)
1226
- }
1227
- const events = {
1228
- onClick: (e: MouseEvent & { currentTarget: SVGGraphicsElement }) => {
1229
- const clickPayload = {
1230
- active: true,
1231
- coordinate: activeCoordinate,
1232
- dataKey: props.dataKey,
1233
- graphicalItemId: props.graphicalItemId,
1234
- index: activeIndex,
1235
- }
1236
- if (newCtx != null) setTooltipInteraction(newCtx.setState, "itemInteraction", "click", clickPayload)
1237
- props.onClick(nodeProps, e)
1238
- },
1239
- onMouseEnter: fireEnter,
1240
- onMouseOver: fireEnter,
1241
- onMouseLeave: fireLeave,
1242
- onMouseOut: fireLeave,
1243
- }
1244
-
1245
- return (
1246
- <Layer>
1247
- {renderNodeItem(
1248
- props.nodeContent,
1249
- nodeProps,
1250
- events as unknown as Record<string, ((e: Event) => void) | undefined>,
1251
- )}
1252
- </Layer>
1253
- )
1254
- }
1255
-
1256
- function AllNodeElements(props: {
1257
- graphicalItemId: GraphicalItemId
1258
- modifiedNodes: ReadonlyArray<NodeProps>
1259
- nodeContent: SankeyNodeOptions | undefined
1260
- onMouseEnter: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1261
- onMouseLeave: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1262
- onClick: (nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
1263
- dataKey: DataKey<unknown>
1264
- }): JSX.Element {
1265
- return (
1266
- <Layer class="recharts-sankey-nodes">
1267
- <For each={props.modifiedNodes as NodeProps[]}>
1268
- {(modifiedNode, i) => (
1269
- <NodeElement
1270
- graphicalItemId={props.graphicalItemId}
1271
- props={modifiedNode}
1272
- nodeContent={props.nodeContent}
1273
- i={i()}
1274
- onMouseEnter={props.onMouseEnter}
1275
- onMouseLeave={props.onMouseLeave}
1276
- onClick={props.onClick}
1277
- dataKey={props.dataKey}
1278
- />
1279
- )}
1280
- </For>
1281
- </Layer>
1282
- )
1283
- }
1284
-
1285
- export const sankeyDefaultProps = {
1286
- accessibilityLayer: true,
1287
- align: "justify",
1288
- dataKey: "value",
1289
- iterations: 32,
1290
- linkCurvature: 0.5,
1291
- margin: { bottom: 5, left: 5, right: 5, top: 5 },
1292
- nameKey: "name",
1293
- nodePadding: 10,
1294
- nodeWidth: 10,
1295
- sort: true,
1296
- verticalAlign: "justify",
1297
- ...initialEventSettingsState,
1298
- } as const satisfies Partial<Props>
1299
-
1300
- type PropsWithResolvedDefaults = RequiresDefaultProps<Props, typeof sankeyDefaultProps>
1301
-
1302
- type InternalSankeyProps = WithIdRequired<PropsWithResolvedDefaults>
1303
-
1304
- function SankeyImpl(props: InternalSankeyProps): JSX.Element {
1305
- const width = createMemo(() => useChartWidth())
1306
- const height = createMemo(() => useChartHeight())
1307
-
1308
- const computed = createMemo(() => {
1309
- const w = width()
1310
- const h = height()
1311
- if (w == null || h == null || w <= 0 || h <= 0 || props.data == null) {
1312
- return {
1313
- links: [] as SankeyLink[],
1314
- modifiedLinks: [] as LinkProps[],
1315
- modifiedNodes: [] as NodeProps[],
1316
- nodes: [] as SankeyNode[],
1317
- }
1318
- }
1319
- const contentWidth = w - (props.margin.left ?? 0) - (props.margin.right ?? 0)
1320
- const contentHeight = h - (props.margin.top ?? 0) - (props.margin.bottom ?? 0)
1321
- const result = computeData({
1322
- align: props.align,
1323
- data: props.data,
1324
- height: contentHeight,
1325
- iterations: props.iterations,
1326
- nodePadding: props.nodePadding,
1327
- nodeWidth: props.nodeWidth,
1328
- sort: props.sort,
1329
- verticalAlign: props.verticalAlign,
1330
- width: contentWidth,
1331
- })
1332
-
1333
- const top = props.margin.top || 0
1334
- const left = props.margin.left || 0
1335
- const newModifiedLinks = result.links
1336
- .map((l, i) => {
1337
- return buildLinkProps({
1338
- i,
1339
- left,
1340
- link: l,
1341
- linkContent: props.link,
1342
- linkCurvature: props.linkCurvature,
1343
- nodes: result.nodes,
1344
- top,
1345
- })
1346
- })
1347
- .filter(isNotNil)
1348
-
1349
- const newModifiedNodes = result.nodes.map((n, i) => {
1350
- return buildNodeProps({
1351
- i,
1352
- left,
1353
- node: n,
1354
- nodeContent: props.node,
1355
- top,
1356
- })
1357
- })
1358
-
1359
- return {
1360
- links: result.links,
1361
- modifiedLinks: newModifiedLinks,
1362
- modifiedNodes: newModifiedNodes,
1363
- nodes: result.nodes,
1364
- }
1365
- })
1366
-
1367
- function handleMouseEnter(item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) {
1368
- if (props.onMouseEnter) {
1369
- props.onMouseEnter(item, type, e)
1370
- }
1371
- }
1372
-
1373
- function handleMouseLeave(item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) {
1374
- if (props.onMouseLeave) {
1375
- props.onMouseLeave(item, type, e)
1376
- }
1377
- }
1378
-
1379
- function handleClick(item: NodeProps | LinkProps, type: SankeyElementType, e: MouseEvent & { currentTarget: SVGGraphicsElement }) {
1380
- if (props.onClick) {
1381
- props.onClick(item, type, e)
1382
- }
1383
- }
1384
-
1385
- const attrs = () => svgPropertiesNoEvents(props)
1386
-
1387
- const tabIndex = () => {
1388
- const explicit = props.tabIndex ?? props.tabindex
1389
- if (typeof explicit === "number") {
1390
- return explicit
1391
- }
1392
- return props.accessibilityLayer ? 0 : undefined
1393
- }
1394
-
1395
- const role = () => {
1396
- if (typeof props.role === "string") {
1397
- return props.role
1398
- }
1399
- return props.accessibilityLayer ? "application" : undefined
1400
- }
1401
-
1402
- return (
1403
- <Show
1404
- when={
1405
- isPositiveNumber(width()) &&
1406
- isPositiveNumber(height()) &&
1407
- props.data?.links &&
1408
- props.data?.nodes
1409
- }
1410
- >
1411
- <SetComputedData
1412
- computedData={{ links: computed().modifiedLinks, nodes: computed().modifiedNodes }}
1413
- />
1414
- <Surface
1415
- {...attrs()}
1416
- title={props.title}
1417
- desc={props.desc}
1418
- role={role()}
1419
- tabindex={tabIndex()}
1420
- width={width() ?? 0}
1421
- height={height() ?? 0}
1422
- >
1423
- {props.children}
1424
- <AllSankeyLinkElements
1425
- graphicalItemId={props.id}
1426
- links={computed().links}
1427
- modifiedLinks={computed().modifiedLinks}
1428
- linkContent={props.link}
1429
- dataKey={props.dataKey}
1430
- onMouseEnter={(linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) =>
1431
- handleMouseEnter(linkProps, "link", e)
1432
- }
1433
- onMouseLeave={(linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) =>
1434
- handleMouseLeave(linkProps, "link", e)
1435
- }
1436
- onClick={(linkProps: LinkProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => handleClick(linkProps, "link", e)}
1437
- />
1438
- <AllNodeElements
1439
- graphicalItemId={props.id}
1440
- modifiedNodes={computed().modifiedNodes}
1441
- nodeContent={props.node}
1442
- dataKey={props.dataKey}
1443
- onMouseEnter={(nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) =>
1444
- handleMouseEnter(nodeProps, "node", e)
1445
- }
1446
- onMouseLeave={(nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) =>
1447
- handleMouseLeave(nodeProps, "node", e)
1448
- }
1449
- onClick={(nodeProps: NodeProps, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => handleClick(nodeProps, "node", e)}
1450
- />
1451
- </Surface>
1452
- </Show>
1453
- )
1454
- }
1455
-
1456
- /**
1457
- * Flow diagram in which the width of the arrows is proportional to the flow rate.
1458
- * It is typically used to visualize energy or material or cost transfers between processes.
1459
- *
1460
- * @consumes ResponsiveContainerContext
1461
- * @provides TooltipEntrySettings
1462
- */
1463
- export function Sankey(outsideProps: Props): JSX.Element {
1464
- /* GOTCHA-005-B: do not spread {...props} into a deep child — that enumerates the
1465
- Solid props proxy and triggers `children` getter, which instantiates user JSX
1466
- (Tooltip, Customized, etc.) under the OUTER owner (no RechartsWrapper Provider
1467
- in scope). Strip children via splitProps and pass them as JSX so they're created
1468
- inside RechartsWrapper where TooltipPortalContext / LegendPortalContext live. */
1469
- const [childrenSplit, restProps] = splitProps(outsideProps, ["children"])
1470
- const props: PropsWithResolvedDefaults = resolveDefaultProps(restProps, sankeyDefaultProps)
1471
-
1472
- return (
1473
- <RechartsStateProvider
1474
- preloadedState={{
1475
- layout: untrack(() =>
1476
- createInitialLayoutState({ height: props.height, margin: props.margin, width: props.width }),
1477
- ),
1478
- options,
1479
- }}
1480
- >
1481
- <ReportChartSize width={props.width} height={props.height} />
1482
- <ReportChartMargin margin={props.margin} />
1483
- <ReportEventSettings
1484
- throttleDelay={props.throttleDelay}
1485
- throttledEvents={props.throttledEvents}
1486
- />
1487
-
1488
- <RechartsWrapper
1489
- class={props.class}
1490
- style={props.style}
1491
- width={props.width}
1492
- height={props.height}
1493
- /*
1494
- * Sankey, same as Treemap, suffers from overfilling the container
1495
- * and causing infinite render loops where the chart keeps growing.
1496
- */
1497
- responsive={false}
1498
- onMouseEnter={undefined}
1499
- onMouseLeave={undefined}
1500
- onClick={undefined}
1501
- onMouseMove={undefined}
1502
- onMouseDown={undefined}
1503
- onMouseUp={undefined}
1504
- onContextMenu={undefined}
1505
- onDoubleClick={undefined}
1506
- onTouchStart={undefined}
1507
- onTouchMove={undefined}
1508
- onTouchEnd={undefined}
1509
- >
1510
- <RegisterGraphicalItemId id={props.id} type="sankey">
1511
- {(id) => (
1512
- <>
1513
- <SetSankeyTooltipEntrySettings
1514
- dataKey={props.dataKey}
1515
- nameKey={props.nameKey}
1516
- stroke={props.stroke}
1517
- strokeWidth={props.strokeWidth}
1518
- fill={props.fill}
1519
- name={props.name}
1520
- data={props.data}
1521
- id={id}
1522
- />
1523
- <SankeyImpl {...props} id={id}>
1524
- {childrenSplit.children}
1525
- </SankeyImpl>
1526
- </>
1527
- )}
1528
- </RegisterGraphicalItemId>
1529
- </RechartsWrapper>
1530
- </RechartsStateProvider>
1531
- )
1532
- }
1533
-
1534
- Sankey.displayName = "Sankey"