@gravity-ui/charts 1.16.0 → 1.17.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 (87) hide show
  1. package/dist/{esm/components/Axis → cjs/components/AxisX}/AxisX.js +1 -15
  2. package/dist/{esm/components/Axis → cjs/components/AxisY}/AxisY.d.ts +2 -10
  3. package/dist/cjs/components/AxisY/AxisY.js +173 -0
  4. package/dist/cjs/components/AxisY/prepare-axis-data.d.ts +9 -0
  5. package/dist/cjs/components/AxisY/prepare-axis-data.js +306 -0
  6. package/dist/cjs/components/AxisY/styles.css +15 -0
  7. package/dist/cjs/components/AxisY/types.d.ts +81 -0
  8. package/dist/cjs/components/AxisY/types.js +1 -0
  9. package/dist/cjs/components/AxisY/utils.d.ts +12 -0
  10. package/dist/cjs/components/AxisY/utils.js +71 -0
  11. package/dist/cjs/components/ChartInner/index.js +31 -3
  12. package/dist/cjs/components/ChartInner/useChartInnerProps.js +13 -1
  13. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +5 -2
  14. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +7 -1
  15. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +12 -7
  16. package/dist/cjs/constants/date.d.ts +1 -0
  17. package/dist/cjs/constants/date.js +1 -0
  18. package/dist/cjs/constants/index.d.ts +1 -0
  19. package/dist/cjs/constants/index.js +1 -0
  20. package/dist/cjs/hooks/useChartOptions/types.d.ts +7 -1
  21. package/dist/cjs/hooks/useChartOptions/x-axis.js +5 -5
  22. package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +3 -1
  23. package/dist/cjs/hooks/useChartOptions/y-axis.js +20 -20
  24. package/dist/cjs/hooks/useCrosshair/index.js +2 -1
  25. package/dist/cjs/index.d.ts +1 -1
  26. package/dist/cjs/index.js +1 -1
  27. package/dist/cjs/types/chart/axis.d.ts +11 -1
  28. package/dist/cjs/types/chart/base.d.ts +1 -0
  29. package/dist/cjs/utils/chart/axis-generators/bottom.js +3 -3
  30. package/dist/cjs/utils/chart/axis.d.ts +14 -8
  31. package/dist/cjs/utils/chart/axis.js +34 -9
  32. package/dist/cjs/utils/chart/format.js +2 -1
  33. package/dist/cjs/utils/chart/index.d.ts +0 -7
  34. package/dist/cjs/utils/chart/index.js +0 -17
  35. package/dist/cjs/utils/chart/text.d.ts +2 -1
  36. package/dist/cjs/utils/chart/text.js +3 -10
  37. package/dist/{cjs/components/Axis → esm/components/AxisX}/AxisX.js +1 -15
  38. package/dist/{cjs/components/Axis → esm/components/AxisY}/AxisY.d.ts +2 -10
  39. package/dist/esm/components/AxisY/AxisY.js +173 -0
  40. package/dist/esm/components/AxisY/prepare-axis-data.d.ts +9 -0
  41. package/dist/esm/components/AxisY/prepare-axis-data.js +306 -0
  42. package/dist/esm/components/AxisY/styles.css +15 -0
  43. package/dist/esm/components/AxisY/types.d.ts +81 -0
  44. package/dist/esm/components/AxisY/types.js +1 -0
  45. package/dist/esm/components/AxisY/utils.d.ts +12 -0
  46. package/dist/esm/components/AxisY/utils.js +71 -0
  47. package/dist/esm/components/ChartInner/index.js +31 -3
  48. package/dist/esm/components/ChartInner/useChartInnerProps.js +13 -1
  49. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +5 -2
  50. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +7 -1
  51. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +12 -7
  52. package/dist/esm/constants/date.d.ts +1 -0
  53. package/dist/esm/constants/date.js +1 -0
  54. package/dist/esm/constants/index.d.ts +1 -0
  55. package/dist/esm/constants/index.js +1 -0
  56. package/dist/esm/hooks/useChartOptions/types.d.ts +7 -1
  57. package/dist/esm/hooks/useChartOptions/x-axis.js +5 -5
  58. package/dist/esm/hooks/useChartOptions/y-axis.d.ts +3 -1
  59. package/dist/esm/hooks/useChartOptions/y-axis.js +20 -20
  60. package/dist/esm/hooks/useCrosshair/index.js +2 -1
  61. package/dist/esm/index.d.ts +1 -1
  62. package/dist/esm/index.js +1 -1
  63. package/dist/esm/types/chart/axis.d.ts +11 -1
  64. package/dist/esm/types/chart/base.d.ts +1 -0
  65. package/dist/esm/utils/chart/axis-generators/bottom.js +3 -3
  66. package/dist/esm/utils/chart/axis.d.ts +14 -8
  67. package/dist/esm/utils/chart/axis.js +34 -9
  68. package/dist/esm/utils/chart/format.js +2 -1
  69. package/dist/esm/utils/chart/index.d.ts +0 -7
  70. package/dist/esm/utils/chart/index.js +0 -17
  71. package/dist/esm/utils/chart/text.d.ts +2 -1
  72. package/dist/esm/utils/chart/text.js +3 -10
  73. package/package.json +1 -1
  74. package/dist/cjs/components/Axis/AxisY.js +0 -416
  75. package/dist/cjs/components/Axis/index.d.ts +0 -2
  76. package/dist/cjs/components/Axis/index.js +0 -2
  77. package/dist/cjs/components/Tooltip/utils.d.ts +0 -30
  78. package/dist/cjs/components/Tooltip/utils.js +0 -126
  79. package/dist/esm/components/Axis/AxisY.js +0 -416
  80. package/dist/esm/components/Axis/index.d.ts +0 -2
  81. package/dist/esm/components/Axis/index.js +0 -2
  82. package/dist/esm/components/Tooltip/utils.d.ts +0 -30
  83. package/dist/esm/components/Tooltip/utils.js +0 -126
  84. /package/dist/cjs/components/{Axis → AxisX}/AxisX.d.ts +0 -0
  85. /package/dist/cjs/components/{Axis → AxisX}/styles.css +0 -0
  86. /package/dist/esm/components/{Axis → AxisX}/AxisX.d.ts +0 -0
  87. /package/dist/esm/components/{Axis → AxisX}/styles.css +0 -0
@@ -1,23 +1,9 @@
1
1
  import React from 'react';
2
2
  import { line, select } from 'd3';
3
- import { block, formatAxisTickLabel, getAxisTitleRows, getBandsPosition, getClosestPointsRange, getLineDashArray, getMaxTickCount, getScaleTicks, getTicksCount, handleOverflowingText, } from '../../utils';
3
+ import { block, getAxisTitleRows, getBandsPosition, getLabelFormatter, getLineDashArray, getMaxTickCount, getTicksCount, handleOverflowingText, } from '../../utils';
4
4
  import { axisBottom } from '../../utils/chart/axis-generators';
5
5
  import './styles.css';
6
6
  const b = block('axis');
7
- function getLabelFormatter({ axis, scale }) {
8
- const ticks = getScaleTicks(scale);
9
- const tickStep = getClosestPointsRange(axis, ticks);
10
- return (value) => {
11
- if (!axis.labels.enabled) {
12
- return '';
13
- }
14
- return formatAxisTickLabel({
15
- axis,
16
- value,
17
- step: tickStep,
18
- });
19
- };
20
- }
21
7
  export function getTitlePosition(args) {
22
8
  const { axis, width, rowCount } = args;
23
9
  if (rowCount < 1) {
@@ -1,19 +1,11 @@
1
1
  import React from 'react';
2
- import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
2
+ import type { AxisYData } from './types';
3
3
  import './styles.css';
4
4
  interface Props {
5
- axes: PreparedAxis[];
6
- boundsOffsetTop: number;
7
- boundsOffsetLeft: number;
8
- scale: ChartScale[];
9
- width: number;
10
- height: number;
5
+ preparedAxisData: AxisYData;
11
6
  htmlLayout: HTMLElement | null;
12
- split: PreparedSplit;
13
7
  plotBeforeRef?: React.MutableRefObject<SVGGElement | null>;
14
8
  plotAfterRef?: React.MutableRefObject<SVGGElement | null>;
15
- bottomLimit?: number;
16
- topLimit?: number;
17
9
  }
18
10
  export declare const AxisY: (props: Props) => React.JSX.Element;
19
11
  export {};
@@ -0,0 +1,173 @@
1
+ import React from 'react';
2
+ import { line, select } from 'd3';
3
+ import { HtmlLayer } from '../../hooks/useShapes/HtmlLayer';
4
+ import { block, getLineDashArray } from '../../utils';
5
+ import './styles.css';
6
+ const b = block('y-axis');
7
+ export const AxisY = (props) => {
8
+ const { htmlLayout, plotBeforeRef, plotAfterRef, preparedAxisData } = props;
9
+ const ref = React.useRef(null);
10
+ const lineGenerator = line();
11
+ const htmlLabels = preparedAxisData.ticks.map((d) => d.htmlLabel).filter(Boolean);
12
+ React.useEffect(() => {
13
+ if (!ref.current) {
14
+ return;
15
+ }
16
+ const svgElement = select(ref.current);
17
+ svgElement.selectAll('*').remove();
18
+ let plotBeforeContainer = null;
19
+ let plotAfterContainer = null;
20
+ const plotDataAttr = 'data-plot-y';
21
+ if (plotBeforeRef === null || plotBeforeRef === void 0 ? void 0 : plotBeforeRef.current) {
22
+ plotBeforeContainer = select(plotBeforeRef.current);
23
+ plotBeforeContainer.selectAll(`[${plotDataAttr}]`).remove();
24
+ }
25
+ if (plotAfterRef === null || plotAfterRef === void 0 ? void 0 : plotAfterRef.current) {
26
+ plotAfterContainer = select(plotAfterRef.current);
27
+ plotAfterContainer.selectAll(`[${plotDataAttr}]`).remove();
28
+ }
29
+ if (preparedAxisData.title) {
30
+ svgElement
31
+ .append('g')
32
+ .attr('class', b('title'))
33
+ .append('text')
34
+ .attr('text-anchor', 'start')
35
+ .style('dominant-baseline', 'text-after-edge')
36
+ .style('transform', `translate(${preparedAxisData.title.x}px, ${preparedAxisData.title.y}px) rotate(${preparedAxisData.title.rotate}deg) translate(0px, ${preparedAxisData.title.offset}px)`)
37
+ .attr('font-size', preparedAxisData.title.style.fontSize)
38
+ .selectAll('tspan')
39
+ .data(preparedAxisData.title.content)
40
+ .join('tspan')
41
+ .html((d) => d.text)
42
+ .attr('x', (d) => d.x)
43
+ .attr('y', (d) => d.y)
44
+ .attr('text-anchor', 'start');
45
+ }
46
+ svgElement
47
+ .append('path')
48
+ .attr('class', b('domain'))
49
+ .attr('d', lineGenerator([preparedAxisData.domain.start, preparedAxisData.domain.end]))
50
+ .style('stroke', preparedAxisData.domain.lineColor);
51
+ const tickClassName = b('tick');
52
+ const ticks = svgElement
53
+ .selectAll(`.${tickClassName}`)
54
+ .remove()
55
+ .data(preparedAxisData.ticks)
56
+ .join('g')
57
+ .attr('class', tickClassName);
58
+ const labelClassName = b('label');
59
+ ticks.each(function () {
60
+ var _a;
61
+ const tickSelection = select(this);
62
+ const tickData = tickSelection.datum();
63
+ if (tickData.line) {
64
+ tickSelection.append('path').attr('d', lineGenerator(tickData.line.points));
65
+ }
66
+ if (tickData.svgLabel) {
67
+ const label = tickData.svgLabel;
68
+ const textSelection = tickSelection.append('text');
69
+ if (label.title) {
70
+ textSelection.append('title').html(label.title);
71
+ }
72
+ textSelection
73
+ .selectAll('tspan')
74
+ .data(label.content)
75
+ .join('tspan')
76
+ .html((d) => d.text)
77
+ .attr('x', (d) => d.x)
78
+ .attr('y', (d) => d.y)
79
+ .attr('text-anchor', 'start')
80
+ .attr('class', labelClassName)
81
+ .style('dominant-baseline', 'text-before-edge')
82
+ .style('font-size', label.style.fontSize)
83
+ .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '');
84
+ }
85
+ });
86
+ if (preparedAxisData.plotBands.length > 0) {
87
+ const plotBandDataAttr = `data-plot-y-band-${preparedAxisData.id}`;
88
+ const setPlotBands = (plotContainer, plotBands) => {
89
+ if (!plotContainer || !plotBands.length) {
90
+ return;
91
+ }
92
+ const plotBandsSelection = plotContainer
93
+ .selectAll(`[${plotBandDataAttr}]`)
94
+ .remove()
95
+ .data(plotBands)
96
+ .join('g')
97
+ .attr(plotDataAttr, 1)
98
+ .attr(plotBandDataAttr, 1)
99
+ .style('transform', (d) => `translate(${d.x}px, ${d.y}px)`);
100
+ plotBandsSelection
101
+ .append('rect')
102
+ .attr('width', (d) => d.width)
103
+ .attr('height', (d) => d.height)
104
+ .attr('fill', (d) => d.color)
105
+ .attr('opacity', (d) => d.opacity);
106
+ plotBandsSelection.each(function () {
107
+ var _a, _b;
108
+ const plotBandSelection = select(this);
109
+ const band = plotBandSelection.datum();
110
+ const label = band.label;
111
+ if (label) {
112
+ plotBandSelection
113
+ .append('text')
114
+ .html(label.text)
115
+ .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
116
+ .style('font-size', label.style.fontSize)
117
+ .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
118
+ .style('dominant-baseline', 'text-before-edge')
119
+ .attr('x', label.x)
120
+ .attr('y', label.y);
121
+ }
122
+ });
123
+ };
124
+ setPlotBands(plotBeforeContainer, preparedAxisData.plotBands.filter((item) => item.layerPlacement === 'before'));
125
+ setPlotBands(plotAfterContainer, preparedAxisData.plotBands.filter((item) => item.layerPlacement === 'after'));
126
+ }
127
+ if (preparedAxisData.plotLines.length > 0) {
128
+ const plotLineDataAttr = `data-plot-y-line-${preparedAxisData.id}`;
129
+ const setPlotLines = (plotContainer, plotLines) => {
130
+ if (!plotContainer || !plotLines.length) {
131
+ return;
132
+ }
133
+ const plotLinesSelection = plotContainer
134
+ .selectAll(`[${plotLineDataAttr}]`)
135
+ .remove()
136
+ .data(plotLines)
137
+ .join('g')
138
+ .attr(plotDataAttr, 1)
139
+ .attr(plotLineDataAttr, 1)
140
+ .style('transform', (d) => `translate(${d.x}px, ${d.y}px)`);
141
+ plotLinesSelection
142
+ .append('path')
143
+ .attr('d', (d) => lineGenerator(d.points))
144
+ .attr('stroke', (d) => d.color)
145
+ .attr('stroke-width', (d) => d.lineWidth)
146
+ .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
147
+ .attr('opacity', (d) => d.opacity);
148
+ plotLinesSelection.each(function () {
149
+ var _a, _b;
150
+ const itemSelection = select(this);
151
+ const plotLine = itemSelection.datum();
152
+ const label = plotLine.label;
153
+ if (label) {
154
+ itemSelection
155
+ .append('text')
156
+ .text(label.text)
157
+ .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
158
+ .style('font-size', label.style.fontSize)
159
+ .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
160
+ .style('dominant-baseline', 'text-before-edge')
161
+ .attr('x', label.x)
162
+ .attr('y', label.y);
163
+ }
164
+ });
165
+ };
166
+ setPlotLines(plotBeforeContainer, preparedAxisData.plotLines.filter((item) => item.layerPlacement === 'before'));
167
+ setPlotLines(plotAfterContainer, preparedAxisData.plotLines.filter((item) => item.layerPlacement === 'after'));
168
+ }
169
+ }, [lineGenerator, plotAfterRef, plotBeforeRef, preparedAxisData]);
170
+ return (React.createElement(React.Fragment, null,
171
+ React.createElement(HtmlLayer, { preparedData: { htmlElements: htmlLabels }, htmlLayout: htmlLayout }),
172
+ React.createElement("g", { ref: ref, className: b() })));
173
+ };
@@ -0,0 +1,9 @@
1
+ import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
2
+ import type { AxisYData } from './types';
3
+ export declare function prepareAxisData({ axis, split, scale, width, height, }: {
4
+ axis: PreparedAxis;
5
+ split: PreparedSplit;
6
+ scale: ChartScale;
7
+ width: number;
8
+ height: number;
9
+ }): Promise<AxisYData>;
@@ -0,0 +1,306 @@
1
+ import { getUniqId } from '@gravity-ui/uikit';
2
+ import { calculateCos, calculateSin, getBandsPosition, getLabelFormatter, getLabelsSize, getTextSizeFn, getTextWithElipsis, wrapText, } from '../../utils';
3
+ import { getTickValues } from './utils';
4
+ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHeight, }) {
5
+ var _a;
6
+ const originalTextSize = await getTextSize(text);
7
+ // Currently, a preliminary label calculation is used to build the chart - we cannot exceed it here.
8
+ // Therefore, we rely on a pre-calculated number instead of the current maximum label width.
9
+ const labelMaxWidth = axis.labels.width; //axis.labels.maxWidth;
10
+ const size = originalTextSize;
11
+ const content = [];
12
+ // Warp label text only for categories - it will look strange for numbers or dates.
13
+ if (originalTextSize.width > labelMaxWidth && axis.type === 'category') {
14
+ const textRows = await wrapText({
15
+ text,
16
+ style: axis.labels.style,
17
+ width: labelMaxWidth,
18
+ getTextSize,
19
+ });
20
+ let topOffset = top;
21
+ let newLabelWidth = 0;
22
+ let newLabelHeight = 0;
23
+ for (let textRowIndex = 0; textRowIndex < textRows.length; textRowIndex++) {
24
+ const textRow = textRows[textRowIndex];
25
+ let textSize = await getTextSize(textRow.text);
26
+ if (newLabelHeight + textSize.height <= labelMaxHeight) {
27
+ newLabelWidth = Math.max(newLabelWidth, textSize.width);
28
+ newLabelHeight += textSize.height;
29
+ let rowText = textRow.text.trim();
30
+ if (textRowIndex < textRows.length - 1) {
31
+ const nextTextRow = textRows[textRowIndex + 1];
32
+ if (newLabelHeight + (await getTextSize(nextTextRow.text)).height >
33
+ labelMaxHeight) {
34
+ rowText = textRow.text + nextTextRow.text;
35
+ }
36
+ }
37
+ textSize = await getTextSize(rowText);
38
+ if (textSize.width > labelMaxWidth) {
39
+ rowText = await getTextWithElipsis({
40
+ text: rowText,
41
+ getTextWidth: async (str) => (await getTextSize(str)).width,
42
+ maxWidth: labelMaxWidth,
43
+ });
44
+ textSize = await getTextSize(rowText);
45
+ }
46
+ const x = axis.position === 'left'
47
+ ? left - textSize.width - axis.labels.margin
48
+ : left + axis.labels.margin;
49
+ content.push({
50
+ text: rowText,
51
+ x,
52
+ y: topOffset,
53
+ size: textSize,
54
+ });
55
+ topOffset += textSize.height;
56
+ }
57
+ }
58
+ content.forEach((row) => {
59
+ row.y -= newLabelHeight / 2;
60
+ });
61
+ size.width = newLabelWidth;
62
+ size.height = newLabelHeight;
63
+ }
64
+ else {
65
+ const x = axis.position === 'left'
66
+ ? left - size.width - axis.labels.margin
67
+ : left + axis.labels.margin;
68
+ content.push({
69
+ text,
70
+ x,
71
+ y: Math.max(0, top - size.height / 2),
72
+ size,
73
+ });
74
+ }
75
+ const svgLabel = {
76
+ title: content.length > 1 || ((_a = content[0]) === null || _a === void 0 ? void 0 : _a.text) !== text ? text : undefined,
77
+ content: content,
78
+ style: axis.labels.style,
79
+ size: size,
80
+ };
81
+ return svgLabel;
82
+ }
83
+ // eslint-disable-next-line complexity
84
+ export async function prepareAxisData({ axis, split, scale, width, height, }) {
85
+ var _a, _b, _c;
86
+ const axisPlotTopPosition = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
87
+ const axisHeight = ((_b = split.plots[axis.plotIndex]) === null || _b === void 0 ? void 0 : _b.height) || height;
88
+ const domainX = axis.position === 'left' ? 0 : width;
89
+ const domain = {
90
+ start: [domainX, axisPlotTopPosition],
91
+ end: [domainX, axisPlotTopPosition + axisHeight],
92
+ lineColor: (_c = axis.lineColor) !== null && _c !== void 0 ? _c : '',
93
+ };
94
+ const ticks = [];
95
+ const getTextSize = getTextSizeFn({ style: axis.labels.style });
96
+ const labelLineHeight = (await getTextSize('Tmp')).height;
97
+ const values = getTickValues({ scale, axis, labelLineHeight });
98
+ const labelMaxHeight = values.length > 1 ? values[0].y - values[1].y - axis.labels.padding * 2 : axisHeight;
99
+ const labelFormatter = getLabelFormatter({ axis, scale });
100
+ for (let i = 0; i < values.length; i++) {
101
+ const tickValue = values[i];
102
+ const y = axisPlotTopPosition + tickValue.y;
103
+ let svgLabel = null;
104
+ let htmlLabel = null;
105
+ if (axis.labels.enabled) {
106
+ if (axis.labels.html) {
107
+ const content = String(tickValue.value);
108
+ const labelSize = await getLabelsSize({
109
+ labels: [content],
110
+ html: true,
111
+ style: axis.labels.style,
112
+ });
113
+ const size = { width: labelSize.maxWidth, height: labelSize.maxHeight };
114
+ const left = domainX;
115
+ const top = y;
116
+ const x = axis.position === 'left'
117
+ ? left - size.width - axis.labels.margin
118
+ : left + axis.labels.margin;
119
+ htmlLabel = {
120
+ content,
121
+ x,
122
+ y: top - size.height / 2,
123
+ size,
124
+ style: axis.labels.style,
125
+ };
126
+ }
127
+ else {
128
+ const text = labelFormatter(tickValue.value);
129
+ svgLabel = await getSvgAxisLabel({
130
+ getTextSize,
131
+ text,
132
+ axis,
133
+ top: y,
134
+ left: domainX,
135
+ labelMaxHeight,
136
+ });
137
+ }
138
+ }
139
+ const tickLine = axis.grid.enabled
140
+ ? {
141
+ points: [
142
+ [0, y],
143
+ [width, y],
144
+ ],
145
+ }
146
+ : null;
147
+ ticks.push({
148
+ line: tickLine,
149
+ svgLabel,
150
+ htmlLabel,
151
+ });
152
+ }
153
+ let labelsWidth = ticks.reduce((acc, item) => { var _a, _b, _c, _d; return Math.max(acc, (_d = (_b = (_a = item.svgLabel) === null || _a === void 0 ? void 0 : _a.size.width) !== null && _b !== void 0 ? _b : (_c = item.htmlLabel) === null || _c === void 0 ? void 0 : _c.size.width) !== null && _d !== void 0 ? _d : 0); }, 0);
154
+ labelsWidth = Math.min(axis.labels.width, labelsWidth);
155
+ let title = null;
156
+ if (axis.title.text) {
157
+ const getTitleTextSize = getTextSizeFn({ style: axis.title.style });
158
+ const rotateAngle = axis.position === 'left' ? -90 : 90;
159
+ const sin = Math.abs(calculateSin(rotateAngle));
160
+ const cos = Math.abs(calculateCos(rotateAngle));
161
+ const titleContent = [];
162
+ const titleMaxWidth = sin * axisHeight;
163
+ if (axis.title.maxRowCount > 1) {
164
+ const titleTextRows = await wrapText({
165
+ text: axis.title.text,
166
+ style: axis.title.style,
167
+ width: titleMaxWidth,
168
+ getTextSize: getTitleTextSize,
169
+ });
170
+ for (let i = 0; i < axis.title.maxRowCount && i < titleTextRows.length; i++) {
171
+ const textRow = titleTextRows[i];
172
+ const textRowContent = textRow.text.trim();
173
+ const textRowSize = await getTitleTextSize(textRowContent);
174
+ titleContent.push({
175
+ text: textRowContent,
176
+ x: 0,
177
+ y: textRow.y,
178
+ size: textRowSize,
179
+ });
180
+ }
181
+ }
182
+ else {
183
+ const text = await getTextWithElipsis({
184
+ text: axis.title.text,
185
+ maxWidth: titleMaxWidth,
186
+ getTextWidth: async (s) => (await getTitleTextSize(s)).width,
187
+ });
188
+ titleContent.push({
189
+ text,
190
+ x: 0,
191
+ y: 0,
192
+ size: await getTitleTextSize(text),
193
+ });
194
+ }
195
+ const originalTextSize = titleContent.reduce((acc, item) => {
196
+ acc.width = Math.max(acc.width, item.size.width);
197
+ acc.height += item.size.height;
198
+ return acc;
199
+ }, { width: 0, height: 0 });
200
+ const rotatedTitleSize = {
201
+ width: sin * originalTextSize.height + cos * originalTextSize.width,
202
+ height: sin * originalTextSize.width + cos * originalTextSize.height,
203
+ };
204
+ const bottom = Math.max(0, calculateSin(rotateAngle) * originalTextSize.width);
205
+ let y = 0;
206
+ switch (axis.title.align) {
207
+ case 'left': {
208
+ y = -bottom + axisHeight;
209
+ break;
210
+ }
211
+ case 'center': {
212
+ y = -bottom + axisHeight / 2 + rotatedTitleSize.height / 2;
213
+ break;
214
+ }
215
+ case 'right': {
216
+ y = -bottom + rotatedTitleSize.height;
217
+ break;
218
+ }
219
+ }
220
+ const left = Math.min(0, calculateCos(rotateAngle) * originalTextSize.width);
221
+ const x = axis.position === 'left'
222
+ ? -left - labelsWidth - axis.labels.margin - axis.title.margin
223
+ : -left + width + labelsWidth + axis.labels.margin + axis.title.margin;
224
+ title = {
225
+ content: titleContent,
226
+ style: axis.title.style,
227
+ size: rotatedTitleSize,
228
+ x: x,
229
+ y: axisPlotTopPosition + y,
230
+ rotate: rotateAngle,
231
+ offset: -(originalTextSize.height / titleContent.length) * (titleContent.length - 1),
232
+ };
233
+ }
234
+ const plotBands = [];
235
+ axis.plotBands.forEach((plotBand) => {
236
+ var _a, _b;
237
+ const axisScale = scale;
238
+ const { from, to } = getBandsPosition({
239
+ band: plotBand,
240
+ axisScale,
241
+ axis: 'y',
242
+ });
243
+ const halfBandwidth = ((_b = (_a = axisScale.bandwidth) === null || _a === void 0 ? void 0 : _a.call(axisScale)) !== null && _b !== void 0 ? _b : 0) / 2;
244
+ const startPos = halfBandwidth + Math.min(from, to);
245
+ const endPos = Math.min(Math.abs(to - from), axisHeight - Math.min(from, to));
246
+ const top = Math.max(0, startPos);
247
+ plotBands.push({
248
+ layerPlacement: plotBand.layerPlacement,
249
+ x: 0,
250
+ y: axisPlotTopPosition + top,
251
+ width,
252
+ height: Math.min(endPos, axisHeight),
253
+ color: plotBand.color,
254
+ opacity: plotBand.opacity,
255
+ label: plotBand.label.text
256
+ ? {
257
+ text: plotBand.label.text,
258
+ style: plotBand.label.style,
259
+ x: plotBand.label.padding,
260
+ y: plotBand.label.padding,
261
+ }
262
+ : null,
263
+ });
264
+ });
265
+ const plotLines = [];
266
+ for (let i = 0; i < axis.plotLines.length; i++) {
267
+ const plotLine = axis.plotLines[i];
268
+ const axisScale = scale;
269
+ const plotLineValue = Number(axisScale(plotLine.value));
270
+ const points = [
271
+ [0, plotLineValue],
272
+ [width, plotLineValue],
273
+ ];
274
+ let label = null;
275
+ if (plotLine.label.text) {
276
+ const getTitleTextSize = getTextSizeFn({ style: plotLine.label.style });
277
+ const size = await getTitleTextSize(plotLine.label.text);
278
+ label = {
279
+ text: plotLine.label.text,
280
+ style: plotLine.label.style,
281
+ x: plotLine.label.padding,
282
+ y: Math.max(0, plotLineValue - size.height - plotLine.label.padding),
283
+ };
284
+ }
285
+ plotLines.push({
286
+ layerPlacement: plotLine.layerPlacement,
287
+ x: 0,
288
+ y: axisPlotTopPosition,
289
+ width,
290
+ color: plotLine.color,
291
+ opacity: plotLine.opacity,
292
+ label,
293
+ points,
294
+ lineWidth: plotLine.width,
295
+ dashStyle: plotLine.dashStyle,
296
+ });
297
+ }
298
+ return {
299
+ id: getUniqId(),
300
+ title,
301
+ ticks,
302
+ domain,
303
+ plotBands,
304
+ plotLines,
305
+ };
306
+ }
@@ -0,0 +1,15 @@
1
+ .gcharts-y-axis__domain {
2
+ stroke: var(--g-color-line-generic-active);
3
+ }
4
+ .gcharts-y-axis__label {
5
+ fill: var(--g-color-text-secondary);
6
+ stroke: none;
7
+ dominant-baseline: text-after-edge;
8
+ }
9
+ .gcharts-y-axis__tick {
10
+ stroke: var(--g-color-line-generic);
11
+ }
12
+ .gcharts-y-axis__title {
13
+ dominant-baseline: text-after-edge;
14
+ fill: var(--g-color-text-secondary);
15
+ }
@@ -0,0 +1,81 @@
1
+ import type { DashStyle } from 'src/constants';
2
+ import type { BaseTextStyle, HtmlItem, PlotLayerPlacement } from '../../types';
3
+ export type TextRowData = {
4
+ text: string;
5
+ x: number;
6
+ y: number;
7
+ size: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ };
12
+ export type AxisSvgLabelData = {
13
+ content: TextRowData[];
14
+ title?: string;
15
+ style: BaseTextStyle;
16
+ size: {
17
+ width: number;
18
+ height: number;
19
+ };
20
+ };
21
+ export type AxisTickLine = {
22
+ points: [number, number][];
23
+ };
24
+ export type AxisTickData = {
25
+ line: AxisTickLine | null;
26
+ svgLabel: AxisSvgLabelData | null;
27
+ htmlLabel: HtmlItem | null;
28
+ };
29
+ export type AxisTitleData = {
30
+ content: TextRowData[];
31
+ style: BaseTextStyle;
32
+ size: {
33
+ width: number;
34
+ height: number;
35
+ };
36
+ x: number;
37
+ y: number;
38
+ rotate: number;
39
+ offset: number;
40
+ };
41
+ export type AxisPlotLineLabel = {
42
+ text: string;
43
+ style: BaseTextStyle;
44
+ x: number;
45
+ y: number;
46
+ };
47
+ export type AxisPlotLineData = {
48
+ layerPlacement: PlotLayerPlacement;
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ points: [number, number][];
53
+ color: string;
54
+ lineWidth: number;
55
+ opacity: number;
56
+ label: AxisPlotLineLabel | null;
57
+ dashStyle: DashStyle;
58
+ };
59
+ export type AxisPlotBandData = {
60
+ layerPlacement: PlotLayerPlacement;
61
+ x: number;
62
+ y: number;
63
+ width: number;
64
+ height: number;
65
+ color: string;
66
+ opacity: number;
67
+ label: AxisPlotLineLabel | null;
68
+ };
69
+ export type AxisDomainData = {
70
+ start: [number, number];
71
+ end: [number, number];
72
+ lineColor: string;
73
+ };
74
+ export type AxisYData = {
75
+ id: string;
76
+ title: AxisTitleData | null;
77
+ domain: AxisDomainData;
78
+ ticks: AxisTickData[];
79
+ plotLines: AxisPlotLineData[];
80
+ plotBands: AxisPlotBandData[];
81
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { ChartScale, PreparedAxis } from '../../hooks';
2
+ export declare function getTickValues({ scale, axis, labelLineHeight, }: {
3
+ scale: ChartScale;
4
+ axis: PreparedAxis;
5
+ labelLineHeight: number;
6
+ }): {
7
+ y: number;
8
+ value: number | Date;
9
+ }[] | {
10
+ y: number;
11
+ value: string;
12
+ }[];