@gravity-ui/chartkit 4.14.0 → 4.16.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 (71) hide show
  1. package/build/constants/index.d.ts +1 -0
  2. package/build/constants/index.js +1 -0
  3. package/build/constants/widget-data.d.ts +34 -0
  4. package/build/constants/widget-data.js +37 -0
  5. package/build/plugins/d3/examples/ExampleWrapper.d.ts +7 -0
  6. package/build/plugins/d3/examples/ExampleWrapper.js +5 -0
  7. package/build/plugins/d3/examples/area/Basic.js +3 -4
  8. package/build/plugins/d3/examples/area/StackedArea.js +3 -4
  9. package/build/plugins/d3/examples/bar-x/Basic.js +8 -4
  10. package/build/plugins/d3/examples/bar-x/DataLabels.js +4 -2
  11. package/build/plugins/d3/examples/bar-x/GroupedColumns.js +4 -2
  12. package/build/plugins/d3/examples/bar-x/StackedColumns.js +4 -2
  13. package/build/plugins/d3/examples/bar-y/Basic.js +4 -2
  14. package/build/plugins/d3/examples/bar-y/GroupedColumns.js +4 -2
  15. package/build/plugins/d3/examples/bar-y/StackedColumns.js +4 -2
  16. package/build/plugins/d3/examples/combined/LineAndBarX.js +5 -3
  17. package/build/plugins/d3/examples/line/Basic.js +4 -2
  18. package/build/plugins/d3/examples/line/DataLabels.js +4 -2
  19. package/build/plugins/d3/examples/line/LineWithMarkers.js +4 -2
  20. package/build/plugins/d3/examples/line/Shapes.d.ts +2 -0
  21. package/build/plugins/d3/examples/line/Shapes.js +93 -0
  22. package/build/plugins/d3/examples/pie/Basic.js +4 -2
  23. package/build/plugins/d3/examples/pie/Donut.js +4 -2
  24. package/build/plugins/d3/examples/scatter/Basic.js +4 -2
  25. package/build/plugins/d3/renderer/components/Legend.js +23 -1
  26. package/build/plugins/d3/renderer/components/styles.css +4 -0
  27. package/build/plugins/d3/renderer/hooks/useSeries/constants.d.ts +2 -3
  28. package/build/plugins/d3/renderer/hooks/useSeries/constants.js +1 -1
  29. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line-series.d.ts +2 -0
  30. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line-series.js +11 -0
  31. package/build/plugins/d3/renderer/hooks/useSeries/prepare-pie.d.ts +2 -1
  32. package/build/plugins/d3/renderer/hooks/useSeries/prepare-pie.js +11 -1
  33. package/build/plugins/d3/renderer/hooks/useSeries/prepareSeries.js +8 -5
  34. package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +23 -12
  35. package/build/plugins/d3/renderer/hooks/useSeries/utils.d.ts +2 -1
  36. package/build/plugins/d3/renderer/hooks/useSeries/utils.js +5 -6
  37. package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +5 -62
  38. package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +9 -65
  39. package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +5 -2
  40. package/build/plugins/d3/renderer/hooks/useShapes/line/types.d.ts +3 -0
  41. package/build/plugins/d3/renderer/hooks/useShapes/marker.d.ts +12 -0
  42. package/build/plugins/d3/renderer/hooks/useShapes/marker.js +70 -0
  43. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.d.ts +3 -2
  44. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.js +28 -0
  45. package/build/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.js +9 -3
  46. package/build/plugins/d3/renderer/hooks/useShapes/pie/types.d.ts +5 -0
  47. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +16 -9
  48. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.d.ts +1 -0
  49. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +3 -0
  50. package/build/plugins/d3/renderer/hooks/useShapes/utils.d.ts +2 -0
  51. package/build/plugins/d3/renderer/hooks/useShapes/utils.js +17 -0
  52. package/build/plugins/d3/renderer/utils/index.d.ts +1 -0
  53. package/build/plugins/d3/renderer/utils/index.js +1 -0
  54. package/build/plugins/d3/renderer/utils/symbol.d.ts +5 -0
  55. package/build/plugins/d3/renderer/utils/symbol.js +36 -0
  56. package/build/plugins/d3/renderer/validation/index.js +2 -8
  57. package/build/plugins/highcharts/renderer/helpers/config/config.js +0 -3
  58. package/build/types/widget-data/area.d.ts +2 -1
  59. package/build/types/widget-data/bar-x.d.ts +2 -1
  60. package/build/types/widget-data/bar-y.d.ts +2 -1
  61. package/build/types/widget-data/halo.d.ts +9 -0
  62. package/build/types/widget-data/halo.js +1 -0
  63. package/build/types/widget-data/index.d.ts +1 -0
  64. package/build/types/widget-data/index.js +1 -0
  65. package/build/types/widget-data/legend.d.ts +8 -0
  66. package/build/types/widget-data/line.d.ts +6 -1
  67. package/build/types/widget-data/marker.d.ts +0 -8
  68. package/build/types/widget-data/pie.d.ts +2 -1
  69. package/build/types/widget-data/scatter.d.ts +3 -2
  70. package/build/types/widget-data/series.d.ts +19 -4
  71. package/package.json +8 -2
@@ -1,7 +1,8 @@
1
- import { PieSeries } from '../../../../../types';
1
+ import { ChartKitWidgetSeriesOptions, PieSeries } from '../../../../../types';
2
2
  import { PreparedLegend, PreparedSeries } from './types';
3
3
  type PreparePieSeriesArgs = {
4
4
  series: PieSeries;
5
+ seriesOptions?: ChartKitWidgetSeriesOptions;
5
6
  legend: PreparedLegend;
6
7
  };
7
8
  export declare function preparePieSeries(args: PreparePieSeriesArgs): PreparedSeries[];
@@ -5,10 +5,11 @@ import get from 'lodash/get';
5
5
  import { DEFAULT_DATALABELS_PADDING, DEFAULT_DATALABELS_STYLE } from './constants';
6
6
  import { prepareLegendSymbol } from './utils';
7
7
  export function preparePieSeries(args) {
8
- const { series, legend } = args;
8
+ const { series, seriesOptions, legend } = args;
9
9
  const dataNames = series.data.map((d) => d.name);
10
10
  const colorScale = scaleOrdinal(dataNames, DEFAULT_PALETTE);
11
11
  const stackId = getRandomCKId();
12
+ const seriesHoverState = get(seriesOptions, 'pie.states.hover');
12
13
  const preparedSeries = series.data.map((dataItem) => {
13
14
  var _a, _b, _c;
14
15
  const result = {
@@ -41,6 +42,15 @@ export function preparePieSeries(args) {
41
42
  radius: series.radius || '100%',
42
43
  innerRadius: series.innerRadius || 0,
43
44
  stackId,
45
+ states: {
46
+ hover: {
47
+ halo: {
48
+ enabled: get(seriesHoverState, 'halo.enabled', true),
49
+ opacity: get(seriesHoverState, 'halo.opacity', 0.25),
50
+ size: get(seriesHoverState, 'halo.size', 10),
51
+ },
52
+ },
53
+ },
44
54
  };
45
55
  return result;
46
56
  });
@@ -1,5 +1,6 @@
1
1
  import cloneDeep from 'lodash/cloneDeep';
2
2
  import get from 'lodash/get';
3
+ import { getSymbolType } from '../../utils';
3
4
  import { prepareLineSeries } from './prepare-line-series';
4
5
  import { prepareBarXSeries } from './prepare-bar-x';
5
6
  import { prepareBarYSeries } from './prepare-bar-y';
@@ -8,15 +9,17 @@ import { ChartKitError } from '../../../../../libs';
8
9
  import { preparePieSeries } from './prepare-pie';
9
10
  import { prepareArea } from './prepare-area';
10
11
  function prepareAxisRelatedSeries(args) {
11
- const { colorScale, series, legend } = args;
12
+ const { colorScale, series, legend, index } = args;
12
13
  const preparedSeries = cloneDeep(series);
13
14
  const name = 'name' in series && series.name ? series.name : '';
15
+ const symbolType = (series.symbolType || getSymbolType(index));
16
+ preparedSeries.symbolType = symbolType;
14
17
  preparedSeries.color = 'color' in series && series.color ? series.color : colorScale(name);
15
18
  preparedSeries.name = name;
16
19
  preparedSeries.visible = get(preparedSeries, 'visible', true);
17
20
  preparedSeries.legend = {
18
21
  enabled: get(preparedSeries, 'legend.enabled', legend.enabled),
19
- symbol: prepareLegendSymbol(series),
22
+ symbol: prepareLegendSymbol(series, symbolType),
20
23
  };
21
24
  return [preparedSeries];
22
25
  }
@@ -25,7 +28,7 @@ export function prepareSeries(args) {
25
28
  switch (type) {
26
29
  case 'pie': {
27
30
  return series.reduce((acc, singleSeries) => {
28
- acc.push(...preparePieSeries({ series: singleSeries, legend }));
31
+ acc.push(...preparePieSeries({ series: singleSeries, seriesOptions, legend }));
29
32
  return acc;
30
33
  }, []);
31
34
  }
@@ -36,8 +39,8 @@ export function prepareSeries(args) {
36
39
  return prepareBarYSeries({ series: series, legend, colorScale });
37
40
  }
38
41
  case 'scatter': {
39
- return series.reduce((acc, singleSeries) => {
40
- acc.push(...prepareAxisRelatedSeries({ series: singleSeries, legend, colorScale }));
42
+ return series.reduce((acc, singleSeries, index) => {
43
+ acc.push(...prepareAxisRelatedSeries({ series: singleSeries, legend, colorScale, index }));
41
44
  return acc;
42
45
  }, []);
43
46
  }
@@ -1,5 +1,6 @@
1
- import { BarXSeries, BarXSeriesData, BaseTextStyle, ChartKitWidgetLegend, PieSeries, PieSeriesData, RectLegendSymbolOptions, ScatterSeries, ScatterSeriesData, BarYSeries, BarYSeriesData, LineSeries, LineSeriesData, ConnectorShape, ConnectorCurve, PathLegendSymbolOptions, AreaSeries, AreaSeriesData } from '../../../../../types';
1
+ import { BarXSeries, BarXSeriesData, BaseTextStyle, ChartKitWidgetLegend, PieSeries, PieSeriesData, RectLegendSymbolOptions, ScatterSeries, ScatterSeriesData, BarYSeries, BarYSeriesData, LineSeries, LineSeriesData, ConnectorShape, ConnectorCurve, PathLegendSymbolOptions, SymbolLegendSymbolOptions, AreaSeries, AreaSeriesData } from '../../../../../types';
2
2
  import type { SeriesOptionsDefaults } from '../../constants';
3
+ import { DashStyle, LineCap, SymbolType } from '../../../../../constants';
3
4
  export type RectLegendSymbol = {
4
5
  shape: 'rect';
5
6
  } & Required<RectLegendSymbolOptions>;
@@ -7,7 +8,11 @@ export type PathLegendSymbol = {
7
8
  shape: 'path';
8
9
  strokeWidth: number;
9
10
  } & Required<PathLegendSymbolOptions>;
10
- export type PreparedLegendSymbol = RectLegendSymbol | PathLegendSymbol;
11
+ export type SymbolLegendSymbol = {
12
+ shape: 'symbol';
13
+ symbolType: SymbolType;
14
+ } & Required<SymbolLegendSymbolOptions>;
15
+ export type PreparedLegendSymbol = RectLegendSymbol | PathLegendSymbol | SymbolLegendSymbol;
11
16
  export type PreparedLegend = Required<ChartKitWidgetLegend> & {
12
17
  height: number;
13
18
  lineHeight: number;
@@ -22,6 +27,7 @@ export type LegendItem = {
22
27
  symbol: PreparedLegendSymbol;
23
28
  textWidth: number;
24
29
  visible?: boolean;
30
+ dashStyle?: DashStyle;
25
31
  };
26
32
  export type LegendConfig = {
27
33
  offset: {
@@ -33,6 +39,11 @@ export type LegendConfig = {
33
39
  maxPage: number;
34
40
  };
35
41
  };
42
+ export type PreparedHaloOptions = {
43
+ enabled: boolean;
44
+ opacity: number;
45
+ size: number;
46
+ };
36
47
  type BasePreparedSeries = {
37
48
  color: string;
38
49
  name: string;
@@ -46,6 +57,7 @@ type BasePreparedSeries = {
46
57
  export type PreparedScatterSeries = {
47
58
  type: ScatterSeries['type'];
48
59
  data: ScatterSeriesData[];
60
+ symbolType: SymbolType;
49
61
  } & BasePreparedSeries;
50
62
  export type PreparedBarXSeries = {
51
63
  type: BarXSeries['type'];
@@ -93,6 +105,11 @@ export type PreparedPieSeries = {
93
105
  distance: number;
94
106
  connectorCurve: ConnectorCurve;
95
107
  };
108
+ states: {
109
+ hover: {
110
+ halo: PreparedHaloOptions;
111
+ };
112
+ };
96
113
  } & BasePreparedSeries;
97
114
  export type PreparedLineSeries = {
98
115
  type: LineSeries['type'];
@@ -118,14 +135,12 @@ export type PreparedLineSeries = {
118
135
  radius: number;
119
136
  borderWidth: number;
120
137
  borderColor: string;
121
- halo: {
122
- enabled: boolean;
123
- opacity: number;
124
- radius: number;
125
- };
138
+ halo: PreparedHaloOptions;
126
139
  };
127
140
  };
128
141
  };
142
+ dashStyle: DashStyle;
143
+ linecap: LineCap;
129
144
  } & BasePreparedSeries;
130
145
  export type PreparedAreaSeries = {
131
146
  type: AreaSeries['type'];
@@ -154,11 +169,7 @@ export type PreparedAreaSeries = {
154
169
  radius: number;
155
170
  borderWidth: number;
156
171
  borderColor: string;
157
- halo: {
158
- enabled: boolean;
159
- opacity: number;
160
- radius: number;
161
- };
172
+ halo: PreparedHaloOptions;
162
173
  };
163
174
  };
164
175
  };
@@ -1,6 +1,7 @@
1
1
  import { PreparedLegendSymbol, PreparedSeries, StackedSeries } from './types';
2
2
  import { ChartKitWidgetSeries } from '../../../../../types';
3
+ import { SymbolType } from '../../../../../constants';
3
4
  export declare const getActiveLegendItems: (series: PreparedSeries[]) => string[];
4
5
  export declare const getAllLegendItems: (series: PreparedSeries[]) => string[];
5
- export declare function prepareLegendSymbol(series: ChartKitWidgetSeries): PreparedLegendSymbol;
6
+ export declare function prepareLegendSymbol(series: ChartKitWidgetSeries, symbolType?: SymbolType): PreparedLegendSymbol;
6
7
  export declare function getSeriesStackId(series: StackedSeries): string;
@@ -1,6 +1,7 @@
1
1
  import memoize from 'lodash/memoize';
2
- import { DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_LEGEND_SYMBOL_SIZE } from './constants';
3
2
  import { getRandomCKId } from '../../../../../utils';
3
+ import { DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_LEGEND_SYMBOL_SIZE } from './constants';
4
+ import { SymbolType } from '../../../../../constants';
4
5
  export const getActiveLegendItems = (series) => {
5
6
  return series.reduce((acc, s) => {
6
7
  if (s.legend.enabled && s.visible) {
@@ -12,15 +13,13 @@ export const getActiveLegendItems = (series) => {
12
13
  export const getAllLegendItems = (series) => {
13
14
  return series.map((s) => s.name);
14
15
  };
15
- export function prepareLegendSymbol(series) {
16
+ export function prepareLegendSymbol(series, symbolType) {
16
17
  var _a;
17
18
  const symbolOptions = ((_a = series.legend) === null || _a === void 0 ? void 0 : _a.symbol) || {};
18
- const symbolHeight = (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.height) || DEFAULT_LEGEND_SYMBOL_SIZE;
19
19
  return {
20
- shape: 'rect',
20
+ shape: 'symbol',
21
+ symbolType: symbolType || SymbolType.Circle,
21
22
  width: (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.width) || DEFAULT_LEGEND_SYMBOL_SIZE,
22
- height: symbolHeight,
23
- radius: (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.radius) || symbolHeight / 2,
24
23
  padding: (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.padding) || DEFAULT_LEGEND_SYMBOL_PADDING,
25
24
  };
26
25
  }
@@ -1,43 +1,11 @@
1
1
  import React from 'react';
2
- import { color, line as lineGenerator, area as areaGenerator, select, symbol, symbolCircle, symbolSquare, } from 'd3';
2
+ import { color, line as lineGenerator, area as areaGenerator, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { filterOverlappingLabels } from '../../../utils';
6
6
  import { setActiveState } from '../utils';
7
+ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
8
  const b = block('d3-area');
8
- function setMarker(selection, state) {
9
- selection
10
- .attr('d', (d) => {
11
- const radius = d.point.series.marker.states[state].radius +
12
- d.point.series.marker.states[state].borderWidth;
13
- return getMarkerSymbol(d.point.series.marker.states.normal.symbol, radius);
14
- })
15
- .attr('stroke-width', (d) => d.point.series.marker.states[state].borderWidth)
16
- .attr('stroke', (d) => d.point.series.marker.states[state].borderColor);
17
- }
18
- function getMarkerSymbol(type, radius) {
19
- switch (type) {
20
- case 'square': {
21
- const size = Math.pow(radius, 2) * Math.PI;
22
- return symbol(symbolSquare, size)();
23
- }
24
- case 'circle':
25
- default: {
26
- const size = Math.pow(radius, 2) * Math.PI;
27
- return symbol(symbolCircle, size)();
28
- }
29
- }
30
- }
31
- const getMarkerVisibility = (d) => {
32
- const markerStates = d.point.series.marker.states;
33
- const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled;
34
- return enabled ? '' : 'hidden';
35
- };
36
- const getMarkerHaloVisibility = (d) => {
37
- const markerStates = d.point.series.marker.states;
38
- const enabled = markerStates.hover.halo.enabled && d.hovered;
39
- return enabled ? '' : 'hidden';
40
- };
41
9
  export const AreaSeriesShapes = (args) => {
42
10
  const { dispatcher, preparedData, seriesOptions } = args;
43
11
  const ref = React.useRef(null);
@@ -100,28 +68,7 @@ export const AreaSeriesShapes = (args) => {
100
68
  .selectAll('marker')
101
69
  .data(markers)
102
70
  .join('g')
103
- .attr('class', b('marker'))
104
- .attr('visibility', getMarkerVisibility)
105
- .attr('transform', (d) => {
106
- return `translate(${d.point.x},${d.point.y})`;
107
- });
108
- markerSelection
109
- .append('path')
110
- .attr('class', b('marker-halo'))
111
- .attr('d', (d) => {
112
- const type = d.point.series.marker.states.normal.symbol;
113
- const radius = d.point.series.marker.states.hover.halo.radius;
114
- return getMarkerSymbol(type, radius);
115
- })
116
- .attr('fill', (d) => d.point.series.color)
117
- .attr('opacity', (d) => d.point.series.marker.states.hover.halo.opacity)
118
- .attr('z-index', -1)
119
- .attr('visibility', getMarkerHaloVisibility);
120
- markerSelection
121
- .append('path')
122
- .attr('class', b('marker-symbol'))
123
- .call(setMarker, 'normal')
124
- .attr('fill', (d) => d.point.series.color);
71
+ .call(renderMarker);
125
72
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
126
73
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
127
74
  dispatcher.on('hover-shape.area', (data) => {
@@ -165,12 +112,8 @@ export const AreaSeriesShapes = (args) => {
165
112
  if (d.hovered !== hovered) {
166
113
  d.hovered = hovered;
167
114
  elementSelection.attr('visibility', getMarkerVisibility(d));
168
- elementSelection
169
- .select(`.${b('marker-halo')}`)
170
- .attr('visibility', getMarkerHaloVisibility);
171
- elementSelection
172
- .select(`.${b('marker-symbol')}`)
173
- .call(setMarker, hovered ? 'hover' : 'normal');
115
+ selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
116
+ selectMarkerSymbol(elementSelection).call(setMarker, hovered ? 'hover' : 'normal');
174
117
  }
175
118
  if (d.point.series.marker.states.normal.enabled) {
176
119
  const isActive = Boolean(!inactiveEnabled ||
@@ -1,43 +1,11 @@
1
1
  import React from 'react';
2
- import { color, line as lineGenerator, select, symbol, symbolCircle, symbolSquare } from 'd3';
2
+ import { color, line as lineGenerator, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { filterOverlappingLabels } from '../../../utils';
6
- import { setActiveState } from '../utils';
6
+ import { getLineDashArray, setActiveState } from '../utils';
7
+ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
8
  const b = block('d3-line');
8
- function setMarker(selection, state) {
9
- selection
10
- .attr('d', (d) => {
11
- const radius = d.point.series.marker.states[state].radius +
12
- d.point.series.marker.states[state].borderWidth;
13
- return getMarkerSymbol(d.point.series.marker.states.normal.symbol, radius);
14
- })
15
- .attr('stroke-width', (d) => d.point.series.marker.states[state].borderWidth)
16
- .attr('stroke', (d) => d.point.series.marker.states[state].borderColor);
17
- }
18
- function getMarkerSymbol(type, radius) {
19
- switch (type) {
20
- case 'square': {
21
- const size = Math.pow(radius, 2) * Math.PI;
22
- return symbol(symbolSquare, size)();
23
- }
24
- case 'circle':
25
- default: {
26
- const size = Math.pow(radius, 2) * Math.PI;
27
- return symbol(symbolCircle, size)();
28
- }
29
- }
30
- }
31
- const getMarkerVisibility = (d) => {
32
- const markerStates = d.point.series.marker.states;
33
- const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled;
34
- return enabled ? '' : 'hidden';
35
- };
36
- const getMarkerHaloVisibility = (d) => {
37
- const markerStates = d.point.series.marker.states;
38
- const enabled = markerStates.hover.halo.enabled && d.hovered;
39
- return enabled ? '' : 'hidden';
40
- };
41
9
  export const LineSeriesShapes = (args) => {
42
10
  const { dispatcher, preparedData, seriesOptions } = args;
43
11
  const ref = React.useRef(null);
@@ -61,8 +29,9 @@ export const LineSeriesShapes = (args) => {
61
29
  .attr('fill', 'none')
62
30
  .attr('stroke', (d) => d.color)
63
31
  .attr('stroke-width', (d) => d.width)
64
- .attr('stroke-linejoin', 'round')
65
- .attr('stroke-linecap', 'round');
32
+ .attr('stroke-linejoin', (d) => d.linecap)
33
+ .attr('stroke-linecap', (d) => d.linecap)
34
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width));
66
35
  let dataLabels = preparedData.reduce((acc, d) => {
67
36
  return acc.concat(d.labels);
68
37
  }, []);
@@ -86,28 +55,7 @@ export const LineSeriesShapes = (args) => {
86
55
  .selectAll('marker')
87
56
  .data(markers)
88
57
  .join('g')
89
- .attr('class', b('marker'))
90
- .attr('visibility', getMarkerVisibility)
91
- .attr('transform', (d) => {
92
- return `translate(${d.point.x},${d.point.y})`;
93
- });
94
- markerSelection
95
- .append('path')
96
- .attr('class', b('marker-halo'))
97
- .attr('d', (d) => {
98
- const type = d.point.series.marker.states.normal.symbol;
99
- const radius = d.point.series.marker.states.hover.halo.radius;
100
- return getMarkerSymbol(type, radius);
101
- })
102
- .attr('fill', (d) => d.point.series.color)
103
- .attr('opacity', (d) => d.point.series.marker.states.hover.halo.opacity)
104
- .attr('z-index', -1)
105
- .attr('visibility', getMarkerHaloVisibility);
106
- markerSelection
107
- .append('path')
108
- .attr('class', b('marker-symbol'))
109
- .call(setMarker, 'normal')
110
- .attr('fill', (d) => d.point.series.color);
58
+ .call(renderMarker);
111
59
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
112
60
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
113
61
  dispatcher.on('hover-shape.line', (data) => {
@@ -150,12 +98,8 @@ export const LineSeriesShapes = (args) => {
150
98
  if (d.hovered !== hovered) {
151
99
  d.hovered = hovered;
152
100
  elementSelection.attr('visibility', getMarkerVisibility(d));
153
- elementSelection
154
- .select(`.${b('marker-halo')}`)
155
- .attr('visibility', getMarkerHaloVisibility);
156
- elementSelection
157
- .select(`.${b('marker-symbol')}`)
158
- .call(setMarker, hovered ? 'hover' : 'normal');
101
+ selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
102
+ selectMarkerSymbol(elementSelection).call(setMarker, hovered ? 'hover' : 'normal');
159
103
  }
160
104
  if (d.point.series.marker.states.normal.enabled) {
161
105
  const isActive = Boolean(!inactiveEnabled ||
@@ -51,7 +51,7 @@ export const prepareLineData = (args) => {
51
51
  hovered: false,
52
52
  }));
53
53
  }
54
- acc.push({
54
+ const result = {
55
55
  points,
56
56
  markers,
57
57
  labels,
@@ -61,7 +61,10 @@ export const prepareLineData = (args) => {
61
61
  hovered: false,
62
62
  active: true,
63
63
  id: s.id,
64
- });
64
+ dashStyle: s.dashStyle,
65
+ linecap: s.linecap,
66
+ };
67
+ acc.push(result);
65
68
  return acc;
66
69
  }, []);
67
70
  };
@@ -1,6 +1,7 @@
1
1
  import { PreparedLineSeries } from '../../useSeries/types';
2
2
  import { LineSeriesData } from '../../../../../../types';
3
3
  import { LabelData } from '../../../types';
4
+ import { DashStyle, LineCap } from '../../../../../../constants';
4
5
  export type PointData = {
5
6
  x: number;
6
7
  y: number;
@@ -22,4 +23,6 @@ export type PreparedLineData = {
22
23
  hovered: boolean;
23
24
  active: boolean;
24
25
  labels: LabelData[];
26
+ dashStyle: DashStyle;
27
+ linecap: LineCap;
25
28
  };
@@ -0,0 +1,12 @@
1
+ import { BaseType, Selection } from 'd3';
2
+ import { MarkerData as LineMarkerData } from './line/types';
3
+ import { MarkerData as AreaMarkerData } from './area/types';
4
+ type MarkerData = LineMarkerData | AreaMarkerData;
5
+ export declare function renderMarker<T extends MarkerData>(selection: Selection<BaseType | SVGGElement, T, SVGGElement, unknown>): Selection<SVGGElement | BaseType, T, SVGGElement, unknown>;
6
+ export declare function getMarkerVisibility(d: MarkerData): "" | "hidden";
7
+ export declare function getMarkerHaloVisibility(d: MarkerData): "" | "hidden";
8
+ export declare function setMarker<T extends BaseType, D extends MarkerData>(selection: Selection<T, D, BaseType | null, unknown>, state: 'normal' | 'hover'): void;
9
+ export declare function getMarkerSymbol(type: string, radius: number): string | null;
10
+ export declare function selectMarkerHalo<T>(parentSelection: Selection<BaseType, T, null, undefined>): Selection<BaseType, T, null, undefined>;
11
+ export declare function selectMarkerSymbol<T>(parentSelection: Selection<BaseType, T, null, undefined>): Selection<BaseType, T, null, undefined>;
12
+ export {};
@@ -0,0 +1,70 @@
1
+ import { symbol, symbolCircle, symbolSquare } from 'd3';
2
+ import { block } from '../../../../../utils/cn';
3
+ const b = block('d3-marker');
4
+ const haloClassName = b('halo');
5
+ const symbolClassName = b('symbol');
6
+ export function renderMarker(selection) {
7
+ const markerSelection = selection
8
+ .attr('class', b('wrapper'))
9
+ .attr('visibility', getMarkerVisibility)
10
+ .attr('transform', (d) => {
11
+ return `translate(${d.point.x},${d.point.y})`;
12
+ });
13
+ markerSelection
14
+ .append('path')
15
+ .attr('class', haloClassName)
16
+ .attr('d', (d) => {
17
+ const type = d.point.series.marker.states.normal.symbol;
18
+ const radius = d.point.series.marker.states.hover.halo.size;
19
+ return getMarkerSymbol(type, radius);
20
+ })
21
+ .attr('fill', (d) => d.point.series.color)
22
+ .attr('opacity', (d) => d.point.series.marker.states.hover.halo.opacity)
23
+ .attr('z-index', -1)
24
+ .attr('visibility', getMarkerHaloVisibility);
25
+ markerSelection
26
+ .append('path')
27
+ .attr('class', symbolClassName)
28
+ .call(setMarker, 'normal')
29
+ .attr('fill', (d) => d.point.series.color);
30
+ return markerSelection;
31
+ }
32
+ export function getMarkerVisibility(d) {
33
+ const markerStates = d.point.series.marker.states;
34
+ const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled;
35
+ return enabled ? '' : 'hidden';
36
+ }
37
+ export function getMarkerHaloVisibility(d) {
38
+ const markerStates = d.point.series.marker.states;
39
+ const enabled = markerStates.hover.halo.enabled && d.hovered;
40
+ return enabled ? '' : 'hidden';
41
+ }
42
+ export function setMarker(selection, state) {
43
+ selection
44
+ .attr('d', (d) => {
45
+ const radius = d.point.series.marker.states[state].radius +
46
+ d.point.series.marker.states[state].borderWidth;
47
+ return getMarkerSymbol(d.point.series.marker.states.normal.symbol, radius);
48
+ })
49
+ .attr('stroke-width', (d) => d.point.series.marker.states[state].borderWidth)
50
+ .attr('stroke', (d) => d.point.series.marker.states[state].borderColor);
51
+ }
52
+ export function getMarkerSymbol(type, radius) {
53
+ switch (type) {
54
+ case 'square': {
55
+ const size = Math.pow(radius, 2) * Math.PI;
56
+ return symbol(symbolSquare, size)();
57
+ }
58
+ case 'circle':
59
+ default: {
60
+ const size = Math.pow(radius, 2) * Math.PI;
61
+ return symbol(symbolCircle, size)();
62
+ }
63
+ }
64
+ }
65
+ export function selectMarkerHalo(parentSelection) {
66
+ return parentSelection.select(`.${haloClassName}`);
67
+ }
68
+ export function selectMarkerSymbol(parentSelection) {
69
+ return parentSelection.select(`.${symbolClassName}`);
70
+ }
@@ -1,12 +1,13 @@
1
1
  import React from 'react';
2
- import type { Dispatch } from 'd3';
2
+ import type { Dispatch, PieArcDatum } from 'd3';
3
3
  import { PreparedSeriesOptions } from '../../useSeries/types';
4
- import { PreparedPieData } from './types';
4
+ import { PreparedPieData, SegmentData } from './types';
5
5
  type PreparePieSeriesArgs = {
6
6
  dispatcher: Dispatch<object>;
7
7
  preparedData: PreparedPieData[];
8
8
  seriesOptions: PreparedSeriesOptions;
9
9
  svgContainer: SVGSVGElement | null;
10
10
  };
11
+ export declare function getHaloVisibility(d: PieArcDatum<SegmentData>): "" | "hidden";
11
12
  export declare function PieSeriesShapes(args: PreparePieSeriesArgs): React.JSX.Element;
12
13
  export {};
@@ -7,6 +7,10 @@ import { line as lineGenerator } from 'd3-shape';
7
7
  import { setEllipsisForOverflowTexts } from '../../../utils';
8
8
  import { getCurveFactory } from './utils';
9
9
  const b = block('d3-pie');
10
+ export function getHaloVisibility(d) {
11
+ const enabled = d.data.pie.halo.enabled && d.data.hovered;
12
+ return enabled ? '' : 'hidden';
13
+ }
10
14
  export function PieSeriesShapes(args) {
11
15
  const { dispatcher, preparedData, seriesOptions, svgContainer } = args;
12
16
  const ref = React.useRef(null);
@@ -30,6 +34,27 @@ export function PieSeriesShapes(args) {
30
34
  })
31
35
  .style('stroke', (pieData) => pieData.borderColor)
32
36
  .style('stroke-width', (pieData) => pieData.borderWidth);
37
+ shapesSelection
38
+ .selectAll('halo')
39
+ .data((pieData) => {
40
+ if (pieData.halo.enabled) {
41
+ return pieData.segments;
42
+ }
43
+ return [];
44
+ })
45
+ .join('path')
46
+ .attr('d', (d) => {
47
+ const arcGenerator = arc()
48
+ .innerRadius(d.data.pie.innerRadius)
49
+ .outerRadius(d.data.pie.radius + d.data.pie.halo.size)
50
+ .cornerRadius(d.data.pie.borderRadius);
51
+ return arcGenerator(d);
52
+ })
53
+ .attr('class', b('halo'))
54
+ .attr('fill', (d) => d.data.color)
55
+ .attr('opacity', (d) => d.data.pie.halo.opacity)
56
+ .attr('z-index', -1)
57
+ .attr('visibility', getHaloVisibility);
33
58
  shapesSelection
34
59
  .selectAll(segmentSelector)
35
60
  .data((pieData) => pieData.segments)
@@ -108,6 +133,7 @@ export function PieSeriesShapes(args) {
108
133
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
109
134
  shapesSelection.datum((_d, index, list) => {
110
135
  const pieSelection = select(list[index]);
136
+ const haloSelection = pieSelection.selectAll(`.${b('halo')}`);
111
137
  pieSelection
112
138
  .selectAll(segmentSelector)
113
139
  .datum((d, i, elements) => {
@@ -122,6 +148,8 @@ export function PieSeriesShapes(args) {
122
148
  }
123
149
  return initialColor;
124
150
  });
151
+ const currentSegmentHalo = haloSelection.nodes()[i];
152
+ select(currentSegmentHalo).attr('visibility', getHaloVisibility);
125
153
  }
126
154
  setActiveState({
127
155
  element: elements[i],
@@ -15,12 +15,13 @@ const getCenter = (boundsWidth, boundsHeight, center) => {
15
15
  return [resultX, resultY];
16
16
  };
17
17
  export function preparePieData(args) {
18
- const { series: prepapredSeries, boundsWidth, boundsHeight } = args;
18
+ const { series: preparedSeries, boundsWidth, boundsHeight } = args;
19
19
  const maxRadius = Math.min(boundsWidth, boundsHeight) / 2;
20
- const groupedPieSeries = group(prepapredSeries, (pieSeries) => pieSeries.stackId);
20
+ const groupedPieSeries = group(preparedSeries, (pieSeries) => pieSeries.stackId);
21
21
  return Array.from(groupedPieSeries).map(([stackId, items]) => {
22
22
  var _a, _b, _c;
23
- const { center, borderWidth, borderColor, borderRadius, radius: seriesRadius, innerRadius: seriesInnerRadius, dataLabels, } = items[0];
23
+ const series = items[0];
24
+ const { center, borderWidth, borderColor, borderRadius, radius: seriesRadius, innerRadius: seriesInnerRadius, dataLabels, } = series;
24
25
  const radius = (_a = calculateNumericProperty({ value: seriesRadius, base: maxRadius })) !== null && _a !== void 0 ? _a : maxRadius;
25
26
  const data = {
26
27
  id: stackId,
@@ -34,6 +35,11 @@ export function preparePieData(args) {
34
35
  borderRadius,
35
36
  series: items[0],
36
37
  connectorCurve: dataLabels.connectorCurve,
38
+ halo: {
39
+ enabled: series.states.hover.halo.enabled,
40
+ opacity: series.states.hover.halo.opacity,
41
+ size: series.states.hover.halo.size,
42
+ },
37
43
  };
38
44
  const segments = items.map((item) => {
39
45
  return {
@@ -31,4 +31,9 @@ export type PreparedPieData = {
31
31
  borderColor: string;
32
32
  series: PreparedPieSeries;
33
33
  connectorCurve: ConnectorCurve;
34
+ halo: {
35
+ enabled: boolean;
36
+ opacity: number;
37
+ size: number;
38
+ };
34
39
  };