@gravity-ui/charts 1.17.0 → 1.18.1
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/prepare-axis-data.d.ts +4 -2
- package/dist/cjs/components/AxisY/prepare-axis-data.js +11 -10
- package/dist/cjs/components/AxisY/utils.d.ts +4 -2
- package/dist/cjs/components/AxisY/utils.js +47 -23
- package/dist/cjs/components/ChartInner/index.js +11 -5
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -1
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +3 -2
- package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
- package/dist/cjs/components/Tooltip/ChartTooltipContent.js +2 -2
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +2 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +3 -3
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +4 -3
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +6 -9
- package/dist/cjs/components/Tooltip/index.js +1 -1
- package/dist/cjs/hooks/useAxisScales/index.d.ts +3 -4
- package/dist/cjs/hooks/useAxisScales/index.js +82 -28
- package/dist/cjs/hooks/useChartOptions/index.d.ts +3 -1
- package/dist/cjs/hooks/useChartOptions/index.js +3 -3
- package/dist/cjs/hooks/useChartOptions/tooltip.d.ts +4 -1
- package/dist/cjs/hooks/useChartOptions/tooltip.js +18 -3
- package/dist/cjs/hooks/useChartOptions/utils.d.ts +5 -2
- package/dist/cjs/hooks/useChartOptions/utils.js +2 -3
- package/dist/cjs/hooks/useChartOptions/x-axis.js +21 -9
- package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +1 -3
- package/dist/cjs/hooks/useChartOptions/y-axis.js +23 -12
- package/dist/cjs/hooks/useCrosshair/index.d.ts +1 -1
- package/dist/cjs/hooks/useCrosshair/index.js +2 -1
- package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +3 -0
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +3 -0
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.d.ts +5 -3
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +46 -20
- package/dist/cjs/hooks/useShapes/index.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/index.js +2 -0
- package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +3 -0
- package/dist/cjs/hooks/useShapes/scatter/prepare-data.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/scatter/prepare-data.js +6 -0
- package/dist/cjs/hooks/useShapes/waterfall/prepare-data.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +6 -3
- package/dist/cjs/hooks/useZoom/index.d.ts +1 -1
- package/dist/cjs/hooks/useZoom/types.d.ts +1 -1
- package/dist/cjs/hooks/useZoom/utils.d.ts +1 -1
- package/dist/cjs/hooks/useZoom/utils.js +46 -18
- package/dist/cjs/hooks/utils/bar-y.d.ts +7 -10
- package/dist/cjs/hooks/utils/bar-y.js +33 -18
- package/dist/cjs/types/chart/tooltip.d.ts +3 -0
- package/dist/cjs/utils/chart/array.d.ts +1 -0
- package/dist/cjs/utils/chart/array.js +12 -0
- package/dist/cjs/utils/chart/format.js +2 -2
- package/dist/cjs/utils/chart/index.d.ts +1 -0
- package/dist/cjs/utils/chart/index.js +3 -1
- package/dist/cjs/utils/chart/labels.d.ts +27 -5
- package/dist/cjs/utils/chart/labels.js +39 -3
- package/dist/cjs/utils/chart/zoom.js +14 -8
- package/dist/esm/components/AxisY/prepare-axis-data.d.ts +4 -2
- package/dist/esm/components/AxisY/prepare-axis-data.js +11 -10
- package/dist/esm/components/AxisY/utils.d.ts +4 -2
- package/dist/esm/components/AxisY/utils.js +47 -23
- package/dist/esm/components/ChartInner/index.js +11 -5
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -1
- package/dist/esm/components/ChartInner/useChartInnerProps.js +3 -2
- package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
- package/dist/esm/components/Tooltip/ChartTooltipContent.js +2 -2
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +2 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +3 -3
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +4 -3
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +6 -9
- package/dist/esm/components/Tooltip/index.js +1 -1
- package/dist/esm/hooks/useAxisScales/index.d.ts +3 -4
- package/dist/esm/hooks/useAxisScales/index.js +82 -28
- package/dist/esm/hooks/useChartOptions/index.d.ts +3 -1
- package/dist/esm/hooks/useChartOptions/index.js +3 -3
- package/dist/esm/hooks/useChartOptions/tooltip.d.ts +4 -1
- package/dist/esm/hooks/useChartOptions/tooltip.js +18 -3
- package/dist/esm/hooks/useChartOptions/utils.d.ts +5 -2
- package/dist/esm/hooks/useChartOptions/utils.js +2 -3
- package/dist/esm/hooks/useChartOptions/x-axis.js +21 -9
- package/dist/esm/hooks/useChartOptions/y-axis.d.ts +1 -3
- package/dist/esm/hooks/useChartOptions/y-axis.js +23 -12
- package/dist/esm/hooks/useCrosshair/index.d.ts +1 -1
- package/dist/esm/hooks/useCrosshair/index.js +2 -1
- package/dist/esm/hooks/useSeries/prepare-bar-y.js +3 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.js +3 -0
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +1 -1
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +3 -0
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.d.ts +5 -3
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +46 -20
- package/dist/esm/hooks/useShapes/index.d.ts +1 -1
- package/dist/esm/hooks/useShapes/index.js +2 -0
- package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +1 -1
- package/dist/esm/hooks/useShapes/line/prepare-data.js +3 -0
- package/dist/esm/hooks/useShapes/scatter/prepare-data.d.ts +1 -1
- package/dist/esm/hooks/useShapes/scatter/prepare-data.js +6 -0
- package/dist/esm/hooks/useShapes/waterfall/prepare-data.d.ts +1 -1
- package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +6 -3
- package/dist/esm/hooks/useZoom/index.d.ts +1 -1
- package/dist/esm/hooks/useZoom/types.d.ts +1 -1
- package/dist/esm/hooks/useZoom/utils.d.ts +1 -1
- package/dist/esm/hooks/useZoom/utils.js +46 -18
- package/dist/esm/hooks/utils/bar-y.d.ts +7 -10
- package/dist/esm/hooks/utils/bar-y.js +33 -18
- package/dist/esm/types/chart/tooltip.d.ts +3 -0
- package/dist/esm/utils/chart/array.d.ts +1 -0
- package/dist/esm/utils/chart/array.js +12 -0
- package/dist/esm/utils/chart/format.js +2 -2
- package/dist/esm/utils/chart/index.d.ts +1 -0
- package/dist/esm/utils/chart/index.js +3 -1
- package/dist/esm/utils/chart/labels.d.ts +27 -5
- package/dist/esm/utils/chart/labels.js +39 -3
- package/dist/esm/utils/chart/zoom.js +14 -8
- package/package.json +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSeries, PreparedSplit } from '../../hooks';
|
|
2
2
|
import type { AxisYData } from './types';
|
|
3
|
-
export declare function prepareAxisData({ axis, split, scale, width, height, }: {
|
|
3
|
+
export declare function prepareAxisData({ axis, split, scale, top: topOffset, width, height, series, }: {
|
|
4
4
|
axis: PreparedAxis;
|
|
5
5
|
split: PreparedSplit;
|
|
6
6
|
scale: ChartScale;
|
|
7
|
+
top: number;
|
|
7
8
|
width: number;
|
|
8
9
|
height: number;
|
|
10
|
+
series: PreparedSeries[];
|
|
9
11
|
}): Promise<AxisYData>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getUniqId } from '@gravity-ui/uikit';
|
|
2
|
-
import { calculateCos, calculateSin,
|
|
2
|
+
import { calculateCos, calculateSin, formatAxisTickLabel, getBandsPosition, getLabelsSize, getMinSpaceBetween, getTextSizeFn, getTextWithElipsis, wrapText, } from '../../utils';
|
|
3
3
|
import { getTickValues } from './utils';
|
|
4
|
-
async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHeight, }) {
|
|
4
|
+
async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHeight, topOffset, }) {
|
|
5
5
|
var _a;
|
|
6
6
|
const originalTextSize = await getTextSize(text);
|
|
7
7
|
// Currently, a preliminary label calculation is used to build the chart - we cannot exceed it here.
|
|
@@ -17,7 +17,7 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHei
|
|
|
17
17
|
width: labelMaxWidth,
|
|
18
18
|
getTextSize,
|
|
19
19
|
});
|
|
20
|
-
let
|
|
20
|
+
let labelTopOffset = top;
|
|
21
21
|
let newLabelWidth = 0;
|
|
22
22
|
let newLabelHeight = 0;
|
|
23
23
|
for (let textRowIndex = 0; textRowIndex < textRows.length; textRowIndex++) {
|
|
@@ -49,10 +49,10 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHei
|
|
|
49
49
|
content.push({
|
|
50
50
|
text: rowText,
|
|
51
51
|
x,
|
|
52
|
-
y:
|
|
52
|
+
y: labelTopOffset,
|
|
53
53
|
size: textSize,
|
|
54
54
|
});
|
|
55
|
-
|
|
55
|
+
labelTopOffset += textSize.height;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
content.forEach((row) => {
|
|
@@ -68,7 +68,7 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHei
|
|
|
68
68
|
content.push({
|
|
69
69
|
text,
|
|
70
70
|
x,
|
|
71
|
-
y: Math.max(
|
|
71
|
+
y: Math.max(-topOffset, top - size.height / 2),
|
|
72
72
|
size,
|
|
73
73
|
});
|
|
74
74
|
}
|
|
@@ -81,7 +81,7 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHei
|
|
|
81
81
|
return svgLabel;
|
|
82
82
|
}
|
|
83
83
|
// eslint-disable-next-line complexity
|
|
84
|
-
export async function prepareAxisData({ axis, split, scale, width, height, }) {
|
|
84
|
+
export async function prepareAxisData({ axis, split, scale, top: topOffset, width, height, series, }) {
|
|
85
85
|
var _a, _b, _c;
|
|
86
86
|
const axisPlotTopPosition = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
|
|
87
87
|
const axisHeight = ((_b = split.plots[axis.plotIndex]) === null || _b === void 0 ? void 0 : _b.height) || height;
|
|
@@ -94,9 +94,9 @@ export async function prepareAxisData({ axis, split, scale, width, height, }) {
|
|
|
94
94
|
const ticks = [];
|
|
95
95
|
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
96
96
|
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
97
|
-
const values = getTickValues({ scale, axis, labelLineHeight });
|
|
97
|
+
const values = getTickValues({ scale, axis, labelLineHeight, series });
|
|
98
|
+
const tickStep = getMinSpaceBetween(values, (d) => Number(d.value));
|
|
98
99
|
const labelMaxHeight = values.length > 1 ? values[0].y - values[1].y - axis.labels.padding * 2 : axisHeight;
|
|
99
|
-
const labelFormatter = getLabelFormatter({ axis, scale });
|
|
100
100
|
for (let i = 0; i < values.length; i++) {
|
|
101
101
|
const tickValue = values[i];
|
|
102
102
|
const y = axisPlotTopPosition + tickValue.y;
|
|
@@ -125,7 +125,7 @@ export async function prepareAxisData({ axis, split, scale, width, height, }) {
|
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
else {
|
|
128
|
-
const text =
|
|
128
|
+
const text = formatAxisTickLabel({ value: tickValue.value, axis, step: tickStep });
|
|
129
129
|
svgLabel = await getSvgAxisLabel({
|
|
130
130
|
getTextSize,
|
|
131
131
|
text,
|
|
@@ -133,6 +133,7 @@ export async function prepareAxisData({ axis, split, scale, width, height, }) {
|
|
|
133
133
|
top: y,
|
|
134
134
|
left: domainX,
|
|
135
135
|
labelMaxHeight,
|
|
136
|
+
topOffset,
|
|
136
137
|
});
|
|
137
138
|
}
|
|
138
139
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis } from '../../hooks';
|
|
2
|
-
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSeries } from '../../hooks';
|
|
2
|
+
import type { ChartSeries } from '../../types';
|
|
3
|
+
export declare function getTickValues({ scale, axis, labelLineHeight, series, }: {
|
|
3
4
|
scale: ChartScale;
|
|
4
5
|
axis: PreparedAxis;
|
|
5
6
|
labelLineHeight: number;
|
|
7
|
+
series: PreparedSeries[] | ChartSeries[];
|
|
6
8
|
}): {
|
|
7
9
|
y: number;
|
|
8
10
|
value: number | Date;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getTicksCount, isBandScale } from '../../utils';
|
|
1
|
+
import { getDomainDataYBySeries, getMinSpaceBetween, getTicksCount, isBandScale } from '../../utils';
|
|
2
2
|
function thinOut(items, delta) {
|
|
3
3
|
const arr = [];
|
|
4
4
|
for (let i = 0; i < items.length; i = i + delta) {
|
|
@@ -6,39 +6,63 @@ function thinOut(items, delta) {
|
|
|
6
6
|
}
|
|
7
7
|
return arr;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
return arr.reduce((acc, item, index) => {
|
|
11
|
-
const prev = arr[index - 1];
|
|
12
|
-
if (prev) {
|
|
13
|
-
return Math.min(acc, Math.abs(iterator(prev) - iterator(item)));
|
|
14
|
-
}
|
|
15
|
-
return acc;
|
|
16
|
-
}, Infinity);
|
|
17
|
-
}
|
|
18
|
-
export function getTickValues({ scale, axis, labelLineHeight, }) {
|
|
9
|
+
export function getTickValues({ scale, axis, labelLineHeight, series, }) {
|
|
19
10
|
if ('ticks' in scale && typeof scale.ticks === 'function') {
|
|
20
11
|
const range = scale.range();
|
|
21
12
|
const height = Math.abs(range[0] - range[1]);
|
|
22
13
|
if (!height) {
|
|
23
14
|
return [];
|
|
24
15
|
}
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
const getScaleTicks = () => {
|
|
17
|
+
var _a;
|
|
18
|
+
if (series.some((s) => s.type === 'bar-y')) {
|
|
19
|
+
const domainData = getDomainDataYBySeries(series);
|
|
20
|
+
if (domainData.length < 3) {
|
|
21
|
+
return domainData;
|
|
22
|
+
}
|
|
23
|
+
const ticksCount = (_a = getTicksCount({ axis, range: height })) !== null && _a !== void 0 ? _a : domainData.length;
|
|
24
|
+
return scale.ticks(Math.min(ticksCount, domainData.length));
|
|
25
|
+
}
|
|
26
|
+
const ticksCount = getTicksCount({ axis, range: height });
|
|
27
|
+
return scale.ticks(ticksCount);
|
|
28
|
+
};
|
|
29
|
+
const scaleTicks = getScaleTicks();
|
|
30
|
+
const originalTickValues = scaleTicks.map((t) => ({
|
|
27
31
|
y: scale(t),
|
|
28
32
|
value: t,
|
|
29
33
|
}));
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
34
|
+
if (originalTickValues.length <= 1) {
|
|
35
|
+
return originalTickValues;
|
|
32
36
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
// first, we try to draw "beautiful" tick values
|
|
38
|
+
let result = originalTickValues;
|
|
39
|
+
let availableSpaceForLabel = getMinSpaceBetween(result, (d) => d.y) - axis.labels.padding * 2;
|
|
40
|
+
let ticksCount = result.length - 1;
|
|
41
|
+
while (availableSpaceForLabel < labelLineHeight && result.length > 1) {
|
|
36
42
|
ticksCount = ticksCount ? ticksCount - 1 : result.length - 1;
|
|
37
|
-
|
|
43
|
+
const newScaleTicks = scale.ticks(ticksCount);
|
|
44
|
+
result = newScaleTicks.map((t) => ({
|
|
38
45
|
y: scale(t),
|
|
39
46
|
value: t,
|
|
40
47
|
}));
|
|
41
|
-
|
|
48
|
+
availableSpaceForLabel =
|
|
49
|
+
getMinSpaceBetween(result, (d) => d.y) - axis.labels.padding * 2;
|
|
50
|
+
}
|
|
51
|
+
// when this is not possible (for example, such values cannot be selected for the logarithmic axis with a small range)
|
|
52
|
+
// just thin out the originally proposed result
|
|
53
|
+
if (!result.length) {
|
|
54
|
+
result = originalTickValues;
|
|
55
|
+
availableSpaceForLabel =
|
|
56
|
+
getMinSpaceBetween(result, (d) => d.y) - axis.labels.padding * 2;
|
|
57
|
+
let delta = 2;
|
|
58
|
+
while (availableSpaceForLabel < labelLineHeight && result.length > 1) {
|
|
59
|
+
result = thinOut(result, delta);
|
|
60
|
+
if (result.length > 1) {
|
|
61
|
+
delta += 1;
|
|
62
|
+
availableSpaceForLabel =
|
|
63
|
+
getMinSpaceBetween(result, (d) => d.y) - axis.labels.padding * 2;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
}
|
|
43
67
|
return result;
|
|
44
68
|
}
|
|
@@ -56,13 +80,13 @@ export function getTickValues({ scale, axis, labelLineHeight, }) {
|
|
|
56
80
|
return items;
|
|
57
81
|
}
|
|
58
82
|
let result = [...items];
|
|
59
|
-
let
|
|
83
|
+
let availableSpaceForLabel = Math.abs(result[0].y - result[1].y) - axis.labels.padding * 2;
|
|
60
84
|
let delta = 2;
|
|
61
|
-
while (
|
|
85
|
+
while (availableSpaceForLabel < labelLineHeight && result.length > 1) {
|
|
62
86
|
result = thinOut(items, delta);
|
|
63
87
|
if (result.length > 1) {
|
|
64
88
|
delta += 1;
|
|
65
|
-
|
|
89
|
+
availableSpaceForLabel = result[0].y - result[1].y - axis.labels.padding * 2;
|
|
66
90
|
}
|
|
67
91
|
}
|
|
68
92
|
return result;
|
|
@@ -96,9 +96,11 @@ export const ChartInner = (props) => {
|
|
|
96
96
|
const axisData = await prepareAxisData({
|
|
97
97
|
axis,
|
|
98
98
|
scale,
|
|
99
|
+
top: boundsOffsetTop,
|
|
99
100
|
width: boundsWidth,
|
|
100
101
|
height: boundsHeight,
|
|
101
102
|
split: preparedSplit,
|
|
103
|
+
series: preparedSeries,
|
|
102
104
|
});
|
|
103
105
|
items.push(axisData);
|
|
104
106
|
}
|
|
@@ -107,7 +109,7 @@ export const ChartInner = (props) => {
|
|
|
107
109
|
setYAxisDataItems(items);
|
|
108
110
|
}
|
|
109
111
|
})();
|
|
110
|
-
}, [boundsHeight, boundsWidth, preparedSplit, yAxis, yScale]);
|
|
112
|
+
}, [boundsHeight, boundsOffsetTop, boundsWidth, preparedSeries, preparedSplit, yAxis, yScale]);
|
|
111
113
|
return (React.createElement("div", { className: b() },
|
|
112
114
|
React.createElement("svg", { ref: svgRef, width: width, height: height,
|
|
113
115
|
// We use onPointerMove here because onMouseMove works incorrectly when the zoom setting is enabled:
|
|
@@ -121,10 +123,14 @@ export const ChartInner = (props) => {
|
|
|
121
123
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
122
124
|
})),
|
|
123
125
|
React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
|
|
124
|
-
xScale &&
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
xScale && xAxis && (React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
|
|
127
|
+
React.createElement(AxisX, { axis: xAxis, boundsOffsetLeft: boundsOffsetLeft, boundsOffsetTop: boundsOffsetTop, height: boundsHeight, htmlLayout: htmlLayout, leftmostLimit: svgXPos, plotAfterRef: plotAfterRef, plotBeforeRef: plotBeforeRef, scale: xScale, split: preparedSplit, width: boundsWidth }))),
|
|
128
|
+
Boolean(yAxisDataItems.length) && (React.createElement(React.Fragment, null, yAxisDataItems.map((axisData, index) => {
|
|
129
|
+
if (!axisData) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return (React.createElement(AxisY, { key: index, htmlLayout: htmlLayout, plotAfterRef: plotAfterRef, plotBeforeRef: plotBeforeRef, preparedAxisData: axisData }));
|
|
133
|
+
}))),
|
|
128
134
|
React.createElement("g", { ref: plotBeforeRef }),
|
|
129
135
|
shapes,
|
|
130
136
|
React.createElement("g", { ref: plotAfterRef })),
|
|
@@ -51,6 +51,6 @@ export declare function useChartInnerProps(props: Props): {
|
|
|
51
51
|
xAxis: PreparedAxis | null;
|
|
52
52
|
xScale: import("../../hooks").ChartScale | undefined;
|
|
53
53
|
yAxis: PreparedAxis[];
|
|
54
|
-
yScale: import("../../hooks").ChartScale[] | undefined;
|
|
54
|
+
yScale: (import("../../hooks").ChartScale | undefined)[] | undefined;
|
|
55
55
|
};
|
|
56
56
|
export {};
|
|
@@ -20,6 +20,8 @@ export function useChartInnerProps(props) {
|
|
|
20
20
|
colors: data.colors,
|
|
21
21
|
title: data.title,
|
|
22
22
|
tooltip: data.tooltip,
|
|
23
|
+
xAxis: data.xAxis,
|
|
24
|
+
yAxes: data.yAxis,
|
|
23
25
|
});
|
|
24
26
|
const preparedSeriesOptions = React.useMemo(() => {
|
|
25
27
|
return getPreparedOptions(data.series.options);
|
|
@@ -64,10 +66,9 @@ export function useChartInnerProps(props) {
|
|
|
64
66
|
boundsHeight: estimatedBoundsHeight,
|
|
65
67
|
width,
|
|
66
68
|
seriesData: zoomedSeriesData,
|
|
67
|
-
seriesOptions: preparedSeriesOptions,
|
|
68
69
|
yAxis: data.yAxis,
|
|
69
70
|
}).then((val) => setYAxis(val));
|
|
70
|
-
}, [data.yAxis, estimatedBoundsHeight, height,
|
|
71
|
+
}, [data.yAxis, estimatedBoundsHeight, height, width, zoomedSeriesData]);
|
|
71
72
|
const { preparedSeries, preparedLegend, handleLegendItemClick } = useSeries({
|
|
72
73
|
colors,
|
|
73
74
|
legend: data.legend,
|
|
@@ -2,10 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import isNil from 'lodash/isNil';
|
|
3
3
|
import { DefaultTooltipContent } from './DefaultTooltipContent';
|
|
4
4
|
export const ChartTooltipContent = (props) => {
|
|
5
|
-
const { hovered, xAxis, yAxis, renderer, rowRenderer, valueFormat, headerFormat, totals, pinned, } = props;
|
|
5
|
+
const { hovered, xAxis, yAxis, renderer, rowRenderer, valueFormat, headerFormat, totals, pinned, qa, } = props;
|
|
6
6
|
if (!hovered) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
9
9
|
const customTooltip = renderer === null || renderer === void 0 ? void 0 : renderer({ hovered, xAxis, yAxis });
|
|
10
|
-
return isNil(customTooltip) ? (React.createElement(DefaultTooltipContent, { hovered: hovered, pinned: pinned, rowRenderer: rowRenderer, totals: totals, valueFormat: valueFormat, headerFormat: headerFormat, xAxis: xAxis, yAxis: yAxis })) : (customTooltip);
|
|
10
|
+
return isNil(customTooltip) ? (React.createElement(DefaultTooltipContent, { hovered: hovered, pinned: pinned, rowRenderer: rowRenderer, totals: totals, valueFormat: valueFormat, headerFormat: headerFormat, xAxis: xAxis, yAxis: yAxis, qa: qa })) : (customTooltip);
|
|
11
11
|
};
|
|
@@ -9,6 +9,7 @@ type Props = {
|
|
|
9
9
|
headerFormat?: ChartTooltip['headerFormat'];
|
|
10
10
|
xAxis?: ChartXAxis | null;
|
|
11
11
|
yAxis?: ChartYAxis;
|
|
12
|
+
qa?: string;
|
|
12
13
|
};
|
|
13
|
-
export declare const DefaultTooltipContent: ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, }: Props) => React.JSX.Element;
|
|
14
|
+
export declare const DefaultTooltipContent: ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, qa, }: Props) => React.JSX.Element;
|
|
14
15
|
export {};
|
|
@@ -10,13 +10,13 @@ import { Row } from './Row';
|
|
|
10
10
|
import { RowWithAggregation } from './RowWithAggregation';
|
|
11
11
|
import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getXRowData, } from './utils';
|
|
12
12
|
const b = block('tooltip');
|
|
13
|
-
export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, }) => {
|
|
13
|
+
export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, qa, }) => {
|
|
14
14
|
var _a;
|
|
15
15
|
const [visibleRows, setVisibleRows] = React.useState();
|
|
16
16
|
const [maxContentRowsHeight, setMaxContentRowsHeight] = React.useState();
|
|
17
17
|
const [scrollBarWidth, setScrollBarWidth] = React.useState(0);
|
|
18
18
|
const contentRowsRef = React.useRef(null);
|
|
19
|
-
const measureValue = getMeasureValue({ data: hovered, xAxis, yAxis });
|
|
19
|
+
const measureValue = getMeasureValue({ data: hovered, xAxis, yAxis, headerFormat });
|
|
20
20
|
const hoveredValues = getHoveredValues({ hovered, xAxis, yAxis });
|
|
21
21
|
const prevHoveredValues = usePrevious(hoveredValues);
|
|
22
22
|
const visibleHovered = pinned || !visibleRows ? hovered : hovered.slice(0, visibleRows);
|
|
@@ -83,7 +83,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
|
|
|
83
83
|
setScrollBarWidth(0);
|
|
84
84
|
}
|
|
85
85
|
}, [pinned]);
|
|
86
|
-
return (React.createElement("div", { className: b('content') },
|
|
86
|
+
return (React.createElement("div", { className: b('content'), "data-qa": qa },
|
|
87
87
|
formattedHeadValue && (React.createElement("div", { className: b('series-name'), dangerouslySetInnerHTML: { __html: formattedHeadValue } })),
|
|
88
88
|
React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: { maxHeight: maxContentRowsHeight } },
|
|
89
89
|
visibleHovered.map((seriesItem, i) => {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { ChartSeriesData, ChartTooltip, ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
2
2
|
export type HoveredValue = string | number | null | undefined;
|
|
3
3
|
export declare function getXRowData(data: ChartSeriesData, xAxis?: ChartXAxis | null): string | number | undefined;
|
|
4
|
-
export declare function getDefaultValueFormat({ axis, }: {
|
|
4
|
+
export declare function getDefaultValueFormat({ axis, closestPointsRange, }: {
|
|
5
5
|
axis?: ChartXAxis | ChartYAxis | null;
|
|
6
|
+
closestPointsRange?: number;
|
|
6
7
|
}): ValueFormat | undefined;
|
|
7
|
-
export declare const getMeasureValue: ({ data, xAxis, yAxis,
|
|
8
|
+
export declare const getMeasureValue: ({ data, xAxis, yAxis, headerFormat, }: {
|
|
8
9
|
data: TooltipDataChunk[];
|
|
9
10
|
xAxis?: ChartXAxis | null;
|
|
10
11
|
yAxis?: ChartYAxis;
|
|
11
|
-
|
|
12
|
+
headerFormat?: ChartTooltip["headerFormat"];
|
|
12
13
|
}) => {
|
|
13
14
|
value: string | null;
|
|
14
15
|
formattedValue?: undefined;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import { DEFAULT_DATE_FORMAT } from '../../../constants';
|
|
3
2
|
import { i18n } from '../../../i18n';
|
|
4
|
-
import { getDataCategoryValue } from '../../../utils';
|
|
3
|
+
import { getDataCategoryValue, getDefaultDateFormat } from '../../../utils';
|
|
5
4
|
import { getFormattedValue } from '../../../utils/chart/format';
|
|
6
5
|
function getRowData(fieldName, data, axis) {
|
|
7
6
|
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
@@ -20,7 +19,7 @@ export function getXRowData(data, xAxis) {
|
|
|
20
19
|
function getYRowData(data, yAxis) {
|
|
21
20
|
return getRowData('y', data, yAxis);
|
|
22
21
|
}
|
|
23
|
-
export function getDefaultValueFormat({ axis, }) {
|
|
22
|
+
export function getDefaultValueFormat({ axis, closestPointsRange, }) {
|
|
24
23
|
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
25
24
|
case 'linear':
|
|
26
25
|
case 'logarithmic': {
|
|
@@ -31,14 +30,14 @@ export function getDefaultValueFormat({ axis, }) {
|
|
|
31
30
|
case 'datetime': {
|
|
32
31
|
return {
|
|
33
32
|
type: 'date',
|
|
34
|
-
format:
|
|
33
|
+
format: getDefaultDateFormat(closestPointsRange),
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
default:
|
|
38
37
|
return undefined;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
|
-
export const getMeasureValue = ({ data, xAxis, yAxis,
|
|
40
|
+
export const getMeasureValue = ({ data, xAxis, yAxis, headerFormat, }) => {
|
|
42
41
|
var _a, _b, _c, _d, _e, _f;
|
|
43
42
|
if (data.every((item) => ['pie', 'treemap', 'waterfall', 'sankey'].includes(item.series.type))) {
|
|
44
43
|
return null;
|
|
@@ -49,18 +48,16 @@ export const getMeasureValue = ({ data, xAxis, yAxis, valueFormat, }) => {
|
|
|
49
48
|
}
|
|
50
49
|
if (data.some((item) => item.series.type === 'bar-y')) {
|
|
51
50
|
const value = getYRowData((_c = data[0]) === null || _c === void 0 ? void 0 : _c.data, yAxis);
|
|
52
|
-
const format = valueFormat !== null && valueFormat !== void 0 ? valueFormat : getDefaultValueFormat({ axis: yAxis });
|
|
53
51
|
const formattedValue = getFormattedValue({
|
|
54
52
|
value: getYRowData((_d = data[0]) === null || _d === void 0 ? void 0 : _d.data, yAxis),
|
|
55
|
-
format,
|
|
53
|
+
format: headerFormat,
|
|
56
54
|
});
|
|
57
55
|
return { value, formattedValue };
|
|
58
56
|
}
|
|
59
57
|
const value = getXRowData((_e = data[0]) === null || _e === void 0 ? void 0 : _e.data, xAxis);
|
|
60
|
-
const format = valueFormat !== null && valueFormat !== void 0 ? valueFormat : getDefaultValueFormat({ axis: xAxis });
|
|
61
58
|
const formattedValue = getFormattedValue({
|
|
62
59
|
value: getXRowData((_f = data[0]) === null || _f === void 0 ? void 0 : _f.data, xAxis),
|
|
63
|
-
format,
|
|
60
|
+
format: headerFormat,
|
|
64
61
|
});
|
|
65
62
|
return { value, formattedValue };
|
|
66
63
|
};
|
|
@@ -23,5 +23,5 @@ export const Tooltip = (props) => {
|
|
|
23
23
|
}, [left, top]);
|
|
24
24
|
return (hovered === null || hovered === void 0 ? void 0 : hovered.length) ? (React.createElement(Popup, { anchorElement: anchor, className: b({ pinned: tooltipPinned }), disableTransition: true, floatingStyles: tooltipPinned ? undefined : { pointerEvents: 'none' }, offset: { mainAxis: 20 }, onOpenChange: tooltipPinned ? handleOnOpenChange : undefined, open: true, placement: ['right', 'left', 'top', 'bottom'] },
|
|
25
25
|
React.createElement("div", { className: b('popup-content') },
|
|
26
|
-
React.createElement(ChartTooltipContent, { hovered: hovered, pinned: tooltipPinned, renderer: tooltip.renderer, rowRenderer: tooltip.rowRenderer, totals: tooltip.totals, valueFormat: tooltip.valueFormat, headerFormat: tooltip.headerFormat, xAxis: xAxis, yAxis: yAxis })))) : null;
|
|
26
|
+
React.createElement(ChartTooltipContent, { hovered: hovered, pinned: tooltipPinned, renderer: tooltip.renderer, rowRenderer: tooltip.rowRenderer, totals: tooltip.totals, valueFormat: tooltip.valueFormat, headerFormat: tooltip.headerFormat, xAxis: xAxis, yAxis: yAxis, qa: tooltip.qa })))) : null;
|
|
27
27
|
};
|
|
@@ -17,21 +17,20 @@ type Args = {
|
|
|
17
17
|
};
|
|
18
18
|
type ReturnValue = {
|
|
19
19
|
xScale?: ChartScale;
|
|
20
|
-
yScale?: ChartScale[];
|
|
20
|
+
yScale?: (ChartScale | undefined)[];
|
|
21
21
|
};
|
|
22
22
|
export declare function createYScale(args: {
|
|
23
23
|
axis: PreparedAxis;
|
|
24
24
|
boundsHeight: number;
|
|
25
25
|
series: (PreparedSeries | ChartSeries)[];
|
|
26
|
-
|
|
27
|
-
}): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
|
|
26
|
+
}): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
|
|
28
27
|
export declare function createXScale(args: {
|
|
29
28
|
axis: PreparedAxis | ChartAxis;
|
|
30
29
|
boundsWidth: number;
|
|
31
30
|
series: (PreparedSeries | ChartSeries)[];
|
|
32
31
|
seriesOptions: PreparedSeriesOptions;
|
|
33
32
|
hasZoomX?: boolean;
|
|
34
|
-
}): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never
|
|
33
|
+
}): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
|
|
35
34
|
/**
|
|
36
35
|
* Uses to create scales for axis related series
|
|
37
36
|
*/
|
|
@@ -3,11 +3,26 @@ import { extent, scaleBand, scaleLinear, scaleLog, scaleUtc } from 'd3';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { DEFAULT_AXIS_TYPE, SeriesType } from '../../constants';
|
|
5
5
|
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDefaultMinXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
|
|
6
|
-
import {
|
|
6
|
+
import { getBandSize } from '../utils';
|
|
7
7
|
import { getBarXLayoutForNumericScale, groupBarXDataByXValue } from '../utils/bar-x';
|
|
8
8
|
const X_AXIS_ZOOM_PADDING = 0.02;
|
|
9
|
-
function
|
|
10
|
-
|
|
9
|
+
function validateArrayData(data) {
|
|
10
|
+
let hasNumberAndNullValues;
|
|
11
|
+
let hasOnlyNullValues;
|
|
12
|
+
for (const d of data) {
|
|
13
|
+
const isNumber = typeof d === 'number';
|
|
14
|
+
const isNull = d === null;
|
|
15
|
+
hasNumberAndNullValues =
|
|
16
|
+
typeof hasNumberAndNullValues === 'undefined'
|
|
17
|
+
? isNumber || isNull
|
|
18
|
+
: hasNumberAndNullValues && (isNumber || isNull);
|
|
19
|
+
hasOnlyNullValues =
|
|
20
|
+
typeof hasOnlyNullValues === 'undefined' ? isNull : hasOnlyNullValues && isNull;
|
|
21
|
+
if (!hasNumberAndNullValues) {
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { hasNumberAndNullValues, hasOnlyNullValues };
|
|
11
26
|
}
|
|
12
27
|
function filterCategoriesByVisibleSeries(args) {
|
|
13
28
|
const { axisDirection, categories, series } = args;
|
|
@@ -19,30 +34,18 @@ function filterCategoriesByVisibleSeries(args) {
|
|
|
19
34
|
});
|
|
20
35
|
}
|
|
21
36
|
});
|
|
22
|
-
|
|
37
|
+
const filteredCategories = categories.filter((c) => visibleCategories.has(c));
|
|
38
|
+
return filteredCategories.length > 0 ? filteredCategories : categories;
|
|
23
39
|
}
|
|
24
40
|
// axis is validated in `validation/index.ts`, so the value of `axis.type` is definitely valid.
|
|
25
41
|
// eslint-disable-next-line consistent-return
|
|
26
42
|
function getYScaleRange(args) {
|
|
27
|
-
const { axis, boundsHeight
|
|
43
|
+
const { axis, boundsHeight } = args;
|
|
28
44
|
switch (axis.type) {
|
|
29
45
|
case 'datetime':
|
|
30
46
|
case 'linear':
|
|
31
47
|
case 'logarithmic': {
|
|
32
|
-
|
|
33
|
-
const barYSeries = series.filter((s) => s.type === SeriesType.BarY);
|
|
34
|
-
if (barYSeries.length) {
|
|
35
|
-
const groupedData = groupBarYDataByYValue(barYSeries, [axis]);
|
|
36
|
-
if (Object.keys(groupedData).length > 1) {
|
|
37
|
-
const { bandSize } = getBarYLayoutForNumericScale({
|
|
38
|
-
plotHeight: boundsHeight - boundsHeight * axis.maxPadding,
|
|
39
|
-
groupedData,
|
|
40
|
-
seriesOptions: seriesOptions,
|
|
41
|
-
});
|
|
42
|
-
const offset = bandSize / 2;
|
|
43
|
-
range = [range[0] - offset, range[1] + offset];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
48
|
+
const range = [boundsHeight, 0];
|
|
46
49
|
switch (axis.order) {
|
|
47
50
|
case 'sortDesc':
|
|
48
51
|
case 'reverse': {
|
|
@@ -56,18 +59,23 @@ function getYScaleRange(args) {
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
}
|
|
62
|
+
// eslint-disable-next-line complexity
|
|
59
63
|
export function createYScale(args) {
|
|
60
|
-
const { axis, boundsHeight, series
|
|
64
|
+
const { axis, boundsHeight, series } = args;
|
|
61
65
|
const yMinProps = get(axis, 'min');
|
|
62
66
|
const yMaxProps = get(axis, 'max');
|
|
63
67
|
const yCategories = get(axis, 'categories');
|
|
64
68
|
const yTimestamps = get(axis, 'timestamps');
|
|
65
|
-
const range = getYScaleRange({ axis, boundsHeight
|
|
69
|
+
const range = getYScaleRange({ axis, boundsHeight });
|
|
66
70
|
switch (axis.type) {
|
|
67
71
|
case 'linear':
|
|
68
72
|
case 'logarithmic': {
|
|
69
73
|
const domain = getDomainDataYBySeries(series);
|
|
70
|
-
|
|
74
|
+
const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domain);
|
|
75
|
+
if (hasOnlyNullValues || domain.length === 0) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
if (hasNumberAndNullValues) {
|
|
71
79
|
const [yMinDomain, yMaxDomain] = extent(domain);
|
|
72
80
|
const yMin = typeof yMinProps === 'number' ? yMinProps : yMinDomain;
|
|
73
81
|
let yMax;
|
|
@@ -79,7 +87,23 @@ export function createYScale(args) {
|
|
|
79
87
|
yMax = hasSeriesWithVolumeOnYAxis ? Math.max(yMaxDomain, 0) : yMaxDomain;
|
|
80
88
|
}
|
|
81
89
|
const scaleFn = axis.type === 'logarithmic' ? scaleLog : scaleLinear;
|
|
82
|
-
|
|
90
|
+
const scale = scaleFn().domain([yMin, yMax]).range(range);
|
|
91
|
+
let offsetMin = 0;
|
|
92
|
+
let offsetMax = boundsHeight * axis.maxPadding;
|
|
93
|
+
const barYSeries = series.filter((s) => s.type === SeriesType.BarY);
|
|
94
|
+
if (barYSeries.length) {
|
|
95
|
+
if (domain.length > 1) {
|
|
96
|
+
const bandWidth = getBandSize({
|
|
97
|
+
scale: scale,
|
|
98
|
+
domain: domain,
|
|
99
|
+
});
|
|
100
|
+
offsetMin += bandWidth / 2;
|
|
101
|
+
offsetMax += bandWidth / 2;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
|
|
105
|
+
const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
|
|
106
|
+
return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
|
|
83
107
|
}
|
|
84
108
|
break;
|
|
85
109
|
}
|
|
@@ -103,11 +127,31 @@ export function createYScale(args) {
|
|
|
103
127
|
}
|
|
104
128
|
else {
|
|
105
129
|
const domain = getDomainDataYBySeries(series);
|
|
106
|
-
|
|
130
|
+
const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domain);
|
|
131
|
+
if (hasOnlyNullValues || domain.length === 0) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
if (hasNumberAndNullValues) {
|
|
107
135
|
const [yMinTimestamp, yMaxTimestamp] = extent(domain);
|
|
108
136
|
const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
|
|
109
137
|
const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
|
|
110
|
-
|
|
138
|
+
const scale = scaleUtc().domain([yMin, yMax]).range(range);
|
|
139
|
+
let offsetMin = 0;
|
|
140
|
+
let offsetMax = boundsHeight * axis.maxPadding;
|
|
141
|
+
const barYSeries = series.filter((s) => s.type === SeriesType.BarY);
|
|
142
|
+
if (barYSeries.length) {
|
|
143
|
+
if (Object.keys(domain).length > 1) {
|
|
144
|
+
const bandWidth = getBandSize({
|
|
145
|
+
scale: scale,
|
|
146
|
+
domain: domain,
|
|
147
|
+
});
|
|
148
|
+
offsetMin += bandWidth / 2;
|
|
149
|
+
offsetMax += bandWidth / 2;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
|
|
153
|
+
const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
|
|
154
|
+
return scale.domain([yMin - domainOffsetMin, yMax + domainOffsetMax]);
|
|
111
155
|
}
|
|
112
156
|
}
|
|
113
157
|
}
|
|
@@ -178,7 +222,14 @@ export function createXScale(args) {
|
|
|
178
222
|
case 'linear':
|
|
179
223
|
case 'logarithmic': {
|
|
180
224
|
const domainData = getDomainDataXBySeries(series);
|
|
181
|
-
|
|
225
|
+
const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domainData);
|
|
226
|
+
if (hasOnlyNullValues || domainData.length === 0) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
if (series.some((s) => s.stacking === 'percent')) {
|
|
230
|
+
return scaleLinear().domain([0, 100]).range(range);
|
|
231
|
+
}
|
|
232
|
+
if (hasNumberAndNullValues) {
|
|
182
233
|
const [xMinDomain, xMaxDomain] = extent(domainData);
|
|
183
234
|
let xMin;
|
|
184
235
|
let xMax;
|
|
@@ -227,7 +278,11 @@ export function createXScale(args) {
|
|
|
227
278
|
case 'datetime': {
|
|
228
279
|
let domain = null;
|
|
229
280
|
const domainData = get(axis, 'timestamps') || getDomainDataXBySeries(series);
|
|
230
|
-
|
|
281
|
+
const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domainData);
|
|
282
|
+
if (hasOnlyNullValues || domainData.length === 0) {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
if (hasNumberAndNullValues) {
|
|
231
286
|
const [xMinTimestamp, xMaxTimestamp] = extent(domainData);
|
|
232
287
|
const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
|
|
233
288
|
const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
|
|
@@ -271,7 +326,6 @@ const createScales = (args) => {
|
|
|
271
326
|
axis,
|
|
272
327
|
boundsHeight: axisHeight,
|
|
273
328
|
series: visibleAxisSeries.length ? visibleAxisSeries : axisSeries,
|
|
274
|
-
seriesOptions,
|
|
275
329
|
});
|
|
276
330
|
}),
|
|
277
331
|
};
|