@gravity-ui/chartkit 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/build/plugins/d3/__stories__/LinearCategories.stories.d.ts +4 -0
  2. package/build/plugins/d3/__stories__/LinearCategories.stories.js +101 -0
  3. package/build/plugins/d3/__stories__/Timestamp.stories.d.ts +4 -0
  4. package/build/plugins/d3/__stories__/Timestamp.stories.js +89 -0
  5. package/build/plugins/d3/__stories__/penguins.json +3098 -0
  6. package/build/plugins/d3/index.d.ts +7 -0
  7. package/build/plugins/d3/index.js +10 -0
  8. package/build/plugins/d3/renderer/D3Widget.d.ts +15 -0
  9. package/build/plugins/d3/renderer/D3Widget.js +40 -0
  10. package/build/plugins/d3/renderer/components/AxisX.d.ts +10 -0
  11. package/build/plugins/d3/renderer/components/AxisX.js +68 -0
  12. package/build/plugins/d3/renderer/components/AxisY.d.ts +10 -0
  13. package/build/plugins/d3/renderer/components/AxisY.js +73 -0
  14. package/build/plugins/d3/renderer/components/Chart.d.ts +10 -0
  15. package/build/plugins/d3/renderer/components/Chart.js +64 -0
  16. package/build/plugins/d3/renderer/components/Legend.d.ts +12 -0
  17. package/build/plugins/d3/renderer/components/Legend.js +66 -0
  18. package/build/plugins/d3/renderer/components/Title.d.ts +7 -0
  19. package/build/plugins/d3/renderer/components/Title.js +8 -0
  20. package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.d.ts +10 -0
  21. package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.js +21 -0
  22. package/build/plugins/d3/renderer/components/Tooltip/index.d.ts +12 -0
  23. package/build/plugins/d3/renderer/components/Tooltip/index.js +53 -0
  24. package/build/plugins/d3/renderer/components/index.d.ts +1 -0
  25. package/build/plugins/d3/renderer/components/index.js +1 -0
  26. package/build/plugins/d3/renderer/components/styles.css +61 -0
  27. package/build/plugins/d3/renderer/constants.d.ts +1 -0
  28. package/build/plugins/d3/renderer/constants.js +22 -0
  29. package/build/plugins/d3/renderer/hooks/index.d.ts +10 -0
  30. package/build/plugins/d3/renderer/hooks/index.js +10 -0
  31. package/build/plugins/d3/renderer/hooks/useChartDimensions/index.d.ts +17 -0
  32. package/build/plugins/d3/renderer/hooks/useChartDimensions/index.js +13 -0
  33. package/build/plugins/d3/renderer/hooks/useChartEvents/index.d.ts +5 -0
  34. package/build/plugins/d3/renderer/hooks/useChartEvents/index.js +15 -0
  35. package/build/plugins/d3/renderer/hooks/useChartOptions/chart.d.ts +8 -0
  36. package/build/plugins/d3/renderer/hooks/useChartOptions/chart.js +60 -0
  37. package/build/plugins/d3/renderer/hooks/useChartOptions/constants.d.ts +3 -0
  38. package/build/plugins/d3/renderer/hooks/useChartOptions/constants.js +3 -0
  39. package/build/plugins/d3/renderer/hooks/useChartOptions/index.d.ts +3 -0
  40. package/build/plugins/d3/renderer/hooks/useChartOptions/index.js +32 -0
  41. package/build/plugins/d3/renderer/hooks/useChartOptions/legend.d.ts +6 -0
  42. package/build/plugins/d3/renderer/hooks/useChartOptions/legend.js +5 -0
  43. package/build/plugins/d3/renderer/hooks/useChartOptions/title.d.ts +5 -0
  44. package/build/plugins/d3/renderer/hooks/useChartOptions/title.js +17 -0
  45. package/build/plugins/d3/renderer/hooks/useChartOptions/tooltip.d.ts +5 -0
  46. package/build/plugins/d3/renderer/hooks/useChartOptions/tooltip.js +5 -0
  47. package/build/plugins/d3/renderer/hooks/useChartOptions/types.d.ts +32 -0
  48. package/build/plugins/d3/renderer/hooks/useChartOptions/types.js +1 -0
  49. package/build/plugins/d3/renderer/hooks/useChartOptions/utils.d.ts +5 -0
  50. package/build/plugins/d3/renderer/hooks/useChartOptions/utils.js +18 -0
  51. package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.d.ts +5 -0
  52. package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.js +29 -0
  53. package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.d.ts +5 -0
  54. package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +34 -0
  55. package/build/plugins/d3/renderer/hooks/useLegend/index.d.ts +13 -0
  56. package/build/plugins/d3/renderer/hooks/useLegend/index.js +28 -0
  57. package/build/plugins/d3/renderer/hooks/useScales/index.d.ts +17 -0
  58. package/build/plugins/d3/renderer/hooks/useScales/index.js +101 -0
  59. package/build/plugins/d3/renderer/hooks/useSeries/index.d.ts +14 -0
  60. package/build/plugins/d3/renderer/hooks/useSeries/index.js +23 -0
  61. package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +19 -0
  62. package/build/plugins/d3/renderer/hooks/useShapes/index.js +73 -0
  63. package/build/plugins/d3/renderer/hooks/useTooltip/index.d.ts +13 -0
  64. package/build/plugins/d3/renderer/hooks/useTooltip/index.js +19 -0
  65. package/build/plugins/d3/renderer/hooks/useTooltip/types.d.ts +7 -0
  66. package/build/plugins/d3/renderer/hooks/useTooltip/types.js +1 -0
  67. package/build/plugins/d3/renderer/utils/index.d.ts +18 -0
  68. package/build/plugins/d3/renderer/utils/index.js +71 -0
  69. package/build/plugins/d3/types.d.ts +4 -0
  70. package/build/plugins/d3/types.js +1 -0
  71. package/build/types/widget-data/axis.d.ts +22 -0
  72. package/build/types/widget-data/axis.js +1 -0
  73. package/build/types/widget-data/base.d.ts +15 -0
  74. package/build/types/widget-data/base.js +1 -0
  75. package/build/types/widget-data/chart.d.ts +9 -0
  76. package/build/types/widget-data/chart.js +1 -0
  77. package/build/types/widget-data/index.d.ts +24 -0
  78. package/build/types/widget-data/index.js +9 -0
  79. package/build/types/widget-data/legend.d.ts +3 -0
  80. package/build/types/widget-data/legend.js +1 -0
  81. package/build/types/widget-data/pie.d.ts +10 -0
  82. package/build/types/widget-data/pie.js +1 -0
  83. package/build/types/widget-data/scatter.d.ts +20 -0
  84. package/build/types/widget-data/scatter.js +1 -0
  85. package/build/types/widget-data/series.d.ts +4 -0
  86. package/build/types/widget-data/series.js +1 -0
  87. package/build/types/widget-data/title.d.ts +5 -0
  88. package/build/types/widget-data/title.js +1 -0
  89. package/build/types/widget-data/tooltip.d.ts +12 -0
  90. package/build/types/widget-data/tooltip.js +1 -0
  91. package/build/types/widget.d.ts +5 -0
  92. package/package.json +4 -2
@@ -0,0 +1,7 @@
1
+ import { ChartKitPlugin } from '../../types';
2
+ /**
3
+ * It is an experemental plugin
4
+ *
5
+ * DO NOT USE IT IN YOUR PRODUCTION
6
+ * */
7
+ export declare const D3Plugin: ChartKitPlugin;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ /**
3
+ * It is an experemental plugin
4
+ *
5
+ * DO NOT USE IT IN YOUR PRODUCTION
6
+ * */
7
+ export const D3Plugin = {
8
+ type: 'd3',
9
+ renderer: React.lazy(() => import('./renderer/D3Widget')),
10
+ };
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import type { ChartKitWidgetRef } from '../../../types';
3
+ declare const D3Widget: React.ForwardRefExoticComponent<{
4
+ type: "d3";
5
+ data: import("../../../types/widget-data").ChartKitWidgetData<any>;
6
+ id?: string | undefined;
7
+ isMobile?: boolean | undefined;
8
+ onLoad?: ((data?: import("../../../types").ChartKitOnLoadData<"d3"> | undefined) => void) | undefined;
9
+ onRender?: ((data: import("../../../types").ChartKitOnRenderData) => void) | undefined;
10
+ onChartLoad?: ((data: import("../../../types").ChartKitOnChartLoad<"d3">) => void) | undefined;
11
+ onError?: import("../../../types").ChartKitOnError | undefined;
12
+ renderError?: import("../../../types").RenderError | undefined;
13
+ renderPluginLoader?: (() => React.ReactNode) | undefined;
14
+ } & {} & React.RefAttributes<ChartKitWidgetRef | undefined>>;
15
+ export default D3Widget;
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { select } from 'd3';
3
+ import debounce from 'lodash/debounce';
4
+ import { Chart } from './components';
5
+ const D3Widget = React.forwardRef(function D3Widget(props, forwardedRef) {
6
+ const ref = React.useRef(null);
7
+ const debounced = React.useRef();
8
+ const [dimensions, setDimensions] = React.useState();
9
+ const handleResize = React.useCallback(() => {
10
+ if (ref.current) {
11
+ const { width, height } = ref.current.getBoundingClientRect();
12
+ setDimensions({ width, height });
13
+ }
14
+ }, []);
15
+ const debuncedHandleResize = React.useMemo(() => {
16
+ var _a;
17
+ (_a = debounced.current) === null || _a === void 0 ? void 0 : _a.cancel();
18
+ debounced.current = debounce(handleResize, 200);
19
+ return debounced.current;
20
+ }, [handleResize]);
21
+ React.useImperativeHandle(forwardedRef, () => ({
22
+ reflow() {
23
+ handleResize();
24
+ },
25
+ }), [handleResize]);
26
+ React.useEffect(() => {
27
+ const selection = select(window);
28
+ selection.on('resize', debuncedHandleResize);
29
+ return () => {
30
+ // https://d3js.org/d3-selection/events#selection_on
31
+ selection.on('resize', null);
32
+ };
33
+ }, [debuncedHandleResize]);
34
+ React.useEffect(() => {
35
+ // dimensions initialize
36
+ handleResize();
37
+ }, [handleResize]);
38
+ return (React.createElement("div", { ref: ref, style: { width: '100%', height: '100%' } }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (React.createElement(Chart, { width: dimensions.width, height: dimensions.height, data: props.data }))));
39
+ });
40
+ export default D3Widget;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { ChartOptions, ChartScale } from '../hooks';
3
+ type Props = {
4
+ axis: ChartOptions['xAxis'];
5
+ width: number;
6
+ height: number;
7
+ scale: ChartScale;
8
+ };
9
+ export declare const AxisX: ({ axis, width, height, scale }: Props) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ import { axisBottom, select } from 'd3';
4
+ import { formatAxisTickLabel, parseTransformStyle } from '../utils';
5
+ const b = block('chartkit-d3-axis');
6
+ const EMPTY_SPACE_BETWEEN_LABELS = 10;
7
+ // Note: this method do not prepared for rotated labels
8
+ const removeOverlappingXTicks = (axis) => {
9
+ var _a;
10
+ const a = axis.selectAll('g.tick').nodes();
11
+ if (a.length <= 1) {
12
+ return;
13
+ }
14
+ for (let i = 0, x = 0; i < a.length; i++) {
15
+ const node = a[i];
16
+ const r = node.getBoundingClientRect();
17
+ if (r.left < x) {
18
+ (_a = node === null || node === void 0 ? void 0 : node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
19
+ }
20
+ else {
21
+ x = r.right + EMPTY_SPACE_BETWEEN_LABELS;
22
+ }
23
+ }
24
+ };
25
+ // FIXME: add overflow ellipsis for the labels that out of boundaries
26
+ export const AxisX = ({ axis, width, height, scale }) => {
27
+ const ref = React.useRef(null);
28
+ React.useEffect(() => {
29
+ if (!ref.current) {
30
+ return;
31
+ }
32
+ const svgElement = select(ref.current);
33
+ svgElement.selectAll('*').remove();
34
+ const xAxisGenerator = axisBottom(scale)
35
+ .tickSize(height * -1)
36
+ .tickPadding(axis.labels.padding)
37
+ .tickFormat((value) => {
38
+ return formatAxisTickLabel({
39
+ axisType: axis.type,
40
+ value,
41
+ dateFormat: axis.labels.dateFormat,
42
+ numberFormat: axis.labels.numberFormat,
43
+ });
44
+ });
45
+ svgElement.call(xAxisGenerator).attr('class', b());
46
+ svgElement.select('.domain').attr('d', `M0,0V0H${width}`);
47
+ svgElement.selectAll('.tick text').style('font-size', axis.labels.style.fontSize);
48
+ const transformStyle = svgElement.select('.tick').attr('transform');
49
+ const { x } = parseTransformStyle(transformStyle);
50
+ if (x === 0) {
51
+ // Remove tick that has the same x coordinate like domain
52
+ svgElement.select('.tick').remove();
53
+ }
54
+ if (axis.title.text) {
55
+ const textY = axis.title.height + parseInt(axis.labels.style.fontSize) + axis.labels.padding;
56
+ svgElement
57
+ .append('text')
58
+ .attr('class', b('title'))
59
+ .attr('text-anchor', 'middle')
60
+ .attr('x', width / 2)
61
+ .attr('y', textY)
62
+ .attr('font-size', axis.title.style.fontSize)
63
+ .text(axis.title.text);
64
+ }
65
+ removeOverlappingXTicks(svgElement);
66
+ }, [axis, width, height, scale]);
67
+ return React.createElement("g", { ref: ref });
68
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { ChartOptions, ChartScale } from '../hooks';
3
+ type Props = {
4
+ axises: ChartOptions['yAxis'];
5
+ width: number;
6
+ height: number;
7
+ scale: ChartScale;
8
+ };
9
+ export declare const AxisY: ({ axises, width, height, scale }: Props) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ import { axisLeft, select } from 'd3';
4
+ import { formatAxisTickLabel, parseTransformStyle } from '../utils';
5
+ const b = block('chartkit-d3-axis');
6
+ const EMPTY_SPACE_BETWEEN_LABELS = 10;
7
+ // Note: this method do not prepared for rotated labels
8
+ const removeOverlappingYTicks = (axis) => {
9
+ var _a;
10
+ const a = axis.selectAll('g.tick').nodes();
11
+ if (a.length <= 1) {
12
+ return;
13
+ }
14
+ for (let i = 0, x = 0; i < a.length; i++) {
15
+ const node = a[i];
16
+ const r = node.getBoundingClientRect();
17
+ if (r.bottom > x && i !== 0) {
18
+ (_a = node === null || node === void 0 ? void 0 : node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
19
+ }
20
+ else {
21
+ x = r.top - EMPTY_SPACE_BETWEEN_LABELS;
22
+ }
23
+ }
24
+ };
25
+ // FIXME: add overflow ellipsis for the labels that out of boundaries
26
+ export const AxisY = ({ axises, width, height, scale }) => {
27
+ const ref = React.useRef(null);
28
+ React.useEffect(() => {
29
+ if (!ref.current) {
30
+ return;
31
+ }
32
+ const axis = axises[0];
33
+ const svgElement = select(ref.current);
34
+ svgElement.selectAll('*').remove();
35
+ const yAxisGenerator = axisLeft(scale)
36
+ .tickSize(width * -1)
37
+ .tickPadding(axis.labels.padding)
38
+ .tickFormat((value) => {
39
+ return formatAxisTickLabel({
40
+ axisType: axis.type,
41
+ value,
42
+ dateFormat: axis.labels.dateFormat,
43
+ numberFormat: axis.labels.numberFormat,
44
+ });
45
+ });
46
+ svgElement.call(yAxisGenerator).attr('class', b());
47
+ 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)');
52
+ const transformStyle = svgElement.select('.tick').attr('transform');
53
+ const { y } = parseTransformStyle(transformStyle);
54
+ if (y === height) {
55
+ // Remove stroke from tick that has the same y coordinate like domain
56
+ svgElement.select('.tick line').style('stroke', 'none');
57
+ }
58
+ if (axis.title.text) {
59
+ const textY = axis.title.height + axis.labels.padding;
60
+ svgElement
61
+ .append('text')
62
+ .attr('class', b('title'))
63
+ .attr('text-anchor', 'middle')
64
+ .attr('dy', -textY)
65
+ .attr('dx', -height / 2)
66
+ .attr('font-size', axis.title.style.fontSize)
67
+ .attr('transform', 'rotate(-90)')
68
+ .text(axis.title.text);
69
+ }
70
+ removeOverlappingYTicks(svgElement);
71
+ }, [axises, width, height, scale]);
72
+ return React.createElement("g", { ref: ref });
73
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { ChartKitWidgetData } from '../../../../types/widget-data';
3
+ import './styles.css';
4
+ type Props = {
5
+ width: number;
6
+ height: number;
7
+ data: ChartKitWidgetData;
8
+ };
9
+ export declare const Chart: ({ width, height, data }: Props) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ import { AxisY } from './AxisY';
4
+ import { AxisX } from './AxisX';
5
+ import { Legend } from './Legend';
6
+ import { Title } from './Title';
7
+ import { Tooltip } from './Tooltip';
8
+ import { useChartDimensions, useChartEvents, useChartOptions, useLegend, useScales, useSeries, useShapes, useTooltip, } from '../hooks';
9
+ import { isAxisRelatedSeries } from '../utils';
10
+ import './styles.css';
11
+ const b = block('chartkit-d3');
12
+ export const Chart = ({ width, height, data }) => {
13
+ // FIXME: add data validation
14
+ const { series } = data;
15
+ const svgRef = React.createRef();
16
+ const hasAxisRelatedSeries = series.some(isAxisRelatedSeries);
17
+ const { chartHovered, handleMouseEnter, handleMouseLeave } = useChartEvents();
18
+ const { chart, legend, title, tooltip, xAxis, yAxis } = useChartOptions(data);
19
+ const { boundsWidth, boundsHeight, legendHeight } = useChartDimensions({
20
+ width,
21
+ height,
22
+ margin: chart.margin,
23
+ legend,
24
+ title,
25
+ xAxis,
26
+ yAxis,
27
+ });
28
+ const { activeLegendItems, handleLegendItemClick } = useLegend({ series });
29
+ const { chartSeries } = useSeries({ activeLegendItems, series });
30
+ const { xScale, yScale } = useScales({
31
+ boundsWidth,
32
+ boundsHeight,
33
+ series: chartSeries,
34
+ xAxis,
35
+ yAxis,
36
+ });
37
+ const { hovered, pointerPosition, handleSeriesMouseMove, handleSeriesMouseLeave } = useTooltip({
38
+ tooltip,
39
+ });
40
+ const { shapes } = useShapes({
41
+ series: chartSeries,
42
+ xAxis,
43
+ xScale,
44
+ yAxis,
45
+ yScale,
46
+ svgContainer: svgRef.current,
47
+ onSeriesMouseMove: handleSeriesMouseMove,
48
+ onSeriesMouseLeave: handleSeriesMouseLeave,
49
+ });
50
+ return (React.createElement(React.Fragment, null,
51
+ React.createElement("svg", { ref: svgRef, className: b({ hovered: chartHovered }), width: width, height: height, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
52
+ title && React.createElement(Title, Object.assign({}, title, { chartWidth: width })),
53
+ React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[
54
+ chart.margin.left,
55
+ chart.margin.top + ((title === null || title === void 0 ? void 0 : title.height) || 0),
56
+ ].join(',')})` },
57
+ hasAxisRelatedSeries && (React.createElement(React.Fragment, null,
58
+ React.createElement(AxisY, { axises: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale }),
59
+ React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
60
+ React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale })))),
61
+ shapes),
62
+ legend.enabled && (React.createElement(Legend, { width: boundsWidth, offsetWidth: chart.margin.left, height: legendHeight, offsetHeight: height - legendHeight / 2, chartSeries: chartSeries, onItemClick: handleLegendItemClick }))),
63
+ React.createElement(Tooltip, { hovered: hovered, pointerPosition: pointerPosition, tooltip: tooltip, xAxis: xAxis, yAxis: yAxis[0] })));
64
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { ChartSeries, OnLegendItemClick } from '../hooks';
3
+ type Props = {
4
+ width: number;
5
+ height: number;
6
+ offsetWidth: number;
7
+ offsetHeight: number;
8
+ chartSeries: ChartSeries[];
9
+ onItemClick: OnLegendItemClick;
10
+ };
11
+ export declare const Legend: (props: Props) => React.JSX.Element;
12
+ export {};
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ import { select } from 'd3';
4
+ const b = block('chartkit-d3-legend');
5
+ export const Legend = (props) => {
6
+ const { width, offsetWidth, height, offsetHeight, chartSeries, onItemClick } = props;
7
+ return (React.createElement("g", { width: width, height: height, ref: (node) => {
8
+ if (!node) {
9
+ return;
10
+ }
11
+ const size = 10;
12
+ const textWidths = [0];
13
+ const svgElement = select(node);
14
+ svgElement.selectAll('*').remove();
15
+ const legendItemTemplate = svgElement
16
+ .selectAll('legend-history')
17
+ .data(chartSeries)
18
+ .enter()
19
+ .append('g')
20
+ .attr('class', b('item'))
21
+ .on('click', function (e, d) {
22
+ onItemClick({ name: d.name, metaKey: e.metaKey });
23
+ });
24
+ svgElement
25
+ .selectAll('*')
26
+ .data(chartSeries)
27
+ .append('text')
28
+ .text(function (d) {
29
+ return d.name;
30
+ })
31
+ .each(function () {
32
+ textWidths.push(this.getComputedTextLength());
33
+ })
34
+ .remove();
35
+ legendItemTemplate
36
+ .append('rect')
37
+ .attr('x', function (_d, i) {
38
+ return (offsetWidth +
39
+ i * size +
40
+ textWidths.slice(0, i + 1).reduce((acc, tw) => acc + tw, 0));
41
+ })
42
+ .attr('y', offsetHeight - size / 2)
43
+ .attr('width', size)
44
+ .attr('height', size)
45
+ .style('fill', function (d) {
46
+ return d.color;
47
+ });
48
+ legendItemTemplate
49
+ .append('text')
50
+ .attr('x', function (_d, i) {
51
+ return (offsetWidth +
52
+ i * size +
53
+ size +
54
+ textWidths.slice(0, i + 1).reduce((acc, tw) => acc + tw, 0));
55
+ })
56
+ .attr('y', offsetHeight)
57
+ .attr('class', function (d) {
58
+ const mods = { selected: d.visible, unselected: !d.visible };
59
+ return b('item-text', mods);
60
+ })
61
+ .text(function (d) {
62
+ return ('name' in d && d.name);
63
+ })
64
+ .style('alignment-baseline', 'middle');
65
+ } }));
66
+ };
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { PreparedTitle } from '../hooks';
3
+ type Props = PreparedTitle & {
4
+ chartWidth: number;
5
+ };
6
+ export declare const Title: (props: Props) => React.JSX.Element;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ const b = block('chartkit-d3-title');
4
+ export const Title = (props) => {
5
+ const { chartWidth, text, height, style } = props;
6
+ return (React.createElement("text", { className: b(), dx: chartWidth / 2, dy: height / 2, dominantBaseline: "middle", textAnchor: "middle", style: { fontSize: style === null || style === void 0 ? void 0 : style.fontSize, lineHeight: `${height}px` } },
7
+ React.createElement("tspan", null, text)));
8
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { TooltipHoveredData } from '../../../../../types/widget-data';
3
+ import type { PreparedAxis } from '../../hooks';
4
+ type Props = {
5
+ hovered: TooltipHoveredData;
6
+ xAxis: PreparedAxis;
7
+ yAxis: PreparedAxis;
8
+ };
9
+ export declare const DefaultContent: ({ hovered, xAxis, yAxis }: Props) => React.JSX.Element | null;
10
+ export {};
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
3
+ const { data, series } = hovered;
4
+ switch (series.type) {
5
+ case 'scatter': {
6
+ const scatterData = data;
7
+ const xRow = xAxis.type === 'category' ? scatterData.category : scatterData.x;
8
+ const yRow = yAxis.type === 'category' ? scatterData.category : scatterData.y;
9
+ return (React.createElement("div", null,
10
+ React.createElement("div", null,
11
+ React.createElement("span", null, "X:\u00A0"),
12
+ React.createElement("b", null, xRow)),
13
+ React.createElement("div", null,
14
+ React.createElement("span", null, "Y:\u00A0"),
15
+ React.createElement("b", null, yRow))));
16
+ }
17
+ default: {
18
+ return null;
19
+ }
20
+ }
21
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { TooltipHoveredData } from '../../../../../types/widget-data';
3
+ import type { PointerPosition, PreparedAxis, PreparedTooltip } from '../../hooks';
4
+ type TooltipProps = {
5
+ tooltip: PreparedTooltip;
6
+ xAxis: PreparedAxis;
7
+ yAxis: PreparedAxis;
8
+ hovered?: TooltipHoveredData;
9
+ pointerPosition?: PointerPosition;
10
+ };
11
+ export declare const Tooltip: (props: TooltipProps) => React.JSX.Element | null;
12
+ export {};
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import block from 'bem-cn-lite';
3
+ import { DefaultContent } from './DefaultContent';
4
+ const b = block('chartkit-d3-tooltip');
5
+ const POINTER_OFFSET_X = 20;
6
+ export const Tooltip = (props) => {
7
+ const { hovered, pointerPosition, tooltip, xAxis, yAxis } = props;
8
+ const ref = React.useRef(null);
9
+ const size = React.useMemo(() => {
10
+ if (ref.current && hovered) {
11
+ const { width, height } = ref.current.getBoundingClientRect();
12
+ return { width, height };
13
+ }
14
+ return undefined;
15
+ }, [hovered, pointerPosition]);
16
+ const position = React.useMemo(() => {
17
+ if (hovered && pointerPosition && size) {
18
+ const { clientWidth } = document.documentElement;
19
+ const { width, height } = size;
20
+ const [pointerLeft, pointetTop] = pointerPosition;
21
+ const outOfRightBoudary = pointerLeft + width + POINTER_OFFSET_X >= clientWidth;
22
+ const outOfTopBoundary = pointetTop - height / 2 <= 0;
23
+ const left = outOfRightBoudary
24
+ ? pointerLeft - width - POINTER_OFFSET_X
25
+ : pointerLeft + POINTER_OFFSET_X;
26
+ const top = outOfTopBoundary ? 0 : pointetTop - height / 2;
27
+ return { left, top };
28
+ }
29
+ else if (hovered && pointerPosition) {
30
+ return { left: -1000, top: -1000 };
31
+ }
32
+ return undefined;
33
+ }, [hovered, pointerPosition, size]);
34
+ const content = React.useMemo(() => {
35
+ if (tooltip.renderer && hovered) {
36
+ return tooltip.renderer({ hovered });
37
+ }
38
+ else if (hovered) {
39
+ return React.createElement(DefaultContent, { hovered: hovered, xAxis: xAxis, yAxis: yAxis });
40
+ }
41
+ return null;
42
+ }, [hovered, tooltip, xAxis, yAxis]);
43
+ if (!position || !hovered) {
44
+ return null;
45
+ }
46
+ const { left, top } = position;
47
+ const style = {
48
+ position: 'absolute',
49
+ top,
50
+ left: left,
51
+ };
52
+ return (React.createElement("div", { ref: ref, className: b(), style: style }, content));
53
+ };
@@ -0,0 +1 @@
1
+ export { Chart } from './Chart';
@@ -0,0 +1 @@
1
+ export { Chart } from './Chart';
@@ -0,0 +1,61 @@
1
+ .chartkit-d3-axis .domain {
2
+ stroke: var(--g-color-line-generic-active);
3
+ }
4
+
5
+ .chartkit-d3-axis .tick text {
6
+ color: var(--g-color-text-secondary);
7
+ }
8
+
9
+ .chartkit-d3-axis .tick line {
10
+ stroke: var(--g-color-line-generic);
11
+ }
12
+
13
+ .chartkit-d3-axis__title {
14
+ fill: var(--g-color-text-secondary);
15
+ }
16
+
17
+ .chartkit-d3-legend__item {
18
+ cursor: pointer;
19
+ user-select: none;
20
+ }
21
+
22
+ .chartkit-d3-legend__item-text {
23
+ fill: var(--g-color-text-secondary);
24
+ }
25
+
26
+ .chartkit-d3-legend__item-text_unselected {
27
+ fill: var(--g-color-text-hint);
28
+ }
29
+
30
+ .chartkit-d3-legend__item-text:hover {
31
+ fill: var(--g-color-text-complementary);
32
+ }
33
+
34
+ .chartkit-d3-scatter__point {
35
+ stroke-width: 1px;
36
+ }
37
+
38
+ .chartkit-d3_hovered .chartkit-d3-scatter__point {
39
+ opacity: 0.5;
40
+ }
41
+
42
+ .chartkit-d3-scatter__point:hover {
43
+ stroke: #fff;
44
+ opacity: 1;
45
+ }
46
+
47
+ .chartkit-d3-title {
48
+ font-size: var(--g-text-subheader-2-font-size);
49
+ font-weight: var(--g-text-subheader-font-weight);
50
+ fill: var(--g-color-text-primary);
51
+ }
52
+
53
+ .chartkit-d3-tooltip {
54
+ position: absolute;
55
+ padding: 10px 14px;
56
+ background-color: var(--g-color-infographics-tooltip-bg);
57
+ border: 1px solid var(--g-color-line-generic);
58
+ border-radius: 3px;
59
+ box-shadow: 0 2px 12px var(--g-color-sfx-shadow);
60
+ z-index: 100001;
61
+ }
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_PALETTE: string[];
@@ -0,0 +1,22 @@
1
+ export const DEFAULT_PALETTE = [
2
+ '#4DA2F1',
3
+ '#FF3D64',
4
+ '#8AD554',
5
+ '#FFC636',
6
+ '#FFB9DD',
7
+ '#84D1EE',
8
+ '#FF91A1',
9
+ '#54A520',
10
+ '#DB9100',
11
+ '#BA74B3',
12
+ '#1F68A9',
13
+ '#ED65A9',
14
+ '#0FA08D',
15
+ '#FF7E00',
16
+ '#E8B0A4',
17
+ '#52A6C5',
18
+ '#BE2443',
19
+ '#70C1AF',
20
+ '#FFB46C',
21
+ '#DCA3D7',
22
+ ];
@@ -0,0 +1,10 @@
1
+ export * from './useChartDimensions';
2
+ export * from './useChartEvents';
3
+ export * from './useChartOptions';
4
+ export * from './useChartOptions/types';
5
+ export * from './useLegend';
6
+ export * from './useScales';
7
+ export * from './useSeries';
8
+ export * from './useShapes';
9
+ export * from './useTooltip';
10
+ export * from './useTooltip/types';
@@ -0,0 +1,10 @@
1
+ export * from './useChartDimensions';
2
+ export * from './useChartEvents';
3
+ export * from './useChartOptions';
4
+ export * from './useChartOptions/types';
5
+ export * from './useLegend';
6
+ export * from './useScales';
7
+ export * from './useSeries';
8
+ export * from './useShapes';
9
+ export * from './useTooltip';
10
+ export * from './useTooltip/types';
@@ -0,0 +1,17 @@
1
+ import type { ChartMargin } from '../../../../../types/widget-data';
2
+ import type { ChartOptions, PreparedAxis, PreparedTitle } from '../useChartOptions/types';
3
+ type Args = {
4
+ width: number;
5
+ height: number;
6
+ margin: ChartMargin;
7
+ legend: ChartOptions['legend'];
8
+ title?: PreparedTitle;
9
+ xAxis?: PreparedAxis;
10
+ yAxis?: PreparedAxis[];
11
+ };
12
+ export declare const useChartDimensions: (args: Args) => {
13
+ boundsWidth: number;
14
+ boundsHeight: number;
15
+ legendHeight: number;
16
+ };
17
+ export {};