@gravity-ui/charts 0.7.0 → 0.9.0

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 (168) hide show
  1. package/README.md +1 -4
  2. package/dist/cjs/components/Axis/AxisX.d.ts +1 -0
  3. package/dist/cjs/components/Axis/AxisX.js +43 -6
  4. package/dist/cjs/components/Axis/AxisY.d.ts +1 -0
  5. package/dist/cjs/components/Axis/AxisY.js +63 -17
  6. package/dist/cjs/components/Axis/styles.css +5 -5
  7. package/dist/cjs/components/ChartInner/index.js +8 -6
  8. package/dist/cjs/components/ChartInner/styles.css +4 -4
  9. package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
  10. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +7 -4
  11. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +3 -2
  12. package/dist/cjs/components/Legend/index.js +2 -3
  13. package/dist/cjs/components/Legend/styles.css +14 -14
  14. package/dist/cjs/components/PlotTitle/index.js +1 -1
  15. package/dist/cjs/components/PlotTitle/styles.css +1 -1
  16. package/dist/cjs/components/Title/index.js +1 -1
  17. package/dist/cjs/components/Title/styles.css +1 -1
  18. package/dist/cjs/components/Tooltip/DefaultContent.js +19 -3
  19. package/dist/cjs/constants/index.d.ts +1 -0
  20. package/dist/cjs/constants/index.js +1 -0
  21. package/dist/cjs/hooks/useChartOptions/tooltip.js +2 -1
  22. package/dist/cjs/hooks/useChartOptions/types.d.ts +13 -2
  23. package/dist/cjs/hooks/useChartOptions/x-axis.js +9 -1
  24. package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -1
  25. package/dist/cjs/hooks/useSeries/constants.js +1 -1
  26. package/dist/cjs/hooks/useSeries/prepare-bar-x.d.ts +2 -1
  27. package/dist/cjs/hooks/useSeries/prepare-bar-x.js +2 -1
  28. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +2 -1
  29. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
  30. package/dist/cjs/hooks/useSeries/prepare-pie.js +2 -2
  31. package/dist/cjs/hooks/useSeries/prepare-sankey.d.ts +11 -0
  32. package/dist/cjs/hooks/useSeries/prepare-sankey.js +38 -0
  33. package/dist/cjs/hooks/useSeries/prepareSeries.js +21 -2
  34. package/dist/cjs/hooks/useSeries/types.d.ts +12 -2
  35. package/dist/cjs/hooks/useSeries/utils.js +1 -1
  36. package/dist/cjs/hooks/useShapes/area/index.js +1 -1
  37. package/dist/cjs/hooks/useShapes/bar-x/index.js +16 -2
  38. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +2 -1
  39. package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +1 -0
  40. package/dist/cjs/hooks/useShapes/bar-y/index.js +16 -2
  41. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +2 -1
  42. package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +1 -0
  43. package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
  44. package/dist/cjs/hooks/useShapes/index.js +19 -0
  45. package/dist/cjs/hooks/useShapes/line/index.js +3 -3
  46. package/dist/cjs/hooks/useShapes/marker.js +1 -1
  47. package/dist/cjs/hooks/useShapes/pie/index.js +4 -4
  48. package/dist/cjs/hooks/useShapes/pie/prepare-data.js +37 -35
  49. package/dist/cjs/hooks/useShapes/pie/types.d.ts +1 -1
  50. package/dist/cjs/hooks/useShapes/sankey/index.d.ts +12 -0
  51. package/dist/cjs/hooks/useShapes/sankey/index.js +67 -0
  52. package/dist/cjs/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  53. package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +72 -0
  54. package/dist/cjs/hooks/useShapes/sankey/types.d.ts +33 -0
  55. package/dist/cjs/hooks/useShapes/sankey/types.js +1 -0
  56. package/dist/cjs/hooks/useShapes/scatter/index.js +1 -1
  57. package/dist/cjs/hooks/useShapes/styles.css +7 -7
  58. package/dist/cjs/hooks/useShapes/treemap/index.js +1 -1
  59. package/dist/cjs/hooks/useShapes/utils.d.ts +7 -2
  60. package/dist/cjs/hooks/useShapes/utils.js +22 -17
  61. package/dist/cjs/hooks/useShapes/waterfall/index.js +2 -3
  62. package/dist/cjs/index.d.ts +1 -1
  63. package/dist/cjs/index.js +1 -0
  64. package/dist/cjs/types/chart/axis.d.ts +24 -0
  65. package/dist/cjs/types/chart/bar-x.d.ts +5 -0
  66. package/dist/cjs/types/chart/bar-y.d.ts +5 -0
  67. package/dist/cjs/types/chart/pie.d.ts +2 -0
  68. package/dist/cjs/types/chart/sankey.d.ts +22 -0
  69. package/dist/cjs/types/chart/sankey.js +1 -0
  70. package/dist/cjs/types/chart/series.d.ts +13 -2
  71. package/dist/cjs/types/chart/tooltip.d.ts +9 -1
  72. package/dist/cjs/types/index.d.ts +1 -0
  73. package/dist/cjs/types/index.js +1 -0
  74. package/dist/cjs/utils/chart/get-closest-data.d.ts +2 -0
  75. package/dist/cjs/utils/chart/get-closest-data.js +39 -3
  76. package/dist/cjs/utils/chart/index.js +1 -1
  77. package/dist/cjs/utils/chart/series/index.d.ts +1 -0
  78. package/dist/cjs/utils/chart/series/index.js +1 -0
  79. package/dist/cjs/utils/chart/series/line.d.ts +2 -0
  80. package/dist/cjs/utils/chart/series/line.js +17 -0
  81. package/dist/cjs/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
  82. package/dist/cjs/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
  83. package/dist/cjs/utils/index.d.ts +1 -1
  84. package/dist/cjs/utils/index.js +1 -1
  85. package/dist/esm/components/Axis/AxisX.d.ts +1 -0
  86. package/dist/esm/components/Axis/AxisX.js +43 -6
  87. package/dist/esm/components/Axis/AxisY.d.ts +1 -0
  88. package/dist/esm/components/Axis/AxisY.js +63 -17
  89. package/dist/esm/components/Axis/styles.css +5 -5
  90. package/dist/esm/components/ChartInner/index.js +8 -6
  91. package/dist/esm/components/ChartInner/styles.css +4 -4
  92. package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
  93. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +7 -4
  94. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +3 -2
  95. package/dist/esm/components/Legend/index.js +2 -3
  96. package/dist/esm/components/Legend/styles.css +14 -14
  97. package/dist/esm/components/PlotTitle/index.js +1 -1
  98. package/dist/esm/components/PlotTitle/styles.css +1 -1
  99. package/dist/esm/components/Title/index.js +1 -1
  100. package/dist/esm/components/Title/styles.css +1 -1
  101. package/dist/esm/components/Tooltip/DefaultContent.js +19 -3
  102. package/dist/esm/constants/index.d.ts +1 -0
  103. package/dist/esm/constants/index.js +1 -0
  104. package/dist/esm/hooks/useChartOptions/tooltip.js +2 -1
  105. package/dist/esm/hooks/useChartOptions/types.d.ts +13 -2
  106. package/dist/esm/hooks/useChartOptions/x-axis.js +9 -1
  107. package/dist/esm/hooks/useChartOptions/y-axis.js +9 -1
  108. package/dist/esm/hooks/useSeries/constants.js +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-pie.js +2 -2
  114. package/dist/esm/hooks/useSeries/prepare-sankey.d.ts +11 -0
  115. package/dist/esm/hooks/useSeries/prepare-sankey.js +38 -0
  116. package/dist/esm/hooks/useSeries/prepareSeries.js +21 -2
  117. package/dist/esm/hooks/useSeries/types.d.ts +12 -2
  118. package/dist/esm/hooks/useSeries/utils.js +1 -1
  119. package/dist/esm/hooks/useShapes/area/index.js +1 -1
  120. package/dist/esm/hooks/useShapes/bar-x/index.js +16 -2
  121. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +2 -1
  122. package/dist/esm/hooks/useShapes/bar-x/types.d.ts +1 -0
  123. package/dist/esm/hooks/useShapes/bar-y/index.js +16 -2
  124. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +2 -1
  125. package/dist/esm/hooks/useShapes/bar-y/types.d.ts +1 -0
  126. package/dist/esm/hooks/useShapes/index.d.ts +2 -1
  127. package/dist/esm/hooks/useShapes/index.js +19 -0
  128. package/dist/esm/hooks/useShapes/line/index.js +3 -3
  129. package/dist/esm/hooks/useShapes/marker.js +1 -1
  130. package/dist/esm/hooks/useShapes/pie/index.js +4 -4
  131. package/dist/esm/hooks/useShapes/pie/prepare-data.js +37 -35
  132. package/dist/esm/hooks/useShapes/pie/types.d.ts +1 -1
  133. package/dist/esm/hooks/useShapes/sankey/index.d.ts +12 -0
  134. package/dist/esm/hooks/useShapes/sankey/index.js +67 -0
  135. package/dist/esm/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
  136. package/dist/esm/hooks/useShapes/sankey/prepare-data.js +72 -0
  137. package/dist/esm/hooks/useShapes/sankey/types.d.ts +33 -0
  138. package/dist/esm/hooks/useShapes/sankey/types.js +1 -0
  139. package/dist/esm/hooks/useShapes/scatter/index.js +1 -1
  140. package/dist/esm/hooks/useShapes/styles.css +7 -7
  141. package/dist/esm/hooks/useShapes/treemap/index.js +1 -1
  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 +2 -3
  145. package/dist/esm/index.d.ts +1 -1
  146. package/dist/esm/index.js +1 -0
  147. package/dist/esm/types/chart/axis.d.ts +24 -0
  148. package/dist/esm/types/chart/bar-x.d.ts +5 -0
  149. package/dist/esm/types/chart/bar-y.d.ts +5 -0
  150. package/dist/esm/types/chart/pie.d.ts +2 -0
  151. package/dist/esm/types/chart/sankey.d.ts +22 -0
  152. package/dist/esm/types/chart/sankey.js +1 -0
  153. package/dist/esm/types/chart/series.d.ts +13 -2
  154. package/dist/esm/types/chart/tooltip.d.ts +9 -1
  155. package/dist/esm/types/index.d.ts +1 -0
  156. package/dist/esm/types/index.js +1 -0
  157. package/dist/esm/utils/chart/get-closest-data.d.ts +2 -0
  158. package/dist/esm/utils/chart/get-closest-data.js +39 -3
  159. package/dist/esm/utils/chart/index.js +1 -1
  160. package/dist/esm/utils/chart/series/index.d.ts +1 -0
  161. package/dist/esm/utils/chart/series/index.js +1 -0
  162. package/dist/esm/utils/chart/series/line.d.ts +2 -0
  163. package/dist/esm/utils/chart/series/line.js +17 -0
  164. package/dist/esm/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
  165. package/dist/esm/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
  166. package/dist/esm/utils/index.d.ts +1 -1
  167. package/dist/esm/utils/index.js +1 -1
  168. package/package.json +13 -2
package/README.md CHANGED
@@ -1,7 +1,4 @@
1
- # @gravity-ui/charts · [![npm package](https://img.shields.io/npm/v/@gravity-ui/charts)](https://www.npmjs.com/package/@gravity-ui/charts) [![CI](https://img.shields.io/github/actions/workflow/status/gravity-ui/charts/.github/workflows/ci.yml?label=CI&logo=github)](https://github.com/gravity-ui/charts/actions/workflows/ci.yml?query=branch:main) [![storybook](https://img.shields.io/badge/Storybook-deployed-ff4685)](https://preview.gravity-ui.com/charts/)
2
-
3
- > [!WARNING]
4
- > The library may have major changes in minor releases while it is on version `0.*.*`.
1
+ # Gravity Charts · [![npm package](https://img.shields.io/npm/v/@gravity-ui/charts)](https://www.npmjs.com/package/@gravity-ui/charts) [![CI](https://img.shields.io/github/actions/workflow/status/gravity-ui/charts/.github/workflows/ci.yml?label=CI&logo=github)](https://github.com/gravity-ui/charts/actions/workflows/ci.yml?query=branch:main) [![storybook](https://img.shields.io/badge/Storybook-deployed-ff4685)](https://preview.gravity-ui.com/charts/)
5
2
 
6
3
  ## Install
7
4
 
@@ -7,6 +7,7 @@ type Props = {
7
7
  height: number;
8
8
  scale: ChartScale;
9
9
  split: PreparedSplit;
10
+ plotRef?: React.MutableRefObject<SVGGElement | null>;
10
11
  };
11
12
  export declare function getTitlePosition(args: {
12
13
  axis: PreparedAxis;
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
- import { select } from 'd3';
3
- import { block, formatAxisTickLabel, getAxisTitleRows, getClosestPointsRange, getMaxTickCount, getScaleTicks, getTicksCount, handleOverflowingText, } from '../../utils';
2
+ import { line, select } from 'd3';
3
+ import { block, formatAxisTickLabel, getAxisTitleRows, getClosestPointsRange, getLineDashArray, getMaxTickCount, getScaleTicks, getTicksCount, handleOverflowingText, } from '../../utils';
4
4
  import { axisBottom } from '../../utils/chart/axis-generators';
5
5
  import './styles.css';
6
- const b = block('d3-axis');
6
+ const b = block('axis');
7
7
  function getLabelFormatter({ axis, scale }) {
8
8
  const ticks = getScaleTicks(scale);
9
9
  const tickStep = getClosestPointsRange(axis, ticks);
@@ -42,7 +42,7 @@ export function getTitlePosition(args) {
42
42
  return { x, y };
43
43
  }
44
44
  export const AxisX = React.memo(function AxisX(props) {
45
- const { axis, width, height: totalHeight, scale, split } = props;
45
+ const { axis, width, height: totalHeight, scale, split, plotRef } = props;
46
46
  const ref = React.useRef(null);
47
47
  React.useEffect(() => {
48
48
  if (!ref.current) {
@@ -57,8 +57,9 @@ export const AxisX = React.memo(function AxisX(props) {
57
57
  return [-top, -(top + height)];
58
58
  });
59
59
  }
60
+ const axisScale = scale;
60
61
  const xAxisGenerator = axisBottom({
61
- scale: scale,
62
+ scale: axisScale,
62
63
  ticks: {
63
64
  items: tickItems,
64
65
  labelFormat: getLabelFormatter({ axis, scale }),
@@ -103,6 +104,42 @@ export const AxisX = React.memo(function AxisX(props) {
103
104
  }
104
105
  });
105
106
  }
106
- }, [axis, width, totalHeight, scale, split]);
107
+ // add plot lines
108
+ if (plotRef && axis.plotLines.length > 0) {
109
+ const plotLineClassName = b('plotLine');
110
+ const plotLineContainer = select(plotRef.current);
111
+ plotLineContainer.selectAll(`.${plotLineClassName}-x`).remove();
112
+ const plotLinesSelection = plotLineContainer
113
+ .selectAll(`.${plotLineClassName}-x`)
114
+ .data(axis.plotLines)
115
+ .join('g')
116
+ .attr('class', `${plotLineClassName}-x`);
117
+ const lineGenerator = line();
118
+ plotLinesSelection
119
+ .append('path')
120
+ .attr('d', (plotLine) => {
121
+ const plotLineValue = Number(axisScale(plotLine.value));
122
+ const points = [
123
+ [plotLineValue, 0],
124
+ [plotLineValue, totalHeight],
125
+ ];
126
+ return lineGenerator(points);
127
+ })
128
+ .attr('stroke', (plotLine) => plotLine.color)
129
+ .attr('stroke-width', (plotLine) => plotLine.width)
130
+ .attr('stroke-dasharray', (plotLine) => getLineDashArray(plotLine.dashStyle, plotLine.width))
131
+ .attr('opacity', (plotLine) => plotLine.opacity);
132
+ // set layer placement
133
+ plotLinesSelection.each((plotLineData, i, nodes) => {
134
+ const plotLineSelection = select(nodes[i]);
135
+ if (plotLineData.layerPlacement === 'before') {
136
+ plotLineSelection.lower();
137
+ }
138
+ else {
139
+ plotLineSelection.raise();
140
+ }
141
+ });
142
+ }
143
+ }, [axis, width, totalHeight, scale, split, plotRef]);
107
144
  return React.createElement("g", { ref: ref });
108
145
  });
@@ -7,6 +7,7 @@ type Props = {
7
7
  width: number;
8
8
  height: number;
9
9
  split: PreparedSplit;
10
+ plotRef?: React.MutableRefObject<SVGGElement | null>;
10
11
  };
11
12
  export declare const AxisY: (props: Props) => React.JSX.Element;
12
13
  export {};
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { axisLeft, axisRight, line, select } from 'd3';
3
- import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getClosestPointsRange, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
3
+ import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
4
4
  import './styles.css';
5
- const b = block('d3-axis');
5
+ const b = block('axis');
6
6
  function transformLabel(args) {
7
7
  const { node, axis } = args;
8
8
  let topOffset = axis.labels.lineHeight / 2;
@@ -56,11 +56,14 @@ function getTitlePosition(args) {
56
56
  if (rowCount < 1) {
57
57
  return { x: 0, y: 0 };
58
58
  }
59
- const x = -(axis.title.height -
59
+ let x = axis.title.height -
60
60
  axis.title.height / rowCount +
61
61
  axis.title.margin +
62
62
  axis.labels.margin +
63
- axis.labels.width);
63
+ axis.labels.width;
64
+ if (axis.position === 'left') {
65
+ x = x * -1;
66
+ }
64
67
  let y;
65
68
  switch (axis.title.align) {
66
69
  case 'left': {
@@ -79,35 +82,44 @@ function getTitlePosition(args) {
79
82
  return { x, y };
80
83
  }
81
84
  export const AxisY = (props) => {
82
- const { axes, width, height: totalHeight, scale, split } = props;
85
+ const { axes, width, height: totalHeight, scale, split, plotRef } = props;
83
86
  const height = getAxisHeight({ split, boundsHeight: totalHeight });
84
87
  const ref = React.useRef(null);
88
+ const lineGenerator = line();
85
89
  React.useEffect(() => {
86
90
  if (!ref.current) {
87
91
  return;
88
92
  }
89
93
  const svgElement = select(ref.current);
90
94
  svgElement.selectAll('*').remove();
95
+ const getAxisPosition = (axis) => {
96
+ var _a;
97
+ const top = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
98
+ if (axis.position === 'left') {
99
+ return `translate(0, ${top}px)`;
100
+ }
101
+ return `translate(${width}px, 0)`;
102
+ };
103
+ const plotLines = axes.reduce((acc, axis) => {
104
+ if (axis.plotLines.length) {
105
+ acc.push(...axis.plotLines.map((plotLine) => {
106
+ return Object.assign(Object.assign({}, plotLine), { transform: getAxisPosition(axis) });
107
+ }));
108
+ }
109
+ return acc;
110
+ }, []);
91
111
  const axisSelection = svgElement
92
112
  .selectAll('axis')
93
113
  .data(axes)
94
114
  .join('g')
95
115
  .attr('class', b())
96
- .style('transform', (d) => {
97
- var _a;
98
- const top = ((_a = split.plots[d.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
99
- if (d.position === 'left') {
100
- return `translate(0, ${top}px)`;
101
- }
102
- return `translate(${width}px, 0)`;
103
- });
116
+ .style('transform', (d) => getAxisPosition(d));
104
117
  axisSelection.each((d, index, node) => {
105
118
  const seriesScale = scale[index];
106
119
  const axisItem = select(node[index]);
120
+ const axisScale = seriesScale;
107
121
  const yAxisGenerator = getAxisGenerator({
108
- axisGenerator: d.position === 'left'
109
- ? axisLeft(seriesScale)
110
- : axisRight(seriesScale),
122
+ axisGenerator: d.position === 'left' ? axisLeft(axisScale) : axisRight(axisScale),
111
123
  preparedAxis: d,
112
124
  height,
113
125
  width,
@@ -148,6 +160,40 @@ export const AxisY = (props) => {
148
160
  })
149
161
  .remove();
150
162
  }
163
+ if (plotRef && d.plotLines.length > 0) {
164
+ const plotLineClassName = b('plotLine');
165
+ const plotLineContainer = select(plotRef.current);
166
+ plotLineContainer.selectAll(`.${plotLineClassName}`).remove();
167
+ const plotLinesSelection = plotLineContainer
168
+ .selectAll(`.${plotLineClassName}`)
169
+ .data(plotLines)
170
+ .join('g')
171
+ .attr('class', plotLineClassName)
172
+ .style('transform', (plotLine) => plotLine.transform);
173
+ plotLinesSelection
174
+ .append('path')
175
+ .attr('d', (plotLine) => {
176
+ const plotLineValue = Number(axisScale(plotLine.value));
177
+ const points = [
178
+ [0, plotLineValue],
179
+ [width, plotLineValue],
180
+ ];
181
+ return lineGenerator(points);
182
+ })
183
+ .attr('stroke', (plotLine) => plotLine.color)
184
+ .attr('stroke-width', (plotLine) => plotLine.width)
185
+ .attr('stroke-dasharray', (plotLine) => getLineDashArray(plotLine.dashStyle, plotLine.width))
186
+ .attr('opacity', (plotLine) => plotLine.opacity);
187
+ plotLinesSelection.each((plotLineData, i, nodes) => {
188
+ const plotLineSelection = select(nodes[i]);
189
+ if (plotLineData.layerPlacement === 'before') {
190
+ plotLineSelection.lower();
191
+ }
192
+ else {
193
+ plotLineSelection.raise();
194
+ }
195
+ });
196
+ }
151
197
  return axisItem;
152
198
  });
153
199
  axisSelection
@@ -157,7 +203,7 @@ export const AxisY = (props) => {
157
203
  [0, 0],
158
204
  [0, height],
159
205
  ];
160
- return line()(points);
206
+ return lineGenerator(points);
161
207
  })
162
208
  .style('stroke', (d) => d.lineColor || '');
163
209
  svgElement.selectAll('.tick').each((_d, index, nodes) => {
@@ -1,17 +1,17 @@
1
- .gcharts-d3-axis .domain {
1
+ .gcharts-axis .domain {
2
2
  stroke: var(--g-color-line-generic-active);
3
3
  }
4
- .gcharts-d3-axis .tick text {
4
+ .gcharts-axis .tick text {
5
5
  color: var(--g-color-text-secondary);
6
6
  alignment-baseline: after-edge;
7
7
  }
8
- .gcharts-d3-axis .tick line, .gcharts-d3-axis .tick path {
8
+ .gcharts-axis .tick line, .gcharts-axis .tick path {
9
9
  stroke: var(--g-color-line-generic);
10
10
  }
11
- .gcharts-d3-axis__title {
11
+ .gcharts-axis__title {
12
12
  alignment-baseline: after-edge;
13
13
  fill: var(--g-color-text-secondary);
14
14
  }
15
- .gcharts-d3-axis__title tspan {
15
+ .gcharts-axis__title tspan {
16
16
  alignment-baseline: after-edge;
17
17
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { EventType, block, getD3Dispatcher } from '../../utils';
2
+ import { EventType, block, getDispatcher } from '../../utils';
3
3
  import { AxisX, AxisY } from '../Axis';
4
4
  import { Legend } from '../Legend';
5
5
  import { PlotTitle } from '../PlotTitle';
@@ -9,13 +9,14 @@ import { useChartInnerHandlers } from './useChartInnerHandlers';
9
9
  import { useChartInnerProps } from './useChartInnerProps';
10
10
  import { useChartInnerState } from './useChartInnerState';
11
11
  import './styles.css';
12
- const b = block('d3');
12
+ const b = block('chart');
13
13
  export const ChartInner = (props) => {
14
14
  var _a, _b, _c, _d;
15
15
  const { width, height, data } = props;
16
16
  const svgRef = React.useRef(null);
17
17
  const htmlLayerRef = React.useRef(null);
18
- const dispatcher = React.useMemo(() => getD3Dispatcher(), []);
18
+ const plotRef = React.useRef(null);
19
+ const dispatcher = React.useMemo(() => getDispatcher(), []);
19
20
  const { boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedSeries, preparedSplit, preparedLegend, prevHeight, prevWidth, shapes, shapesData, title, tooltip, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { dispatcher, htmlLayout: htmlLayerRef.current }));
20
21
  const { tooltipPinned, togglePinTooltip, unpinTooltip } = useChartInnerState({
21
22
  dispatcher,
@@ -34,6 +35,7 @@ export const ChartInner = (props) => {
34
35
  unpinTooltip,
35
36
  xAxis,
36
37
  yAxis,
38
+ tooltipThrottle: tooltip.throttle,
37
39
  });
38
40
  const clickHandler = (_b = (_a = data.chart) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.click;
39
41
  const pointerMoveHandler = (_d = (_c = data.chart) === null || _c === void 0 ? void 0 : _c.events) === null || _d === void 0 ? void 0 : _d.pointermove;
@@ -63,11 +65,11 @@ export const ChartInner = (props) => {
63
65
  React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit.plots.map((plot, index) => {
64
66
  return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
65
67
  })),
66
- React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})` },
68
+ React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
67
69
  xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length) && (React.createElement(React.Fragment, null,
68
- React.createElement(AxisY, { axes: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale, split: preparedSplit }),
70
+ React.createElement(AxisY, { axes: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale, split: preparedSplit, plotRef: plotRef }),
69
71
  React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
70
- React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, split: preparedSplit })))),
72
+ React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, split: preparedSplit, plotRef: plotRef })))),
71
73
  shapes),
72
74
  preparedLegend.enabled && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip }))),
73
75
  React.createElement("div", { className: b('html-layer'), ref: htmlLayerRef, style: {
@@ -1,10 +1,10 @@
1
- .gcharts-d3 {
2
- --d3-data-labels: var(--g-color-text-secondary);
1
+ .gcharts-chart {
2
+ --gcharts-data-labels: var(--g-color-text-secondary);
3
3
  position: absolute;
4
4
  }
5
- .gcharts-d3__html-layer {
5
+ .gcharts-chart__html-layer {
6
6
  display: contents;
7
7
  }
8
- .gcharts-d3__html-layer > * {
8
+ .gcharts-chart__html-layer > * {
9
9
  transform: inherit;
10
10
  }
@@ -16,6 +16,7 @@ type Props = {
16
16
  unpinTooltip: ChartInnerState['unpinTooltip'];
17
17
  xAxis: PreparedAxis;
18
18
  yAxis: PreparedAxis[];
19
+ tooltipThrottle: number;
19
20
  };
20
21
  export declare function useChartInnerHandlers(props: Props): {
21
22
  handleChartClick: (event: React.MouseEvent<SVGSVGElement>) => void;
@@ -4,9 +4,8 @@ import throttle from 'lodash/throttle';
4
4
  import { IS_TOUCH_ENABLED } from '../../constants';
5
5
  import { EventType } from '../../utils';
6
6
  import { getClosestPoints } from '../../utils/chart/get-closest-data';
7
- const THROTTLE_DELAY = 50;
8
7
  export function useChartInnerHandlers(props) {
9
- const { boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, dispatcher, shapesData, svgContainer, togglePinTooltip, tooltipPinned, unpinTooltip, xAxis, yAxis, } = props;
8
+ const { boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, dispatcher, shapesData, svgContainer, togglePinTooltip, tooltipPinned, unpinTooltip, xAxis, yAxis, tooltipThrottle, } = props;
10
9
  const isOutsideBounds = React.useCallback((x, y) => {
11
10
  return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
12
11
  }, [boundsHeight, boundsWidth]);
@@ -24,6 +23,8 @@ export function useChartInnerHandlers(props) {
24
23
  const closest = getClosestPoints({
25
24
  position: [x, y],
26
25
  shapesData,
26
+ boundsHeight,
27
+ boundsWidth,
27
28
  });
28
29
  dispatcher.call(EventType.HOVER_SHAPE, event.target, closest, [pointerX, pointerY]);
29
30
  dispatcher.call(EventType.POINTERMOVE_CHART, {}, {
@@ -38,7 +39,7 @@ export function useChartInnerHandlers(props) {
38
39
  };
39
40
  const throttledHandleMouseMove = IS_TOUCH_ENABLED
40
41
  ? undefined
41
- : throttle(handleMouseMove, THROTTLE_DELAY);
42
+ : throttle(handleMouseMove, tooltipThrottle);
42
43
  const handleMouseLeave = (event) => {
43
44
  if (tooltipPinned) {
44
45
  return;
@@ -53,7 +54,7 @@ export function useChartInnerHandlers(props) {
53
54
  handleMove([pointerX, pointerY], event);
54
55
  };
55
56
  const throttledHandleTouchMove = IS_TOUCH_ENABLED
56
- ? throttle(handleTouchMove, THROTTLE_DELAY)
57
+ ? throttle(handleTouchMove, tooltipThrottle)
57
58
  : undefined;
58
59
  const handleChartClick = (event) => {
59
60
  const [pointerX, pointerY] = pointer(event, svgContainer);
@@ -65,6 +66,8 @@ export function useChartInnerHandlers(props) {
65
66
  const items = getClosestPoints({
66
67
  position: [x, y],
67
68
  shapesData,
69
+ boundsHeight,
70
+ boundsWidth,
68
71
  });
69
72
  const selected = items === null || items === void 0 ? void 0 : items.find((item) => item.closest);
70
73
  if (!selected) {
@@ -29,11 +29,12 @@ export declare function useChartInnerProps(props: Props): {
29
29
  prevWidth: number | undefined;
30
30
  shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
31
31
  shapesData: import("../../hooks").ShapeData[];
32
- title: (import("../../types").ChartTitle & {
32
+ title: (import("../..").ChartTitle & {
33
33
  height: number;
34
34
  }) | undefined;
35
- tooltip: import("../../types").ChartTooltip<any> & {
35
+ tooltip: import("../..").ChartTooltip<any> & {
36
36
  enabled: boolean;
37
+ throttle: number;
37
38
  };
38
39
  xAxis: import("../../hooks").PreparedAxis;
39
40
  xScale: import("../../hooks").ChartScale | undefined;
@@ -1,12 +1,11 @@
1
1
  import React from 'react';
2
2
  import { line as lineGenerator, scaleLinear, select, symbol } from 'd3';
3
3
  import { CONTINUOUS_LEGEND_SIZE } from '../../constants';
4
- import { getLineDashArray } from '../../hooks/useShapes/utils';
5
4
  import { formatNumber } from '../../libs';
6
- import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getSymbol, } from '../../utils';
5
+ import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getLineDashArray, getSymbol, } from '../../utils';
7
6
  import { axisBottom } from '../../utils/chart/axis-generators';
8
7
  import './styles.css';
9
- const b = block('d3-legend');
8
+ const b = block('legend');
10
9
  const getLegendPosition = (args) => {
11
10
  const { align, offsetWidth = 0, width, contentWidth } = args;
12
11
  const top = 0;
@@ -1,47 +1,47 @@
1
- .gcharts-d3-legend {
1
+ .gcharts-legend {
2
2
  color: var(--g-color-text-secondary);
3
3
  }
4
- .gcharts-d3-legend__title {
4
+ .gcharts-legend__title {
5
5
  fill: var(--g-color-text-secondary);
6
6
  }
7
- .gcharts-d3-legend__item {
7
+ .gcharts-legend__item {
8
8
  cursor: pointer;
9
9
  user-select: none;
10
10
  }
11
- .gcharts-d3-legend__item-symbol_shape_rect.gcharts-d3-legend__item-symbol_unselected {
11
+ .gcharts-legend__item-symbol_shape_rect.gcharts-legend__item-symbol_unselected {
12
12
  fill: var(--g-color-text-hint);
13
13
  }
14
- .gcharts-d3-legend__item-symbol_shape_path.gcharts-d3-legend__item-symbol_unselected {
14
+ .gcharts-legend__item-symbol_shape_path.gcharts-legend__item-symbol_unselected {
15
15
  stroke: var(--g-color-text-hint);
16
16
  }
17
- .gcharts-d3-legend__item-symbol_shape_symbol.gcharts-d3-legend__item-symbol_unselected {
17
+ .gcharts-legend__item-symbol_shape_symbol.gcharts-legend__item-symbol_unselected {
18
18
  fill: var(--g-color-text-hint);
19
19
  }
20
- .gcharts-d3-legend__item-text {
20
+ .gcharts-legend__item-text {
21
21
  fill: var(--g-color-text-secondary);
22
22
  alignment-baseline: before-edge;
23
23
  }
24
- .gcharts-d3-legend__item-text_unselected {
24
+ .gcharts-legend__item-text_unselected {
25
25
  fill: var(--g-color-text-hint);
26
26
  }
27
- .gcharts-d3-legend__item-text:hover {
27
+ .gcharts-legend__item-text:hover {
28
28
  fill: var(--g-color-text-complementary);
29
29
  }
30
- .gcharts-d3-legend__pagination {
30
+ .gcharts-legend__pagination {
31
31
  user-select: none;
32
32
  fill: var(--g-color-text-primary);
33
33
  }
34
- .gcharts-d3-legend__pagination-counter, .gcharts-d3-legend__pagination-arrow {
34
+ .gcharts-legend__pagination-counter, .gcharts-legend__pagination-arrow {
35
35
  alignment-baseline: middle;
36
36
  }
37
- .gcharts-d3-legend__pagination-arrow {
37
+ .gcharts-legend__pagination-arrow {
38
38
  cursor: pointer;
39
39
  fill: var(--g-color-text-brand);
40
40
  }
41
- .gcharts-d3-legend__pagination-arrow_inactive {
41
+ .gcharts-legend__pagination-arrow_inactive {
42
42
  cursor: inherit;
43
43
  fill: var(--g-color-base-generic-accent-disabled);
44
44
  }
45
- .gcharts-d3-legend__pagination-arrow:hover:not(.gcharts-d3-legend__pagination-arrow_inactive) {
45
+ .gcharts-legend__pagination-arrow:hover:not(.gcharts-legend__pagination-arrow_inactive) {
46
46
  fill: var(--g-color-base-brand-hover);
47
47
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { block } from '../../utils';
3
3
  import './styles.css';
4
- const b = block('d3-plot-title');
4
+ const b = block('plot-title');
5
5
  export const PlotTitle = (props) => {
6
6
  const { title } = props;
7
7
  if (!title) {
@@ -1,4 +1,4 @@
1
- .chartkit-d3-plot-title {
1
+ .gcharts-plot-title {
2
2
  font-size: var(--g-text-subheader-3-font-size);
3
3
  font-weight: var(--g-text-subheader-font-weight);
4
4
  fill: var(--g-color-text-secondary);
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { block } from '../../utils';
3
3
  import './styles.css';
4
- const b = block('d3-title');
4
+ const b = block('title');
5
5
  export const Title = (props) => {
6
6
  const { chartWidth, text, height, style } = props;
7
7
  return (React.createElement("text", { className: b(), dx: chartWidth / 2, dy: height / 2, dominantBaseline: "middle", textAnchor: "middle", style: Object.assign({ lineHeight: `${height}px` }, style) },
@@ -1,4 +1,4 @@
1
- .gcharts-d3-title {
1
+ .gcharts-title {
2
2
  font-size: var(--g-text-subheader-2-font-size);
3
3
  font-weight: var(--g-text-subheader-font-weight);
4
4
  fill: var(--g-color-text-primary);
@@ -3,7 +3,7 @@ import { dateTime } from '@gravity-ui/date-utils';
3
3
  import get from 'lodash/get';
4
4
  import { formatNumber } from '../../libs';
5
5
  import { block, getDataCategoryValue, getWaterfallPointSubtotal } from '../../utils';
6
- const b = block('d3-tooltip');
6
+ const b = block('tooltip');
7
7
  const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
8
8
  const getRowData = (fieldName, data, axis) => {
9
9
  switch (axis === null || axis === void 0 ? void 0 : axis.type) {
@@ -29,7 +29,7 @@ const getXRowData = (data, xAxis) => getRowData('x', data, xAxis);
29
29
  const getYRowData = (data, yAxis) => getRowData('y', data, yAxis);
30
30
  const getMeasureValue = (data, xAxis, yAxis) => {
31
31
  var _a, _b;
32
- if (data.every((item) => ['pie', 'treemap', 'waterfall'].includes(item.series.type))) {
32
+ if (data.every((item) => ['pie', 'treemap', 'waterfall', 'sankey'].includes(item.series.type))) {
33
33
  return null;
34
34
  }
35
35
  if (data.some((item) => item.series.type === 'bar-y')) {
@@ -41,7 +41,9 @@ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
41
41
  const measureValue = getMeasureValue(hovered, xAxis, yAxis);
42
42
  return (React.createElement(React.Fragment, null,
43
43
  measureValue && React.createElement("div", null, measureValue),
44
- hovered.map(({ data, series, closest }, i) => {
44
+ hovered.map((seriesItem, i) => {
45
+ var _a;
46
+ const { data, series, closest } = seriesItem;
45
47
  const id = `${get(series, 'id')}_${i}`;
46
48
  const color = get(series, 'color');
47
49
  switch (series.type) {
@@ -93,6 +95,20 @@ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
93
95
  "\u00A0"),
94
96
  React.createElement("span", null, seriesData.value)));
95
97
  }
98
+ case 'sankey': {
99
+ const { target, data: source } = seriesItem;
100
+ const value = (_a = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _a === void 0 ? void 0 : _a.value;
101
+ return (React.createElement("div", { key: id, className: b('content-row') },
102
+ React.createElement("div", { className: b('color'), style: { backgroundColor: source.color } }),
103
+ React.createElement("div", { style: { display: 'flex', gap: 8, verticalAlign: 'center' } },
104
+ source.name,
105
+ " ",
106
+ React.createElement("span", null, "\u2192"),
107
+ " ", target === null || target === void 0 ? void 0 :
108
+ target.name,
109
+ ": ",
110
+ value)));
111
+ }
96
112
  default: {
97
113
  return null;
98
114
  }
@@ -9,6 +9,7 @@ export declare const SeriesType: {
9
9
  readonly Scatter: "scatter";
10
10
  readonly Treemap: "treemap";
11
11
  readonly Waterfall: "waterfall";
12
+ readonly Sankey: "sankey";
12
13
  };
13
14
  export declare enum DashStyle {
14
15
  Dash = "Dash",
@@ -9,6 +9,7 @@ export const SeriesType = {
9
9
  Scatter: 'scatter',
10
10
  Treemap: 'treemap',
11
11
  Waterfall: 'waterfall',
12
+ Sankey: 'sankey',
12
13
  };
13
14
  export var DashStyle;
14
15
  (function (DashStyle) {
@@ -1,5 +1,6 @@
1
1
  import get from 'lodash/get';
2
2
  export const getPreparedTooltip = (args) => {
3
+ var _a;
3
4
  const { tooltip } = args;
4
- return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true) });
5
+ return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0 });
5
6
  };
@@ -1,4 +1,5 @@
1
- import type { BaseTextStyle, ChartAxis, ChartAxisLabels, ChartAxisTitleAlignment, ChartAxisType, ChartData, ChartMargin } from '../../types';
1
+ import type { DashStyle } from 'src/constants';
2
+ import type { AxisPlotLine, BaseTextStyle, ChartAxis, ChartAxisLabels, ChartAxisTitleAlignment, ChartAxisType, ChartData, ChartMargin } from '../../types';
2
3
  type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style' | 'autoRotation'> & Required<Pick<ChartAxisLabels, 'enabled' | 'padding' | 'margin' | 'rotation'>> & {
3
4
  style: BaseTextStyle;
4
5
  rotation: number;
@@ -10,7 +11,15 @@ type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style'
10
11
  export type PreparedChart = {
11
12
  margin: ChartMargin;
12
13
  };
13
- export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels'> & {
14
+ export type PreparedAxisPlotLine = {
15
+ value: number;
16
+ color: string;
17
+ width: number;
18
+ dashStyle: DashStyle;
19
+ opacity: number;
20
+ layerPlacement: AxisPlotLine['layerPlacement'];
21
+ };
22
+ export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels' | 'plotLines'> & {
14
23
  type: ChartAxisType;
15
24
  labels: PreparedAxisLabels;
16
25
  title: {
@@ -32,12 +41,14 @@ export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels'> & {
32
41
  };
33
42
  position: 'left' | 'right' | 'top' | 'bottom';
34
43
  plotIndex: number;
44
+ plotLines: PreparedAxisPlotLine[];
35
45
  };
36
46
  export type PreparedTitle = ChartData['title'] & {
37
47
  height: number;
38
48
  };
39
49
  export type PreparedTooltip = ChartData['tooltip'] & {
40
50
  enabled: boolean;
51
+ throttle: number;
41
52
  };
42
53
  export type ChartOptions = {
43
54
  chart: PreparedChart;
@@ -1,5 +1,5 @@
1
1
  import get from 'lodash/get';
2
- import { DEFAULT_AXIS_LABEL_FONT_SIZE, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
2
+ import { DEFAULT_AXIS_LABEL_FONT_SIZE, DashStyle, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
3
3
  import { CHART_SERIES_WITH_VOLUME_ON_X_AXIS, calculateCos, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, getXAxisItems, hasOverlappingLabels, wrapText, } from '../../utils';
4
4
  import { createXScale } from '../useAxisScales';
5
5
  function getLabelSettings({ axis, series, width, autoRotation = true, }) {
@@ -102,6 +102,14 @@ export const getPreparedXAxis = ({ xAxis, series, width, }) => {
102
102
  },
103
103
  position: 'bottom',
104
104
  plotIndex: 0,
105
+ plotLines: get(xAxis, 'plotLines', []).map((d) => ({
106
+ value: get(d, 'value', 0),
107
+ color: get(d, 'color', 'var(--g-color-base-brand)'),
108
+ width: get(d, 'width', 1),
109
+ dashStyle: get(d, 'dashStyle', DashStyle.Solid),
110
+ opacity: get(d, 'opacity', 1),
111
+ layerPlacement: get(d, 'layerPlacement', 'before'),
112
+ })),
105
113
  };
106
114
  const { height, rotation } = getLabelSettings({
107
115
  axis: preparedXAxis,