@gravity-ui/charts 1.28.2 → 1.30.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 (52) hide show
  1. package/README.md +19 -3
  2. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +3 -1
  3. package/dist/cjs/constants/defaults/legend.d.ts +1 -0
  4. package/dist/cjs/constants/defaults/legend.js +1 -0
  5. package/dist/cjs/hooks/useAxisScales/index.js +32 -8
  6. package/dist/cjs/hooks/useRangeSlider/index.js +1 -0
  7. package/dist/cjs/hooks/useSeries/prepare-legend.js +17 -3
  8. package/dist/cjs/hooks/useSeries/prepare-line.js +1 -1
  9. package/dist/cjs/hooks/useSeries/types.d.ts +2 -2
  10. package/dist/cjs/hooks/useShapes/area/index.js +1 -1
  11. package/dist/cjs/hooks/useShapes/bar-x/index.js +1 -1
  12. package/dist/cjs/hooks/useShapes/bar-y/index.js +1 -1
  13. package/dist/cjs/hooks/useShapes/funnel/index.js +1 -1
  14. package/dist/cjs/hooks/useShapes/heatmap/index.js +1 -1
  15. package/dist/cjs/hooks/useShapes/index.d.ts +1 -0
  16. package/dist/cjs/hooks/useShapes/index.js +3 -1
  17. package/dist/cjs/hooks/useShapes/line/index.js +3 -3
  18. package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +1 -0
  19. package/dist/cjs/hooks/useShapes/line/prepare-data.js +6 -6
  20. package/dist/cjs/hooks/useShapes/line/types.d.ts +4 -6
  21. package/dist/cjs/hooks/useShapes/radar/index.js +1 -1
  22. package/dist/cjs/hooks/useShapes/sankey/index.js +1 -1
  23. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -1
  24. package/dist/cjs/types/chart/base.d.ts +6 -0
  25. package/dist/cjs/types/chart/legend.d.ts +7 -0
  26. package/dist/cjs/types/chart/line.d.ts +19 -13
  27. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +3 -1
  28. package/dist/esm/constants/defaults/legend.d.ts +1 -0
  29. package/dist/esm/constants/defaults/legend.js +1 -0
  30. package/dist/esm/hooks/useAxisScales/index.js +32 -8
  31. package/dist/esm/hooks/useRangeSlider/index.js +1 -0
  32. package/dist/esm/hooks/useSeries/prepare-legend.js +17 -3
  33. package/dist/esm/hooks/useSeries/prepare-line.js +1 -1
  34. package/dist/esm/hooks/useSeries/types.d.ts +2 -2
  35. package/dist/esm/hooks/useShapes/area/index.js +1 -1
  36. package/dist/esm/hooks/useShapes/bar-x/index.js +1 -1
  37. package/dist/esm/hooks/useShapes/bar-y/index.js +1 -1
  38. package/dist/esm/hooks/useShapes/funnel/index.js +1 -1
  39. package/dist/esm/hooks/useShapes/heatmap/index.js +1 -1
  40. package/dist/esm/hooks/useShapes/index.d.ts +1 -0
  41. package/dist/esm/hooks/useShapes/index.js +3 -1
  42. package/dist/esm/hooks/useShapes/line/index.js +3 -3
  43. package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +1 -0
  44. package/dist/esm/hooks/useShapes/line/prepare-data.js +6 -6
  45. package/dist/esm/hooks/useShapes/line/types.d.ts +4 -6
  46. package/dist/esm/hooks/useShapes/radar/index.js +1 -1
  47. package/dist/esm/hooks/useShapes/sankey/index.js +1 -1
  48. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -1
  49. package/dist/esm/types/chart/base.d.ts +6 -0
  50. package/dist/esm/types/chart/legend.d.ts +7 -0
  51. package/dist/esm/types/chart/line.d.ts +19 -13
  52. package/package.json +2 -2
package/README.md CHANGED
@@ -1,15 +1,31 @@
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/)
1
+ # Gravity UI Charts
2
2
 
3
- ## Install
3
+ A flexible JavaScript library for data visualization and chart rendering using React.
4
+
5
+ [![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/)
6
+
7
+ ## Documentation
8
+
9
+ - [Overview](https://gravity-ui.github.io/charts/pages/overview.html)
10
+ - [API](https://gravity-ui.github.io/charts/pages/api/overview.html)
11
+ - [Guides](https://gravity-ui.github.io/charts/pages/guides/tooltip.html)
12
+
13
+ ## Get started
14
+
15
+ ### Install
4
16
 
5
17
  ```shell
6
18
  npm install @gravity-ui/uikit @gravity-ui/charts
7
19
  ```
8
20
 
9
- ## Development
21
+ ### Development
10
22
 
11
23
  To start the development server with storybook run the following:
12
24
 
13
25
  ```shell
14
26
  npm run start
15
27
  ```
28
+
29
+ ## Contributing
30
+
31
+ Please refer to the [contributing document](https://github.com/gravity-ui/charts/blob/main/CONTRIBUTING.md) if you wish to make pull requests.
@@ -1,4 +1,5 @@
1
1
  import { pointer } from 'd3';
2
+ import get from 'lodash/get';
2
3
  import throttle from 'lodash/throttle';
3
4
  import { IS_TOUCH_ENABLED } from '../../constants';
4
5
  import { EventType } from '../../utils';
@@ -16,9 +17,10 @@ export function useChartInnerHandlers(props) {
16
17
  dispatcher.call(EventType.POINTERMOVE_CHART, {}, undefined, event);
17
18
  return;
18
19
  }
20
+ const shapesDataWithTooltipEnabled = shapesData.filter((d) => get(d, 'series.tooltip.enabled', true));
19
21
  const closest = getClosestPoints({
20
22
  position: [x, y],
21
- shapesData,
23
+ shapesData: shapesDataWithTooltipEnabled,
22
24
  boundsHeight,
23
25
  boundsWidth,
24
26
  });
@@ -1,6 +1,7 @@
1
1
  import type { ChartLegend } from '../../types';
2
2
  export declare const legendDefaults: {
3
3
  align: Required<ChartLegend>["align"];
4
+ verticalAlign: Required<ChartLegend>["verticalAlign"];
4
5
  justifyContent: Required<ChartLegend>["justifyContent"];
5
6
  itemDistance: number;
6
7
  margin: number;
@@ -1,5 +1,6 @@
1
1
  export const legendDefaults = {
2
2
  align: 'center',
3
+ verticalAlign: 'top',
3
4
  justifyContent: 'center',
4
5
  itemDistance: 20,
5
6
  margin: 15,
@@ -116,8 +116,14 @@ export function createYScale(args) {
116
116
  offsetMax += bandWidth / 2;
117
117
  }
118
118
  }
119
- const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
120
- const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
119
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateY;
120
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateY;
121
+ const domainOffsetMin = isMinSpecified
122
+ ? 0
123
+ : Math.abs(scale.invert(offsetMin) - scale.invert(0));
124
+ const domainOffsetMax = isMaxSpecified
125
+ ? 0
126
+ : Math.abs(scale.invert(offsetMax) - scale.invert(0));
121
127
  return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
122
128
  }
123
129
  break;
@@ -185,8 +191,14 @@ export function createYScale(args) {
185
191
  offsetMax += bandWidth / 2;
186
192
  }
187
193
  }
188
- const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
189
- const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
194
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateY;
195
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateY;
196
+ const domainOffsetMin = isMinSpecified
197
+ ? 0
198
+ : Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
199
+ const domainOffsetMax = isMaxSpecified
200
+ ? 0
201
+ : Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
190
202
  return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
191
203
  }
192
204
  }
@@ -307,8 +319,14 @@ export function createXScale(args) {
307
319
  offsetMax += bandWidth / 2;
308
320
  }
309
321
  }
310
- const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
311
- const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
322
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateX;
323
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateX;
324
+ const domainOffsetMin = isMinSpecified
325
+ ? 0
326
+ : Math.abs(scale.invert(offsetMin) - scale.invert(0));
327
+ const domainOffsetMax = isMaxSpecified
328
+ ? 0
329
+ : Math.abs(scale.invert(offsetMax) - scale.invert(0));
312
330
  // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
313
331
  const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
314
332
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
@@ -374,8 +392,14 @@ export function createXScale(args) {
374
392
  offsetMax += bandWidth / 2;
375
393
  }
376
394
  }
377
- const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
378
- const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
395
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateX;
396
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateX;
397
+ const domainOffsetMin = isMinSpecified
398
+ ? 0
399
+ : Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
400
+ const domainOffsetMax = isMaxSpecified
401
+ ? 0
402
+ : Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
379
403
  // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
380
404
  const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
381
405
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
@@ -51,6 +51,7 @@ export function useRangeSlider(props) {
51
51
  clipPathId,
52
52
  clipPathBySeriesType: CLIP_PATH_BY_SERIES_TYPE,
53
53
  htmlLayout,
54
+ isRangeSlider: true,
54
55
  series: filteredPreparedSeries,
55
56
  seriesOptions: preparedSeriesOptions,
56
57
  split: EMPTY_PREPARED_SPLIT,
@@ -57,6 +57,7 @@ export async function getPreparedLegend(args) {
57
57
  }
58
58
  return {
59
59
  align: get(legend, 'align', legendDefaults.align),
60
+ verticalAlign: get(legend, 'verticalAlign', legendDefaults.verticalAlign),
60
61
  justifyContent: get(legend, 'justifyContent', legendDefaults.justifyContent),
61
62
  enabled,
62
63
  height,
@@ -174,7 +175,19 @@ function getPagination(args) {
174
175
  return { pages };
175
176
  }
176
177
  function getLegendOffset(args) {
177
- const { position, chartWidth, chartHeight, chartMargin, legendWidth, legendHeight } = args;
178
+ const { position, verticalAlign, chartWidth, chartHeight, chartMargin, legendWidth, legendHeight, } = args;
179
+ const getVerticalTop = () => {
180
+ const availableHeight = chartHeight - chartMargin.top - chartMargin.bottom;
181
+ switch (verticalAlign) {
182
+ case 'bottom':
183
+ return chartMargin.top + availableHeight - legendHeight;
184
+ case 'center':
185
+ return chartMargin.top + (availableHeight - legendHeight) / 2;
186
+ case 'top':
187
+ default:
188
+ return chartMargin.top;
189
+ }
190
+ };
178
191
  switch (position) {
179
192
  case 'top':
180
193
  return {
@@ -183,12 +196,12 @@ function getLegendOffset(args) {
183
196
  };
184
197
  case 'right':
185
198
  return {
186
- top: chartMargin.top,
199
+ top: getVerticalTop(),
187
200
  left: chartWidth - chartMargin.right - legendWidth,
188
201
  };
189
202
  case 'left':
190
203
  return {
191
- top: chartMargin.top,
204
+ top: getVerticalTop(),
192
205
  left: chartMargin.left,
193
206
  };
194
207
  case 'bottom':
@@ -257,6 +270,7 @@ export function getLegendComponents(args) {
257
270
  }
258
271
  const offset = getLegendOffset({
259
272
  position: preparedLegend.position,
273
+ verticalAlign: preparedLegend.verticalAlign,
260
274
  chartWidth,
261
275
  chartHeight,
262
276
  chartMargin,
@@ -94,7 +94,7 @@ export function prepareLineSeries(args) {
94
94
  cursor: get(series, 'cursor', null),
95
95
  yAxis: get(series, 'yAxis', 0),
96
96
  tooltip: series.tooltip,
97
- rangeSlider: Object.assign({}, seriesRangeSliderOptionsDefaults, series.rangeSlider),
97
+ rangeSlider: Object.assign(Object.assign({}, seriesRangeSliderOptionsDefaults), series.rangeSlider),
98
98
  };
99
99
  return prepared;
100
100
  }, []);
@@ -1,5 +1,5 @@
1
1
  import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
2
- import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
2
+ import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
3
3
  export type RectLegendSymbol = {
4
4
  shape: 'rect';
5
5
  } & Required<RectLegendSymbolOptions>;
@@ -83,7 +83,7 @@ type BasePreparedSeries = {
83
83
  tooltip: ChartSeries['tooltip'];
84
84
  };
85
85
  type BasePreparedAxisRelatedSeries = {
86
- rangeSlider: Required<ChartSeriesRangeSliderOptions>;
86
+ rangeSlider: Required<ChartSeriesRangeSliderOptions> & Partial<LineSeriesLineBaseStyle>;
87
87
  };
88
88
  export type PreparedScatterSeries = {
89
89
  type: ScatterSeries['type'];
@@ -62,7 +62,7 @@ export const AreaSeriesShapes = (args) => {
62
62
  .selectAll('text')
63
63
  .data(dataLabels)
64
64
  .join('text')
65
- .text((d) => d.text)
65
+ .html((d) => d.text)
66
66
  .attr('class', b('label'))
67
67
  .attr('x', (d) => d.x)
68
68
  .attr('y', (d) => d.y)
@@ -53,7 +53,7 @@ export const BarXSeriesShapes = (args) => {
53
53
  .selectAll('text')
54
54
  .data(dataLabels)
55
55
  .join('text')
56
- .text((d) => d.text)
56
+ .html((d) => d.text)
57
57
  .attr('class', b('label'))
58
58
  .attr('x', (d) => d.x)
59
59
  .attr('y', (d) => d.y)
@@ -43,7 +43,7 @@ export function BarYSeriesShapes(args) {
43
43
  .selectAll('text')
44
44
  .data(dataLabels)
45
45
  .join('text')
46
- .text((d) => d.text)
46
+ .html((d) => d.text)
47
47
  .attr('class', b('label'))
48
48
  .attr('x', (d) => d.x)
49
49
  .attr('y', (d) => d.y)
@@ -56,7 +56,7 @@ export const FunnelSeriesShapes = (args) => {
56
56
  .selectAll('text')
57
57
  .data(preparedData.svgLabels)
58
58
  .join('text')
59
- .text((d) => d.text)
59
+ .html((d) => d.text)
60
60
  .attr('class', b('label'))
61
61
  .attr('x', (d) => d.x)
62
62
  .attr('y', (d) => d.y)
@@ -34,7 +34,7 @@ export const HeatmapSeriesShapes = (args) => {
34
34
  .selectAll('text')
35
35
  .data(preparedData.labels)
36
36
  .join('text')
37
- .text((d) => d.text)
37
+ .html((d) => d.text)
38
38
  .attr('class', b('label'))
39
39
  .attr('x', (d) => d.x)
40
40
  .attr('y', (d) => d.y)
@@ -34,6 +34,7 @@ type Args = {
34
34
  clipPathBySeriesType?: ClipPathBySeriesType;
35
35
  dispatcher?: Dispatch<object>;
36
36
  isOutsideBounds?: (x: number, y: number) => boolean;
37
+ isRangeSlider?: boolean;
37
38
  xScale?: ChartScale;
38
39
  yScale?: (ChartScale | undefined)[];
39
40
  };
@@ -30,7 +30,7 @@ function shouldUseClipPathId(seriesType, clipPathBySeriesType) {
30
30
  return (_a = clipPathBySeriesType === null || clipPathBySeriesType === void 0 ? void 0 : clipPathBySeriesType[seriesType]) !== null && _a !== void 0 ? _a : true;
31
31
  }
32
32
  export const useShapes = (args) => {
33
- const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
33
+ const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
34
34
  const [shapesElemens, setShapesElements] = React.useState([]);
35
35
  const [shapesElemensData, setShapesElemensData] = React.useState([]);
36
36
  const countedRef = React.useRef(0);
@@ -106,6 +106,7 @@ export const useShapes = (args) => {
106
106
  yScale,
107
107
  split,
108
108
  isOutsideBounds,
109
+ isRangeSlider,
109
110
  });
110
111
  shapes.push(React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
111
112
  shapesData.push(...preparedData);
@@ -232,6 +233,7 @@ export const useShapes = (args) => {
232
233
  dispatcher,
233
234
  htmlLayout,
234
235
  isOutsideBounds,
236
+ isRangeSlider,
235
237
  series,
236
238
  seriesOptions,
237
239
  split,
@@ -33,10 +33,10 @@ export const LineSeriesShapes = (args) => {
33
33
  .attr('d', (d) => line(d.points))
34
34
  .attr('fill', 'none')
35
35
  .attr('stroke', (d) => d.color)
36
- .attr('stroke-width', (d) => d.width)
36
+ .attr('stroke-width', (d) => d.lineWidth)
37
37
  .attr('stroke-linejoin', (d) => d.linecap)
38
38
  .attr('stroke-linecap', (d) => d.linecap)
39
- .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width))
39
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
40
40
  .attr('opacity', (d) => d.opacity)
41
41
  .attr('cursor', (d) => d.series.cursor);
42
42
  let dataLabels = preparedData.reduce((acc, d) => {
@@ -49,7 +49,7 @@ export const LineSeriesShapes = (args) => {
49
49
  .selectAll('text')
50
50
  .data(dataLabels)
51
51
  .join('text')
52
- .text((d) => d.text)
52
+ .html((d) => d.text)
53
53
  .attr('class', b('label'))
54
54
  .attr('x', (d) => d.x)
55
55
  .attr('y', (d) => d.y)
@@ -11,4 +11,5 @@ export declare const prepareLineData: (args: {
11
11
  yScale: (ChartScale | undefined)[];
12
12
  split: PreparedSplit;
13
13
  isOutsideBounds: (x: number, y: number) => boolean;
14
+ isRangeSlider?: boolean;
14
15
  }) => Promise<PreparedLineData[]>;
@@ -13,8 +13,8 @@ async function getHtmlLabel(point, series, xMax) {
13
13
  };
14
14
  }
15
15
  export const prepareLineData = async (args) => {
16
- var _a;
17
- const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds } = args;
16
+ var _a, _b, _c;
17
+ const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds, isRangeSlider } = args;
18
18
  const [_xMin, xRangeMax] = xScale.range();
19
19
  const xMax = xRangeMax;
20
20
  const acc = [];
@@ -99,16 +99,16 @@ export const prepareLineData = async (args) => {
99
99
  points,
100
100
  markers,
101
101
  labels,
102
- color: s.color,
103
- width: s.lineWidth,
104
102
  series: s,
105
103
  hovered: false,
106
104
  active: true,
107
105
  id: s.id,
106
+ htmlElements,
107
+ color: s.color,
108
+ lineWidth: (_b = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _b !== void 0 ? _b : s.lineWidth,
108
109
  dashStyle: s.dashStyle,
109
110
  linecap: s.linecap,
110
- opacity: s.opacity,
111
- htmlElements,
111
+ opacity: (_c = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _c !== void 0 ? _c : s.opacity,
112
112
  };
113
113
  acc.push(result);
114
114
  }
@@ -1,5 +1,5 @@
1
1
  import type { DashStyle, LineCap } from '../../../constants';
2
- import type { HtmlItem, LabelData, LineSeriesData } from '../../../types';
2
+ import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
3
3
  import type { PreparedLineSeries } from '../../useSeries/types';
4
4
  export type PointData = {
5
5
  x: number | null;
@@ -22,14 +22,12 @@ export type PreparedLineData = {
22
22
  id: string;
23
23
  points: PointData[];
24
24
  markers: MarkerData[];
25
- color: string;
26
- width: number;
27
25
  series: PreparedLineSeries;
28
26
  hovered: boolean;
29
27
  active: boolean;
30
28
  labels: LabelData[];
29
+ htmlElements: HtmlItem[];
30
+ color: string;
31
31
  dashStyle: DashStyle;
32
32
  linecap: LineCap;
33
- opacity: number | null;
34
- htmlElements: HtmlItem[];
35
- };
33
+ } & Required<LineSeriesLineBaseStyle>;
@@ -69,7 +69,7 @@ export function RadarSeriesShapes(args) {
69
69
  .selectAll('text')
70
70
  .data((radarData) => radarData.labels)
71
71
  .join('text')
72
- .text((d) => d.text)
72
+ .html((d) => d.text)
73
73
  .attr('class', b('label'))
74
74
  .attr('x', (d) => d.x)
75
75
  .attr('y', (d) => d.y)
@@ -42,7 +42,7 @@ export const SankeySeriesShape = (props) => {
42
42
  .selectAll()
43
43
  .data(preparedData.labels)
44
44
  .join('text')
45
- .text((d) => d.text)
45
+ .html((d) => d.text)
46
46
  .attr('class', b('label'))
47
47
  .attr('x', (d) => d.x)
48
48
  .attr('y', (d) => d.y)
@@ -41,7 +41,7 @@ export const WaterfallSeriesShapes = (args) => {
41
41
  .selectAll('text')
42
42
  .data(dataLabels)
43
43
  .join('text')
44
- .text((d) => d.text)
44
+ .html((d) => d.text)
45
45
  .attr('class', b('label'))
46
46
  .attr('x', (d) => d.x)
47
47
  .attr('y', (d) => d.y)
@@ -56,6 +56,12 @@ export interface BaseSeries {
56
56
  tooltip?: {
57
57
  /** Formatting settings for tooltip value. */
58
58
  valueFormat?: ValueFormat;
59
+ /**
60
+ * Enable or disable the visibility of this series in the tooltip.
61
+ *
62
+ * @default true
63
+ */
64
+ enabled?: boolean;
59
65
  };
60
66
  }
61
67
  export interface BaseSeriesData<T = MeaningfulAny> {
@@ -25,6 +25,13 @@ export interface ChartLegend extends ChartLegendItem {
25
25
  * @default center
26
26
  * */
27
27
  align?: 'left' | 'center' | 'right';
28
+ /**
29
+ * The vertical alignment of the legend box within the chart area.
30
+ * Only applies when position is 'left' or 'right'.
31
+ *
32
+ * @default top
33
+ * */
34
+ verticalAlign?: 'top' | 'center' | 'bottom';
28
35
  /**
29
36
  * Defines how items should be positioned in the legend when overflowing (moving to the next line).
30
37
  *
@@ -29,30 +29,36 @@ export interface LineSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
29
29
  };
30
30
  };
31
31
  }
32
- export interface LineSeries<T = MeaningfulAny> extends BaseSeries {
32
+ export interface LineSeriesLineBaseStyle {
33
+ /** Pixel width of the graph line.
34
+ *
35
+ * @default 1 (for individual series).
36
+ * For series within the range slider, values are inherited from the individual series by default.
37
+ */
38
+ lineWidth?: number;
39
+ /** Individual opacity for the line.
40
+ *
41
+ * For series within the range slider, values are inherited from the individual series by default.
42
+ */
43
+ opacity?: number | null;
44
+ }
45
+ export interface LineSeries<T = MeaningfulAny> extends BaseSeries, LineSeriesLineBaseStyle {
33
46
  type: typeof SERIES_TYPE.Line;
34
47
  data: LineSeriesData<T>[];
35
48
  /** The name of the series (used in legend, tooltip etc) */
36
49
  name: string;
37
50
  /** The main color of the series (hex, rgba) */
38
51
  color?: string;
39
- /** Pixel width of the graph line.
40
- *
41
- * @default 1
42
- * */
43
- lineWidth?: number;
52
+ /** Option for line stroke style */
53
+ dashStyle?: DashStyle;
54
+ /** Option for line cap style */
55
+ linecap?: `${LineCap}`;
44
56
  /** Individual series legend options. Has higher priority than legend options in widget data */
45
57
  legend?: BaseSeriesLegend & {
46
58
  symbol?: RectLegendSymbolOptions;
47
59
  };
48
60
  /** Options for the point markers of line series */
49
61
  marker?: PointMarkerOptions;
50
- /** Option for line stroke style */
51
- dashStyle?: DashStyle;
52
- /** Option for line cap style */
53
- linecap?: `${LineCap}`;
54
- /** Individual opacity for the line. */
55
- opacity?: number;
56
62
  /** Y-axis index (when using two axes) */
57
63
  yAxis?: number;
58
64
  /**
@@ -68,5 +74,5 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries {
68
74
  /**
69
75
  * Options to configure how this series appears and behaves in the Range Slider component.
70
76
  */
71
- rangeSlider?: ChartSeriesRangeSliderOptions;
77
+ rangeSlider?: ChartSeriesRangeSliderOptions & LineSeriesLineBaseStyle;
72
78
  }
@@ -1,4 +1,5 @@
1
1
  import { pointer } from 'd3';
2
+ import get from 'lodash/get';
2
3
  import throttle from 'lodash/throttle';
3
4
  import { IS_TOUCH_ENABLED } from '../../constants';
4
5
  import { EventType } from '../../utils';
@@ -16,9 +17,10 @@ export function useChartInnerHandlers(props) {
16
17
  dispatcher.call(EventType.POINTERMOVE_CHART, {}, undefined, event);
17
18
  return;
18
19
  }
20
+ const shapesDataWithTooltipEnabled = shapesData.filter((d) => get(d, 'series.tooltip.enabled', true));
19
21
  const closest = getClosestPoints({
20
22
  position: [x, y],
21
- shapesData,
23
+ shapesData: shapesDataWithTooltipEnabled,
22
24
  boundsHeight,
23
25
  boundsWidth,
24
26
  });
@@ -1,6 +1,7 @@
1
1
  import type { ChartLegend } from '../../types';
2
2
  export declare const legendDefaults: {
3
3
  align: Required<ChartLegend>["align"];
4
+ verticalAlign: Required<ChartLegend>["verticalAlign"];
4
5
  justifyContent: Required<ChartLegend>["justifyContent"];
5
6
  itemDistance: number;
6
7
  margin: number;
@@ -1,5 +1,6 @@
1
1
  export const legendDefaults = {
2
2
  align: 'center',
3
+ verticalAlign: 'top',
3
4
  justifyContent: 'center',
4
5
  itemDistance: 20,
5
6
  margin: 15,
@@ -116,8 +116,14 @@ export function createYScale(args) {
116
116
  offsetMax += bandWidth / 2;
117
117
  }
118
118
  }
119
- const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
120
- const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
119
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateY;
120
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateY;
121
+ const domainOffsetMin = isMinSpecified
122
+ ? 0
123
+ : Math.abs(scale.invert(offsetMin) - scale.invert(0));
124
+ const domainOffsetMax = isMaxSpecified
125
+ ? 0
126
+ : Math.abs(scale.invert(offsetMax) - scale.invert(0));
121
127
  return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
122
128
  }
123
129
  break;
@@ -185,8 +191,14 @@ export function createYScale(args) {
185
191
  offsetMax += bandWidth / 2;
186
192
  }
187
193
  }
188
- const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
189
- const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
194
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateY;
195
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateY;
196
+ const domainOffsetMin = isMinSpecified
197
+ ? 0
198
+ : Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
199
+ const domainOffsetMax = isMaxSpecified
200
+ ? 0
201
+ : Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
190
202
  return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
191
203
  }
192
204
  }
@@ -307,8 +319,14 @@ export function createXScale(args) {
307
319
  offsetMax += bandWidth / 2;
308
320
  }
309
321
  }
310
- const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
311
- const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
322
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateX;
323
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateX;
324
+ const domainOffsetMin = isMinSpecified
325
+ ? 0
326
+ : Math.abs(scale.invert(offsetMin) - scale.invert(0));
327
+ const domainOffsetMax = isMaxSpecified
328
+ ? 0
329
+ : Math.abs(scale.invert(offsetMax) - scale.invert(0));
312
330
  // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
313
331
  const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
314
332
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
@@ -374,8 +392,14 @@ export function createXScale(args) {
374
392
  offsetMax += bandWidth / 2;
375
393
  }
376
394
  }
377
- const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
378
- const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
395
+ const isMinSpecified = typeof get(axis, 'min') === 'number' && !zoomStateX;
396
+ const isMaxSpecified = typeof get(axis, 'max') === 'number' && !zoomStateX;
397
+ const domainOffsetMin = isMinSpecified
398
+ ? 0
399
+ : Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
400
+ const domainOffsetMax = isMaxSpecified
401
+ ? 0
402
+ : Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
379
403
  // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
380
404
  const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
381
405
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
@@ -51,6 +51,7 @@ export function useRangeSlider(props) {
51
51
  clipPathId,
52
52
  clipPathBySeriesType: CLIP_PATH_BY_SERIES_TYPE,
53
53
  htmlLayout,
54
+ isRangeSlider: true,
54
55
  series: filteredPreparedSeries,
55
56
  seriesOptions: preparedSeriesOptions,
56
57
  split: EMPTY_PREPARED_SPLIT,
@@ -57,6 +57,7 @@ export async function getPreparedLegend(args) {
57
57
  }
58
58
  return {
59
59
  align: get(legend, 'align', legendDefaults.align),
60
+ verticalAlign: get(legend, 'verticalAlign', legendDefaults.verticalAlign),
60
61
  justifyContent: get(legend, 'justifyContent', legendDefaults.justifyContent),
61
62
  enabled,
62
63
  height,
@@ -174,7 +175,19 @@ function getPagination(args) {
174
175
  return { pages };
175
176
  }
176
177
  function getLegendOffset(args) {
177
- const { position, chartWidth, chartHeight, chartMargin, legendWidth, legendHeight } = args;
178
+ const { position, verticalAlign, chartWidth, chartHeight, chartMargin, legendWidth, legendHeight, } = args;
179
+ const getVerticalTop = () => {
180
+ const availableHeight = chartHeight - chartMargin.top - chartMargin.bottom;
181
+ switch (verticalAlign) {
182
+ case 'bottom':
183
+ return chartMargin.top + availableHeight - legendHeight;
184
+ case 'center':
185
+ return chartMargin.top + (availableHeight - legendHeight) / 2;
186
+ case 'top':
187
+ default:
188
+ return chartMargin.top;
189
+ }
190
+ };
178
191
  switch (position) {
179
192
  case 'top':
180
193
  return {
@@ -183,12 +196,12 @@ function getLegendOffset(args) {
183
196
  };
184
197
  case 'right':
185
198
  return {
186
- top: chartMargin.top,
199
+ top: getVerticalTop(),
187
200
  left: chartWidth - chartMargin.right - legendWidth,
188
201
  };
189
202
  case 'left':
190
203
  return {
191
- top: chartMargin.top,
204
+ top: getVerticalTop(),
192
205
  left: chartMargin.left,
193
206
  };
194
207
  case 'bottom':
@@ -257,6 +270,7 @@ export function getLegendComponents(args) {
257
270
  }
258
271
  const offset = getLegendOffset({
259
272
  position: preparedLegend.position,
273
+ verticalAlign: preparedLegend.verticalAlign,
260
274
  chartWidth,
261
275
  chartHeight,
262
276
  chartMargin,
@@ -94,7 +94,7 @@ export function prepareLineSeries(args) {
94
94
  cursor: get(series, 'cursor', null),
95
95
  yAxis: get(series, 'yAxis', 0),
96
96
  tooltip: series.tooltip,
97
- rangeSlider: Object.assign({}, seriesRangeSliderOptionsDefaults, series.rangeSlider),
97
+ rangeSlider: Object.assign(Object.assign({}, seriesRangeSliderOptionsDefaults), series.rangeSlider),
98
98
  };
99
99
  return prepared;
100
100
  }, []);
@@ -1,5 +1,5 @@
1
1
  import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
2
- import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
2
+ import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
3
3
  export type RectLegendSymbol = {
4
4
  shape: 'rect';
5
5
  } & Required<RectLegendSymbolOptions>;
@@ -83,7 +83,7 @@ type BasePreparedSeries = {
83
83
  tooltip: ChartSeries['tooltip'];
84
84
  };
85
85
  type BasePreparedAxisRelatedSeries = {
86
- rangeSlider: Required<ChartSeriesRangeSliderOptions>;
86
+ rangeSlider: Required<ChartSeriesRangeSliderOptions> & Partial<LineSeriesLineBaseStyle>;
87
87
  };
88
88
  export type PreparedScatterSeries = {
89
89
  type: ScatterSeries['type'];
@@ -62,7 +62,7 @@ export const AreaSeriesShapes = (args) => {
62
62
  .selectAll('text')
63
63
  .data(dataLabels)
64
64
  .join('text')
65
- .text((d) => d.text)
65
+ .html((d) => d.text)
66
66
  .attr('class', b('label'))
67
67
  .attr('x', (d) => d.x)
68
68
  .attr('y', (d) => d.y)
@@ -53,7 +53,7 @@ export const BarXSeriesShapes = (args) => {
53
53
  .selectAll('text')
54
54
  .data(dataLabels)
55
55
  .join('text')
56
- .text((d) => d.text)
56
+ .html((d) => d.text)
57
57
  .attr('class', b('label'))
58
58
  .attr('x', (d) => d.x)
59
59
  .attr('y', (d) => d.y)
@@ -43,7 +43,7 @@ export function BarYSeriesShapes(args) {
43
43
  .selectAll('text')
44
44
  .data(dataLabels)
45
45
  .join('text')
46
- .text((d) => d.text)
46
+ .html((d) => d.text)
47
47
  .attr('class', b('label'))
48
48
  .attr('x', (d) => d.x)
49
49
  .attr('y', (d) => d.y)
@@ -56,7 +56,7 @@ export const FunnelSeriesShapes = (args) => {
56
56
  .selectAll('text')
57
57
  .data(preparedData.svgLabels)
58
58
  .join('text')
59
- .text((d) => d.text)
59
+ .html((d) => d.text)
60
60
  .attr('class', b('label'))
61
61
  .attr('x', (d) => d.x)
62
62
  .attr('y', (d) => d.y)
@@ -34,7 +34,7 @@ export const HeatmapSeriesShapes = (args) => {
34
34
  .selectAll('text')
35
35
  .data(preparedData.labels)
36
36
  .join('text')
37
- .text((d) => d.text)
37
+ .html((d) => d.text)
38
38
  .attr('class', b('label'))
39
39
  .attr('x', (d) => d.x)
40
40
  .attr('y', (d) => d.y)
@@ -34,6 +34,7 @@ type Args = {
34
34
  clipPathBySeriesType?: ClipPathBySeriesType;
35
35
  dispatcher?: Dispatch<object>;
36
36
  isOutsideBounds?: (x: number, y: number) => boolean;
37
+ isRangeSlider?: boolean;
37
38
  xScale?: ChartScale;
38
39
  yScale?: (ChartScale | undefined)[];
39
40
  };
@@ -30,7 +30,7 @@ function shouldUseClipPathId(seriesType, clipPathBySeriesType) {
30
30
  return (_a = clipPathBySeriesType === null || clipPathBySeriesType === void 0 ? void 0 : clipPathBySeriesType[seriesType]) !== null && _a !== void 0 ? _a : true;
31
31
  }
32
32
  export const useShapes = (args) => {
33
- const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
33
+ const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
34
34
  const [shapesElemens, setShapesElements] = React.useState([]);
35
35
  const [shapesElemensData, setShapesElemensData] = React.useState([]);
36
36
  const countedRef = React.useRef(0);
@@ -106,6 +106,7 @@ export const useShapes = (args) => {
106
106
  yScale,
107
107
  split,
108
108
  isOutsideBounds,
109
+ isRangeSlider,
109
110
  });
110
111
  shapes.push(React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
111
112
  shapesData.push(...preparedData);
@@ -232,6 +233,7 @@ export const useShapes = (args) => {
232
233
  dispatcher,
233
234
  htmlLayout,
234
235
  isOutsideBounds,
236
+ isRangeSlider,
235
237
  series,
236
238
  seriesOptions,
237
239
  split,
@@ -33,10 +33,10 @@ export const LineSeriesShapes = (args) => {
33
33
  .attr('d', (d) => line(d.points))
34
34
  .attr('fill', 'none')
35
35
  .attr('stroke', (d) => d.color)
36
- .attr('stroke-width', (d) => d.width)
36
+ .attr('stroke-width', (d) => d.lineWidth)
37
37
  .attr('stroke-linejoin', (d) => d.linecap)
38
38
  .attr('stroke-linecap', (d) => d.linecap)
39
- .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width))
39
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
40
40
  .attr('opacity', (d) => d.opacity)
41
41
  .attr('cursor', (d) => d.series.cursor);
42
42
  let dataLabels = preparedData.reduce((acc, d) => {
@@ -49,7 +49,7 @@ export const LineSeriesShapes = (args) => {
49
49
  .selectAll('text')
50
50
  .data(dataLabels)
51
51
  .join('text')
52
- .text((d) => d.text)
52
+ .html((d) => d.text)
53
53
  .attr('class', b('label'))
54
54
  .attr('x', (d) => d.x)
55
55
  .attr('y', (d) => d.y)
@@ -11,4 +11,5 @@ export declare const prepareLineData: (args: {
11
11
  yScale: (ChartScale | undefined)[];
12
12
  split: PreparedSplit;
13
13
  isOutsideBounds: (x: number, y: number) => boolean;
14
+ isRangeSlider?: boolean;
14
15
  }) => Promise<PreparedLineData[]>;
@@ -13,8 +13,8 @@ async function getHtmlLabel(point, series, xMax) {
13
13
  };
14
14
  }
15
15
  export const prepareLineData = async (args) => {
16
- var _a;
17
- const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds } = args;
16
+ var _a, _b, _c;
17
+ const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds, isRangeSlider } = args;
18
18
  const [_xMin, xRangeMax] = xScale.range();
19
19
  const xMax = xRangeMax;
20
20
  const acc = [];
@@ -99,16 +99,16 @@ export const prepareLineData = async (args) => {
99
99
  points,
100
100
  markers,
101
101
  labels,
102
- color: s.color,
103
- width: s.lineWidth,
104
102
  series: s,
105
103
  hovered: false,
106
104
  active: true,
107
105
  id: s.id,
106
+ htmlElements,
107
+ color: s.color,
108
+ lineWidth: (_b = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _b !== void 0 ? _b : s.lineWidth,
108
109
  dashStyle: s.dashStyle,
109
110
  linecap: s.linecap,
110
- opacity: s.opacity,
111
- htmlElements,
111
+ opacity: (_c = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _c !== void 0 ? _c : s.opacity,
112
112
  };
113
113
  acc.push(result);
114
114
  }
@@ -1,5 +1,5 @@
1
1
  import type { DashStyle, LineCap } from '../../../constants';
2
- import type { HtmlItem, LabelData, LineSeriesData } from '../../../types';
2
+ import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
3
3
  import type { PreparedLineSeries } from '../../useSeries/types';
4
4
  export type PointData = {
5
5
  x: number | null;
@@ -22,14 +22,12 @@ export type PreparedLineData = {
22
22
  id: string;
23
23
  points: PointData[];
24
24
  markers: MarkerData[];
25
- color: string;
26
- width: number;
27
25
  series: PreparedLineSeries;
28
26
  hovered: boolean;
29
27
  active: boolean;
30
28
  labels: LabelData[];
29
+ htmlElements: HtmlItem[];
30
+ color: string;
31
31
  dashStyle: DashStyle;
32
32
  linecap: LineCap;
33
- opacity: number | null;
34
- htmlElements: HtmlItem[];
35
- };
33
+ } & Required<LineSeriesLineBaseStyle>;
@@ -69,7 +69,7 @@ export function RadarSeriesShapes(args) {
69
69
  .selectAll('text')
70
70
  .data((radarData) => radarData.labels)
71
71
  .join('text')
72
- .text((d) => d.text)
72
+ .html((d) => d.text)
73
73
  .attr('class', b('label'))
74
74
  .attr('x', (d) => d.x)
75
75
  .attr('y', (d) => d.y)
@@ -42,7 +42,7 @@ export const SankeySeriesShape = (props) => {
42
42
  .selectAll()
43
43
  .data(preparedData.labels)
44
44
  .join('text')
45
- .text((d) => d.text)
45
+ .html((d) => d.text)
46
46
  .attr('class', b('label'))
47
47
  .attr('x', (d) => d.x)
48
48
  .attr('y', (d) => d.y)
@@ -41,7 +41,7 @@ export const WaterfallSeriesShapes = (args) => {
41
41
  .selectAll('text')
42
42
  .data(dataLabels)
43
43
  .join('text')
44
- .text((d) => d.text)
44
+ .html((d) => d.text)
45
45
  .attr('class', b('label'))
46
46
  .attr('x', (d) => d.x)
47
47
  .attr('y', (d) => d.y)
@@ -56,6 +56,12 @@ export interface BaseSeries {
56
56
  tooltip?: {
57
57
  /** Formatting settings for tooltip value. */
58
58
  valueFormat?: ValueFormat;
59
+ /**
60
+ * Enable or disable the visibility of this series in the tooltip.
61
+ *
62
+ * @default true
63
+ */
64
+ enabled?: boolean;
59
65
  };
60
66
  }
61
67
  export interface BaseSeriesData<T = MeaningfulAny> {
@@ -25,6 +25,13 @@ export interface ChartLegend extends ChartLegendItem {
25
25
  * @default center
26
26
  * */
27
27
  align?: 'left' | 'center' | 'right';
28
+ /**
29
+ * The vertical alignment of the legend box within the chart area.
30
+ * Only applies when position is 'left' or 'right'.
31
+ *
32
+ * @default top
33
+ * */
34
+ verticalAlign?: 'top' | 'center' | 'bottom';
28
35
  /**
29
36
  * Defines how items should be positioned in the legend when overflowing (moving to the next line).
30
37
  *
@@ -29,30 +29,36 @@ export interface LineSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
29
29
  };
30
30
  };
31
31
  }
32
- export interface LineSeries<T = MeaningfulAny> extends BaseSeries {
32
+ export interface LineSeriesLineBaseStyle {
33
+ /** Pixel width of the graph line.
34
+ *
35
+ * @default 1 (for individual series).
36
+ * For series within the range slider, values are inherited from the individual series by default.
37
+ */
38
+ lineWidth?: number;
39
+ /** Individual opacity for the line.
40
+ *
41
+ * For series within the range slider, values are inherited from the individual series by default.
42
+ */
43
+ opacity?: number | null;
44
+ }
45
+ export interface LineSeries<T = MeaningfulAny> extends BaseSeries, LineSeriesLineBaseStyle {
33
46
  type: typeof SERIES_TYPE.Line;
34
47
  data: LineSeriesData<T>[];
35
48
  /** The name of the series (used in legend, tooltip etc) */
36
49
  name: string;
37
50
  /** The main color of the series (hex, rgba) */
38
51
  color?: string;
39
- /** Pixel width of the graph line.
40
- *
41
- * @default 1
42
- * */
43
- lineWidth?: number;
52
+ /** Option for line stroke style */
53
+ dashStyle?: DashStyle;
54
+ /** Option for line cap style */
55
+ linecap?: `${LineCap}`;
44
56
  /** Individual series legend options. Has higher priority than legend options in widget data */
45
57
  legend?: BaseSeriesLegend & {
46
58
  symbol?: RectLegendSymbolOptions;
47
59
  };
48
60
  /** Options for the point markers of line series */
49
61
  marker?: PointMarkerOptions;
50
- /** Option for line stroke style */
51
- dashStyle?: DashStyle;
52
- /** Option for line cap style */
53
- linecap?: `${LineCap}`;
54
- /** Individual opacity for the line. */
55
- opacity?: number;
56
62
  /** Y-axis index (when using two axes) */
57
63
  yAxis?: number;
58
64
  /**
@@ -68,5 +74,5 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries {
68
74
  /**
69
75
  * Options to configure how this series appears and behaves in the Range Slider component.
70
76
  */
71
- rangeSlider?: ChartSeriesRangeSliderOptions;
77
+ rangeSlider?: ChartSeriesRangeSliderOptions & LineSeriesLineBaseStyle;
72
78
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.28.2",
4
- "description": "React component used to render charts",
3
+ "version": "1.30.0",
4
+ "description": "A flexible JavaScript library for data visualization and chart rendering using React",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",
7
7
  "module": "./dist/esm/index.js",