@gravity-ui/charts 0.6.0 → 0.6.1-beta.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 (172) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/components/Axis/AxisY.d.ts +1 -0
  3. package/dist/cjs/components/Axis/AxisY.js +55 -13
  4. package/dist/cjs/components/ChartInner/index.js +3 -2
  5. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +4 -0
  6. package/dist/cjs/components/Legend/index.js +1 -2
  7. package/dist/cjs/components/PlotTitle/index.js +1 -1
  8. package/dist/cjs/components/PlotTitle/styles.css +1 -1
  9. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +2 -2
  10. package/dist/cjs/components/Tooltip/DefaultContent.js +19 -3
  11. package/dist/cjs/components/Tooltip/index.js +2 -2
  12. package/dist/cjs/components/Tooltip/styles.css +11 -9
  13. package/dist/cjs/components/index.d.ts +10 -9
  14. package/dist/cjs/constants/index.d.ts +1 -0
  15. package/dist/cjs/constants/index.js +1 -0
  16. package/dist/cjs/hooks/useChartOptions/types.d.ts +11 -1
  17. package/dist/cjs/hooks/useChartOptions/x-axis.js +1 -0
  18. package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -1
  19. package/dist/cjs/hooks/useSeries/prepare-area.d.ts +1 -1
  20. package/dist/cjs/hooks/useSeries/prepare-bar-x.d.ts +2 -1
  21. package/dist/cjs/hooks/useSeries/prepare-bar-x.js +2 -1
  22. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +2 -1
  23. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
  24. package/dist/cjs/hooks/useSeries/prepare-line.d.ts +1 -1
  25. package/dist/cjs/hooks/useSeries/prepare-pie.js +2 -2
  26. package/dist/cjs/hooks/useSeries/prepare-sankey.d.ts +11 -0
  27. package/dist/cjs/hooks/useSeries/prepare-sankey.js +38 -0
  28. package/dist/cjs/hooks/useSeries/prepareSeries.js +21 -2
  29. package/dist/cjs/hooks/useSeries/types.d.ts +12 -2
  30. package/dist/cjs/hooks/useSeries/utils.js +1 -1
  31. package/dist/cjs/hooks/useShapes/area/prepare-data.js +4 -0
  32. package/dist/cjs/hooks/useShapes/bar-x/index.js +16 -2
  33. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +3 -1
  34. package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +1 -0
  35. package/dist/cjs/hooks/useShapes/bar-y/index.js +16 -2
  36. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +3 -1
  37. package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +1 -0
  38. package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
  39. package/dist/cjs/hooks/useShapes/index.js +19 -0
  40. package/dist/cjs/hooks/useShapes/line/index.js +2 -2
  41. package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -0
  42. package/dist/cjs/hooks/useShapes/pie/index.js +5 -4
  43. package/dist/cjs/hooks/useShapes/pie/prepare-data.js +168 -118
  44. package/dist/cjs/hooks/useShapes/pie/types.d.ts +2 -2
  45. package/dist/cjs/hooks/useShapes/sankey/index.d.ts +12 -0
  46. package/dist/cjs/hooks/useShapes/sankey/index.js +67 -0
  47. package/dist/cjs/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  48. package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +72 -0
  49. package/dist/cjs/hooks/useShapes/sankey/types.d.ts +33 -0
  50. package/dist/cjs/hooks/useShapes/sankey/types.js +1 -0
  51. package/dist/cjs/hooks/useShapes/styles.css +2 -2
  52. package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +1 -0
  53. package/dist/cjs/hooks/useShapes/utils.d.ts +7 -2
  54. package/dist/cjs/hooks/useShapes/utils.js +22 -17
  55. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -2
  56. package/dist/cjs/types/chart/area.d.ts +6 -6
  57. package/dist/cjs/types/chart/axis.d.ts +32 -7
  58. package/dist/cjs/types/chart/bar-x.d.ts +9 -4
  59. package/dist/cjs/types/chart/bar-y.d.ts +10 -6
  60. package/dist/cjs/types/chart/base.d.ts +6 -6
  61. package/dist/cjs/types/chart/chart.d.ts +4 -4
  62. package/dist/cjs/types/chart/halo.d.ts +2 -2
  63. package/dist/cjs/types/chart/legend.d.ts +10 -10
  64. package/dist/cjs/types/chart/line.d.ts +4 -4
  65. package/dist/cjs/types/chart/marker.d.ts +2 -2
  66. package/dist/cjs/types/chart/pie.d.ts +6 -4
  67. package/dist/cjs/types/chart/sankey.d.ts +22 -0
  68. package/dist/cjs/types/chart/sankey.js +1 -0
  69. package/dist/cjs/types/chart/scatter.d.ts +4 -4
  70. package/dist/cjs/types/chart/series.d.ts +21 -10
  71. package/dist/cjs/types/chart/split.d.ts +4 -4
  72. package/dist/cjs/types/chart/title.d.ts +2 -2
  73. package/dist/cjs/types/chart/tooltip.d.ts +27 -21
  74. package/dist/cjs/types/chart/treemap.d.ts +4 -4
  75. package/dist/cjs/types/chart/waterfall.d.ts +4 -4
  76. package/dist/cjs/types/chart-ui.d.ts +10 -6
  77. package/dist/cjs/types/formatter.d.ts +4 -4
  78. package/dist/cjs/types/index.d.ts +35 -4
  79. package/dist/cjs/types/index.js +1 -0
  80. package/dist/cjs/utils/chart/get-closest-data.d.ts +2 -0
  81. package/dist/cjs/utils/chart/get-closest-data.js +39 -3
  82. package/dist/cjs/utils/chart/index.js +1 -1
  83. package/dist/cjs/utils/chart/series/index.d.ts +1 -0
  84. package/dist/cjs/utils/chart/series/index.js +1 -0
  85. package/dist/cjs/utils/chart/series/line.d.ts +2 -0
  86. package/dist/cjs/utils/chart/series/line.js +17 -0
  87. package/dist/esm/components/Axis/AxisY.d.ts +1 -0
  88. package/dist/esm/components/Axis/AxisY.js +55 -13
  89. package/dist/esm/components/ChartInner/index.js +3 -2
  90. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +4 -0
  91. package/dist/esm/components/Legend/index.js +1 -2
  92. package/dist/esm/components/PlotTitle/index.js +1 -1
  93. package/dist/esm/components/PlotTitle/styles.css +1 -1
  94. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +2 -2
  95. package/dist/esm/components/Tooltip/DefaultContent.js +19 -3
  96. package/dist/esm/components/Tooltip/index.js +2 -2
  97. package/dist/esm/components/Tooltip/styles.css +11 -9
  98. package/dist/esm/components/index.d.ts +10 -9
  99. package/dist/esm/constants/index.d.ts +1 -0
  100. package/dist/esm/constants/index.js +1 -0
  101. package/dist/esm/hooks/useChartOptions/types.d.ts +11 -1
  102. package/dist/esm/hooks/useChartOptions/x-axis.js +1 -0
  103. package/dist/esm/hooks/useChartOptions/y-axis.js +9 -1
  104. package/dist/esm/hooks/useSeries/prepare-area.d.ts +1 -1
  105. package/dist/esm/hooks/useSeries/prepare-bar-x.d.ts +2 -1
  106. package/dist/esm/hooks/useSeries/prepare-bar-x.js +2 -1
  107. package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +2 -1
  108. package/dist/esm/hooks/useSeries/prepare-bar-y.js +3 -1
  109. package/dist/esm/hooks/useSeries/prepare-line.d.ts +1 -1
  110. package/dist/esm/hooks/useSeries/prepare-pie.js +2 -2
  111. package/dist/esm/hooks/useSeries/prepare-sankey.d.ts +11 -0
  112. package/dist/esm/hooks/useSeries/prepare-sankey.js +38 -0
  113. package/dist/esm/hooks/useSeries/prepareSeries.js +21 -2
  114. package/dist/esm/hooks/useSeries/types.d.ts +12 -2
  115. package/dist/esm/hooks/useSeries/utils.js +1 -1
  116. package/dist/esm/hooks/useShapes/area/prepare-data.js +4 -0
  117. package/dist/esm/hooks/useShapes/bar-x/index.js +16 -2
  118. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +3 -1
  119. package/dist/esm/hooks/useShapes/bar-x/types.d.ts +1 -0
  120. package/dist/esm/hooks/useShapes/bar-y/index.js +16 -2
  121. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +3 -1
  122. package/dist/esm/hooks/useShapes/bar-y/types.d.ts +1 -0
  123. package/dist/esm/hooks/useShapes/index.d.ts +2 -1
  124. package/dist/esm/hooks/useShapes/index.js +19 -0
  125. package/dist/esm/hooks/useShapes/line/index.js +2 -2
  126. package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -0
  127. package/dist/esm/hooks/useShapes/pie/index.js +5 -4
  128. package/dist/esm/hooks/useShapes/pie/prepare-data.js +168 -118
  129. package/dist/esm/hooks/useShapes/pie/types.d.ts +2 -2
  130. package/dist/esm/hooks/useShapes/sankey/index.d.ts +12 -0
  131. package/dist/esm/hooks/useShapes/sankey/index.js +67 -0
  132. package/dist/esm/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  133. package/dist/esm/hooks/useShapes/sankey/prepare-data.js +72 -0
  134. package/dist/esm/hooks/useShapes/sankey/types.d.ts +33 -0
  135. package/dist/esm/hooks/useShapes/sankey/types.js +1 -0
  136. package/dist/esm/hooks/useShapes/styles.css +2 -2
  137. package/dist/esm/hooks/useShapes/treemap/prepare-data.js +1 -0
  138. package/dist/esm/hooks/useShapes/utils.d.ts +7 -2
  139. package/dist/esm/hooks/useShapes/utils.js +22 -17
  140. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -2
  141. package/dist/esm/types/chart/area.d.ts +6 -6
  142. package/dist/esm/types/chart/axis.d.ts +32 -7
  143. package/dist/esm/types/chart/bar-x.d.ts +9 -4
  144. package/dist/esm/types/chart/bar-y.d.ts +10 -6
  145. package/dist/esm/types/chart/base.d.ts +6 -6
  146. package/dist/esm/types/chart/chart.d.ts +4 -4
  147. package/dist/esm/types/chart/halo.d.ts +2 -2
  148. package/dist/esm/types/chart/legend.d.ts +10 -10
  149. package/dist/esm/types/chart/line.d.ts +4 -4
  150. package/dist/esm/types/chart/marker.d.ts +2 -2
  151. package/dist/esm/types/chart/pie.d.ts +6 -4
  152. package/dist/esm/types/chart/sankey.d.ts +22 -0
  153. package/dist/esm/types/chart/sankey.js +1 -0
  154. package/dist/esm/types/chart/scatter.d.ts +4 -4
  155. package/dist/esm/types/chart/series.d.ts +21 -10
  156. package/dist/esm/types/chart/split.d.ts +4 -4
  157. package/dist/esm/types/chart/title.d.ts +2 -2
  158. package/dist/esm/types/chart/tooltip.d.ts +27 -21
  159. package/dist/esm/types/chart/treemap.d.ts +4 -4
  160. package/dist/esm/types/chart/waterfall.d.ts +4 -4
  161. package/dist/esm/types/chart-ui.d.ts +10 -6
  162. package/dist/esm/types/formatter.d.ts +4 -4
  163. package/dist/esm/types/index.d.ts +35 -4
  164. package/dist/esm/types/index.js +1 -0
  165. package/dist/esm/utils/chart/get-closest-data.d.ts +2 -0
  166. package/dist/esm/utils/chart/get-closest-data.js +39 -3
  167. package/dist/esm/utils/chart/index.js +1 -1
  168. package/dist/esm/utils/chart/series/index.d.ts +1 -0
  169. package/dist/esm/utils/chart/series/index.js +1 -0
  170. package/dist/esm/utils/chart/series/line.d.ts +2 -0
  171. package/dist/esm/utils/chart/series/line.js +17 -0
  172. package/package.json +7 -2
@@ -18,18 +18,17 @@ export function preparePieData(args) {
18
18
  const { series: preparedSeries, boundsWidth, boundsHeight } = args;
19
19
  const maxRadius = Math.min(boundsWidth, boundsHeight) / 2;
20
20
  const groupedPieSeries = group(preparedSeries, (pieSeries) => pieSeries.stackId);
21
- return Array.from(groupedPieSeries).map(([stackId, items]) => {
22
- var _a, _b, _c;
21
+ const prepareItem = (stackId, items) => {
22
+ var _a;
23
23
  const series = items[0];
24
- const { center, borderWidth, borderColor, borderRadius, radius: seriesRadius, innerRadius: seriesInnerRadius, dataLabels, } = series;
25
- const radius = (_a = calculateNumericProperty({ value: seriesRadius, base: maxRadius })) !== null && _a !== void 0 ? _a : maxRadius;
24
+ const { center, borderWidth, borderColor, borderRadius, innerRadius: seriesInnerRadius, dataLabels, } = series;
26
25
  const data = {
27
26
  id: stackId,
28
27
  center: getCenter(boundsWidth, boundsHeight, center),
29
- innerRadius: (_b = calculateNumericProperty({ value: seriesInnerRadius, base: radius })) !== null && _b !== void 0 ? _b : 0,
30
- radius,
28
+ innerRadius: 0,
31
29
  segments: [],
32
30
  labels: [],
31
+ htmlLabels: [],
33
32
  connectors: [],
34
33
  borderColor,
35
34
  borderWidth,
@@ -41,9 +40,20 @@ export function preparePieData(args) {
41
40
  opacity: series.states.hover.halo.opacity,
42
41
  size: series.states.hover.halo.size,
43
42
  },
44
- htmlElements: [],
45
43
  };
44
+ const { maxHeight: labelHeight } = getLabelsSize({
45
+ labels: ['Some Label'],
46
+ style: dataLabels.style,
47
+ });
48
+ let segmentMaxRadius = 0;
46
49
  const segments = items.map((item) => {
50
+ var _a;
51
+ let maxSegmentRadius = maxRadius;
52
+ if (dataLabels.enabled) {
53
+ maxSegmentRadius -= dataLabels.distance + dataLabels.connectorPadding + labelHeight;
54
+ }
55
+ const segmentRadius = (_a = calculateNumericProperty({ value: item.radius, base: maxSegmentRadius })) !== null && _a !== void 0 ? _a : maxSegmentRadius;
56
+ segmentMaxRadius = Math.max(segmentMaxRadius, segmentRadius);
47
57
  return {
48
58
  value: item.value,
49
59
  color: item.color,
@@ -52,135 +62,175 @@ export function preparePieData(args) {
52
62
  hovered: false,
53
63
  active: true,
54
64
  pie: data,
65
+ radius: segmentRadius,
55
66
  };
56
67
  });
57
68
  data.segments = pieGenerator(segments);
69
+ data.innerRadius =
70
+ (_a = calculateNumericProperty({ value: seriesInnerRadius, base: segmentMaxRadius })) !== null && _a !== void 0 ? _a : 0;
71
+ return data;
72
+ };
73
+ const prepareLabels = (prepareLabelsArgs) => {
74
+ const { data, series } = prepareLabelsArgs;
75
+ const { dataLabels } = series[0];
76
+ const labels = [];
77
+ const htmlLabels = [];
78
+ const connectors = [];
79
+ if (!dataLabels.enabled) {
80
+ return { labels, htmlLabels, connectors };
81
+ }
58
82
  let line = lineGenerator();
59
83
  const curveFactory = getCurveFactory(data);
60
84
  if (curveFactory) {
61
85
  line = line.curve(curveFactory);
62
86
  }
63
- if (dataLabels.enabled) {
64
- const { style, connectorPadding, distance } = dataLabels;
65
- const { maxHeight: labelHeight } = getLabelsSize({ labels: ['Some Label'], style });
66
- const minSegmentRadius = maxRadius - connectorPadding - distance - labelHeight;
67
- if (data.radius > minSegmentRadius) {
68
- data.radius = minSegmentRadius;
69
- data.innerRadius =
70
- (_c = calculateNumericProperty({ value: seriesInnerRadius, base: data.radius })) !== null && _c !== void 0 ? _c : 0;
71
- }
72
- const connectorStartPointGenerator = arc()
73
- .innerRadius(data.radius)
74
- .outerRadius(data.radius);
75
- const connectorMidPointRadius = data.radius + distance / 2;
76
- const connectorMidPointGenerator = arc()
77
- .innerRadius(connectorMidPointRadius)
78
- .outerRadius(connectorMidPointRadius);
79
- const connectorArcRadius = data.radius + distance;
80
- const connectorEndPointGenerator = arc()
81
- .innerRadius(connectorArcRadius)
82
- .outerRadius(connectorArcRadius);
83
- const labelArcRadius = connectorArcRadius + connectorPadding;
84
- const labelArcGenerator = arc()
85
- .innerRadius(labelArcRadius)
86
- .outerRadius(labelArcRadius);
87
- const labels = [];
88
- items.forEach((d, index) => {
89
- const prevLabel = labels[labels.length - 1];
90
- const text = String(d.data.label || d.data.value);
91
- const shouldUseHtml = dataLabels.html;
92
- const labelSize = getLabelsSize({ labels: [text], style, html: shouldUseHtml });
93
- const labelWidth = labelSize.maxWidth;
94
- const relatedSegment = data.segments[index];
95
- const getLabelPosition = (angle) => {
96
- let [x, y] = labelArcGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
87
+ const { style, connectorPadding, distance } = dataLabels;
88
+ const { maxHeight: labelHeight } = getLabelsSize({ labels: ['Some Label'], style });
89
+ const connectorStartPointGenerator = arc()
90
+ .innerRadius((d) => d.data.radius)
91
+ .outerRadius((d) => d.data.radius);
92
+ const connectorMidPointGenerator = arc()
93
+ .innerRadius((d) => d.data.radius + distance / 2)
94
+ .outerRadius((d) => d.data.radius + distance / 2);
95
+ const connectorEndPointGenerator = arc()
96
+ .innerRadius((d) => d.data.radius + distance)
97
+ .outerRadius((d) => d.data.radius + distance);
98
+ const labelArcGenerator = arc()
99
+ .innerRadius((d) => d.data.radius + distance + connectorPadding)
100
+ .outerRadius((d) => d.data.radius + distance + connectorPadding);
101
+ series.forEach((d, index) => {
102
+ const prevLabel = labels[labels.length - 1];
103
+ const text = String(d.data.label || d.data.value);
104
+ const shouldUseHtml = dataLabels.html;
105
+ const labelSize = getLabelsSize({ labels: [text], style, html: shouldUseHtml });
106
+ const labelWidth = labelSize.maxWidth;
107
+ const relatedSegment = data.segments[index];
108
+ const getLabelPosition = (angle) => {
109
+ let [x, y] = labelArcGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
110
+ if (shouldUseHtml) {
111
+ x = x < 0 ? x - labelWidth : x;
112
+ y = y - labelSize.maxHeight;
113
+ }
114
+ else {
97
115
  y = y < 0 ? y - labelHeight : y;
98
- if (shouldUseHtml) {
99
- x = x < 0 ? x - labelWidth : x;
100
- }
101
- x = Math.max(-boundsWidth / 2, x);
102
- return [x, y];
103
- };
104
- const getConnectorPoints = (angle) => {
105
- const connectorStartPoint = connectorStartPointGenerator.centroid(relatedSegment);
106
- const connectorEndPoint = connectorEndPointGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
107
- if (dataLabels.connectorShape === 'straight-line') {
108
- return [connectorStartPoint, connectorEndPoint];
109
- }
110
- const connectorMidPoint = connectorMidPointGenerator.centroid(relatedSegment);
111
- return [connectorStartPoint, connectorMidPoint, connectorEndPoint];
112
- };
113
- const midAngle = Math.max((prevLabel === null || prevLabel === void 0 ? void 0 : prevLabel.angle) || 0, relatedSegment.startAngle +
114
- (relatedSegment.endAngle - relatedSegment.startAngle) / 2);
115
- const [x, y] = getLabelPosition(midAngle);
116
- const label = {
117
- text,
118
- x,
119
- y,
120
- style,
121
- size: { width: labelWidth, height: labelHeight },
122
- maxWidth: labelWidth,
123
- textAnchor: midAngle < Math.PI ? 'start' : 'end',
124
- series: { id: d.id },
125
- active: true,
126
- segment: relatedSegment.data,
127
- angle: midAngle,
128
- };
129
- let overlap = false;
130
- if (prevLabel) {
131
- overlap = isLabelsOverlapping(prevLabel, label, dataLabels.padding);
132
- if (overlap) {
133
- let shouldAdjustAngle = true;
134
- const step = Math.PI / 180;
135
- while (shouldAdjustAngle) {
136
- const newAngle = label.angle + step;
137
- if (newAngle > FULL_CIRCLE &&
138
- newAngle % FULL_CIRCLE > labels[0].angle) {
116
+ }
117
+ x = Math.max(-boundsWidth / 2, x);
118
+ return [x, y];
119
+ };
120
+ const getConnectorPoints = (angle) => {
121
+ const connectorStartPoint = connectorStartPointGenerator.centroid(relatedSegment);
122
+ const connectorEndPoint = connectorEndPointGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
123
+ if (dataLabels.connectorShape === 'straight-line') {
124
+ return [connectorStartPoint, connectorEndPoint];
125
+ }
126
+ const connectorMidPoint = connectorMidPointGenerator.centroid(relatedSegment);
127
+ return [connectorStartPoint, connectorMidPoint, connectorEndPoint];
128
+ };
129
+ const midAngle = Math.max((prevLabel === null || prevLabel === void 0 ? void 0 : prevLabel.angle) || 0, relatedSegment.startAngle +
130
+ (relatedSegment.endAngle - relatedSegment.startAngle) / 2);
131
+ const [x, y] = getLabelPosition(midAngle);
132
+ const label = {
133
+ text,
134
+ x,
135
+ y,
136
+ style,
137
+ size: { width: labelWidth, height: labelHeight },
138
+ maxWidth: labelWidth,
139
+ textAnchor: midAngle < Math.PI ? 'start' : 'end',
140
+ series: { id: d.id },
141
+ active: true,
142
+ segment: relatedSegment.data,
143
+ angle: midAngle,
144
+ };
145
+ let overlap = false;
146
+ if (prevLabel) {
147
+ overlap = isLabelsOverlapping(prevLabel, label, dataLabels.padding);
148
+ if (overlap) {
149
+ let shouldAdjustAngle = true;
150
+ const step = Math.PI / 180;
151
+ while (shouldAdjustAngle) {
152
+ const newAngle = label.angle + step;
153
+ if (newAngle > FULL_CIRCLE && newAngle % FULL_CIRCLE > labels[0].angle) {
154
+ shouldAdjustAngle = false;
155
+ }
156
+ else {
157
+ label.angle = newAngle;
158
+ const [newX, newY] = getLabelPosition(newAngle);
159
+ label.x = newX;
160
+ label.y = newY;
161
+ if (!isLabelsOverlapping(prevLabel, label, dataLabels.padding)) {
139
162
  shouldAdjustAngle = false;
140
- }
141
- else {
142
- label.angle = newAngle;
143
- const [newX, newY] = getLabelPosition(newAngle);
144
- label.x = newX;
145
- label.y = newY;
146
- if (!isLabelsOverlapping(prevLabel, label, dataLabels.padding)) {
147
- shouldAdjustAngle = false;
148
- overlap = false;
149
- }
163
+ overlap = false;
150
164
  }
151
165
  }
152
166
  }
153
167
  }
154
- if (dataLabels.allowOverlap || !overlap) {
155
- const left = getLeftPosition(label);
156
- if (Math.abs(left) > boundsWidth / 2) {
157
- label.maxWidth = label.size.width - (Math.abs(left) - boundsWidth / 2);
158
- }
159
- else {
160
- const right = left + label.size.width;
161
- if (right > boundsWidth / 2) {
162
- label.maxWidth = label.size.width - (right - boundsWidth / 2);
163
- }
164
- }
165
- if (shouldUseHtml) {
166
- data.htmlElements.push({
167
- x: boundsWidth / 2 + label.x,
168
- y: boundsHeight / 2 + label.y,
169
- content: label.text,
170
- });
171
- }
172
- else {
173
- labels.push(label);
168
+ }
169
+ if (dataLabels.allowOverlap || !overlap) {
170
+ const left = getLeftPosition(label);
171
+ if (Math.abs(left) > boundsWidth / 2) {
172
+ label.maxWidth = label.size.width - (Math.abs(left) - boundsWidth / 2);
173
+ }
174
+ else {
175
+ const right = left + label.size.width;
176
+ if (right > boundsWidth / 2) {
177
+ label.maxWidth = label.size.width - (right - boundsWidth / 2);
174
178
  }
175
- const connector = {
176
- path: line(getConnectorPoints(midAngle)),
177
- color: relatedSegment.data.color,
178
- };
179
- data.connectors.push(connector);
180
179
  }
180
+ if (shouldUseHtml) {
181
+ htmlLabels.push({
182
+ x: data.center[0] + label.x,
183
+ y: Math.max(0, data.center[1] + label.y),
184
+ content: label.text,
185
+ size: label.size,
186
+ });
187
+ }
188
+ else {
189
+ labels.push(label);
190
+ }
191
+ const connector = {
192
+ path: line(getConnectorPoints(midAngle)),
193
+ color: relatedSegment.data.color,
194
+ };
195
+ connectors.push(connector);
196
+ }
197
+ });
198
+ return {
199
+ labels,
200
+ htmlLabels,
201
+ connectors,
202
+ };
203
+ };
204
+ return Array.from(groupedPieSeries).map(([stackId, items]) => {
205
+ const data = prepareItem(stackId, items);
206
+ const preparedLabels = prepareLabels({
207
+ data,
208
+ series: items,
209
+ });
210
+ const segmentMaxRadius = Math.max(...data.segments.map((s) => s.data.radius));
211
+ const top = Math.min(data.center[1] - segmentMaxRadius, ...preparedLabels.labels.map((l) => l.y + data.center[1]), ...preparedLabels.htmlLabels.map((l) => l.y));
212
+ const bottom = Math.max(data.center[1] + segmentMaxRadius, ...preparedLabels.labels.map((l) => l.y + data.center[1] + l.size.height), ...preparedLabels.htmlLabels.map((l) => l.y + l.size.height));
213
+ const topAdjustment = Math.floor(top - data.halo.size);
214
+ if (topAdjustment > 0) {
215
+ data.segments.forEach((s) => {
216
+ s.data.radius += topAdjustment / 2;
217
+ });
218
+ data.center[1] -= topAdjustment / 2;
219
+ }
220
+ const bottomAdjustment = Math.floor(boundsHeight - bottom - data.halo.size);
221
+ if (bottomAdjustment > 0) {
222
+ data.segments.forEach((s) => {
223
+ s.data.radius += bottomAdjustment / 2;
181
224
  });
182
- data.labels = labels;
225
+ data.center[1] += bottomAdjustment / 2;
183
226
  }
227
+ const { labels, htmlLabels, connectors } = prepareLabels({
228
+ data,
229
+ series: items,
230
+ });
231
+ data.labels = labels;
232
+ data.htmlLabels = htmlLabels;
233
+ data.connectors = connectors;
184
234
  return data;
185
235
  });
186
236
  }
@@ -9,6 +9,7 @@ export type SegmentData = {
9
9
  hovered: boolean;
10
10
  active: boolean;
11
11
  pie: PreparedPieData;
12
+ radius: number;
12
13
  };
13
14
  export type PieLabelData = LabelData & {
14
15
  segment: SegmentData;
@@ -25,7 +26,6 @@ export type PreparedPieData = {
25
26
  labels: PieLabelData[];
26
27
  connectors: PieConnectorData[];
27
28
  center: [number, number];
28
- radius: number;
29
29
  innerRadius: number;
30
30
  borderRadius: number;
31
31
  borderWidth: number;
@@ -37,5 +37,5 @@ export type PreparedPieData = {
37
37
  opacity: number;
38
38
  size: number;
39
39
  };
40
- htmlElements: HtmlItem[];
40
+ htmlLabels: HtmlItem[];
41
41
  };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { Dispatch } from 'd3';
3
+ import type { PreparedSeriesOptions } from '../../useSeries/types';
4
+ import type { PreparedSankeyData } from './types';
5
+ type ShapeProps = {
6
+ dispatcher: Dispatch<object>;
7
+ preparedData: PreparedSankeyData;
8
+ seriesOptions: PreparedSeriesOptions;
9
+ htmlLayout: HTMLElement | null;
10
+ };
11
+ export declare const SankeySeriesShape: (props: ShapeProps) => React.JSX.Element;
12
+ export {};
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { select } from 'd3';
3
+ import { block } from '../../../utils';
4
+ import { HtmlLayer } from '../HtmlLayer';
5
+ const b = block('sankey');
6
+ export const SankeySeriesShape = (props) => {
7
+ const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
8
+ const hoveredDataRef = React.useRef(null);
9
+ const ref = React.useRef(null);
10
+ React.useEffect(() => {
11
+ if (!ref.current) {
12
+ return () => { };
13
+ }
14
+ const svgElement = select(ref.current);
15
+ svgElement.selectAll('*').remove();
16
+ // nodes
17
+ svgElement
18
+ .append('g')
19
+ .selectAll()
20
+ .data(preparedData.nodes)
21
+ .join('rect')
22
+ .attr('x', (d) => d.x0)
23
+ .attr('y', (d) => d.y0)
24
+ .attr('height', (d) => d.y1 - d.y0)
25
+ .attr('width', (d) => d.x1 - d.x0)
26
+ .attr('fill', (d) => d.color);
27
+ // links
28
+ svgElement
29
+ .append('g')
30
+ .attr('fill', 'none')
31
+ .selectAll()
32
+ .data(preparedData.links)
33
+ .join('g')
34
+ .append('path')
35
+ .attr('stroke-opacity', (d) => d.opacity)
36
+ .attr('d', (d) => d.path)
37
+ .attr('stroke', (d) => d.color)
38
+ .attr('stroke-width', (d) => d.strokeWidth);
39
+ // dataLabels
40
+ svgElement
41
+ .append('g')
42
+ .selectAll()
43
+ .data(preparedData.labels)
44
+ .join('text')
45
+ .text((d) => d.text)
46
+ .attr('class', b('label'))
47
+ .attr('x', (d) => d.x)
48
+ .attr('y', (d) => d.y)
49
+ .attr('dy', '0.35em')
50
+ .attr('text-anchor', (d) => d.textAnchor)
51
+ .attr('fill', (d) => { var _a; return (_a = d.style.fontColor) !== null && _a !== void 0 ? _a : null; });
52
+ const eventName = `hover-shape.sankey`;
53
+ function handleShapeHover(data) {
54
+ hoveredDataRef.current = data;
55
+ }
56
+ if (hoveredDataRef.current !== null) {
57
+ handleShapeHover(hoveredDataRef.current);
58
+ }
59
+ dispatcher.on(eventName, handleShapeHover);
60
+ return () => {
61
+ dispatcher.on(eventName, null);
62
+ };
63
+ }, [dispatcher, preparedData, seriesOptions]);
64
+ return (React.createElement(React.Fragment, null,
65
+ React.createElement("g", { ref: ref, className: b() }),
66
+ React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
67
+ };
@@ -0,0 +1,7 @@
1
+ import type { PreparedSankeySeries } from '../../useSeries/types';
2
+ import type { PreparedSankeyData } from './types';
3
+ export declare function prepareSankeyData(args: {
4
+ series: PreparedSankeySeries;
5
+ width: number;
6
+ height: number;
7
+ }): PreparedSankeyData;
@@ -0,0 +1,72 @@
1
+ import { sankey, sankeyLinkHorizontal } from 'd3-sankey';
2
+ export function prepareSankeyData(args) {
3
+ const { series, width, height } = args;
4
+ const htmlElements = [];
5
+ const sankeyGenerator = sankey()
6
+ .nodeId((d) => d.name)
7
+ .nodeSort((d) => d.index)
8
+ .nodeWidth(15)
9
+ .nodePadding(10)
10
+ .extent([
11
+ [1, 5],
12
+ [width - 1, height - 5],
13
+ ]);
14
+ const { nodes, links } = sankeyGenerator({
15
+ nodes: series.data,
16
+ links: series.data.reduce((acc, item) => {
17
+ item.links.forEach((l) => {
18
+ const target = series.data.find((d) => d.name === l.name);
19
+ if (target) {
20
+ acc.push({
21
+ source: item,
22
+ target,
23
+ value: l.value,
24
+ });
25
+ }
26
+ });
27
+ return acc;
28
+ }, []),
29
+ });
30
+ const sankeyNodes = nodes.map((node) => {
31
+ var _a, _b, _c, _d, _e, _f;
32
+ return {
33
+ x0: (_a = node.x0) !== null && _a !== void 0 ? _a : 0,
34
+ x1: (_b = node.x1) !== null && _b !== void 0 ? _b : 0,
35
+ y0: (_c = node.y0) !== null && _c !== void 0 ? _c : 0,
36
+ y1: (_d = node.y1) !== null && _d !== void 0 ? _d : 0,
37
+ color: (_e = node.color) !== null && _e !== void 0 ? _e : '',
38
+ data: series.data[(_f = node.index) !== null && _f !== void 0 ? _f : 0],
39
+ };
40
+ });
41
+ const sankeyLinks = links.map((d) => {
42
+ var _a, _b;
43
+ return {
44
+ opacity: 0.75,
45
+ color: (_a = d.source.color) !== null && _a !== void 0 ? _a : '',
46
+ path: sankeyLinkHorizontal()(d),
47
+ strokeWidth: Math.max(1, (_b = d.width) !== null && _b !== void 0 ? _b : 0),
48
+ source: d.source,
49
+ target: d.target,
50
+ value: d.value,
51
+ };
52
+ });
53
+ const dataLabels = [];
54
+ if (series.dataLabels.enabled) {
55
+ const labels = nodes.map((d) => {
56
+ var _a, _b, _c, _d;
57
+ const x0 = (_a = d.x0) !== null && _a !== void 0 ? _a : 0;
58
+ const x1 = (_b = d.x1) !== null && _b !== void 0 ? _b : 0;
59
+ const y0 = (_c = d.y0) !== null && _c !== void 0 ? _c : 0;
60
+ const y1 = (_d = d.y1) !== null && _d !== void 0 ? _d : 0;
61
+ return {
62
+ text: d.name,
63
+ x: x0 < width / 2 ? x1 + 6 : x0 - 6,
64
+ y: (y1 + y0) / 2,
65
+ textAnchor: x0 < width / 2 ? 'start' : 'end',
66
+ style: series.dataLabels.style,
67
+ };
68
+ });
69
+ dataLabels.push(...labels);
70
+ }
71
+ return { series, nodes: sankeyNodes, links: sankeyLinks, htmlElements, labels: dataLabels };
72
+ }
@@ -0,0 +1,33 @@
1
+ import type { BaseTextStyle, HtmlItem, SankeySeriesData } from '../../../types';
2
+ import type { PreparedSankeySeries } from '../../useSeries/types';
3
+ export type SankeyDataLabel = {
4
+ text: string;
5
+ x: number;
6
+ y: number;
7
+ textAnchor: 'start' | 'end';
8
+ style: BaseTextStyle;
9
+ };
10
+ export type SankeyNode = {
11
+ x0: number;
12
+ x1: number;
13
+ y0: number;
14
+ y1: number;
15
+ color: string;
16
+ data: SankeySeriesData;
17
+ };
18
+ export type SankeyLink = {
19
+ opacity: number;
20
+ color: string;
21
+ path: string | null;
22
+ strokeWidth: number;
23
+ source: SankeySeriesData;
24
+ target: SankeySeriesData;
25
+ value: number;
26
+ };
27
+ export type PreparedSankeyData = {
28
+ series: PreparedSankeySeries;
29
+ htmlElements: HtmlItem[];
30
+ nodes: SankeyNode[];
31
+ links: SankeyLink[];
32
+ labels: SankeyDataLabel[];
33
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -12,12 +12,12 @@
12
12
  alignment-baseline: before-edge;
13
13
  }
14
14
 
15
- .gcharts-d3-bar-x__label {
15
+ .gcharts-bar-x__label {
16
16
  user-select: none;
17
17
  fill: var(--g-color-text-complementary);
18
18
  }
19
19
 
20
- .gcharts-d3-bar-y__label {
20
+ .gcharts-bar-y__label {
21
21
  user-select: none;
22
22
  fill: var(--g-color-text-complementary);
23
23
  alignment-baseline: after-edge;
@@ -33,6 +33,7 @@ function getLabels(args) {
33
33
  content: text,
34
34
  x,
35
35
  y,
36
+ size: { width, height: lineHeight },
36
37
  }
37
38
  : {
38
39
  text,
@@ -1,5 +1,4 @@
1
1
  import type { BaseType } from 'd3';
2
- import type { DashStyle } from '../../constants';
3
2
  import type { BasicInactiveState } from '../../types';
4
3
  import type { ChartScale } from '../useAxisScales';
5
4
  import type { PreparedAxis } from '../useChartOptions/types';
@@ -26,4 +25,10 @@ export declare function setActiveState<T extends {
26
25
  state: BasicInactiveState | undefined;
27
26
  active: boolean;
28
27
  }): T;
29
- export declare function getLineDashArray(dashStyle: DashStyle, strokeWidth?: number): string;
28
+ export declare function getRectPath(args: {
29
+ x: number;
30
+ y: number;
31
+ width: number;
32
+ height: number;
33
+ borderRadius?: number | number[];
34
+ }): import("d3-path").Path;
@@ -1,4 +1,4 @@
1
- import { select } from 'd3';
1
+ import { path, select } from 'd3';
2
2
  import get from 'lodash/get';
3
3
  import { getDataCategoryValue } from '../../utils';
4
4
  export function getXValue(args) {
@@ -36,20 +36,25 @@ export function setActiveState(args) {
36
36
  }
37
37
  return datum;
38
38
  }
39
- export function getLineDashArray(dashStyle, strokeWidth = 2) {
40
- const value = dashStyle.toLowerCase();
41
- const arrayValue = value
42
- .replace('shortdashdotdot', '3,1,1,1,1,1,')
43
- .replace('shortdashdot', '3,1,1,1')
44
- .replace('shortdot', '1,1,')
45
- .replace('shortdash', '3,1,')
46
- .replace('longdash', '8,3,')
47
- .replace(/dot/g, '1,3,')
48
- .replace('dash', '4,3,')
49
- .replace(/,$/, '')
50
- .split(',')
51
- .map((part) => {
52
- return `${parseInt(part, 10) * strokeWidth}`;
53
- });
54
- return arrayValue.join(',').replace(/NaN/g, 'none');
39
+ export function getRectPath(args) {
40
+ const { x, y, width, height, borderRadius = 0 } = args;
41
+ const borderRadiuses = typeof borderRadius === 'number' ? new Array(4).fill(borderRadius) : borderRadius;
42
+ const [borderRadiusTopLeft = 0, borderRadiusTopRight = 0, borderRadiusBottomRight = 0, borderRadiusBottomLeft = 0,] = borderRadiuses !== null && borderRadiuses !== void 0 ? borderRadiuses : [];
43
+ const p = path();
44
+ let startAngle = -Math.PI / 2;
45
+ const angle = Math.PI / 2;
46
+ p.moveTo(x + borderRadiusTopLeft, y);
47
+ p.lineTo(x + width - borderRadiusTopRight, y);
48
+ p.arc(x + width - borderRadiusTopRight, y + borderRadiusTopRight, borderRadiusTopRight, startAngle, startAngle + angle);
49
+ startAngle += angle;
50
+ p.lineTo(x + width, y + height - borderRadiusBottomRight);
51
+ p.arc(x + width - borderRadiusBottomRight, y + height - borderRadiusBottomRight, borderRadiusBottomRight, startAngle, startAngle + angle);
52
+ startAngle += angle;
53
+ p.lineTo(x + borderRadiusBottomLeft, y + height);
54
+ p.arc(x + borderRadiusBottomLeft, y + height - borderRadiusBottomLeft, borderRadiusBottomLeft, startAngle, startAngle + angle);
55
+ startAngle += angle;
56
+ p.lineTo(x, y + borderRadiusTopLeft);
57
+ p.arc(x + borderRadiusTopLeft, y + borderRadiusTopLeft, borderRadiusTopLeft, startAngle, startAngle + angle);
58
+ p.closePath();
59
+ return p;
55
60
  }