@gravity-ui/charts 1.18.2 → 1.20.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/dist/cjs/components/AxisY/AxisY.js +7 -5
- package/dist/cjs/components/AxisY/prepare-axis-data.js +8 -5
- package/dist/cjs/components/AxisY/types.d.ts +1 -1
- package/dist/cjs/components/AxisY/utils.js +1 -1
- package/dist/cjs/components/ChartInner/index.js +20 -26
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +2 -2
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +57 -31
- package/dist/cjs/components/ChartInner/utils.d.ts +1 -0
- package/dist/cjs/components/ChartInner/utils.js +21 -0
- package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -1
- package/dist/cjs/components/Tooltip/ChartTooltipContent.js +3 -2
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +1 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +2 -1
- package/dist/cjs/constants/chart-types.d.ts +1 -0
- package/dist/cjs/constants/chart-types.js +1 -0
- package/dist/cjs/constants/defaults/series-options.js +8 -0
- package/dist/cjs/hooks/useAxisScales/index.js +47 -8
- package/dist/cjs/hooks/useChartOptions/tooltip.js +1 -1
- package/dist/cjs/hooks/useChartOptions/x-axis.d.ts +1 -1
- package/dist/cjs/hooks/useChartOptions/x-axis.js +15 -4
- package/dist/cjs/hooks/useChartOptions/y-axis.js +15 -7
- package/dist/cjs/hooks/useSeries/prepare-heatmap.d.ts +11 -0
- package/dist/cjs/hooks/useSeries/prepare-heatmap.js +37 -0
- package/dist/cjs/hooks/useSeries/prepareSeries.js +9 -0
- package/dist/cjs/hooks/useSeries/types.d.ts +14 -2
- package/dist/cjs/hooks/useShapes/heatmap/index.d.ts +13 -0
- package/dist/cjs/hooks/useShapes/heatmap/index.js +74 -0
- package/dist/cjs/hooks/useShapes/heatmap/prepare-data.d.ts +13 -0
- package/dist/cjs/hooks/useShapes/heatmap/prepare-data.js +97 -0
- package/dist/cjs/hooks/useShapes/heatmap/types.d.ts +24 -0
- package/dist/cjs/hooks/useShapes/heatmap/types.js +1 -0
- package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/index.js +15 -0
- package/dist/cjs/hooks/useShapes/styles.css +4 -0
- package/dist/cjs/hooks/useTooltip/index.js +11 -1
- package/dist/cjs/hooks/utils/bar-y.d.ts +0 -5
- package/dist/cjs/hooks/utils/bar-y.js +2 -29
- package/dist/cjs/hooks/utils/get-band-size.d.ts +5 -0
- package/dist/cjs/hooks/utils/get-band-size.js +29 -0
- package/dist/cjs/i18n/keysets/en.json +2 -1
- package/dist/cjs/i18n/keysets/ru.json +2 -1
- package/dist/cjs/types/chart/axis.d.ts +3 -1
- package/dist/cjs/types/chart/heatmap.d.ts +47 -0
- package/dist/cjs/types/chart/heatmap.js +1 -0
- package/dist/cjs/types/chart/series.d.ts +19 -2
- package/dist/cjs/types/chart/tooltip.d.ts +7 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/utils/chart/color.js +3 -2
- package/dist/cjs/utils/chart/get-closest-data.js +18 -1
- package/dist/cjs/utils/chart/index.js +10 -13
- package/dist/cjs/utils/chart/series/waterfall.d.ts +1 -1
- package/dist/cjs/utils/chart/series/waterfall.js +3 -3
- package/dist/cjs/validation/validate-axes.js +31 -1
- package/dist/esm/components/AxisY/AxisY.js +7 -5
- package/dist/esm/components/AxisY/prepare-axis-data.js +8 -5
- package/dist/esm/components/AxisY/types.d.ts +1 -1
- package/dist/esm/components/AxisY/utils.js +1 -1
- package/dist/esm/components/ChartInner/index.js +20 -26
- package/dist/esm/components/ChartInner/useChartInnerProps.js +57 -31
- package/dist/esm/components/ChartInner/utils.d.ts +1 -0
- package/dist/esm/components/ChartInner/utils.js +21 -0
- package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -1
- package/dist/esm/components/Tooltip/ChartTooltipContent.js +3 -2
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +1 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +2 -1
- package/dist/esm/constants/chart-types.d.ts +1 -0
- package/dist/esm/constants/chart-types.js +1 -0
- package/dist/esm/constants/defaults/series-options.js +8 -0
- package/dist/esm/hooks/useAxisScales/index.js +47 -8
- package/dist/esm/hooks/useChartOptions/tooltip.js +1 -1
- package/dist/esm/hooks/useChartOptions/x-axis.d.ts +1 -1
- package/dist/esm/hooks/useChartOptions/x-axis.js +15 -4
- package/dist/esm/hooks/useChartOptions/y-axis.js +15 -7
- package/dist/esm/hooks/useSeries/prepare-heatmap.d.ts +11 -0
- package/dist/esm/hooks/useSeries/prepare-heatmap.js +37 -0
- package/dist/esm/hooks/useSeries/prepareSeries.js +9 -0
- package/dist/esm/hooks/useSeries/types.d.ts +14 -2
- package/dist/esm/hooks/useShapes/heatmap/index.d.ts +13 -0
- package/dist/esm/hooks/useShapes/heatmap/index.js +74 -0
- package/dist/esm/hooks/useShapes/heatmap/prepare-data.d.ts +13 -0
- package/dist/esm/hooks/useShapes/heatmap/prepare-data.js +97 -0
- package/dist/esm/hooks/useShapes/heatmap/types.d.ts +24 -0
- package/dist/esm/hooks/useShapes/heatmap/types.js +1 -0
- package/dist/esm/hooks/useShapes/index.d.ts +2 -1
- package/dist/esm/hooks/useShapes/index.js +15 -0
- package/dist/esm/hooks/useShapes/styles.css +4 -0
- package/dist/esm/hooks/useTooltip/index.js +11 -1
- package/dist/esm/hooks/utils/bar-y.d.ts +0 -5
- package/dist/esm/hooks/utils/bar-y.js +2 -29
- package/dist/esm/hooks/utils/get-band-size.d.ts +5 -0
- package/dist/esm/hooks/utils/get-band-size.js +29 -0
- package/dist/esm/i18n/keysets/en.json +2 -1
- package/dist/esm/i18n/keysets/ru.json +2 -1
- package/dist/esm/types/chart/axis.d.ts +3 -1
- package/dist/esm/types/chart/heatmap.d.ts +47 -0
- package/dist/esm/types/chart/heatmap.js +1 -0
- package/dist/esm/types/chart/series.d.ts +19 -2
- package/dist/esm/types/chart/tooltip.d.ts +7 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/utils/chart/color.js +3 -2
- package/dist/esm/utils/chart/get-closest-data.js +18 -1
- package/dist/esm/utils/chart/index.js +10 -13
- package/dist/esm/utils/chart/series/waterfall.d.ts +1 -1
- package/dist/esm/utils/chart/series/waterfall.js +3 -3
- package/dist/esm/validation/validate-axes.js +31 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, axisCrosshairDefaults, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
|
|
3
|
-
import { calculateCos, calculateNumericProperty, formatAxisTickLabel, getAxisItems, getClosestPointsRange, getDefaultDateFormat, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, hasOverlappingLabels, wrapText, } from '../../utils';
|
|
2
|
+
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, SeriesType, axisCrosshairDefaults, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
|
|
3
|
+
import { calculateCos, calculateNumericProperty, formatAxisTickLabel, getAxisItems, getClosestPointsRange, getDefaultDateFormat, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, hasOverlappingLabels, isAxisRelatedSeries, wrapText, } from '../../utils';
|
|
4
4
|
import { createXScale } from '../useAxisScales';
|
|
5
5
|
import { getAxisCategories, prepareAxisPlotLabel } from './utils';
|
|
6
6
|
async function setLabelSettings({ axis, seriesData, seriesOptions, width, autoRotation = true, }) {
|
|
@@ -49,8 +49,18 @@ async function setLabelSettings({ axis, seriesData, seriesOptions, width, autoRo
|
|
|
49
49
|
axis.labels.height = Math.min(maxHeight, labelsHeight);
|
|
50
50
|
axis.labels.rotation = rotation;
|
|
51
51
|
}
|
|
52
|
+
function getMaxPaddingBySeries({ series }) {
|
|
53
|
+
if (series.some((s) => s.type === SeriesType.Heatmap)) {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
return 0.01;
|
|
57
|
+
}
|
|
52
58
|
export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width, }) => {
|
|
53
59
|
var _a, _b, _c, _d, _e;
|
|
60
|
+
const hasAxisRelatedSeries = seriesData.some(isAxisRelatedSeries);
|
|
61
|
+
if (!hasAxisRelatedSeries) {
|
|
62
|
+
return Promise.resolve(null);
|
|
63
|
+
}
|
|
54
64
|
const titleText = get(xAxis, 'title.text', '');
|
|
55
65
|
const titleStyle = Object.assign(Object.assign({}, xAxisTitleDefaults.style), get(xAxis, 'title.style'));
|
|
56
66
|
const titleMaxRowsCount = get(xAxis, 'title.maxRowCount', xAxisTitleDefaults.maxRowCount);
|
|
@@ -70,6 +80,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width
|
|
|
70
80
|
const labelsLineHeight = labelsHtml
|
|
71
81
|
? getHorizontalHtmlTextHeight({ text: 'Tmp', style: labelsStyle })
|
|
72
82
|
: getHorizontalSvgTextHeight({ text: 'Tmp', style: labelsStyle });
|
|
83
|
+
const shouldHideGrid = seriesData.some((s) => s.type === SeriesType.Heatmap);
|
|
73
84
|
const preparedXAxis = {
|
|
74
85
|
type: get(xAxis, 'type', 'linear'),
|
|
75
86
|
labels: {
|
|
@@ -100,9 +111,9 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width
|
|
|
100
111
|
},
|
|
101
112
|
min: get(xAxis, 'min'),
|
|
102
113
|
max: get(xAxis, 'max'),
|
|
103
|
-
maxPadding: get(xAxis, 'maxPadding',
|
|
114
|
+
maxPadding: get(xAxis, 'maxPadding', getMaxPaddingBySeries({ series: seriesData })),
|
|
104
115
|
grid: {
|
|
105
|
-
enabled: get(xAxis, 'grid.enabled', true),
|
|
116
|
+
enabled: shouldHideGrid ? false : get(xAxis, 'grid.enabled', true),
|
|
106
117
|
},
|
|
107
118
|
ticks: {
|
|
108
119
|
pixelInterval: ((_c = xAxis === null || xAxis === void 0 ? void 0 : xAxis.ticks) === null || _c === void 0 ? void 0 : _c.interval)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import { getTickValues } from '../../components/AxisY/utils';
|
|
3
|
-
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisCrosshairDefaults, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
4
|
-
import { calculateNumericProperty, formatAxisTickLabel,
|
|
3
|
+
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, SeriesType, axisCrosshairDefaults, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
4
|
+
import { calculateNumericProperty, formatAxisTickLabel, getDefaultDateFormat, getDefaultMinYAxisValue, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getMinSpaceBetween, getTextSizeFn, isAxisRelatedSeries, wrapText, } from '../../utils';
|
|
5
5
|
import { createYScale } from '../useAxisScales';
|
|
6
6
|
import { getAxisCategories, prepareAxisPlotLabel } from './utils';
|
|
7
7
|
const getAxisLabelMaxWidth = async (args) => {
|
|
@@ -20,8 +20,7 @@ const getAxisLabelMaxWidth = async (args) => {
|
|
|
20
20
|
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
21
21
|
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
22
22
|
const tickValues = getTickValues({ axis, scale, labelLineHeight, series: seriesData });
|
|
23
|
-
const
|
|
24
|
-
const tickStep = getClosestPointsRange(axis, ticks);
|
|
23
|
+
const tickStep = getMinSpaceBetween(tickValues, (d) => Number(d.value));
|
|
25
24
|
if (axis.type === 'datetime' && !axis.labels.dateFormat) {
|
|
26
25
|
axis.labels.dateFormat = getDefaultDateFormat(tickStep);
|
|
27
26
|
}
|
|
@@ -38,6 +37,12 @@ const getAxisLabelMaxWidth = async (args) => {
|
|
|
38
37
|
});
|
|
39
38
|
return { height: size.maxHeight, width: size.maxWidth };
|
|
40
39
|
};
|
|
40
|
+
function getMaxPaddingBySeries({ series }) {
|
|
41
|
+
if (series.some((s) => s.type === SeriesType.Heatmap)) {
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
return 0.05;
|
|
45
|
+
}
|
|
41
46
|
export const getPreparedYAxis = ({ height, boundsHeight, width, seriesData, yAxis, }) => {
|
|
42
47
|
const axisByPlot = [];
|
|
43
48
|
const axisItems = yAxis || [{}];
|
|
@@ -72,6 +77,7 @@ export const getPreparedYAxis = ({ height, boundsHeight, width, seriesData, yAxi
|
|
|
72
77
|
})).slice(0, titleMaxRowsCount);
|
|
73
78
|
const titleSize = await getLabelsSize({ labels: [titleText], style: titleStyle });
|
|
74
79
|
const axisType = get(axisItem, 'type', DEFAULT_AXIS_TYPE);
|
|
80
|
+
const shouldHideGrid = axisItem.visible === false || seriesData.some((s) => s.type === SeriesType.Heatmap);
|
|
75
81
|
const preparedAxis = {
|
|
76
82
|
type: axisType,
|
|
77
83
|
labels: {
|
|
@@ -104,10 +110,12 @@ export const getPreparedYAxis = ({ height, boundsHeight, width, seriesData, yAxi
|
|
|
104
110
|
},
|
|
105
111
|
min: (_c = get(axisItem, 'min')) !== null && _c !== void 0 ? _c : getDefaultMinYAxisValue(seriesData),
|
|
106
112
|
max: get(axisItem, 'max'),
|
|
107
|
-
maxPadding: get(axisItem, 'maxPadding',
|
|
113
|
+
maxPadding: get(axisItem, 'maxPadding', getMaxPaddingBySeries({ series: seriesData })),
|
|
108
114
|
grid: {
|
|
109
|
-
enabled:
|
|
110
|
-
|
|
115
|
+
enabled: shouldHideGrid
|
|
116
|
+
? false
|
|
117
|
+
: get(axisItem, 'grid.enabled', firstPlotAxis ||
|
|
118
|
+
(!firstPlotAxis && !((_d = axisByPlot[plotIndex][0].visible) !== null && _d !== void 0 ? _d : true))),
|
|
111
119
|
},
|
|
112
120
|
ticks: {
|
|
113
121
|
pixelInterval: ((_e = axisItem.ticks) === null || _e === void 0 ? void 0 : _e.interval)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScaleOrdinal } from 'd3';
|
|
2
|
+
import type { ChartSeriesOptions, HeatmapSeries } from '../../types';
|
|
3
|
+
import type { PreparedLegend, PreparedSeries } from './types';
|
|
4
|
+
type PrepareHeatmapSeriesArgs = {
|
|
5
|
+
colorScale: ScaleOrdinal<string, string>;
|
|
6
|
+
series: HeatmapSeries[];
|
|
7
|
+
legend: PreparedLegend;
|
|
8
|
+
seriesOptions?: ChartSeriesOptions;
|
|
9
|
+
};
|
|
10
|
+
export declare function prepareHeatmapSeries(args: PrepareHeatmapSeriesArgs): PreparedSeries[];
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import { DEFAULT_DATALABELS_STYLE } from '../../constants';
|
|
3
|
+
import { getUniqId } from '../../utils';
|
|
4
|
+
import { DEFAULT_DATALABELS_PADDING } from './constants';
|
|
5
|
+
import { prepareLegendSymbol } from './utils';
|
|
6
|
+
export function prepareHeatmapSeries(args) {
|
|
7
|
+
const { colorScale, series: seriesList, seriesOptions, legend } = args;
|
|
8
|
+
return seriesList.map((series) => {
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
10
|
+
const name = series.name || '';
|
|
11
|
+
const color = series.color || colorScale(name);
|
|
12
|
+
return {
|
|
13
|
+
type: series.type,
|
|
14
|
+
color,
|
|
15
|
+
name,
|
|
16
|
+
id: getUniqId(),
|
|
17
|
+
visible: get(series, 'visible', true),
|
|
18
|
+
legend: {
|
|
19
|
+
enabled: get(series, 'legend.enabled', legend.enabled),
|
|
20
|
+
symbol: prepareLegendSymbol(series),
|
|
21
|
+
},
|
|
22
|
+
data: series.data,
|
|
23
|
+
dataLabels: {
|
|
24
|
+
enabled: ((_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) || false,
|
|
25
|
+
style: Object.assign({}, DEFAULT_DATALABELS_STYLE, (_b = series.dataLabels) === null || _b === void 0 ? void 0 : _b.style),
|
|
26
|
+
padding: get(series, 'dataLabels.padding', DEFAULT_DATALABELS_PADDING),
|
|
27
|
+
html: (_d = (_c = series.dataLabels) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : false,
|
|
28
|
+
format: (_e = series.dataLabels) === null || _e === void 0 ? void 0 : _e.format,
|
|
29
|
+
},
|
|
30
|
+
cursor: get(series, 'cursor', null),
|
|
31
|
+
yAxis: get(series, 'yAxis', 0),
|
|
32
|
+
tooltip: series.tooltip,
|
|
33
|
+
borderColor: (_h = (_f = series.borderColor) !== null && _f !== void 0 ? _f : (_g = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.heatmap) === null || _g === void 0 ? void 0 : _g.borderColor) !== null && _h !== void 0 ? _h : 'var(--gcharts-shape-border-color)',
|
|
34
|
+
borderWidth: (_l = (_j = series.borderWidth) !== null && _j !== void 0 ? _j : (_k = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.heatmap) === null || _k === void 0 ? void 0 : _k.borderWidth) !== null && _l !== void 0 ? _l : 0,
|
|
35
|
+
};
|
|
36
|
+
}, []);
|
|
37
|
+
}
|
|
@@ -2,6 +2,7 @@ import { ChartError } from '../../libs';
|
|
|
2
2
|
import { prepareArea } from './prepare-area';
|
|
3
3
|
import { prepareBarXSeries } from './prepare-bar-x';
|
|
4
4
|
import { prepareBarYSeries } from './prepare-bar-y';
|
|
5
|
+
import { prepareHeatmapSeries } from './prepare-heatmap';
|
|
5
6
|
import { prepareLineSeries } from './prepare-line';
|
|
6
7
|
import { preparePieSeries } from './prepare-pie';
|
|
7
8
|
import { prepareRadarSeries } from './prepare-radar';
|
|
@@ -90,6 +91,14 @@ export async function prepareSeries(args) {
|
|
|
90
91
|
colors,
|
|
91
92
|
});
|
|
92
93
|
}
|
|
94
|
+
case 'heatmap': {
|
|
95
|
+
return await prepareHeatmapSeries({
|
|
96
|
+
series: series,
|
|
97
|
+
legend,
|
|
98
|
+
colorScale,
|
|
99
|
+
seriesOptions,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
93
102
|
default: {
|
|
94
103
|
throw new ChartError({
|
|
95
104
|
message: `Series type "${type}" does not support data preparation for series that do not support the presence of axes`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
|
|
2
|
-
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
2
|
+
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ConnectorCurve, ConnectorShape, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
3
3
|
export type RectLegendSymbol = {
|
|
4
4
|
shape: 'rect';
|
|
5
5
|
} & Required<RectLegendSymbolOptions>;
|
|
@@ -137,6 +137,18 @@ export type PreparedBarYSeries = {
|
|
|
137
137
|
borderWidth: number;
|
|
138
138
|
borderColor: string;
|
|
139
139
|
} & BasePreparedSeries;
|
|
140
|
+
export type PreparedHeatmapSeries = {
|
|
141
|
+
type: HeatmapSeries['type'];
|
|
142
|
+
data: HeatmapSeriesData[];
|
|
143
|
+
dataLabels: {
|
|
144
|
+
enabled: boolean;
|
|
145
|
+
style: BaseTextStyle;
|
|
146
|
+
html: boolean;
|
|
147
|
+
format?: ValueFormat;
|
|
148
|
+
};
|
|
149
|
+
borderWidth: number;
|
|
150
|
+
borderColor: string;
|
|
151
|
+
} & BasePreparedSeries;
|
|
140
152
|
export type PreparedPieSeries = {
|
|
141
153
|
type: PieSeries['type'];
|
|
142
154
|
data: PieSeriesData;
|
|
@@ -313,7 +325,7 @@ export type PreparedRadarSeries = {
|
|
|
313
325
|
};
|
|
314
326
|
};
|
|
315
327
|
} & BasePreparedSeries;
|
|
316
|
-
export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries | PreparedSankeySeries | PreparedRadarSeries;
|
|
328
|
+
export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries | PreparedSankeySeries | PreparedRadarSeries | PreparedHeatmapSeries;
|
|
317
329
|
export type PreparedSeriesOptions = SeriesOptionsDefaults;
|
|
318
330
|
export type StackedSeries = BarXSeries | AreaSeries | BarYSeries;
|
|
319
331
|
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Dispatch } from 'd3';
|
|
3
|
+
import type { PreparedSeriesOptions } from '../../useSeries/types';
|
|
4
|
+
import type { PreparedHeatmapData } from './types';
|
|
5
|
+
export { prepareHeatmapData } from './prepare-data';
|
|
6
|
+
export * from './types';
|
|
7
|
+
type Args = {
|
|
8
|
+
dispatcher: Dispatch<object>;
|
|
9
|
+
preparedData: PreparedHeatmapData;
|
|
10
|
+
seriesOptions: PreparedSeriesOptions;
|
|
11
|
+
htmlLayout: HTMLElement | null;
|
|
12
|
+
};
|
|
13
|
+
export declare const HeatmapSeriesShapes: (args: Args) => React.JSX.Element;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { color, select } from 'd3';
|
|
3
|
+
import { block } from '../../../utils';
|
|
4
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
5
|
+
export { prepareHeatmapData } from './prepare-data';
|
|
6
|
+
export * from './types';
|
|
7
|
+
const b = block('heatmap');
|
|
8
|
+
export const HeatmapSeriesShapes = (args) => {
|
|
9
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
|
+
const hoveredDataRef = React.useRef(null);
|
|
11
|
+
const ref = React.useRef(null);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
if (!ref.current) {
|
|
15
|
+
return () => { };
|
|
16
|
+
}
|
|
17
|
+
const svgElement = select(ref.current);
|
|
18
|
+
const hoverOptions = (_b = (_a = seriesOptions.heatmap) === null || _a === void 0 ? void 0 : _a.states) === null || _b === void 0 ? void 0 : _b.hover;
|
|
19
|
+
svgElement.selectAll('*').remove();
|
|
20
|
+
// heatmap cells
|
|
21
|
+
const cellsSelection = svgElement
|
|
22
|
+
.selectAll('rect')
|
|
23
|
+
.data(preparedData.items)
|
|
24
|
+
.join('rect')
|
|
25
|
+
.attr('x', (d) => d.x)
|
|
26
|
+
.attr('y', (d) => d.y)
|
|
27
|
+
.attr('height', (d) => d.height)
|
|
28
|
+
.attr('width', (d) => d.width)
|
|
29
|
+
.attr('fill', (d) => d.color)
|
|
30
|
+
.attr('stroke', (d) => d.borderColor)
|
|
31
|
+
.attr('stroke-width', (d) => d.borderWidth);
|
|
32
|
+
// dataLabels
|
|
33
|
+
svgElement
|
|
34
|
+
.selectAll('text')
|
|
35
|
+
.data(preparedData.labels)
|
|
36
|
+
.join('text')
|
|
37
|
+
.text((d) => d.text)
|
|
38
|
+
.attr('class', b('label'))
|
|
39
|
+
.attr('x', (d) => d.x)
|
|
40
|
+
.attr('y', (d) => d.y)
|
|
41
|
+
.style('font-size', (d) => d.style.fontSize)
|
|
42
|
+
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
43
|
+
.style('fill', (d) => d.style.fontColor || null);
|
|
44
|
+
function handleShapeHover(data) {
|
|
45
|
+
hoveredDataRef.current = data;
|
|
46
|
+
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
47
|
+
if (hoverEnabled) {
|
|
48
|
+
const hovered = data === null || data === void 0 ? void 0 : data.reduce((acc, d) => {
|
|
49
|
+
acc.add(d.data);
|
|
50
|
+
return acc;
|
|
51
|
+
}, new Set());
|
|
52
|
+
cellsSelection.attr('fill', (d) => {
|
|
53
|
+
var _a;
|
|
54
|
+
const fillColor = d.color;
|
|
55
|
+
if (hovered === null || hovered === void 0 ? void 0 : hovered.has(d.data)) {
|
|
56
|
+
return (((_a = color(fillColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions.brightness).toString()) ||
|
|
57
|
+
fillColor);
|
|
58
|
+
}
|
|
59
|
+
return fillColor;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (hoveredDataRef.current !== null) {
|
|
64
|
+
handleShapeHover(hoveredDataRef.current);
|
|
65
|
+
}
|
|
66
|
+
dispatcher.on('hover-shape.heatmap', handleShapeHover);
|
|
67
|
+
return () => {
|
|
68
|
+
dispatcher.on('hover-shape.heatmap', null);
|
|
69
|
+
};
|
|
70
|
+
}, [dispatcher, preparedData, seriesOptions]);
|
|
71
|
+
return (React.createElement(React.Fragment, null,
|
|
72
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
73
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
74
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChartScale } from '../../../hooks/useAxisScales';
|
|
2
|
+
import type { PreparedAxis } from '../../../hooks/useChartOptions/types';
|
|
3
|
+
import type { PreparedHeatmapSeries } from '../../useSeries/types';
|
|
4
|
+
import type { PreparedHeatmapData } from './types';
|
|
5
|
+
type PrepareHeatmapDataArgs = {
|
|
6
|
+
series: PreparedHeatmapSeries;
|
|
7
|
+
xAxis: PreparedAxis;
|
|
8
|
+
yAxis: PreparedAxis;
|
|
9
|
+
xScale: ChartScale;
|
|
10
|
+
yScale: ChartScale;
|
|
11
|
+
};
|
|
12
|
+
export declare function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale, }: PrepareHeatmapDataArgs): Promise<PreparedHeatmapData>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { getBandSize } from '../../../hooks/utils/get-band-size';
|
|
2
|
+
import { getDomainDataXBySeries, getDomainDataYBySeries, getFormattedValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isBandScale, } from '../../../utils';
|
|
3
|
+
export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale, }) {
|
|
4
|
+
var _a, _b, _c, _d, _e;
|
|
5
|
+
const yDomainData = getDomainDataYBySeries([series]);
|
|
6
|
+
const bandHeight = getBandSize({ domain: yDomainData, scale: yScale });
|
|
7
|
+
const yAxisCategories = (_a = yAxis.categories) !== null && _a !== void 0 ? _a : [];
|
|
8
|
+
const xDomainData = getDomainDataXBySeries([series]);
|
|
9
|
+
const bandWidth = getBandSize({ domain: xDomainData, scale: xScale });
|
|
10
|
+
const xAxisCategories = (_b = xAxis.categories) !== null && _b !== void 0 ? _b : [];
|
|
11
|
+
const heatmapItems = series.data.map((d) => {
|
|
12
|
+
var _a, _b, _c;
|
|
13
|
+
let x = 0;
|
|
14
|
+
if (isBandScale(xScale)) {
|
|
15
|
+
x = (_a = xScale(xAxisCategories[d.x])) !== null && _a !== void 0 ? _a : 0;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const scale = xScale;
|
|
19
|
+
x = scale(d.x) - bandWidth / 2;
|
|
20
|
+
}
|
|
21
|
+
let y = 0;
|
|
22
|
+
if (isBandScale(yScale)) {
|
|
23
|
+
y = (_b = yScale(yAxisCategories[d.y])) !== null && _b !== void 0 ? _b : 0;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const scale = yScale;
|
|
27
|
+
y = scale(d.y) - bandHeight / 2;
|
|
28
|
+
}
|
|
29
|
+
const item = {
|
|
30
|
+
x,
|
|
31
|
+
y,
|
|
32
|
+
color: (_c = d.color) !== null && _c !== void 0 ? _c : series.color,
|
|
33
|
+
width: bandWidth,
|
|
34
|
+
height: bandHeight,
|
|
35
|
+
borderColor: series.borderColor,
|
|
36
|
+
borderWidth: series.borderWidth,
|
|
37
|
+
data: d,
|
|
38
|
+
};
|
|
39
|
+
return item;
|
|
40
|
+
});
|
|
41
|
+
const svgDataLabels = [];
|
|
42
|
+
const htmlDataLabels = [];
|
|
43
|
+
if (series.dataLabels.enabled) {
|
|
44
|
+
if (series.dataLabels.html) {
|
|
45
|
+
for (let i = 0; i < heatmapItems.length; i++) {
|
|
46
|
+
const item = heatmapItems[i];
|
|
47
|
+
const labelContent = (_c = item.data.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
|
|
48
|
+
if (labelContent) {
|
|
49
|
+
const dataLabelsStyle = Object.assign(Object.assign({}, series.dataLabels.style), { maxWidth: `${item.width}px`, maxHeight: `${item.height}px`, overflow: 'hidden' });
|
|
50
|
+
const { maxHeight: height, maxWidth: width } = (_d = (await getLabelsSize({
|
|
51
|
+
labels: [labelContent],
|
|
52
|
+
style: dataLabelsStyle,
|
|
53
|
+
html: true,
|
|
54
|
+
}))) !== null && _d !== void 0 ? _d : {};
|
|
55
|
+
const size = { width, height };
|
|
56
|
+
htmlDataLabels.push({
|
|
57
|
+
x: item.x + item.width / 2 - size.width / 2,
|
|
58
|
+
y: item.y + item.height / 2 - size.height / 2,
|
|
59
|
+
content: labelContent,
|
|
60
|
+
style: dataLabelsStyle,
|
|
61
|
+
size,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const getTextSize = getTextSizeFn({ style: series.dataLabels.style });
|
|
68
|
+
for (let i = 0; i < heatmapItems.length; i++) {
|
|
69
|
+
const item = heatmapItems[i];
|
|
70
|
+
const labelContent = (_e = item.data.label) !== null && _e !== void 0 ? _e : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
|
|
71
|
+
if (labelContent) {
|
|
72
|
+
const size = await getTextSize(labelContent);
|
|
73
|
+
const text = await getTextWithElipsis({
|
|
74
|
+
text: labelContent,
|
|
75
|
+
getTextWidth: (s) => getTextSize(s).then((value) => value.width),
|
|
76
|
+
maxWidth: item.width,
|
|
77
|
+
});
|
|
78
|
+
if (text) {
|
|
79
|
+
svgDataLabels.push({
|
|
80
|
+
x: item.x + item.width / 2 - size.width / 2,
|
|
81
|
+
y: item.y + item.height / 2 - size.height / 2,
|
|
82
|
+
text,
|
|
83
|
+
style: series.dataLabels.style,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const preparedData = {
|
|
91
|
+
series: series,
|
|
92
|
+
htmlElements: htmlDataLabels,
|
|
93
|
+
items: heatmapItems,
|
|
94
|
+
labels: svgDataLabels,
|
|
95
|
+
};
|
|
96
|
+
return preparedData;
|
|
97
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BaseTextStyle, HeatmapSeriesData, HtmlItem } from '../../../types';
|
|
2
|
+
import type { PreparedHeatmapSeries } from '../../useSeries/types';
|
|
3
|
+
export type HeatmapItem = {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
color: string;
|
|
9
|
+
borderColor: string | null;
|
|
10
|
+
borderWidth: number | null;
|
|
11
|
+
data: HeatmapSeriesData;
|
|
12
|
+
};
|
|
13
|
+
export type HeatmapLabel = {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
text: string;
|
|
17
|
+
style: BaseTextStyle;
|
|
18
|
+
};
|
|
19
|
+
export type PreparedHeatmapData = {
|
|
20
|
+
series: PreparedHeatmapSeries;
|
|
21
|
+
items: HeatmapItem[];
|
|
22
|
+
htmlElements: HtmlItem[];
|
|
23
|
+
labels: HeatmapLabel[];
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,6 +6,7 @@ import type { PreparedAxis } from '../useChartOptions/types';
|
|
|
6
6
|
import type { PreparedAreaData } from './area/types';
|
|
7
7
|
import type { PreparedBarXData } from './bar-x';
|
|
8
8
|
import type { PreparedBarYData } from './bar-y/types';
|
|
9
|
+
import type { PreparedHeatmapData } from './heatmap';
|
|
9
10
|
import type { PreparedLineData } from './line/types';
|
|
10
11
|
import type { PreparedPieData } from './pie/types';
|
|
11
12
|
import type { PreparedRadarData } from './radar/types';
|
|
@@ -15,7 +16,7 @@ export type { PreparedBarXData } from './bar-x';
|
|
|
15
16
|
export type { PreparedScatterData } from './scatter/types';
|
|
16
17
|
import type { PreparedWaterfallData } from './waterfall';
|
|
17
18
|
import './styles.css';
|
|
18
|
-
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData;
|
|
19
|
+
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData | PreparedHeatmapData;
|
|
19
20
|
type Args = {
|
|
20
21
|
boundsWidth: number;
|
|
21
22
|
boundsHeight: number;
|
|
@@ -6,6 +6,7 @@ import { AreaSeriesShapes } from './area';
|
|
|
6
6
|
import { prepareAreaData } from './area/prepare-data';
|
|
7
7
|
import { BarXSeriesShapes, prepareBarXData } from './bar-x';
|
|
8
8
|
import { BarYSeriesShapes, prepareBarYData } from './bar-y';
|
|
9
|
+
import { HeatmapSeriesShapes, prepareHeatmapData } from './heatmap';
|
|
9
10
|
import { LineSeriesShapes } from './line';
|
|
10
11
|
import { prepareLineData } from './line/prepare-data';
|
|
11
12
|
import { PieSeriesShapes } from './pie';
|
|
@@ -174,6 +175,20 @@ export const useShapes = (args) => {
|
|
|
174
175
|
shapesData.push(...preparedData);
|
|
175
176
|
break;
|
|
176
177
|
}
|
|
178
|
+
case 'heatmap': {
|
|
179
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale[0])) {
|
|
180
|
+
const preparedData = await prepareHeatmapData({
|
|
181
|
+
series: chartSeries[0],
|
|
182
|
+
xAxis,
|
|
183
|
+
xScale,
|
|
184
|
+
yAxis: yAxis[0],
|
|
185
|
+
yScale: yScale[0],
|
|
186
|
+
});
|
|
187
|
+
shapes.push(React.createElement(HeatmapSeriesShapes, { key: "heatmap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
188
|
+
shapesData.push(preparedData);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
177
192
|
default: {
|
|
178
193
|
throw new ChartError({
|
|
179
194
|
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
2
3
|
export const useTooltip = ({ dispatcher, tooltip }) => {
|
|
3
4
|
const [{ hovered, pointerPosition }, setTooltipState] = React.useState({});
|
|
5
|
+
const prevHovered = React.useRef(hovered);
|
|
4
6
|
React.useEffect(() => {
|
|
5
7
|
if (tooltip === null || tooltip === void 0 ? void 0 : tooltip.enabled) {
|
|
6
8
|
dispatcher.on('hover-shape.tooltip', (nextHovered, nextPointerPosition) => {
|
|
7
|
-
|
|
9
|
+
const isHoveredChanged = !isEqual(prevHovered.current, nextHovered);
|
|
10
|
+
const newTooltipState = {
|
|
11
|
+
pointerPosition: nextPointerPosition,
|
|
12
|
+
hovered: isHoveredChanged ? nextHovered : prevHovered.current,
|
|
13
|
+
};
|
|
14
|
+
if (isHoveredChanged) {
|
|
15
|
+
prevHovered.current = nextHovered;
|
|
16
|
+
}
|
|
17
|
+
setTooltipState(newTooltipState);
|
|
8
18
|
});
|
|
9
19
|
}
|
|
10
20
|
return () => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { AxisDomain, AxisScale } from 'd3';
|
|
2
1
|
import type { BarYSeries, BarYSeriesData } from '../../types';
|
|
3
2
|
import type { ChartScale } from '../useAxisScales';
|
|
4
3
|
import type { PreparedAxis } from '../useChartOptions/types';
|
|
@@ -7,10 +6,6 @@ export declare function groupBarYDataByYValue<T extends BarYSeries | PreparedBar
|
|
|
7
6
|
data: BarYSeriesData;
|
|
8
7
|
series: T;
|
|
9
8
|
}[]>>;
|
|
10
|
-
export declare function getBandSize({ domain, scale, }: {
|
|
11
|
-
domain: AxisDomain[];
|
|
12
|
-
scale: AxisScale<AxisDomain> | undefined;
|
|
13
|
-
}): number;
|
|
14
9
|
export declare function getBarYLayout(args: {
|
|
15
10
|
plotHeight: number;
|
|
16
11
|
seriesOptions: PreparedSeriesOptions;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { max } from 'd3';
|
|
2
2
|
import get from 'lodash/get';
|
|
3
|
-
import { getDataCategoryValue
|
|
3
|
+
import { getDataCategoryValue } from '../../utils';
|
|
4
4
|
import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
|
|
5
5
|
import { getSeriesStackId } from '../useSeries/utils';
|
|
6
|
+
import { getBandSize } from './get-band-size';
|
|
6
7
|
export function groupBarYDataByYValue(series, yAxis) {
|
|
7
8
|
const data = {};
|
|
8
9
|
series.forEach((s) => {
|
|
@@ -27,34 +28,6 @@ export function groupBarYDataByYValue(series, yAxis) {
|
|
|
27
28
|
});
|
|
28
29
|
return data;
|
|
29
30
|
}
|
|
30
|
-
export function getBandSize({ domain, scale, }) {
|
|
31
|
-
if (!scale || !domain.length) {
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
if (isBandScale(scale)) {
|
|
35
|
-
return scale.bandwidth();
|
|
36
|
-
}
|
|
37
|
-
const range = scale.range();
|
|
38
|
-
const plotHeight = Math.abs(range[0] - range[1]);
|
|
39
|
-
if (domain.length === 1) {
|
|
40
|
-
return plotHeight;
|
|
41
|
-
}
|
|
42
|
-
// for the numeric or datetime axes, you first need to count domain.length + 1,
|
|
43
|
-
// since the extreme points are located not in the center of the bar, but along the edges of the axes
|
|
44
|
-
let bandWidth = plotHeight / (domain.length - 1);
|
|
45
|
-
domain.forEach((current, index) => {
|
|
46
|
-
if (index > 0) {
|
|
47
|
-
const prev = domain[index - 1];
|
|
48
|
-
const prevY = scale(prev);
|
|
49
|
-
const currentY = scale(current);
|
|
50
|
-
if (typeof prevY === 'number' && typeof currentY === 'number') {
|
|
51
|
-
const distance = Math.abs(prevY - currentY);
|
|
52
|
-
bandWidth = Math.min(bandWidth, distance);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return bandWidth;
|
|
57
|
-
}
|
|
58
31
|
export function getBarYLayout(args) {
|
|
59
32
|
const { groupedData, seriesOptions, scale } = args;
|
|
60
33
|
const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isBandScale } from '../../utils';
|
|
2
|
+
export function getBandSize({ domain, scale, }) {
|
|
3
|
+
if (!scale || !domain.length) {
|
|
4
|
+
return 0;
|
|
5
|
+
}
|
|
6
|
+
if (isBandScale(scale)) {
|
|
7
|
+
return scale.bandwidth();
|
|
8
|
+
}
|
|
9
|
+
const range = scale.range();
|
|
10
|
+
const plotHeight = Math.abs(range[0] - range[1]);
|
|
11
|
+
if (domain.length === 1) {
|
|
12
|
+
return plotHeight;
|
|
13
|
+
}
|
|
14
|
+
// for the numeric or datetime axes, you first need to count domain.length + 1,
|
|
15
|
+
// since the extreme points are located not in the center of the bar, but along the edges of the axes
|
|
16
|
+
let bandWidth = plotHeight / (domain.length - 1);
|
|
17
|
+
domain.forEach((current, index) => {
|
|
18
|
+
if (index > 0) {
|
|
19
|
+
const prev = domain[index - 1];
|
|
20
|
+
const prevY = scale(prev);
|
|
21
|
+
const currentY = scale(current);
|
|
22
|
+
if (typeof prevY === 'number' && typeof currentY === 'number') {
|
|
23
|
+
const distance = Math.abs(prevY - currentY);
|
|
24
|
+
bandWidth = Math.min(bandWidth, distance);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return bandWidth;
|
|
29
|
+
}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"label_invalid-tooltip-totals-aggregation-type-str": "It seems you are trying to use inappropriate value for built-in \"tooltip.totals.aggregation\". Available values: [{{values}}].",
|
|
19
19
|
"label_invalid-axis-type": "It seems you are trying to use inappropriate type for \"{{key}}\" axis. Available types: [{{values}}].",
|
|
20
20
|
"label_invalid-axis-labels-html-type": "It seems you are trying to use inappropriate type for \"labels.html\" property. Only boolean is allowed.",
|
|
21
|
-
"label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis."
|
|
21
|
+
"label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis.",
|
|
22
|
+
"label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}]."
|
|
22
23
|
},
|
|
23
24
|
"tooltip": {
|
|
24
25
|
"label_totals_sum": "Sum",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"label_invalid-tooltip-totals-aggregation-type-str": "Похоже, что вы пытаетесь использовать некорректное значение для встроенной агрегации \"tooltip.totals.aggregation\". Доступные значения: [{{values}}].",
|
|
19
19
|
"label_invalid-axis-type": "Похоже, что вы пытаетесь использовать некорректный тип для оси \"{{key}}\". Доступные типы: [{{values}}].",
|
|
20
20
|
"label_invalid-axis-labels-html-type": "Похоже, что вы пытаетесь использовать некорректный тип для свойства \"labels.html\". Допускается только использование булевых значений.",
|
|
21
|
-
"label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\"."
|
|
21
|
+
"label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\".",
|
|
22
|
+
"label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}]."
|
|
22
23
|
},
|
|
23
24
|
"tooltip": {
|
|
24
25
|
"label_totals_sum": "Сумма",
|