@octanejs/recharts 0.1.62 → 0.1.64

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 (73) hide show
  1. package/package.json +5 -5
  2. package/src/animation/AnimatedItems.tsrx +36 -31
  3. package/src/animation/CSSTransitionAnimate.tsrx +1 -2
  4. package/src/animation/JavascriptAnimate.tsrx +1 -2
  5. package/src/cartesian/Area.tsrx +414 -386
  6. package/src/cartesian/AreaRevealShape.tsrx +103 -84
  7. package/src/cartesian/Bar.tsrx +343 -317
  8. package/src/cartesian/BarStack.tsrx +33 -28
  9. package/src/cartesian/CartesianAxis.tsrx +168 -165
  10. package/src/cartesian/CartesianGrid.tsrx +256 -272
  11. package/src/cartesian/ErrorBar.tsrx +108 -104
  12. package/src/cartesian/Funnel.tsrx +405 -382
  13. package/src/cartesian/GraphicalItemClipPath.tsrx +4 -8
  14. package/src/cartesian/Line.tsrx +190 -177
  15. package/src/cartesian/LineDrawShape.tsrx +14 -15
  16. package/src/cartesian/ReferenceLine.tsrx +119 -105
  17. package/src/cartesian/Scatter.tsrx +416 -398
  18. package/src/cartesian/XAxis.tsrx +39 -32
  19. package/src/cartesian/YAxis.tsrx +47 -37
  20. package/src/cartesian/ZAxis.tsrx +76 -73
  21. package/src/chart/AreaChart.tsrx +15 -11
  22. package/src/chart/BarChart.tsrx +15 -11
  23. package/src/chart/CategoricalChart.tsrx +32 -26
  24. package/src/chart/ComposedChart.tsrx +15 -11
  25. package/src/chart/FunnelChart.tsrx +15 -11
  26. package/src/chart/LineChart.tsrx +15 -11
  27. package/src/chart/PieChart.tsrx +15 -11
  28. package/src/chart/PolarChart.tsrx +45 -48
  29. package/src/chart/RadarChart.tsrx +38 -32
  30. package/src/chart/RadialBarChart.tsrx +15 -11
  31. package/src/chart/RechartsWrapper.tsrx +214 -162
  32. package/src/chart/Sankey.tsrx +412 -378
  33. package/src/chart/ScatterChart.tsrx +15 -11
  34. package/src/chart/SunburstChart.tsrx +162 -155
  35. package/src/component/ActivePoints.tsrx +19 -13
  36. package/src/component/Cursor.tsrx +25 -18
  37. package/src/component/DefaultLegendContent.tsrx +131 -127
  38. package/src/component/DefaultTooltipContent.tsrx +46 -42
  39. package/src/component/Dots.tsrx +11 -5
  40. package/src/component/Label.tsrx +69 -55
  41. package/src/component/LabelList.tsrx +32 -27
  42. package/src/component/Legend.tsrx +120 -123
  43. package/src/component/ResponsiveContainer.tsrx +18 -11
  44. package/src/component/Text.tsrx +50 -43
  45. package/src/component/Tooltip.tsrx +234 -223
  46. package/src/component/TooltipBoundingBox.tsrx +34 -34
  47. package/src/container/ClipPathProvider.tsrx +1 -3
  48. package/src/container/Layer.tsrx +5 -1
  49. package/src/container/RootSurface.tsrx +31 -21
  50. package/src/container/Surface.tsrx +15 -13
  51. package/src/context/ErrorBarContext.tsrx +5 -5
  52. package/src/polar/Pie.tsrx +541 -487
  53. package/src/polar/PolarAngleAxis.tsrx +245 -227
  54. package/src/polar/PolarGrid.tsrx +139 -127
  55. package/src/polar/PolarRadiusAxis.tsrx +204 -185
  56. package/src/polar/Radar.tsrx +274 -264
  57. package/src/polar/RadialBar.tsrx +408 -361
  58. package/src/shape/Cross.tsrx +13 -7
  59. package/src/shape/Curve.tsrx +54 -44
  60. package/src/shape/Dot.tsrx +10 -8
  61. package/src/shape/Polygon.tsrx +38 -29
  62. package/src/shape/Rectangle.tsrx +73 -28
  63. package/src/shape/Sector.tsrx +30 -18
  64. package/src/shape/Symbols.tsrx +13 -11
  65. package/src/shape/Trapezoid.tsrx +16 -11
  66. package/src/state/RechartsStoreProvider.tsrx +5 -1
  67. package/src/synchronisation/useChartSynchronisation.tsrx +8 -7
  68. package/src/util/BarUtils.tsrx +43 -40
  69. package/src/util/FunnelUtils.tsrx +5 -5
  70. package/src/util/RadialBarUtils.tsrx +3 -4
  71. package/src/util/ScatterUtils.tsrx +13 -8
  72. package/src/zIndex/ZIndexLayer.tsrx +2 -2
  73. package/src/zIndex/ZIndexPortal.tsrx +2 -8
@@ -73,53 +73,56 @@ const cubicValue = (
73
73
  t: number,
74
74
  ): number => {
75
75
  const inverseT = 1 - t;
76
- return inverseT ** 3 * start + 3 * inverseT ** 2 * t * control1 +
76
+ return (
77
+ inverseT ** 3 * start +
78
+ 3 * inverseT ** 2 * t * control1 +
77
79
  3 * inverseT * t ** 2 * control2 +
78
- t ** 3 * end;
80
+ t ** 3 * end
81
+ );
79
82
  };
80
83
 
81
84
  // TODO why is this not reading dataKey?
82
85
  const getValue = (entry: LinkDataItem | SankeyNode | undefined): number =>
83
- entry && entry.value || 0;
86
+ (entry && entry.value) || 0;
84
87
 
85
- const getSumOfIds = (links: ReadonlyArray<LinkDataItem>, ids: number[]): number => ids.reduce(
86
- (result, id) => result + getValue(links[id]),
87
- 0,
88
- );
88
+ const getSumOfIds = (links: ReadonlyArray<LinkDataItem>, ids: number[]): number =>
89
+ ids.reduce((result, id) => result + getValue(links[id]), 0);
89
90
 
90
91
  const getSumWithWeightedSource = (
91
92
  tree: ReadonlyArray<SankeyNode>,
92
93
  links: ReadonlyArray<LinkDataItemDy>,
93
94
  ids: number[],
94
- ) => ids.reduce((result, id) => {
95
- const link = links[id];
96
- if (link == null) {
97
- return result;
98
- }
99
- const sourceNode = tree[link.source];
100
- if (sourceNode == null) {
101
- return result;
102
- }
95
+ ) =>
96
+ ids.reduce((result, id) => {
97
+ const link = links[id];
98
+ if (link == null) {
99
+ return result;
100
+ }
101
+ const sourceNode = tree[link.source];
102
+ if (sourceNode == null) {
103
+ return result;
104
+ }
103
105
 
104
- return result + centerY(sourceNode) * getValue(links[id]);
105
- }, 0);
106
+ return result + centerY(sourceNode) * getValue(links[id]);
107
+ }, 0);
106
108
 
107
109
  const getSumWithWeightedTarget = (
108
110
  tree: ReadonlyArray<SankeyNode>,
109
111
  links: ReadonlyArray<LinkDataItemDy>,
110
112
  ids: ReadonlyArray<number>,
111
- ): number => ids.reduce((result: number, id: number) => {
112
- const link = links[id];
113
- if (link == null) {
114
- return result;
115
- }
116
- const targetNode = tree[link.target];
117
- if (targetNode == null) {
118
- return result;
119
- }
113
+ ): number =>
114
+ ids.reduce((result: number, id: number) => {
115
+ const link = links[id];
116
+ if (link == null) {
117
+ return result;
118
+ }
119
+ const targetNode = tree[link.target];
120
+ if (targetNode == null) {
121
+ return result;
122
+ }
120
123
 
121
- return result + centerY(targetNode) * getValue(links[id]);
122
- }, 0);
124
+ return result + centerY(targetNode) * getValue(links[id]);
125
+ }, 0);
123
126
 
124
127
  const ascendingY = (a: { y: number }, b: { y: number }) => a.y - b.y;
125
128
 
@@ -159,10 +162,10 @@ const updateDepthOfTargets = (tree: SankeyNode[], curNode: SankeyNode) => {
159
162
  if (target) {
160
163
  const newDepth = curNode.depth + 1;
161
164
  /*
162
- * Only recurse when the depth grows. Depth is the longest path to a node, so once it stops increasing
163
- * the subtree is already up to date; without this guard every path through the graph is walked
164
- * separately, which explodes combinatorially on dense graphs.
165
- */
165
+ * Only recurse when the depth grows. Depth is the longest path to a node, so once it stops increasing
166
+ * the subtree is already up to date; without this guard every path through the graph is walked
167
+ * separately, which explodes combinatorially on dense graphs.
168
+ */
166
169
  if (newDepth > target.depth) {
167
170
  target.depth = newDepth;
168
171
  updateDepthOfTargets(tree, target);
@@ -292,9 +295,10 @@ const updateYOfTree = (
292
295
  }
293
296
  }
294
297
 
295
- return links.map(
296
- (link: LinkDataItem): LinkDataItemDy => ({ ...link, dy: getValue(link) * yRatio }),
297
- );
298
+ return links.map((link: LinkDataItem): LinkDataItemDy => ({
299
+ ...link,
300
+ dy: getValue(link) * yRatio,
301
+ }));
298
302
  };
299
303
 
300
304
  const resolveCollisions = (
@@ -369,8 +373,7 @@ const relaxLeftToRight = (
369
373
  if (node.sourceLinks.length) {
370
374
  const sourceSum = getSumOfIds(links, node.sourceLinks);
371
375
  const weightedSum = getSumWithWeightedSource(tree, links, node.sourceLinks);
372
- const y =
373
- sourceSum === 0 ? centerY(node) : weightedSum / sourceSum;
376
+ const y = sourceSum === 0 ? centerY(node) : weightedSum / sourceSum;
374
377
 
375
378
  node.y += (y - centerY(node)) * alpha;
376
379
  }
@@ -381,8 +384,8 @@ const relaxLeftToRight = (
381
384
  const relaxRightToLeft = (
382
385
  tree: ReadonlyArray<SankeyNode>,
383
386
  /*
384
- * depthTree array is modified by this method!
385
- */
387
+ * depthTree array is modified by this method!
388
+ */
386
389
  depthTree: SankeyNode[][],
387
390
  links: ReadonlyArray<LinkDataItemDy>,
388
391
  alpha: number,
@@ -402,8 +405,7 @@ const relaxRightToLeft = (
402
405
  if (node.targetLinks.length) {
403
406
  const targetSum = getSumOfIds(links, node.targetLinks);
404
407
  const weightedSum = getSumWithWeightedTarget(tree, links, node.targetLinks);
405
- const y =
406
- targetSum === 0 ? centerY(node) : weightedSum / targetSum;
408
+ const y = targetSum === 0 ? centerY(node) : weightedSum / targetSum;
407
409
 
408
410
  node.y += (y - centerY(node)) * alpha;
409
411
  }
@@ -411,10 +413,10 @@ const relaxRightToLeft = (
411
413
  }
412
414
  };
413
415
 
414
- const updateYOfLinks: (tree: SankeyNode[], links: LinkDataItemDy[]) => asserts links is SankeyLink[] = (
415
- tree,
416
- links,
417
- ) => {
416
+ const updateYOfLinks: (
417
+ tree: SankeyNode[],
418
+ links: LinkDataItemDy[],
419
+ ) => asserts links is SankeyLink[] = (tree, links) => {
418
420
  for (let i = 0, len = tree.length; i < len; i++) {
419
421
  const node = tree[i];
420
422
  if (node == null) {
@@ -486,8 +488,7 @@ const getLinkYAtX = (
486
488
  ): number => {
487
489
  const sourceX = sourceNode.x + sourceNode.dx;
488
490
  const targetX = targetNode.x;
489
- const progress =
490
- targetX === sourceX ? 0 : (x - sourceX) / (targetX - sourceX);
491
+ const progress = targetX === sourceX ? 0 : (x - sourceX) / (targetX - sourceX);
491
492
  const boundedProgress = Math.min(Math.max(progress, 0), 1);
492
493
  const sourceY = sourceNode.y + (link.sy ?? 0) + link.dy / 2;
493
494
  const targetY = targetNode.y + (link.ty ?? 0) + link.dy / 2;
@@ -521,8 +522,7 @@ const resolveNodeLinkCollisions = (
521
522
  continue;
522
523
  }
523
524
 
524
- const depthX =
525
- nodes[0] == null ? undefined : nodes[0].x + nodes[0].dx / 2;
525
+ const depthX = nodes[0] == null ? undefined : nodes[0].x + nodes[0].dx / 2;
526
526
  if (depthX == null) {
527
527
  continue;
528
528
  }
@@ -541,21 +541,18 @@ const resolveNodeLinkCollisions = (
541
541
  }
542
542
 
543
543
  if (
544
- depth <= Math.min(sourceDepth, targetDepth) || depth >= Math.max(sourceDepth, targetDepth)
544
+ depth <= Math.min(sourceDepth, targetDepth) ||
545
+ depth >= Math.max(sourceDepth, targetDepth)
545
546
  ) {
546
547
  return [];
547
548
  }
548
549
 
549
550
  const y = getLinkYAtX(sourceNode, targetNode, link, depthX) - link.dy / 2;
550
- return [
551
- { y, dy: link.dy, fixed: true as const },
552
- ];
551
+ return [{ y, dy: link.dy, fixed: true as const }];
553
552
  });
554
553
 
555
- const containedNodeObstacles = fixedObstacles.filter(
556
- (obstacle) => nodes.some(
557
- (node) => node.y >= obstacle.y && node.y + node.dy <= obstacle.y + obstacle.dy,
558
- ),
554
+ const containedNodeObstacles = fixedObstacles.filter((obstacle) =>
555
+ nodes.some((node) => node.y >= obstacle.y && node.y + node.dy <= obstacle.y + obstacle.dy),
559
556
  );
560
557
 
561
558
  if (containedNodeObstacles.length === 0) {
@@ -650,7 +647,7 @@ export const computeData = ({
650
647
  if (verticalAlign === 'justify') {
651
648
  let alpha = 1;
652
649
  for (let i = 1; i <= iterations; i++) {
653
- relaxRightToLeft(tree, depthTree, linksWithDy, alpha *= 0.99);
650
+ relaxRightToLeft(tree, depthTree, linksWithDy, (alpha *= 0.99));
654
651
 
655
652
  resolveCollisions(depthTree, height, nodePadding, sort);
656
653
 
@@ -685,11 +682,10 @@ const getLinkCoordinateOfTooltip = (item: LinkProps): Coordinate | undefined =>
685
682
  // Layout augments the user's data records, retaining arbitrary fields selected
686
683
  // by nameKey. Computed link payloads contain node objects, not source indices.
687
684
  type SankeyTooltipNode = SankeyNode & Record<string | number, unknown>;
688
- type SankeyTooltipLink =
689
- Omit<LinkProps['payload'], 'source' | 'target'> & {
690
- source: SankeyTooltipNode;
691
- target: SankeyTooltipNode;
692
- } & Record<string | number, unknown>;
685
+ type SankeyTooltipLink = Omit<LinkProps['payload'], 'source' | 'target'> & {
686
+ source: SankeyTooltipNode;
687
+ target: SankeyTooltipNode;
688
+ } & Record<string | number, unknown>;
693
689
  type SankeyTooltipPayload = {
694
690
  payload: SankeyTooltipNode | SankeyTooltipLink;
695
691
  name: unknown;
@@ -753,38 +749,40 @@ const options: ChartOptions = {
753
749
  eventEmitter: undefined,
754
750
  };
755
751
 
756
- const SetSankeyTooltipEntrySettings = React.memo(({
757
- dataKey,
758
- nameKey,
759
- stroke,
760
- strokeWidth,
761
- fill,
762
- name,
763
- data,
764
- id,
765
- }: Pick<
766
- InternalSankeyProps,
767
- 'dataKey' | 'nameKey' | 'stroke' | 'strokeWidth' | 'fill' | 'name' | 'data' | 'id'
768
- >) => {
769
- const tooltipEntrySettings: TooltipPayloadConfiguration = {
770
- dataDefinedOnItem: data,
771
- getPosition: noop,
772
- settings: {
773
- stroke,
774
- strokeWidth,
775
- fill,
776
- dataKey,
777
- name,
778
- nameKey,
779
- hide: false,
780
- type: undefined,
781
- color: fill,
782
- unit: '',
783
- graphicalItemId: id,
784
- },
785
- };
786
- return <SetTooltipEntrySettings tooltipEntrySettings={tooltipEntrySettings} />;
787
- });
752
+ const SetSankeyTooltipEntrySettings = React.memo(
753
+ ({
754
+ dataKey,
755
+ nameKey,
756
+ stroke,
757
+ strokeWidth,
758
+ fill,
759
+ name,
760
+ data,
761
+ id,
762
+ }: Pick<
763
+ InternalSankeyProps,
764
+ 'dataKey' | 'nameKey' | 'stroke' | 'strokeWidth' | 'fill' | 'name' | 'data' | 'id'
765
+ >) => {
766
+ const tooltipEntrySettings: TooltipPayloadConfiguration = {
767
+ dataDefinedOnItem: data,
768
+ getPosition: noop,
769
+ settings: {
770
+ stroke,
771
+ strokeWidth,
772
+ fill,
773
+ dataKey,
774
+ name,
775
+ nameKey,
776
+ hide: false,
777
+ type: undefined,
778
+ color: fill,
779
+ unit: '',
780
+ graphicalItemId: id,
781
+ },
782
+ };
783
+ return <SetTooltipEntrySettings tooltipEntrySettings={tooltipEntrySettings} />;
784
+ },
785
+ );
788
786
 
789
787
  interface LinkDataItem {
790
788
  source: number;
@@ -825,11 +823,10 @@ export interface SankeyData {
825
823
  export type SankeyNodeOptions =
826
824
  OctaneElement<RectangleProps> | ((props: NodeProps) => OctaneNode) | RectangleProps;
827
825
 
828
- type SankeyLinkSvgProps =
829
- Omit<SVGProps<SVGPathElement>, 'targetX' | 'targetY'> & {
830
- targetX?: number;
831
- targetY?: number;
832
- };
826
+ type SankeyLinkSvgProps = Omit<SVGProps<SVGPathElement>, 'targetX' | 'targetY'> & {
827
+ targetX?: number;
828
+ targetY?: number;
829
+ };
833
830
 
834
831
  type SankeyLinkOptions =
835
832
  | OctaneElement<SankeyLinkSvgProps>
@@ -838,139 +835,145 @@ type SankeyLinkOptions =
838
835
 
839
836
  interface SankeyProps extends EventThrottlingProps {
840
837
  /**
841
- * Name represents each sector in the tooltip.
842
- * This allows you to extract the name from the data:
843
- *
844
- * - `string`: the name of the field in the data object;
845
- * - `number`: the index of the field in the data;
846
- * - `function`: a function that receives the data object and returns the name.
847
- *
848
- * @defaultValue name
849
- */
838
+ * Name represents each sector in the tooltip.
839
+ * This allows you to extract the name from the data:
840
+ *
841
+ * - `string`: the name of the field in the data object;
842
+ * - `number`: the index of the field in the data;
843
+ * - `function`: a function that receives the data object and returns the name.
844
+ *
845
+ * @defaultValue name
846
+ */
850
847
  nameKey?: DataKey<any>;
851
848
  /**
852
- * dataKey prop in Sankey defines which key in the link objects represents the value of the link _in Tooltip only_.
853
- *
854
- * Unlike other charts where dataKey is used to extract values from the data array, in Sankey charts,
855
- * the value of each link is directly taken from the 'value' property of the link objects.
856
- *
857
- * @default 'value'
858
- */
849
+ * dataKey prop in Sankey defines which key in the link objects represents the value of the link _in Tooltip only_.
850
+ *
851
+ * Unlike other charts where dataKey is used to extract values from the data array, in Sankey charts,
852
+ * the value of each link is directly taken from the 'value' property of the link objects.
853
+ *
854
+ * @default 'value'
855
+ */
859
856
  dataKey?: DataKey<any>;
860
857
  /**
861
- * The width of chart container.
862
- * Can be a number or a percent string like "100%".
863
- *
864
- * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
865
- */
858
+ * The width of chart container.
859
+ * Can be a number or a percent string like "100%".
860
+ *
861
+ * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
862
+ */
866
863
  width?: number | Percent;
867
864
  /**
868
- * The height of chart container.
869
- * Can be a number or a percent string like "100%".
870
- *
871
- * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
872
- */
865
+ * The height of chart container.
866
+ * Can be a number or a percent string like "100%".
867
+ *
868
+ * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart sizing guide}
869
+ */
873
870
  height?: number | Percent;
874
871
  /**
875
- * The source data, including the array of nodes, and the relationships, represented by links.
876
- *
877
- * Note that Sankey requires a specific data structure.
878
- * Each node should have a unique index in the nodes array, and each link should reference these nodes by their indices.
879
- * This is different from other chart types in Recharts, which accept arbitrary data.
880
- *
881
- * @example
882
- * nodes: [
883
- * { name: 'Visit' },
884
- * { name: 'Direct-Favourite' },
885
- * { name: 'Page-Click' },
886
- * { name: 'Detail-Favourite' },
887
- * { name: 'Lost' },
888
- * ],
889
- * links: [
890
- * { source: 0, target: 1, value: 3728.3 },
891
- * { source: 0, target: 2, value: 354170 },
892
- * { source: 2, target: 3, value: 62429 },
893
- * { source: 2, target: 4, value: 291741 },
894
- * ],
895
- */
872
+ * The source data, including the array of nodes, and the relationships, represented by links.
873
+ *
874
+ * Note that Sankey requires a specific data structure.
875
+ * Each node should have a unique index in the nodes array, and each link should reference these nodes by their indices.
876
+ * This is different from other chart types in Recharts, which accept arbitrary data.
877
+ *
878
+ * @example
879
+ * nodes: [
880
+ * { name: 'Visit' },
881
+ * { name: 'Direct-Favourite' },
882
+ * { name: 'Page-Click' },
883
+ * { name: 'Detail-Favourite' },
884
+ * { name: 'Lost' },
885
+ * ],
886
+ * links: [
887
+ * { source: 0, target: 1, value: 3728.3 },
888
+ * { source: 0, target: 2, value: 354170 },
889
+ * { source: 2, target: 3, value: 62429 },
890
+ * { source: 2, target: 4, value: 291741 },
891
+ * ],
892
+ */
896
893
  data: SankeyData;
897
894
  /**
898
- * The padding between the nodes
899
- * @default 10
900
- */
895
+ * The padding between the nodes
896
+ * @default 10
897
+ */
901
898
  nodePadding?: number;
902
899
  /**
903
- * The width of node
904
- * @default 10
905
- */
900
+ * The width of node
901
+ * @default 10
902
+ */
906
903
  nodeWidth?: number;
907
904
  /**
908
- * The curvature of width
909
- * @default 0.5
910
- */
905
+ * The curvature of width
906
+ * @default 0.5
907
+ */
911
908
  linkCurvature?: number;
912
909
  /**
913
- * The number of the iterations between the links
914
- * @default 32
915
- */
910
+ * The number of the iterations between the links
911
+ * @default 32
912
+ */
916
913
  iterations?: number;
917
914
  /**
918
- * If set an object, the option is the configuration of nodes.
919
- * If set a React element, the option is the custom react element of drawing the nodes.
920
- *
921
- * @example <Sankey node={MyCustomComponent} />
922
- * @example <Sankey node={{stroke: #77c878, strokeWidth: 2}} />
923
- */
915
+ * If set an object, the option is the configuration of nodes.
916
+ * If set a React element, the option is the custom react element of drawing the nodes.
917
+ *
918
+ * @example <Sankey node={MyCustomComponent} />
919
+ * @example <Sankey node={{stroke: #77c878, strokeWidth: 2}} />
920
+ */
924
921
  node?: SankeyNodeOptions;
925
922
  /**
926
- * If set an object, the option is the configuration of links.
927
- * If set a React element, the option is the custom react element of drawing the links.
928
- *
929
- * @example <Sankey link={MyCustomComponent} />
930
- * @example <Sankey link={{ fill: #77c878 }} />
931
- */
923
+ * If set an object, the option is the configuration of links.
924
+ * If set a React element, the option is the custom react element of drawing the links.
925
+ *
926
+ * @example <Sankey link={MyCustomComponent} />
927
+ * @example <Sankey link={{ fill: #77c878 }} />
928
+ */
932
929
  link?: SankeyLinkOptions;
933
930
  style?: CSSProperties;
934
931
  className?: string;
935
932
  children?: OctaneNode;
936
933
  /**
937
- * Empty space around the container.
938
- *
939
- * @defaultValue {"top":5,"right":5,"bottom":5,"left":5}
940
- */
934
+ * Empty space around the container.
935
+ *
936
+ * @defaultValue {"top":5,"right":5,"bottom":5,"left":5}
937
+ */
941
938
  margin?: Partial<Margin>;
942
939
  /**
943
- * The customized event handler of click on the area in this group
944
- */
945
- onClick?: (item: NodeProps | LinkProps, type: SankeyElementType, e: NativeMouseEvent<
946
- SVGGraphicsElement
947
- >) => void;
940
+ * The customized event handler of click on the area in this group
941
+ */
942
+ onClick?: (
943
+ item: NodeProps | LinkProps,
944
+ type: SankeyElementType,
945
+ e: NativeMouseEvent<SVGGraphicsElement>,
946
+ ) => void;
948
947
  /**
949
- * The customized event handler of mouseenter on the area in this group
950
- */
951
- onMouseEnter?: (item: NodeProps | LinkProps, type: SankeyElementType, e: NativeMouseEvent<
952
- SVGGraphicsElement
953
- >) => void;
948
+ * The customized event handler of mouseenter on the area in this group
949
+ */
950
+ onMouseEnter?: (
951
+ item: NodeProps | LinkProps,
952
+ type: SankeyElementType,
953
+ e: NativeMouseEvent<SVGGraphicsElement>,
954
+ ) => void;
954
955
  /**
955
- * The customized event handler of mouseleave on the area in this group
956
- */
957
- onMouseLeave?: (item: NodeProps | LinkProps, type: SankeyElementType, e: NativeMouseEvent<
958
- SVGGraphicsElement
959
- >) => void;
956
+ * The customized event handler of mouseleave on the area in this group
957
+ */
958
+ onMouseLeave?: (
959
+ item: NodeProps | LinkProps,
960
+ type: SankeyElementType,
961
+ e: NativeMouseEvent<SVGGraphicsElement>,
962
+ ) => void;
960
963
  /**
961
- * Whether to sort the nodes on the y axis, or to display them as user-defined.
962
- * @default true
963
- */
964
+ * Whether to sort the nodes on the y axis, or to display them as user-defined.
965
+ * @default true
966
+ */
964
967
  sort?: boolean;
965
968
  /**
966
- * 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.
967
- * @default 'justify'
968
- */
969
+ * 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.
970
+ * @default 'justify'
971
+ */
969
972
  verticalAlign?: SankeyVerticalAlign;
970
973
  /**
971
- * 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.
972
- * @default 'justify'
973
- */
974
+ * 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.
975
+ * @default 'justify'
976
+ */
974
977
  align?: 'left' | 'justify';
975
978
  }
976
979
 
@@ -997,18 +1000,20 @@ function renderLinkItem(option: SankeyLinkOptions | undefined, props: LinkProps)
997
1000
  ...others
998
1001
  } = props;
999
1002
 
1000
- return <path
1001
- className="recharts-sankey-link"
1002
- d={`
1003
+ return (
1004
+ <path
1005
+ className="recharts-sankey-link"
1006
+ d={`
1003
1007
  M${sourceX},${sourceY}
1004
1008
  C${sourceControlX},${sourceY} ${targetControlX},${targetY} ${targetX},${targetY}
1005
1009
  `}
1006
- fill="none"
1007
- stroke="#333"
1008
- strokeWidth={linkWidth}
1009
- strokeOpacity="0.2"
1010
- {...svgPropertiesNoEvents(others)}
1011
- />;
1010
+ fill="none"
1011
+ stroke="#333"
1012
+ strokeWidth={linkWidth}
1013
+ strokeOpacity="0.2"
1014
+ {...svgPropertiesNoEvents(others)}
1015
+ />
1016
+ );
1012
1017
  }
1013
1018
 
1014
1019
  const buildLinkProps = ({
@@ -1135,26 +1140,29 @@ function AllSankeyLinkElements({
1135
1140
  onClick: (linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) => void;
1136
1141
  dataKey: DataKey<any>;
1137
1142
  }) {
1138
- return <Layer className="recharts-sankey-links" key="recharts-sankey-links">{links.map((
1139
- link: SankeyLink,
1140
- i: number,
1141
- ) => {
1142
- const linkProps = modifiedLinks[i];
1143
- if (linkProps == null) {
1144
- return null;
1145
- }
1146
- return <SankeyLinkElement
1147
- graphicalItemId={graphicalItemId}
1148
- key={`link-${link.source}-${link.target}-${link.value}`}
1149
- props={linkProps}
1150
- linkContent={linkContent}
1151
- i={i}
1152
- onMouseEnter={onMouseEnter}
1153
- onMouseLeave={onMouseLeave}
1154
- onClick={onClick}
1155
- dataKey={dataKey}
1156
- />;
1157
- })}</Layer>;
1143
+ return (
1144
+ <Layer className="recharts-sankey-links" key="recharts-sankey-links">
1145
+ {links.map((link: SankeyLink, i: number) => {
1146
+ const linkProps = modifiedLinks[i];
1147
+ if (linkProps == null) {
1148
+ return null;
1149
+ }
1150
+ return (
1151
+ <SankeyLinkElement
1152
+ graphicalItemId={graphicalItemId}
1153
+ key={`link-${link.source}-${link.target}-${link.value}`}
1154
+ props={linkProps}
1155
+ linkContent={linkContent}
1156
+ i={i}
1157
+ onMouseEnter={onMouseEnter}
1158
+ onMouseLeave={onMouseLeave}
1159
+ onClick={onClick}
1160
+ dataKey={dataKey}
1161
+ />
1162
+ );
1163
+ })}
1164
+ </Layer>
1165
+ );
1158
1166
  }
1159
1167
 
1160
1168
  function renderNodeItem(option: SankeyNodeOptions | undefined, props: NodeProps) {
@@ -1165,12 +1173,14 @@ function renderNodeItem(option: SankeyNodeOptions | undefined, props: NodeProps)
1165
1173
  return option(props);
1166
1174
  }
1167
1175
 
1168
- return <Rectangle
1169
- className="recharts-sankey-node"
1170
- fill="#0088fe"
1171
- fillOpacity="0.8"
1172
- {...svgPropertiesNoEvents(props)}
1173
- />;
1176
+ return (
1177
+ <Rectangle
1178
+ className="recharts-sankey-node"
1179
+ fill="#0088fe"
1180
+ fillOpacity="0.8"
1181
+ {...svgPropertiesNoEvents(props)}
1182
+ />
1183
+ );
1174
1184
  }
1175
1185
 
1176
1186
  const buildNodeProps = ({
@@ -1272,22 +1282,25 @@ function AllNodeElements({
1272
1282
  onClick: (nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) => void;
1273
1283
  dataKey: DataKey<any>;
1274
1284
  }) {
1275
- return <Layer className="recharts-sankey-nodes" key="recharts-sankey-nodes">{modifiedNodes.map((
1276
- modifiedNode,
1277
- i,
1278
- ) => {
1279
- return <NodeElement
1280
- graphicalItemId={graphicalItemId}
1281
- key={`node-${modifiedNode.index}-${modifiedNode.x}-${modifiedNode.y}`}
1282
- props={modifiedNode}
1283
- nodeContent={nodeContent}
1284
- i={i}
1285
- onMouseEnter={onMouseEnter}
1286
- onMouseLeave={onMouseLeave}
1287
- onClick={onClick}
1288
- dataKey={dataKey}
1289
- />;
1290
- })}</Layer>;
1285
+ return (
1286
+ <Layer className="recharts-sankey-nodes" key="recharts-sankey-nodes">
1287
+ {modifiedNodes.map((modifiedNode, i) => {
1288
+ return (
1289
+ <NodeElement
1290
+ graphicalItemId={graphicalItemId}
1291
+ key={`node-${modifiedNode.index}-${modifiedNode.x}-${modifiedNode.y}`}
1292
+ props={modifiedNode}
1293
+ nodeContent={nodeContent}
1294
+ i={i}
1295
+ onMouseEnter={onMouseEnter}
1296
+ onMouseLeave={onMouseLeave}
1297
+ onClick={onClick}
1298
+ dataKey={dataKey}
1299
+ />
1300
+ );
1301
+ })}
1302
+ </Layer>
1303
+ );
1291
1304
  }
1292
1305
 
1293
1306
  export const sankeyDefaultProps = {
@@ -1353,17 +1366,19 @@ function SankeyImpl(props: InternalSankeyProps) {
1353
1366
 
1354
1367
  const top = margin.top || 0;
1355
1368
  const left = margin.left || 0;
1356
- const newModifiedLinks = computed.links.map((l, i) => {
1357
- return buildLinkProps({
1358
- link: l,
1359
- nodes: computed.nodes,
1360
- i,
1361
- top,
1362
- left,
1363
- linkContent: link,
1364
- linkCurvature,
1365
- });
1366
- }).filter(isNotNil);
1369
+ const newModifiedLinks = computed.links
1370
+ .map((l, i) => {
1371
+ return buildLinkProps({
1372
+ link: l,
1373
+ nodes: computed.nodes,
1374
+ i,
1375
+ top,
1376
+ left,
1377
+ linkContent: link,
1378
+ linkCurvature,
1379
+ });
1380
+ })
1381
+ .filter(isNotNil);
1367
1382
 
1368
1383
  const newModifiedNodes = computed.nodes.map((n, i) => {
1369
1384
  return buildNodeProps({
@@ -1397,79 +1412,94 @@ function SankeyImpl(props: InternalSankeyProps) {
1397
1412
  verticalAlign,
1398
1413
  ]);
1399
1414
 
1400
- const handleMouseEnter = useCallback((
1401
- item: NodeProps | LinkProps,
1402
- type: SankeyElementType,
1403
- e: NativeMouseEvent<SVGGraphicsElement>,
1404
- ) => {
1405
- if (onMouseEnter) {
1406
- onMouseEnter(item, type, e);
1407
- }
1408
- }, [onMouseEnter]);
1415
+ const handleMouseEnter = useCallback(
1416
+ (
1417
+ item: NodeProps | LinkProps,
1418
+ type: SankeyElementType,
1419
+ e: NativeMouseEvent<SVGGraphicsElement>,
1420
+ ) => {
1421
+ if (onMouseEnter) {
1422
+ onMouseEnter(item, type, e);
1423
+ }
1424
+ },
1425
+ [onMouseEnter],
1426
+ );
1409
1427
 
1410
- const handleMouseLeave = useCallback((
1411
- item: NodeProps | LinkProps,
1412
- type: SankeyElementType,
1413
- e: NativeMouseEvent<SVGGraphicsElement>,
1414
- ) => {
1415
- if (onMouseLeave) {
1416
- onMouseLeave(item, type, e);
1417
- }
1418
- }, [onMouseLeave]);
1428
+ const handleMouseLeave = useCallback(
1429
+ (
1430
+ item: NodeProps | LinkProps,
1431
+ type: SankeyElementType,
1432
+ e: NativeMouseEvent<SVGGraphicsElement>,
1433
+ ) => {
1434
+ if (onMouseLeave) {
1435
+ onMouseLeave(item, type, e);
1436
+ }
1437
+ },
1438
+ [onMouseLeave],
1439
+ );
1419
1440
 
1420
- const handleClick = useCallback((
1421
- item: NodeProps | LinkProps,
1422
- type: SankeyElementType,
1423
- e: NativeMouseEvent<SVGGraphicsElement>,
1424
- ) => {
1425
- if (onClick) {
1426
- onClick(item, type, e);
1427
- }
1428
- }, [onClick]);
1441
+ const handleClick = useCallback(
1442
+ (
1443
+ item: NodeProps | LinkProps,
1444
+ type: SankeyElementType,
1445
+ e: NativeMouseEvent<SVGGraphicsElement>,
1446
+ ) => {
1447
+ if (onClick) {
1448
+ onClick(item, type, e);
1449
+ }
1450
+ },
1451
+ [onClick],
1452
+ );
1429
1453
 
1430
1454
  if (
1431
- !isPositiveNumber(width) || !isPositiveNumber(height) || !data || !data.links || !data.nodes
1455
+ !isPositiveNumber(width) ||
1456
+ !isPositiveNumber(height) ||
1457
+ !data ||
1458
+ !data.links ||
1459
+ !data.nodes
1432
1460
  ) {
1433
1461
  return null;
1434
1462
  }
1435
1463
 
1436
- return <>
1437
- <SetComputedData computedData={{ links: modifiedLinks, nodes: modifiedNodes }} />
1438
- <Surface {...attrs} width={width} height={height}>
1439
- {children}
1440
- <AllSankeyLinkElements
1441
- graphicalItemId={id}
1442
- links={links}
1443
- modifiedLinks={modifiedLinks}
1444
- linkContent={link}
1445
- dataKey={dataKey}
1446
- onMouseEnter={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1447
- handleMouseEnter(linkProps, 'link', e)}
1448
- onMouseLeave={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1449
- handleMouseLeave(linkProps, 'link', e)}
1450
- onClick={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) => handleClick(
1451
- linkProps,
1452
- 'link',
1453
- e,
1454
- )}
1455
- />
1456
- <AllNodeElements
1457
- graphicalItemId={id}
1458
- modifiedNodes={modifiedNodes}
1459
- nodeContent={node}
1460
- dataKey={dataKey}
1461
- onMouseEnter={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1462
- handleMouseEnter(nodeProps, 'node', e)}
1463
- onMouseLeave={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1464
- handleMouseLeave(nodeProps, 'node', e)}
1465
- onClick={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) => handleClick(
1466
- nodeProps,
1467
- 'node',
1468
- e,
1469
- )}
1470
- />
1471
- </Surface>
1472
- </>;
1464
+ return (
1465
+ <>
1466
+ <SetComputedData computedData={{ links: modifiedLinks, nodes: modifiedNodes }} />
1467
+ <Surface {...attrs} width={width} height={height}>
1468
+ {children}
1469
+ <AllSankeyLinkElements
1470
+ graphicalItemId={id}
1471
+ links={links}
1472
+ modifiedLinks={modifiedLinks}
1473
+ linkContent={link}
1474
+ dataKey={dataKey}
1475
+ onMouseEnter={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1476
+ handleMouseEnter(linkProps, 'link', e)
1477
+ }
1478
+ onMouseLeave={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1479
+ handleMouseLeave(linkProps, 'link', e)
1480
+ }
1481
+ onClick={(linkProps: LinkProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1482
+ handleClick(linkProps, 'link', e)
1483
+ }
1484
+ />
1485
+ <AllNodeElements
1486
+ graphicalItemId={id}
1487
+ modifiedNodes={modifiedNodes}
1488
+ nodeContent={node}
1489
+ dataKey={dataKey}
1490
+ onMouseEnter={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1491
+ handleMouseEnter(nodeProps, 'node', e)
1492
+ }
1493
+ onMouseLeave={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1494
+ handleMouseLeave(nodeProps, 'node', e)
1495
+ }
1496
+ onClick={(nodeProps: NodeProps, e: NativeMouseEvent<SVGGraphicsElement>) =>
1497
+ handleClick(nodeProps, 'node', e)
1498
+ }
1499
+ />
1500
+ </Surface>
1501
+ </>
1502
+ );
1473
1503
  }
1474
1504
 
1475
1505
  /**
@@ -1484,57 +1514,61 @@ export function Sankey(outsideProps: Props) {
1484
1514
  const { width, height, style, className, id: externalId, throttleDelay, throttledEvents } = props;
1485
1515
  const [tooltipPortal, setTooltipPortal] = useState<HTMLElement | null>(null);
1486
1516
 
1487
- return <RechartsStoreProvider preloadedState={{ options }} reduxStoreName={className ?? 'Sankey'}>
1488
- <ReportChartSize width={width} height={height} />
1489
- <ReportChartMargin margin={props.margin} />
1490
- <ReportEventSettings throttleDelay={throttleDelay} throttledEvents={throttledEvents} />
1491
-
1492
- <RechartsWrapper
1493
- className={className}
1494
- style={style}
1495
- width={width}
1496
- height={height}
1497
- /*
1498
- * Sankey, same as Treemap, suffers from overfilling the container
1499
- * and causing infinite render loops where the chart keeps growing.
1500
- */
1501
- responsive={false}
1502
- ref={(node: HTMLDivElement | null) => {
1503
- if (node && !tooltipPortal) {
1504
- setTooltipPortal(node);
1505
- }
1506
- }}
1507
- onMouseEnter={undefined}
1508
- onMouseLeave={undefined}
1509
- onClick={undefined}
1510
- onMouseMove={undefined}
1511
- onMouseDown={undefined}
1512
- onMouseUp={undefined}
1513
- onContextMenu={undefined}
1514
- onDoubleClick={undefined}
1515
- onTouchStart={undefined}
1516
- onTouchMove={undefined}
1517
- onTouchEnd={undefined}
1518
- >
1519
- <TooltipPortalContext value={tooltipPortal}>
1520
- <RegisterGraphicalItemId id={externalId} type="sankey">
1521
- {(id) => <>
1522
- <SetSankeyTooltipEntrySettings
1523
- dataKey={props.dataKey}
1524
- nameKey={props.nameKey}
1525
- stroke={props.stroke}
1526
- strokeWidth={props.strokeWidth}
1527
- fill={props.fill}
1528
- name={props.name}
1529
- data={props.data}
1530
- id={id}
1531
- />
1532
- <SankeyImpl {...props} id={id} />
1533
- </>}
1534
- </RegisterGraphicalItemId>
1535
- </TooltipPortalContext>
1536
- </RechartsWrapper>
1537
- </RechartsStoreProvider>;
1517
+ return (
1518
+ <RechartsStoreProvider preloadedState={{ options }} reduxStoreName={className ?? 'Sankey'}>
1519
+ <ReportChartSize width={width} height={height} />
1520
+ <ReportChartMargin margin={props.margin} />
1521
+ <ReportEventSettings throttleDelay={throttleDelay} throttledEvents={throttledEvents} />
1522
+
1523
+ <RechartsWrapper
1524
+ className={className}
1525
+ style={style}
1526
+ width={width}
1527
+ height={height}
1528
+ /*
1529
+ * Sankey, same as Treemap, suffers from overfilling the container
1530
+ * and causing infinite render loops where the chart keeps growing.
1531
+ */
1532
+ responsive={false}
1533
+ ref={(node: HTMLDivElement | null) => {
1534
+ if (node && !tooltipPortal) {
1535
+ setTooltipPortal(node);
1536
+ }
1537
+ }}
1538
+ onMouseEnter={undefined}
1539
+ onMouseLeave={undefined}
1540
+ onClick={undefined}
1541
+ onMouseMove={undefined}
1542
+ onMouseDown={undefined}
1543
+ onMouseUp={undefined}
1544
+ onContextMenu={undefined}
1545
+ onDoubleClick={undefined}
1546
+ onTouchStart={undefined}
1547
+ onTouchMove={undefined}
1548
+ onTouchEnd={undefined}
1549
+ >
1550
+ <TooltipPortalContext value={tooltipPortal}>
1551
+ <RegisterGraphicalItemId id={externalId} type="sankey">
1552
+ {(id) => (
1553
+ <>
1554
+ <SetSankeyTooltipEntrySettings
1555
+ dataKey={props.dataKey}
1556
+ nameKey={props.nameKey}
1557
+ stroke={props.stroke}
1558
+ strokeWidth={props.strokeWidth}
1559
+ fill={props.fill}
1560
+ name={props.name}
1561
+ data={props.data}
1562
+ id={id}
1563
+ />
1564
+ <SankeyImpl {...props} id={id} />
1565
+ </>
1566
+ )}
1567
+ </RegisterGraphicalItemId>
1568
+ </TooltipPortalContext>
1569
+ </RechartsWrapper>
1570
+ </RechartsStoreProvider>
1571
+ );
1538
1572
  }
1539
1573
 
1540
1574
  Sankey.displayName = 'Sankey';