@gravity-ui/charts 1.34.0 → 1.34.2
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/AxisX/prepare-axis-data.d.ts +6 -5
- package/dist/cjs/components/AxisX/prepare-axis-data.js +2 -2
- package/dist/cjs/components/AxisY/utils.js +3 -3
- package/dist/cjs/components/ChartInner/index.js +23 -10
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +3 -1
- package/dist/cjs/components/RangeSlider/index.js +1 -0
- package/dist/cjs/hooks/useAxis/x-axis.js +1 -1
- package/dist/cjs/hooks/useBrush/index.js +24 -5
- package/dist/cjs/hooks/useBrush/types.d.ts +1 -0
- package/dist/cjs/hooks/useBrush/utils.d.ts +4 -0
- package/dist/cjs/hooks/useBrush/utils.js +4 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +85 -25
- package/dist/cjs/hooks/useShapes/index.d.ts +3 -0
- package/dist/cjs/hooks/useShapes/index.js +40 -27
- package/dist/cjs/hooks/useShapes/utils.d.ts +10 -0
- package/dist/cjs/hooks/useShapes/utils.js +15 -0
- package/dist/cjs/setup-jsdom.d.ts +0 -0
- package/dist/cjs/setup-jsdom.js +19 -0
- package/dist/cjs/utils/chart/axis/common.d.ts +2 -2
- package/dist/cjs/utils/chart/axis/common.js +2 -2
- package/dist/cjs/utils/chart/axis/x-axis.d.ts +11 -10
- package/dist/cjs/utils/chart/axis/x-axis.js +24 -3
- package/dist/cjs/utils/chart/index.d.ts +2 -29
- package/dist/cjs/utils/chart/index.js +2 -19
- package/dist/cjs/utils/chart/series-type-guards.d.ts +30 -0
- package/dist/cjs/utils/chart/series-type-guards.js +19 -0
- package/dist/esm/components/AxisX/prepare-axis-data.d.ts +6 -5
- package/dist/esm/components/AxisX/prepare-axis-data.js +2 -2
- package/dist/esm/components/AxisY/utils.js +3 -3
- package/dist/esm/components/ChartInner/index.js +23 -10
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +3 -1
- package/dist/esm/components/RangeSlider/index.js +1 -0
- package/dist/esm/hooks/useAxis/x-axis.js +1 -1
- package/dist/esm/hooks/useBrush/index.js +24 -5
- package/dist/esm/hooks/useBrush/types.d.ts +1 -0
- package/dist/esm/hooks/useBrush/utils.d.ts +4 -0
- package/dist/esm/hooks/useBrush/utils.js +4 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.js +85 -25
- package/dist/esm/hooks/useShapes/index.d.ts +3 -0
- package/dist/esm/hooks/useShapes/index.js +40 -27
- package/dist/esm/hooks/useShapes/utils.d.ts +10 -0
- package/dist/esm/hooks/useShapes/utils.js +15 -0
- package/dist/esm/setup-jsdom.d.ts +0 -0
- package/dist/esm/setup-jsdom.js +19 -0
- package/dist/esm/utils/chart/axis/common.d.ts +2 -2
- package/dist/esm/utils/chart/axis/common.js +2 -2
- package/dist/esm/utils/chart/axis/x-axis.d.ts +11 -10
- package/dist/esm/utils/chart/axis/x-axis.js +24 -3
- package/dist/esm/utils/chart/index.d.ts +2 -29
- package/dist/esm/utils/chart/index.js +2 -19
- package/dist/esm/utils/chart/series-type-guards.d.ts +30 -0
- package/dist/esm/utils/chart/series-type-guards.js +19 -0
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSeries, PreparedSplit } from '../../hooks';
|
|
2
2
|
import type { AxisXData } from './types';
|
|
3
|
-
export declare function prepareXAxisData({ axis,
|
|
3
|
+
export declare function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRight, boundsWidth, height, scale, series, split, yAxis, }: {
|
|
4
4
|
axis: PreparedAxis;
|
|
5
|
-
yAxis: PreparedAxis[];
|
|
6
|
-
scale: ChartScale;
|
|
7
|
-
boundsWidth: number;
|
|
8
5
|
boundsOffsetLeft: number;
|
|
9
6
|
boundsOffsetRight: number;
|
|
7
|
+
boundsWidth: number;
|
|
10
8
|
height: number;
|
|
9
|
+
scale: ChartScale;
|
|
10
|
+
series: PreparedSeries[];
|
|
11
11
|
split: PreparedSplit;
|
|
12
|
+
yAxis: PreparedAxis[];
|
|
12
13
|
}): Promise<AxisXData[]>;
|
|
@@ -68,7 +68,7 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
|
|
|
68
68
|
return svgLabel;
|
|
69
69
|
}
|
|
70
70
|
// eslint-disable-next-line complexity
|
|
71
|
-
export async function prepareXAxisData({ axis,
|
|
71
|
+
export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRight, boundsWidth, height, scale, series, split, yAxis, }) {
|
|
72
72
|
var _a, _b, _c, _d, _e, _f;
|
|
73
73
|
const xAxisItems = [];
|
|
74
74
|
for (let plotIndex = 0; plotIndex < split.plots.length; plotIndex++) {
|
|
@@ -95,7 +95,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
|
|
|
95
95
|
const ticks = [];
|
|
96
96
|
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
97
97
|
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
98
|
-
const values = getXAxisTickValues({ scale, axis, labelLineHeight });
|
|
98
|
+
const values = getXAxisTickValues({ scale, axis, labelLineHeight, series });
|
|
99
99
|
const tickStep = getMinSpaceBetween(values, (d) => Number(d.value));
|
|
100
100
|
const labelMaxWidth = values.length > 1
|
|
101
101
|
? Math.abs(values[0].x - values[1].x) - axis.labels.padding * 2
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDomainDataYBySeries, getMinSpaceBetween,
|
|
1
|
+
import { getDomainDataYBySeries, getMinSpaceBetween, getTicksCountByPixelInterval, isBandScale, thinOut, } from '../../utils';
|
|
2
2
|
export function getTickValues({ scale, axis, labelLineHeight, series, }) {
|
|
3
3
|
if ('ticks' in scale && typeof scale.ticks === 'function') {
|
|
4
4
|
const range = scale.range();
|
|
@@ -13,10 +13,10 @@ export function getTickValues({ scale, axis, labelLineHeight, series, }) {
|
|
|
13
13
|
if (domainData.length < 3) {
|
|
14
14
|
return domainData;
|
|
15
15
|
}
|
|
16
|
-
const ticksCount = (_a =
|
|
16
|
+
const ticksCount = (_a = getTicksCountByPixelInterval({ axis, axisWidth: height })) !== null && _a !== void 0 ? _a : domainData.length;
|
|
17
17
|
return scale.ticks(Math.min(ticksCount, domainData.length));
|
|
18
18
|
}
|
|
19
|
-
const ticksCount =
|
|
19
|
+
const ticksCount = getTicksCountByPixelInterval({ axis, axisWidth: height });
|
|
20
20
|
return scale.ticks(ticksCount);
|
|
21
21
|
};
|
|
22
22
|
const scaleTicks = getScaleTicks();
|
|
@@ -6,6 +6,7 @@ import { getPreparedRangeSlider } from '../../hooks/useAxis/range-slider';
|
|
|
6
6
|
import { getPreparedChart } from '../../hooks/useChartOptions/chart';
|
|
7
7
|
import { getPreparedTitle } from '../../hooks/useChartOptions/title';
|
|
8
8
|
import { getPreparedTooltip } from '../../hooks/useChartOptions/tooltip';
|
|
9
|
+
import { getClipPathIdByBounds } from '../../hooks/useShapes/utils';
|
|
9
10
|
import { EventType, block, getDispatcher, isBandScale } from '../../utils';
|
|
10
11
|
import { AxisX } from '../AxisX/AxisX';
|
|
11
12
|
import { prepareXAxisData } from '../AxisX/prepare-axis-data';
|
|
@@ -63,7 +64,7 @@ export const ChartInner = (props) => {
|
|
|
63
64
|
preparedRangeSlider,
|
|
64
65
|
tooltip: preparedTooltip,
|
|
65
66
|
});
|
|
66
|
-
const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, isOutsideBounds, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, prevHeight, prevWidth, shapes, shapesData, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
67
|
+
const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, isOutsideBounds, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, prevHeight, prevWidth, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
67
68
|
dispatcher,
|
|
68
69
|
htmlLayout, plotNode: plotRef.current, preparedChart, rangeSliderDomain: (_a = rangeSliderRef.current) === null || _a === void 0 ? void 0 : _a.getDomain(), rangeSliderState, svgContainer: svgRef.current, updateZoomState,
|
|
69
70
|
zoomState }));
|
|
@@ -159,18 +160,29 @@ export const ChartInner = (props) => {
|
|
|
159
160
|
if (axis && scale) {
|
|
160
161
|
const axisData = await prepareXAxisData({
|
|
161
162
|
axis,
|
|
162
|
-
yAxis,
|
|
163
|
-
scale,
|
|
164
|
-
boundsWidth,
|
|
165
163
|
boundsOffsetLeft: boundsOffsetLeft,
|
|
166
164
|
boundsOffsetRight: width - boundsWidth - boundsOffsetLeft,
|
|
165
|
+
boundsWidth,
|
|
167
166
|
height: boundsHeight,
|
|
167
|
+
scale,
|
|
168
|
+
series: preparedSeries.filter((s) => s.visible),
|
|
168
169
|
split: preparedSplit,
|
|
170
|
+
yAxis,
|
|
169
171
|
});
|
|
170
172
|
items.push(...axisData);
|
|
171
173
|
}
|
|
172
174
|
return items;
|
|
173
|
-
}, [
|
|
175
|
+
}, [
|
|
176
|
+
boundsHeight,
|
|
177
|
+
boundsOffsetLeft,
|
|
178
|
+
boundsWidth,
|
|
179
|
+
preparedSeries,
|
|
180
|
+
preparedSplit,
|
|
181
|
+
width,
|
|
182
|
+
xAxis,
|
|
183
|
+
xScale,
|
|
184
|
+
yAxis,
|
|
185
|
+
]);
|
|
174
186
|
const xAxisDataItems = useAsyncState([], setXAxisDataItems);
|
|
175
187
|
React.useEffect(() => {
|
|
176
188
|
if (!initialized && xScale) {
|
|
@@ -206,16 +218,17 @@ export const ChartInner = (props) => {
|
|
|
206
218
|
updateRangeSliderState,
|
|
207
219
|
xScale,
|
|
208
220
|
]);
|
|
209
|
-
const areShapesReady = shapes.length > 0;
|
|
210
221
|
React.useEffect(() => {
|
|
211
|
-
if (
|
|
222
|
+
if (shapesReady) {
|
|
212
223
|
onReady === null || onReady === void 0 ? void 0 : onReady({ dimensions: { width, height } });
|
|
213
224
|
}
|
|
214
|
-
}, [height,
|
|
225
|
+
}, [height, shapesReady, onReady, width]);
|
|
215
226
|
const chartContent = (React.createElement(React.Fragment, null,
|
|
216
227
|
React.createElement("defs", null,
|
|
217
|
-
React.createElement("clipPath", { id: clipPathId },
|
|
218
|
-
React.createElement("rect", { x: 0, y: 0, width: boundsWidth, height: boundsHeight }))
|
|
228
|
+
React.createElement("clipPath", { id: getClipPathIdByBounds({ clipPathId }) },
|
|
229
|
+
React.createElement("rect", { x: 0, y: 0, width: boundsWidth, height: boundsHeight })),
|
|
230
|
+
React.createElement("clipPath", { id: getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' }) },
|
|
231
|
+
React.createElement("rect", { x: 0, y: -boundsHeight, width: boundsWidth, height: boundsHeight * 3 }))),
|
|
219
232
|
preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle, { chartWidth: width })),
|
|
220
233
|
React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit.plots.map((plot, index) => {
|
|
221
234
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
@@ -44,6 +44,7 @@ export declare function useChartInnerProps(props: Props): {
|
|
|
44
44
|
prevWidth: number | undefined;
|
|
45
45
|
shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
|
|
46
46
|
shapesData: import("../../hooks").ShapeData[];
|
|
47
|
+
shapesReady: boolean;
|
|
47
48
|
svgXPos: number | undefined;
|
|
48
49
|
xAxis: import("../../hooks").PreparedXAxis | null;
|
|
49
50
|
xScale: import("../../hooks").ChartScale | undefined;
|
|
@@ -111,7 +111,7 @@ export function useChartInnerProps(props) {
|
|
|
111
111
|
const isOutsideBounds = React.useCallback((x, y) => {
|
|
112
112
|
return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
|
|
113
113
|
}, [boundsHeight, boundsWidth]);
|
|
114
|
-
const { shapes, shapesData } = useShapes({
|
|
114
|
+
const { shapes, shapesData, shapesReady } = useShapes({
|
|
115
115
|
boundsWidth,
|
|
116
116
|
boundsHeight,
|
|
117
117
|
clipPathBySeriesType: CLIP_PATH_BY_SERIES_TYPE,
|
|
@@ -126,6 +126,7 @@ export function useChartInnerProps(props) {
|
|
|
126
126
|
htmlLayout,
|
|
127
127
|
clipPathId,
|
|
128
128
|
isOutsideBounds,
|
|
129
|
+
zoomState,
|
|
129
130
|
});
|
|
130
131
|
const handleAttemptToSetZoomState = React.useCallback((nextZoomState) => {
|
|
131
132
|
const { preparedSeries: nextZoomedSeriesData } = getZoomedSeriesData({
|
|
@@ -182,6 +183,7 @@ export function useChartInnerProps(props) {
|
|
|
182
183
|
prevWidth,
|
|
183
184
|
shapes,
|
|
184
185
|
shapesData,
|
|
186
|
+
shapesReady,
|
|
185
187
|
svgXPos: x,
|
|
186
188
|
xAxis,
|
|
187
189
|
xScale,
|
|
@@ -15,7 +15,7 @@ async function setLabelSettings({ axis, seriesData, width, axisLabels, }) {
|
|
|
15
15
|
}
|
|
16
16
|
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
17
17
|
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
18
|
-
const tickValues = getXAxisTickValues({ axis, scale, labelLineHeight });
|
|
18
|
+
const tickValues = getXAxisTickValues({ axis, scale, labelLineHeight, series: seriesData });
|
|
19
19
|
const tickStep = getMinSpaceBetween(tickValues, (d) => Number(d.value));
|
|
20
20
|
if (axis.type === 'datetime' && !(axisLabels === null || axisLabels === void 0 ? void 0 : axisLabels.dateFormat)) {
|
|
21
21
|
axis.labels.dateFormat = getDefaultDateFormat(tickStep);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { brush, brushX, brushY, select } from 'd3';
|
|
2
|
+
import { brush, brushX, brushY, pointer, select } from 'd3';
|
|
3
3
|
import { block } from '../../utils';
|
|
4
|
-
import { getNormalizedSelection, setBrushBorder, setBrushHandles } from './utils';
|
|
4
|
+
import { getDefaultSelection, getNormalizedSelection, setBrushBorder, setBrushHandles, } from './utils';
|
|
5
5
|
import './styles.css';
|
|
6
6
|
const b = block('brush');
|
|
7
7
|
export function useBrush(props) {
|
|
8
|
-
const { areas, brushOptions, disabled, node, selection, type, onBrushStart, onBrush, onBrushEnd, } = props;
|
|
8
|
+
const { areas, brushOptions, disabled, node, preventNullSelection = false, selection, type, onBrushStart, onBrush, onBrushEnd, } = props;
|
|
9
9
|
React.useEffect(() => {
|
|
10
10
|
if (!node || !areas.length || disabled) {
|
|
11
11
|
return () => { };
|
|
@@ -103,7 +103,15 @@ export function useBrush(props) {
|
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
if (event.sourceEvent) {
|
|
106
|
-
|
|
106
|
+
let resultSelection = event.selection;
|
|
107
|
+
if (preventNullSelection && !resultSelection) {
|
|
108
|
+
const [pointerPositionX] = pointer(event, this);
|
|
109
|
+
resultSelection = getDefaultSelection({
|
|
110
|
+
brushWidth,
|
|
111
|
+
pointerPositionX,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
onBrushEnd === null || onBrushEnd === void 0 ? void 0 : onBrushEnd.call(this, instance, resultSelection);
|
|
107
115
|
}
|
|
108
116
|
});
|
|
109
117
|
groupSelection.call(instance);
|
|
@@ -129,5 +137,16 @@ export function useBrush(props) {
|
|
|
129
137
|
groupSelection === null || groupSelection === void 0 ? void 0 : groupSelection.remove();
|
|
130
138
|
});
|
|
131
139
|
};
|
|
132
|
-
}, [
|
|
140
|
+
}, [
|
|
141
|
+
areas,
|
|
142
|
+
brushOptions,
|
|
143
|
+
disabled,
|
|
144
|
+
node,
|
|
145
|
+
preventNullSelection,
|
|
146
|
+
selection,
|
|
147
|
+
type,
|
|
148
|
+
onBrushStart,
|
|
149
|
+
onBrush,
|
|
150
|
+
onBrushEnd,
|
|
151
|
+
]);
|
|
133
152
|
}
|
|
@@ -15,6 +15,7 @@ export interface BrushArea {
|
|
|
15
15
|
export interface UseBrushProps {
|
|
16
16
|
areas: BrushArea[];
|
|
17
17
|
node: SVGGElement | null;
|
|
18
|
+
preventNullSelection?: boolean;
|
|
18
19
|
brushOptions?: DeepRequired<ChartBrush>;
|
|
19
20
|
disabled?: boolean;
|
|
20
21
|
onBrush?: (this: SVGGElement, brushInstance: BrushBehavior<unknown>, selection: BrushSelection) => void;
|
|
@@ -17,3 +17,7 @@ export declare function getNormalizedSelection(args: {
|
|
|
17
17
|
selection: BrushSelection;
|
|
18
18
|
width: number;
|
|
19
19
|
}): [number, number] | [[number, number], [number, number]];
|
|
20
|
+
export declare function getDefaultSelection(args: {
|
|
21
|
+
brushWidth: number;
|
|
22
|
+
pointerPositionX: number;
|
|
23
|
+
}): BrushSelection;
|
|
@@ -170,3 +170,7 @@ export function getNormalizedSelection(args) {
|
|
|
170
170
|
}
|
|
171
171
|
return resultSelection;
|
|
172
172
|
}
|
|
173
|
+
export function getDefaultSelection(args) {
|
|
174
|
+
const { brushWidth, pointerPositionX } = args;
|
|
175
|
+
return pointerPositionX < 0 ? [0, 1] : [brushWidth - 1, brushWidth];
|
|
176
|
+
}
|
|
@@ -94,11 +94,13 @@ export const prepareAreaData = async (args) => {
|
|
|
94
94
|
const positiveStackValues = new Map();
|
|
95
95
|
const negativeStackValues = new Map();
|
|
96
96
|
xValues.forEach(([key]) => {
|
|
97
|
-
positiveStackValues.set(key, 0);
|
|
98
|
-
negativeStackValues.set(key, 0);
|
|
97
|
+
positiveStackValues.set(key, { prev: 0, next: 0 });
|
|
98
|
+
negativeStackValues.set(key, { prev: 0, next: 0 });
|
|
99
99
|
});
|
|
100
100
|
const seriesStackData = [];
|
|
101
|
-
|
|
101
|
+
// Process series in reverse order so that the first series in input
|
|
102
|
+
// appears at the top of the stack (furthest from baseline)
|
|
103
|
+
for (let j = seriesStack.length - 1; j >= 0; j--) {
|
|
102
104
|
const s = seriesStack[j];
|
|
103
105
|
const yAxisIndex = s.yAxis;
|
|
104
106
|
const seriesYAxis = yAxis[yAxisIndex];
|
|
@@ -123,40 +125,97 @@ export const prepareAreaData = async (args) => {
|
|
|
123
125
|
: d.x);
|
|
124
126
|
return m.set(key, d);
|
|
125
127
|
}, new Map());
|
|
126
|
-
const points = xValues.reduce((pointsAcc, [x, xValue]) => {
|
|
127
|
-
var _a, _b;
|
|
128
|
+
const points = xValues.reduce((pointsAcc, [x, xValue], index) => {
|
|
129
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
128
130
|
const d = (_a = seriesData.get(x)) !== null && _a !== void 0 ? _a : {
|
|
129
131
|
x,
|
|
130
132
|
y: 0,
|
|
131
133
|
};
|
|
132
134
|
const yDataValue = (_b = d.y) !== null && _b !== void 0 ? _b : null;
|
|
135
|
+
if (s.nullMode === 'connect' && yDataValue === null) {
|
|
136
|
+
return pointsAcc;
|
|
137
|
+
}
|
|
133
138
|
const yValue = getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale });
|
|
134
|
-
let y = null;
|
|
135
|
-
let y0 = yAxisTop + yMin;
|
|
136
139
|
if (typeof yDataValue === 'number' && yValue !== null) {
|
|
140
|
+
const prevPoint = seriesData.get((_c = xValues[index - 1]) === null || _c === void 0 ? void 0 : _c[0]);
|
|
141
|
+
const nextPoint = seriesData.get((_d = xValues[index + 1]) === null || _d === void 0 ? void 0 : _d[0]);
|
|
142
|
+
const currentPointStackHeight = Math.abs(yMin - yValue);
|
|
137
143
|
if (yDataValue >= 0) {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
const positiveStackHeights = positiveStackValues.get(x);
|
|
145
|
+
let prevSectionStackHeight = (_e = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.prev) !== null && _e !== void 0 ? _e : 0;
|
|
146
|
+
let nextSectionStackHeight = (_f = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.next) !== null && _f !== void 0 ? _f : 0;
|
|
147
|
+
pointsAcc.push({
|
|
148
|
+
y0: yAxisTop + yMin - prevSectionStackHeight,
|
|
149
|
+
x: xValue,
|
|
150
|
+
y: yAxisTop + yValue - prevSectionStackHeight,
|
|
151
|
+
data: d,
|
|
152
|
+
series: s,
|
|
153
|
+
});
|
|
154
|
+
if (prevSectionStackHeight !== nextSectionStackHeight) {
|
|
155
|
+
pointsAcc.push({
|
|
156
|
+
y0: yAxisTop + yMin - nextSectionStackHeight,
|
|
157
|
+
x: xValue,
|
|
158
|
+
y: yAxisTop + yValue - nextSectionStackHeight,
|
|
159
|
+
data: d,
|
|
160
|
+
series: s,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null) {
|
|
164
|
+
prevSectionStackHeight =
|
|
165
|
+
prevSectionStackHeight + currentPointStackHeight;
|
|
166
|
+
}
|
|
167
|
+
if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null) {
|
|
168
|
+
nextSectionStackHeight =
|
|
169
|
+
nextSectionStackHeight + currentPointStackHeight;
|
|
170
|
+
}
|
|
171
|
+
positiveStackValues.set(x, {
|
|
172
|
+
prev: prevSectionStackHeight,
|
|
173
|
+
next: nextSectionStackHeight,
|
|
174
|
+
});
|
|
142
175
|
}
|
|
143
176
|
else {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
177
|
+
const negativeStackHeights = negativeStackValues.get(x);
|
|
178
|
+
let prevSectionStackHeight = (_g = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.prev) !== null && _g !== void 0 ? _g : 0;
|
|
179
|
+
let nextSectionStackHeight = (_h = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.next) !== null && _h !== void 0 ? _h : 0;
|
|
180
|
+
pointsAcc.push({
|
|
181
|
+
y0: yAxisTop + yMin + prevSectionStackHeight,
|
|
182
|
+
x: xValue,
|
|
183
|
+
y: yAxisTop + yValue + prevSectionStackHeight,
|
|
184
|
+
data: d,
|
|
185
|
+
series: s,
|
|
186
|
+
});
|
|
187
|
+
if (prevSectionStackHeight !== nextSectionStackHeight) {
|
|
188
|
+
pointsAcc.push({
|
|
189
|
+
y0: yAxisTop + yMin + nextSectionStackHeight,
|
|
190
|
+
x: xValue,
|
|
191
|
+
y: yAxisTop + yValue + nextSectionStackHeight,
|
|
192
|
+
data: d,
|
|
193
|
+
series: s,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null) {
|
|
197
|
+
prevSectionStackHeight =
|
|
198
|
+
prevSectionStackHeight + currentPointStackHeight;
|
|
199
|
+
}
|
|
200
|
+
if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null) {
|
|
201
|
+
nextSectionStackHeight =
|
|
202
|
+
nextSectionStackHeight + currentPointStackHeight;
|
|
203
|
+
}
|
|
204
|
+
negativeStackValues.set(x, {
|
|
205
|
+
prev: prevSectionStackHeight,
|
|
206
|
+
next: nextSectionStackHeight,
|
|
207
|
+
});
|
|
148
208
|
}
|
|
149
209
|
}
|
|
150
|
-
|
|
151
|
-
|
|
210
|
+
else {
|
|
211
|
+
pointsAcc.push({
|
|
212
|
+
y0: yAxisTop + yMin,
|
|
213
|
+
x: xValue,
|
|
214
|
+
y: null,
|
|
215
|
+
data: d,
|
|
216
|
+
series: s,
|
|
217
|
+
});
|
|
152
218
|
}
|
|
153
|
-
pointsAcc.push({
|
|
154
|
-
y0,
|
|
155
|
-
x: xValue,
|
|
156
|
-
y,
|
|
157
|
-
data: d,
|
|
158
|
-
series: s,
|
|
159
|
-
});
|
|
160
219
|
return pointsAcc;
|
|
161
220
|
}, []);
|
|
162
221
|
const labels = [];
|
|
@@ -197,7 +256,8 @@ export const prepareAreaData = async (args) => {
|
|
|
197
256
|
}
|
|
198
257
|
if (series.some((s) => s.stacking === 'percent')) {
|
|
199
258
|
xValues.forEach(([x], index) => {
|
|
200
|
-
|
|
259
|
+
var _a;
|
|
260
|
+
const stackHeight = ((_a = positiveStackValues.get(x)) === null || _a === void 0 ? void 0 : _a.prev) || 0;
|
|
201
261
|
let acc = 0;
|
|
202
262
|
const ratio = plotHeight / stackHeight;
|
|
203
263
|
seriesStackData.forEach((item) => {
|
|
@@ -5,6 +5,7 @@ import type { PreparedXAxis, PreparedYAxis } from '../useAxis/types';
|
|
|
5
5
|
import type { ChartScale } from '../useAxisScales/types';
|
|
6
6
|
import type { PreparedSeries, PreparedSeriesOptions } from '../useSeries/types';
|
|
7
7
|
import type { PreparedSplit } from '../useSplit/types';
|
|
8
|
+
import type { ZoomState } from '../useZoom/types';
|
|
8
9
|
import type { PreparedAreaData } from './area/types';
|
|
9
10
|
import type { PreparedBarXData } from './bar-x';
|
|
10
11
|
import type { PreparedBarYData } from './bar-y/types';
|
|
@@ -37,8 +38,10 @@ type Args = {
|
|
|
37
38
|
isRangeSlider?: boolean;
|
|
38
39
|
xScale?: ChartScale;
|
|
39
40
|
yScale?: (ChartScale | undefined)[];
|
|
41
|
+
zoomState?: Partial<ZoomState>;
|
|
40
42
|
};
|
|
41
43
|
export declare const useShapes: (args: Args) => {
|
|
42
44
|
shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
|
|
43
45
|
shapesData: ShapeData[];
|
|
46
|
+
shapesReady: boolean;
|
|
44
47
|
};
|
|
@@ -20,6 +20,7 @@ import { prepareSankeyData } from './sankey/prepare-data';
|
|
|
20
20
|
import { ScatterSeriesShape, prepareScatterData } from './scatter';
|
|
21
21
|
import { TreemapSeriesShape } from './treemap';
|
|
22
22
|
import { prepareTreemapData } from './treemap/prepare-data';
|
|
23
|
+
import { getSeriesClipPathId } from './utils';
|
|
23
24
|
import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
|
|
24
25
|
import './styles.css';
|
|
25
26
|
function IS_OUTSIDE_BOUNDS() {
|
|
@@ -30,9 +31,10 @@ function shouldUseClipPathId(seriesType, clipPathBySeriesType) {
|
|
|
30
31
|
return (_a = clipPathBySeriesType === null || clipPathBySeriesType === void 0 ? void 0 : clipPathBySeriesType[seriesType]) !== null && _a !== void 0 ? _a : true;
|
|
31
32
|
}
|
|
32
33
|
export const useShapes = (args) => {
|
|
33
|
-
const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
|
|
34
|
+
const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, zoomState, } = args;
|
|
34
35
|
const [shapesElemens, setShapesElements] = React.useState([]);
|
|
35
36
|
const [shapesElemensData, setShapesElemensData] = React.useState([]);
|
|
37
|
+
const shapesReadyRef = React.useRef(false);
|
|
36
38
|
const countedRef = React.useRef(0);
|
|
37
39
|
React.useEffect(() => {
|
|
38
40
|
countedRef.current++;
|
|
@@ -44,7 +46,7 @@ export const useShapes = (args) => {
|
|
|
44
46
|
const shapes = [];
|
|
45
47
|
await Promise.all(
|
|
46
48
|
// eslint-disable-next-line complexity
|
|
47
|
-
Array.from(groupedSeries).map(async (item) => {
|
|
49
|
+
Array.from(groupedSeries).map(async (item, index) => {
|
|
48
50
|
const [seriesType, chartSeries] = item;
|
|
49
51
|
switch (seriesType) {
|
|
50
52
|
case SERIES_TYPE.BarX: {
|
|
@@ -60,8 +62,8 @@ export const useShapes = (args) => {
|
|
|
60
62
|
split,
|
|
61
63
|
isRangeSlider,
|
|
62
64
|
});
|
|
63
|
-
shapes
|
|
64
|
-
shapesData.
|
|
65
|
+
shapes[index] = (React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
66
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
65
67
|
}
|
|
66
68
|
break;
|
|
67
69
|
}
|
|
@@ -77,8 +79,8 @@ export const useShapes = (args) => {
|
|
|
77
79
|
yAxis,
|
|
78
80
|
yScale,
|
|
79
81
|
});
|
|
80
|
-
shapes
|
|
81
|
-
shapesData.
|
|
82
|
+
shapes[index] = (React.createElement(BarYSeriesShapes, { key: SERIES_TYPE.BarY, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
83
|
+
shapesData.splice(index, 0, ...preparedData.shapes);
|
|
82
84
|
}
|
|
83
85
|
break;
|
|
84
86
|
}
|
|
@@ -92,8 +94,8 @@ export const useShapes = (args) => {
|
|
|
92
94
|
yAxis,
|
|
93
95
|
yScale,
|
|
94
96
|
});
|
|
95
|
-
shapes
|
|
96
|
-
shapesData.
|
|
97
|
+
shapes[index] = (React.createElement(WaterfallSeriesShapes, { key: SERIES_TYPE.Waterfall, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
98
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
97
99
|
}
|
|
98
100
|
break;
|
|
99
101
|
}
|
|
@@ -109,8 +111,13 @@ export const useShapes = (args) => {
|
|
|
109
111
|
isOutsideBounds,
|
|
110
112
|
isRangeSlider,
|
|
111
113
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
const resultClipPathId = getSeriesClipPathId({
|
|
115
|
+
clipPathId,
|
|
116
|
+
yAxis,
|
|
117
|
+
zoomState,
|
|
118
|
+
});
|
|
119
|
+
shapes[index] = (React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
|
|
120
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
114
121
|
}
|
|
115
122
|
break;
|
|
116
123
|
}
|
|
@@ -127,8 +134,8 @@ export const useShapes = (args) => {
|
|
|
127
134
|
isOutsideBounds,
|
|
128
135
|
isRangeSlider,
|
|
129
136
|
});
|
|
130
|
-
shapes
|
|
131
|
-
shapesData.
|
|
137
|
+
shapes[index] = (React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
138
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
132
139
|
}
|
|
133
140
|
break;
|
|
134
141
|
}
|
|
@@ -142,10 +149,10 @@ export const useShapes = (args) => {
|
|
|
142
149
|
yScale,
|
|
143
150
|
isOutsideBounds,
|
|
144
151
|
});
|
|
145
|
-
shapes
|
|
152
|
+
shapes[index] = (React.createElement(ScatterSeriesShape, { key: SERIES_TYPE.Scatter, clipPathId: shouldUseClipPathId(SERIES_TYPE.Scatter, clipPathBySeriesType)
|
|
146
153
|
? clipPathId
|
|
147
154
|
: undefined, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
148
|
-
shapesData.
|
|
155
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
149
156
|
}
|
|
150
157
|
break;
|
|
151
158
|
}
|
|
@@ -155,8 +162,8 @@ export const useShapes = (args) => {
|
|
|
155
162
|
boundsWidth,
|
|
156
163
|
boundsHeight,
|
|
157
164
|
});
|
|
158
|
-
shapes
|
|
159
|
-
shapesData.
|
|
165
|
+
shapes[index] = (React.createElement(PieSeriesShapes, { key: SERIES_TYPE.Pie, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
166
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
160
167
|
break;
|
|
161
168
|
}
|
|
162
169
|
case SERIES_TYPE.Treemap: {
|
|
@@ -167,8 +174,8 @@ export const useShapes = (args) => {
|
|
|
167
174
|
width: boundsWidth,
|
|
168
175
|
height: boundsHeight,
|
|
169
176
|
});
|
|
170
|
-
shapes
|
|
171
|
-
shapesData.
|
|
177
|
+
shapes[index] = (React.createElement(TreemapSeriesShape, { key: SERIES_TYPE.Treemap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
178
|
+
shapesData.splice(index, 0, preparedData);
|
|
172
179
|
break;
|
|
173
180
|
}
|
|
174
181
|
case SERIES_TYPE.Sankey: {
|
|
@@ -177,8 +184,8 @@ export const useShapes = (args) => {
|
|
|
177
184
|
width: boundsWidth,
|
|
178
185
|
height: boundsHeight,
|
|
179
186
|
});
|
|
180
|
-
shapes
|
|
181
|
-
shapesData.
|
|
187
|
+
shapes[index] = (React.createElement(SankeySeriesShape, { key: SERIES_TYPE.Sankey, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
188
|
+
shapesData.splice(index, 0, preparedData);
|
|
182
189
|
break;
|
|
183
190
|
}
|
|
184
191
|
case SERIES_TYPE.Radar: {
|
|
@@ -187,8 +194,8 @@ export const useShapes = (args) => {
|
|
|
187
194
|
boundsWidth,
|
|
188
195
|
boundsHeight,
|
|
189
196
|
});
|
|
190
|
-
shapes
|
|
191
|
-
shapesData.
|
|
197
|
+
shapes[index] = (React.createElement(RadarSeriesShapes, { key: SERIES_TYPE.Radar, dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
198
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
192
199
|
break;
|
|
193
200
|
}
|
|
194
201
|
case SERIES_TYPE.Heatmap: {
|
|
@@ -200,8 +207,8 @@ export const useShapes = (args) => {
|
|
|
200
207
|
yAxis: yAxis[0],
|
|
201
208
|
yScale: yScale[0],
|
|
202
209
|
});
|
|
203
|
-
shapes
|
|
204
|
-
shapesData.
|
|
210
|
+
shapes[index] = (React.createElement(HeatmapSeriesShapes, { key: SERIES_TYPE.Heatmap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
211
|
+
shapesData.splice(index, 0, preparedData);
|
|
205
212
|
}
|
|
206
213
|
break;
|
|
207
214
|
}
|
|
@@ -211,8 +218,8 @@ export const useShapes = (args) => {
|
|
|
211
218
|
boundsWidth,
|
|
212
219
|
boundsHeight,
|
|
213
220
|
});
|
|
214
|
-
shapes
|
|
215
|
-
shapesData.
|
|
221
|
+
shapes[index] = (React.createElement(FunnelSeriesShapes, { key: "funnel", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
222
|
+
shapesData.splice(index, 0, preparedData);
|
|
216
223
|
break;
|
|
217
224
|
}
|
|
218
225
|
default: {
|
|
@@ -223,6 +230,7 @@ export const useShapes = (args) => {
|
|
|
223
230
|
}
|
|
224
231
|
}));
|
|
225
232
|
if (countedRef.current === currentRun) {
|
|
233
|
+
shapesReadyRef.current = true;
|
|
226
234
|
setShapesElements(shapes);
|
|
227
235
|
setShapesElemensData(shapesData);
|
|
228
236
|
}
|
|
@@ -243,6 +251,11 @@ export const useShapes = (args) => {
|
|
|
243
251
|
xScale,
|
|
244
252
|
yAxis,
|
|
245
253
|
yScale,
|
|
254
|
+
zoomState,
|
|
246
255
|
]);
|
|
247
|
-
return {
|
|
256
|
+
return {
|
|
257
|
+
shapes: shapesElemens,
|
|
258
|
+
shapesData: shapesElemensData,
|
|
259
|
+
shapesReady: shapesReadyRef.current,
|
|
260
|
+
};
|
|
248
261
|
};
|
|
@@ -2,6 +2,7 @@ import type { BaseType } from 'd3';
|
|
|
2
2
|
import type { BasicInactiveState } from '../../types';
|
|
3
3
|
import type { PreparedXAxis, PreparedYAxis } from '../useAxis/types';
|
|
4
4
|
import type { ChartScale } from '../useAxisScales/types';
|
|
5
|
+
import type { ZoomState } from '../useZoom/types';
|
|
5
6
|
export declare function getXValue(args: {
|
|
6
7
|
point: {
|
|
7
8
|
x?: number | string | null;
|
|
@@ -46,3 +47,12 @@ export declare function getRectBorderPath(args: {
|
|
|
46
47
|
borderWidth: number;
|
|
47
48
|
borderRadius?: number | number[];
|
|
48
49
|
}): string;
|
|
50
|
+
export declare function getClipPathIdByBounds(args: {
|
|
51
|
+
clipPathId: string;
|
|
52
|
+
bounds?: 'horizontal';
|
|
53
|
+
}): string;
|
|
54
|
+
export declare function getSeriesClipPathId(args: {
|
|
55
|
+
clipPathId: string;
|
|
56
|
+
yAxis: PreparedYAxis[];
|
|
57
|
+
zoomState?: Partial<ZoomState>;
|
|
58
|
+
}): string;
|