@gravity-ui/chartkit 3.2.0 → 3.4.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 (70) hide show
  1. package/build/plugins/d3/renderer/components/AxisX.js +15 -5
  2. package/build/plugins/d3/renderer/components/AxisY.js +18 -8
  3. package/build/plugins/d3/renderer/components/Chart.js +3 -3
  4. package/build/plugins/d3/renderer/hooks/useChartOptions/chart.js +16 -9
  5. package/build/plugins/d3/renderer/hooks/useChartOptions/legend.js +4 -2
  6. package/build/plugins/d3/renderer/hooks/useChartOptions/types.d.ts +8 -0
  7. package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.js +8 -0
  8. package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +8 -0
  9. package/build/plugins/d3/renderer/hooks/useScales/index.js +22 -14
  10. package/build/plugins/d3/renderer/hooks/useShapes/bar-x.d.ts +16 -0
  11. package/build/plugins/d3/renderer/hooks/useShapes/bar-x.js +75 -0
  12. package/build/plugins/d3/renderer/hooks/useShapes/index.js +28 -57
  13. package/build/plugins/d3/renderer/hooks/useShapes/scatter.d.ts +18 -0
  14. package/build/plugins/d3/renderer/hooks/useShapes/scatter.js +62 -0
  15. package/build/plugins/highcharts/renderer/helpers/config/utils/index.js +1 -1
  16. package/build/types/widget-data/axis.d.ts +20 -0
  17. package/build/types/widget-data/bar-x.d.ts +31 -0
  18. package/build/types/widget-data/index.d.ts +6 -2
  19. package/build/types/widget-data/index.js +1 -0
  20. package/build/types/widget-data/series.d.ts +16 -2
  21. package/package.json +7 -2
  22. package/build/libs/chartkit-error/__tests__/chartkit-error.js +0 -27
  23. package/build/libs/settings/__tests__/settings.test.d.ts +0 -1
  24. package/build/libs/settings/__tests__/settings.test.js +0 -17
  25. package/build/plugins/d3/__stories__/LinearCategories.stories.d.ts +0 -4
  26. package/build/plugins/d3/__stories__/LinearCategories.stories.js +0 -101
  27. package/build/plugins/d3/__stories__/Timestamp.stories.d.ts +0 -4
  28. package/build/plugins/d3/__stories__/Timestamp.stories.js +0 -89
  29. package/build/plugins/d3/__stories__/penguins.json +0 -3098
  30. package/build/plugins/highcharts/__stories__/Line.stories.d.ts +0 -3
  31. package/build/plugins/highcharts/__stories__/Line.stories.js +0 -12
  32. package/build/plugins/highcharts/__stories__/Pie.stories.d.ts +0 -3
  33. package/build/plugins/highcharts/__stories__/Pie.stories.js +0 -12
  34. package/build/plugins/highcharts/__stories__/area/Range.stories.d.ts +0 -3
  35. package/build/plugins/highcharts/__stories__/area/Range.stories.js +0 -12
  36. package/build/plugins/highcharts/__stories__/area/Stacked.stories.d.ts +0 -3
  37. package/build/plugins/highcharts/__stories__/area/Stacked.stories.js +0 -12
  38. package/build/plugins/highcharts/__stories__/column/HorizontalStacked.stories.d.ts +0 -3
  39. package/build/plugins/highcharts/__stories__/column/HorizontalStacked.stories.js +0 -12
  40. package/build/plugins/highcharts/__stories__/column/Vertical.stories.d.ts +0 -3
  41. package/build/plugins/highcharts/__stories__/column/Vertical.stories.js +0 -12
  42. package/build/plugins/highcharts/__stories__/column/VerticalStacked.stories.d.ts +0 -3
  43. package/build/plugins/highcharts/__stories__/column/VerticalStacked.stories.js +0 -12
  44. package/build/plugins/highcharts/__stories__/combined/ComboChartWithSameLegendValues.stories.d.ts +0 -3
  45. package/build/plugins/highcharts/__stories__/combined/ComboChartWithSameLegendValues.stories.js +0 -12
  46. package/build/plugins/highcharts/__stories__/complex/TwoAxis.stories.d.ts +0 -3
  47. package/build/plugins/highcharts/__stories__/complex/TwoAxis.stories.js +0 -12
  48. package/build/plugins/highcharts/__stories__/components/ChartStory.d.ts +0 -12
  49. package/build/plugins/highcharts/__stories__/components/ChartStory.js +0 -28
  50. package/build/plugins/highcharts/__stories__/constants/story-settings.d.ts +0 -42
  51. package/build/plugins/highcharts/__stories__/constants/story-settings.js +0 -42
  52. package/build/plugins/highcharts/__stories__/custom-error-render/custom-error-render.stories.d.ts +0 -3
  53. package/build/plugins/highcharts/__stories__/custom-error-render/custom-error-render.stories.js +0 -41
  54. package/build/plugins/highcharts/__stories__/no-data/no-data.stories.d.ts +0 -3
  55. package/build/plugins/highcharts/__stories__/no-data/no-data.stories.js +0 -20
  56. package/build/plugins/highcharts/__stories__/pie/WithTotals.stories.d.ts +0 -3
  57. package/build/plugins/highcharts/__stories__/pie/WithTotals.stories.js +0 -12
  58. package/build/plugins/highcharts/__tests__/prepare-data.test.d.ts +0 -1
  59. package/build/plugins/highcharts/__tests__/prepare-data.test.js +0 -13
  60. package/build/plugins/indicator/__stories__/Indicator.stories.d.ts +0 -4
  61. package/build/plugins/indicator/__stories__/Indicator.stories.js +0 -45
  62. package/build/plugins/yagr/__stories__/Yagr.stories.d.ts +0 -6
  63. package/build/plugins/yagr/__stories__/Yagr.stories.js +0 -90
  64. package/build/plugins/yagr/__stories__/mocks/line10.d.ts +0 -53
  65. package/build/plugins/yagr/__stories__/mocks/line10.js +0 -78
  66. package/build/plugins/yagr/__tests__/utils.test.d.ts +0 -1
  67. package/build/plugins/yagr/__tests__/utils.test.js +0 -26
  68. package/build/utils/__tests__/common.test.d.ts +0 -1
  69. package/build/utils/__tests__/common.test.js +0 -9
  70. /package/build/{libs/chartkit-error/__tests__/chartkit-error.d.ts → types/widget-data/bar-x.js} +0 -0
@@ -31,20 +31,30 @@ export const AxisX = ({ axis, width, height, scale }) => {
31
31
  }
32
32
  const svgElement = select(ref.current);
33
33
  svgElement.selectAll('*').remove();
34
- const xAxisGenerator = axisBottom(scale)
35
- .tickSize(height * -1)
34
+ const tickSize = axis.grid.enabled ? height * -1 : 0;
35
+ let xAxisGenerator = axisBottom(scale)
36
+ .tickSize(tickSize)
36
37
  .tickPadding(axis.labels.padding)
37
38
  .tickFormat((value) => {
39
+ if (!axis.labels.enabled) {
40
+ return '';
41
+ }
38
42
  return formatAxisTickLabel({
39
43
  axisType: axis.type,
40
44
  value,
41
- dateFormat: axis.labels.dateFormat,
42
- numberFormat: axis.labels.numberFormat,
45
+ dateFormat: axis.labels['dateFormat'],
46
+ numberFormat: axis.labels['numberFormat'],
43
47
  });
44
48
  });
49
+ if (axis.ticks.pixelInterval) {
50
+ const ticksCount = width / axis.ticks.pixelInterval;
51
+ xAxisGenerator = xAxisGenerator.ticks(ticksCount);
52
+ }
45
53
  svgElement.call(xAxisGenerator).attr('class', b());
46
54
  svgElement.select('.domain').attr('d', `M0,0V0H${width}`);
47
- svgElement.selectAll('.tick text').style('font-size', axis.labels.style.fontSize);
55
+ if (axis.labels.enabled) {
56
+ svgElement.selectAll('.tick text').style('font-size', axis.labels.style.fontSize);
57
+ }
48
58
  const transformStyle = svgElement.select('.tick').attr('transform');
49
59
  const { x } = parseTransformStyle(transformStyle);
50
60
  if (x === 0) {
@@ -32,23 +32,33 @@ export const AxisY = ({ axises, width, height, scale }) => {
32
32
  const axis = axises[0];
33
33
  const svgElement = select(ref.current);
34
34
  svgElement.selectAll('*').remove();
35
- const yAxisGenerator = axisLeft(scale)
36
- .tickSize(width * -1)
35
+ const tickSize = axis.grid.enabled ? width * -1 : 0;
36
+ let yAxisGenerator = axisLeft(scale)
37
+ .tickSize(tickSize)
37
38
  .tickPadding(axis.labels.padding)
38
39
  .tickFormat((value) => {
40
+ if (!axis.labels.enabled) {
41
+ return '';
42
+ }
39
43
  return formatAxisTickLabel({
40
44
  axisType: axis.type,
41
45
  value,
42
- dateFormat: axis.labels.dateFormat,
43
- numberFormat: axis.labels.numberFormat,
46
+ dateFormat: axis.labels['dateFormat'],
47
+ numberFormat: axis.labels['numberFormat'],
44
48
  });
45
49
  });
50
+ if (axis.ticks.pixelInterval) {
51
+ const ticksCount = height / axis.ticks.pixelInterval;
52
+ yAxisGenerator = yAxisGenerator.ticks(ticksCount);
53
+ }
46
54
  svgElement.call(yAxisGenerator).attr('class', b());
47
55
  svgElement.select('.domain').attr('d', `M0,${height}H0V0`);
48
- svgElement
49
- .selectAll('.tick text')
50
- .style('font-size', axis.labels.style.fontSize)
51
- .style('transform', 'translateY(-1px)');
56
+ if (axis.labels.enabled) {
57
+ svgElement
58
+ .selectAll('.tick text')
59
+ .style('font-size', axis.labels.style.fontSize)
60
+ .style('transform', 'translateY(-1px)');
61
+ }
52
62
  const transformStyle = svgElement.select('.tick').attr('transform');
53
63
  const { y } = parseTransformStyle(transformStyle);
54
64
  if (y === height) {
@@ -13,7 +13,7 @@ export const Chart = ({ width, height, data }) => {
13
13
  // FIXME: add data validation
14
14
  const { series } = data;
15
15
  const svgRef = React.createRef();
16
- const hasAxisRelatedSeries = series.some(isAxisRelatedSeries);
16
+ const hasAxisRelatedSeries = series.data.some(isAxisRelatedSeries);
17
17
  const { chartHovered, handleMouseEnter, handleMouseLeave } = useChartEvents();
18
18
  const { chart, legend, title, tooltip, xAxis, yAxis } = useChartOptions(data);
19
19
  const { boundsWidth, boundsHeight, legendHeight } = useChartDimensions({
@@ -25,8 +25,8 @@ export const Chart = ({ width, height, data }) => {
25
25
  xAxis,
26
26
  yAxis,
27
27
  });
28
- const { activeLegendItems, handleLegendItemClick } = useLegend({ series });
29
- const { chartSeries } = useSeries({ activeLegendItems, series });
28
+ const { activeLegendItems, handleLegendItemClick } = useLegend({ series: series.data });
29
+ const { chartSeries } = useSeries({ activeLegendItems, series: series.data });
30
30
  const { xScale, yScale } = useScales({
31
31
  boundsWidth,
32
32
  boundsHeight,
@@ -24,12 +24,15 @@ const getAxisLabelMaxWidth = (args) => {
24
24
  maxDomainValue = max(domain);
25
25
  }
26
26
  }
27
- const formattedValue = formatAxisTickLabel({
28
- axisType: axis.type,
29
- value: maxDomainValue,
30
- dateFormat: axis.labels.dateFormat,
31
- numberFormat: axis.labels.numberFormat,
32
- });
27
+ let formattedValue = '';
28
+ if (axis.labels.enabled) {
29
+ formattedValue = formatAxisTickLabel({
30
+ axisType: axis.type,
31
+ value: maxDomainValue,
32
+ dateFormat: axis.labels['dateFormat'],
33
+ numberFormat: axis.labels['numberFormat'],
34
+ });
35
+ }
33
36
  select(document.body)
34
37
  .append('text')
35
38
  .style('font-size', axis.labels.style.fontSize)
@@ -47,12 +50,16 @@ export const getPreparedChart = (args) => {
47
50
  getHorisontalSvgTextDimensions({ text: 'Tmp', style: preparedXAxis.labels.style });
48
51
  const marginLeft = get(chart, 'margin.left', AXIS_WIDTH) +
49
52
  preparedY1Axis.labels.padding +
50
- getAxisLabelMaxWidth({ axis: preparedY1Axis, series }) +
53
+ getAxisLabelMaxWidth({ axis: preparedY1Axis, series: series.data }) +
51
54
  (preparedY1Axis.title.height || 0);
55
+ const marginTop = get(chart, 'margin.top', 0) +
56
+ getHorisontalSvgTextDimensions({ text: 'Tmp', style: preparedY1Axis.labels.style }) / 2;
57
+ const marginRight = get(chart, 'margin.right', 0) +
58
+ getAxisLabelMaxWidth({ axis: preparedXAxis, series: series.data }) / 2;
52
59
  return {
53
60
  margin: {
54
- top: get(chart, 'margin.top', 0),
55
- right: get(chart, 'margin.right', 0),
61
+ top: marginTop,
62
+ right: marginRight,
56
63
  bottom: marginBottom,
57
64
  left: marginLeft,
58
65
  },
@@ -1,5 +1,7 @@
1
- import get from 'lodash/get';
2
1
  export const getPreparedLegend = (args) => {
3
2
  const { legend, series } = args;
4
- return { enabled: get(legend, 'enabled', true) && series.length > 1 };
3
+ const enabled = legend === null || legend === void 0 ? void 0 : legend.enabled;
4
+ return {
5
+ enabled: typeof enabled === 'boolean' ? enabled : series.data.length > 1,
6
+ };
5
7
  };
@@ -14,6 +14,14 @@ export type PreparedAxis = Omit<ChartKitWidgetAxis, 'type' | 'labels'> & {
14
14
  text: string;
15
15
  style: BaseTextStyle;
16
16
  };
17
+ min?: number;
18
+ grid: {
19
+ enabled: boolean;
20
+ };
21
+ maxPadding: number;
22
+ ticks: {
23
+ pixelInterval?: number;
24
+ };
17
25
  };
18
26
  export type PreparedTitle = ChartKitWidgetData['title'] & {
19
27
  height: number;
@@ -24,6 +24,14 @@ export const getPreparedXAxis = ({ xAxis }) => {
24
24
  ? getHorisontalSvgTextDimensions({ text: titleText, style: titleStyle })
25
25
  : 0,
26
26
  },
27
+ min: get(xAxis, 'min'),
28
+ maxPadding: get(xAxis, 'maxPadding', 0.01),
29
+ grid: {
30
+ enabled: get(xAxis, 'grid.enabled', true),
31
+ },
32
+ ticks: {
33
+ pixelInterval: get(xAxis, 'ticks.pixelInterval'),
34
+ },
27
35
  };
28
36
  return preparedXAxis;
29
37
  };
@@ -29,6 +29,14 @@ export const getPreparedYAxis = ({ yAxis }) => {
29
29
  ? getHorisontalSvgTextDimensions({ text: y1TitleText, style: y1TitleStyle })
30
30
  : 0,
31
31
  },
32
+ min: get(yAxis1, 'min'),
33
+ maxPadding: get(yAxis1, 'maxPadding', 0.05),
34
+ grid: {
35
+ enabled: get(yAxis1, 'grid.enabled', true),
36
+ },
37
+ ticks: {
38
+ pixelInterval: get(yAxis1, 'ticks.pixelInterval'),
39
+ },
32
40
  };
33
41
  return [preparedY1Axis];
34
42
  };
@@ -15,11 +15,13 @@ const filterCategoriesByVisibleSeries = (categories, series) => {
15
15
  export const useScales = (args) => {
16
16
  const { boundsWidth, boundsHeight, series, xAxis, yAxis } = args;
17
17
  const scales = React.useMemo(() => {
18
+ const xMin = get(xAxis, 'min');
18
19
  const xType = get(xAxis, 'type', 'linear');
19
- const xCatigories = get(xAxis, 'categories');
20
+ const xCategories = get(xAxis, 'categories');
20
21
  const xTimestamps = get(xAxis, 'timestamps');
21
22
  const yType = get(yAxis[0], 'type', 'linear');
22
- const yCatigories = get(yAxis[0], 'categories');
23
+ const yMin = get(yAxis[0], 'min');
24
+ const yCategories = get(yAxis[0], 'categories');
23
25
  const yTimestamps = get(xAxis, 'timestamps');
24
26
  let visibleSeries = getOnlyVisibleSeries(series);
25
27
  // Reassign to all series in case of all series unselected,
@@ -30,29 +32,32 @@ export const useScales = (args) => {
30
32
  switch (xType) {
31
33
  case 'linear': {
32
34
  const domain = getDomainDataXBySeries(visibleSeries);
35
+ const range = [0, boundsWidth - boundsWidth * xAxis.maxPadding];
33
36
  if (isNumericalArrayData(domain)) {
34
- const [xMin, xMax] = extent(domain);
35
- xScale = scaleLinear().domain([xMin, xMax]).range([0, boundsWidth]).nice();
37
+ const [domainXMin, xMax] = extent(domain);
38
+ const xMinValue = typeof xMin === 'number' ? xMin : domainXMin;
39
+ xScale = scaleLinear().domain([xMinValue, xMax]).range(range).nice();
36
40
  }
37
41
  break;
38
42
  }
39
43
  case 'category': {
40
- if (xCatigories) {
41
- const filteredCategories = filterCategoriesByVisibleSeries(xCatigories, visibleSeries);
44
+ if (xCategories) {
45
+ const filteredCategories = filterCategoriesByVisibleSeries(xCategories, visibleSeries);
42
46
  xScale = scaleBand().domain(filteredCategories).range([0, boundsWidth]);
43
47
  }
44
48
  break;
45
49
  }
46
50
  case 'datetime': {
51
+ const range = [0, boundsWidth - boundsWidth * xAxis.maxPadding];
47
52
  if (xTimestamps) {
48
53
  const [xMin, xMax] = extent(xTimestamps);
49
- xScale = scaleUtc().domain([xMin, xMax]).range([0, boundsWidth]).nice();
54
+ xScale = scaleUtc().domain([xMin, xMax]).range(range).nice();
50
55
  }
51
56
  else {
52
57
  const domain = getDomainDataXBySeries(visibleSeries);
53
58
  if (isNumericalArrayData(domain)) {
54
59
  const [xMin, xMax] = extent(domain);
55
- xScale = scaleUtc().domain([xMin, xMax]).range([0, boundsWidth]).nice();
60
+ xScale = scaleUtc().domain([xMin, xMax]).range(range).nice();
56
61
  }
57
62
  }
58
63
  break;
@@ -64,29 +69,32 @@ export const useScales = (args) => {
64
69
  switch (yType) {
65
70
  case 'linear': {
66
71
  const domain = getDomainDataYBySeries(visibleSeries);
72
+ const range = [boundsHeight, boundsHeight * yAxis[0].maxPadding];
67
73
  if (isNumericalArrayData(domain)) {
68
- const [yMin, yMax] = extent(domain);
69
- yScale = scaleLinear().domain([yMin, yMax]).range([boundsHeight, 0]).nice();
74
+ const [domainYMin, yMax] = extent(domain);
75
+ const yMinValue = typeof yMin === 'number' ? yMin : domainYMin;
76
+ yScale = scaleLinear().domain([yMinValue, yMax]).range(range).nice();
70
77
  }
71
78
  break;
72
79
  }
73
80
  case 'category': {
74
- if (yCatigories) {
75
- const filteredCategories = filterCategoriesByVisibleSeries(yCatigories, visibleSeries);
81
+ if (yCategories) {
82
+ const filteredCategories = filterCategoriesByVisibleSeries(yCategories, visibleSeries);
76
83
  yScale = scaleBand().domain(filteredCategories).range([boundsHeight, 0]);
77
84
  }
78
85
  break;
79
86
  }
80
87
  case 'datetime': {
88
+ const range = [boundsHeight, boundsHeight * yAxis[0].maxPadding];
81
89
  if (yTimestamps) {
82
90
  const [yMin, yMax] = extent(yTimestamps);
83
- yScale = scaleUtc().domain([yMin, yMax]).range([boundsHeight, 0]).nice();
91
+ yScale = scaleUtc().domain([yMin, yMax]).range(range).nice();
84
92
  }
85
93
  else {
86
94
  const domain = getDomainDataYBySeries(visibleSeries);
87
95
  if (isNumericalArrayData(domain)) {
88
96
  const [yMin, yMax] = extent(domain);
89
- yScale = scaleUtc().domain([yMin, yMax]).range([boundsHeight, 0]).nice();
97
+ yScale = scaleUtc().domain([yMin, yMax]).range(range).nice();
90
98
  }
91
99
  }
92
100
  break;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { ChartOptions } from '../useChartOptions/types';
3
+ import { ChartScale } from '../useScales';
4
+ import { OnSeriesMouseLeave, OnSeriesMouseMove } from '../useTooltip/types';
5
+ import { BarXSeries } from '../../../../../types/widget-data';
6
+ type Args = {
7
+ series: BarXSeries[];
8
+ xAxis: ChartOptions['xAxis'];
9
+ xScale: ChartScale;
10
+ yAxis: ChartOptions['yAxis'];
11
+ yScale: ChartScale;
12
+ onSeriesMouseMove?: OnSeriesMouseMove;
13
+ onSeriesMouseLeave?: OnSeriesMouseLeave;
14
+ };
15
+ export declare function prepareBarXSeries(args: Args): React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
16
+ export {};
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ const DEFAULT_BAR_RECT_WIDTH = 50;
4
+ const DEFAULT_LINEAR_BAR_RECT_WIDTH = 20;
5
+ const MIN_RECT_GAP = 1;
6
+ const b = block('chartkit-d3-bar');
7
+ const getRectProperties = (args) => {
8
+ const { point, xAxis, xScale, yAxis, yScale, minPointDistance } = args;
9
+ let cx;
10
+ let cy;
11
+ let width;
12
+ let height;
13
+ if (xAxis.type === 'category') {
14
+ const xBandScale = xScale;
15
+ const maxWidth = xBandScale.bandwidth() - MIN_RECT_GAP;
16
+ width = Math.min(maxWidth, DEFAULT_BAR_RECT_WIDTH);
17
+ cx = (xBandScale(point.category) || 0) + xBandScale.step() / 2 - width / 2;
18
+ }
19
+ else {
20
+ const xLinearScale = xScale;
21
+ const [min, max] = xLinearScale.domain();
22
+ const range = xLinearScale.range();
23
+ const maxWidth = ((range[1] - range[0]) * minPointDistance) / (Number(max) - Number(min)) - MIN_RECT_GAP;
24
+ width = Math.min(Math.max(maxWidth, 1), DEFAULT_LINEAR_BAR_RECT_WIDTH);
25
+ cx = xLinearScale(point.x) - width / 2;
26
+ }
27
+ if (yAxis[0].type === 'linear') {
28
+ const yLinearScale = yScale;
29
+ cy = yLinearScale(point.y);
30
+ height = yLinearScale(yLinearScale.domain()[0]) - cy;
31
+ }
32
+ else {
33
+ throw Error(`The "${yAxis[0].type}" type for the Y axis is not supported`);
34
+ }
35
+ return { x: cx, y: cy, width, height };
36
+ };
37
+ function minDiff(arr) {
38
+ let result = Infinity;
39
+ for (let i = 0; i < arr.length - 1; i++) {
40
+ for (let j = i + 1; j < arr.length; j++) {
41
+ const diff = Math.abs(arr[i] - arr[j]);
42
+ if (diff < result) {
43
+ result = diff;
44
+ }
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+ export function prepareBarXSeries(args) {
50
+ const { series, xAxis, xScale, yAxis, yScale, onSeriesMouseMove, onSeriesMouseLeave } = args;
51
+ const seriesData = series.map(({ data }) => data).flat(2);
52
+ const minPointDistance = minDiff(seriesData.map((item) => Number(item.x)));
53
+ return series.reduce((result, item) => {
54
+ const randomKey = Math.random().toString();
55
+ item.data.forEach((point, i) => {
56
+ const rectProps = getRectProperties({
57
+ point,
58
+ xAxis,
59
+ xScale,
60
+ yAxis,
61
+ yScale,
62
+ minPointDistance,
63
+ });
64
+ result.push(React.createElement("rect", Object.assign({ key: `${i}-${randomKey}`, className: b('rect'), fill: item.color }, rectProps, { onMouseMove: function () {
65
+ onSeriesMouseMove === null || onSeriesMouseMove === void 0 ? void 0 : onSeriesMouseMove({
66
+ hovered: {
67
+ data: point,
68
+ series: item,
69
+ },
70
+ });
71
+ }, onMouseLeave: onSeriesMouseLeave })));
72
+ });
73
+ return result;
74
+ }, []);
75
+ }
@@ -1,67 +1,38 @@
1
1
  import React from 'react';
2
- import block from 'bem-cn-lite';
3
- import { pointer } from 'd3';
2
+ import { group } from 'd3';
4
3
  import { getOnlyVisibleSeries } from '../../utils';
5
- const b = block('chartkit-d3-scatter');
6
- const DEFAULT_SCATTER_POINT_RADIUS = 4;
7
- const prepareCategoricalScatterData = (data) => {
8
- return data.filter((d) => typeof d.category === 'string');
9
- };
10
- const prepareLinearScatterData = (data) => {
11
- return data.filter((d) => typeof d.x === 'number' && typeof d.y === 'number');
12
- };
13
- const getPointProperties = (args) => {
14
- const { point, xAxis, xScale, yAxis, yScale } = args;
15
- const r = point.radius || DEFAULT_SCATTER_POINT_RADIUS;
16
- let cx;
17
- let cy;
18
- if (xAxis.type === 'category') {
19
- const xBandScale = xScale;
20
- cx = xBandScale(point.category) + xBandScale.step() / 2;
21
- }
22
- else {
23
- const xLinearScale = xScale;
24
- cx = xLinearScale(point.x);
25
- }
26
- if (yAxis[0].type === 'category') {
27
- const yBandScale = yScale;
28
- cy = yBandScale(point.category) + yBandScale.step() / 2;
29
- }
30
- else {
31
- const xLinearScale = yScale;
32
- cy = xLinearScale(point.y);
33
- }
34
- return { r, cx, cy };
35
- };
4
+ import { prepareBarXSeries } from './bar-x';
5
+ import { prepareScatterSeries } from './scatter';
36
6
  export const useShapes = (args) => {
37
7
  const { series, xAxis, xScale, yAxis, yScale, svgContainer, onSeriesMouseMove, onSeriesMouseLeave, } = args;
38
8
  const shapes = React.useMemo(() => {
39
9
  const visibleSeries = getOnlyVisibleSeries(series);
40
- return visibleSeries.reduce((acc, s) => {
41
- var _a;
42
- const randomKey = Math.random().toString();
43
- switch (s.type) {
10
+ const groupedSeries = group(visibleSeries, (item) => item.type);
11
+ return Array.from(groupedSeries).reduce((acc, item) => {
12
+ const [seriesType, chartSeries] = item;
13
+ switch (seriesType) {
14
+ case 'bar-x': {
15
+ acc.push(...prepareBarXSeries({
16
+ series: chartSeries,
17
+ xAxis,
18
+ xScale,
19
+ yAxis,
20
+ yScale,
21
+ onSeriesMouseMove,
22
+ onSeriesMouseLeave,
23
+ }));
24
+ break;
25
+ }
44
26
  case 'scatter': {
45
- const preparedData = xAxis.type === 'category' || ((_a = yAxis[0]) === null || _a === void 0 ? void 0 : _a.type) === 'category'
46
- ? prepareCategoricalScatterData(s.data)
47
- : prepareLinearScatterData(s.data);
48
- acc.push(...preparedData.map((point, i) => {
49
- const pointProps = getPointProperties({
50
- point,
51
- xAxis,
52
- xScale,
53
- yAxis,
54
- yScale,
55
- });
56
- return (React.createElement("circle", Object.assign({ key: `${i}-${randomKey}`, className: b('point'), fill: s.color }, pointProps, { onMouseMove: function (e) {
57
- onSeriesMouseMove === null || onSeriesMouseMove === void 0 ? void 0 : onSeriesMouseMove({
58
- hovered: {
59
- data: point,
60
- series: s,
61
- },
62
- pointerPosition: pointer(e, svgContainer),
63
- });
64
- }, onMouseLeave: onSeriesMouseLeave })));
27
+ acc.push(...prepareScatterSeries({
28
+ series: chartSeries,
29
+ xAxis,
30
+ xScale,
31
+ yAxis,
32
+ yScale,
33
+ onSeriesMouseMove,
34
+ onSeriesMouseLeave,
35
+ svgContainer,
65
36
  }));
66
37
  break;
67
38
  }
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { ChartOptions } from '../useChartOptions/types';
3
+ import { ChartScale } from '../useScales';
4
+ import { OnSeriesMouseLeave, OnSeriesMouseMove } from '../useTooltip/types';
5
+ import { ScatterSeries } from '../../../../../types/widget-data';
6
+ type PrepareScatterSeriesArgs = {
7
+ series: ScatterSeries[];
8
+ xAxis: ChartOptions['xAxis'];
9
+ xScale: ChartScale;
10
+ yAxis: ChartOptions['yAxis'];
11
+ yScale: ChartScale;
12
+ svgContainer: SVGSVGElement | null;
13
+ onSeriesMouseMove?: OnSeriesMouseMove;
14
+ onSeriesMouseLeave?: OnSeriesMouseLeave;
15
+ key?: string;
16
+ };
17
+ export declare function prepareScatterSeries(args: PrepareScatterSeriesArgs): React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
18
+ export {};
@@ -0,0 +1,62 @@
1
+ import { pointer } from 'd3';
2
+ import React from 'react';
3
+ import block from 'bem-cn-lite';
4
+ const b = block('chartkit-d3-scatter');
5
+ const DEFAULT_SCATTER_POINT_RADIUS = 4;
6
+ const prepareCategoricalScatterData = (data) => {
7
+ return data.filter((d) => typeof d.category === 'string');
8
+ };
9
+ const prepareLinearScatterData = (data) => {
10
+ return data.filter((d) => typeof d.x === 'number' && typeof d.y === 'number');
11
+ };
12
+ const getPointProperties = (args) => {
13
+ const { point, xAxis, xScale, yAxis, yScale } = args;
14
+ const r = point.radius || DEFAULT_SCATTER_POINT_RADIUS;
15
+ let cx;
16
+ let cy;
17
+ if (xAxis.type === 'category') {
18
+ const xBandScale = xScale;
19
+ cx = (xBandScale(point.category) || 0) + xBandScale.step() / 2;
20
+ }
21
+ else {
22
+ const xLinearScale = xScale;
23
+ cx = xLinearScale(point.x);
24
+ }
25
+ if (yAxis[0].type === 'category') {
26
+ const yBandScale = yScale;
27
+ cy = (yBandScale(point.category) || 0) + yBandScale.step() / 2;
28
+ }
29
+ else {
30
+ const yLinearScale = yScale;
31
+ cy = yLinearScale(point.y);
32
+ }
33
+ return { r, cx, cy };
34
+ };
35
+ export function prepareScatterSeries(args) {
36
+ const { series, xAxis, xScale, yAxis, yScale, onSeriesMouseMove, onSeriesMouseLeave, key, svgContainer, } = args;
37
+ return series.reduce((result, s) => {
38
+ var _a;
39
+ const preparedData = xAxis.type === 'category' || ((_a = yAxis[0]) === null || _a === void 0 ? void 0 : _a.type) === 'category'
40
+ ? prepareCategoricalScatterData(s.data)
41
+ : prepareLinearScatterData(s.data);
42
+ result.push(...preparedData.map((point, i) => {
43
+ const pointProps = getPointProperties({
44
+ point,
45
+ xAxis,
46
+ xScale,
47
+ yAxis,
48
+ yScale,
49
+ });
50
+ return (React.createElement("circle", Object.assign({ key: `${i}-${key}`, className: b('point'), fill: s.color }, pointProps, { onMouseMove: function (e) {
51
+ onSeriesMouseMove === null || onSeriesMouseMove === void 0 ? void 0 : onSeriesMouseMove({
52
+ hovered: {
53
+ data: point,
54
+ series: s,
55
+ },
56
+ pointerPosition: pointer(e, svgContainer),
57
+ });
58
+ }, onMouseLeave: onSeriesMouseLeave })));
59
+ }));
60
+ return result;
61
+ }, []);
62
+ }
@@ -13,7 +13,7 @@ export { mergeArrayWithObject } from './mergeArrayWithObject';
13
13
  export { numberFormat } from './numberFormat';
14
14
  export { setNavigatorDefaultPeriod } from './setNavigatorDefaultPeriod';
15
15
  export const getSortedData = (data, sort = {}) => {
16
- const { enabled = true, order = 'desc', iteratee = 'y' } = sort;
16
+ const { enabled = false, order = 'desc', iteratee = 'y' } = sort;
17
17
  if (!enabled) {
18
18
  return [...data];
19
19
  }
@@ -19,4 +19,24 @@ export type ChartKitWidgetAxis = {
19
19
  title?: {
20
20
  text?: string;
21
21
  };
22
+ /** The minimum value of the axis. If undefined the min value is automatically calculate */
23
+ min?: number;
24
+ grid?: {
25
+ /** Enable or disable the grid lines.
26
+ *
27
+ * Defaults to true.
28
+ * */
29
+ enabled?: boolean;
30
+ };
31
+ ticks?: {
32
+ /** Pixel interval of the tick marks. Not applicable to categorized axis.
33
+ * The specified value is only a hint; the interval between ticks can be greater or less depending on the data. */
34
+ pixelInterval?: number;
35
+ };
36
+ /** Padding of the max value relative to the length of the axis.
37
+ * A padding of 0.05 will make a 100px axis 5px longer.
38
+ *
39
+ * Defaults to 0.05 for Y axis and to 0.01 for X axis
40
+ * */
41
+ maxPadding?: number;
22
42
  };
@@ -0,0 +1,31 @@
1
+ import type { BaseSeries, BaseSeriesData } from './base';
2
+ import type { ChartKitWidgetSeriesOptions } from './series';
3
+ export type BarXSeriesData<T = any> = BaseSeriesData<T> & {
4
+ /** The x value of the point */
5
+ x?: number;
6
+ /** The y value of the point */
7
+ y?: number;
8
+ /** Corresponding value of axis category */
9
+ category?: string;
10
+ };
11
+ export type BarXSeries<T = any> = BaseSeries & {
12
+ type: 'bar-x';
13
+ data: BarXSeriesData<T>[];
14
+ /** The name of the series (used in legend) */
15
+ name: string;
16
+ /** The main color of the series (hex, rgba) */
17
+ color?: string;
18
+ stacking?: 'normal' | 'percent';
19
+ /** This option allows grouping series in a stacked chart */
20
+ stackId?: string;
21
+ /** Whether to group non-stacked columns or to let them render independent of each other.
22
+ * When false columns will be laid out individually and overlap each other.
23
+ *
24
+ * @default true
25
+ * */
26
+ grouping?: boolean;
27
+ dataLabels?: ChartKitWidgetSeriesOptions['dataLabels'] & {
28
+ /** Whether to align the data label inside the box or to the actual value point */
29
+ inside?: boolean;
30
+ };
31
+ };