@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
|
@@ -131,3 +131,18 @@ export function getRectBorderPath(args) {
|
|
|
131
131
|
}).toString();
|
|
132
132
|
return `${outerPath} ${innerPath}`;
|
|
133
133
|
}
|
|
134
|
+
export function getClipPathIdByBounds(args) {
|
|
135
|
+
const { bounds, clipPathId } = args;
|
|
136
|
+
return bounds ? `${clipPathId}-${bounds}` : clipPathId;
|
|
137
|
+
}
|
|
138
|
+
export function getSeriesClipPathId(args) {
|
|
139
|
+
const { clipPathId, yAxis, zoomState } = args;
|
|
140
|
+
const hasMinOrMax = yAxis.some((axis) => {
|
|
141
|
+
return typeof (axis === null || axis === void 0 ? void 0 : axis.min) === 'number' || typeof (axis === null || axis === void 0 ? void 0 : axis.max) === 'number';
|
|
142
|
+
});
|
|
143
|
+
const hasZoom = zoomState && Object.keys(zoomState).length > 0;
|
|
144
|
+
if (!hasZoom && !hasMinOrMax) {
|
|
145
|
+
return getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' });
|
|
146
|
+
}
|
|
147
|
+
return getClipPathIdByBounds({ clipPathId });
|
|
148
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Global mocks for jsdom environment.
|
|
3
|
+
// Guarded by typeof checks so this file is safe to run in the `node` environment too.
|
|
4
|
+
if (typeof document !== 'undefined') {
|
|
5
|
+
// jsdom does not implement document.fonts
|
|
6
|
+
if (!document.fonts) {
|
|
7
|
+
Object.defineProperty(document, 'fonts', {
|
|
8
|
+
value: { ready: Promise.resolve() },
|
|
9
|
+
configurable: true,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (typeof HTMLCanvasElement !== 'undefined') {
|
|
14
|
+
// jsdom does not implement HTMLCanvasElement.prototype.getContext (used for text measurement)
|
|
15
|
+
HTMLCanvasElement.prototype.getContext = (() => ({
|
|
16
|
+
font: '',
|
|
17
|
+
measureText: () => ({ width: 0 }),
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
@@ -3,9 +3,9 @@ import type { ChartScale, PreparedAxis, PreparedAxisPlotBand, PreparedSplit } fr
|
|
|
3
3
|
import type { ChartAxis } from '../../../types';
|
|
4
4
|
import type { AxisDirection } from '../types';
|
|
5
5
|
type Ticks = number[] | string[] | Date[];
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function getTicksCountByPixelInterval({ axis, axisWidth, }: {
|
|
7
7
|
axis: PreparedAxis;
|
|
8
|
-
|
|
8
|
+
axisWidth: number;
|
|
9
9
|
}): number | undefined;
|
|
10
10
|
export declare function isBandScale(scale?: ChartScale | AxisScale<AxisDomain>): scale is ScaleBand<string>;
|
|
11
11
|
export declare function isTimeScale(scale?: ChartScale | AxisScale<AxisDomain>): scale is ScaleTime<number, number>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ascending, descending, reverse, sort } from 'd3';
|
|
2
2
|
import clamp from 'lodash/clamp';
|
|
3
|
-
export function
|
|
3
|
+
export function getTicksCountByPixelInterval({ axis, axisWidth, }) {
|
|
4
4
|
let ticksCount;
|
|
5
5
|
if (axis.ticks.pixelInterval) {
|
|
6
|
-
ticksCount = Math.ceil(
|
|
6
|
+
ticksCount = Math.ceil(axisWidth / axis.ticks.pixelInterval);
|
|
7
7
|
}
|
|
8
8
|
return ticksCount;
|
|
9
9
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis } from '../../../hooks';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSeries } from '../../../hooks';
|
|
2
|
+
import type { ChartSeries } from '../../../types';
|
|
3
|
+
type TickValue = {
|
|
4
|
+
x: number;
|
|
5
|
+
value: number | string | Date;
|
|
6
|
+
};
|
|
7
|
+
export declare function getXAxisTickValues({ axis, labelLineHeight, scale, series, }: {
|
|
4
8
|
axis: PreparedAxis;
|
|
5
9
|
labelLineHeight: number;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
x: number;
|
|
11
|
-
value: string;
|
|
12
|
-
}[];
|
|
10
|
+
scale: ChartScale;
|
|
11
|
+
series?: ChartSeries[] | PreparedSeries[];
|
|
12
|
+
}): TickValue[];
|
|
13
|
+
export {};
|
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
import { getMinSpaceBetween } from '../array';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { isSeriesWithNumericalXValues } from '../series-type-guards';
|
|
3
|
+
import { getTicksCountByPixelInterval, isBandScale, thinOut } from './common';
|
|
4
|
+
const DEFAULT_TICKS_COUNT = 10;
|
|
5
|
+
function getTicksCount(args) {
|
|
6
|
+
const { axis, axisWidth, series } = args;
|
|
7
|
+
const result = getTicksCountByPixelInterval({ axis, axisWidth });
|
|
8
|
+
if (typeof result === 'number') {
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
if (series) {
|
|
12
|
+
const xDataSet = new Set();
|
|
13
|
+
series === null || series === void 0 ? void 0 : series.forEach((item) => {
|
|
14
|
+
if (isSeriesWithNumericalXValues(item)) {
|
|
15
|
+
item.data.forEach((data) => {
|
|
16
|
+
xDataSet.add(data.x);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return xDataSet.size < DEFAULT_TICKS_COUNT ? xDataSet.size : DEFAULT_TICKS_COUNT;
|
|
21
|
+
}
|
|
22
|
+
return DEFAULT_TICKS_COUNT;
|
|
23
|
+
}
|
|
24
|
+
export function getXAxisTickValues({ axis, labelLineHeight, scale, series, }) {
|
|
4
25
|
if ('ticks' in scale && typeof scale.ticks === 'function') {
|
|
5
26
|
const range = scale.range();
|
|
6
27
|
const axisWidth = Math.abs(range[0] - range[1]);
|
|
7
28
|
if (!axisWidth) {
|
|
8
29
|
return [];
|
|
9
30
|
}
|
|
10
|
-
const scaleTicksCount = getTicksCount({ axis,
|
|
31
|
+
const scaleTicksCount = getTicksCount({ axis, axisWidth, series });
|
|
11
32
|
const scaleTicks = scale.ticks(scaleTicksCount);
|
|
12
33
|
const originalTickValues = scaleTicks.map((t) => ({
|
|
13
34
|
x: scale(t),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BaseTextStyle, ChartSeries, ChartSeriesData } from '../../types';
|
|
2
|
+
import type { UnknownSeries } from './series-type-guards';
|
|
2
3
|
import type { AxisDirection } from './types';
|
|
3
4
|
export * from './axis/common';
|
|
4
5
|
export * from './array';
|
|
@@ -8,41 +9,13 @@ export * from './labels';
|
|
|
8
9
|
export * from './legend';
|
|
9
10
|
export * from './math';
|
|
10
11
|
export * from './series';
|
|
12
|
+
export * from './series-type-guards';
|
|
11
13
|
export * from './symbol';
|
|
12
14
|
export * from './text';
|
|
13
15
|
export * from './time';
|
|
14
16
|
export * from './zoom';
|
|
15
17
|
export declare const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS: ChartSeries['type'][];
|
|
16
18
|
export declare const CHART_SERIES_WITH_VOLUME_ON_X_AXIS: ChartSeries['type'][];
|
|
17
|
-
type UnknownSeries = {
|
|
18
|
-
type: ChartSeries['type'];
|
|
19
|
-
data: unknown;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Checks whether the series should be drawn with axes.
|
|
23
|
-
*
|
|
24
|
-
* @param series - The series object to check.
|
|
25
|
-
* @returns `true` if the series should be drawn with axes, `false` otherwise.
|
|
26
|
-
*/
|
|
27
|
-
export declare function isAxisRelatedSeries(series: UnknownSeries): boolean;
|
|
28
|
-
export declare function isSeriesWithNumericalXValues(series: UnknownSeries): series is {
|
|
29
|
-
type: ChartSeries['type'];
|
|
30
|
-
data: {
|
|
31
|
-
x: number;
|
|
32
|
-
}[];
|
|
33
|
-
};
|
|
34
|
-
export declare function isSeriesWithNumericalYValues(series: UnknownSeries): series is {
|
|
35
|
-
type: ChartSeries['type'];
|
|
36
|
-
data: {
|
|
37
|
-
y: number;
|
|
38
|
-
}[];
|
|
39
|
-
};
|
|
40
|
-
export declare function isSeriesWithCategoryValues(series: UnknownSeries): series is {
|
|
41
|
-
type: ChartSeries['type'];
|
|
42
|
-
data: {
|
|
43
|
-
category: string;
|
|
44
|
-
}[];
|
|
45
|
-
};
|
|
46
19
|
export declare const getDomainDataXBySeries: (series: UnknownSeries[]) => ({} | undefined)[];
|
|
47
20
|
export declare function getDefaultMaxXAxisValue(series: UnknownSeries[]): 0 | undefined;
|
|
48
21
|
export declare function getDefaultMinXAxisValue(series: UnknownSeries[]): number | undefined;
|
|
@@ -5,6 +5,7 @@ import sortBy from 'lodash/sortBy';
|
|
|
5
5
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE, SERIES_TYPE } from '../../constants';
|
|
6
6
|
import { getSeriesStackId } from '../../hooks/useSeries/utils';
|
|
7
7
|
import { getWaterfallPointSubtotal } from './series/waterfall';
|
|
8
|
+
import { isSeriesWithNumericalXValues, isSeriesWithNumericalYValues } from './series-type-guards';
|
|
8
9
|
export * from './axis/common';
|
|
9
10
|
export * from './array';
|
|
10
11
|
export * from './color';
|
|
@@ -13,35 +14,17 @@ export * from './labels';
|
|
|
13
14
|
export * from './legend';
|
|
14
15
|
export * from './math';
|
|
15
16
|
export * from './series';
|
|
17
|
+
export * from './series-type-guards';
|
|
16
18
|
export * from './symbol';
|
|
17
19
|
export * from './text';
|
|
18
20
|
export * from './time';
|
|
19
21
|
export * from './zoom';
|
|
20
|
-
const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey', 'radar', 'funnel'];
|
|
21
22
|
export const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS = [
|
|
22
23
|
'bar-x',
|
|
23
24
|
'area',
|
|
24
25
|
'waterfall',
|
|
25
26
|
];
|
|
26
27
|
export const CHART_SERIES_WITH_VOLUME_ON_X_AXIS = ['bar-y'];
|
|
27
|
-
/**
|
|
28
|
-
* Checks whether the series should be drawn with axes.
|
|
29
|
-
*
|
|
30
|
-
* @param series - The series object to check.
|
|
31
|
-
* @returns `true` if the series should be drawn with axes, `false` otherwise.
|
|
32
|
-
*/
|
|
33
|
-
export function isAxisRelatedSeries(series) {
|
|
34
|
-
return !CHARTS_WITHOUT_AXIS.includes(series.type);
|
|
35
|
-
}
|
|
36
|
-
export function isSeriesWithNumericalXValues(series) {
|
|
37
|
-
return isAxisRelatedSeries(series);
|
|
38
|
-
}
|
|
39
|
-
export function isSeriesWithNumericalYValues(series) {
|
|
40
|
-
return isAxisRelatedSeries(series);
|
|
41
|
-
}
|
|
42
|
-
export function isSeriesWithCategoryValues(series) {
|
|
43
|
-
return isAxisRelatedSeries(series);
|
|
44
|
-
}
|
|
45
28
|
function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y') {
|
|
46
29
|
const acc = [];
|
|
47
30
|
const stackedSeries = group(seriesList, getSeriesStackId);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChartSeries } from '../../types';
|
|
2
|
+
export type UnknownSeries = {
|
|
3
|
+
type: ChartSeries['type'];
|
|
4
|
+
data: unknown;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether the series should be drawn with axes.
|
|
8
|
+
*
|
|
9
|
+
* @param series - The series object to check.
|
|
10
|
+
* @returns `true` if the series should be drawn with axes, `false` otherwise.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isAxisRelatedSeries(series: UnknownSeries): boolean;
|
|
13
|
+
export declare function isSeriesWithNumericalXValues(series: UnknownSeries): series is {
|
|
14
|
+
type: ChartSeries['type'];
|
|
15
|
+
data: {
|
|
16
|
+
x: number;
|
|
17
|
+
}[];
|
|
18
|
+
};
|
|
19
|
+
export declare function isSeriesWithNumericalYValues(series: UnknownSeries): series is {
|
|
20
|
+
type: ChartSeries['type'];
|
|
21
|
+
data: {
|
|
22
|
+
y: number;
|
|
23
|
+
}[];
|
|
24
|
+
};
|
|
25
|
+
export declare function isSeriesWithCategoryValues(series: UnknownSeries): series is {
|
|
26
|
+
type: ChartSeries['type'];
|
|
27
|
+
data: {
|
|
28
|
+
category: string;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey', 'radar', 'funnel'];
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the series should be drawn with axes.
|
|
4
|
+
*
|
|
5
|
+
* @param series - The series object to check.
|
|
6
|
+
* @returns `true` if the series should be drawn with axes, `false` otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export function isAxisRelatedSeries(series) {
|
|
9
|
+
return !CHARTS_WITHOUT_AXIS.includes(series.type);
|
|
10
|
+
}
|
|
11
|
+
export function isSeriesWithNumericalXValues(series) {
|
|
12
|
+
return isAxisRelatedSeries(series);
|
|
13
|
+
}
|
|
14
|
+
export function isSeriesWithNumericalYValues(series) {
|
|
15
|
+
return isAxisRelatedSeries(series);
|
|
16
|
+
}
|
|
17
|
+
export function isSeriesWithCategoryValues(series) {
|
|
18
|
+
return isAxisRelatedSeries(series);
|
|
19
|
+
}
|
|
@@ -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
|
+
}
|