@gravity-ui/chartkit 5.0.0 → 5.2.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 (44) hide show
  1. package/build/plugins/d3/renderer/components/Chart.js +10 -0
  2. package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.js +17 -5
  3. package/build/plugins/d3/renderer/d3-dispatcher.js +1 -1
  4. package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +1 -0
  5. package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +1 -0
  6. package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.js +1 -0
  7. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.js +2 -0
  8. package/build/plugins/d3/renderer/hooks/useSeries/prepare-pie.js +2 -0
  9. package/build/plugins/d3/renderer/hooks/useSeries/prepare-scatter.js +1 -0
  10. package/build/plugins/d3/renderer/hooks/useSeries/prepare-treemap.js +3 -1
  11. package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +4 -1
  12. package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +2 -1
  13. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.js +3 -1
  14. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.js +1 -0
  15. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/types.d.ts +1 -0
  16. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/index.js +3 -1
  17. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.js +1 -0
  18. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/types.d.ts +1 -0
  19. package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +3 -1
  20. package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +1 -0
  21. package/build/plugins/d3/renderer/hooks/useShapes/line/types.d.ts +1 -0
  22. package/build/plugins/d3/renderer/hooks/useShapes/marker.js +8 -1
  23. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.js +20 -9
  24. package/build/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.js +1 -0
  25. package/build/plugins/d3/renderer/hooks/useShapes/pie/types.d.ts +1 -0
  26. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +13 -2
  27. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +2 -0
  28. package/build/plugins/d3/renderer/hooks/useShapes/scatter/types.d.ts +1 -0
  29. package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.js +12 -4
  30. package/build/plugins/highcharts/renderer/components/withSplitPane/withSplitPane.d.ts +1 -0
  31. package/build/plugins/highcharts/renderer/components/withSplitPane/withSplitPane.js +2 -0
  32. package/build/plugins/yagr/renderer/tooltip/renderTooltip.d.ts +2 -2
  33. package/build/plugins/yagr/renderer/tooltip/renderTooltip.js +23 -2
  34. package/build/plugins/yagr/renderer/utils.js +1 -1
  35. package/build/plugins/yagr/types.d.ts +12 -2
  36. package/build/types/widget-data/area.d.ts +15 -0
  37. package/build/types/widget-data/bar-x.d.ts +2 -0
  38. package/build/types/widget-data/bar-y.d.ts +2 -0
  39. package/build/types/widget-data/base.d.ts +2 -0
  40. package/build/types/widget-data/chart.d.ts +6 -0
  41. package/build/types/widget-data/line.d.ts +9 -0
  42. package/build/types/widget-data/pie.d.ts +2 -0
  43. package/build/types/widget-data/scatter.d.ts +3 -0
  44. package/package.json +4 -3
@@ -13,6 +13,7 @@ import { Tooltip, TooltipTriggerArea } from './Tooltip';
13
13
  import './styles.css';
14
14
  const b = block('d3');
15
15
  export const Chart = (props) => {
16
+ var _a, _b;
16
17
  const { width, height, data } = props;
17
18
  const svgRef = React.useRef(null);
18
19
  const dispatcher = React.useMemo(() => {
@@ -60,6 +61,15 @@ export const Chart = (props) => {
60
61
  yScale,
61
62
  svgContainer: svgRef.current,
62
63
  });
64
+ const clickHandler = (_b = (_a = data.chart) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.click;
65
+ React.useEffect(() => {
66
+ if (clickHandler) {
67
+ dispatcher.on('click-chart', clickHandler);
68
+ }
69
+ return () => {
70
+ dispatcher.on('click-chart', null);
71
+ };
72
+ }, [dispatcher, clickHandler]);
63
73
  const boundsOffsetTop = chart.margin.top;
64
74
  const boundsOffsetLeft = chart.margin.left + getWidthOccupiedByYAxis({ preparedAxis: yAxis });
65
75
  return (React.createElement(React.Fragment, null,
@@ -101,7 +101,7 @@ export const TooltipTriggerArea = (args) => {
101
101
  });
102
102
  return sort(result, (item) => item.y);
103
103
  }, [shapesData]);
104
- const handleMouseMove = (e) => {
104
+ const getShapeData = (point) => {
105
105
  var _a, _b;
106
106
  const { left: ownLeft, top: ownTop } = ((_a = rectRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) || {
107
107
  left: 0,
@@ -111,9 +111,9 @@ export const TooltipTriggerArea = (args) => {
111
111
  left: 0,
112
112
  top: 0,
113
113
  };
114
- const [pointerX, pointerY] = pointer(e, svgContainer);
115
- const hoverShapeData = [];
116
- hoverShapeData === null || hoverShapeData === void 0 ? void 0 : hoverShapeData.push(...getBarXShapeData({
114
+ const [pointerX, pointerY] = point; //pointer(e, svgContainer);
115
+ const result = [];
116
+ result === null || result === void 0 ? void 0 : result.push(...getBarXShapeData({
117
117
  shapesData,
118
118
  point: [pointerX, pointerY],
119
119
  left: ownLeft - containerLeft,
@@ -127,6 +127,11 @@ export const TooltipTriggerArea = (args) => {
127
127
  data: barYData,
128
128
  point: [pointerX - (ownLeft - containerLeft), pointerY - (ownTop - containerTop)],
129
129
  }));
130
+ return result;
131
+ };
132
+ const handleMouseMove = (e) => {
133
+ const [pointerX, pointerY] = pointer(e, svgContainer);
134
+ const hoverShapeData = getShapeData([pointerX, pointerY]);
130
135
  if (hoverShapeData.length) {
131
136
  const position = [pointerX, pointerY];
132
137
  dispatcher.call('hover-shape', e.target, hoverShapeData, position);
@@ -137,5 +142,12 @@ export const TooltipTriggerArea = (args) => {
137
142
  throttledHandleMouseMove.cancel();
138
143
  dispatcher.call('hover-shape', {}, undefined);
139
144
  };
140
- return (React.createElement("rect", { ref: rectRef, width: boundsWidth, height: boundsHeight, fill: "transparent", onMouseMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave }));
145
+ const handleClick = (e) => {
146
+ const [pointerX, pointerY] = pointer(e, svgContainer);
147
+ const shapeData = getShapeData([pointerX, pointerY]);
148
+ if (shapeData.length) {
149
+ dispatcher.call('click-chart', undefined, { point: get(shapeData, '[0].data'), series: get(shapeData, '[0].series') }, e);
150
+ }
151
+ };
152
+ return (React.createElement("rect", { ref: rectRef, width: boundsWidth, height: boundsHeight, fill: "transparent", onMouseMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave, onClick: handleClick }));
141
153
  };
@@ -1,4 +1,4 @@
1
1
  import { dispatch } from 'd3';
2
2
  export const getD3Dispatcher = () => {
3
- return dispatch('hover-shape');
3
+ return dispatch('hover-shape', 'click-chart');
4
4
  };
@@ -54,6 +54,7 @@ export function prepareArea(args) {
54
54
  allowOverlap: get(series, 'dataLabels.allowOverlap', false),
55
55
  },
56
56
  marker: prepareMarker(series, seriesOptions),
57
+ cursor: get(series, 'cursor', null),
57
58
  };
58
59
  return prepared;
59
60
  }, []);
@@ -30,6 +30,7 @@ export function prepareBarXSeries(args) {
30
30
  allowOverlap: ((_e = series.dataLabels) === null || _e === void 0 ? void 0 : _e.allowOverlap) || false,
31
31
  padding: get(series, 'dataLabels.padding', DEFAULT_DATALABELS_PADDING),
32
32
  },
33
+ cursor: get(series, 'cursor', null),
33
34
  };
34
35
  }, []);
35
36
  }
@@ -40,6 +40,7 @@ export function prepareBarYSeries(args) {
40
40
  stacking: series.stacking,
41
41
  stackId: getSeriesStackId(series),
42
42
  dataLabels: prepareDataLabels(series),
43
+ cursor: get(series, 'cursor', null),
43
44
  };
44
45
  }, []);
45
46
  }
@@ -72,6 +72,8 @@ export function prepareLineSeries(args) {
72
72
  marker: prepareMarker(series, seriesOptions),
73
73
  dashStyle: dashStyle,
74
74
  linecap: prepareLinecap(dashStyle, series, seriesOptions),
75
+ opacity: get(series, 'opacity', null),
76
+ cursor: get(series, 'cursor', null),
75
77
  };
76
78
  return prepared;
77
79
  }, []);
@@ -52,6 +52,8 @@ export function preparePieSeries(args) {
52
52
  },
53
53
  },
54
54
  renderCustomShape: series.renderCustomShape,
55
+ opacity: get(dataItem, 'opacity', null),
56
+ cursor: get(series, 'cursor', null),
55
57
  };
56
58
  return result;
57
59
  });
@@ -39,6 +39,7 @@ export function prepareScatterSeries(args) {
39
39
  },
40
40
  data: s.data,
41
41
  marker: prepareMarker(s, seriesOptions, index),
42
+ cursor: get(s, 'cursor', null),
42
43
  };
43
44
  return prepared;
44
45
  }, []);
@@ -10,7 +10,7 @@ export function prepareTreemap(args) {
10
10
  const id = getRandomCKId();
11
11
  const name = s.name || '';
12
12
  const color = s.color || colorScale(name);
13
- return {
13
+ const preparedSeries = {
14
14
  color,
15
15
  data: s.data,
16
16
  dataLabels: {
@@ -29,6 +29,8 @@ export function prepareTreemap(args) {
29
29
  },
30
30
  levels: s.levels,
31
31
  layoutAlgorithm: get(s, 'layoutAlgorithm', LayoutAlgorithm.Binary),
32
+ cursor: get(s, 'cursor', null),
32
33
  };
34
+ return preparedSeries;
33
35
  });
34
36
  }
@@ -53,6 +53,7 @@ type BasePreparedSeries = {
53
53
  enabled: boolean;
54
54
  symbol: PreparedLegendSymbol;
55
55
  };
56
+ cursor: string | null;
56
57
  };
57
58
  export type PreparedScatterSeries = {
58
59
  type: ScatterSeries['type'];
@@ -130,6 +131,7 @@ export type PreparedPieSeries = {
130
131
  };
131
132
  };
132
133
  renderCustomShape?: PieSeries['renderCustomShape'];
134
+ opacity: number | null;
133
135
  } & BasePreparedSeries;
134
136
  export type PreparedLineSeries = {
135
137
  type: LineSeries['type'];
@@ -161,6 +163,7 @@ export type PreparedLineSeries = {
161
163
  };
162
164
  dashStyle: DashStyle;
163
165
  linecap: LineCap;
166
+ opacity: number | null;
164
167
  } & BasePreparedSeries;
165
168
  export type PreparedAreaSeries = {
166
169
  type: AreaSeries['type'];
@@ -204,7 +207,7 @@ export type PreparedTreemapSeries = {
204
207
  allowOverlap: boolean;
205
208
  };
206
209
  layoutAlgorithm: `${LayoutAlgorithm}`;
207
- } & BasePreparedSeries & TreemapSeries;
210
+ } & BasePreparedSeries & Omit<TreemapSeries, keyof BasePreparedSeries>;
208
211
  export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries;
209
212
  export type PreparedSeriesOptions = SeriesOptionsDefaults;
210
213
  export type StackedSeries = BarXSeries | AreaSeries | BarYSeries;
@@ -25,7 +25,8 @@ export const AreaSeriesShapes = (args) => {
25
25
  .selectAll('shape')
26
26
  .data(preparedData)
27
27
  .join('g')
28
- .attr('class', b('series'));
28
+ .attr('class', b('series'))
29
+ .attr('cursor', (d) => d.series.cursor);
29
30
  shapeSelection
30
31
  .append('path')
31
32
  .attr('class', b('line'))
@@ -27,7 +27,9 @@ export const BarXSeriesShapes = (args) => {
27
27
  .attr('y', (d) => d.y)
28
28
  .attr('height', (d) => d.height)
29
29
  .attr('width', (d) => d.width)
30
- .attr('fill', (d) => d.data.color || d.series.color);
30
+ .attr('fill', (d) => d.data.color || d.series.color)
31
+ .attr('opacity', (d) => d.opacity)
32
+ .attr('cursor', (d) => d.series.cursor);
31
33
  let dataLabels = preparedData.map((d) => d.label).filter(Boolean);
32
34
  if (!((_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
33
35
  dataLabels = filterOverlappingLabels(dataLabels);
@@ -117,6 +117,7 @@ export const prepareBarXData = (args) => {
117
117
  y: y - stackHeight,
118
118
  width: rectWidth,
119
119
  height,
120
+ opacity: get(yValue.data, 'opacity', null),
120
121
  data: yValue.data,
121
122
  series: yValue.series,
122
123
  };
@@ -6,6 +6,7 @@ export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
6
6
  y: number;
7
7
  width: number;
8
8
  height: number;
9
+ opacity: number | null;
9
10
  series: PreparedBarXSeries;
10
11
  label?: LabelData;
11
12
  };
@@ -23,7 +23,9 @@ export const BarYSeriesShapes = (args) => {
23
23
  .attr('y', (d) => d.y)
24
24
  .attr('height', (d) => d.height)
25
25
  .attr('width', (d) => d.width)
26
- .attr('fill', (d) => d.color);
26
+ .attr('fill', (d) => d.color)
27
+ .attr('opacity', (d) => d.data.opacity || null)
28
+ .attr('cursor', (d) => d.series.cursor);
27
29
  const dataLabels = preparedData.filter((d) => d.series.dataLabels.enabled);
28
30
  const labelSelection = svgElement
29
31
  .selectAll('text')
@@ -104,6 +104,7 @@ export const prepareBarYData = (args) => {
104
104
  width,
105
105
  height: barHeight,
106
106
  color: data.color || s.color,
107
+ opacity: get(data, 'opacity', null),
107
108
  data,
108
109
  series: s,
109
110
  });
@@ -6,5 +6,6 @@ export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
6
6
  width: number;
7
7
  height: number;
8
8
  color: string;
9
+ opacity: number | null;
9
10
  series: PreparedBarYSeries;
10
11
  };
@@ -31,7 +31,9 @@ export const LineSeriesShapes = (args) => {
31
31
  .attr('stroke-width', (d) => d.width)
32
32
  .attr('stroke-linejoin', (d) => d.linecap)
33
33
  .attr('stroke-linecap', (d) => d.linecap)
34
- .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width));
34
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width))
35
+ .attr('opacity', (d) => d.opacity)
36
+ .attr('cursor', (d) => d.series.cursor);
35
37
  let dataLabels = preparedData.reduce((acc, d) => {
36
38
  return acc.concat(d.labels);
37
39
  }, []);
@@ -63,6 +63,7 @@ export const prepareLineData = (args) => {
63
63
  id: s.id,
64
64
  dashStyle: s.dashStyle,
65
65
  linecap: s.linecap,
66
+ opacity: s.opacity,
66
67
  };
67
68
  acc.push(result);
68
69
  return acc;
@@ -25,4 +25,5 @@ export type PreparedLineData = {
25
25
  labels: LabelData[];
26
26
  dashStyle: DashStyle;
27
27
  linecap: LineCap;
28
+ opacity: number | null;
28
29
  };
@@ -36,7 +36,14 @@ export function renderMarker(selection) {
36
36
  }
37
37
  export function getMarkerVisibility(d) {
38
38
  const markerStates = d.point.series.marker.states;
39
- const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled;
39
+ let enabled;
40
+ if (d.hovered) {
41
+ enabled = markerStates.hover.enabled && d.hovered;
42
+ }
43
+ else {
44
+ enabled =
45
+ markerStates.normal.enabled || get(d.point.data, 'marker.states.normal.enabled', false);
46
+ }
40
47
  return enabled ? '' : 'hidden';
41
48
  }
42
49
  export function getMarkerHaloVisibility(d) {
@@ -32,7 +32,8 @@ export function PieSeriesShapes(args) {
32
32
  return `translate(${x}, ${y})`;
33
33
  })
34
34
  .style('stroke', (pieData) => pieData.borderColor)
35
- .style('stroke-width', (pieData) => pieData.borderWidth);
35
+ .style('stroke-width', (pieData) => pieData.borderWidth)
36
+ .attr('cursor', (pieData) => pieData.series.cursor);
36
37
  // Render halo appearing outside the hovered slice
37
38
  shapesSelection
38
39
  .selectAll('halo')
@@ -68,7 +69,8 @@ export function PieSeriesShapes(args) {
68
69
  return arcGenerator(d);
69
70
  })
70
71
  .attr('class', b('segment'))
71
- .attr('fill', (d) => d.data.color);
72
+ .attr('fill', (d) => d.data.color)
73
+ .attr('opacity', (d) => d.data.opacity);
72
74
  shapesSelection
73
75
  .selectAll('text')
74
76
  .data((pieData) => pieData.labels)
@@ -114,17 +116,20 @@ export function PieSeriesShapes(args) {
114
116
  nodes[index].append(customShape);
115
117
  }
116
118
  });
119
+ const getSelectedSegment = (element) => {
120
+ const datum = select(element).datum();
121
+ const seriesId = get(datum, 'data.series.id', get(datum, 'series.id'));
122
+ return preparedData.reduce((result, pie) => {
123
+ var _a;
124
+ return result || ((_a = pie.segments.find((s) => s.data.series.id === seriesId)) === null || _a === void 0 ? void 0 : _a.data);
125
+ }, undefined);
126
+ };
117
127
  const eventName = `hover-shape.pie`;
118
128
  const hoverOptions = get(seriesOptions, 'pie.states.hover');
119
129
  const inactiveOptions = get(seriesOptions, 'pie.states.inactive');
120
130
  svgElement
121
131
  .on('mousemove', (e) => {
122
- const datum = select(e.target).datum();
123
- const seriesId = get(datum, 'data.series.id', get(datum, 'series.id'));
124
- const currentSegment = preparedData.reduce((result, pie) => {
125
- var _a;
126
- return (result || ((_a = pie.segments.find((s) => s.data.series.id === seriesId)) === null || _a === void 0 ? void 0 : _a.data));
127
- }, undefined);
132
+ const currentSegment = getSelectedSegment(e.target);
128
133
  if (currentSegment) {
129
134
  const data = {
130
135
  series: {
@@ -132,13 +137,19 @@ export function PieSeriesShapes(args) {
132
137
  type: 'pie',
133
138
  name: currentSegment.series.name,
134
139
  },
135
- data: currentSegment.series,
140
+ data: currentSegment.series.data,
136
141
  };
137
142
  dispatcher.call('hover-shape', {}, [data], pointer(e, svgContainer));
138
143
  }
139
144
  })
140
145
  .on('mouseleave', () => {
141
146
  dispatcher.call('hover-shape', {}, undefined);
147
+ })
148
+ .on('click', (e) => {
149
+ const selectedSegment = getSelectedSegment(e.target);
150
+ if (selectedSegment) {
151
+ dispatcher.call('click-chart', undefined, { point: selectedSegment.series.data, series: selectedSegment.series }, e);
152
+ }
142
153
  });
143
154
  dispatcher.on(eventName, (data) => {
144
155
  const selectedSeriesId = data === null || data === void 0 ? void 0 : data[0].series.id;
@@ -45,6 +45,7 @@ export function preparePieData(args) {
45
45
  return {
46
46
  value: item.value,
47
47
  color: item.color,
48
+ opacity: item.opacity,
48
49
  series: item,
49
50
  hovered: false,
50
51
  active: true,
@@ -5,6 +5,7 @@ import { PreparedPieSeries } from '../../useSeries/types';
5
5
  export type SegmentData = {
6
6
  value: number;
7
7
  color: string;
8
+ opacity: number | null;
8
9
  series: PreparedPieSeries;
9
10
  hovered: boolean;
10
11
  active: boolean;
@@ -22,10 +22,15 @@ export function ScatterSeriesShape(props) {
22
22
  .data(preparedData, shapeKey)
23
23
  .join('g')
24
24
  .call(renderMarker)
25
- .attr('fill', (d) => d.point.data.color || d.point.series.color || '');
25
+ .attr('fill', (d) => d.point.data.color || d.point.series.color || '')
26
+ .attr('opacity', (d) => d.point.opacity)
27
+ .attr('cursor', (d) => d.point.series.cursor);
28
+ const getSelectedPoint = (element) => {
29
+ return select(element).datum();
30
+ };
26
31
  svgElement
27
32
  .on('mousemove', (e) => {
28
- const datum = select(e.target).datum();
33
+ const datum = getSelectedPoint(e.target);
29
34
  if (!datum) {
30
35
  return;
31
36
  }
@@ -42,6 +47,12 @@ export function ScatterSeriesShape(props) {
42
47
  })
43
48
  .on('mouseleave', () => {
44
49
  dispatcher.call('hover-shape', {}, undefined);
50
+ })
51
+ .on('click', (e) => {
52
+ const datum = getSelectedPoint(e.target);
53
+ if (datum) {
54
+ dispatcher.call('click-chart', undefined, { point: datum.point.data, series: datum.point.series }, e);
55
+ }
45
56
  });
46
57
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
47
58
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
@@ -1,3 +1,4 @@
1
+ import get from 'lodash/get';
1
2
  import { getXValue, getYValue } from '../utils';
2
3
  const getFilteredLinearScatterData = (data) => {
3
4
  return data.filter((d) => typeof d.x === 'number' && typeof d.y === 'number');
@@ -15,6 +16,7 @@ export const prepareScatterData = (args) => {
15
16
  series: s,
16
17
  x: getXValue({ point: d, xAxis, xScale }),
17
18
  y: getYValue({ point: d, yAxis, yScale }),
19
+ opacity: get(d, 'opacity', null),
18
20
  },
19
21
  hovered: false,
20
22
  active: true,
@@ -3,6 +3,7 @@ import { PreparedScatterSeries } from '../../useSeries/types';
3
3
  type PointData = {
4
4
  x: number;
5
5
  y: number;
6
+ opacity: number | null;
6
7
  data: ScatterSeriesData;
7
8
  series: PreparedScatterSeries;
8
9
  };
@@ -18,7 +18,8 @@ export const TreemapSeriesShape = (props) => {
18
18
  .selectAll('g')
19
19
  .data(leaves)
20
20
  .join('g')
21
- .attr('transform', (d) => `translate(${d.x0},${d.y0})`);
21
+ .attr('transform', (d) => `translate(${d.x0},${d.y0})`)
22
+ .attr('cursor', series.cursor);
22
23
  const rectSelection = leaf
23
24
  .append('rect')
24
25
  .attr('id', (d) => d.id || d.name)
@@ -44,17 +45,24 @@ export const TreemapSeriesShape = (props) => {
44
45
  .style('font-weight', () => { var _a; return ((_a = series.dataLabels.style) === null || _a === void 0 ? void 0 : _a.fontWeight) || null; })
45
46
  .style('fill', () => { var _a; return ((_a = series.dataLabels.style) === null || _a === void 0 ? void 0 : _a.fontColor) || null; })
46
47
  .call(setEllipsisForOverflowTexts, (d) => d.width);
47
- const eventName = `hover-shape.pie`;
48
+ const getSelectedPart = (node) => {
49
+ const hoveredRect = select(node);
50
+ return hoveredRect.datum();
51
+ };
52
+ const eventName = `hover-shape.treemap`;
48
53
  const hoverOptions = get(seriesOptions, 'treemap.states.hover');
49
54
  const inactiveOptions = get(seriesOptions, 'treemap.states.inactive');
50
55
  svgElement
51
56
  .on('mousemove', (e) => {
52
- const hoveredRect = select(e.target);
53
- const datum = hoveredRect.datum();
57
+ const datum = getSelectedPart(e.target);
54
58
  dispatcher.call('hover-shape', {}, [{ data: datum.data, series }], pointer(e, svgContainer));
55
59
  })
56
60
  .on('mouseleave', () => {
57
61
  dispatcher.call('hover-shape', {}, undefined);
62
+ })
63
+ .on('click', (e) => {
64
+ const datum = getSelectedPart(e.target);
65
+ dispatcher.call('click-chart', undefined, { point: datum.data, series }, e);
58
66
  });
59
67
  dispatcher.on(eventName, (data) => {
60
68
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
@@ -7,4 +7,5 @@ export declare const withSplitPane: <ComposedComponentProps extends {}>(Composed
7
7
  } & {
8
8
  current: any;
9
9
  forwardedRef: React.Ref<ComposedComponentProps>;
10
+ callback?: Highcharts.ChartCallbackFunction | undefined;
10
11
  }> & React.RefAttributes<ComposedComponentProps>>;
@@ -110,8 +110,10 @@ export const withSplitPane = (ComposedComponent) => {
110
110
  }
111
111
  };
112
112
  this.afterCreateCallback = (chart) => {
113
+ var _a, _b;
113
114
  chart.tooltip.splitTooltip = true;
114
115
  chart.tooltip.getTooltipContainer = this.getTooltipContainer;
116
+ (_b = (_a = this.props).callback) === null || _b === void 0 ? void 0 : _b.call(_a, chart);
115
117
  };
116
118
  this.setInitialPaneSize = (callback) => {
117
119
  if (!this.tooltipContainerRef.current || !this.rootRef.current) {
@@ -1,2 +1,2 @@
1
- import type { TooltipRenderOptions } from '../../types';
2
- export declare const getRenderTooltip: (timeZone?: string) => (data: TooltipRenderOptions) => string;
1
+ import type { TooltipRenderOptions, YagrWidgetData } from '../../types';
2
+ export declare const getRenderTooltip: (userData: YagrWidgetData['data']) => (data: TooltipRenderOptions) => string;
@@ -7,12 +7,33 @@ const calcOption = (d) => {
7
7
  })
8
8
  : d;
9
9
  };
10
+ const getSeriesColorProperty = (args) => {
11
+ var _a;
12
+ const { data, userData, row, rowIndex } = args;
13
+ const userSeries = userData.graphs[rowIndex];
14
+ const lineColor = (_a = data.yagr.getSeriesById(row.id)) === null || _a === void 0 ? void 0 : _a.lineColor;
15
+ let seriesColor = row.color;
16
+ switch (userSeries === null || userSeries === void 0 ? void 0 : userSeries.legendColorKey) {
17
+ case 'lineColor': {
18
+ if (lineColor) {
19
+ seriesColor = lineColor;
20
+ }
21
+ break;
22
+ }
23
+ case 'color':
24
+ default: {
25
+ seriesColor = row.color;
26
+ }
27
+ }
28
+ return seriesColor;
29
+ };
10
30
  /*
11
31
  * Default tooltip renderer.
12
32
  * Adapter between native Yagr tooltip config and ChartKit
13
33
  * tooltip renderer.
14
34
  */
15
- export const getRenderTooltip = (timeZone) => (data) => {
35
+ export const getRenderTooltip = (userData) => (data) => {
36
+ const { timeZone } = userData;
16
37
  const cfg = data.yagr.config;
17
38
  const timeMultiplier = cfg.chart.timeMultiplier || 1;
18
39
  const opts = data.options;
@@ -41,7 +62,7 @@ export const getRenderTooltip = (timeZone) => (data) => {
41
62
  activeRowAlwaysFirstInTooltip: rows.length > 1,
42
63
  tooltipHeader: dateTime({ input: x / timeMultiplier, timeZone }).format('DD MMMM YYYY HH:mm:ss'),
43
64
  shared: true,
44
- lines: rows.map((row, i) => (Object.assign(Object.assign({}, row), { seriesName: row.name || 'Serie ' + (i + 1), seriesColor: row.color, selectedSeries: row.active, seriesIdx: row.seriesIdx, percentValue: typeof row.transformed === 'number' ? row.transformed.toFixed(1) : '' }))),
65
+ lines: rows.map((row, i) => (Object.assign(Object.assign({}, row), { seriesName: row.name || 'Serie ' + (i + 1), seriesColor: getSeriesColorProperty({ data, userData, row, rowIndex: i }), selectedSeries: row.active, seriesIdx: row.seriesIdx, percentValue: typeof row.transformed === 'number' ? row.transformed.toFixed(1) : '' }))),
45
66
  withPercent: calcOption(opts.percent),
46
67
  hiddenRowsNumber: hiddenRowsNumber,
47
68
  hiddenRowsSum,
@@ -111,7 +111,7 @@ export const shapeYagrConfig = (args) => {
111
111
  config.chart = chart;
112
112
  if ((_a = config.tooltip) === null || _a === void 0 ? void 0 : _a.show) {
113
113
  config.tooltip = config.tooltip || {};
114
- config.tooltip.render = ((_b = config.tooltip) === null || _b === void 0 ? void 0 : _b.render) || getRenderTooltip(timeZone);
114
+ config.tooltip.render = ((_b = config.tooltip) === null || _b === void 0 ? void 0 : _b.render) || getRenderTooltip(data);
115
115
  if (!config.tooltip.className) {
116
116
  // "className" property prevent default yagr styles adding
117
117
  config.tooltip.className = 'chartkit-yagr-tooltip';
@@ -1,4 +1,4 @@
1
- import type { MinimalValidConfig, RawSerieData, YagrConfig } from '@gravity-ui/yagr';
1
+ import type { MinimalValidConfig, RawSerieData, SeriesOptions, YagrConfig } from '@gravity-ui/yagr';
2
2
  import type Yagr from '@gravity-ui/yagr';
3
3
  import { ChartKitProps } from 'src/types';
4
4
  export type { default as Yagr } from '@gravity-ui/yagr';
@@ -10,9 +10,19 @@ export interface CustomTooltipProps {
10
10
  export type YagrWidgetProps = ChartKitProps<'yagr'> & {
11
11
  id: string;
12
12
  };
13
+ export type YagrSeriesData<T = Omit<SeriesOptions, 'type'>> = RawSerieData<T> & {
14
+ /**
15
+ * Determines what data value should be used to get a color for tooltip series. Does not work in case of using custom tooltip rendered via `tooltip` property.
16
+ * - `lineColor` indicates that lineColor property should be used
17
+ * - `color` indicates that color property should be used
18
+ *
19
+ * @default 'color'
20
+ */
21
+ legendColorKey?: 'color' | 'lineColor';
22
+ };
13
23
  export type YagrWidgetData = {
14
24
  data: {
15
- graphs: RawSerieData[];
25
+ graphs: YagrSeriesData[];
16
26
  timeline: number[];
17
27
  /**
18
28
  * Allow to setup timezone for X axis and tooltip's header.
@@ -19,6 +19,21 @@ export type AreaSeriesData<T = any> = BaseSeriesData<T> & {
19
19
  y?: string | number;
20
20
  /** Data label value of the point. If not specified, the y value is used. */
21
21
  label?: string | number;
22
+ /** Individual marker options for the point. */
23
+ marker?: {
24
+ /** States for a single point marker. */
25
+ states?: {
26
+ /** The normal state of a single point marker. */
27
+ normal?: {
28
+ /**
29
+ * Enable or disable the point marker.
30
+ *
31
+ * @default false
32
+ * */
33
+ enabled: boolean;
34
+ };
35
+ };
36
+ };
22
37
  };
23
38
  export type AreaMarkerSymbol = 'circle' | 'square';
24
39
  export type AreaMarkerOptions = PointMarkerOptions & {
@@ -25,6 +25,8 @@ export type BarXSeriesData<T = any> = BaseSeriesData<T> & {
25
25
  category?: string;
26
26
  /** Data label value of the bar-x column. If not specified, the y value is used. */
27
27
  label?: string | number;
28
+ /** Individual opacity for the bar-x column. */
29
+ opacity?: number;
28
30
  };
29
31
  export type BarXSeries<T = any> = BaseSeries & {
30
32
  type: typeof SeriesType.BarX;
@@ -19,6 +19,8 @@ export type BarYSeriesData<T = any> = BaseSeriesData<T> & {
19
19
  y?: string | number;
20
20
  /** Data label value of the bar. If not specified, the x value is used. */
21
21
  label?: string | number;
22
+ /** Individual opacity for the bar. */
23
+ opacity?: number;
22
24
  };
23
25
  export type BarYSeries<T = any> = BaseSeries & {
24
26
  type: typeof SeriesType.BarY;
@@ -22,6 +22,8 @@ export type BaseSeries = {
22
22
  * */
23
23
  allowOverlap?: boolean;
24
24
  };
25
+ /** You can set the cursor to "pointer" if you have click events attached to the series, to signal to the user that the points and lines can be clicked. */
26
+ cursor?: string;
25
27
  };
26
28
  export type BaseSeriesData<T = any> = {
27
29
  /**
@@ -6,4 +6,10 @@ export type ChartMargin = {
6
6
  };
7
7
  export type ChartKitWidgetChart = {
8
8
  margin?: Partial<ChartMargin>;
9
+ events?: {
10
+ click?: (data: {
11
+ point: unknown;
12
+ series: unknown;
13
+ }, event: PointerEvent) => void;
14
+ };
9
15
  };
@@ -19,6 +19,13 @@ export type LineSeriesData<T = any> = BaseSeriesData<T> & {
19
19
  y?: string | number;
20
20
  /** Data label value of the point. If not specified, the y value is used. */
21
21
  label?: string | number;
22
+ marker?: {
23
+ states?: {
24
+ normal?: {
25
+ enabled: boolean;
26
+ };
27
+ };
28
+ };
22
29
  };
23
30
  export type LineSeries<T = any> = BaseSeries & {
24
31
  type: typeof SeriesType.Line;
@@ -42,4 +49,6 @@ export type LineSeries<T = any> = BaseSeries & {
42
49
  dashStyle?: `${DashStyle}`;
43
50
  /** Option for line cap style */
44
51
  linecap?: `${LineCap}`;
52
+ /** Individual opacity for the line. */
53
+ opacity?: number;
45
54
  };
@@ -11,6 +11,8 @@ export type PieSeriesData<T = any> = BaseSeriesData<T> & {
11
11
  visible?: boolean;
12
12
  /** Initial data label of the pie segment. If not specified, the value is used. */
13
13
  label?: string;
14
+ /** Individual opacity for the pie segment. */
15
+ opacity?: number;
14
16
  };
15
17
  export type ConnectorShape = 'straight-line' | 'polyline';
16
18
  export type ConnectorCurve = 'linear' | 'basic';
@@ -22,7 +22,10 @@ export type ScatterSeriesData<T = any> = BaseSeriesData<T> & {
22
22
  * @deprecated use `x` or `y` instead
23
23
  */
24
24
  category?: string;
25
+ /** Individual radius for the point. */
25
26
  radius?: number;
27
+ /** Individual opacity for the point. */
28
+ opacity?: number;
26
29
  };
27
30
  export type ScatterSeries<T = any> = BaseSeries & {
28
31
  type: typeof SeriesType.Scatter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/chartkit",
3
- "version": "5.0.0",
3
+ "version": "5.2.0",
4
4
  "description": "React component used to render charts based on any sources you need",
5
5
  "license": "MIT",
6
6
  "repository": "git@github.com:gravity-ui/ChartKit.git",
@@ -48,18 +48,19 @@
48
48
  "dependencies": {
49
49
  "@bem-react/classname": "^1.6.0",
50
50
  "@gravity-ui/date-utils": "^2.1.0",
51
+ "@gravity-ui/i18n": "^1.0.0",
51
52
  "@gravity-ui/yagr": "^4.2.3",
52
53
  "afterframe": "^1.0.2",
53
54
  "d3": "^7.8.5",
54
55
  "lodash": "^4.17.21",
55
- "react-split-pane": "^0.1.92"
56
+ "react-split-pane": "^0.1.92",
57
+ "tslib": "^2.6.2"
56
58
  },
57
59
  "devDependencies": {
58
60
  "@babel/preset-env": "^7.22.6",
59
61
  "@babel/preset-react": "^7.22.5",
60
62
  "@babel/preset-typescript": "^7.22.5",
61
63
  "@gravity-ui/eslint-config": "^3.1.1",
62
- "@gravity-ui/i18n": "^1.0.0",
63
64
  "@gravity-ui/prettier-config": "^1.1.0",
64
65
  "@gravity-ui/stylelint-config": "^4.0.1",
65
66
  "@gravity-ui/tsconfig": "^1.0.0",