@gravity-ui/charts 1.43.1 → 1.45.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/ChartInner/utils/zoom.js +3 -1
  2. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +31 -6
  3. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +4 -5
  4. package/dist/cjs/core/constants/chart-types.d.ts +1 -0
  5. package/dist/cjs/core/constants/chart-types.js +1 -0
  6. package/dist/cjs/core/constants/defaults/annotation.d.ts +12 -0
  7. package/dist/cjs/core/constants/defaults/annotation.js +12 -0
  8. package/dist/cjs/core/constants/defaults/index.d.ts +1 -0
  9. package/dist/cjs/core/constants/defaults/index.js +1 -0
  10. package/dist/cjs/core/constants/defaults/series-options.d.ts +5 -1
  11. package/dist/cjs/core/constants/defaults/series-options.js +13 -0
  12. package/dist/cjs/core/i18n/keysets/en.json +2 -1
  13. package/dist/cjs/core/i18n/keysets/ru.json +2 -1
  14. package/dist/cjs/core/series/constants.d.ts +1 -1
  15. package/dist/cjs/core/series/constants.js +1 -1
  16. package/dist/cjs/core/series/prepare-annotation.d.ts +12 -0
  17. package/dist/cjs/core/series/prepare-annotation.js +31 -0
  18. package/dist/cjs/core/series/prepare-legend.js +2 -2
  19. package/dist/cjs/core/series/prepare-x-range.d.ts +11 -0
  20. package/dist/cjs/core/series/prepare-x-range.js +41 -0
  21. package/dist/cjs/core/series/prepareSeries.js +9 -0
  22. package/dist/cjs/core/series/types.d.ts +34 -2
  23. package/dist/cjs/core/types/chart/annotation.d.ts +45 -0
  24. package/dist/cjs/core/types/chart/annotation.js +1 -0
  25. package/dist/cjs/core/types/chart/area.d.ts +10 -1
  26. package/dist/cjs/core/types/chart/bar-x.d.ts +6 -0
  27. package/dist/cjs/core/types/chart/line.d.ts +8 -0
  28. package/dist/cjs/core/types/chart/marker.d.ts +6 -4
  29. package/dist/cjs/core/types/chart/series.d.ts +36 -2
  30. package/dist/cjs/core/types/chart/tooltip.d.ts +7 -1
  31. package/dist/cjs/core/types/chart/x-range.d.ts +59 -0
  32. package/dist/cjs/core/types/chart/x-range.js +1 -0
  33. package/dist/cjs/core/types/chart/zoom.d.ts +1 -1
  34. package/dist/cjs/core/types/index.d.ts +2 -0
  35. package/dist/cjs/core/types/index.js +2 -0
  36. package/dist/cjs/core/utils/axis/x-axis.js +9 -1
  37. package/dist/cjs/core/utils/color.js +6 -0
  38. package/dist/cjs/core/utils/common.js +10 -0
  39. package/dist/cjs/core/utils/get-closest-data.js +19 -0
  40. package/dist/cjs/core/utils/text.d.ts +8 -0
  41. package/dist/cjs/core/utils/text.js +9 -1
  42. package/dist/cjs/core/validation/index.js +13 -0
  43. package/dist/cjs/core/zoom/zoom.js +24 -7
  44. package/dist/cjs/hooks/useShapes/annotation/index.d.ts +14 -0
  45. package/dist/cjs/hooks/useShapes/annotation/index.js +200 -0
  46. package/dist/cjs/hooks/useShapes/area/index.d.ts +2 -0
  47. package/dist/cjs/hooks/useShapes/area/index.js +21 -2
  48. package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +2 -1
  49. package/dist/cjs/hooks/useShapes/area/prepare-data.js +45 -26
  50. package/dist/cjs/hooks/useShapes/area/types.d.ts +4 -0
  51. package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +2 -0
  52. package/dist/cjs/hooks/useShapes/bar-x/index.js +30 -2
  53. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +32 -11
  54. package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +2 -0
  55. package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
  56. package/dist/cjs/hooks/useShapes/index.js +22 -3
  57. package/dist/cjs/hooks/useShapes/line/index.d.ts +2 -0
  58. package/dist/cjs/hooks/useShapes/line/index.js +21 -7
  59. package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +2 -1
  60. package/dist/cjs/hooks/useShapes/line/prepare-data.js +28 -10
  61. package/dist/cjs/hooks/useShapes/line/types.d.ts +4 -0
  62. package/dist/cjs/hooks/useShapes/x-range/index.d.ts +14 -0
  63. package/dist/cjs/hooks/useShapes/x-range/index.js +115 -0
  64. package/dist/cjs/hooks/useShapes/x-range/prepare-data.d.ts +15 -0
  65. package/dist/cjs/hooks/useShapes/x-range/prepare-data.js +147 -0
  66. package/dist/cjs/hooks/useShapes/x-range/types.d.ts +12 -0
  67. package/dist/cjs/hooks/useShapes/x-range/types.js +1 -0
  68. package/dist/esm/components/ChartInner/utils/zoom.js +3 -1
  69. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +31 -6
  70. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +4 -5
  71. package/dist/esm/core/constants/chart-types.d.ts +1 -0
  72. package/dist/esm/core/constants/chart-types.js +1 -0
  73. package/dist/esm/core/constants/defaults/annotation.d.ts +12 -0
  74. package/dist/esm/core/constants/defaults/annotation.js +12 -0
  75. package/dist/esm/core/constants/defaults/index.d.ts +1 -0
  76. package/dist/esm/core/constants/defaults/index.js +1 -0
  77. package/dist/esm/core/constants/defaults/series-options.d.ts +5 -1
  78. package/dist/esm/core/constants/defaults/series-options.js +13 -0
  79. package/dist/esm/core/i18n/keysets/en.json +2 -1
  80. package/dist/esm/core/i18n/keysets/ru.json +2 -1
  81. package/dist/esm/core/series/constants.d.ts +1 -1
  82. package/dist/esm/core/series/constants.js +1 -1
  83. package/dist/esm/core/series/prepare-annotation.d.ts +12 -0
  84. package/dist/esm/core/series/prepare-annotation.js +31 -0
  85. package/dist/esm/core/series/prepare-legend.js +2 -2
  86. package/dist/esm/core/series/prepare-x-range.d.ts +11 -0
  87. package/dist/esm/core/series/prepare-x-range.js +41 -0
  88. package/dist/esm/core/series/prepareSeries.js +9 -0
  89. package/dist/esm/core/series/types.d.ts +34 -2
  90. package/dist/esm/core/types/chart/annotation.d.ts +45 -0
  91. package/dist/esm/core/types/chart/annotation.js +1 -0
  92. package/dist/esm/core/types/chart/area.d.ts +10 -1
  93. package/dist/esm/core/types/chart/bar-x.d.ts +6 -0
  94. package/dist/esm/core/types/chart/line.d.ts +8 -0
  95. package/dist/esm/core/types/chart/marker.d.ts +6 -4
  96. package/dist/esm/core/types/chart/series.d.ts +36 -2
  97. package/dist/esm/core/types/chart/tooltip.d.ts +7 -1
  98. package/dist/esm/core/types/chart/x-range.d.ts +59 -0
  99. package/dist/esm/core/types/chart/x-range.js +1 -0
  100. package/dist/esm/core/types/chart/zoom.d.ts +1 -1
  101. package/dist/esm/core/types/index.d.ts +2 -0
  102. package/dist/esm/core/types/index.js +2 -0
  103. package/dist/esm/core/utils/axis/x-axis.js +9 -1
  104. package/dist/esm/core/utils/color.js +6 -0
  105. package/dist/esm/core/utils/common.js +10 -0
  106. package/dist/esm/core/utils/get-closest-data.js +19 -0
  107. package/dist/esm/core/utils/text.d.ts +8 -0
  108. package/dist/esm/core/utils/text.js +9 -1
  109. package/dist/esm/core/validation/index.js +13 -0
  110. package/dist/esm/core/zoom/zoom.js +24 -7
  111. package/dist/esm/hooks/useShapes/annotation/index.d.ts +14 -0
  112. package/dist/esm/hooks/useShapes/annotation/index.js +200 -0
  113. package/dist/esm/hooks/useShapes/area/index.d.ts +2 -0
  114. package/dist/esm/hooks/useShapes/area/index.js +21 -2
  115. package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +2 -1
  116. package/dist/esm/hooks/useShapes/area/prepare-data.js +45 -26
  117. package/dist/esm/hooks/useShapes/area/types.d.ts +4 -0
  118. package/dist/esm/hooks/useShapes/bar-x/index.d.ts +2 -0
  119. package/dist/esm/hooks/useShapes/bar-x/index.js +30 -2
  120. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +32 -11
  121. package/dist/esm/hooks/useShapes/bar-x/types.d.ts +2 -0
  122. package/dist/esm/hooks/useShapes/index.d.ts +2 -1
  123. package/dist/esm/hooks/useShapes/index.js +22 -3
  124. package/dist/esm/hooks/useShapes/line/index.d.ts +2 -0
  125. package/dist/esm/hooks/useShapes/line/index.js +21 -7
  126. package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +2 -1
  127. package/dist/esm/hooks/useShapes/line/prepare-data.js +28 -10
  128. package/dist/esm/hooks/useShapes/line/types.d.ts +4 -0
  129. package/dist/esm/hooks/useShapes/x-range/index.d.ts +14 -0
  130. package/dist/esm/hooks/useShapes/x-range/index.js +115 -0
  131. package/dist/esm/hooks/useShapes/x-range/prepare-data.d.ts +15 -0
  132. package/dist/esm/hooks/useShapes/x-range/prepare-data.js +147 -0
  133. package/dist/esm/hooks/useShapes/x-range/types.d.ts +12 -0
  134. package/dist/esm/hooks/useShapes/x-range/types.js +1 -0
  135. package/package.json +2 -2
@@ -2,10 +2,11 @@ import type { PreparedSplit } from '../../../core/layout/split-types';
2
2
  import type { ChartScale } from '../../../core/scales/types';
3
3
  import type { ShapeDataWithLabels } from '../../../types';
4
4
  import type { PreparedXAxis, PreparedYAxis } from '../../useAxis/types';
5
- import type { PreparedLineSeries } from '../../useSeries/types';
5
+ import type { PreparedLineSeries, PreparedSeriesOptions } from '../../useSeries/types';
6
6
  import type { PreparedLineData } from './types';
7
7
  export declare const prepareLineData: (args: {
8
8
  series: PreparedLineSeries[];
9
+ seriesOptions?: PreparedSeriesOptions;
9
10
  xAxis: PreparedXAxis;
10
11
  xScale: ChartScale;
11
12
  yAxis: PreparedYAxis[];
@@ -1,3 +1,4 @@
1
+ import { prepareAnnotation } from '../../../core/series/prepare-annotation';
1
2
  import { filterOverlappingLabels, getLabelsSize, getTextSizeFn } from '../../../core/utils';
2
3
  import { getFormattedValue } from '../../../core/utils/format';
3
4
  import { getXValue, getYValue } from '../utils';
@@ -15,8 +16,8 @@ async function getHtmlLabel(point, series, xMax) {
15
16
  };
16
17
  }
17
18
  export const prepareLineData = async (args) => {
18
- var _a, _b, _c, _d;
19
- const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds, isRangeSlider, otherLayers, } = args;
19
+ var _a, _b, _c, _d, _e, _f, _g;
20
+ const { series, seriesOptions, xAxis, yAxis, xScale, yScale, split, isOutsideBounds, isRangeSlider, otherLayers, } = args;
20
21
  const [_xMin, xRangeMax] = xScale.range();
21
22
  const xMax = xRangeMax;
22
23
  const acc = [];
@@ -29,21 +30,31 @@ export const prepareLineData = async (args) => {
29
30
  if (!seriesYScale) {
30
31
  continue;
31
32
  }
32
- const points = s.data.map((d) => {
33
+ const annotationOpts = (_b = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.line) === null || _b === void 0 ? void 0 : _b.annotation;
34
+ const points = [];
35
+ for (let j = 0; j < s.data.length; j++) {
36
+ const d = s.data[j];
33
37
  const yValue = getYValue({
34
38
  point: d,
35
39
  points: s.data,
36
40
  yAxis: seriesYAxis,
37
41
  yScale: seriesYScale,
38
42
  });
39
- return {
43
+ points.push({
40
44
  x: getXValue({ point: d, points: s.data, xAxis, xScale }),
41
45
  y: yValue === null ? null : yAxisTop + yValue,
42
- active: true,
46
+ color: (_d = (_c = d.marker) === null || _c === void 0 ? void 0 : _c.color) !== null && _d !== void 0 ? _d : d.color,
43
47
  data: d,
44
48
  series: s,
45
- };
46
- });
49
+ annotation: d.annotation && !isRangeSlider
50
+ ? await prepareAnnotation({
51
+ annotation: d.annotation,
52
+ optionsLabel: annotationOpts === null || annotationOpts === void 0 ? void 0 : annotationOpts.label,
53
+ optionsPopup: annotationOpts === null || annotationOpts === void 0 ? void 0 : annotationOpts.popup,
54
+ })
55
+ : undefined,
56
+ });
57
+ }
47
58
  let htmlElements = [];
48
59
  let svgLabels = [];
49
60
  if (s.dataLabels.enabled && !isRangeSlider) {
@@ -64,7 +75,7 @@ export const prepareLineData = async (args) => {
64
75
  if (point.y !== null &&
65
76
  point.x !== null &&
66
77
  !isOutsideBounds(point.x, point.y)) {
67
- const labelValue = (_b = point.data.label) !== null && _b !== void 0 ? _b : point.data.y;
78
+ const labelValue = (_e = point.data.label) !== null && _e !== void 0 ? _e : point.data.y;
68
79
  const text = getFormattedValue(Object.assign({ value: labelValue }, s.dataLabels));
69
80
  const labelSize = await getTextSize(text);
70
81
  const style = s.dataLabels.style;
@@ -112,7 +123,14 @@ export const prepareLineData = async (args) => {
112
123
  return result;
113
124
  }, []);
114
125
  }
126
+ const annotations = points.reduce((result, p) => {
127
+ if (p.annotation && p.x !== null && p.y !== null) {
128
+ result.push({ annotation: p.annotation, x: p.x, y: p.y });
129
+ }
130
+ return result;
131
+ }, []);
115
132
  const result = {
133
+ annotations,
116
134
  points,
117
135
  markers,
118
136
  svgLabels: svgLabels,
@@ -122,11 +140,11 @@ export const prepareLineData = async (args) => {
122
140
  id: s.id,
123
141
  htmlLabels: htmlElements,
124
142
  color: s.color,
125
- lineWidth: (_c = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _c !== void 0 ? _c : s.lineWidth,
143
+ lineWidth: (_f = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _f !== void 0 ? _f : s.lineWidth,
126
144
  dashStyle: s.dashStyle,
127
145
  linecap: s.linecap,
128
146
  linejoin: s.linejoin,
129
- opacity: (_d = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _d !== void 0 ? _d : s.opacity,
147
+ opacity: (_g = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _g !== void 0 ? _g : s.opacity,
130
148
  };
131
149
  acc.push(result);
132
150
  }
@@ -1,11 +1,14 @@
1
1
  import type { DashStyle, LineCap, LineJoin } from '../../../core/constants';
2
+ import type { PreparedAnnotation } from '../../../core/series/types';
2
3
  import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
3
4
  import type { PreparedLineSeries } from '../../useSeries/types';
5
+ import type { AnnotationAnchor } from '../annotation';
4
6
  export type PointData = {
5
7
  x: number | null;
6
8
  y: number | null;
7
9
  data: LineSeriesData;
8
10
  series: PreparedLineSeries;
11
+ annotation?: PreparedAnnotation;
9
12
  color?: string;
10
13
  };
11
14
  export type MarkerPointData = PointData & {
@@ -19,6 +22,7 @@ export type MarkerData = {
19
22
  clipped: boolean;
20
23
  };
21
24
  export type PreparedLineData = {
25
+ annotations: AnnotationAnchor[];
22
26
  id: string;
23
27
  points: PointData[];
24
28
  markers: MarkerData[];
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { Dispatch } from 'd3-dispatch';
3
+ import type { PreparedSeriesOptions } from '../../useSeries/types';
4
+ export { prepareXRangeData } from './prepare-data';
5
+ export type { PreparedXRangeData } from './types';
6
+ import type { PreparedXRangeData } from './types';
7
+ type Args = {
8
+ clipPathId: string;
9
+ htmlLayout: HTMLElement | null;
10
+ preparedData: PreparedXRangeData[];
11
+ seriesOptions: PreparedSeriesOptions;
12
+ dispatcher?: Dispatch<object>;
13
+ };
14
+ export declare function XRangeSeriesShapes(args: Args): React.JSX.Element;
@@ -0,0 +1,115 @@
1
+ import React from 'react';
2
+ import { color } from 'd3-color';
3
+ import { select } from 'd3-selection';
4
+ import get from 'lodash/get';
5
+ import { getLineDashArray } from '../../../core/utils';
6
+ import { block } from '../../../utils';
7
+ import { HtmlLayer } from '../HtmlLayer';
8
+ import { getRectPath } from '../utils';
9
+ export { prepareXRangeData } from './prepare-data';
10
+ const b = block('x-range');
11
+ export function XRangeSeriesShapes(args) {
12
+ const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
13
+ const hoveredDataRef = React.useRef(null);
14
+ const ref = React.useRef(null);
15
+ React.useEffect(() => {
16
+ var _a;
17
+ if (!ref.current) {
18
+ return () => { };
19
+ }
20
+ const svgElement = select(ref.current);
21
+ svgElement.selectAll('*').remove();
22
+ const segmentSelection = svgElement
23
+ .selectAll(`path.${b('segment')}`)
24
+ .data(preparedData)
25
+ .join('path')
26
+ .attr('d', (d) => {
27
+ const borderRadius = Math.min(d.height / 2, d.width / 2, d.series.borderRadius);
28
+ return getRectPath({
29
+ x: d.x,
30
+ y: d.y,
31
+ width: d.width,
32
+ height: d.height,
33
+ borderRadius,
34
+ }).toString();
35
+ })
36
+ .attr('class', b('segment'))
37
+ .attr('fill', (d) => d.color)
38
+ .attr('opacity', (d) => { var _a; return (_a = d.data.opacity) !== null && _a !== void 0 ? _a : d.series.opacity; })
39
+ .attr('cursor', (d) => d.series.cursor);
40
+ svgElement
41
+ .selectAll(`path.${b('segment-border')}`)
42
+ .data(preparedData.filter((d) => d.series.borderWidth > 0))
43
+ .join('path')
44
+ .attr('d', (d) => {
45
+ const borderRadius = Math.min(d.height / 2, d.width / 2, d.series.borderRadius);
46
+ return getRectPath({
47
+ x: d.x,
48
+ y: d.y,
49
+ width: d.width,
50
+ height: d.height,
51
+ borderRadius,
52
+ }).toString();
53
+ })
54
+ .attr('class', b('segment-border'))
55
+ .attr('fill', 'none')
56
+ .attr('stroke', (d) => d.series.borderColor)
57
+ .attr('stroke-width', (d) => d.series.borderWidth)
58
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.series.borderDashStyle, d.series.borderWidth))
59
+ .attr('opacity', (d) => { var _a; return (_a = d.data.opacity) !== null && _a !== void 0 ? _a : d.series.opacity; })
60
+ .attr('pointer-events', 'none');
61
+ const svgLabels = preparedData.flatMap((d) => d.svgLabels);
62
+ svgElement
63
+ .selectAll(`text.${b('label')}`)
64
+ .data(svgLabels)
65
+ .join('text')
66
+ .attr('class', b('label'))
67
+ .attr('x', (d) => d.x)
68
+ .attr('y', (d) => d.y)
69
+ .attr('text-anchor', (d) => d.textAnchor)
70
+ .attr('dominant-baseline', 'central')
71
+ .attr('pointer-events', 'none')
72
+ .style('font-size', (d) => d.style.fontSize)
73
+ .style('font-weight', (d) => d.style.fontWeight || null)
74
+ .style('fill', (d) => d.style.fontColor || null)
75
+ .html((d) => d.text);
76
+ const hoverOptions = get(seriesOptions, 'x-range.states.hover');
77
+ const inactiveOptions = get(seriesOptions, 'x-range.states.inactive');
78
+ function handleShapeHover(data) {
79
+ hoveredDataRef.current = data;
80
+ if (hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled) {
81
+ const hoveredSet = new Set(data === null || data === void 0 ? void 0 : data.map((d) => d.data));
82
+ segmentSelection.attr('fill', (d) => {
83
+ var _a;
84
+ const fillColor = d.color;
85
+ if (hoveredSet.has(d.data)) {
86
+ return (((_a = color(fillColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions.brightness).toString()) ||
87
+ fillColor);
88
+ }
89
+ return fillColor;
90
+ });
91
+ }
92
+ if (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled) {
93
+ const hoveredSeries = data === null || data === void 0 ? void 0 : data.map((d) => d.series.id);
94
+ segmentSelection.attr('opacity', (d) => {
95
+ var _a, _b;
96
+ if ((hoveredSeries === null || hoveredSeries === void 0 ? void 0 : hoveredSeries.length) && !hoveredSeries.includes(d.series.id)) {
97
+ return inactiveOptions.opacity || null;
98
+ }
99
+ return (_b = (_a = d.data.opacity) !== null && _a !== void 0 ? _a : d.series.opacity) !== null && _b !== void 0 ? _b : null;
100
+ });
101
+ }
102
+ }
103
+ if (hoveredDataRef.current !== null) {
104
+ handleShapeHover((_a = hoveredDataRef.current) !== null && _a !== void 0 ? _a : undefined);
105
+ }
106
+ dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.x-range', handleShapeHover);
107
+ return () => {
108
+ dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.x-range', null);
109
+ };
110
+ }, [dispatcher, preparedData, seriesOptions]);
111
+ const htmlLayerData = React.useMemo(() => ({ htmlElements: preparedData.flatMap((d) => d.htmlLabels) }), [preparedData]);
112
+ return (React.createElement(React.Fragment, null,
113
+ React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
114
+ React.createElement(HtmlLayer, { preparedData: htmlLayerData, htmlLayout: htmlLayout })));
115
+ }
@@ -0,0 +1,15 @@
1
+ import type { ChartScale } from '../../../core/scales/types';
2
+ import type { PreparedXAxis, PreparedYAxis } from '../../useAxis/types';
3
+ import type { PreparedXRangeSeries } from '../../useSeries/types';
4
+ import type { PreparedXRangeData } from './types';
5
+ type PrepareXRangeDataArgs = {
6
+ series: PreparedXRangeSeries[];
7
+ xAxis: PreparedXAxis;
8
+ xScale: ChartScale;
9
+ yAxis: PreparedYAxis[];
10
+ yScale: (ChartScale | undefined)[];
11
+ boundsWidth?: number;
12
+ isRangeSlider?: boolean;
13
+ };
14
+ export declare function prepareXRangeData(args: PrepareXRangeDataArgs): Promise<PreparedXRangeData[]>;
15
+ export {};
@@ -0,0 +1,147 @@
1
+ import get from 'lodash/get';
2
+ import { getDataCategoryValue, getLabelsSize, getTextSizeFn, getTextWithElipsis } from '../../../core/utils';
3
+ import { getFormattedValue } from '../../../core/utils/format';
4
+ import { MIN_BAR_WIDTH } from '../../constants';
5
+ import { getBandSize } from '../../utils/get-band-size';
6
+ const DEFAULT_BAR_PADDING = 0.2;
7
+ export async function prepareXRangeData(args) {
8
+ var _a;
9
+ const { series, xAxis, xScale, yAxis, yScale: [yScale], boundsWidth, isRangeSlider, } = args;
10
+ if (!yScale) {
11
+ return [];
12
+ }
13
+ // Collect unique y-domain values
14
+ const domain = [];
15
+ const seen = new Set();
16
+ const categories = get(yAxis[0], 'categories', []);
17
+ series.forEach((s) => {
18
+ s.data.forEach((d) => {
19
+ const key = yAxis[0].type === 'category'
20
+ ? getDataCategoryValue({ axisDirection: 'y', categories, data: d })
21
+ : d.y;
22
+ if (key !== undefined && !seen.has(key)) {
23
+ seen.add(key);
24
+ domain.push(key);
25
+ }
26
+ });
27
+ });
28
+ const bandSize = getBandSize({ domain, scale: yScale });
29
+ const barSize = Math.max(MIN_BAR_WIDTH, bandSize * (1 - DEFAULT_BAR_PADDING));
30
+ const result = [];
31
+ series.forEach((s) => {
32
+ s.data.forEach((d) => {
33
+ let center;
34
+ if (yAxis[0].type === 'category') {
35
+ const bandScale = yScale;
36
+ const yCategory = getDataCategoryValue({ axisDirection: 'y', categories, data: d });
37
+ if (!bandScale.domain().includes(yCategory)) {
38
+ return;
39
+ }
40
+ center = (bandScale(yCategory) || 0) + bandSize / 2;
41
+ }
42
+ else {
43
+ const linearScale = yScale;
44
+ if (d.y === undefined) {
45
+ return;
46
+ }
47
+ center = linearScale(Number(d.y));
48
+ }
49
+ let xStart;
50
+ let xEnd;
51
+ if (xAxis.type === 'category') {
52
+ // x-range on a category x-axis is unusual but supported
53
+ const xBandScale = xScale;
54
+ const xCategories = get(xAxis, 'categories', []);
55
+ const startCategory = getDataCategoryValue({
56
+ axisDirection: 'x',
57
+ categories: xCategories,
58
+ data: { x: d.x0 },
59
+ });
60
+ const endCategory = getDataCategoryValue({
61
+ axisDirection: 'x',
62
+ categories: xCategories,
63
+ data: { x: d.x1 },
64
+ });
65
+ xStart = xBandScale(startCategory) || 0;
66
+ xEnd = (xBandScale(endCategory) || 0) + xBandScale.bandwidth();
67
+ }
68
+ else {
69
+ const linearScale = xScale;
70
+ xStart = linearScale(Number(d.x0));
71
+ xEnd = linearScale(Number(d.x1));
72
+ }
73
+ const width = xEnd - xStart;
74
+ if (width <= 0) {
75
+ return;
76
+ }
77
+ result.push({
78
+ x: xStart,
79
+ y: center - barSize / 2,
80
+ width,
81
+ height: barSize,
82
+ color: d.color || s.color,
83
+ data: d,
84
+ series: s,
85
+ htmlLabels: [],
86
+ svgLabels: [],
87
+ });
88
+ });
89
+ });
90
+ const textSizeFnCache = new Map();
91
+ for (let i = 0; i < result.length; i++) {
92
+ const item = result[i];
93
+ const { dataLabels } = item.series;
94
+ if (!dataLabels.enabled || item.data.label === null || isRangeSlider) {
95
+ continue;
96
+ }
97
+ const content = getFormattedValue(Object.assign({ value: item.data.label }, dataLabels));
98
+ const visibleStart = Math.max(0, item.x);
99
+ const visibleEnd = boundsWidth === undefined
100
+ ? item.x + item.width
101
+ : Math.min(boundsWidth, item.x + item.width);
102
+ const visibleWidth = visibleEnd - visibleStart;
103
+ const visibleCenterX = visibleStart + visibleWidth / 2;
104
+ if (dataLabels.html) {
105
+ const { maxHeight: height, maxWidth: width } = await getLabelsSize({
106
+ labels: [content],
107
+ style: dataLabels.style,
108
+ html: true,
109
+ });
110
+ const htmlItem = {
111
+ content,
112
+ size: { width, height },
113
+ style: dataLabels.style,
114
+ x: visibleCenterX - width / 2,
115
+ y: item.y + item.height / 2 - height / 2,
116
+ };
117
+ item.htmlLabels.push(htmlItem);
118
+ }
119
+ else {
120
+ if (!textSizeFnCache.has(dataLabels.style)) {
121
+ textSizeFnCache.set(dataLabels.style, getTextSizeFn({ style: dataLabels.style }));
122
+ }
123
+ const getTextSize = (_a = textSizeFnCache.get(dataLabels.style)) !== null && _a !== void 0 ? _a : getTextSizeFn({ style: dataLabels.style });
124
+ const availableWidth = Math.max(0, visibleWidth - 2 * dataLabels.padding);
125
+ const text = await getTextWithElipsis({
126
+ text: content,
127
+ getTextWidth: (s) => getTextSize(s).then((r) => r.width),
128
+ maxWidth: availableWidth,
129
+ });
130
+ if (!text) {
131
+ continue;
132
+ }
133
+ const { width, height, hangingOffset } = await getTextSize(text);
134
+ const svgItem = {
135
+ text,
136
+ size: { width, height, hangingOffset },
137
+ style: dataLabels.style,
138
+ textAnchor: 'middle',
139
+ x: visibleCenterX,
140
+ y: item.y + item.height / 2,
141
+ series: item.series,
142
+ };
143
+ item.svgLabels.push(svgItem);
144
+ }
145
+ }
146
+ return result;
147
+ }
@@ -0,0 +1,12 @@
1
+ import type { HtmlItem, LabelData, TooltipDataChunkXRange } from '../../../types';
2
+ import type { PreparedXRangeSeries } from '../../useSeries/types';
3
+ export type PreparedXRangeData = Omit<TooltipDataChunkXRange, 'series'> & {
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ color: string;
9
+ series: PreparedXRangeSeries;
10
+ svgLabels: LabelData[];
11
+ htmlLabels: HtmlItem[];
12
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -6,7 +6,8 @@ function mapSeriesTypeToZoomType(seriesType) {
6
6
  case SERIES_TYPE.Area: {
7
7
  return [ZOOM_TYPE.X, ZOOM_TYPE.XY, ZOOM_TYPE.Y];
8
8
  }
9
- case SERIES_TYPE.BarX: {
9
+ case SERIES_TYPE.BarX:
10
+ case SERIES_TYPE.XRange: {
10
11
  return [ZOOM_TYPE.X];
11
12
  }
12
13
  case SERIES_TYPE.BarY: {
@@ -36,6 +37,7 @@ function getDefaultZoomType(seriesType) {
36
37
  }
37
38
  case SERIES_TYPE.Area:
38
39
  case SERIES_TYPE.BarX:
40
+ case SERIES_TYPE.XRange:
39
41
  case SERIES_TYPE.Line:
40
42
  case SERIES_TYPE.Waterfall: {
41
43
  return ZOOM_TYPE.X;
@@ -43,12 +43,15 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
43
43
  const colorSymbol = getTooltipRowColorSymbol({ series, color });
44
44
  return (React.createElement(Row, { key: id, active: active, color: color, colorSymbol: colorSymbol ? (React.createElement("div", { dangerouslySetInnerHTML: { __html: colorSymbol.outerHTML } })) : undefined, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
45
45
  };
46
- const formattedHeadValue = headerFormat
47
- ? getFormattedValue({
48
- value: measureValue === null || measureValue === void 0 ? void 0 : measureValue.value,
49
- format: headerFormat,
50
- })
51
- : measureValue === null || measureValue === void 0 ? void 0 : measureValue.formattedValue;
46
+ let formattedHeadValue;
47
+ if (measureValue) {
48
+ formattedHeadValue = headerFormat
49
+ ? getFormattedValue({
50
+ value: measureValue.value,
51
+ format: headerFormat,
52
+ })
53
+ : measureValue.formattedValue;
54
+ }
52
55
  React.useEffect(() => {
53
56
  if (!contentRowsRef.current) {
54
57
  return;
@@ -186,6 +189,28 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
186
189
  formattedValue,
187
190
  });
188
191
  }
192
+ case 'x-range': {
193
+ const xRangeData = data;
194
+ const format = rowValueFormat || getDefaultValueFormat({ axis: xAxis });
195
+ const x0Formatted = getFormattedValue({
196
+ value: xRangeData.x0,
197
+ format,
198
+ });
199
+ const x1Formatted = getFormattedValue({
200
+ value: xRangeData.x1,
201
+ format,
202
+ });
203
+ return renderRow({
204
+ id,
205
+ active,
206
+ color,
207
+ name: series.name,
208
+ striped,
209
+ value: hoveredValues[i],
210
+ formattedValue: `${x0Formatted} — ${x1Formatted}`,
211
+ series,
212
+ });
213
+ }
189
214
  default: {
190
215
  return null;
191
216
  }
@@ -48,7 +48,7 @@ export const getMeasureValue = ({ data, xAxis, yAxis, headerFormat, }) => {
48
48
  const value = (_b = (_a = data[0].category) === null || _a === void 0 ? void 0 : _a.key) !== null && _b !== void 0 ? _b : null;
49
49
  return { value };
50
50
  }
51
- if (data.some((item) => item.series.type === 'bar-y')) {
51
+ if (data.some((item) => ['bar-y', 'x-range'].includes(item.series.type))) {
52
52
  const value = getYRowData((_c = data[0]) === null || _c === void 0 ? void 0 : _c.data, yAxis);
53
53
  const formattedValue = getFormattedValue({
54
54
  value: getYRowData((_d = data[0]) === null || _d === void 0 ? void 0 : _d.data, yAxis),
@@ -72,7 +72,9 @@ export function getHoveredValues(args) {
72
72
  case 'area':
73
73
  case 'line':
74
74
  case 'bar-x':
75
- case 'scatter': {
75
+ case 'waterfall':
76
+ case 'scatter':
77
+ case 'x-range': {
76
78
  return getYRowData(data, yAxis);
77
79
  }
78
80
  case 'bar-y': {
@@ -90,9 +92,6 @@ export function getHoveredValues(args) {
90
92
  const { target, data: source } = seriesItem;
91
93
  return (_a = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _a === void 0 ? void 0 : _a.value;
92
94
  }
93
- case 'waterfall': {
94
- return getYRowData(data, yAxis);
95
- }
96
95
  default: {
97
96
  return undefined;
98
97
  }
@@ -11,5 +11,6 @@ export declare const SERIES_TYPE: {
11
11
  readonly Radar: "radar";
12
12
  readonly Heatmap: "heatmap";
13
13
  readonly Funnel: "funnel";
14
+ readonly XRange: "x-range";
14
15
  };
15
16
  export type SeriesType = (typeof SERIES_TYPE)[keyof typeof SERIES_TYPE];
@@ -11,4 +11,5 @@ export const SERIES_TYPE = {
11
11
  Radar: 'radar',
12
12
  Heatmap: 'heatmap',
13
13
  Funnel: 'funnel',
14
+ XRange: 'x-range',
14
15
  };
@@ -0,0 +1,12 @@
1
+ export declare const annotationLabelDefaults: {
2
+ style: {
3
+ fontSize: string;
4
+ fontColor: string;
5
+ };
6
+ };
7
+ export declare const annotationPopupDefaults: {
8
+ backgroundColor: string;
9
+ borderRadius: number;
10
+ offset: number;
11
+ padding: [number, number];
12
+ };
@@ -0,0 +1,12 @@
1
+ export const annotationLabelDefaults = {
2
+ style: {
3
+ fontSize: '13px',
4
+ fontColor: 'var(--g-color-text-light-primary)',
5
+ },
6
+ };
7
+ export const annotationPopupDefaults = {
8
+ backgroundColor: 'var(--g-color-base-float-heavy)',
9
+ borderRadius: 4,
10
+ offset: 5,
11
+ padding: [4, 8],
12
+ };
@@ -1,3 +1,4 @@
1
+ export * from './annotation';
1
2
  export * from './axis';
2
3
  export * from './brush';
3
4
  export * from './data-labels';
@@ -1,3 +1,4 @@
1
+ export * from './annotation';
1
2
  export * from './axis';
2
3
  export * from './brush';
3
4
  export * from './data-labels';
@@ -21,7 +21,11 @@ type DefaultWaterfallSeriesOptions = Partial<ChartSeriesOptions['waterfall']> &
21
21
  barPadding: number;
22
22
  };
23
23
  };
24
- export type SeriesOptionsDefaults = Partial<ChartSeriesOptions> & DefaultBarXSeriesOptions & DefaultBarYSeriesOptions & DefaultWaterfallSeriesOptions;
24
+ export type SeriesOptionsDefaults = Partial<ChartSeriesOptions> & DefaultBarXSeriesOptions & DefaultBarYSeriesOptions & DefaultWaterfallSeriesOptions & {
25
+ 'x-range': {
26
+ borderRadius: number;
27
+ };
28
+ };
25
29
  export declare const seriesOptionsDefaults: SeriesOptionsDefaults;
26
30
  export declare const seriesRangeSliderOptionsDefaults: Required<ChartSeriesRangeSliderOptions>;
27
31
  export {};
@@ -133,6 +133,19 @@ export const seriesOptionsDefaults = {
133
133
  },
134
134
  },
135
135
  },
136
+ 'x-range': {
137
+ borderRadius: 0,
138
+ states: {
139
+ hover: {
140
+ enabled: true,
141
+ brightness: 0.3,
142
+ },
143
+ inactive: {
144
+ enabled: false,
145
+ opacity: 0.5,
146
+ },
147
+ },
148
+ },
136
149
  };
137
150
  export const seriesRangeSliderOptionsDefaults = {
138
151
  visible: true,
@@ -21,7 +21,8 @@
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis.",
22
22
  "label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}].",
23
23
  "label_invalid-axis-categories": "It seems you are trying to use inappropriate value for \"categories\", or defined it incorrectly. Categories must be a non-empty array for an axis with \"category\" type.",
24
- "label_inconsistent-y-axis-configuration": "It seems you have inconsistent Y-axis configuration. Possible reasons:\n1. Multiple Y axes with the same position and plot index.\n2. At the moment, 'category' axis is not supported in dual Y-axis configurations."
24
+ "label_inconsistent-y-axis-configuration": "It seems you have inconsistent Y-axis configuration. Possible reasons:\n1. Multiple Y axes with the same position and plot index.\n2. At the moment, 'category' axis is not supported in dual Y-axis configurations.",
25
+ "label_stacking-area-connect-null-mode": "It seems you are using \"nullMode: 'connect'\" with a stacking area series. The \"connect\" null mode is not supported in stacking mode. Use \"zero\" or \"skip\" instead."
25
26
  },
26
27
  "tooltip": {
27
28
  "label_totals_sum": "Sum",
@@ -21,7 +21,8 @@
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\".",
22
22
  "label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}].",
23
23
  "label_invalid-axis-categories": "Похоже, что вы пытаетесь использовать недопустимое значение для \"categories\", или указали его неверно. Категории для оси типа \"category\" должны быть непустым массивом.",
24
- "label_inconsistent-y-axis-configuration": "Похоже, что конфигурация осей Y неконсистентна. Возможные причины:\n1. Несколько осей Y имеют одинаковые значения position и plotIndex.\n2. На данный момент категорийные оси не поддерживаются в конфигурациях с двумя осями Y."
24
+ "label_inconsistent-y-axis-configuration": "Похоже, что конфигурация осей Y неконсистентна. Возможные причины:\n1. Несколько осей Y имеют одинаковые значения position и plotIndex.\n2. На данный момент категорийные оси не поддерживаются в конфигурациях с двумя осями Y.",
25
+ "label_stacking-area-connect-null-mode": "Похоже, что вы используете \"nullMode: 'connect'\" с серией area с накоплением. Режим null \"connect\" не поддерживается в режиме накопления. Используйте \"zero\" или \"skip\"."
25
26
  },
26
27
  "tooltip": {
27
28
  "label_totals_sum": "Сумма",