@gravity-ui/charts 1.10.2 → 1.11.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/ChartInner/index.js +8 -3
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +2 -1
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +1 -5
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +2 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +9 -3
- package/dist/cjs/components/ChartInner/utils.d.ts +1 -1
- package/dist/cjs/components/ChartInner/utils.js +3 -3
- package/dist/cjs/hooks/hooks-utils/zoom.d.ts +1 -1
- package/dist/cjs/hooks/hooks-utils/zoom.js +2 -2
- package/dist/cjs/hooks/useAxisScales/index.js +49 -18
- package/dist/cjs/hooks/useChartOptions/x-axis.js +3 -14
- package/dist/cjs/hooks/useChartOptions/y-axis.js +5 -24
- package/dist/cjs/hooks/useShapes/area/index.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/area/index.js +13 -9
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -1
- package/dist/cjs/hooks/useShapes/area/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.js +2 -2
- package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-y/index.js +2 -2
- package/dist/cjs/hooks/useShapes/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/index.js +11 -6
- package/dist/cjs/hooks/useShapes/line/index.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/line/index.js +16 -12
- package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +2 -1
- package/dist/cjs/hooks/useShapes/line/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/marker.js +6 -0
- package/dist/cjs/hooks/useShapes/scatter/prepare-data.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/scatter/prepare-data.js +6 -3
- package/dist/cjs/hooks/useShapes/scatter/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/waterfall/index.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/waterfall/index.js +2 -2
- package/dist/cjs/hooks/useZoom/index.js +1 -1
- package/dist/cjs/hooks/useZoom/utils.d.ts +1 -1
- package/dist/cjs/hooks/useZoom/utils.js +3 -3
- package/dist/cjs/types/chart/axis.d.ts +4 -5
- package/dist/cjs/utils/chart/axis-generators/bottom.js +3 -1
- package/dist/cjs/utils/chart/index.d.ts +2 -0
- package/dist/cjs/utils/chart/index.js +31 -0
- package/dist/esm/components/ChartInner/index.js +8 -3
- package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +2 -1
- package/dist/esm/components/ChartInner/useChartInnerHandlers.js +1 -5
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +2 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +9 -3
- package/dist/esm/components/ChartInner/utils.d.ts +1 -1
- package/dist/esm/components/ChartInner/utils.js +3 -3
- package/dist/esm/hooks/hooks-utils/zoom.d.ts +1 -1
- package/dist/esm/hooks/hooks-utils/zoom.js +2 -2
- package/dist/esm/hooks/useAxisScales/index.js +49 -18
- package/dist/esm/hooks/useChartOptions/x-axis.js +3 -14
- package/dist/esm/hooks/useChartOptions/y-axis.js +5 -24
- package/dist/esm/hooks/useShapes/area/index.d.ts +1 -0
- package/dist/esm/hooks/useShapes/area/index.js +13 -9
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -1
- package/dist/esm/hooks/useShapes/area/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-x/index.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-x/index.js +2 -2
- package/dist/esm/hooks/useShapes/bar-y/index.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-y/index.js +2 -2
- package/dist/esm/hooks/useShapes/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/index.js +11 -6
- package/dist/esm/hooks/useShapes/line/index.d.ts +1 -0
- package/dist/esm/hooks/useShapes/line/index.js +16 -12
- package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +1 -0
- package/dist/esm/hooks/useShapes/line/prepare-data.js +2 -1
- package/dist/esm/hooks/useShapes/line/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/marker.js +6 -0
- package/dist/esm/hooks/useShapes/scatter/prepare-data.d.ts +1 -0
- package/dist/esm/hooks/useShapes/scatter/prepare-data.js +6 -3
- package/dist/esm/hooks/useShapes/scatter/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/waterfall/index.d.ts +1 -0
- package/dist/esm/hooks/useShapes/waterfall/index.js +2 -2
- package/dist/esm/hooks/useZoom/index.js +1 -1
- package/dist/esm/hooks/useZoom/utils.d.ts +1 -1
- package/dist/esm/hooks/useZoom/utils.js +3 -3
- package/dist/esm/types/chart/axis.d.ts +4 -5
- package/dist/esm/utils/chart/axis-generators/bottom.js +3 -1
- package/dist/esm/utils/chart/index.d.ts +2 -0
- package/dist/esm/utils/chart/index.js +31 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { extent, scaleBand, scaleLinear, scaleLog, scaleUtc } from 'd3';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { DEFAULT_AXIS_TYPE } from '../../constants';
|
|
5
|
-
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
|
|
5
|
+
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDefaultMinXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
|
|
6
6
|
const isNumericalArrayData = (data) => {
|
|
7
7
|
return data.every((d) => typeof d === 'number' || d === null);
|
|
8
8
|
};
|
|
@@ -20,7 +20,8 @@ const filterCategoriesByVisibleSeries = (args) => {
|
|
|
20
20
|
};
|
|
21
21
|
export function createYScale(axis, series, boundsHeight) {
|
|
22
22
|
const yType = get(axis, 'type', DEFAULT_AXIS_TYPE);
|
|
23
|
-
const
|
|
23
|
+
const yMinProps = get(axis, 'min');
|
|
24
|
+
const yMaxProps = get(axis, 'max');
|
|
24
25
|
const yCategories = get(axis, 'categories');
|
|
25
26
|
const yTimestamps = get(axis, 'timestamps');
|
|
26
27
|
switch (yType) {
|
|
@@ -29,14 +30,18 @@ export function createYScale(axis, series, boundsHeight) {
|
|
|
29
30
|
const domain = getDomainDataYBySeries(series);
|
|
30
31
|
const range = [boundsHeight, boundsHeight * axis.maxPadding];
|
|
31
32
|
if (isNumericalArrayData(domain)) {
|
|
32
|
-
const [
|
|
33
|
-
const
|
|
34
|
-
let
|
|
35
|
-
if (
|
|
36
|
-
|
|
33
|
+
const [yMinDomain, yMaxDomain] = extent(domain);
|
|
34
|
+
const yMin = typeof yMinProps === 'number' ? yMinProps : yMinDomain;
|
|
35
|
+
let yMax;
|
|
36
|
+
if (typeof yMaxProps === 'number') {
|
|
37
|
+
yMax = yMaxProps;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const hasSeriesWithVolumeOnYAxis = series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type));
|
|
41
|
+
yMax = hasSeriesWithVolumeOnYAxis ? Math.max(yMaxDomain, 0) : yMaxDomain;
|
|
37
42
|
}
|
|
38
43
|
const scaleFn = yType === 'logarithmic' ? scaleLog : scaleLinear;
|
|
39
|
-
return scaleFn().domain([
|
|
44
|
+
return scaleFn().domain([yMin, yMax]).range(range).nice();
|
|
40
45
|
}
|
|
41
46
|
break;
|
|
42
47
|
}
|
|
@@ -54,13 +59,17 @@ export function createYScale(axis, series, boundsHeight) {
|
|
|
54
59
|
case 'datetime': {
|
|
55
60
|
const range = [boundsHeight, boundsHeight * axis.maxPadding];
|
|
56
61
|
if (yTimestamps) {
|
|
57
|
-
const [
|
|
62
|
+
const [yMinTimestamp, yMaxTimestamp] = extent(yTimestamps);
|
|
63
|
+
const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
|
|
64
|
+
const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
|
|
58
65
|
return scaleUtc().domain([yMin, yMax]).range(range).nice();
|
|
59
66
|
}
|
|
60
67
|
else {
|
|
61
68
|
const domain = getDomainDataYBySeries(series);
|
|
62
69
|
if (isNumericalArrayData(domain)) {
|
|
63
|
-
const [
|
|
70
|
+
const [yMinTimestamp, yMaxTimestamp] = extent(domain);
|
|
71
|
+
const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
|
|
72
|
+
const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
|
|
64
73
|
return scaleUtc().domain([yMin, yMax]).range(range).nice();
|
|
65
74
|
}
|
|
66
75
|
}
|
|
@@ -86,9 +95,10 @@ function calculateXAxisPadding(series) {
|
|
|
86
95
|
});
|
|
87
96
|
return result;
|
|
88
97
|
}
|
|
98
|
+
// eslint-disable-next-line complexity
|
|
89
99
|
export function createXScale(axis, series, boundsWidth, hasZoomX) {
|
|
90
|
-
const
|
|
91
|
-
const
|
|
100
|
+
const xMinProps = get(axis, 'min');
|
|
101
|
+
const xMaxProps = get(axis, 'max');
|
|
92
102
|
const xType = get(axis, 'type', DEFAULT_AXIS_TYPE);
|
|
93
103
|
const xCategories = get(axis, 'categories');
|
|
94
104
|
const xTimestamps = get(axis, 'timestamps');
|
|
@@ -100,11 +110,28 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
|
|
|
100
110
|
case 'logarithmic': {
|
|
101
111
|
const domain = getDomainDataXBySeries(series);
|
|
102
112
|
if (isNumericalArrayData(domain)) {
|
|
103
|
-
const [
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
const [xMinDomain, xMaxDomain] = extent(domain);
|
|
114
|
+
let xMin;
|
|
115
|
+
let xMax;
|
|
116
|
+
if (typeof xMinProps === 'number') {
|
|
117
|
+
xMin = xMinProps;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const xMinDefault = getDefaultMinXAxisValue(series);
|
|
121
|
+
xMin = xMinDefault !== null && xMinDefault !== void 0 ? xMinDefault : xMinDomain;
|
|
122
|
+
}
|
|
123
|
+
if (typeof xMaxProps === 'number') {
|
|
124
|
+
xMax = xMaxProps;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const xMaxDefault = getDefaultMaxXAxisValue(series);
|
|
128
|
+
xMax =
|
|
129
|
+
typeof xMaxDefault === 'number'
|
|
130
|
+
? Math.max(xMaxDefault, xMaxDomain)
|
|
131
|
+
: xMaxDomain;
|
|
132
|
+
}
|
|
106
133
|
const scaleFn = xType === 'logarithmic' ? scaleLog : scaleLinear;
|
|
107
|
-
const scale = scaleFn().domain([
|
|
134
|
+
const scale = scaleFn().domain([xMin, xMax]).range(xRange);
|
|
108
135
|
if (!hasZoomX) {
|
|
109
136
|
scale.nice();
|
|
110
137
|
}
|
|
@@ -129,7 +156,9 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
|
|
|
129
156
|
}
|
|
130
157
|
case 'datetime': {
|
|
131
158
|
if (xTimestamps) {
|
|
132
|
-
const [
|
|
159
|
+
const [xMinTimestamp, xMaxTimestamp] = extent(xTimestamps);
|
|
160
|
+
const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
|
|
161
|
+
const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
|
|
133
162
|
const scale = scaleUtc().domain([xMin, xMax]).range(xRange);
|
|
134
163
|
if (!hasZoomX) {
|
|
135
164
|
scale.nice();
|
|
@@ -139,7 +168,9 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
|
|
|
139
168
|
else {
|
|
140
169
|
const domain = getDomainDataXBySeries(series);
|
|
141
170
|
if (isNumericalArrayData(domain)) {
|
|
142
|
-
const [
|
|
171
|
+
const [xMinTimestamp, xMaxTimestamp] = extent(domain);
|
|
172
|
+
const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
|
|
173
|
+
const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
|
|
143
174
|
const scale = scaleUtc().domain([xMin, xMax]).range(xRange);
|
|
144
175
|
if (!hasZoomX) {
|
|
145
176
|
scale.nice();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, axisCrosshairDefaults, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
|
|
3
|
-
import {
|
|
3
|
+
import { calculateCos, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, getXAxisItems, hasOverlappingLabels, wrapText, } from '../../utils';
|
|
4
4
|
import { createXScale } from '../useAxisScales';
|
|
5
5
|
async function getLabelSettings({ axis, seriesData, width, autoRotation = true, }) {
|
|
6
6
|
const scale = createXScale(axis, seriesData, width);
|
|
@@ -36,18 +36,6 @@ async function getLabelSettings({ axis, seriesData, width, autoRotation = true,
|
|
|
36
36
|
const maxHeight = rotation ? calculateCos(rotation) * axis.labels.maxWidth : labelsHeight;
|
|
37
37
|
return { height: Math.min(maxHeight, labelsHeight), rotation };
|
|
38
38
|
}
|
|
39
|
-
function getAxisMin(axis, series) {
|
|
40
|
-
const min = axis === null || axis === void 0 ? void 0 : axis.min;
|
|
41
|
-
if (typeof min === 'undefined' &&
|
|
42
|
-
(series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_X_AXIS.includes(s.type)))) {
|
|
43
|
-
return series.reduce((minValue, s) => {
|
|
44
|
-
// @ts-expect-error
|
|
45
|
-
const minYValue = s.data.reduce((res, d) => Math.min(res, get(d, 'x', 0)), 0);
|
|
46
|
-
return Math.min(minValue, minYValue);
|
|
47
|
-
}, 0);
|
|
48
|
-
}
|
|
49
|
-
return min;
|
|
50
|
-
}
|
|
51
39
|
export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
|
|
52
40
|
var _a;
|
|
53
41
|
const titleText = get(xAxis, 'title.text', '');
|
|
@@ -92,7 +80,8 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
|
|
|
92
80
|
align: get(xAxis, 'title.align', xAxisTitleDefaults.align),
|
|
93
81
|
maxRowCount: get(xAxis, 'title.maxRowCount', xAxisTitleDefaults.maxRowCount),
|
|
94
82
|
},
|
|
95
|
-
min:
|
|
83
|
+
min: get(xAxis, 'min'),
|
|
84
|
+
max: get(xAxis, 'max'),
|
|
96
85
|
maxPadding: get(xAxis, 'maxPadding', 0.01),
|
|
97
86
|
grid: {
|
|
98
87
|
enabled: get(xAxis, 'grid.enabled', true),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisCrosshairDefaults, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
3
|
-
import {
|
|
3
|
+
import { formatAxisTickLabel, getClosestPointsRange, getDefaultMinYAxisValue, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, isAxisRelatedSeries, wrapText, } from '../../utils';
|
|
4
4
|
import { createYScale } from '../useAxisScales';
|
|
5
5
|
const getAxisLabelMaxWidth = async (args) => {
|
|
6
6
|
const { axis, seriesData } = args;
|
|
@@ -23,26 +23,6 @@ const getAxisLabelMaxWidth = async (args) => {
|
|
|
23
23
|
});
|
|
24
24
|
return size.maxWidth;
|
|
25
25
|
};
|
|
26
|
-
function getAxisMin(axis, seriesData) {
|
|
27
|
-
const min = axis === null || axis === void 0 ? void 0 : axis.min;
|
|
28
|
-
if (typeof min === 'undefined' &&
|
|
29
|
-
(seriesData === null || seriesData === void 0 ? void 0 : seriesData.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type)))) {
|
|
30
|
-
return seriesData.reduce((minValue, s) => {
|
|
31
|
-
switch (s.type) {
|
|
32
|
-
case 'waterfall': {
|
|
33
|
-
const minSubTotal = s.data.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, s) || 0), 0);
|
|
34
|
-
return Math.min(minValue, minSubTotal);
|
|
35
|
-
}
|
|
36
|
-
default: {
|
|
37
|
-
// @ts-expect-error
|
|
38
|
-
const minYValue = s.data.reduce((res, d) => Math.min(res, get(d, 'y', 0)), 0);
|
|
39
|
-
return Math.min(minValue, minYValue);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}, 0);
|
|
43
|
-
}
|
|
44
|
-
return min;
|
|
45
|
-
}
|
|
46
26
|
export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
|
|
47
27
|
const axisByPlot = [];
|
|
48
28
|
const axisItems = yAxis || [{}];
|
|
@@ -51,7 +31,7 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
|
|
|
51
31
|
return Promise.resolve([]);
|
|
52
32
|
}
|
|
53
33
|
return Promise.all(axisItems.map(async (axisItem) => {
|
|
54
|
-
var _a;
|
|
34
|
+
var _a, _b;
|
|
55
35
|
const plotIndex = get(axisItem, 'plotIndex', 0);
|
|
56
36
|
const firstPlotAxis = !axisByPlot[plotIndex];
|
|
57
37
|
if (firstPlotAxis) {
|
|
@@ -104,11 +84,12 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
|
|
|
104
84
|
align: get(axisItem, 'title.align', yAxisTitleDefaults.align),
|
|
105
85
|
maxRowCount: titleMaxRowsCount,
|
|
106
86
|
},
|
|
107
|
-
min:
|
|
87
|
+
min: (_a = get(axisItem, 'min')) !== null && _a !== void 0 ? _a : getDefaultMinYAxisValue(seriesData),
|
|
88
|
+
max: get(axisItem, 'max'),
|
|
108
89
|
maxPadding: get(axisItem, 'maxPadding', 0.05),
|
|
109
90
|
grid: {
|
|
110
91
|
enabled: get(axisItem, 'grid.enabled', firstPlotAxis ||
|
|
111
|
-
(!firstPlotAxis && !((
|
|
92
|
+
(!firstPlotAxis && !((_b = axisByPlot[plotIndex][0].visible) !== null && _b !== void 0 ? _b : true))),
|
|
112
93
|
},
|
|
113
94
|
ticks: {
|
|
114
95
|
pixelInterval: get(axisItem, 'ticks.pixelInterval'),
|
|
@@ -7,22 +7,25 @@ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarke
|
|
|
7
7
|
import { setActiveState } from '../utils';
|
|
8
8
|
const b = block('area');
|
|
9
9
|
export const AreaSeriesShapes = (args) => {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
11
11
|
const hoveredDataRef = React.useRef(null);
|
|
12
|
-
const
|
|
12
|
+
const plotRef = React.useRef(null);
|
|
13
|
+
const markersRef = React.useRef(null);
|
|
13
14
|
React.useEffect(() => {
|
|
14
15
|
var _a;
|
|
15
|
-
if (!
|
|
16
|
+
if (!plotRef.current || !markersRef.current) {
|
|
16
17
|
return () => { };
|
|
17
18
|
}
|
|
18
|
-
const
|
|
19
|
+
const plotSvgElement = select(plotRef.current);
|
|
20
|
+
const markersSvgElement = select(markersRef.current);
|
|
19
21
|
const hoverOptions = get(seriesOptions, 'area.states.hover');
|
|
20
22
|
const inactiveOptions = get(seriesOptions, 'area.states.inactive');
|
|
21
23
|
const line = lineGenerator()
|
|
22
24
|
.x((d) => d.x)
|
|
23
25
|
.y((d) => d.y);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
plotSvgElement.selectAll('*').remove();
|
|
27
|
+
markersSvgElement.selectAll('*').remove();
|
|
28
|
+
const shapeSelection = plotSvgElement
|
|
26
29
|
.selectAll('shape')
|
|
27
30
|
.data(preparedData)
|
|
28
31
|
.join('g')
|
|
@@ -53,7 +56,7 @@ export const AreaSeriesShapes = (args) => {
|
|
|
53
56
|
if (!((_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
|
|
54
57
|
dataLabels = filterOverlappingLabels(dataLabels);
|
|
55
58
|
}
|
|
56
|
-
const labelsSelection =
|
|
59
|
+
const labelsSelection = plotSvgElement
|
|
57
60
|
.selectAll('text')
|
|
58
61
|
.data(dataLabels)
|
|
59
62
|
.join('text')
|
|
@@ -66,7 +69,7 @@ export const AreaSeriesShapes = (args) => {
|
|
|
66
69
|
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
67
70
|
.style('fill', (d) => d.style.fontColor || null);
|
|
68
71
|
const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
|
|
69
|
-
const markerSelection =
|
|
72
|
+
const markerSelection = markersSvgElement
|
|
70
73
|
.selectAll('marker')
|
|
71
74
|
.data(markers)
|
|
72
75
|
.join('g')
|
|
@@ -144,6 +147,7 @@ export const AreaSeriesShapes = (args) => {
|
|
|
144
147
|
};
|
|
145
148
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
146
149
|
return (React.createElement(React.Fragment, null,
|
|
147
|
-
React.createElement("g", { ref:
|
|
150
|
+
React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
151
|
+
React.createElement("g", { ref: markersRef }),
|
|
148
152
|
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
149
153
|
};
|
|
@@ -53,7 +53,7 @@ function getXValues(series, xAxis, xScale) {
|
|
|
53
53
|
return sort(Array.from(xValues), ([_x, xValue]) => xValue);
|
|
54
54
|
}
|
|
55
55
|
export const prepareAreaData = async (args) => {
|
|
56
|
-
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight } = args;
|
|
56
|
+
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, isOutsideBounds } = args;
|
|
57
57
|
const [_xMin, xRangeMax] = xScale.range();
|
|
58
58
|
const xMax = xRangeMax / (1 - xAxis.maxPadding);
|
|
59
59
|
const result = [];
|
|
@@ -142,6 +142,7 @@ export const prepareAreaData = async (args) => {
|
|
|
142
142
|
point: p,
|
|
143
143
|
active: true,
|
|
144
144
|
hovered: false,
|
|
145
|
+
clipped: isOutsideBounds(p.x, p.y),
|
|
145
146
|
}));
|
|
146
147
|
}
|
|
147
148
|
seriesStackData.push({
|
|
@@ -8,7 +8,7 @@ export { prepareBarXData } from './prepare-data';
|
|
|
8
8
|
export * from './types';
|
|
9
9
|
const b = block('bar-x');
|
|
10
10
|
export const BarXSeriesShapes = (args) => {
|
|
11
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
12
12
|
const hoveredDataRef = React.useRef(null);
|
|
13
13
|
const ref = React.useRef(null);
|
|
14
14
|
React.useEffect(() => {
|
|
@@ -110,6 +110,6 @@ export const BarXSeriesShapes = (args) => {
|
|
|
110
110
|
};
|
|
111
111
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
112
112
|
return (React.createElement(React.Fragment, null,
|
|
113
|
-
React.createElement("g", { ref: ref, className: b() }),
|
|
113
|
+
React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
114
114
|
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
115
115
|
};
|
|
@@ -7,7 +7,7 @@ import { getRectPath } from '../utils';
|
|
|
7
7
|
export { prepareBarYData } from './prepare-data';
|
|
8
8
|
const b = block('bar-y');
|
|
9
9
|
export const BarYSeriesShapes = (args) => {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
11
11
|
const hoveredDataRef = React.useRef(null);
|
|
12
12
|
const ref = React.useRef(null);
|
|
13
13
|
React.useEffect(() => {
|
|
@@ -99,6 +99,6 @@ export const BarYSeriesShapes = (args) => {
|
|
|
99
99
|
};
|
|
100
100
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
101
101
|
return (React.createElement(React.Fragment, null,
|
|
102
|
-
React.createElement("g", { ref: ref, className: b() }),
|
|
102
|
+
React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
103
103
|
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
104
104
|
};
|
|
@@ -28,6 +28,8 @@ type Args = {
|
|
|
28
28
|
yScale?: ChartScale[];
|
|
29
29
|
split: PreparedSplit;
|
|
30
30
|
htmlLayout: HTMLElement | null;
|
|
31
|
+
clipPathId: string;
|
|
32
|
+
isOutsideBounds: (x: number, y: number) => boolean;
|
|
31
33
|
};
|
|
32
34
|
export declare const useShapes: (args: Args) => {
|
|
33
35
|
shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
|
|
@@ -20,7 +20,7 @@ import { prepareTreemapData } from './treemap/prepare-data';
|
|
|
20
20
|
import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
|
|
21
21
|
import './styles.css';
|
|
22
22
|
export const useShapes = (args) => {
|
|
23
|
-
const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, } = args;
|
|
23
|
+
const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, clipPathId, isOutsideBounds, } = args;
|
|
24
24
|
const [shapesElemens, setShapesElements] = React.useState([]);
|
|
25
25
|
const [shapesElemensData, setShapesElemensData] = React.useState([]);
|
|
26
26
|
const setShapes = React.useCallback(async () => {
|
|
@@ -44,7 +44,7 @@ export const useShapes = (args) => {
|
|
|
44
44
|
yScale,
|
|
45
45
|
boundsHeight,
|
|
46
46
|
});
|
|
47
|
-
shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
47
|
+
shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
48
48
|
shapesData.push(...preparedData);
|
|
49
49
|
}
|
|
50
50
|
break;
|
|
@@ -59,7 +59,7 @@ export const useShapes = (args) => {
|
|
|
59
59
|
yAxis,
|
|
60
60
|
yScale,
|
|
61
61
|
});
|
|
62
|
-
shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
62
|
+
shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
63
63
|
shapesData.push(...preparedData);
|
|
64
64
|
}
|
|
65
65
|
break;
|
|
@@ -74,7 +74,7 @@ export const useShapes = (args) => {
|
|
|
74
74
|
yAxis,
|
|
75
75
|
yScale,
|
|
76
76
|
});
|
|
77
|
-
shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
77
|
+
shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
78
78
|
shapesData.push(...preparedData);
|
|
79
79
|
}
|
|
80
80
|
break;
|
|
@@ -88,8 +88,9 @@ export const useShapes = (args) => {
|
|
|
88
88
|
yAxis,
|
|
89
89
|
yScale,
|
|
90
90
|
split,
|
|
91
|
+
isOutsideBounds,
|
|
91
92
|
});
|
|
92
|
-
shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
93
|
+
shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
93
94
|
shapesData.push(...preparedData);
|
|
94
95
|
}
|
|
95
96
|
break;
|
|
@@ -103,8 +104,9 @@ export const useShapes = (args) => {
|
|
|
103
104
|
yAxis,
|
|
104
105
|
yScale,
|
|
105
106
|
boundsHeight,
|
|
107
|
+
isOutsideBounds,
|
|
106
108
|
});
|
|
107
|
-
shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
109
|
+
shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
108
110
|
shapesData.push(...preparedData);
|
|
109
111
|
}
|
|
110
112
|
break;
|
|
@@ -117,6 +119,7 @@ export const useShapes = (args) => {
|
|
|
117
119
|
xScale,
|
|
118
120
|
yAxis,
|
|
119
121
|
yScale,
|
|
122
|
+
isOutsideBounds,
|
|
120
123
|
});
|
|
121
124
|
shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
122
125
|
shapesData.push(...preparedData);
|
|
@@ -186,6 +189,8 @@ export const useShapes = (args) => {
|
|
|
186
189
|
xScale,
|
|
187
190
|
yAxis,
|
|
188
191
|
yScale,
|
|
192
|
+
clipPathId,
|
|
193
|
+
isOutsideBounds,
|
|
189
194
|
]);
|
|
190
195
|
React.useEffect(() => {
|
|
191
196
|
setShapes();
|
|
@@ -7,22 +7,25 @@ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarke
|
|
|
7
7
|
import { setActiveState } from '../utils';
|
|
8
8
|
const b = block('line');
|
|
9
9
|
export const LineSeriesShapes = (args) => {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
11
11
|
const hoveredDataRef = React.useRef(null);
|
|
12
|
-
const
|
|
12
|
+
const plotRef = React.useRef(null);
|
|
13
|
+
const markersRef = React.useRef(null);
|
|
13
14
|
React.useEffect(() => {
|
|
14
15
|
var _a;
|
|
15
|
-
if (!
|
|
16
|
+
if (!plotRef.current || !markersRef.current) {
|
|
16
17
|
return () => { };
|
|
17
18
|
}
|
|
18
|
-
const
|
|
19
|
+
const plotSvgElement = select(plotRef.current);
|
|
20
|
+
const markersSvgElement = select(markersRef.current);
|
|
19
21
|
const hoverOptions = get(seriesOptions, 'line.states.hover');
|
|
20
22
|
const inactiveOptions = get(seriesOptions, 'line.states.inactive');
|
|
21
23
|
const line = lineGenerator()
|
|
22
24
|
.x((d) => d.x)
|
|
23
25
|
.y((d) => d.y);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
plotSvgElement.selectAll('*').remove();
|
|
27
|
+
markersSvgElement.selectAll('*').remove();
|
|
28
|
+
const lineSelection = plotSvgElement
|
|
26
29
|
.selectAll('path')
|
|
27
30
|
.data(preparedData)
|
|
28
31
|
.join('path')
|
|
@@ -41,7 +44,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
41
44
|
if (!((_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
|
|
42
45
|
dataLabels = filterOverlappingLabels(dataLabels);
|
|
43
46
|
}
|
|
44
|
-
const labelsSelection =
|
|
47
|
+
const labelsSelection = plotSvgElement
|
|
45
48
|
.selectAll('text')
|
|
46
49
|
.data(dataLabels)
|
|
47
50
|
.join('text')
|
|
@@ -54,7 +57,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
54
57
|
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
55
58
|
.style('fill', (d) => d.style.fontColor || null);
|
|
56
59
|
const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
|
|
57
|
-
const markerSelection =
|
|
60
|
+
const markerSelection = markersSvgElement
|
|
58
61
|
.selectAll('marker')
|
|
59
62
|
.data(markers)
|
|
60
63
|
.join('g')
|
|
@@ -71,10 +74,10 @@ export const LineSeriesShapes = (args) => {
|
|
|
71
74
|
const hovered = Boolean(hoverEnabled && selectedSeriesIds.includes(d.id));
|
|
72
75
|
if (d.hovered !== hovered) {
|
|
73
76
|
d.hovered = hovered;
|
|
74
|
-
elementSelection.attr('stroke', (
|
|
77
|
+
elementSelection.attr('stroke', (dSelection) => {
|
|
75
78
|
var _a;
|
|
76
|
-
const initialColor =
|
|
77
|
-
if (
|
|
79
|
+
const initialColor = dSelection.color || '';
|
|
80
|
+
if (dSelection.hovered) {
|
|
78
81
|
return (((_a = color(initialColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness).toString()) || initialColor);
|
|
79
82
|
}
|
|
80
83
|
return initialColor;
|
|
@@ -131,6 +134,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
131
134
|
};
|
|
132
135
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
133
136
|
return (React.createElement(React.Fragment, null,
|
|
134
|
-
React.createElement("g", { ref:
|
|
137
|
+
React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
138
|
+
React.createElement("g", { ref: markersRef }),
|
|
135
139
|
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
136
140
|
};
|
|
@@ -40,7 +40,7 @@ async function getHtmlLabel(point, series, xMax) {
|
|
|
40
40
|
}
|
|
41
41
|
export const prepareLineData = async (args) => {
|
|
42
42
|
var _a;
|
|
43
|
-
const { series, xAxis, yAxis, xScale, yScale, split } = args;
|
|
43
|
+
const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds } = args;
|
|
44
44
|
const [_xMin, xRangeMax] = xScale.range();
|
|
45
45
|
const xMax = xRangeMax / (1 - xAxis.maxPadding);
|
|
46
46
|
const acc = [];
|
|
@@ -74,6 +74,7 @@ export const prepareLineData = async (args) => {
|
|
|
74
74
|
point: p,
|
|
75
75
|
active: true,
|
|
76
76
|
hovered: false,
|
|
77
|
+
clipped: isOutsideBounds(p.x, p.y),
|
|
77
78
|
}));
|
|
78
79
|
}
|
|
79
80
|
const result = {
|
|
@@ -16,6 +16,9 @@ export function renderMarker(selection) {
|
|
|
16
16
|
.append('path')
|
|
17
17
|
.attr('class', haloClassName)
|
|
18
18
|
.attr('d', (d) => {
|
|
19
|
+
if ('clipped' in d && d.clipped) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
19
22
|
const series = d.point.series;
|
|
20
23
|
const type = series.marker.states.normal.symbol;
|
|
21
24
|
const radius = get(d.point.data, 'radius', series.marker.states.hover.radius);
|
|
@@ -53,6 +56,9 @@ export function getMarkerHaloVisibility(d) {
|
|
|
53
56
|
export function setMarker(selection, state) {
|
|
54
57
|
selection
|
|
55
58
|
.attr('d', (d) => {
|
|
59
|
+
if ('clipped' in d && d.clipped) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
56
62
|
const series = d.point.series;
|
|
57
63
|
const type = series.marker.states.normal.symbol;
|
|
58
64
|
const radius = get(d.point.data, 'radius', series.marker.states[state].radius);
|
|
@@ -4,7 +4,7 @@ const getFilteredLinearScatterData = (data) => {
|
|
|
4
4
|
return data.filter((d) => typeof d.x === 'number' && typeof d.y === 'number');
|
|
5
5
|
};
|
|
6
6
|
export const prepareScatterData = (args) => {
|
|
7
|
-
const { series, xAxis, xScale, yAxis, yScale } = args;
|
|
7
|
+
const { series, xAxis, xScale, yAxis, yScale, isOutsideBounds } = args;
|
|
8
8
|
return series.reduce((acc, s) => {
|
|
9
9
|
const yAxisIndex = get(s, 'yAxis', 0);
|
|
10
10
|
const seriesYAxis = yAxis[yAxisIndex];
|
|
@@ -14,18 +14,21 @@ export const prepareScatterData = (args) => {
|
|
|
14
14
|
: getFilteredLinearScatterData(s.data);
|
|
15
15
|
filteredData.forEach((d) => {
|
|
16
16
|
var _a;
|
|
17
|
+
const x = getXValue({ point: d, xAxis, xScale });
|
|
18
|
+
const y = getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale });
|
|
17
19
|
acc.push({
|
|
18
20
|
point: {
|
|
19
21
|
data: d,
|
|
20
22
|
series: s,
|
|
21
|
-
x
|
|
22
|
-
y
|
|
23
|
+
x,
|
|
24
|
+
y,
|
|
23
25
|
opacity: get(d, 'opacity', null),
|
|
24
26
|
color: (_a = d.color) !== null && _a !== void 0 ? _a : s.color,
|
|
25
27
|
},
|
|
26
28
|
hovered: false,
|
|
27
29
|
active: true,
|
|
28
30
|
htmlElements: [],
|
|
31
|
+
clipped: isOutsideBounds(x, y),
|
|
29
32
|
});
|
|
30
33
|
});
|
|
31
34
|
return acc;
|