@gravity-ui/chartkit 4.6.0 → 4.7.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.
- package/build/plugins/d3/examples/bar-x/Basic.d.ts +4 -0
- package/build/plugins/d3/examples/bar-x/Basic.js +78 -0
- package/build/plugins/d3/examples/bar-x/GroupedColumns.d.ts +2 -0
- package/build/plugins/d3/examples/bar-x/GroupedColumns.js +44 -0
- package/build/plugins/d3/examples/bar-x/StackedColumns.d.ts +2 -0
- package/build/plugins/d3/examples/bar-x/StackedColumns.js +45 -0
- package/build/plugins/d3/examples/nintendoGames.d.ts +62 -0
- package/build/plugins/d3/examples/nintendoGames.js +12037 -0
- package/build/plugins/d3/examples/pie/Basic.d.ts +2 -0
- package/build/plugins/d3/examples/pie/Basic.js +30 -0
- package/build/plugins/d3/examples/pie/Donut.d.ts +2 -0
- package/build/plugins/d3/examples/pie/Donut.js +31 -0
- package/build/plugins/d3/examples/scatter/Basic.d.ts +2 -0
- package/build/plugins/d3/examples/scatter/Basic.js +66 -0
- package/build/plugins/d3/renderer/D3Widget.js +11 -1
- package/build/plugins/d3/renderer/components/AxisX.d.ts +1 -2
- package/build/plugins/d3/renderer/components/AxisX.js +8 -21
- package/build/plugins/d3/renderer/components/AxisY.js +50 -18
- package/build/plugins/d3/renderer/components/Chart.js +25 -17
- package/build/plugins/d3/renderer/components/Legend.js +20 -22
- package/build/plugins/d3/renderer/components/Title.js +1 -1
- package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.d.ts +2 -2
- package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.js +8 -0
- package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.d.ts +14 -0
- package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.js +70 -0
- package/build/plugins/d3/renderer/components/Tooltip/index.d.ts +5 -3
- package/build/plugins/d3/renderer/components/Tooltip/index.js +4 -2
- package/build/plugins/d3/renderer/components/styles.css +3 -0
- package/build/plugins/d3/renderer/constants/defaults/axis.d.ts +9 -0
- package/build/plugins/d3/renderer/constants/defaults/axis.js +6 -0
- package/build/plugins/d3/renderer/constants/defaults/index.d.ts +1 -0
- package/build/plugins/d3/renderer/constants/defaults/index.js +1 -0
- package/build/plugins/d3/renderer/constants/defaults/series-options.d.ts +11 -0
- package/build/plugins/d3/renderer/constants/defaults/series-options.js +41 -0
- package/build/plugins/d3/renderer/constants/index.d.ts +0 -1
- package/build/plugins/d3/renderer/constants/index.js +0 -1
- package/build/plugins/d3/renderer/d3-dispatcher.d.ts +1 -0
- package/build/plugins/d3/renderer/d3-dispatcher.js +4 -0
- package/build/plugins/d3/renderer/hooks/index.d.ts +0 -1
- package/build/plugins/d3/renderer/hooks/index.js +0 -1
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.d.ts +6 -5
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.js +2 -1
- package/build/plugins/d3/renderer/hooks/useChartDimensions/index.js +8 -41
- package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.d.ts +3 -0
- package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.js +17 -4
- package/build/plugins/d3/renderer/hooks/useChartOptions/chart.d.ts +2 -4
- package/build/plugins/d3/renderer/hooks/useChartOptions/chart.js +4 -23
- package/build/plugins/d3/renderer/hooks/useChartOptions/index.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useChartOptions/index.js +2 -10
- package/build/plugins/d3/renderer/hooks/useChartOptions/title.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useChartOptions/title.js +1 -0
- package/build/plugins/d3/renderer/hooks/useChartOptions/types.d.ts +8 -5
- package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.d.ts +5 -3
- package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.js +61 -6
- package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +20 -12
- package/build/plugins/d3/renderer/hooks/useSeries/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/index.js +8 -2
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-legend.js +8 -3
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-options.d.ts +3 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-options.js +5 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepareSeries.js +6 -3
- package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +5 -1
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.d.ts +12 -0
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.js +91 -0
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.d.ts +19 -0
- package/build/plugins/d3/renderer/hooks/useShapes/{bar-x.js → bar-x/prepare-data.js} +9 -88
- package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +13 -10
- package/build/plugins/d3/renderer/hooks/useShapes/index.js +28 -13
- package/build/plugins/d3/renderer/hooks/useShapes/pie.d.ts +6 -4
- package/build/plugins/d3/renderer/hooks/useShapes/pie.js +98 -20
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.d.ts +15 -0
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +89 -0
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.d.ts +19 -0
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +55 -0
- package/build/plugins/d3/renderer/hooks/useShapes/styles.css +1 -9
- package/build/plugins/d3/renderer/hooks/useTooltip/index.d.ts +6 -6
- package/build/plugins/d3/renderer/hooks/useTooltip/index.js +15 -17
- package/build/plugins/d3/renderer/hooks/useTooltip/types.d.ts +0 -6
- package/build/plugins/d3/renderer/utils/axis-generators/bottom.d.ts +3 -1
- package/build/plugins/d3/renderer/utils/axis-generators/bottom.js +77 -38
- package/build/plugins/d3/renderer/utils/axis.js +0 -6
- package/build/plugins/d3/renderer/utils/index.d.ts +5 -0
- package/build/plugins/d3/renderer/utils/index.js +13 -8
- package/build/plugins/d3/renderer/utils/math.d.ts +2 -0
- package/build/plugins/d3/renderer/utils/math.js +8 -0
- package/build/plugins/d3/renderer/utils/text.d.ts +6 -6
- package/build/plugins/d3/renderer/utils/text.js +25 -15
- package/build/types/widget-data/axis.d.ts +10 -0
- package/build/types/widget-data/series.d.ts +51 -0
- package/build/types/widget-data/tooltip.d.ts +18 -7
- package/package.json +2 -2
- package/build/plugins/d3/renderer/hooks/useChartEvents/index.d.ts +0 -5
- package/build/plugins/d3/renderer/hooks/useChartEvents/index.js +0 -15
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x.d.ts +0 -21
- package/build/plugins/d3/renderer/hooks/useShapes/defaults.d.ts +0 -5
- package/build/plugins/d3/renderer/hooks/useShapes/defaults.js +0 -5
- package/build/plugins/d3/renderer/hooks/useShapes/scatter.d.ts +0 -19
- package/build/plugins/d3/renderer/hooks/useShapes/scatter.js +0 -89
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import { axisLabelsDefaults, DEFAULT_AXIS_LABEL_FONT_SIZE,
|
|
2
|
+
import { axisLabelsDefaults, DEFAULT_AXIS_LABEL_FONT_SIZE, yAxisTitleDefaults, } from '../../constants';
|
|
3
3
|
import { getHorisontalSvgTextHeight, formatAxisTickLabel, getClosestPointsRange, getScaleTicks, getLabelsMaxWidth, } from '../../utils';
|
|
4
4
|
import { createYScale } from '../useAxisScales';
|
|
5
5
|
const getAxisLabelMaxWidth = (args) => {
|
|
@@ -18,39 +18,45 @@ const getAxisLabelMaxWidth = (args) => {
|
|
|
18
18
|
}));
|
|
19
19
|
return getLabelsMaxWidth({
|
|
20
20
|
labels,
|
|
21
|
-
style:
|
|
21
|
+
style: {
|
|
22
|
+
'font-size': axis.labels.style.fontSize,
|
|
23
|
+
'font-weight': axis.labels.style.fontWeight || '',
|
|
24
|
+
},
|
|
25
|
+
rotation: axis.labels.rotation,
|
|
22
26
|
});
|
|
23
27
|
};
|
|
24
|
-
const applyLabelsMaxWidth = (args) => {
|
|
25
|
-
const { series, preparedYAxis } = args;
|
|
26
|
-
preparedYAxis.labels.maxWidth = getAxisLabelMaxWidth({ axis: preparedYAxis, series });
|
|
27
|
-
};
|
|
28
28
|
export const getPreparedYAxis = ({ series, yAxis, }) => {
|
|
29
29
|
// FIXME: add support for n axises
|
|
30
30
|
const yAxis1 = yAxis === null || yAxis === void 0 ? void 0 : yAxis[0];
|
|
31
|
+
const labelsEnabled = get(yAxis1, 'labels.enabled', true);
|
|
31
32
|
const y1LabelsStyle = {
|
|
32
33
|
fontSize: get(yAxis1, 'labels.style.fontSize', DEFAULT_AXIS_LABEL_FONT_SIZE),
|
|
33
34
|
};
|
|
34
35
|
const y1TitleText = get(yAxis1, 'title.text', '');
|
|
35
36
|
const y1TitleStyle = {
|
|
36
|
-
fontSize: get(yAxis1, 'title.style.fontSize',
|
|
37
|
+
fontSize: get(yAxis1, 'title.style.fontSize', yAxisTitleDefaults.fontSize),
|
|
37
38
|
};
|
|
38
39
|
const preparedY1Axis = {
|
|
39
40
|
type: get(yAxis1, 'type', 'linear'),
|
|
40
41
|
labels: {
|
|
41
|
-
enabled:
|
|
42
|
-
margin: get(yAxis1, 'labels.margin', axisLabelsDefaults.margin),
|
|
43
|
-
padding: get(yAxis1, 'labels.padding', axisLabelsDefaults.padding),
|
|
44
|
-
autoRotation: get(yAxis1, 'labels.autoRotation', false),
|
|
42
|
+
enabled: labelsEnabled,
|
|
43
|
+
margin: labelsEnabled ? get(yAxis1, 'labels.margin', axisLabelsDefaults.margin) : 0,
|
|
44
|
+
padding: labelsEnabled ? get(yAxis1, 'labels.padding', axisLabelsDefaults.padding) : 0,
|
|
45
45
|
dateFormat: get(yAxis1, 'labels.dateFormat'),
|
|
46
46
|
numberFormat: get(yAxis1, 'labels.numberFormat'),
|
|
47
47
|
style: y1LabelsStyle,
|
|
48
|
+
rotation: get(yAxis1, 'labels.rotation', 0),
|
|
49
|
+
width: 0,
|
|
50
|
+
height: 0,
|
|
51
|
+
lineHeight: getHorisontalSvgTextHeight({ text: 'TmpLabel', style: y1LabelsStyle }),
|
|
52
|
+
maxWidth: get(yAxis1, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
|
|
48
53
|
},
|
|
49
54
|
lineColor: get(yAxis1, 'lineColor'),
|
|
50
55
|
categories: get(yAxis1, 'categories'),
|
|
51
56
|
timestamps: get(yAxis1, 'timestamps'),
|
|
52
57
|
title: {
|
|
53
58
|
text: y1TitleText,
|
|
59
|
+
margin: get(yAxis1, 'title.margin', yAxisTitleDefaults.margin),
|
|
54
60
|
style: y1TitleStyle,
|
|
55
61
|
height: y1TitleText
|
|
56
62
|
? getHorisontalSvgTextHeight({ text: y1TitleText, style: y1TitleStyle })
|
|
@@ -65,6 +71,8 @@ export const getPreparedYAxis = ({ series, yAxis, }) => {
|
|
|
65
71
|
pixelInterval: get(yAxis1, 'ticks.pixelInterval'),
|
|
66
72
|
},
|
|
67
73
|
};
|
|
68
|
-
|
|
74
|
+
if (labelsEnabled) {
|
|
75
|
+
preparedY1Axis.labels.width = getAxisLabelMaxWidth({ axis: preparedY1Axis, series });
|
|
76
|
+
}
|
|
69
77
|
return [preparedY1Axis];
|
|
70
78
|
};
|
|
@@ -23,6 +23,7 @@ export declare const useSeries: (args: Args) => {
|
|
|
23
23
|
};
|
|
24
24
|
preparedLegend: import("./types").PreparedLegend;
|
|
25
25
|
preparedSeries: PreparedSeries[];
|
|
26
|
+
preparedSeriesOptions: import("../../constants").SeriesOptionsDefaults;
|
|
26
27
|
handleLegendItemClick: OnLegendItemClick;
|
|
27
28
|
};
|
|
28
29
|
export {};
|
|
@@ -4,9 +4,10 @@ import { DEFAULT_PALETTE } from '../../constants';
|
|
|
4
4
|
import { getSeriesNames } from '../../utils';
|
|
5
5
|
import { getActiveLegendItems, getAllLegendItems } from './utils';
|
|
6
6
|
import { getPreparedLegend, getLegendComponents } from './prepare-legend';
|
|
7
|
+
import { getPreparedOptions } from './prepare-options';
|
|
7
8
|
import { prepareSeries } from './prepareSeries';
|
|
8
9
|
export const useSeries = (args) => {
|
|
9
|
-
const { chartWidth, chartHeight, chartMargin, legend, preparedYAxis, series: { data: series }, } = args;
|
|
10
|
+
const { chartWidth, chartHeight, chartMargin, legend, preparedYAxis, series: { data: series, options: seriesOptions }, } = args;
|
|
10
11
|
const preparedLegend = React.useMemo(() => getPreparedLegend({ legend, series }), [legend, series]);
|
|
11
12
|
const preparedSeries = React.useMemo(() => {
|
|
12
13
|
const seriesNames = getSeriesNames(series);
|
|
@@ -22,9 +23,13 @@ export const useSeries = (args) => {
|
|
|
22
23
|
return acc;
|
|
23
24
|
}, []);
|
|
24
25
|
}, [series, preparedLegend]);
|
|
26
|
+
const preparedSeriesOptions = React.useMemo(() => {
|
|
27
|
+
return getPreparedOptions(seriesOptions);
|
|
28
|
+
}, [seriesOptions]);
|
|
25
29
|
const [activeLegendItems, setActiveLegendItems] = React.useState(getActiveLegendItems(preparedSeries));
|
|
26
30
|
const chartSeries = React.useMemo(() => {
|
|
27
|
-
return preparedSeries.map((singleSeries) => {
|
|
31
|
+
return preparedSeries.map((singleSeries, i) => {
|
|
32
|
+
singleSeries.id = `Series ${i + 1}`;
|
|
28
33
|
if (singleSeries.legend.enabled) {
|
|
29
34
|
return Object.assign(Object.assign({}, singleSeries), { visible: activeLegendItems.includes(singleSeries.name) });
|
|
30
35
|
}
|
|
@@ -67,6 +72,7 @@ export const useSeries = (args) => {
|
|
|
67
72
|
legendConfig,
|
|
68
73
|
preparedLegend,
|
|
69
74
|
preparedSeries: chartSeries,
|
|
75
|
+
preparedSeriesOptions,
|
|
70
76
|
handleLegendItemClick,
|
|
71
77
|
};
|
|
72
78
|
};
|
|
@@ -5,6 +5,7 @@ import { select } from 'd3';
|
|
|
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
9
|
export const getPreparedLegend = (args) => {
|
|
9
10
|
const { legend, series } = args;
|
|
10
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;
|
|
@@ -80,13 +81,17 @@ export const getLegendComponents = (args) => {
|
|
|
80
81
|
let legendHeight = preparedLegend.lineHeight * items.length;
|
|
81
82
|
let pagination;
|
|
82
83
|
if (maxLegendHeight < legendHeight) {
|
|
83
|
-
|
|
84
|
+
// extra line for paginator
|
|
85
|
+
const limit = Math.floor(maxLegendHeight / preparedLegend.lineHeight) - 1;
|
|
84
86
|
const maxPage = Math.ceil(items.length / limit);
|
|
85
87
|
pagination = { limit, maxPage };
|
|
86
88
|
legendHeight = maxLegendHeight;
|
|
87
89
|
}
|
|
88
90
|
preparedLegend.height = legendHeight;
|
|
89
|
-
const top = chartHeight - chartMargin.bottom - preparedLegend.height
|
|
90
|
-
const offset = {
|
|
91
|
+
const top = chartHeight - chartMargin.bottom - preparedLegend.height;
|
|
92
|
+
const offset = {
|
|
93
|
+
left: chartMargin.left + getWidthOccupiedByYAxis({ preparedAxis: preparedYAxis }),
|
|
94
|
+
top,
|
|
95
|
+
};
|
|
91
96
|
return { legendConfig: { offset, pagination }, legendItems: items };
|
|
92
97
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { scaleOrdinal } from 'd3';
|
|
2
1
|
import cloneDeep from 'lodash/cloneDeep';
|
|
3
2
|
import get from 'lodash/get';
|
|
3
|
+
import { scaleOrdinal } from 'd3';
|
|
4
|
+
import { getRandomCKId } from '../../../../../utils';
|
|
4
5
|
import { DEFAULT_PALETTE } from '../../constants';
|
|
5
6
|
import { DEFAULT_LEGEND_SYMBOL_SIZE } from './constants';
|
|
6
|
-
import { getRandomCKId } from '../../../../../utils';
|
|
7
7
|
const DEFAULT_DATALABELS_STYLE = {
|
|
8
8
|
fontSize: '11px',
|
|
9
9
|
fontWeight: 'bold',
|
|
@@ -53,6 +53,7 @@ function prepareBarXSeries(args) {
|
|
|
53
53
|
type: series.type,
|
|
54
54
|
color: color,
|
|
55
55
|
name: name,
|
|
56
|
+
id: '',
|
|
56
57
|
visible: get(series, 'visible', true),
|
|
57
58
|
legend: {
|
|
58
59
|
enabled: get(series, 'legend.enabled', legend.enabled),
|
|
@@ -80,13 +81,15 @@ function preparePieSeries(args) {
|
|
|
80
81
|
var _a, _b;
|
|
81
82
|
const result = {
|
|
82
83
|
type: 'pie',
|
|
83
|
-
data: dataItem
|
|
84
|
+
data: dataItem,
|
|
84
85
|
dataLabels: {
|
|
85
86
|
enabled: get(series, 'dataLabels.enabled', true),
|
|
86
87
|
},
|
|
87
88
|
label: dataItem.label,
|
|
89
|
+
value: dataItem.value,
|
|
88
90
|
visible: typeof dataItem.visible === 'boolean' ? dataItem.visible : true,
|
|
89
91
|
name: dataItem.name,
|
|
92
|
+
id: '',
|
|
90
93
|
color: dataItem.color || colorScale(dataItem.name),
|
|
91
94
|
legend: {
|
|
92
95
|
enabled: get(series, 'legend.enabled', legend.enabled),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BarXSeries, BarXSeriesData, BaseTextStyle, ChartKitWidgetLegend, PieSeries, PieSeriesData, RectLegendSymbolOptions, ScatterSeries, ScatterSeriesData } from '../../../../../types/widget-data';
|
|
2
|
+
import type { SeriesOptionsDefaults } from '../../constants';
|
|
2
3
|
export type RectLegendSymbol = {
|
|
3
4
|
shape: 'rect';
|
|
4
5
|
} & Required<RectLegendSymbolOptions>;
|
|
@@ -31,6 +32,7 @@ export type LegendConfig = {
|
|
|
31
32
|
type BasePreparedSeries = {
|
|
32
33
|
color: string;
|
|
33
34
|
name: string;
|
|
35
|
+
id: string;
|
|
34
36
|
visible: boolean;
|
|
35
37
|
legend: {
|
|
36
38
|
enabled: boolean;
|
|
@@ -52,9 +54,11 @@ export type PreparedBarXSeries = {
|
|
|
52
54
|
};
|
|
53
55
|
} & BasePreparedSeries;
|
|
54
56
|
export type PreparedPieSeries = BasePreparedSeries & Required<Omit<PieSeries, 'data'>> & {
|
|
55
|
-
data: PieSeriesData
|
|
57
|
+
data: PieSeriesData;
|
|
58
|
+
value: PieSeriesData['value'];
|
|
56
59
|
stackId: string;
|
|
57
60
|
label?: PieSeriesData['label'];
|
|
58
61
|
};
|
|
59
62
|
export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedPieSeries;
|
|
63
|
+
export type PreparedSeriesOptions = SeriesOptionsDefaults;
|
|
60
64
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Dispatch } from 'd3';
|
|
3
|
+
import type { PreparedSeriesOptions } from '../../useSeries/types';
|
|
4
|
+
import type { PreparedBarXData } from './prepare-data';
|
|
5
|
+
export { prepareBarXData } from './prepare-data';
|
|
6
|
+
export type { PreparedBarXData } from './prepare-data';
|
|
7
|
+
type Args = {
|
|
8
|
+
dispatcher: Dispatch<object>;
|
|
9
|
+
preparedData: PreparedBarXData[];
|
|
10
|
+
seriesOptions: PreparedSeriesOptions;
|
|
11
|
+
};
|
|
12
|
+
export declare const BarXSeriesShapes: (args: Args) => React.JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import get from 'lodash/get';
|
|
3
|
+
import { color, select } from 'd3';
|
|
4
|
+
import { block } from '../../../../../../utils/cn';
|
|
5
|
+
export { prepareBarXData } from './prepare-data';
|
|
6
|
+
const DEFAULT_LABEL_PADDING = 7;
|
|
7
|
+
const b = block('d3-bar-x');
|
|
8
|
+
export const BarXSeriesShapes = (args) => {
|
|
9
|
+
const { dispatcher, preparedData, seriesOptions } = args;
|
|
10
|
+
const ref = React.useRef(null);
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
if (!ref.current) {
|
|
13
|
+
return () => { };
|
|
14
|
+
}
|
|
15
|
+
const svgElement = select(ref.current);
|
|
16
|
+
const hoverOptions = get(seriesOptions, 'bar-x.states.hover');
|
|
17
|
+
const inactiveOptions = get(seriesOptions, 'bar-x.states.inactive');
|
|
18
|
+
svgElement.selectAll('*').remove();
|
|
19
|
+
const rectSelection = svgElement
|
|
20
|
+
.selectAll('allRects')
|
|
21
|
+
.data(preparedData)
|
|
22
|
+
.join('rect')
|
|
23
|
+
.attr('class', b('segment'))
|
|
24
|
+
.attr('x', (d) => d.x)
|
|
25
|
+
.attr('y', (d) => d.y)
|
|
26
|
+
.attr('height', (d) => d.height)
|
|
27
|
+
.attr('width', (d) => d.width)
|
|
28
|
+
.attr('fill', (d) => d.data.color || d.series.color);
|
|
29
|
+
const dataLabels = preparedData.filter((d) => d.series.dataLabels.enabled);
|
|
30
|
+
const labelSelection = svgElement
|
|
31
|
+
.selectAll('allLabels')
|
|
32
|
+
.data(dataLabels)
|
|
33
|
+
.join('text')
|
|
34
|
+
.text((d) => String(d.data.label || d.data.y))
|
|
35
|
+
.attr('class', b('label'))
|
|
36
|
+
.attr('x', (d) => d.x + d.width / 2)
|
|
37
|
+
.attr('y', (d) => {
|
|
38
|
+
if (d.series.dataLabels.inside) {
|
|
39
|
+
return d.y + d.height / 2;
|
|
40
|
+
}
|
|
41
|
+
return d.y - DEFAULT_LABEL_PADDING;
|
|
42
|
+
})
|
|
43
|
+
.attr('text-anchor', 'middle')
|
|
44
|
+
.style('font-size', (d) => d.series.dataLabels.style.fontSize)
|
|
45
|
+
.style('font-weight', (d) => d.series.dataLabels.style.fontWeight || null)
|
|
46
|
+
.style('fill', (d) => d.series.dataLabels.style.fontColor || null);
|
|
47
|
+
dispatcher.on('hover-shape.bar-x', (data) => {
|
|
48
|
+
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
49
|
+
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
50
|
+
if (!data) {
|
|
51
|
+
if (hoverEnabled) {
|
|
52
|
+
rectSelection.attr('fill', (d) => d.data.color || d.series.color);
|
|
53
|
+
}
|
|
54
|
+
if (inactiveEnabled) {
|
|
55
|
+
rectSelection.attr('opacity', null);
|
|
56
|
+
labelSelection.attr('opacity', null);
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (hoverEnabled) {
|
|
61
|
+
const hoveredValues = data.map((d) => d.data.x);
|
|
62
|
+
rectSelection.attr('fill', (d) => {
|
|
63
|
+
var _a;
|
|
64
|
+
const fillColor = d.data.color || d.series.color;
|
|
65
|
+
if (hoveredValues.includes(d.data.x)) {
|
|
66
|
+
return (((_a = color(fillColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness).toString()) ||
|
|
67
|
+
fillColor);
|
|
68
|
+
}
|
|
69
|
+
return fillColor;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (inactiveEnabled) {
|
|
73
|
+
const hoveredSeries = data.map((d) => d.series.id);
|
|
74
|
+
rectSelection.attr('opacity', (d) => {
|
|
75
|
+
return hoveredSeries.includes(d.series.id)
|
|
76
|
+
? null
|
|
77
|
+
: (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
|
|
78
|
+
});
|
|
79
|
+
labelSelection.attr('opacity', (d) => {
|
|
80
|
+
return hoveredSeries.includes(d.series.id)
|
|
81
|
+
? null
|
|
82
|
+
: (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return () => {
|
|
87
|
+
dispatcher.on('hover-shape.bar-x', null);
|
|
88
|
+
};
|
|
89
|
+
}, [dispatcher, preparedData, seriesOptions]);
|
|
90
|
+
return React.createElement("g", { ref: ref, className: b() });
|
|
91
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TooltipDataChunkBarX } from '../../../../../../types';
|
|
2
|
+
import type { ChartScale } from '../../useAxisScales';
|
|
3
|
+
import type { PreparedAxis } from '../../useChartOptions/types';
|
|
4
|
+
import type { PreparedBarXSeries, PreparedSeriesOptions } from '../../useSeries/types';
|
|
5
|
+
export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
series: PreparedBarXSeries;
|
|
11
|
+
};
|
|
12
|
+
export declare const prepareBarXData: (args: {
|
|
13
|
+
series: PreparedBarXSeries[];
|
|
14
|
+
seriesOptions: PreparedSeriesOptions;
|
|
15
|
+
xAxis: PreparedAxis;
|
|
16
|
+
xScale: ChartScale;
|
|
17
|
+
yAxis: PreparedAxis[];
|
|
18
|
+
yScale: ChartScale;
|
|
19
|
+
}) => PreparedBarXData[];
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { ascending, descending, max,
|
|
2
|
-
import React from 'react';
|
|
1
|
+
import { ascending, descending, max, sort } from 'd3';
|
|
3
2
|
import get from 'lodash/get';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { DEFAULT_BAR_X_SERIES_OPTIONS } from './defaults';
|
|
3
|
+
import { getDataCategoryValue } from '../../../utils';
|
|
4
|
+
const MIN_RECT_WIDTH = 1;
|
|
7
5
|
const MIN_RECT_GAP = 1;
|
|
8
6
|
const MIN_GROUP_GAP = 1;
|
|
9
|
-
const
|
|
10
|
-
const b = block('d3-bar-x');
|
|
11
|
-
function prepareData(args) {
|
|
7
|
+
export const prepareBarXData = (args) => {
|
|
12
8
|
const { series, seriesOptions, xAxis, xScale, yScale } = args;
|
|
13
9
|
const categories = get(xAxis, 'categories', []);
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const groupPadding = get(seriesOptions, 'bar-x.groupPadding', defaultGroupPadding);
|
|
10
|
+
const barMaxWidth = get(seriesOptions, 'bar-x.barMaxWidth');
|
|
11
|
+
const barPadding = get(seriesOptions, 'bar-x.barPadding');
|
|
12
|
+
const groupPadding = get(seriesOptions, 'bar-x.groupPadding');
|
|
18
13
|
const sortingOptions = get(seriesOptions, 'bar-x.dataSorting');
|
|
19
14
|
const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
|
|
20
15
|
const sortKey = (() => {
|
|
@@ -72,7 +67,7 @@ function prepareData(args) {
|
|
|
72
67
|
const groupGap = Math.max(bandWidth * groupPadding, MIN_GROUP_GAP);
|
|
73
68
|
const groupWidth = bandWidth - groupGap;
|
|
74
69
|
const rectGap = Math.max(bandWidth * barPadding, MIN_RECT_GAP);
|
|
75
|
-
const rectWidth = Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth);
|
|
70
|
+
const rectWidth = Math.max(MIN_RECT_WIDTH, Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth));
|
|
76
71
|
const result = [];
|
|
77
72
|
Object.entries(data).forEach(([xValue, val]) => {
|
|
78
73
|
const stacks = Object.values(val);
|
|
@@ -109,78 +104,4 @@ function prepareData(args) {
|
|
|
109
104
|
});
|
|
110
105
|
});
|
|
111
106
|
return result;
|
|
112
|
-
}
|
|
113
|
-
export function BarXSeriesShapes(args) {
|
|
114
|
-
const { top, left, series, seriesOptions, xAxis, xScale, yAxis, yScale, onSeriesMouseMove, onSeriesMouseLeave, svgContainer, } = args;
|
|
115
|
-
const ref = React.useRef(null);
|
|
116
|
-
React.useEffect(() => {
|
|
117
|
-
if (!ref.current) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const svgElement = select(ref.current);
|
|
121
|
-
svgElement.selectAll('*').remove();
|
|
122
|
-
const shapes = prepareData({
|
|
123
|
-
series,
|
|
124
|
-
seriesOptions,
|
|
125
|
-
xAxis,
|
|
126
|
-
xScale,
|
|
127
|
-
yAxis,
|
|
128
|
-
yScale,
|
|
129
|
-
});
|
|
130
|
-
svgElement
|
|
131
|
-
.selectAll('allRects')
|
|
132
|
-
.data(shapes)
|
|
133
|
-
.join('rect')
|
|
134
|
-
.attr('class', b('segment'))
|
|
135
|
-
.attr('x', (d) => d.x)
|
|
136
|
-
.attr('y', (d) => d.y)
|
|
137
|
-
.attr('height', (d) => d.height)
|
|
138
|
-
.attr('width', (d) => d.width)
|
|
139
|
-
.attr('fill', (d) => d.data.color || d.series.color)
|
|
140
|
-
.on('mousemove', (e, d) => {
|
|
141
|
-
const [x, y] = pointer(e, svgContainer);
|
|
142
|
-
onSeriesMouseMove === null || onSeriesMouseMove === void 0 ? void 0 : onSeriesMouseMove({
|
|
143
|
-
hovered: {
|
|
144
|
-
data: d.data,
|
|
145
|
-
series: d.series,
|
|
146
|
-
},
|
|
147
|
-
pointerPosition: [x - left, y - top],
|
|
148
|
-
});
|
|
149
|
-
})
|
|
150
|
-
.on('mouseleave', () => {
|
|
151
|
-
if (onSeriesMouseLeave) {
|
|
152
|
-
onSeriesMouseLeave();
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
const dataLabels = shapes.filter((s) => s.series.dataLabels.enabled);
|
|
156
|
-
svgElement
|
|
157
|
-
.selectAll('allLabels')
|
|
158
|
-
.data(dataLabels)
|
|
159
|
-
.join('text')
|
|
160
|
-
.text((d) => String(d.data.label || d.data.y))
|
|
161
|
-
.attr('class', b('label'))
|
|
162
|
-
.attr('x', (d) => d.x + d.width / 2)
|
|
163
|
-
.attr('y', (d) => {
|
|
164
|
-
if (d.series.dataLabels.inside) {
|
|
165
|
-
return d.y + d.height / 2;
|
|
166
|
-
}
|
|
167
|
-
return d.y - DEFAULT_LABEL_PADDING;
|
|
168
|
-
})
|
|
169
|
-
.attr('text-anchor', 'middle')
|
|
170
|
-
.style('font-size', (d) => d.series.dataLabels.style.fontSize)
|
|
171
|
-
.style('font-weight', (d) => d.series.dataLabels.style.fontWeight || null)
|
|
172
|
-
.style('fill', (d) => d.series.dataLabels.style.fontColor || null);
|
|
173
|
-
}, [
|
|
174
|
-
onSeriesMouseMove,
|
|
175
|
-
onSeriesMouseLeave,
|
|
176
|
-
svgContainer,
|
|
177
|
-
xAxis,
|
|
178
|
-
xScale,
|
|
179
|
-
yAxis,
|
|
180
|
-
yScale,
|
|
181
|
-
series,
|
|
182
|
-
left,
|
|
183
|
-
top,
|
|
184
|
-
]);
|
|
185
|
-
return React.createElement("g", { ref: ref, className: b() });
|
|
186
|
-
}
|
|
107
|
+
};
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
2
|
+
import { Dispatch } from 'd3';
|
|
3
|
+
import type { PreparedAxis } from '../useChartOptions/types';
|
|
4
4
|
import type { ChartScale } from '../useAxisScales';
|
|
5
|
-
import type { PreparedSeries } from '../';
|
|
6
|
-
import type {
|
|
5
|
+
import type { PreparedSeries, PreparedSeriesOptions } from '../';
|
|
6
|
+
import type { PreparedBarXData } from './bar-x';
|
|
7
|
+
import type { PreparedScatterData } from './scatter';
|
|
7
8
|
import './styles.css';
|
|
9
|
+
export type { PreparedBarXData } from './bar-x';
|
|
10
|
+
export type { PreparedScatterData } from './scatter';
|
|
11
|
+
export type ShapeData = PreparedBarXData | PreparedScatterData;
|
|
8
12
|
type Args = {
|
|
9
13
|
top: number;
|
|
10
14
|
left: number;
|
|
11
15
|
boundsWidth: number;
|
|
12
16
|
boundsHeight: number;
|
|
17
|
+
dispatcher: Dispatch<object>;
|
|
13
18
|
series: PreparedSeries[];
|
|
14
|
-
seriesOptions
|
|
15
|
-
xAxis:
|
|
16
|
-
yAxis:
|
|
19
|
+
seriesOptions: PreparedSeriesOptions;
|
|
20
|
+
xAxis: PreparedAxis;
|
|
21
|
+
yAxis: PreparedAxis[];
|
|
17
22
|
svgContainer: SVGSVGElement | null;
|
|
18
|
-
onSeriesMouseMove?: OnSeriesMouseMove;
|
|
19
|
-
onSeriesMouseLeave?: OnSeriesMouseLeave;
|
|
20
23
|
xScale?: ChartScale;
|
|
21
24
|
yScale?: ChartScale;
|
|
22
25
|
};
|
|
23
26
|
export declare const useShapes: (args: Args) => {
|
|
24
27
|
shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
|
|
28
|
+
shapesData: ShapeData[];
|
|
25
29
|
};
|
|
26
|
-
export {};
|
|
@@ -1,46 +1,63 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { group } from 'd3';
|
|
3
3
|
import { getOnlyVisibleSeries } from '../../utils';
|
|
4
|
-
import { BarXSeriesShapes } from './bar-x';
|
|
5
|
-
import { ScatterSeriesShape } from './scatter';
|
|
4
|
+
import { BarXSeriesShapes, prepareBarXData } from './bar-x';
|
|
5
|
+
import { ScatterSeriesShape, prepareScatterData } from './scatter';
|
|
6
6
|
import { PieSeriesComponent } from './pie';
|
|
7
7
|
import './styles.css';
|
|
8
8
|
export const useShapes = (args) => {
|
|
9
|
-
const { top, left, boundsWidth, boundsHeight, series, seriesOptions, xAxis, xScale, yAxis, yScale, svgContainer,
|
|
10
|
-
const
|
|
9
|
+
const { top, left, boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, svgContainer, } = args;
|
|
10
|
+
const shapesComponents = React.useMemo(() => {
|
|
11
11
|
const visibleSeries = getOnlyVisibleSeries(series);
|
|
12
12
|
const groupedSeries = group(visibleSeries, (item) => item.type);
|
|
13
|
-
|
|
13
|
+
const shapesData = [];
|
|
14
|
+
const shapes = Array.from(groupedSeries).reduce((acc, item) => {
|
|
14
15
|
const [seriesType, chartSeries] = item;
|
|
15
16
|
switch (seriesType) {
|
|
16
17
|
case 'bar-x': {
|
|
17
18
|
if (xScale && yScale) {
|
|
18
|
-
|
|
19
|
+
const preparedData = prepareBarXData({
|
|
20
|
+
series: chartSeries,
|
|
21
|
+
seriesOptions,
|
|
22
|
+
xAxis,
|
|
23
|
+
xScale,
|
|
24
|
+
yAxis,
|
|
25
|
+
yScale,
|
|
26
|
+
});
|
|
27
|
+
acc.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
28
|
+
shapesData.push(...preparedData);
|
|
19
29
|
}
|
|
20
30
|
break;
|
|
21
31
|
}
|
|
22
32
|
case 'scatter': {
|
|
23
33
|
if (xScale && yScale) {
|
|
24
|
-
const
|
|
25
|
-
|
|
34
|
+
const preparedData = prepareScatterData({
|
|
35
|
+
series: chartSeries,
|
|
36
|
+
xAxis,
|
|
37
|
+
xScale,
|
|
38
|
+
yAxis: yAxis[0],
|
|
39
|
+
yScale,
|
|
26
40
|
});
|
|
27
|
-
acc.push(
|
|
41
|
+
acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, top: top, left: left, preparedData: preparedData, seriesOptions: seriesOptions, svgContainer: svgContainer }));
|
|
28
42
|
}
|
|
29
43
|
break;
|
|
30
44
|
}
|
|
31
45
|
case 'pie': {
|
|
32
46
|
const groupedPieSeries = group(chartSeries, (pieSeries) => pieSeries.stackId);
|
|
33
47
|
acc.push(...Array.from(groupedPieSeries).map(([key, pieSeries]) => {
|
|
34
|
-
return (React.createElement(PieSeriesComponent, { key: `pie-${key}`, boundsWidth: boundsWidth, boundsHeight: boundsHeight,
|
|
48
|
+
return (React.createElement(PieSeriesComponent, { key: `pie-${key}`, boundsWidth: boundsWidth, boundsHeight: boundsHeight, dispatcher: dispatcher, top: top, left: left, series: pieSeries, seriesOptions: seriesOptions, svgContainer: svgContainer }));
|
|
35
49
|
}));
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
return acc;
|
|
39
53
|
}, []);
|
|
54
|
+
return { shapes, shapesData };
|
|
40
55
|
}, [
|
|
41
56
|
boundsWidth,
|
|
42
57
|
boundsHeight,
|
|
58
|
+
dispatcher,
|
|
43
59
|
series,
|
|
60
|
+
seriesOptions,
|
|
44
61
|
xAxis,
|
|
45
62
|
xScale,
|
|
46
63
|
yAxis,
|
|
@@ -48,8 +65,6 @@ export const useShapes = (args) => {
|
|
|
48
65
|
svgContainer,
|
|
49
66
|
left,
|
|
50
67
|
top,
|
|
51
|
-
onSeriesMouseMove,
|
|
52
|
-
onSeriesMouseLeave,
|
|
53
68
|
]);
|
|
54
|
-
return { shapes };
|
|
69
|
+
return { shapes: shapesComponents.shapes, shapesData: shapesComponents.shapesData };
|
|
55
70
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
import { PreparedPieSeries } from '../useSeries/types';
|
|
2
|
+
import type { Dispatch } from 'd3';
|
|
3
|
+
import { PreparedPieSeries, PreparedSeriesOptions } from '../useSeries/types';
|
|
4
4
|
type PreparePieSeriesArgs = {
|
|
5
5
|
boundsWidth: number;
|
|
6
6
|
boundsHeight: number;
|
|
7
|
+
dispatcher: Dispatch<object>;
|
|
8
|
+
top: number;
|
|
9
|
+
left: number;
|
|
7
10
|
series: PreparedPieSeries[];
|
|
11
|
+
seriesOptions: PreparedSeriesOptions;
|
|
8
12
|
svgContainer: SVGSVGElement | null;
|
|
9
|
-
onSeriesMouseMove?: OnSeriesMouseMove;
|
|
10
|
-
onSeriesMouseLeave?: OnSeriesMouseLeave;
|
|
11
13
|
};
|
|
12
14
|
export declare function PieSeriesComponent(args: PreparePieSeriesArgs): React.JSX.Element;
|
|
13
15
|
export {};
|