@gravity-ui/charts 0.8.0 → 0.10.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 (116) hide show
  1. package/README.md +0 -3
  2. package/dist/cjs/components/Axis/AxisX.d.ts +1 -0
  3. package/dist/cjs/components/Axis/AxisX.js +43 -6
  4. package/dist/cjs/components/Axis/AxisY.js +9 -5
  5. package/dist/cjs/components/Axis/styles.css +5 -5
  6. package/dist/cjs/components/ChartInner/index.js +5 -4
  7. package/dist/cjs/components/ChartInner/styles.css +4 -4
  8. package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
  9. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +3 -4
  10. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +3 -2
  11. package/dist/cjs/components/Legend/index.js +1 -1
  12. package/dist/cjs/components/Legend/styles.css +14 -14
  13. package/dist/cjs/components/Title/index.js +1 -1
  14. package/dist/cjs/components/Title/styles.css +1 -1
  15. package/dist/cjs/components/Tooltip/DefaultContent.js +18 -3
  16. package/dist/cjs/constants/defaults/series-options.js +12 -0
  17. package/dist/cjs/constants/index.d.ts +1 -0
  18. package/dist/cjs/constants/index.js +1 -0
  19. package/dist/cjs/hooks/useChartOptions/tooltip.js +2 -1
  20. package/dist/cjs/hooks/useChartOptions/types.d.ts +2 -1
  21. package/dist/cjs/hooks/useChartOptions/x-axis.js +9 -2
  22. package/dist/cjs/hooks/useSeries/constants.js +1 -1
  23. package/dist/cjs/hooks/useSeries/prepare-radar.d.ts +16 -0
  24. package/dist/cjs/hooks/useSeries/prepare-radar.js +63 -0
  25. package/dist/cjs/hooks/useSeries/prepareSeries.js +8 -0
  26. package/dist/cjs/hooks/useSeries/types.d.ts +35 -2
  27. package/dist/cjs/hooks/useShapes/area/index.js +1 -1
  28. package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
  29. package/dist/cjs/hooks/useShapes/index.js +12 -0
  30. package/dist/cjs/hooks/useShapes/line/index.js +1 -1
  31. package/dist/cjs/hooks/useShapes/marker.d.ts +3 -2
  32. package/dist/cjs/hooks/useShapes/marker.js +1 -1
  33. package/dist/cjs/hooks/useShapes/pie/index.js +1 -1
  34. package/dist/cjs/hooks/useShapes/radar/index.d.ts +12 -0
  35. package/dist/cjs/hooks/useShapes/radar/index.js +136 -0
  36. package/dist/cjs/hooks/useShapes/radar/prepare-data.d.ts +9 -0
  37. package/dist/cjs/hooks/useShapes/radar/prepare-data.js +155 -0
  38. package/dist/cjs/hooks/useShapes/radar/types.d.ts +58 -0
  39. package/dist/cjs/hooks/useShapes/radar/types.js +1 -0
  40. package/dist/cjs/hooks/useShapes/scatter/index.js +1 -1
  41. package/dist/cjs/hooks/useShapes/styles.css +9 -5
  42. package/dist/cjs/hooks/useShapes/treemap/index.js +1 -1
  43. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -1
  44. package/dist/cjs/index.d.ts +1 -1
  45. package/dist/cjs/index.js +1 -0
  46. package/dist/cjs/types/chart/axis.d.ts +2 -2
  47. package/dist/cjs/types/chart/radar.d.ts +50 -0
  48. package/dist/cjs/types/chart/radar.js +1 -0
  49. package/dist/cjs/types/chart/series.d.ts +17 -2
  50. package/dist/cjs/types/chart/tooltip.d.ts +10 -1
  51. package/dist/cjs/types/index.d.ts +1 -0
  52. package/dist/cjs/types/index.js +1 -0
  53. package/dist/cjs/utils/chart/get-closest-data.js +39 -2
  54. package/dist/cjs/utils/chart/index.js +1 -1
  55. package/dist/cjs/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
  56. package/dist/cjs/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
  57. package/dist/cjs/utils/index.d.ts +1 -1
  58. package/dist/cjs/utils/index.js +1 -1
  59. package/dist/esm/components/Axis/AxisX.d.ts +1 -0
  60. package/dist/esm/components/Axis/AxisX.js +43 -6
  61. package/dist/esm/components/Axis/AxisY.js +9 -5
  62. package/dist/esm/components/Axis/styles.css +5 -5
  63. package/dist/esm/components/ChartInner/index.js +5 -4
  64. package/dist/esm/components/ChartInner/styles.css +4 -4
  65. package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
  66. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +3 -4
  67. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +3 -2
  68. package/dist/esm/components/Legend/index.js +1 -1
  69. package/dist/esm/components/Legend/styles.css +14 -14
  70. package/dist/esm/components/Title/index.js +1 -1
  71. package/dist/esm/components/Title/styles.css +1 -1
  72. package/dist/esm/components/Tooltip/DefaultContent.js +18 -3
  73. package/dist/esm/constants/defaults/series-options.js +12 -0
  74. package/dist/esm/constants/index.d.ts +1 -0
  75. package/dist/esm/constants/index.js +1 -0
  76. package/dist/esm/hooks/useChartOptions/tooltip.js +2 -1
  77. package/dist/esm/hooks/useChartOptions/types.d.ts +2 -1
  78. package/dist/esm/hooks/useChartOptions/x-axis.js +9 -2
  79. package/dist/esm/hooks/useSeries/constants.js +1 -1
  80. package/dist/esm/hooks/useSeries/prepare-radar.d.ts +16 -0
  81. package/dist/esm/hooks/useSeries/prepare-radar.js +63 -0
  82. package/dist/esm/hooks/useSeries/prepareSeries.js +8 -0
  83. package/dist/esm/hooks/useSeries/types.d.ts +35 -2
  84. package/dist/esm/hooks/useShapes/area/index.js +1 -1
  85. package/dist/esm/hooks/useShapes/index.d.ts +2 -1
  86. package/dist/esm/hooks/useShapes/index.js +12 -0
  87. package/dist/esm/hooks/useShapes/line/index.js +1 -1
  88. package/dist/esm/hooks/useShapes/marker.d.ts +3 -2
  89. package/dist/esm/hooks/useShapes/marker.js +1 -1
  90. package/dist/esm/hooks/useShapes/pie/index.js +1 -1
  91. package/dist/esm/hooks/useShapes/radar/index.d.ts +12 -0
  92. package/dist/esm/hooks/useShapes/radar/index.js +136 -0
  93. package/dist/esm/hooks/useShapes/radar/prepare-data.d.ts +9 -0
  94. package/dist/esm/hooks/useShapes/radar/prepare-data.js +155 -0
  95. package/dist/esm/hooks/useShapes/radar/types.d.ts +58 -0
  96. package/dist/esm/hooks/useShapes/radar/types.js +1 -0
  97. package/dist/esm/hooks/useShapes/scatter/index.js +1 -1
  98. package/dist/esm/hooks/useShapes/styles.css +9 -5
  99. package/dist/esm/hooks/useShapes/treemap/index.js +1 -1
  100. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -1
  101. package/dist/esm/index.d.ts +1 -1
  102. package/dist/esm/index.js +1 -0
  103. package/dist/esm/types/chart/axis.d.ts +2 -2
  104. package/dist/esm/types/chart/radar.d.ts +50 -0
  105. package/dist/esm/types/chart/radar.js +1 -0
  106. package/dist/esm/types/chart/series.d.ts +17 -2
  107. package/dist/esm/types/chart/tooltip.d.ts +10 -1
  108. package/dist/esm/types/index.d.ts +1 -0
  109. package/dist/esm/types/index.js +1 -0
  110. package/dist/esm/utils/chart/get-closest-data.js +39 -2
  111. package/dist/esm/utils/chart/index.js +1 -1
  112. package/dist/esm/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
  113. package/dist/esm/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
  114. package/dist/esm/utils/index.d.ts +1 -1
  115. package/dist/esm/utils/index.js +1 -1
  116. package/package.json +11 -2
@@ -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, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, WaterfallSeries, WaterfallSeriesData } from '../../types';
2
+ import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, WaterfallSeries, WaterfallSeriesData } from '../../types';
3
3
  export type RectLegendSymbol = {
4
4
  shape: 'rect';
5
5
  } & Required<RectLegendSymbolOptions>;
@@ -258,7 +258,40 @@ export type PreparedSankeySeries = {
258
258
  style: BaseTextStyle;
259
259
  };
260
260
  } & BasePreparedSeries & Omit<SankeySeries, keyof BasePreparedSeries>;
261
- export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries | PreparedSankeySeries;
261
+ export type PreparedRadarSeries = {
262
+ type: RadarSeries['type'];
263
+ data: RadarSeriesData[];
264
+ categories: RadarSeriesCategory[];
265
+ borderColor: string;
266
+ borderWidth: number;
267
+ fillOpacity: number;
268
+ dataLabels: {
269
+ enabled: boolean;
270
+ style: BaseTextStyle;
271
+ padding: number;
272
+ allowOverlap: boolean;
273
+ html: boolean;
274
+ };
275
+ marker: {
276
+ states: {
277
+ normal: {
278
+ symbol: `${SymbolType}`;
279
+ enabled: boolean;
280
+ radius: number;
281
+ borderWidth: number;
282
+ borderColor: string;
283
+ };
284
+ hover: {
285
+ enabled: boolean;
286
+ radius: number;
287
+ borderWidth: number;
288
+ borderColor: string;
289
+ halo: PreparedHaloOptions;
290
+ };
291
+ };
292
+ };
293
+ } & BasePreparedSeries;
294
+ export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries | PreparedSankeySeries | PreparedRadarSeries;
262
295
  export type PreparedSeriesOptions = SeriesOptionsDefaults;
263
296
  export type StackedSeries = BarXSeries | AreaSeries | BarYSeries;
264
297
  export {};
@@ -5,7 +5,7 @@ import { block, filterOverlappingLabels } from '../../..//utils';
5
5
  import { HtmlLayer } from '../HtmlLayer';
6
6
  import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
7
  import { setActiveState } from '../utils';
8
- const b = block('d3-area');
8
+ const b = block('area');
9
9
  export const AreaSeriesShapes = (args) => {
10
10
  const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
11
11
  const hoveredDataRef = React.useRef(null);
@@ -8,13 +8,14 @@ import type { PreparedBarXData } from './bar-x';
8
8
  import type { PreparedBarYData } from './bar-y/types';
9
9
  import type { PreparedLineData } from './line/types';
10
10
  import type { PreparedPieData } from './pie/types';
11
+ import type { PreparedRadarData } from './radar/types';
11
12
  import type { PreparedSankeyData } from './sankey/types';
12
13
  import type { PreparedScatterData } from './scatter/types';
13
14
  export type { PreparedBarXData } from './bar-x';
14
15
  export type { PreparedScatterData } from './scatter/types';
15
16
  import type { PreparedWaterfallData } from './waterfall';
16
17
  import './styles.css';
17
- export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData;
18
+ export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData;
18
19
  type Args = {
19
20
  boundsWidth: number;
20
21
  boundsHeight: number;
@@ -10,6 +10,8 @@ import { LineSeriesShapes } from './line';
10
10
  import { prepareLineData } from './line/prepare-data';
11
11
  import { PieSeriesShapes } from './pie';
12
12
  import { preparePieData } from './pie/prepare-data';
13
+ import { RadarSeriesShapes } from './radar';
14
+ import { prepareRadarData } from './radar/prepare-data';
13
15
  import { SankeySeriesShape } from './sankey';
14
16
  import { prepareSankeyData } from './sankey/prepare-data';
15
17
  import { ScatterSeriesShape, prepareScatterData } from './scatter';
@@ -149,6 +151,16 @@ export const useShapes = (args) => {
149
151
  shapesData.push(preparedData);
150
152
  break;
151
153
  }
154
+ case 'radar': {
155
+ const preparedData = prepareRadarData({
156
+ series: chartSeries,
157
+ boundsWidth,
158
+ boundsHeight,
159
+ });
160
+ acc.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
161
+ shapesData.push(...preparedData);
162
+ break;
163
+ }
152
164
  default: {
153
165
  throw new ChartError({
154
166
  message: `The display method is not defined for a series with type "${seriesType}"`,
@@ -5,7 +5,7 @@ import { block, filterOverlappingLabels, getLineDashArray } from '../../../utils
5
5
  import { HtmlLayer } from '../HtmlLayer';
6
6
  import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
7
  import { setActiveState } from '../utils';
8
- const b = block('d3-line');
8
+ const b = block('line');
9
9
  export const LineSeriesShapes = (args) => {
10
10
  const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
11
11
  const hoveredDataRef = React.useRef(null);
@@ -2,9 +2,10 @@ import type { BaseType, Selection } from 'd3';
2
2
  import { SymbolType } from '../../constants';
3
3
  import type { MarkerData as AreaMarkerData } from './area/types';
4
4
  import type { MarkerData as LineMarkerData } from './line/types';
5
+ import type { RadarMarkerData } from './radar/types';
5
6
  import type { MarkerData as ScatterMarkerData } from './scatter/types';
6
- type MarkerData = LineMarkerData | AreaMarkerData | ScatterMarkerData;
7
- export declare function renderMarker<T extends MarkerData>(selection: Selection<BaseType | SVGGElement, T, SVGGElement, unknown>): Selection<BaseType | SVGGElement, T, SVGGElement, unknown>;
7
+ type MarkerData = LineMarkerData | AreaMarkerData | ScatterMarkerData | RadarMarkerData;
8
+ export declare function renderMarker<T extends MarkerData>(selection: Selection<BaseType, T, BaseType, unknown>): Selection<BaseType, T, BaseType, unknown>;
8
9
  export declare function getMarkerVisibility(d: MarkerData): "" | "hidden";
9
10
  export declare function getMarkerHaloVisibility(d: MarkerData): "" | "hidden";
10
11
  export declare function setMarker<T extends BaseType, D extends MarkerData>(selection: Selection<T, D, BaseType | null, unknown>, state: 'normal' | 'hover'): void;
@@ -2,7 +2,7 @@ import { symbol } from 'd3';
2
2
  import get from 'lodash/get';
3
3
  import { SymbolType } from '../../constants';
4
4
  import { block, getSymbol } from '../../utils';
5
- const b = block('d3-marker');
5
+ const b = block('marker');
6
6
  const haloClassName = b('halo');
7
7
  const symbolClassName = b('symbol');
8
8
  export function renderMarker(selection) {
@@ -4,7 +4,7 @@ import get from 'lodash/get';
4
4
  import { block, setEllipsisForOverflowTexts } from '../../../utils';
5
5
  import { HtmlLayer } from '../HtmlLayer';
6
6
  import { setActiveState } from '../utils';
7
- const b = block('d3-pie');
7
+ const b = block('pie');
8
8
  export function getHaloVisibility(d) {
9
9
  const enabled = d.data.pie.halo.enabled && d.data.hovered;
10
10
  return enabled ? '' : 'hidden';
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { Dispatch } from 'd3';
3
+ import type { PreparedSeriesOptions } from '../../useSeries/types';
4
+ import type { PreparedRadarData } from './types';
5
+ type PrepareRadarSeriesArgs = {
6
+ dispatcher: Dispatch<object>;
7
+ series: PreparedRadarData[];
8
+ seriesOptions: PreparedSeriesOptions;
9
+ htmlLayout: HTMLElement | null;
10
+ };
11
+ export declare function RadarSeriesShapes(args: PrepareRadarSeriesArgs): React.JSX.Element;
12
+ export {};
@@ -0,0 +1,136 @@
1
+ import React from 'react';
2
+ import { color, line, select } from 'd3';
3
+ import get from 'lodash/get';
4
+ import { block } from '../../../utils';
5
+ import { HtmlLayer } from '../HtmlLayer';
6
+ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
+ import { setActiveState } from '../utils';
8
+ const b = block('radar');
9
+ export function RadarSeriesShapes(args) {
10
+ const { dispatcher, series: preparedData, seriesOptions, htmlLayout } = args;
11
+ const ref = React.useRef(null);
12
+ React.useEffect(() => {
13
+ if (!ref.current) {
14
+ return () => { };
15
+ }
16
+ const svgElement = select(ref.current);
17
+ svgElement.selectAll('*').remove();
18
+ const areaSelector = `.${b('area')}`;
19
+ const radarSelection = svgElement
20
+ .selectAll('radar')
21
+ .data(preparedData)
22
+ .join('g')
23
+ .attr('id', (radarData) => radarData.id)
24
+ .attr('class', b('item'))
25
+ .attr('cursor', (radarData) => radarData.cursor);
26
+ // render axes
27
+ radarSelection
28
+ .selectAll(`.${b('axis')}`)
29
+ .data((radarData) => radarData.axes)
30
+ .join('line')
31
+ .attr('class', b('axis'))
32
+ .attr('x1', (d) => d.radar.center[0])
33
+ .attr('y1', (d) => d.radar.center[1])
34
+ .attr('x2', (d) => d.point[0])
35
+ .attr('y2', (d) => d.point[1])
36
+ .attr('stroke', (d) => d.strokeColor)
37
+ .attr('stroke-width', (d) => d.strokeWidth);
38
+ // render grid lines
39
+ radarSelection
40
+ .selectAll(`.${b('grid')}`)
41
+ .data((radarData) => radarData.grid)
42
+ .join('path')
43
+ .attr('class', b('grid'))
44
+ .attr('d', (d) => `${line()(d.path)} Z`)
45
+ .attr('fill', 'none')
46
+ .attr('stroke', (d) => d.strokeColor)
47
+ .attr('stroke-width', (d) => d.strokeWidth);
48
+ // render radar area
49
+ const shapesSelection = radarSelection
50
+ .selectAll(areaSelector)
51
+ .data((radarData) => radarData.shapes)
52
+ .join('g')
53
+ .attr('class', b('area'));
54
+ shapesSelection
55
+ .append('path')
56
+ .attr('d', (d) => d.path)
57
+ .attr('fill', (d) => d.color)
58
+ .attr('fill-opacity', (d) => d.fillOpacity)
59
+ .attr('stroke', (d) => d.borderColor)
60
+ .attr('stroke-width', (d) => d.borderWidth);
61
+ // render markers
62
+ const markerSelection = shapesSelection
63
+ .selectAll('marker')
64
+ .data((radarData) => radarData.points)
65
+ .join('g')
66
+ .call(renderMarker);
67
+ // Render labels
68
+ radarSelection
69
+ .selectAll('text')
70
+ .data((radarData) => radarData.labels)
71
+ .join('text')
72
+ .text((d) => d.text)
73
+ .attr('class', b('label'))
74
+ .attr('x', (d) => d.x)
75
+ .attr('y', (d) => d.y)
76
+ .attr('text-anchor', (d) => d.textAnchor)
77
+ .style('font-size', (d) => d.style.fontSize)
78
+ .style('font-weight', (d) => d.style.fontWeight || null)
79
+ .style('fill', (d) => d.style.fontColor || null);
80
+ // Handle hover events
81
+ const eventName = `hover-shape.radar`;
82
+ const hoverOptions = get(seriesOptions, 'radar.states.hover');
83
+ const inactiveOptions = get(seriesOptions, 'radar.states.inactive');
84
+ dispatcher.on(eventName, (data) => {
85
+ const closest = data === null || data === void 0 ? void 0 : data.find((d) => d.closest);
86
+ const selectedSeries = closest === null || closest === void 0 ? void 0 : closest.series;
87
+ const selectedSeriesData = closest === null || closest === void 0 ? void 0 : closest.data;
88
+ const selectedSeriesId = selectedSeries === null || selectedSeries === void 0 ? void 0 : selectedSeries.id;
89
+ const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
90
+ const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
91
+ shapesSelection.datum((d, i, elements) => {
92
+ var _a;
93
+ const hovered = Boolean(hoverEnabled && ((_a = d.series) === null || _a === void 0 ? void 0 : _a.id) === selectedSeriesId);
94
+ if (d.hovered !== hovered) {
95
+ d.hovered = hovered;
96
+ select(elements[i]).attr('fill', () => {
97
+ var _a;
98
+ const initialColor = d.color;
99
+ if (d.hovered) {
100
+ return (((_a = color(initialColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness).toString()) || initialColor);
101
+ }
102
+ return initialColor;
103
+ });
104
+ if (hovered) {
105
+ select(elements[i]).raise();
106
+ }
107
+ }
108
+ setActiveState({
109
+ element: elements[i],
110
+ state: inactiveOptions,
111
+ active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.series.id),
112
+ datum: d,
113
+ });
114
+ markerSelection.datum((markerData, index, markers) => {
115
+ const hoveredState = Boolean(hoverEnabled && markerData.data === selectedSeriesData);
116
+ if (markerData.hovered !== hoveredState) {
117
+ markerData.hovered = hoveredState;
118
+ const elementSelection = select(markers[index]);
119
+ elementSelection.attr('visibility', getMarkerVisibility(markerData));
120
+ selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
121
+ selectMarkerSymbol(elementSelection).call(setMarker, hoveredState ? 'hover' : 'normal');
122
+ }
123
+ return markerData;
124
+ });
125
+ return d;
126
+ });
127
+ });
128
+ return () => {
129
+ dispatcher.on(eventName, null);
130
+ };
131
+ }, [dispatcher, preparedData, seriesOptions]);
132
+ const htmlElements = preparedData.map((d) => d.htmlLabels).flat();
133
+ return (React.createElement(React.Fragment, null,
134
+ React.createElement("g", { ref: ref, className: b() }),
135
+ React.createElement(HtmlLayer, { preparedData: { htmlElements }, htmlLayout: htmlLayout })));
136
+ }
@@ -0,0 +1,9 @@
1
+ import type { PreparedRadarSeries } from '../../useSeries/types';
2
+ import type { PreparedRadarData } from './types';
3
+ type Args = {
4
+ series: PreparedRadarSeries[];
5
+ boundsWidth: number;
6
+ boundsHeight: number;
7
+ };
8
+ export declare function prepareRadarData(args: Args): PreparedRadarData[];
9
+ export {};
@@ -0,0 +1,155 @@
1
+ import { curveLinearClosed, line, range, scaleLinear } from 'd3';
2
+ import { getLabelsSize } from '../../../utils';
3
+ export function prepareRadarData(args) {
4
+ const { series: preparedSeries, boundsWidth, boundsHeight } = args;
5
+ const maxRadius = Math.min(boundsWidth, boundsHeight) / 2;
6
+ const center = [boundsWidth / 2, boundsHeight / 2];
7
+ const result = [];
8
+ const gridStepsCount = 5;
9
+ const radius = maxRadius * 0.8; // Leave some space for labels
10
+ // Create scale for values
11
+ const valueScale = scaleLinear()
12
+ .domain([0, Math.max(...preparedSeries.map((s) => s.data.map((d) => d.value)).flat())])
13
+ .range([0, radius]);
14
+ const [, finalRadius] = valueScale.range();
15
+ const data = {
16
+ type: 'radar',
17
+ id: preparedSeries[0].id,
18
+ center,
19
+ radius: finalRadius,
20
+ shapes: [],
21
+ labels: [],
22
+ axes: [],
23
+ htmlLabels: [],
24
+ grid: [],
25
+ cursor: preparedSeries[0].cursor,
26
+ };
27
+ const categories = preparedSeries[0].categories;
28
+ const axisStrokeColor = 'var(--g-color-line-generic)';
29
+ const axisStrokeWidth = 1;
30
+ // Create axes based on categories
31
+ const axesCount = categories.length;
32
+ const angleStep = (2 * Math.PI) / axesCount;
33
+ data.axes = categories.map((_category, index) => {
34
+ const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
35
+ return {
36
+ point: [
37
+ center[0] + Math.cos(angle) * data.radius,
38
+ center[1] + Math.sin(angle) * data.radius,
39
+ ],
40
+ radar: data,
41
+ strokeColor: axisStrokeColor,
42
+ strokeWidth: axisStrokeWidth,
43
+ angle,
44
+ };
45
+ });
46
+ const gridStepInc = data.radius / gridStepsCount;
47
+ const gridSteps = range(gridStepInc, data.radius + gridStepInc, gridStepInc);
48
+ gridSteps.forEach((gridStep) => {
49
+ const gridLines = {
50
+ path: [],
51
+ strokeColor: axisStrokeColor,
52
+ strokeWidth: axisStrokeWidth,
53
+ };
54
+ categories.forEach((_category, index) => {
55
+ const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
56
+ gridLines.path.push([
57
+ center[0] + Math.cos(angle) * gridStep,
58
+ center[1] + Math.sin(angle) * gridStep,
59
+ ]);
60
+ });
61
+ data.grid.push(gridLines);
62
+ });
63
+ const radarAreaLine = line().curve(curveLinearClosed);
64
+ preparedSeries.forEach((series) => {
65
+ var _a;
66
+ const { dataLabels } = series;
67
+ const markers = [];
68
+ categories.forEach((category, index) => {
69
+ var _a;
70
+ const dataItem = series.data[index];
71
+ const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
72
+ const pointValueScale = scaleLinear()
73
+ .domain([
74
+ 0,
75
+ (_a = category.maxValue) !== null && _a !== void 0 ? _a : Math.max(...preparedSeries.map((s) => s.data[index].value)),
76
+ ])
77
+ .range([0, radius]);
78
+ const pointRadius = pointValueScale(dataItem.value);
79
+ const x = center[0] + Math.cos(angle) * pointRadius;
80
+ const y = center[1] + Math.sin(angle) * pointRadius;
81
+ markers.push({
82
+ point: {
83
+ x,
84
+ y,
85
+ series,
86
+ data: dataItem,
87
+ },
88
+ index,
89
+ position: [x, y],
90
+ color: series.color,
91
+ opacity: 1,
92
+ radius: 2,
93
+ data: dataItem,
94
+ series: series,
95
+ hovered: false,
96
+ active: false,
97
+ });
98
+ });
99
+ data.shapes.push({
100
+ borderWidth: series.borderWidth,
101
+ borderColor: series.borderColor,
102
+ fillOpacity: series.fillOpacity,
103
+ points: markers,
104
+ path: (_a = radarAreaLine(markers.map((p) => p.position))) !== null && _a !== void 0 ? _a : '',
105
+ series: series,
106
+ color: series.color,
107
+ hovered: false,
108
+ active: true,
109
+ });
110
+ // Create labels if enabled
111
+ if (dataLabels.enabled) {
112
+ const { style } = dataLabels;
113
+ const shouldUseHtml = dataLabels.html;
114
+ data.labels = categories.map((category, index) => {
115
+ const text = category.key;
116
+ const labelSize = getLabelsSize({ labels: [text], style });
117
+ const angle = index * angleStep - Math.PI / 2;
118
+ // Position label slightly outside the point
119
+ const labelRadius = data.radius + 10;
120
+ let x = center[0] + Math.cos(angle) * labelRadius;
121
+ let y = center[1] + Math.sin(angle) * labelRadius;
122
+ if (shouldUseHtml) {
123
+ x = x < center[0] ? x - labelSize.maxWidth : x;
124
+ y = y - labelSize.maxHeight;
125
+ }
126
+ else {
127
+ y = y < center[1] ? y - labelSize.maxHeight : y;
128
+ }
129
+ x = Math.max(-boundsWidth / 2, x);
130
+ return {
131
+ text,
132
+ x,
133
+ y,
134
+ style,
135
+ size: { width: labelSize.maxWidth, height: labelSize.maxHeight },
136
+ maxWidth: labelSize.maxWidth,
137
+ textAnchor: angle > Math.PI / 2 && angle < (3 * Math.PI) / 2 ? 'end' : 'start',
138
+ series: { id: series.id },
139
+ };
140
+ });
141
+ // Create HTML labels if needed
142
+ if (dataLabels.html) {
143
+ data.htmlLabels = data.labels.map((label) => ({
144
+ x: label.x,
145
+ y: label.y,
146
+ content: label.text,
147
+ size: label.size,
148
+ }));
149
+ }
150
+ }
151
+ return data;
152
+ });
153
+ result.push(data);
154
+ return result;
155
+ }
@@ -0,0 +1,58 @@
1
+ import type { HtmlItem, LabelData, RadarSeriesData } from '../../../types';
2
+ import type { PreparedRadarSeries } from '../../useSeries/types';
3
+ export type RadarLabelData = LabelData & {
4
+ maxWidth: number;
5
+ };
6
+ export type RadarAxisData = {
7
+ point: [number, number];
8
+ angle: number;
9
+ strokeColor: string;
10
+ strokeWidth: number;
11
+ radar: PreparedRadarData;
12
+ };
13
+ export type RadarGridData = {
14
+ path: [number, number][];
15
+ strokeColor: string;
16
+ strokeWidth: number;
17
+ };
18
+ export type PointData = {
19
+ x: number;
20
+ y: number;
21
+ data: RadarSeriesData;
22
+ series: PreparedRadarSeries;
23
+ };
24
+ export type RadarMarkerData = {
25
+ point: PointData;
26
+ radius: number;
27
+ position: [number, number];
28
+ index: number;
29
+ color: string;
30
+ opacity: number;
31
+ data: RadarSeriesData;
32
+ series: PreparedRadarSeries;
33
+ hovered: boolean;
34
+ active: boolean;
35
+ };
36
+ export type RadarShapeData = {
37
+ points: RadarMarkerData[];
38
+ path: string;
39
+ color: string;
40
+ series: PreparedRadarSeries;
41
+ hovered: boolean;
42
+ active: boolean;
43
+ borderColor: string;
44
+ borderWidth: number;
45
+ fillOpacity: number;
46
+ };
47
+ export type PreparedRadarData = {
48
+ type: 'radar';
49
+ id: string;
50
+ shapes: RadarShapeData[];
51
+ labels: RadarLabelData[];
52
+ axes: RadarAxisData[];
53
+ grid: RadarGridData[];
54
+ center: [number, number];
55
+ radius: number;
56
+ htmlLabels: HtmlItem[];
57
+ cursor: string | null;
58
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -6,7 +6,7 @@ import { HtmlLayer } from '../HtmlLayer';
6
6
  import { getMarkerHaloVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
7
  import { setActiveState, shapeKey } from '../utils';
8
8
  export { prepareScatterData } from './prepare-data';
9
- const b = block('d3-scatter');
9
+ const b = block('scatter');
10
10
  export function ScatterSeriesShape(props) {
11
11
  const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
12
12
  const hoveredDataRef = React.useRef(null);
@@ -1,17 +1,21 @@
1
- .gcharts-d3-scatter__point {
1
+ .gcharts-scatter__point {
2
2
  stroke-width: 1px;
3
3
  }
4
4
 
5
- .gcharts-d3-pie__segment {
5
+ .gcharts-pie__segment {
6
6
  stroke: var(--g-color-base-background);
7
7
  }
8
- .gcharts-d3-pie__label {
8
+ .gcharts-pie__label {
9
9
  font-size: 11px;
10
10
  font-weight: bold;
11
11
  fill: var(--g-color-text-complementary);
12
12
  alignment-baseline: before-edge;
13
13
  }
14
14
 
15
+ .gcharts-radar__label {
16
+ alignment-baseline: before-edge;
17
+ }
18
+
15
19
  .gcharts-bar-x__label {
16
20
  user-select: none;
17
21
  fill: var(--g-color-text-complementary);
@@ -23,13 +27,13 @@
23
27
  alignment-baseline: after-edge;
24
28
  }
25
29
 
26
- .gcharts-d3-treemap__label {
30
+ .gcharts-treemap__label {
27
31
  user-select: none;
28
32
  pointer-events: none;
29
33
  fill: var(--g-color-text-complementary);
30
34
  alignment-baseline: text-before-edge;
31
35
  }
32
36
 
33
- .gcharts-d3-waterfall__connector {
37
+ .gcharts-waterfall__connector {
34
38
  stroke: var(--g-color-line-generic-active);
35
39
  }
@@ -3,7 +3,7 @@ import { color, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block, setEllipsisForOverflowTexts } from '../../../utils';
5
5
  import { HtmlLayer } from '../HtmlLayer';
6
- const b = block('d3-treemap');
6
+ const b = block('treemap');
7
7
  export const TreemapSeriesShape = (props) => {
8
8
  const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
9
9
  const hoveredDataRef = React.useRef(null);
@@ -6,7 +6,7 @@ import { block, filterOverlappingLabels, getLineDashArray, getWaterfallPointColo
6
6
  import { HtmlLayer } from '../HtmlLayer';
7
7
  export { prepareWaterfallData } from './prepare-data';
8
8
  export * from './types';
9
- const b = block('d3-waterfall');
9
+ const b = block('waterfall');
10
10
  export const WaterfallSeriesShapes = (args) => {
11
11
  const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
12
12
  const hoveredDataRef = React.useRef(null);
@@ -1,3 +1,3 @@
1
1
  export { CustomShapeRenderer } from './utils';
2
2
  export * from './components';
3
- export type { ChartData } from './types';
3
+ export * from './types';
package/dist/cjs/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { CustomShapeRenderer } from './utils';
2
2
  export * from './components';
3
+ export * from './types';
@@ -73,6 +73,8 @@ export interface ChartAxis {
73
73
  * Defaults to 0.05 for Y axis and to 0.01 for X axis.
74
74
  * */
75
75
  maxPadding?: number;
76
+ /** An array of lines stretching across the plot area, marking a specific value */
77
+ plotLines?: AxisPlotLine[];
76
78
  }
77
79
  export interface ChartXAxis extends ChartAxis {
78
80
  }
@@ -105,6 +107,4 @@ export interface ChartYAxis extends ChartAxis {
105
107
  /** Property for splitting charts. Determines which area the axis is located in.
106
108
  * */
107
109
  plotIndex?: number;
108
- /** An array of lines stretching across the plot area, marking a specific value */
109
- plotLines?: AxisPlotLine[];
110
110
  }