@gravity-ui/chartkit 5.5.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/build/i18n/keysets/en.json +2 -1
  2. package/build/i18n/keysets/ru.json +2 -4
  3. package/build/plugins/d3/examples/area/TwoYAxis.d.ts +2 -0
  4. package/build/plugins/d3/examples/area/TwoYAxis.js +58 -0
  5. package/build/plugins/d3/examples/bar-x/TwoYAxis.d.ts +2 -0
  6. package/build/plugins/d3/examples/bar-x/TwoYAxis.js +58 -0
  7. package/build/plugins/d3/examples/line/TwoYAxis.d.ts +2 -0
  8. package/build/plugins/d3/examples/line/TwoYAxis.js +58 -0
  9. package/build/plugins/d3/examples/mars-weather.d.ts +13 -0
  10. package/build/plugins/d3/examples/mars-weather.js +1203 -0
  11. package/build/plugins/d3/examples/scatter/TwoYAxis.d.ts +2 -0
  12. package/build/plugins/d3/examples/scatter/TwoYAxis.js +58 -0
  13. package/build/plugins/d3/renderer/components/AxisY.d.ts +1 -1
  14. package/build/plugins/d3/renderer/components/AxisY.js +112 -79
  15. package/build/plugins/d3/renderer/components/Chart.js +4 -3
  16. package/build/plugins/d3/renderer/hooks/useAxisScales/index.d.ts +1 -1
  17. package/build/plugins/d3/renderer/hooks/useAxisScales/index.js +8 -1
  18. package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.d.ts +1 -0
  19. package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.js +11 -10
  20. package/build/plugins/d3/renderer/hooks/useChartOptions/types.d.ts +1 -0
  21. package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.js +1 -0
  22. package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +56 -50
  23. package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.d.ts +1 -1
  24. package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +1 -0
  25. package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +1 -0
  26. package/build/plugins/d3/renderer/hooks/useSeries/prepare-legend.js +3 -3
  27. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.d.ts +1 -1
  28. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.js +1 -0
  29. package/build/plugins/d3/renderer/hooks/useSeries/prepare-scatter.js +1 -0
  30. package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +4 -0
  31. package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.d.ts +2 -1
  32. package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.js +7 -6
  33. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.d.ts +2 -1
  34. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.js +4 -4
  35. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.d.ts +1 -1
  36. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.js +1 -1
  37. package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +1 -1
  38. package/build/plugins/d3/renderer/hooks/useShapes/index.js +3 -1
  39. package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.d.ts +1 -1
  40. package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +2 -1
  41. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.d.ts +2 -2
  42. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +5 -2
  43. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.d.ts +1 -1
  44. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.js +1 -1
  45. package/build/plugins/d3/renderer/utils/text.js +1 -1
  46. package/build/plugins/d3/renderer/validation/index.js +13 -4
  47. package/build/plugins/d3/utils/pie-center-text.js +1 -1
  48. package/build/types/widget-data/area.d.ts +2 -0
  49. package/build/types/widget-data/bar-x.d.ts +2 -0
  50. package/build/types/widget-data/line.d.ts +2 -0
  51. package/build/types/widget-data/scatter.d.ts +2 -0
  52. package/package.json +2 -1
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const TwoYAxis: () => React.JSX.Element;
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { dateTime } from '@gravity-ui/date-utils';
3
+ import { ChartKit } from '../../../../components/ChartKit';
4
+ import { ExampleWrapper } from '../ExampleWrapper';
5
+ import marsWeatherData from '../mars-weather';
6
+ export const TwoYAxis = () => {
7
+ const data = marsWeatherData;
8
+ const minTempData = data.map((d) => ({
9
+ x: dateTime({ input: d.terrestrial_date, format: 'YYYY-MM-DD' }).valueOf(),
10
+ y: d.min_temp,
11
+ }));
12
+ const maxTempData = data.map((d) => ({
13
+ x: dateTime({ input: d.terrestrial_date, format: 'YYYY-MM-DD' }).valueOf(),
14
+ y: d.max_temp,
15
+ }));
16
+ const widgetData = {
17
+ series: {
18
+ data: [
19
+ {
20
+ type: 'scatter',
21
+ data: minTempData,
22
+ name: 'Min Temperature',
23
+ yAxis: 0,
24
+ },
25
+ {
26
+ type: 'scatter',
27
+ data: maxTempData,
28
+ name: 'Max Temperature',
29
+ yAxis: 1,
30
+ },
31
+ ],
32
+ },
33
+ yAxis: [
34
+ {
35
+ title: {
36
+ text: 'Min',
37
+ },
38
+ },
39
+ {
40
+ title: {
41
+ text: 'Max',
42
+ },
43
+ },
44
+ ],
45
+ xAxis: {
46
+ type: 'datetime',
47
+ title: {
48
+ text: 'Terrestrial date',
49
+ },
50
+ ticks: { pixelInterval: 200 },
51
+ },
52
+ title: {
53
+ text: 'Mars weather',
54
+ },
55
+ };
56
+ return (React.createElement(ExampleWrapper, null,
57
+ React.createElement(ChartKit, { type: "d3", data: widgetData })));
58
+ };
@@ -2,9 +2,9 @@ import React from 'react';
2
2
  import type { ChartScale, PreparedAxis } from '../hooks';
3
3
  type Props = {
4
4
  axises: PreparedAxis[];
5
+ scale: ChartScale[];
5
6
  width: number;
6
7
  height: number;
7
- scale: ChartScale;
8
8
  };
9
9
  export declare const AxisY: ({ axises, width, height, scale }: Props) => React.JSX.Element;
10
10
  export {};
@@ -1,11 +1,15 @@
1
1
  import React from 'react';
2
- import { axisLeft, select } from 'd3';
2
+ import { axisLeft, axisRight, line, select } from 'd3';
3
3
  import { block } from '../../../../utils/cn';
4
4
  import { calculateCos, calculateSin, formatAxisTickLabel, getClosestPointsRange, getScaleTicks, getTicksCount, parseTransformStyle, setEllipsisForOverflowText, setEllipsisForOverflowTexts, } from '../utils';
5
5
  const b = block('d3-axis');
6
- function transformLabel(node, axis) {
6
+ function transformLabel(args) {
7
+ const { node, axis } = args;
7
8
  let topOffset = axis.labels.lineHeight / 2;
8
- let leftOffset = -axis.labels.margin;
9
+ let leftOffset = axis.labels.margin;
10
+ if (axis.position === 'left') {
11
+ leftOffset = leftOffset * -1;
12
+ }
9
13
  if (axis.labels.rotation) {
10
14
  if (axis.labels.rotation > 0) {
11
15
  leftOffset -= axis.labels.lineHeight * calculateSin(axis.labels.rotation);
@@ -24,92 +28,121 @@ function transformLabel(node, axis) {
24
28
  }
25
29
  return `translate(${leftOffset}px, ${topOffset}px)`;
26
30
  }
31
+ function getAxisGenerator(args) {
32
+ const { preparedAxis, axisGenerator: generator, width, height, scale } = args;
33
+ const tickSize = preparedAxis.grid.enabled ? width * -1 : 0;
34
+ const step = getClosestPointsRange(preparedAxis, getScaleTicks(scale));
35
+ let axisGenerator = generator
36
+ .tickSize(tickSize)
37
+ .tickPadding(preparedAxis.labels.margin)
38
+ .tickFormat((value) => {
39
+ if (!preparedAxis.labels.enabled) {
40
+ return '';
41
+ }
42
+ return formatAxisTickLabel({
43
+ axis: preparedAxis,
44
+ value,
45
+ step,
46
+ });
47
+ });
48
+ const ticksCount = getTicksCount({ axis: preparedAxis, range: height });
49
+ if (ticksCount) {
50
+ axisGenerator = axisGenerator.ticks(ticksCount);
51
+ }
52
+ return axisGenerator;
53
+ }
27
54
  export const AxisY = ({ axises, width, height, scale }) => {
28
55
  const ref = React.useRef(null);
29
56
  React.useEffect(() => {
30
57
  if (!ref.current) {
31
58
  return;
32
59
  }
33
- const axis = axises[0];
34
60
  const svgElement = select(ref.current);
35
61
  svgElement.selectAll('*').remove();
36
- const tickSize = axis.grid.enabled ? width * -1 : 0;
37
- const step = getClosestPointsRange(axis, getScaleTicks(scale));
38
- let yAxisGenerator = axisLeft(scale)
39
- .tickSize(tickSize)
40
- .tickPadding(axis.labels.margin)
41
- .tickFormat((value) => {
42
- if (!axis.labels.enabled) {
43
- return '';
44
- }
45
- return formatAxisTickLabel({
46
- axis,
47
- value,
48
- step,
62
+ const axisSelection = svgElement
63
+ .selectAll('axis')
64
+ .data(axises)
65
+ .join('g')
66
+ .attr('class', b())
67
+ .style('transform', (_d, index) => (index === 0 ? '' : `translate(${width}px, 0)`));
68
+ axisSelection.each((d, index, node) => {
69
+ const seriesScale = scale[index];
70
+ const axisItem = select(node[index]);
71
+ const yAxisGenerator = getAxisGenerator({
72
+ axisGenerator: index === 0
73
+ ? axisLeft(seriesScale)
74
+ : axisRight(seriesScale),
75
+ preparedAxis: d,
76
+ height,
77
+ width,
78
+ scale: seriesScale,
49
79
  });
80
+ yAxisGenerator(axisItem);
81
+ if (d.labels.enabled) {
82
+ const tickTexts = axisItem
83
+ .selectAll('.tick text')
84
+ // The offset must be applied before the labels are rotated.
85
+ // Therefore, we reset the values and make an offset in transform attribute.
86
+ // FIXME: give up axisLeft(d3) and switch to our own generation method
87
+ .attr('x', null)
88
+ .attr('dy', null)
89
+ .style('font-size', d.labels.style.fontSize)
90
+ .style('transform', function () {
91
+ return transformLabel({ node: this, axis: d });
92
+ });
93
+ const textMaxWidth = !d.labels.rotation || Math.abs(d.labels.rotation) % 360 !== 90
94
+ ? d.labels.maxWidth
95
+ : (height - d.labels.padding * (tickTexts.size() - 1)) / tickTexts.size();
96
+ tickTexts.call(setEllipsisForOverflowTexts, textMaxWidth);
97
+ }
98
+ // remove overlapping ticks
99
+ // Note: this method do not prepared for rotated labels
100
+ if (!d.labels.rotation) {
101
+ let elementY = 0;
102
+ axisItem
103
+ .selectAll('.tick')
104
+ .filter(function (_d, tickIndex) {
105
+ const tickNode = this;
106
+ const r = tickNode.getBoundingClientRect();
107
+ if (r.bottom > elementY && tickIndex !== 0) {
108
+ return true;
109
+ }
110
+ elementY = r.top - d.labels.padding;
111
+ return false;
112
+ })
113
+ .remove();
114
+ }
115
+ return axisItem;
50
116
  });
51
- const ticksCount = getTicksCount({ axis, range: height });
52
- if (ticksCount) {
53
- yAxisGenerator = yAxisGenerator.ticks(ticksCount);
54
- }
55
- svgElement.call(yAxisGenerator).attr('class', b());
56
- svgElement
117
+ axisSelection
57
118
  .select('.domain')
58
- .attr('d', `M0,${height}H0V0`)
59
- .style('stroke', axis.lineColor || '');
60
- if (axis.labels.enabled) {
61
- const tickTexts = svgElement
62
- .selectAll('.tick text')
63
- // The offset must be applied before the labels are rotated.
64
- // Therefore, we reset the values and make an offset in transform attribute.
65
- // FIXME: give up axisLeft(d3) and switch to our own generation method
66
- .attr('x', null)
67
- .attr('dy', null)
68
- .style('font-size', axis.labels.style.fontSize)
69
- .style('transform', function () {
70
- return transformLabel(this, axis);
71
- });
72
- const textMaxWidth = !axis.labels.rotation || Math.abs(axis.labels.rotation) % 360 !== 90
73
- ? axis.labels.maxWidth
74
- : (height - axis.labels.padding * (tickTexts.size() - 1)) / tickTexts.size();
75
- tickTexts.call(setEllipsisForOverflowTexts, textMaxWidth);
76
- }
77
- const transformStyle = svgElement.select('.tick').attr('transform');
78
- const { y } = parseTransformStyle(transformStyle);
79
- if (y === height) {
80
- // Remove stroke from tick that has the same y coordinate like domain
81
- svgElement.select('.tick line').style('stroke', 'none');
82
- }
83
- // remove overlapping ticks
84
- // Note: this method do not prepared for rotated labels
85
- if (!axis.labels.rotation) {
86
- let elementY = 0;
87
- svgElement
88
- .selectAll('.tick')
89
- .filter(function (_d, index) {
90
- const node = this;
91
- const r = node.getBoundingClientRect();
92
- if (r.bottom > elementY && index !== 0) {
93
- return true;
94
- }
95
- elementY = r.top - axis.labels.padding;
96
- return false;
97
- })
98
- .remove();
99
- }
100
- if (axis.title.text) {
101
- const textY = axis.title.margin + axis.labels.margin + axis.labels.width;
102
- svgElement
103
- .append('text')
104
- .attr('class', b('title'))
105
- .attr('text-anchor', 'middle')
106
- .attr('dy', -textY)
107
- .attr('dx', -height / 2)
108
- .attr('font-size', axis.title.style.fontSize)
109
- .attr('transform', 'rotate(-90)')
110
- .text(axis.title.text)
111
- .call(setEllipsisForOverflowText, height);
112
- }
119
+ .attr('d', () => {
120
+ const points = [
121
+ [0, 0],
122
+ [0, height],
123
+ ];
124
+ return line()(points);
125
+ })
126
+ .style('stroke', (d) => d.lineColor || '');
127
+ svgElement.selectAll('.tick').each((_d, index, nodes) => {
128
+ const tickNode = select(nodes[index]);
129
+ if (parseTransformStyle(tickNode.attr('transform')).y === height) {
130
+ // Remove stroke from tick that has the same y coordinate like domain
131
+ tickNode.select('line').style('stroke', 'none');
132
+ }
133
+ });
134
+ axisSelection
135
+ .append('text')
136
+ .attr('class', b('title'))
137
+ .attr('text-anchor', 'middle')
138
+ .attr('dy', (d) => -(d.title.margin + d.labels.margin + d.labels.width))
139
+ .attr('dx', (_d, index) => (index === 0 ? -height / 2 : height / 2))
140
+ .attr('font-size', (d) => d.title.style.fontSize)
141
+ .attr('transform', (_d, index) => (index === 0 ? 'rotate(-90)' : 'rotate(90)'))
142
+ .text((d) => d.title.text)
143
+ .each((_d, index, node) => {
144
+ return setEllipsisForOverflowText(select(node[index]), height);
145
+ });
113
146
  }, [axises, width, height, scale]);
114
- return React.createElement("g", { ref: ref });
147
+ return React.createElement("g", { ref: ref, className: b('container') });
115
148
  };
@@ -4,7 +4,7 @@ import throttle from 'lodash/throttle';
4
4
  import { block } from '../../../../utils/cn';
5
5
  import { getD3Dispatcher } from '../d3-dispatcher';
6
6
  import { useAxisScales, useChartDimensions, useChartOptions, useSeries, useShapes } from '../hooks';
7
- import { getWidthOccupiedByYAxis } from '../hooks/useChartDimensions/utils';
7
+ import { getYAxisWidth } from '../hooks/useChartDimensions/utils';
8
8
  import { getPreparedXAxis } from '../hooks/useChartOptions/x-axis';
9
9
  import { getPreparedYAxis } from '../hooks/useChartOptions/y-axis';
10
10
  import { getClosestPoints } from '../utils/get-closest-data';
@@ -73,7 +73,8 @@ export const Chart = (props) => {
73
73
  };
74
74
  }, [dispatcher, clickHandler]);
75
75
  const boundsOffsetTop = chart.margin.top;
76
- const boundsOffsetLeft = chart.margin.left + getWidthOccupiedByYAxis({ preparedAxis: yAxis });
76
+ // We only need to consider the width of the first left axis
77
+ const boundsOffsetLeft = chart.margin.left + getYAxisWidth(yAxis[0]);
77
78
  const handleMouseMove = (event) => {
78
79
  const [pointerX, pointerY] = pointer(event, svgRef.current);
79
80
  const x = pointerX - boundsOffsetLeft;
@@ -97,7 +98,7 @@ export const Chart = (props) => {
97
98
  React.createElement("svg", { ref: svgRef, className: b(), width: width, height: height, onMouseMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave },
98
99
  title && React.createElement(Title, Object.assign({}, title, { chartWidth: width })),
99
100
  React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})` },
100
- xScale && yScale && (React.createElement(React.Fragment, null,
101
+ xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length) && (React.createElement(React.Fragment, null,
101
102
  React.createElement(AxisY, { axises: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale }),
102
103
  React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
103
104
  React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale })))),
@@ -12,7 +12,7 @@ type Args = {
12
12
  };
13
13
  type ReturnValue = {
14
14
  xScale?: ChartScale;
15
- yScale?: ChartScale;
15
+ yScale?: ChartScale[];
16
16
  };
17
17
  export declare function createYScale(axis: PreparedAxis, series: PreparedSeries[], boundsHeight: number): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
18
18
  export declare function createXScale(axis: PreparedAxis | ChartKitWidgetAxis, series: (PreparedSeries | ChartKitWidgetSeries)[], boundsWidth: number): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
@@ -135,7 +135,14 @@ const createScales = (args) => {
135
135
  visibleSeries = visibleSeries.length === 0 ? series : visibleSeries;
136
136
  return {
137
137
  xScale: createXScale(xAxis, visibleSeries, boundsWidth),
138
- yScale: createYScale(yAxis[0], visibleSeries, boundsHeight),
138
+ yScale: yAxis.map((axis, index) => {
139
+ const axisSeries = series.filter((s) => {
140
+ const seriesAxisIndex = get(s, 'yAxis', 0);
141
+ return seriesAxisIndex === index;
142
+ });
143
+ const visibleAxisSeries = getOnlyVisibleSeries(axisSeries);
144
+ return createYScale(axis, visibleAxisSeries.length ? visibleAxisSeries : axisSeries, boundsHeight);
145
+ }),
139
146
  };
140
147
  };
141
148
  /**
@@ -4,6 +4,7 @@ export declare const getBoundsWidth: (args: {
4
4
  chartMargin: PreparedChart['margin'];
5
5
  preparedYAxis: PreparedAxis[];
6
6
  }) => number;
7
+ export declare function getYAxisWidth(axis: PreparedAxis | undefined): number;
7
8
  export declare function getWidthOccupiedByYAxis(args: {
8
9
  preparedAxis: PreparedAxis[];
9
10
  }): number;
@@ -5,16 +5,17 @@ export const getBoundsWidth = (args) => {
5
5
  chartMargin.left -
6
6
  getWidthOccupiedByYAxis({ preparedAxis: preparedYAxis }));
7
7
  };
8
- export function getWidthOccupiedByYAxis(args) {
9
- const { preparedAxis } = args;
8
+ export function getYAxisWidth(axis) {
10
9
  let result = 0;
11
- preparedAxis.forEach((axis) => {
12
- if (axis.title.text) {
13
- result += axis.title.height + axis.title.margin;
14
- }
15
- if (axis.labels.enabled) {
16
- result += axis.labels.margin + axis.labels.width;
17
- }
18
- });
10
+ if (axis === null || axis === void 0 ? void 0 : axis.title.text) {
11
+ result += axis.title.height + axis.title.margin;
12
+ }
13
+ if (axis === null || axis === void 0 ? void 0 : axis.labels.enabled) {
14
+ result += axis.labels.margin + axis.labels.width;
15
+ }
19
16
  return result;
20
17
  }
18
+ export function getWidthOccupiedByYAxis(args) {
19
+ const { preparedAxis = [] } = args;
20
+ return preparedAxis.reduce((sum, axis) => sum + getYAxisWidth(axis), 0);
21
+ }
@@ -27,6 +27,7 @@ export type PreparedAxis = Omit<ChartKitWidgetAxis, 'type' | 'labels'> & {
27
27
  ticks: {
28
28
  pixelInterval?: number;
29
29
  };
30
+ position: 'left' | 'right' | 'top' | 'bottom';
30
31
  };
31
32
  export type PreparedTitle = ChartKitWidgetData['title'] & {
32
33
  height: number;
@@ -79,6 +79,7 @@ export const getPreparedXAxis = ({ xAxis, series, width, }) => {
79
79
  ticks: {
80
80
  pixelInterval: get(xAxis, 'ticks.pixelInterval'),
81
81
  },
82
+ position: 'bottom',
82
83
  };
83
84
  const { height, rotation } = getLabelSettings({
84
85
  axis: preparedXAxis,
@@ -41,54 +41,60 @@ function getAxisMin(axis, series) {
41
41
  return min;
42
42
  }
43
43
  export const getPreparedYAxis = ({ series, yAxis, }) => {
44
- // FIXME: add support for n axises
45
- const yAxis1 = yAxis === null || yAxis === void 0 ? void 0 : yAxis[0];
46
- const labelsEnabled = get(yAxis1, 'labels.enabled', true);
47
- const y1LabelsStyle = {
48
- fontSize: get(yAxis1, 'labels.style.fontSize', DEFAULT_AXIS_LABEL_FONT_SIZE),
49
- };
50
- const y1TitleText = get(yAxis1, 'title.text', '');
51
- const y1TitleStyle = {
52
- fontSize: get(yAxis1, 'title.style.fontSize', yAxisTitleDefaults.fontSize),
53
- };
54
- const axisType = get(yAxis1, 'type', 'linear');
55
- const preparedY1Axis = {
56
- type: axisType,
57
- labels: {
58
- enabled: labelsEnabled,
59
- margin: labelsEnabled ? get(yAxis1, 'labels.margin', axisLabelsDefaults.margin) : 0,
60
- padding: labelsEnabled ? get(yAxis1, 'labels.padding', axisLabelsDefaults.padding) : 0,
61
- dateFormat: get(yAxis1, 'labels.dateFormat'),
62
- numberFormat: get(yAxis1, 'labels.numberFormat'),
63
- style: y1LabelsStyle,
64
- rotation: get(yAxis1, 'labels.rotation', 0),
65
- width: 0,
66
- height: 0,
67
- lineHeight: getHorisontalSvgTextHeight({ text: 'TmpLabel', style: y1LabelsStyle }),
68
- maxWidth: get(yAxis1, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
69
- },
70
- lineColor: get(yAxis1, 'lineColor'),
71
- categories: get(yAxis1, 'categories'),
72
- timestamps: get(yAxis1, 'timestamps'),
73
- title: {
74
- text: y1TitleText,
75
- margin: get(yAxis1, 'title.margin', yAxisTitleDefaults.margin),
76
- style: y1TitleStyle,
77
- height: y1TitleText
78
- ? getHorisontalSvgTextHeight({ text: y1TitleText, style: y1TitleStyle })
79
- : 0,
80
- },
81
- min: getAxisMin(yAxis1, series),
82
- maxPadding: get(yAxis1, 'maxPadding', 0.05),
83
- grid: {
84
- enabled: get(yAxis1, 'grid.enabled', true),
85
- },
86
- ticks: {
87
- pixelInterval: get(yAxis1, 'ticks.pixelInterval'),
88
- },
89
- };
90
- if (labelsEnabled) {
91
- preparedY1Axis.labels.width = getAxisLabelMaxWidth({ axis: preparedY1Axis, series });
92
- }
93
- return [preparedY1Axis];
44
+ return (yAxis || [{}]).map((axisItem, index) => {
45
+ const axisPosition = index === 0 ? 'left' : 'right';
46
+ const labelsEnabled = get(axisItem, 'labels.enabled', true);
47
+ const labelsStyle = {
48
+ fontSize: get(axisItem, 'labels.style.fontSize', DEFAULT_AXIS_LABEL_FONT_SIZE),
49
+ };
50
+ const titleText = get(axisItem, 'title.text', '');
51
+ const titleStyle = {
52
+ fontSize: get(axisItem, 'title.style.fontSize', yAxisTitleDefaults.fontSize),
53
+ };
54
+ const axisType = get(axisItem, 'type', 'linear');
55
+ const preparedAxis = {
56
+ type: axisType,
57
+ labels: {
58
+ enabled: labelsEnabled,
59
+ margin: labelsEnabled
60
+ ? get(axisItem, 'labels.margin', axisLabelsDefaults.margin)
61
+ : 0,
62
+ padding: labelsEnabled
63
+ ? get(axisItem, 'labels.padding', axisLabelsDefaults.padding)
64
+ : 0,
65
+ dateFormat: get(axisItem, 'labels.dateFormat'),
66
+ numberFormat: get(axisItem, 'labels.numberFormat'),
67
+ style: labelsStyle,
68
+ rotation: get(axisItem, 'labels.rotation', 0),
69
+ width: 0,
70
+ height: 0,
71
+ lineHeight: getHorisontalSvgTextHeight({ text: 'TmpLabel', style: labelsStyle }),
72
+ maxWidth: get(axisItem, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
73
+ },
74
+ lineColor: get(axisItem, 'lineColor'),
75
+ categories: get(axisItem, 'categories'),
76
+ timestamps: get(axisItem, 'timestamps'),
77
+ title: {
78
+ text: titleText,
79
+ margin: get(axisItem, 'title.margin', yAxisTitleDefaults.margin),
80
+ style: titleStyle,
81
+ height: titleText
82
+ ? getHorisontalSvgTextHeight({ text: titleText, style: titleStyle })
83
+ : 0,
84
+ },
85
+ min: getAxisMin(axisItem, series),
86
+ maxPadding: get(axisItem, 'maxPadding', 0.05),
87
+ grid: {
88
+ enabled: get(axisItem, 'grid.enabled', index === 0),
89
+ },
90
+ ticks: {
91
+ pixelInterval: get(axisItem, 'ticks.pixelInterval'),
92
+ },
93
+ position: axisPosition,
94
+ };
95
+ if (labelsEnabled) {
96
+ preparedAxis.labels.width = getAxisLabelMaxWidth({ axis: preparedAxis, series });
97
+ }
98
+ return preparedAxis;
99
+ });
94
100
  };
@@ -5,9 +5,9 @@ export declare const DEFAULT_LINE_WIDTH = 1;
5
5
  export declare const DEFAULT_MARKER: {
6
6
  enabled: boolean;
7
7
  symbol: "circle" | "diamond" | "square" | "triangle" | "triangle-down";
8
- radius: number;
9
8
  borderColor: string;
10
9
  borderWidth: number;
10
+ radius: number;
11
11
  };
12
12
  type PrepareAreaSeriesArgs = {
13
13
  colorScale: ScaleOrdinal<string, string>;
@@ -55,6 +55,7 @@ export function prepareArea(args) {
55
55
  },
56
56
  marker: prepareMarker(series, seriesOptions),
57
57
  cursor: get(series, 'cursor', null),
58
+ yAxis: get(series, 'yAxis', 0),
58
59
  };
59
60
  return prepared;
60
61
  }, []);
@@ -31,6 +31,7 @@ export function prepareBarXSeries(args) {
31
31
  padding: get(series, 'dataLabels.padding', DEFAULT_DATALABELS_PADDING),
32
32
  },
33
33
  cursor: get(series, 'cursor', null),
34
+ yAxis: get(series, 'yAxis', 0),
34
35
  };
35
36
  }, []);
36
37
  }
@@ -5,10 +5,10 @@ import merge from 'lodash/merge';
5
5
  import { legendDefaults } from '../../constants';
6
6
  import { getHorisontalSvgTextHeight } from '../../utils';
7
7
  import { getBoundsWidth } from '../useChartDimensions';
8
- import { getWidthOccupiedByYAxis } from '../useChartDimensions/utils';
8
+ import { getYAxisWidth } from '../useChartDimensions/utils';
9
9
  export const getPreparedLegend = (args) => {
10
10
  const { legend, series } = args;
11
- const enabled = typeof (legend === null || legend === void 0 ? void 0 : legend.enabled) === 'boolean' ? legend === null || legend === void 0 ? void 0 : legend.enabled : series.length > 1;
11
+ const enabled = Boolean(typeof (legend === null || legend === void 0 ? void 0 : legend.enabled) === 'boolean' ? legend === null || legend === void 0 ? void 0 : legend.enabled : series.length > 1);
12
12
  const defaultItemStyle = clone(legendDefaults.itemStyle);
13
13
  const itemStyle = get(legend, 'itemStyle');
14
14
  const computedItemStyle = merge(defaultItemStyle, itemStyle);
@@ -90,7 +90,7 @@ export const getLegendComponents = (args) => {
90
90
  preparedLegend.height = legendHeight;
91
91
  const top = chartHeight - chartMargin.bottom - preparedLegend.height;
92
92
  const offset = {
93
- left: chartMargin.left + getWidthOccupiedByYAxis({ preparedAxis: preparedYAxis }),
93
+ left: chartMargin.left + getYAxisWidth(preparedYAxis[0]),
94
94
  top,
95
95
  };
96
96
  return { legendConfig: { offset, pagination }, legendItems: items };
@@ -8,9 +8,9 @@ export declare const DEFAULT_DASH_STYLE = DashStyle.Solid;
8
8
  export declare const DEFAULT_MARKER: {
9
9
  enabled: boolean;
10
10
  symbol: "circle" | "diamond" | "square" | "triangle" | "triangle-down";
11
- radius: number;
12
11
  borderColor: string;
13
12
  borderWidth: number;
13
+ radius: number;
14
14
  };
15
15
  type PrepareLineSeriesArgs = {
16
16
  colorScale: ScaleOrdinal<string, string>;
@@ -74,6 +74,7 @@ export function prepareLineSeries(args) {
74
74
  linecap: prepareLinecap(dashStyle, series, seriesOptions),
75
75
  opacity: get(series, 'opacity', null),
76
76
  cursor: get(series, 'cursor', null),
77
+ yAxis: get(series, 'yAxis', 0),
77
78
  };
78
79
  return prepared;
79
80
  }, []);
@@ -40,6 +40,7 @@ export function prepareScatterSeries(args) {
40
40
  data: s.data,
41
41
  marker: prepareMarker(s, seriesOptions, index),
42
42
  cursor: get(s, 'cursor', null),
43
+ yAxis: get(s, 'yAxis', 0),
43
44
  };
44
45
  return prepared;
45
46
  }, []);
@@ -76,6 +76,7 @@ export type PreparedScatterSeries = {
76
76
  };
77
77
  };
78
78
  };
79
+ yAxis: number;
79
80
  } & BasePreparedSeries;
80
81
  export type PreparedBarXSeries = {
81
82
  type: BarXSeries['type'];
@@ -89,6 +90,7 @@ export type PreparedBarXSeries = {
89
90
  allowOverlap: boolean;
90
91
  padding: number;
91
92
  };
93
+ yAxis: number;
92
94
  } & BasePreparedSeries;
93
95
  export type PreparedBarYSeries = {
94
96
  type: BarYSeries['type'];
@@ -164,6 +166,7 @@ export type PreparedLineSeries = {
164
166
  dashStyle: DashStyle;
165
167
  linecap: LineCap;
166
168
  opacity: number | null;
169
+ yAxis: number;
167
170
  } & BasePreparedSeries;
168
171
  export type PreparedAreaSeries = {
169
172
  type: AreaSeries['type'];
@@ -196,6 +199,7 @@ export type PreparedAreaSeries = {
196
199
  };
197
200
  };
198
201
  };
202
+ yAxis: number;
199
203
  } & BasePreparedSeries;
200
204
  export type PreparedTreemapSeries = {
201
205
  type: TreemapSeries['type'];
@@ -7,5 +7,6 @@ export declare const prepareAreaData: (args: {
7
7
  xAxis: PreparedAxis;
8
8
  xScale: ChartScale;
9
9
  yAxis: PreparedAxis[];
10
- yScale: ChartScale;
10
+ yScale: ChartScale[];
11
+ boundsHeight: number;
11
12
  }) => PreparedAreaData[];