@gravity-ui/charts 1.11.4 → 1.13.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 (135) hide show
  1. package/dist/cjs/components/Axis/AxisX.js +62 -36
  2. package/dist/cjs/components/Axis/AxisY.js +67 -31
  3. package/dist/cjs/components/ChartInner/styles.css +1 -0
  4. package/dist/cjs/components/ChartInner/useChartInnerProps.js +15 -9
  5. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  6. package/dist/cjs/components/Tooltip/ChartTooltipContent.js +3 -3
  7. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  8. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  9. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  10. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  11. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  12. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  13. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  14. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  15. package/dist/cjs/components/Tooltip/index.js +1 -1
  16. package/dist/cjs/components/Tooltip/styles.css +14 -2
  17. package/dist/cjs/components/Tooltip/utils.d.ts +30 -0
  18. package/dist/cjs/components/Tooltip/utils.js +126 -0
  19. package/dist/cjs/constants/axis.d.ts +6 -0
  20. package/dist/cjs/constants/axis.js +6 -0
  21. package/dist/cjs/constants/index.d.ts +6 -4
  22. package/dist/cjs/constants/index.js +6 -4
  23. package/dist/cjs/constants/tooltip.d.ts +3 -0
  24. package/dist/cjs/constants/tooltip.js +3 -0
  25. package/dist/cjs/hooks/useAxisScales/index.d.ts +14 -3
  26. package/dist/cjs/hooks/useAxisScales/index.js +86 -22
  27. package/dist/cjs/hooks/useChartOptions/types.d.ts +5 -0
  28. package/dist/cjs/hooks/useChartOptions/utils.d.ts +11 -0
  29. package/dist/cjs/hooks/useChartOptions/utils.js +27 -0
  30. package/dist/cjs/hooks/useChartOptions/x-axis.js +6 -2
  31. package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +4 -2
  32. package/dist/cjs/hooks/useChartOptions/y-axis.js +14 -4
  33. package/dist/cjs/hooks/useSeries/prepare-area.d.ts +1 -1
  34. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +3 -0
  35. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +5 -2
  36. package/dist/cjs/hooks/useSeries/prepare-line.d.ts +1 -1
  37. package/dist/cjs/hooks/useSeries/prepare-radar.d.ts +1 -1
  38. package/dist/cjs/hooks/useSeries/types.d.ts +3 -0
  39. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +16 -13
  40. package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +2 -2
  41. package/dist/cjs/hooks/useShapes/bar-y/index.js +5 -9
  42. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.d.ts +2 -2
  43. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +80 -107
  44. package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +7 -2
  45. package/dist/cjs/hooks/useShapes/index.js +1 -1
  46. package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +1 -1
  47. package/dist/cjs/hooks/utils/bar-y.d.ts +27 -0
  48. package/dist/cjs/hooks/utils/bar-y.js +55 -0
  49. package/dist/cjs/hooks/utils/index.d.ts +1 -0
  50. package/dist/cjs/hooks/utils/index.js +1 -0
  51. package/dist/cjs/i18n/keysets/en.json +7 -1
  52. package/dist/cjs/i18n/keysets/ru.json +7 -1
  53. package/dist/cjs/types/chart/axis.d.ts +15 -3
  54. package/dist/cjs/types/chart/bar-y.d.ts +10 -0
  55. package/dist/cjs/types/chart/series.d.ts +10 -0
  56. package/dist/cjs/types/chart/tooltip.d.ts +21 -0
  57. package/dist/cjs/utils/chart/axis-generators/bottom.js +26 -13
  58. package/dist/cjs/utils/chart/get-closest-data.js +13 -12
  59. package/dist/cjs/utils/chart/index.js +1 -1
  60. package/dist/cjs/utils/chart/series/sorting.d.ts +6 -2
  61. package/dist/cjs/utils/chart/series/sorting.js +29 -4
  62. package/dist/cjs/utils/chart/zoom.js +2 -1
  63. package/dist/cjs/validation/index.js +55 -1
  64. package/dist/esm/components/Axis/AxisX.js +62 -36
  65. package/dist/esm/components/Axis/AxisY.js +67 -31
  66. package/dist/esm/components/ChartInner/styles.css +1 -0
  67. package/dist/esm/components/ChartInner/useChartInnerProps.js +15 -9
  68. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  69. package/dist/esm/components/Tooltip/ChartTooltipContent.js +3 -3
  70. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  71. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  72. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  73. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  74. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  75. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  76. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  77. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  78. package/dist/esm/components/Tooltip/index.js +1 -1
  79. package/dist/esm/components/Tooltip/styles.css +14 -2
  80. package/dist/esm/components/Tooltip/utils.d.ts +30 -0
  81. package/dist/esm/components/Tooltip/utils.js +126 -0
  82. package/dist/esm/constants/axis.d.ts +6 -0
  83. package/dist/esm/constants/axis.js +6 -0
  84. package/dist/esm/constants/index.d.ts +6 -4
  85. package/dist/esm/constants/index.js +6 -4
  86. package/dist/esm/constants/tooltip.d.ts +3 -0
  87. package/dist/esm/constants/tooltip.js +3 -0
  88. package/dist/esm/hooks/useAxisScales/index.d.ts +14 -3
  89. package/dist/esm/hooks/useAxisScales/index.js +86 -22
  90. package/dist/esm/hooks/useChartOptions/types.d.ts +5 -0
  91. package/dist/esm/hooks/useChartOptions/utils.d.ts +11 -0
  92. package/dist/esm/hooks/useChartOptions/utils.js +27 -0
  93. package/dist/esm/hooks/useChartOptions/x-axis.js +6 -2
  94. package/dist/esm/hooks/useChartOptions/y-axis.d.ts +4 -2
  95. package/dist/esm/hooks/useChartOptions/y-axis.js +14 -4
  96. package/dist/esm/hooks/useSeries/prepare-area.d.ts +1 -1
  97. package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +3 -0
  98. package/dist/esm/hooks/useSeries/prepare-bar-y.js +5 -2
  99. package/dist/esm/hooks/useSeries/prepare-line.d.ts +1 -1
  100. package/dist/esm/hooks/useSeries/prepare-radar.d.ts +1 -1
  101. package/dist/esm/hooks/useSeries/types.d.ts +3 -0
  102. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +16 -13
  103. package/dist/esm/hooks/useShapes/bar-y/index.d.ts +2 -2
  104. package/dist/esm/hooks/useShapes/bar-y/index.js +5 -9
  105. package/dist/esm/hooks/useShapes/bar-y/prepare-data.d.ts +2 -2
  106. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +80 -107
  107. package/dist/esm/hooks/useShapes/bar-y/types.d.ts +7 -2
  108. package/dist/esm/hooks/useShapes/index.js +1 -1
  109. package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +1 -1
  110. package/dist/esm/hooks/utils/bar-y.d.ts +27 -0
  111. package/dist/esm/hooks/utils/bar-y.js +55 -0
  112. package/dist/esm/hooks/utils/index.d.ts +1 -0
  113. package/dist/esm/hooks/utils/index.js +1 -0
  114. package/dist/esm/i18n/keysets/en.json +7 -1
  115. package/dist/esm/i18n/keysets/ru.json +7 -1
  116. package/dist/esm/types/chart/axis.d.ts +15 -3
  117. package/dist/esm/types/chart/bar-y.d.ts +10 -0
  118. package/dist/esm/types/chart/series.d.ts +10 -0
  119. package/dist/esm/types/chart/tooltip.d.ts +21 -0
  120. package/dist/esm/utils/chart/axis-generators/bottom.js +26 -13
  121. package/dist/esm/utils/chart/get-closest-data.js +13 -12
  122. package/dist/esm/utils/chart/index.js +1 -1
  123. package/dist/esm/utils/chart/series/sorting.d.ts +6 -2
  124. package/dist/esm/utils/chart/series/sorting.js +29 -4
  125. package/dist/esm/utils/chart/zoom.js +2 -1
  126. package/dist/esm/validation/index.js +55 -1
  127. package/package.json +1 -1
  128. package/dist/cjs/components/Tooltip/DefaultContent.d.ts +0 -10
  129. package/dist/cjs/components/Tooltip/DefaultContent.js +0 -187
  130. package/dist/esm/components/Tooltip/DefaultContent.d.ts +0 -10
  131. package/dist/esm/components/Tooltip/DefaultContent.js +0 -187
  132. /package/dist/cjs/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  133. /package/dist/cjs/hooks/{useShapes/constants.js → constants.js} +0 -0
  134. /package/dist/esm/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  135. /package/dist/esm/hooks/{useShapes/constants.js → constants.js} +0 -0
@@ -2,7 +2,7 @@ import get from 'lodash/get';
2
2
  import sortBy from 'lodash/sortBy';
3
3
  import { getLabelsSize } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../../constants';
6
6
  import { getXValue, getYValue } from '../utils';
7
7
  async function getLabelData(d, plotHeight) {
8
8
  var _a, _b;
@@ -0,0 +1,27 @@
1
+ import type { BarYSeries, BarYSeriesData } from '../../types';
2
+ import type { ChartScale } from '../useAxisScales';
3
+ import type { PreparedAxis } from '../useChartOptions/types';
4
+ import type { PreparedBarYSeries, PreparedSeriesOptions } from '../useSeries/types';
5
+ export declare function groupBarYDataByYValue<T extends BarYSeries | PreparedBarYSeries>(series: T[], yAxis: PreparedAxis[]): Record<string | number, Record<string, {
6
+ data: BarYSeriesData;
7
+ series: T;
8
+ }[]>>;
9
+ export declare function getBarYLayoutForNumericScale(args: {
10
+ plotHeight: number;
11
+ seriesOptions: PreparedSeriesOptions;
12
+ groupedData: ReturnType<typeof groupBarYDataByYValue>;
13
+ }): {
14
+ bandSize: number;
15
+ barGap: number;
16
+ barSize: number;
17
+ dataLength: number;
18
+ };
19
+ export declare function getBarYLayoutForCategoryScale(args: {
20
+ groupedData: ReturnType<typeof groupBarYDataByYValue>;
21
+ seriesOptions: PreparedSeriesOptions;
22
+ yScale: ChartScale;
23
+ }): {
24
+ bandSize: number;
25
+ barGap: number;
26
+ barSize: number;
27
+ };
@@ -0,0 +1,55 @@
1
+ import { max } from 'd3';
2
+ import get from 'lodash/get';
3
+ import { getDataCategoryValue } from '../../utils';
4
+ import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { getSeriesStackId } from '../useSeries/utils';
6
+ export function groupBarYDataByYValue(series, yAxis) {
7
+ const data = {};
8
+ series.forEach((s) => {
9
+ s.data.forEach((d) => {
10
+ const axisIndex = get(s, 'yAxis', 0);
11
+ const seriesYAxis = yAxis[axisIndex];
12
+ const categories = get(seriesYAxis, 'categories', []);
13
+ const key = seriesYAxis.type === 'category'
14
+ ? getDataCategoryValue({ axisDirection: 'y', categories, data: d })
15
+ : d.y;
16
+ if (key) {
17
+ if (!data[key]) {
18
+ data[key] = {};
19
+ }
20
+ const stackId = getSeriesStackId(s);
21
+ if (!data[key][stackId]) {
22
+ data[key][stackId] = [];
23
+ }
24
+ data[key][stackId].push({ data: d, series: s });
25
+ }
26
+ });
27
+ });
28
+ return data;
29
+ }
30
+ export function getBarYLayoutForNumericScale(args) {
31
+ const { plotHeight, groupedData, seriesOptions } = args;
32
+ const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
33
+ const barPadding = get(seriesOptions, 'bar-y.barPadding');
34
+ const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
35
+ const dataLength = Object.values(groupedData).reduce((sum, items) => sum + Object.keys(items).length, 0);
36
+ const bandSize = plotHeight / dataLength;
37
+ const groupGap = Math.max(bandSize * groupPadding, MIN_BAR_GROUP_GAP);
38
+ const groupSize = bandSize - groupGap;
39
+ const barGap = Math.max(bandSize * barPadding, MIN_BAR_GAP);
40
+ const barSize = Math.max(MIN_BAR_WIDTH, Math.min(groupSize - barGap, barMaxWidth));
41
+ return { bandSize, barGap, barSize, dataLength };
42
+ }
43
+ export function getBarYLayoutForCategoryScale(args) {
44
+ const { groupedData, seriesOptions, yScale } = args;
45
+ const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
46
+ const barPadding = get(seriesOptions, 'bar-y.barPadding');
47
+ const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
48
+ const bandSize = yScale.bandwidth();
49
+ const maxGroupSize = max(Object.values(groupedData), (d) => Object.values(d).length) || 1;
50
+ const groupGap = Math.max(bandSize * groupPadding, MIN_BAR_GROUP_GAP);
51
+ const groupSize = bandSize - groupGap;
52
+ const barGap = Math.max(bandSize * barPadding, MIN_BAR_GAP);
53
+ const barSize = Math.max(MIN_BAR_WIDTH, Math.min(groupSize / maxGroupSize - barGap, barMaxWidth));
54
+ return { bandSize, barGap, barSize };
55
+ }
@@ -0,0 +1 @@
1
+ export * from './bar-y';
@@ -0,0 +1 @@
1
+ export * from './bar-y';
@@ -13,6 +13,12 @@
13
13
  "label_invalid-treemap-missing-value": "It seems you are trying to use node without \"value\". Check node with this properties: { id: \"{{id}}\", name: \"{{name}}\" }",
14
14
  "label_invalid-y-axis-index": "It seems you are trying to use inappropriate index for Y axis: \"{{index}}\"",
15
15
  "label_invalid-axis-plot-band-option": "It seems you are trying to use inappropriate type for \"{{axis}}\" axis plot band option: \"{{option}}\"",
16
- "label_axis-plot-band-options-not-equal": "It seems you are trying to use different type for \"{{axis}}\" axis plot band options"
16
+ "label_axis-plot-band-options-not-equal": "It seems you are trying to use different type for \"{{axis}}\" axis plot band options",
17
+ "label_invalid-tooltip-totals-aggregation-type": "It seems you are trying to use inappropriate data type for \"tooltip.totals.aggregation\". Available types: string, function.",
18
+ "label_invalid-tooltip-totals-aggregation-type-str": "It seems you are trying to use inappropriate value for built-in \"tooltip.totals.aggregation\". Available values: [{{values}}].",
19
+ "label_invalid-axis-type": "It seems you are trying to use inappropriate type for \"{{key}}\" axis. Available types: [{{values}}]."
20
+ },
21
+ "tooltip": {
22
+ "label_totals_sum": "Sum"
17
23
  }
18
24
  }
@@ -13,6 +13,12 @@
13
13
  "label_invalid-treemap-missing-value": "Похоже, что вы пытаетесь использовать узел без значения \"value\". Проверьте узел с этими свойствами: { id: \"{{id}}\", name: \"{{name}}\" }",
14
14
  "label_invalid-y-axis-index": "Похоже, что вы пытаетесь использовать некорректный индекс для оси Y: \"{{index}}\"",
15
15
  "label_invalid-axis-plot-band-option": "Похоже, что вы пытаетесь использовать некорректный тип для параметра полосы: \"{{option}}\" для оси \"{{axis}}\"",
16
- "label_axis-plot-band-options-not-equal": "Похоже, что вы пытаетесь использовать разные типы для для параметра полосы для оси \"{{axis}}\""
16
+ "label_axis-plot-band-options-not-equal": "Похоже, что вы пытаетесь использовать разные типы для для параметра полосы для оси \"{{axis}}\"",
17
+ "label_invalid-tooltip-totals-aggregation-type": "Похоже, что вы пытаетесь использовать некорректный тип данных для \"tooltip.totals.aggregation\". Доступные типы: string, function.",
18
+ "label_invalid-tooltip-totals-aggregation-type-str": "Похоже, что вы пытаетесь использовать некорректное значение для встроенной агрегации \"tooltip.totals.aggregation\". Доступные значения: [{{values}}].",
19
+ "label_invalid-axis-type": "Похоже, что вы пытаетесь использовать некорректный тип для оси \"{{key}}\". Доступные типы: [{{values}}]."
20
+ },
21
+ "tooltip": {
22
+ "label_totals_sum": "Сумма"
17
23
  }
18
24
  }
@@ -1,7 +1,7 @@
1
- import type { DashStyle } from '../../constants';
1
+ import type { AXIS_TYPE, DashStyle } from '../../constants';
2
2
  import type { FormatNumberOptions } from '../formatter';
3
3
  import type { BaseTextStyle } from './base';
4
- export type ChartAxisType = 'category' | 'datetime' | 'linear' | 'logarithmic';
4
+ export type ChartAxisType = (typeof AXIS_TYPE)[keyof typeof AXIS_TYPE];
5
5
  export type ChartAxisTitleAlignment = 'left' | 'center' | 'right';
6
6
  export interface ChartAxisLabels {
7
7
  /** Enable or disable the axis labels. */
@@ -78,6 +78,10 @@ export interface ChartAxis {
78
78
  plotBands?: AxisPlotBand[];
79
79
  /** Whether axis, including axis title, line, ticks and labels, should be visible. */
80
80
  visible?: boolean;
81
+ /** Setting the order of the axis values. It is not applied by default.
82
+ * the "reverse" value is needed to use the reverse order without sorting
83
+ */
84
+ order?: 'sortAsc' | 'sortDesc' | 'reverse';
81
85
  }
82
86
  export interface ChartXAxis extends ChartAxis {
83
87
  }
@@ -92,6 +96,14 @@ export interface AxisPlot {
92
96
  * @default 1
93
97
  * */
94
98
  opacity?: number;
99
+ label?: {
100
+ text: string;
101
+ style?: Partial<BaseTextStyle>;
102
+ /** The pixel padding for label.
103
+ * @default 5
104
+ */
105
+ padding?: number;
106
+ };
95
107
  }
96
108
  export interface AxisPlotLine extends AxisPlot {
97
109
  /** The position of the line in axis units. */
@@ -121,7 +133,7 @@ export interface AxisPlotBand extends AxisPlot {
121
133
  */
122
134
  to: number | string;
123
135
  }
124
- export interface AxisCrosshair extends Omit<AxisPlotLine, 'value'> {
136
+ export interface AxisCrosshair extends Omit<AxisPlotLine, 'value' | 'label'> {
125
137
  /** Whether the crosshair should snap to the point or follow the pointer independent of points.
126
138
  * @default true
127
139
  */
@@ -29,6 +29,16 @@ export interface BarYSeries<T = MeaningfulAny> extends BaseSeries {
29
29
  name: string;
30
30
  /** The main color of the series (hex, rgba) */
31
31
  color?: string;
32
+ /**
33
+ * The width of the border surrounding each bar.
34
+ *
35
+ * @default 0
36
+ */
37
+ borderWidth?: number;
38
+ /**
39
+ * The color of the border surrounding each bar.
40
+ */
41
+ borderColor?: string;
32
42
  /**
33
43
  * The corner radius of the border surrounding each bar.
34
44
  * @default 0
@@ -115,6 +115,16 @@ export interface ChartSeriesOptions {
115
115
  * @default 0.2
116
116
  */
117
117
  groupPadding?: number;
118
+ /**
119
+ * The width of the border surrounding each bar.
120
+ *
121
+ * @default 0
122
+ */
123
+ borderWidth?: number;
124
+ /**
125
+ * The color of the border surrounding each bar.
126
+ */
127
+ borderColor?: string;
118
128
  /**
119
129
  * The corner radius of the border surrounding each bar.
120
130
  * @default 0
@@ -1,3 +1,4 @@
1
+ import type { TOOLTIP_TOTALS_BUILT_IN_AGGREGATION } from '../../constants';
1
2
  import type { MeaningfulAny } from '../misc';
2
3
  import type { AreaSeries, AreaSeriesData } from './area';
3
4
  import type { ChartXAxis, ChartYAxis } from './axis';
@@ -79,6 +80,10 @@ export interface ChartTooltipRendererArgs<T = MeaningfulAny> {
79
80
  xAxis?: ChartXAxis | null;
80
81
  yAxis?: ChartYAxis;
81
82
  }
83
+ export interface ChartTooltipTotalsAggregationArgs<T = MeaningfulAny> extends ChartTooltipRendererArgs<T> {
84
+ }
85
+ export type ChartTooltipTotalsBuiltInAggregation = (typeof TOOLTIP_TOTALS_BUILT_IN_AGGREGATION)[keyof typeof TOOLTIP_TOTALS_BUILT_IN_AGGREGATION];
86
+ export type ChartTooltipTotalsAggregationValue = number | string | undefined;
82
87
  export interface ChartTooltip<T = MeaningfulAny> {
83
88
  enabled?: boolean;
84
89
  /** Specifies the renderer for the tooltip. If returned null default tooltip renderer will be used. */
@@ -91,4 +96,20 @@ export interface ChartTooltip<T = MeaningfulAny> {
91
96
  throttle?: number;
92
97
  /** Formatting settings for tooltip value. */
93
98
  valueFormat?: ValueFormat;
99
+ /** Settings for totals block in tooltip */
100
+ totals?: {
101
+ /**
102
+ * The aggregation method for calculating totals.
103
+ * It can be a built-in function (e.g., 'sum') or a custom function.
104
+ * @default 'sum'
105
+ */
106
+ aggregation?: ChartTooltipTotalsBuiltInAggregation | ((args: ChartTooltipTotalsAggregationArgs) => ChartTooltipTotalsAggregationValue);
107
+ /**
108
+ * Enables/disables the display of totals
109
+ * @default false
110
+ */
111
+ enabled?: boolean;
112
+ /** The label text for the totals. For built-in aggregations, the label can be omitted. */
113
+ label?: string;
114
+ };
94
115
  }
@@ -93,18 +93,31 @@ export async function axisBottom(args) {
93
93
  let elementX = 0;
94
94
  // add an ellipsis to the labels that go beyond the boundaries of the chart
95
95
  // and remove overlapping labels
96
- labels.each(function (_d, i, nodes) {
97
- var _a, _b;
98
- const currentElement = this;
99
- const currentElementPosition = currentElement.getBoundingClientRect();
96
+ labels
97
+ .nodes()
98
+ .map((element) => {
99
+ const r = element.getBoundingClientRect();
100
+ return {
101
+ left: r.left,
102
+ right: r.right,
103
+ node: element,
104
+ };
105
+ }, {})
106
+ .sort((a, b) => {
107
+ return a.left - b.left;
108
+ })
109
+ .forEach(function (item, i, nodes) {
110
+ var _a, _b, _c, _d;
111
+ const { node, left, right: currentElementPositionRigth } = item;
112
+ const currentElement = node;
100
113
  if (i === 0) {
101
114
  const text = select(currentElement);
102
- const nextElement = nodes[i + 1];
115
+ const nextElement = (_a = nodes[i + 1]) === null || _a === void 0 ? void 0 : _a.node;
103
116
  const nextElementPosition = nextElement === null || nextElement === void 0 ? void 0 : nextElement.getBoundingClientRect();
104
- if (currentElementPosition.left < leftmostLimit) {
105
- const rightmostPossiblePoint = (_a = nextElementPosition === null || nextElementPosition === void 0 ? void 0 : nextElementPosition.left) !== null && _a !== void 0 ? _a : right;
117
+ if (left < leftmostLimit) {
118
+ const rightmostPossiblePoint = (_b = nextElementPosition === null || nextElementPosition === void 0 ? void 0 : nextElementPosition.left) !== null && _b !== void 0 ? _b : right;
106
119
  const remainSpace = rightmostPossiblePoint -
107
- currentElementPosition.right +
120
+ currentElementPositionRigth +
108
121
  x -
109
122
  labelsMargin;
110
123
  text.attr('text-anchor', 'start');
@@ -112,16 +125,16 @@ export async function axisBottom(args) {
112
125
  }
113
126
  }
114
127
  else {
115
- if (currentElementPosition.left < elementX) {
116
- (_b = currentElement.closest('.tick')) === null || _b === void 0 ? void 0 : _b.remove();
128
+ if (left < elementX) {
129
+ (_c = currentElement.closest('.tick')) === null || _c === void 0 ? void 0 : _c.remove();
117
130
  return;
118
131
  }
119
- elementX = currentElementPosition.right + labelsPaddings;
132
+ elementX = currentElementPositionRigth + labelsPaddings;
120
133
  if (i === nodes.length - 1) {
121
- const prevElement = nodes[i - 1];
134
+ const prevElement = (_d = nodes[i - 1]) === null || _d === void 0 ? void 0 : _d.node;
122
135
  const text = select(currentElement);
123
136
  const prevElementPosition = prevElement === null || prevElement === void 0 ? void 0 : prevElement.getBoundingClientRect();
124
- const lackingSpace = Math.max(0, currentElementPosition.right - right);
137
+ const lackingSpace = Math.max(0, currentElementPositionRigth - right);
125
138
  if (lackingSpace) {
126
139
  const remainSpace = right - ((prevElementPosition === null || prevElementPosition === void 0 ? void 0 : prevElementPosition.right) || 0) - labelsPaddings;
127
140
  const translateX = -lackingSpace;
@@ -49,7 +49,7 @@ export function getClosestPoints(args) {
49
49
  const groups = groupBy(shapesData, getSeriesType);
50
50
  // eslint-disable-next-line complexity
51
51
  Object.entries(groups).forEach(([seriesType, list]) => {
52
- var _a, _b;
52
+ var _a, _b, _c;
53
53
  switch (seriesType) {
54
54
  case 'bar-x': {
55
55
  const points = list.map((d) => ({
@@ -106,26 +106,27 @@ export function getClosestPoints(args) {
106
106
  const points = list;
107
107
  const sorted = sort(points, (p) => p.y);
108
108
  const closestYIndex = bisector((p) => p.y).center(sorted, pointerY);
109
- let closestPoints = [];
110
- let closestXIndex = -1;
111
- if (closestYIndex !== -1) {
112
- const closestY = sorted[closestYIndex].y;
113
- closestPoints = sort(points.filter((p) => p.y === closestY), (p) => p.x);
109
+ const closestYPoint = sorted[closestYIndex];
110
+ let selectedPoints = [];
111
+ let closestPointXValue = -1;
112
+ if (closestYPoint) {
113
+ selectedPoints = points.filter((p) => p.data.y === closestYPoint.data.y);
114
+ const closestPoints = sort(selectedPoints.filter((p) => p.y === closestYPoint.y), (p) => p.x);
114
115
  const lastPoint = closestPoints[closestPoints.length - 1];
115
116
  if (pointerX < ((_a = closestPoints[0]) === null || _a === void 0 ? void 0 : _a.x)) {
116
- closestXIndex = 0;
117
+ closestPointXValue = closestPoints[0].x;
117
118
  }
118
119
  else if (lastPoint && pointerX > lastPoint.x + lastPoint.width) {
119
- closestXIndex = closestPoints.length - 1;
120
+ closestPointXValue = lastPoint.x;
120
121
  }
121
122
  else {
122
- closestXIndex = closestPoints.findIndex((p) => pointerX > p.x && pointerX < p.x + p.width);
123
+ closestPointXValue = (_b = closestPoints.find((p) => pointerX > p.x && pointerX < p.x + p.width)) === null || _b === void 0 ? void 0 : _b.x;
123
124
  }
124
125
  }
125
- result.push(...closestPoints.map((p, i) => ({
126
+ result.push(...selectedPoints.map((p) => ({
126
127
  data: p.data,
127
128
  series: p.series,
128
- closest: i === closestXIndex,
129
+ closest: p.x === closestPointXValue && p.y === closestYPoint.y,
129
130
  })));
130
131
  break;
131
132
  }
@@ -164,7 +165,7 @@ export function getClosestPoints(args) {
164
165
  }
165
166
  case 'treemap': {
166
167
  const data = list;
167
- const closestPoint = (_b = data[0]) === null || _b === void 0 ? void 0 : _b.leaves.find((l) => {
168
+ const closestPoint = (_c = data[0]) === null || _c === void 0 ? void 0 : _c.leaves.find((l) => {
168
169
  return (pointerX >= l.x0 && pointerX <= l.x1 && pointerY >= l.y0 && pointerY <= l.y1);
169
170
  });
170
171
  if (closestPoint) {
@@ -238,5 +238,5 @@ export function getClosestPointsRange(axis, points) {
238
238
  if (axis.type === 'category') {
239
239
  return undefined;
240
240
  }
241
- return points[1] - points[0];
241
+ return Math.abs(points[1] - points[0]);
242
242
  }
@@ -1,2 +1,6 @@
1
- import type { ChartSeries } from '../../../types';
2
- export declare function getSortedSeriesData(seriesData: ChartSeries[]): ChartSeries[];
1
+ import type { ChartAxis, ChartSeries } from '../../../types';
2
+ export declare function getSortedSeriesData({ seriesData, yAxes, xAxis, }: {
3
+ seriesData: ChartSeries[];
4
+ yAxes?: ChartAxis[];
5
+ xAxis?: ChartAxis;
6
+ }): ChartSeries[];
@@ -1,12 +1,37 @@
1
1
  import { sort } from 'd3';
2
+ import { isEmpty } from 'lodash';
3
+ import get from 'lodash/get';
2
4
  import { SeriesType } from '../../../constants';
3
- export function getSortedSeriesData(seriesData) {
5
+ import { getAxisCategories } from '../../../hooks/useChartOptions/utils';
6
+ function applyAxisCategoriesOrder({ series, axis, key, }) {
7
+ var _a, _b;
8
+ const originalCategories = (_a = axis === null || axis === void 0 ? void 0 : axis.categories) !== null && _a !== void 0 ? _a : [];
9
+ if (isEmpty(originalCategories)) {
10
+ return series;
11
+ }
12
+ const axisCategories = (_b = getAxisCategories(axis)) !== null && _b !== void 0 ? _b : [];
13
+ const order = Object.fromEntries(axisCategories.map((value, index) => [value, index]));
14
+ const newSeriesData = series.data.map((d) => {
15
+ const value = get(d, key);
16
+ if (typeof value === 'number') {
17
+ return Object.assign(Object.assign({}, d), { [key]: order[originalCategories[value]] });
18
+ }
19
+ return d;
20
+ });
21
+ return Object.assign(Object.assign({}, series), { data: newSeriesData });
22
+ }
23
+ export function getSortedSeriesData({ seriesData, yAxes, xAxis, }) {
4
24
  return seriesData.map((s) => {
5
- switch (s.type) {
25
+ const yAxis = yAxes === null || yAxes === void 0 ? void 0 : yAxes[0];
26
+ let sortedSeries = s;
27
+ sortedSeries = applyAxisCategoriesOrder({ series: sortedSeries, axis: yAxis, key: 'y' });
28
+ sortedSeries = applyAxisCategoriesOrder({ series: sortedSeries, axis: xAxis, key: 'x' });
29
+ switch (sortedSeries.type) {
6
30
  case SeriesType.Area: {
7
- s.data = sort(s.data, (d) => d.x);
31
+ sortedSeries = Object.assign(Object.assign({}, sortedSeries), { data: sort(sortedSeries.data, (d) => d.x) });
32
+ break;
8
33
  }
9
34
  }
10
- return s;
35
+ return sortedSeries;
11
36
  });
12
37
  }
@@ -1,4 +1,5 @@
1
1
  import { SeriesType } from '../../constants';
2
+ import { getAxisCategories } from '../../hooks/useChartOptions/utils';
2
3
  const SERIES_TYPE_WITH_HIDDEN_POINTS = [SeriesType.Area, SeriesType.Line];
3
4
  // eslint-disable-next-line complexity
4
5
  function isValueInRange(args) {
@@ -20,7 +21,7 @@ function isValueInRange(args) {
20
21
  return numValue >= numMin && numValue <= numMax;
21
22
  }
22
23
  case 'category': {
23
- const categories = (axis === null || axis === void 0 ? void 0 : axis.categories) || [];
24
+ const categories = getAxisCategories(axis) || [];
24
25
  if (typeof value === 'string' && typeof min === 'number' && typeof max === 'number') {
25
26
  const valueIndex = categories.indexOf(value);
26
27
  if (min === -1 || max === -1 || valueIndex === -1) {
@@ -1,9 +1,35 @@
1
1
  import get from 'lodash/get';
2
2
  import isEmpty from 'lodash/isEmpty';
3
- import { DEFAULT_AXIS_TYPE, SeriesType } from '../constants';
3
+ import { AXIS_TYPE, DEFAULT_AXIS_TYPE, SeriesType, TOOLTIP_TOTALS_BUILT_IN_AGGREGATION, } from '../constants';
4
4
  import { i18n } from '../i18n';
5
5
  import { CHART_ERROR_CODE, ChartError } from '../libs';
6
+ function getTypeOf(value) {
7
+ return typeof value;
8
+ }
6
9
  const AVAILABLE_SERIES_TYPES = Object.values(SeriesType);
10
+ const AVAILABLE_TOOLTIP_TOTALS_BUILT_IN_AGGREGATIONS = Object.values(TOOLTIP_TOTALS_BUILT_IN_AGGREGATION);
11
+ const AVAILABLE_TOOLTIP_TOTALS_AGGREGATION_TYPES = ['function', 'string'];
12
+ const AVAILABLE_AXIS_TYPES = Object.values(AXIS_TYPE);
13
+ function validateAxisType({ axis, key }) {
14
+ if (axis.type && !AVAILABLE_AXIS_TYPES.includes(axis.type)) {
15
+ throw new ChartError({
16
+ code: CHART_ERROR_CODE.INVALID_DATA,
17
+ message: i18n('error', 'label_invalid-axis-type', {
18
+ key,
19
+ values: AVAILABLE_AXIS_TYPES,
20
+ }),
21
+ });
22
+ }
23
+ }
24
+ function validateAxes(args) {
25
+ const { xAxis, yAxis = [] } = args;
26
+ if (xAxis) {
27
+ validateAxisType({ axis: xAxis, key: 'x' });
28
+ }
29
+ yAxis.forEach((axis) => {
30
+ validateAxisType({ axis, key: 'y' });
31
+ });
32
+ }
7
33
  function validateXYSeries(args) {
8
34
  const { series, xAxis, yAxis = [] } = args;
9
35
  const yAxisIndex = get(series, 'yAxis', 0);
@@ -335,6 +361,32 @@ function countSeriesByType(args) {
335
361
  });
336
362
  return count;
337
363
  }
364
+ function validateTooltip({ tooltip }) {
365
+ if (!tooltip) {
366
+ return;
367
+ }
368
+ if (tooltip.totals) {
369
+ const aggregation = tooltip.totals.aggregation;
370
+ if (aggregation) {
371
+ const aggregationType = getTypeOf(aggregation);
372
+ if (!AVAILABLE_TOOLTIP_TOTALS_AGGREGATION_TYPES.includes(aggregationType)) {
373
+ throw new ChartError({
374
+ code: CHART_ERROR_CODE.INVALID_DATA,
375
+ message: i18n('error', 'label_invalid-tooltip-totals-aggregation-type'),
376
+ });
377
+ }
378
+ if (typeof aggregation === 'string' &&
379
+ !AVAILABLE_TOOLTIP_TOTALS_BUILT_IN_AGGREGATIONS.includes(aggregation)) {
380
+ throw new ChartError({
381
+ code: CHART_ERROR_CODE.INVALID_DATA,
382
+ message: i18n('error', 'label_invalid-tooltip-totals-aggregation-type-str', {
383
+ values: AVAILABLE_TOOLTIP_TOTALS_BUILT_IN_AGGREGATIONS,
384
+ }),
385
+ });
386
+ }
387
+ }
388
+ }
389
+ }
338
390
  export function validateData(data) {
339
391
  if (isEmpty(data) || isEmpty(data.series) || isEmpty(data.series.data)) {
340
392
  throw new ChartError({
@@ -342,6 +394,8 @@ export function validateData(data) {
342
394
  message: i18n('error', 'label_no-data'),
343
395
  });
344
396
  }
397
+ validateAxes({ xAxis: data.xAxis, yAxis: data.yAxis });
398
+ validateTooltip({ tooltip: data.tooltip });
345
399
  if (data.series.data.some((s) => isEmpty(s.data))) {
346
400
  throw new ChartError({
347
401
  code: CHART_ERROR_CODE.INVALID_DATA,