@gravity-ui/charts 0.6.0 → 0.6.1-beta.2

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 (178) 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/ChartInner/useChartInnerProps.d.ts +2 -2
  7. package/dist/cjs/components/Legend/index.js +1 -2
  8. package/dist/cjs/components/PlotTitle/index.js +1 -1
  9. package/dist/cjs/components/PlotTitle/styles.css +1 -1
  10. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +2 -2
  11. package/dist/cjs/components/Tooltip/DefaultContent.js +19 -3
  12. package/dist/cjs/components/Tooltip/index.js +2 -2
  13. package/dist/cjs/components/Tooltip/styles.css +11 -9
  14. package/dist/cjs/components/index.d.ts +10 -9
  15. package/dist/cjs/constants/index.d.ts +1 -0
  16. package/dist/cjs/constants/index.js +1 -0
  17. package/dist/cjs/hooks/useChartOptions/types.d.ts +11 -1
  18. package/dist/cjs/hooks/useChartOptions/x-axis.js +1 -0
  19. package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -1
  20. package/dist/cjs/hooks/useSeries/prepare-area.d.ts +1 -1
  21. package/dist/cjs/hooks/useSeries/prepare-bar-x.d.ts +2 -1
  22. package/dist/cjs/hooks/useSeries/prepare-bar-x.js +2 -1
  23. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +2 -1
  24. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
  25. package/dist/cjs/hooks/useSeries/prepare-line.d.ts +1 -1
  26. package/dist/cjs/hooks/useSeries/prepare-pie.js +2 -2
  27. package/dist/cjs/hooks/useSeries/prepare-sankey.d.ts +11 -0
  28. package/dist/cjs/hooks/useSeries/prepare-sankey.js +38 -0
  29. package/dist/cjs/hooks/useSeries/prepareSeries.js +21 -2
  30. package/dist/cjs/hooks/useSeries/types.d.ts +12 -2
  31. package/dist/cjs/hooks/useSeries/utils.js +1 -1
  32. package/dist/cjs/hooks/useShapes/area/prepare-data.js +4 -0
  33. package/dist/cjs/hooks/useShapes/bar-x/index.js +16 -2
  34. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +3 -1
  35. package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +1 -0
  36. package/dist/cjs/hooks/useShapes/bar-y/index.js +16 -2
  37. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +3 -1
  38. package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +1 -0
  39. package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
  40. package/dist/cjs/hooks/useShapes/index.js +19 -0
  41. package/dist/cjs/hooks/useShapes/line/index.js +2 -2
  42. package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -0
  43. package/dist/cjs/hooks/useShapes/pie/index.js +5 -4
  44. package/dist/cjs/hooks/useShapes/pie/prepare-data.js +168 -118
  45. package/dist/cjs/hooks/useShapes/pie/types.d.ts +2 -2
  46. package/dist/cjs/hooks/useShapes/sankey/index.d.ts +12 -0
  47. package/dist/cjs/hooks/useShapes/sankey/index.js +67 -0
  48. package/dist/cjs/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  49. package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +72 -0
  50. package/dist/cjs/hooks/useShapes/sankey/types.d.ts +33 -0
  51. package/dist/cjs/hooks/useShapes/sankey/types.js +1 -0
  52. package/dist/cjs/hooks/useShapes/styles.css +2 -2
  53. package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +1 -0
  54. package/dist/cjs/hooks/useShapes/utils.d.ts +7 -2
  55. package/dist/cjs/hooks/useShapes/utils.js +22 -17
  56. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -2
  57. package/dist/cjs/index.d.ts +1 -1
  58. package/dist/cjs/index.js +1 -0
  59. package/dist/cjs/types/chart/area.d.ts +6 -6
  60. package/dist/cjs/types/chart/axis.d.ts +32 -7
  61. package/dist/cjs/types/chart/bar-x.d.ts +9 -4
  62. package/dist/cjs/types/chart/bar-y.d.ts +10 -6
  63. package/dist/cjs/types/chart/base.d.ts +6 -6
  64. package/dist/cjs/types/chart/chart.d.ts +4 -4
  65. package/dist/cjs/types/chart/halo.d.ts +2 -2
  66. package/dist/cjs/types/chart/legend.d.ts +10 -10
  67. package/dist/cjs/types/chart/line.d.ts +4 -4
  68. package/dist/cjs/types/chart/marker.d.ts +2 -2
  69. package/dist/cjs/types/chart/pie.d.ts +6 -4
  70. package/dist/cjs/types/chart/sankey.d.ts +22 -0
  71. package/dist/cjs/types/chart/sankey.js +1 -0
  72. package/dist/cjs/types/chart/scatter.d.ts +4 -4
  73. package/dist/cjs/types/chart/series.d.ts +21 -10
  74. package/dist/cjs/types/chart/split.d.ts +4 -4
  75. package/dist/cjs/types/chart/title.d.ts +2 -2
  76. package/dist/cjs/types/chart/tooltip.d.ts +27 -21
  77. package/dist/cjs/types/chart/treemap.d.ts +4 -4
  78. package/dist/cjs/types/chart/waterfall.d.ts +4 -4
  79. package/dist/cjs/types/chart-ui.d.ts +10 -6
  80. package/dist/cjs/types/formatter.d.ts +4 -4
  81. package/dist/cjs/types/index.d.ts +35 -4
  82. package/dist/cjs/types/index.js +1 -0
  83. package/dist/cjs/utils/chart/get-closest-data.d.ts +2 -0
  84. package/dist/cjs/utils/chart/get-closest-data.js +39 -3
  85. package/dist/cjs/utils/chart/index.js +1 -1
  86. package/dist/cjs/utils/chart/series/index.d.ts +1 -0
  87. package/dist/cjs/utils/chart/series/index.js +1 -0
  88. package/dist/cjs/utils/chart/series/line.d.ts +2 -0
  89. package/dist/cjs/utils/chart/series/line.js +17 -0
  90. package/dist/esm/components/Axis/AxisY.d.ts +1 -0
  91. package/dist/esm/components/Axis/AxisY.js +55 -13
  92. package/dist/esm/components/ChartInner/index.js +3 -2
  93. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +4 -0
  94. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +2 -2
  95. package/dist/esm/components/Legend/index.js +1 -2
  96. package/dist/esm/components/PlotTitle/index.js +1 -1
  97. package/dist/esm/components/PlotTitle/styles.css +1 -1
  98. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +2 -2
  99. package/dist/esm/components/Tooltip/DefaultContent.js +19 -3
  100. package/dist/esm/components/Tooltip/index.js +2 -2
  101. package/dist/esm/components/Tooltip/styles.css +11 -9
  102. package/dist/esm/components/index.d.ts +10 -9
  103. package/dist/esm/constants/index.d.ts +1 -0
  104. package/dist/esm/constants/index.js +1 -0
  105. package/dist/esm/hooks/useChartOptions/types.d.ts +11 -1
  106. package/dist/esm/hooks/useChartOptions/x-axis.js +1 -0
  107. package/dist/esm/hooks/useChartOptions/y-axis.js +9 -1
  108. package/dist/esm/hooks/useSeries/prepare-area.d.ts +1 -1
  109. package/dist/esm/hooks/useSeries/prepare-bar-x.d.ts +2 -1
  110. package/dist/esm/hooks/useSeries/prepare-bar-x.js +2 -1
  111. package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +2 -1
  112. package/dist/esm/hooks/useSeries/prepare-bar-y.js +3 -1
  113. package/dist/esm/hooks/useSeries/prepare-line.d.ts +1 -1
  114. package/dist/esm/hooks/useSeries/prepare-pie.js +2 -2
  115. package/dist/esm/hooks/useSeries/prepare-sankey.d.ts +11 -0
  116. package/dist/esm/hooks/useSeries/prepare-sankey.js +38 -0
  117. package/dist/esm/hooks/useSeries/prepareSeries.js +21 -2
  118. package/dist/esm/hooks/useSeries/types.d.ts +12 -2
  119. package/dist/esm/hooks/useSeries/utils.js +1 -1
  120. package/dist/esm/hooks/useShapes/area/prepare-data.js +4 -0
  121. package/dist/esm/hooks/useShapes/bar-x/index.js +16 -2
  122. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +3 -1
  123. package/dist/esm/hooks/useShapes/bar-x/types.d.ts +1 -0
  124. package/dist/esm/hooks/useShapes/bar-y/index.js +16 -2
  125. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +3 -1
  126. package/dist/esm/hooks/useShapes/bar-y/types.d.ts +1 -0
  127. package/dist/esm/hooks/useShapes/index.d.ts +2 -1
  128. package/dist/esm/hooks/useShapes/index.js +19 -0
  129. package/dist/esm/hooks/useShapes/line/index.js +2 -2
  130. package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -0
  131. package/dist/esm/hooks/useShapes/pie/index.js +5 -4
  132. package/dist/esm/hooks/useShapes/pie/prepare-data.js +168 -118
  133. package/dist/esm/hooks/useShapes/pie/types.d.ts +2 -2
  134. package/dist/esm/hooks/useShapes/sankey/index.d.ts +12 -0
  135. package/dist/esm/hooks/useShapes/sankey/index.js +67 -0
  136. package/dist/esm/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  137. package/dist/esm/hooks/useShapes/sankey/prepare-data.js +72 -0
  138. package/dist/esm/hooks/useShapes/sankey/types.d.ts +33 -0
  139. package/dist/esm/hooks/useShapes/sankey/types.js +1 -0
  140. package/dist/esm/hooks/useShapes/styles.css +2 -2
  141. package/dist/esm/hooks/useShapes/treemap/prepare-data.js +1 -0
  142. package/dist/esm/hooks/useShapes/utils.d.ts +7 -2
  143. package/dist/esm/hooks/useShapes/utils.js +22 -17
  144. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -2
  145. package/dist/esm/index.d.ts +1 -1
  146. package/dist/esm/index.js +1 -0
  147. package/dist/esm/types/chart/area.d.ts +6 -6
  148. package/dist/esm/types/chart/axis.d.ts +32 -7
  149. package/dist/esm/types/chart/bar-x.d.ts +9 -4
  150. package/dist/esm/types/chart/bar-y.d.ts +10 -6
  151. package/dist/esm/types/chart/base.d.ts +6 -6
  152. package/dist/esm/types/chart/chart.d.ts +4 -4
  153. package/dist/esm/types/chart/halo.d.ts +2 -2
  154. package/dist/esm/types/chart/legend.d.ts +10 -10
  155. package/dist/esm/types/chart/line.d.ts +4 -4
  156. package/dist/esm/types/chart/marker.d.ts +2 -2
  157. package/dist/esm/types/chart/pie.d.ts +6 -4
  158. package/dist/esm/types/chart/sankey.d.ts +22 -0
  159. package/dist/esm/types/chart/sankey.js +1 -0
  160. package/dist/esm/types/chart/scatter.d.ts +4 -4
  161. package/dist/esm/types/chart/series.d.ts +21 -10
  162. package/dist/esm/types/chart/split.d.ts +4 -4
  163. package/dist/esm/types/chart/title.d.ts +2 -2
  164. package/dist/esm/types/chart/tooltip.d.ts +27 -21
  165. package/dist/esm/types/chart/treemap.d.ts +4 -4
  166. package/dist/esm/types/chart/waterfall.d.ts +4 -4
  167. package/dist/esm/types/chart-ui.d.ts +10 -6
  168. package/dist/esm/types/formatter.d.ts +4 -4
  169. package/dist/esm/types/index.d.ts +35 -4
  170. package/dist/esm/types/index.js +1 -0
  171. package/dist/esm/utils/chart/get-closest-data.d.ts +2 -0
  172. package/dist/esm/utils/chart/get-closest-data.js +39 -3
  173. package/dist/esm/utils/chart/index.js +1 -1
  174. package/dist/esm/utils/chart/series/index.d.ts +1 -0
  175. package/dist/esm/utils/chart/series/index.js +1 -0
  176. package/dist/esm/utils/chart/series/line.d.ts +2 -0
  177. package/dist/esm/utils/chart/series/line.js +17 -0
  178. 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
  }