@gravity-ui/charts 1.7.1 → 1.9.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 (95) hide show
  1. package/dist/cjs/components/Axis/AxisX.js +10 -8
  2. package/dist/cjs/components/Axis/AxisY.js +16 -36
  3. package/dist/cjs/components/ChartInner/index.js +15 -1
  4. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +4 -2
  5. package/dist/cjs/components/ChartInner/useChartInnerProps.js +4 -1
  6. package/dist/cjs/components/Legend/index.d.ts +1 -0
  7. package/dist/cjs/components/Legend/index.js +113 -51
  8. package/dist/cjs/components/Legend/styles.css +13 -0
  9. package/dist/cjs/components/Tooltip/DefaultContent.js +6 -3
  10. package/dist/cjs/constants/chart-types.d.ts +12 -0
  11. package/dist/cjs/constants/chart-types.js +12 -0
  12. package/dist/cjs/constants/defaults/axis.d.ts +3 -1
  13. package/dist/cjs/constants/defaults/axis.js +10 -0
  14. package/dist/cjs/constants/index.d.ts +6 -47
  15. package/dist/cjs/constants/index.js +6 -72
  16. package/dist/cjs/constants/layout-algorithms.d.ts +7 -0
  17. package/dist/cjs/constants/layout-algorithms.js +8 -0
  18. package/dist/cjs/constants/line-styles.d.ts +20 -0
  19. package/dist/cjs/constants/line-styles.js +20 -0
  20. package/dist/cjs/constants/palette.d.ts +1 -0
  21. package/dist/cjs/constants/palette.js +22 -0
  22. package/dist/cjs/constants/symbol-types.d.ts +7 -0
  23. package/dist/cjs/constants/symbol-types.js +8 -0
  24. package/dist/cjs/constants/typography.d.ts +1 -0
  25. package/dist/cjs/constants/typography.js +1 -0
  26. package/dist/cjs/hooks/index.d.ts +1 -0
  27. package/dist/cjs/hooks/index.js +1 -0
  28. package/dist/cjs/hooks/useChartOptions/types.d.ts +4 -2
  29. package/dist/cjs/hooks/useChartOptions/x-axis.js +11 -2
  30. package/dist/cjs/hooks/useChartOptions/y-axis.js +14 -3
  31. package/dist/cjs/hooks/useCrosshair/index.d.ts +17 -0
  32. package/dist/cjs/hooks/useCrosshair/index.js +139 -0
  33. package/dist/cjs/hooks/useCrosshair/useCrosshairHover.d.ts +11 -0
  34. package/dist/cjs/hooks/useCrosshair/useCrosshairHover.js +18 -0
  35. package/dist/cjs/hooks/useSeries/index.d.ts +4 -2
  36. package/dist/cjs/hooks/useSeries/prepare-legend.d.ts +11 -9
  37. package/dist/cjs/hooks/useSeries/prepare-legend.js +78 -23
  38. package/dist/cjs/hooks/useSeries/prepare-line.d.ts +1 -2
  39. package/dist/cjs/hooks/useSeries/prepare-line.js +3 -3
  40. package/dist/cjs/hooks/useSeries/types.d.ts +7 -3
  41. package/dist/cjs/hooks/useShapes/waterfall/index.js +2 -2
  42. package/dist/cjs/types/chart/axis.d.ts +26 -21
  43. package/dist/cjs/types/chart/legend.d.ts +6 -0
  44. package/dist/cjs/types/chart/line.d.ts +1 -1
  45. package/dist/cjs/types/chart/series.d.ts +1 -1
  46. package/dist/cjs/utils/chart/axis.d.ts +1 -0
  47. package/dist/cjs/utils/chart/axis.js +8 -0
  48. package/dist/esm/components/Axis/AxisX.js +10 -8
  49. package/dist/esm/components/Axis/AxisY.js +16 -36
  50. package/dist/esm/components/ChartInner/index.js +15 -1
  51. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +4 -2
  52. package/dist/esm/components/ChartInner/useChartInnerProps.js +4 -1
  53. package/dist/esm/components/Legend/index.d.ts +1 -0
  54. package/dist/esm/components/Legend/index.js +113 -51
  55. package/dist/esm/components/Legend/styles.css +13 -0
  56. package/dist/esm/components/Tooltip/DefaultContent.js +6 -3
  57. package/dist/esm/constants/chart-types.d.ts +12 -0
  58. package/dist/esm/constants/chart-types.js +12 -0
  59. package/dist/esm/constants/defaults/axis.d.ts +3 -1
  60. package/dist/esm/constants/defaults/axis.js +10 -0
  61. package/dist/esm/constants/index.d.ts +6 -47
  62. package/dist/esm/constants/index.js +6 -72
  63. package/dist/esm/constants/layout-algorithms.d.ts +7 -0
  64. package/dist/esm/constants/layout-algorithms.js +8 -0
  65. package/dist/esm/constants/line-styles.d.ts +20 -0
  66. package/dist/esm/constants/line-styles.js +20 -0
  67. package/dist/esm/constants/palette.d.ts +1 -0
  68. package/dist/esm/constants/palette.js +22 -0
  69. package/dist/esm/constants/symbol-types.d.ts +7 -0
  70. package/dist/esm/constants/symbol-types.js +8 -0
  71. package/dist/esm/constants/typography.d.ts +1 -0
  72. package/dist/esm/constants/typography.js +1 -0
  73. package/dist/esm/hooks/index.d.ts +1 -0
  74. package/dist/esm/hooks/index.js +1 -0
  75. package/dist/esm/hooks/useChartOptions/types.d.ts +4 -2
  76. package/dist/esm/hooks/useChartOptions/x-axis.js +11 -2
  77. package/dist/esm/hooks/useChartOptions/y-axis.js +14 -3
  78. package/dist/esm/hooks/useCrosshair/index.d.ts +17 -0
  79. package/dist/esm/hooks/useCrosshair/index.js +139 -0
  80. package/dist/esm/hooks/useCrosshair/useCrosshairHover.d.ts +11 -0
  81. package/dist/esm/hooks/useCrosshair/useCrosshairHover.js +18 -0
  82. package/dist/esm/hooks/useSeries/index.d.ts +4 -2
  83. package/dist/esm/hooks/useSeries/prepare-legend.d.ts +11 -9
  84. package/dist/esm/hooks/useSeries/prepare-legend.js +78 -23
  85. package/dist/esm/hooks/useSeries/prepare-line.d.ts +1 -2
  86. package/dist/esm/hooks/useSeries/prepare-line.js +3 -3
  87. package/dist/esm/hooks/useSeries/types.d.ts +7 -3
  88. package/dist/esm/hooks/useShapes/waterfall/index.js +2 -2
  89. package/dist/esm/types/chart/axis.d.ts +26 -21
  90. package/dist/esm/types/chart/legend.d.ts +6 -0
  91. package/dist/esm/types/chart/line.d.ts +1 -1
  92. package/dist/esm/types/chart/series.d.ts +1 -1
  93. package/dist/esm/utils/chart/axis.d.ts +1 -0
  94. package/dist/esm/utils/chart/axis.js +8 -0
  95. package/package.json +1 -1
@@ -6,7 +6,7 @@ import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
6
6
  import { getDefaultColorStops, getDomainForContinuousColorScale, getHorisontalSvgTextHeight, getLabelsSize, } from '../../utils';
7
7
  import { getBoundsWidth } from '../useChartDimensions';
8
8
  import { getYAxisWidth } from '../useChartDimensions/utils';
9
- export const getPreparedLegend = (args) => {
9
+ export function getPreparedLegend(args) {
10
10
  var _a, _b, _c, _d, _e, _f, _g;
11
11
  const { legend, series } = args;
12
12
  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);
@@ -69,40 +69,65 @@ export const getPreparedLegend = (args) => {
69
69
  width: legendWidth,
70
70
  ticks,
71
71
  colorScale,
72
+ html: get(legend, 'html', false),
72
73
  };
73
- };
74
- const getFlattenLegendItems = (series) => {
74
+ }
75
+ function getFlattenLegendItems(series, preparedLegend) {
75
76
  return series.reduce((acc, s) => {
76
77
  const legendEnabled = get(s, 'legend.enabled', true);
77
78
  if (legendEnabled) {
78
- acc.push(Object.assign(Object.assign({}, s), { symbol: s.legend.symbol }));
79
+ acc.push(Object.assign(Object.assign({}, s), { height: preparedLegend.lineHeight, symbol: s.legend.symbol }));
79
80
  }
80
81
  return acc;
81
82
  }, []);
82
- };
83
- const getGroupedLegendItems = (args) => {
83
+ }
84
+ function getGroupedLegendItems(args) {
84
85
  const { maxLegendWidth, items, preparedLegend } = args;
85
86
  const result = [[]];
87
+ const bodySelection = select(document.body);
86
88
  let textWidthsInLine = [0];
87
89
  let lineIndex = 0;
88
90
  items.forEach((item) => {
89
- select(document.body)
90
- .append('text')
91
- .text(item.name)
91
+ const itemSelection = preparedLegend.html
92
+ ? bodySelection
93
+ .append('div')
94
+ .html(item.name)
95
+ .style('position', 'absolute')
96
+ .style('display', 'inline-block')
97
+ .style('white-space', 'nowrap')
98
+ : bodySelection.append('text').text(item.name).style('white-space', 'nowrap');
99
+ itemSelection
92
100
  .style('font-size', preparedLegend.itemStyle.fontSize)
93
101
  .each(function () {
94
102
  const resultItem = clone(item);
95
- const textWidth = this.getBoundingClientRect().width;
96
- resultItem.textWidth = textWidth;
103
+ const { height, width: textWidth } = this.getBoundingClientRect();
104
+ resultItem.height = height;
105
+ if (textWidth >
106
+ maxLegendWidth - resultItem.symbol.width - resultItem.symbol.padding) {
107
+ resultItem.overflowed = true;
108
+ resultItem.textWidth =
109
+ maxLegendWidth - resultItem.symbol.width - resultItem.symbol.padding;
110
+ }
111
+ else {
112
+ resultItem.textWidth = textWidth;
113
+ }
97
114
  textWidthsInLine.push(textWidth);
98
115
  const textsWidth = textWidthsInLine.reduce((acc, width) => acc + width, 0);
116
+ if (!result[lineIndex]) {
117
+ result[lineIndex] = [];
118
+ }
99
119
  result[lineIndex].push(resultItem);
100
120
  const symbolsWidth = result[lineIndex].reduce((acc, { symbol }) => {
101
121
  return acc + symbol.width + symbol.padding;
102
122
  }, 0);
103
123
  const distancesWidth = (result[lineIndex].length - 1) * preparedLegend.itemDistance;
104
- const isOverfilled = maxLegendWidth < textsWidth + symbolsWidth + distancesWidth;
105
- if (isOverfilled) {
124
+ const isOverflowedAsOnlyItemInLine = resultItem.overflowed && result[lineIndex].length === 1;
125
+ const isCurrentLineOverMaxWidth = maxLegendWidth < textsWidth + symbolsWidth + distancesWidth;
126
+ if (isOverflowedAsOnlyItemInLine) {
127
+ lineIndex += 1;
128
+ textWidthsInLine = [];
129
+ }
130
+ else if (isCurrentLineOverMaxWidth) {
106
131
  result[lineIndex].pop();
107
132
  lineIndex += 1;
108
133
  textWidthsInLine = [textWidth];
@@ -114,12 +139,36 @@ const getGroupedLegendItems = (args) => {
114
139
  .remove();
115
140
  });
116
141
  return result;
117
- };
118
- export const getLegendComponents = (args) => {
142
+ }
143
+ function getPagination(args) {
144
+ const { items, maxLegendHeight, paginatorHeight } = args;
145
+ const pages = [];
146
+ let currentPageIndex = 0;
147
+ let currentHeight = 0;
148
+ items.forEach((item, i) => {
149
+ if (!pages[currentPageIndex]) {
150
+ pages[currentPageIndex] = { start: i, end: i };
151
+ }
152
+ const legendLineHeight = Math.max(...item.map((item) => item.height));
153
+ currentHeight += legendLineHeight;
154
+ if (currentHeight > maxLegendHeight - paginatorHeight) {
155
+ pages[currentPageIndex].end = i;
156
+ currentPageIndex += 1;
157
+ currentHeight = legendLineHeight;
158
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice#end
159
+ pages[currentPageIndex] = { start: i, end: i + (i === items.length - 1 ? 1 : 0) };
160
+ }
161
+ else if (i === items.length - 1) {
162
+ pages[currentPageIndex].end = i + 1;
163
+ }
164
+ });
165
+ return { pages };
166
+ }
167
+ export function getLegendComponents(args) {
119
168
  const { chartWidth, chartHeight, chartMargin, series, preparedLegend, preparedYAxis } = args;
120
169
  const maxLegendWidth = getBoundsWidth({ chartWidth, chartMargin, preparedYAxis });
121
170
  const maxLegendHeight = (chartHeight - chartMargin.top - chartMargin.bottom - preparedLegend.margin) / 2;
122
- const flattenLegendItems = getFlattenLegendItems(series);
171
+ const flattenLegendItems = getFlattenLegendItems(series, preparedLegend);
123
172
  const items = getGroupedLegendItems({
124
173
  maxLegendWidth,
125
174
  items: flattenLegendItems,
@@ -127,13 +176,19 @@ export const getLegendComponents = (args) => {
127
176
  });
128
177
  let pagination;
129
178
  if (preparedLegend.type === 'discrete') {
130
- let legendHeight = preparedLegend.lineHeight * items.length;
179
+ const lineHeights = items.reduce((acc, item) => {
180
+ acc.push(Math.max(...item.map((item) => item.height)));
181
+ return acc;
182
+ }, []);
183
+ let legendHeight = lineHeights.reduce((acc, height) => acc + height, 0);
131
184
  if (maxLegendHeight < legendHeight) {
132
- // extra line for paginator
133
- const limit = Math.floor(maxLegendHeight / preparedLegend.lineHeight) - 1;
134
- const maxPage = Math.ceil(items.length / limit);
135
- pagination = { limit, maxPage };
136
- legendHeight = preparedLegend.lineHeight * (limit + 1);
185
+ const lines = Math.floor(maxLegendHeight / preparedLegend.lineHeight);
186
+ legendHeight = preparedLegend.lineHeight * lines;
187
+ pagination = getPagination({
188
+ items,
189
+ maxLegendHeight: legendHeight,
190
+ paginatorHeight: preparedLegend.lineHeight,
191
+ });
137
192
  }
138
193
  preparedLegend.height = legendHeight;
139
194
  }
@@ -143,4 +198,4 @@ export const getLegendComponents = (args) => {
143
198
  top,
144
199
  };
145
200
  return { legendConfig: { offset, pagination }, legendItems: items };
146
- };
201
+ }
@@ -1,10 +1,9 @@
1
1
  import type { ScaleOrdinal } from 'd3';
2
- import { DashStyle } from '../../constants';
3
2
  import type { ChartSeriesOptions, LineSeries } from '../../types';
4
3
  import type { PreparedLegend, PreparedLineSeries } from './types';
5
4
  export declare const DEFAULT_LEGEND_SYMBOL_SIZE = 16;
6
5
  export declare const DEFAULT_LINE_WIDTH = 1;
7
- export declare const DEFAULT_DASH_STYLE = DashStyle.Solid;
6
+ export declare const DEFAULT_DASH_STYLE: "Solid";
8
7
  export declare const DEFAULT_MARKER: {
9
8
  enabled: boolean;
10
9
  symbol: `${import("../../constants").SymbolType}`;
@@ -1,14 +1,14 @@
1
1
  import get from 'lodash/get';
2
2
  import merge from 'lodash/merge';
3
- import { DEFAULT_DATALABELS_STYLE, DashStyle, LineCap } from '../../constants';
3
+ import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap } from '../../constants';
4
4
  import { getUniqId } from '../../utils';
5
5
  import { DEFAULT_DATALABELS_PADDING, DEFAULT_HALO_OPTIONS, DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_POINT_MARKER_OPTIONS, } from './constants';
6
6
  export const DEFAULT_LEGEND_SYMBOL_SIZE = 16;
7
7
  export const DEFAULT_LINE_WIDTH = 1;
8
- export const DEFAULT_DASH_STYLE = DashStyle.Solid;
8
+ export const DEFAULT_DASH_STYLE = DASH_STYLE.Solid;
9
9
  export const DEFAULT_MARKER = Object.assign(Object.assign({}, DEFAULT_POINT_MARKER_OPTIONS), { enabled: false });
10
10
  function prepareLinecap(dashStyle, series, seriesOptions) {
11
- const defaultLineCap = dashStyle === DashStyle.Solid ? LineCap.Round : LineCap.None;
11
+ const defaultLineCap = dashStyle === DASH_STYLE.Solid ? LineCap.Round : LineCap.None;
12
12
  const lineCapFromSeriesOptions = get(seriesOptions, 'line.linecap', defaultLineCap);
13
13
  return get(series, 'linecap', lineCapFromSeriesOptions);
14
14
  }
@@ -39,11 +39,13 @@ export type OnLegendItemClick = (data: {
39
39
  }) => void;
40
40
  export type LegendItem = {
41
41
  color: string;
42
+ height: number;
42
43
  name: string;
43
44
  symbol: PreparedLegendSymbol;
44
45
  textWidth: number;
45
- visible?: boolean;
46
46
  dashStyle?: DashStyle;
47
+ overflowed?: boolean;
48
+ visible?: boolean;
47
49
  };
48
50
  export type LegendConfig = {
49
51
  offset: {
@@ -51,8 +53,10 @@ export type LegendConfig = {
51
53
  top: number;
52
54
  };
53
55
  pagination?: {
54
- limit: number;
55
- maxPage: number;
56
+ pages: {
57
+ start: number;
58
+ end: number;
59
+ }[];
56
60
  };
57
61
  };
58
62
  export type PreparedHaloOptions = {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { color, line as lineGenerator, select } from 'd3';
3
3
  import get from 'lodash/get';
4
- import { DashStyle } from '../../../constants';
4
+ import { DASH_STYLE } from '../../../constants';
5
5
  import { block, filterOverlappingLabels, getLineDashArray, getWaterfallPointColor, } from '../../../utils';
6
6
  import { HtmlLayer } from '../HtmlLayer';
7
7
  export { prepareWaterfallData } from './prepare-data';
@@ -77,7 +77,7 @@ export const WaterfallSeriesShapes = (args) => {
77
77
  return line(points);
78
78
  })
79
79
  .attr('stroke-width', 1)
80
- .attr('stroke-dasharray', () => getLineDashArray(DashStyle.Dash, 1));
80
+ .attr('stroke-dasharray', () => getLineDashArray(DASH_STYLE.Dash, 1));
81
81
  function handleShapeHover(data) {
82
82
  hoveredDataRef.current = data;
83
83
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
@@ -1,4 +1,4 @@
1
- import type { DashStyle } from 'src/constants';
1
+ import type { DashStyle } from '../../constants';
2
2
  import type { FormatNumberOptions } from '../formatter';
3
3
  import type { BaseTextStyle } from './base';
4
4
  export type ChartAxisType = 'category' | 'datetime' | 'linear' | 'logarithmic';
@@ -7,14 +7,12 @@ export interface ChartAxisLabels {
7
7
  /** Enable or disable the axis labels. */
8
8
  enabled?: boolean;
9
9
  /** The label's pixel distance from the perimeter of the plot area.
10
- *
11
- * @default: 10
10
+ * @default 10
12
11
  */
13
12
  margin?: number;
14
13
  /** The pixel padding for axis labels, to ensure white space between them.
15
- *
16
- * @defaults: 5
17
- * */
14
+ * @default 5
15
+ */
18
16
  padding?: number;
19
17
  dateFormat?: string;
20
18
  numberFormat?: FormatNumberOptions;
@@ -24,13 +22,14 @@ export interface ChartAxisLabels {
24
22
  * As the chart gets narrower, it will start rotating the labels -45 degrees. */
25
23
  autoRotation?: boolean;
26
24
  /** Rotation of the labels in degrees.
27
- *
28
- * @default: 0
25
+ * @default 0
29
26
  */
30
27
  rotation?: number;
31
28
  }
32
29
  export interface ChartAxis {
33
30
  categories?: string[];
31
+ /** Configure a crosshair that follows either the mouse pointer or the hovered point. */
32
+ crosshair?: AxisCrosshair;
34
33
  timestamps?: number[];
35
34
  type?: ChartAxisType;
36
35
  /** The axis labels show the number or category for each tick. */
@@ -42,14 +41,14 @@ export interface ChartAxis {
42
41
  /** CSS styles for the title */
43
42
  style?: Partial<BaseTextStyle>;
44
43
  /** The pixel distance between the axis labels or line and the title.
45
- *
46
- * Defaults to 4 for horizontal axes, 8 for vertical.
47
- * */
44
+ * @default 4 for horizontal axes, 8 for vertical
45
+ */
48
46
  margin?: number;
49
47
  /** Alignment of the title. */
50
48
  align?: ChartAxisTitleAlignment;
51
49
  /** Allows limiting of the contents of a title block to the specified number of lines.
52
- * Defaults to 1. */
50
+ * @default 1
51
+ */
53
52
  maxRowCount?: number;
54
53
  };
55
54
  /** The minimum value of the axis. If undefined the min value is automatically calculate. */
@@ -57,9 +56,8 @@ export interface ChartAxis {
57
56
  /** The grid lines settings. */
58
57
  grid?: {
59
58
  /** Enable or disable the grid lines.
60
- *
61
- * Defaults to true.
62
- * */
59
+ * @default true
60
+ */
63
61
  enabled?: boolean;
64
62
  };
65
63
  ticks?: {
@@ -69,9 +67,8 @@ export interface ChartAxis {
69
67
  };
70
68
  /** Padding of the max value relative to the length of the axis.
71
69
  * A padding of 0.05 will make a 100px axis 5px longer.
72
- *
73
- * Defaults to 0.05 for Y axis and to 0.01 for X axis.
74
- * */
70
+ * @default 0.05 for Y axis, 0.01 for X axis
71
+ */
75
72
  maxPadding?: number;
76
73
  /** An array of lines stretching across the plot area, marking a specific value */
77
74
  plotLines?: AxisPlotLine[];
@@ -90,7 +87,6 @@ export interface AxisPlot {
90
87
  color?: string;
91
88
  /**
92
89
  * Individual opacity for the line.
93
- *
94
90
  * @default 1
95
91
  * */
96
92
  opacity?: number;
@@ -101,12 +97,11 @@ export interface AxisPlotLine extends AxisPlot {
101
97
  /** The color of the plot line (hex, rgba). */
102
98
  color?: string;
103
99
  /** Pixel width of the plot line.
104
- *
105
100
  * @default 1
106
101
  * */
107
102
  width?: number;
108
103
  /** Option for line stroke style. */
109
- dashStyle?: `${DashStyle}`;
104
+ dashStyle?: DashStyle;
110
105
  }
111
106
  export interface AxisPlotBand extends AxisPlot {
112
107
  /**
@@ -124,6 +119,16 @@ export interface AxisPlotBand extends AxisPlot {
124
119
  */
125
120
  to: number | string;
126
121
  }
122
+ export interface AxisCrosshair extends Omit<AxisPlotLine, 'value'> {
123
+ /** Whether the crosshair should snap to the point or follow the pointer independent of points.
124
+ * @default true
125
+ */
126
+ snap?: boolean;
127
+ /** Enable or disable the axis crosshair.
128
+ * @default false
129
+ */
130
+ enabled?: boolean;
131
+ }
127
132
  export interface ChartYAxis extends ChartAxis {
128
133
  /** Axis location.
129
134
  * Possible values - 'left' and 'right'.
@@ -53,6 +53,12 @@ export interface ChartLegend {
53
53
  domain?: number[];
54
54
  };
55
55
  width?: number;
56
+ /**
57
+ * Allows to use any html-tags to display the content.
58
+ *
59
+ * @default false
60
+ * */
61
+ html?: boolean;
56
62
  }
57
63
  export interface BaseLegendSymbol {
58
64
  /**
@@ -47,7 +47,7 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries {
47
47
  /** Options for the point markers of line series */
48
48
  marker?: PointMarkerOptions;
49
49
  /** Option for line stroke style */
50
- dashStyle?: `${DashStyle}`;
50
+ dashStyle?: DashStyle;
51
51
  /** Option for line cap style */
52
52
  linecap?: `${LineCap}`;
53
53
  /** Individual opacity for the line. */
@@ -183,7 +183,7 @@ export interface ChartSeriesOptions {
183
183
  *
184
184
  * @default 'Solid'
185
185
  * */
186
- dashStyle?: `${DashStyle}`;
186
+ dashStyle?: DashStyle;
187
187
  /** Options for line cap style
188
188
  *
189
189
  * @default 'round' when dashStyle is not 'solid', 'none' when dashStyle is not 'solid'
@@ -35,6 +35,7 @@ interface GetBandsPositionArgs {
35
35
  axisScale: AxisScale<AxisDomain>;
36
36
  axis: AxisDirection;
37
37
  }
38
+ export declare const getAxisPlotsPosition: (axis: PreparedAxis, split: PreparedSplit, width?: number) => string;
38
39
  export declare function getBandsPosition(args: GetBandsPositionArgs): {
39
40
  from: number;
40
41
  to: number;
@@ -70,6 +70,14 @@ export function getAxisTitleRows(args) {
70
70
  return acc;
71
71
  }, []);
72
72
  }
73
+ export const getAxisPlotsPosition = (axis, split, width = 0) => {
74
+ var _a;
75
+ const top = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
76
+ if (axis.position === 'left') {
77
+ return `translate(0, ${top}px)`;
78
+ }
79
+ return `translate(${width}px, ${top}px)`;
80
+ };
73
81
  export function getBandsPosition(args) {
74
82
  var _a, _b, _c;
75
83
  const { band, axisScale } = args;
@@ -50,11 +50,11 @@ export const AxisX = React.memo(function AxisX(props) {
50
50
  }
51
51
  const svgElement = select(ref.current);
52
52
  svgElement.selectAll('*').remove();
53
- const plotClassName = b('plot-x');
53
+ const plotDataAttr = 'data-plot-x';
54
54
  let plotContainer = null;
55
55
  if (plotRef === null || plotRef === void 0 ? void 0 : plotRef.current) {
56
56
  plotContainer = select(plotRef.current);
57
- plotContainer.selectAll(`.${plotClassName}`).remove();
57
+ plotContainer.selectAll(`[${plotDataAttr}]`).remove();
58
58
  }
59
59
  if (!axis.visible) {
60
60
  return;
@@ -116,12 +116,13 @@ export const AxisX = React.memo(function AxisX(props) {
116
116
  }
117
117
  // add plot bands
118
118
  if (plotContainer && axis.plotBands.length > 0) {
119
- const plotBandClassName = b('plot-x-band');
119
+ const plotBandDataAttr = 'plot-x-band';
120
120
  const plotBandsSelection = plotContainer
121
- .selectAll(`.${plotBandClassName}-x`)
121
+ .selectAll(`[${plotBandDataAttr}]`)
122
122
  .data(axis.plotBands)
123
123
  .join('g')
124
- .attr('class', `${plotClassName} ${plotBandClassName}-x`);
124
+ .attr(plotDataAttr, 1)
125
+ .attr(plotBandDataAttr, 1);
125
126
  plotBandsSelection
126
127
  .append('rect')
127
128
  .attr('x', (band) => {
@@ -153,12 +154,13 @@ export const AxisX = React.memo(function AxisX(props) {
153
154
  }
154
155
  // add plot lines
155
156
  if (plotContainer && axis.plotLines.length > 0) {
156
- const plotLineClassName = b('plot-x-line');
157
+ const plotLineDataAttr = 'plot-x-line';
157
158
  const plotLinesSelection = plotContainer
158
- .selectAll(`.${plotLineClassName}`)
159
+ .selectAll(`[${plotLineDataAttr}]`)
159
160
  .data(axis.plotLines)
160
161
  .join('g')
161
- .attr('class', `${plotClassName} ${plotLineClassName}`);
162
+ .attr(plotDataAttr, 1)
163
+ .attr(plotLineDataAttr, 1);
162
164
  const lineGenerator = line();
163
165
  plotLinesSelection
164
166
  .append('path')
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { axisLeft, axisRight, line, select } from 'd3';
3
- import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getBandsPosition, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
3
+ import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisPlotsPosition, getAxisTitleRows, getBandsPosition, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
4
4
  import './styles.css';
5
5
  const b = block('axis');
6
6
  function transformLabel(args) {
@@ -97,39 +97,17 @@ export const AxisY = (props) => {
97
97
  const svgElement = select(ref.current);
98
98
  svgElement.selectAll('*').remove();
99
99
  let plotContainer = null;
100
- const plotClassName = b('plot-y');
100
+ const plotDataAttr = 'data-plot-y';
101
101
  if (plotRef === null || plotRef === void 0 ? void 0 : plotRef.current) {
102
102
  plotContainer = select(plotRef.current);
103
- plotContainer.selectAll(`.${plotClassName}`).remove();
103
+ plotContainer.selectAll(`[${plotDataAttr}]`).remove();
104
104
  }
105
- const getAxisPosition = (axis) => {
106
- var _a;
107
- const top = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
108
- if (axis.position === 'left') {
109
- return `translate(0, ${top}px)`;
110
- }
111
- return `translate(${width}px, 0)`;
112
- };
113
- const plotLines = axes.reduce((acc, axis) => {
114
- if (axis.plotLines.length) {
115
- acc.push(...axis.plotLines.map((plotLine) => {
116
- return Object.assign(Object.assign({}, plotLine), { transform: getAxisPosition(axis) });
117
- }));
118
- }
119
- return acc;
120
- }, []);
121
- const plotBands = axes.reduce((acc, axis) => {
122
- if (axis.plotBands.length) {
123
- acc.push(...axis.plotBands.map((plotBand) => (Object.assign(Object.assign({}, plotBand), { transform: getAxisPosition(axis) }))));
124
- }
125
- return acc;
126
- }, []);
127
105
  const axisSelection = svgElement
128
106
  .selectAll('axis')
129
107
  .data(axes)
130
108
  .join('g')
131
109
  .attr('class', b())
132
- .style('transform', (d) => getAxisPosition(d));
110
+ .style('transform', (d) => getAxisPlotsPosition(d, split, width));
133
111
  axisSelection.each((d, index, node) => {
134
112
  const seriesScale = scale[index];
135
113
  const axisItem = select(node[index]);
@@ -197,13 +175,14 @@ export const AxisY = (props) => {
197
175
  .remove();
198
176
  }
199
177
  if (plotContainer && d.plotBands.length > 0) {
200
- const plotBandClassName = b('plot-y-band');
178
+ const plotBandDataAttr = `data-plot-y-band-${index}`;
201
179
  const plotBandsSelection = plotContainer
202
- .selectAll(`.${plotBandClassName}`)
203
- .data(plotBands)
180
+ .selectAll(`[${plotBandDataAttr}]`)
181
+ .data(d.plotBands)
204
182
  .join('g')
205
- .attr('class', `${plotClassName} ${plotBandClassName}`)
206
- .style('transform', (plotBand) => plotBand.transform);
183
+ .attr(plotDataAttr, 1)
184
+ .attr(plotBandDataAttr, 1)
185
+ .style('transform', getAxisPlotsPosition(d, split));
207
186
  plotBandsSelection
208
187
  .append('rect')
209
188
  .attr('x', 0)
@@ -234,13 +213,14 @@ export const AxisY = (props) => {
234
213
  });
235
214
  }
236
215
  if (plotContainer && d.plotLines.length > 0) {
237
- const plotLineClassName = b('plot-y-line');
216
+ const plotLineDataAttr = `data-plot-y-line-${index}`;
238
217
  const plotLinesSelection = plotContainer
239
- .selectAll(`.${plotLineClassName}`)
240
- .data(plotLines)
218
+ .selectAll(`[${plotLineDataAttr}]`)
219
+ .data(d.plotLines)
241
220
  .join('g')
242
- .attr('class', `${plotClassName} ${plotLineClassName}`)
243
- .style('transform', (plotLine) => plotLine.transform);
221
+ .attr(plotDataAttr, 1)
222
+ .attr(plotLineDataAttr, 1)
223
+ .style('transform', getAxisPlotsPosition(d, split));
244
224
  plotLinesSelection
245
225
  .append('path')
246
226
  .attr('d', (plotLine) => {
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { useCrosshair } from '../../hooks';
2
3
  import { EventType, block, getDispatcher } from '../../utils';
3
4
  import { AxisX, AxisY } from '../Axis';
4
5
  import { Legend } from '../Legend';
@@ -39,6 +40,19 @@ export const ChartInner = (props) => {
39
40
  });
40
41
  const clickHandler = (_b = (_a = data.chart) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.click;
41
42
  const pointerMoveHandler = (_d = (_c = data.chart) === null || _c === void 0 ? void 0 : _c.events) === null || _d === void 0 ? void 0 : _d.pointermove;
43
+ useCrosshair({
44
+ split: preparedSplit,
45
+ plotElement: plotRef.current,
46
+ boundsOffsetLeft,
47
+ boundsOffsetTop,
48
+ width: boundsWidth,
49
+ height: boundsHeight,
50
+ xAxis,
51
+ yAxes: yAxis,
52
+ yScale,
53
+ xScale,
54
+ dispatcher,
55
+ });
42
56
  React.useEffect(() => {
43
57
  if (clickHandler) {
44
58
  dispatcher.on(EventType.CLICK_CHART, clickHandler);
@@ -71,7 +85,7 @@ export const ChartInner = (props) => {
71
85
  React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
72
86
  React.createElement(AxisX, { leftmostLimit: svgXPos, axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, split: preparedSplit, plotRef: plotRef })))),
73
87
  shapes),
74
- preparedLegend.enabled && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip }))),
88
+ preparedLegend.enabled && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayerRef.current }))),
75
89
  React.createElement("div", { className: b('html-layer'), ref: htmlLayerRef, style: {
76
90
  '--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
77
91
  } }),
@@ -20,8 +20,10 @@ export declare function useChartInnerProps(props: Props): {
20
20
  top: number;
21
21
  };
22
22
  pagination: {
23
- limit: number;
24
- maxPage: number;
23
+ pages: {
24
+ start: number;
25
+ end: number;
26
+ }[];
25
27
  } | undefined;
26
28
  };
27
29
  legendItems: import("../../hooks").LegendItem[][];
@@ -56,9 +56,12 @@ export function useChartInnerProps(props) {
56
56
  htmlLayout,
57
57
  });
58
58
  const boundsOffsetTop = chart.margin.top;
59
- // We need to calculate the width of each axis because the first axis can be hidden
59
+ // We need to calculate the width of each left axis because the first axis can be hidden
60
60
  const boundsOffsetLeft = chart.margin.left +
61
61
  yAxis.reduce((acc, axis) => {
62
+ if (axis.position !== 'left') {
63
+ return acc;
64
+ }
62
65
  const axisWidth = getYAxisWidth(axis);
63
66
  if (acc < axisWidth) {
64
67
  acc = axisWidth;
@@ -7,6 +7,7 @@ type Props = {
7
7
  legend: PreparedLegend;
8
8
  items: LegendItem[][];
9
9
  config: LegendConfig;
10
+ htmlLayout: HTMLElement | null;
10
11
  onItemClick: OnLegendItemClick;
11
12
  onUpdate?: () => void;
12
13
  };