@gravity-ui/charts 1.41.1 → 1.42.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 +2 -2
- package/dist/cjs/components/ChartInner/useDefaultState.js +4 -1
- package/dist/cjs/components/ChartInner/utils/tooltip.js +6 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +2 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +2 -2
- package/dist/cjs/hooks/useRangeSlider/index.js +5 -2
- package/dist/cjs/hooks/useRangeSlider/types.d.ts +1 -0
- package/dist/cjs/types/chart/tooltip.d.ts +33 -0
- package/dist/cjs/utils/chart/time.d.ts +14 -3
- package/dist/cjs/utils/chart/time.js +5 -4
- package/dist/cjs/utils/chart/tooltip.d.ts +3 -2
- package/dist/cjs/utils/chart/tooltip.js +7 -3
- package/dist/esm/components/ChartInner/index.js +2 -2
- package/dist/esm/components/ChartInner/useDefaultState.js +4 -1
- package/dist/esm/components/ChartInner/utils/tooltip.js +6 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +2 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +2 -2
- package/dist/esm/hooks/useRangeSlider/index.js +5 -2
- package/dist/esm/hooks/useRangeSlider/types.d.ts +1 -0
- package/dist/esm/types/chart/tooltip.d.ts +33 -0
- package/dist/esm/utils/chart/time.d.ts +14 -3
- package/dist/esm/utils/chart/time.js +5 -4
- package/dist/esm/utils/chart/tooltip.d.ts +3 -2
- package/dist/esm/utils/chart/tooltip.js +7 -3
- package/package.json +1 -1
|
@@ -61,7 +61,7 @@ export const ChartInner = (props) => {
|
|
|
61
61
|
preparedRangeSlider,
|
|
62
62
|
tooltip: preparedTooltip,
|
|
63
63
|
});
|
|
64
|
-
const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
64
|
+
const { activeLegendItems, allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
65
65
|
dispatcher,
|
|
66
66
|
htmlLayout, plotNode: plotRef.current, preparedChart,
|
|
67
67
|
rangeSliderState,
|
|
@@ -270,7 +270,7 @@ export const ChartInner = (props) => {
|
|
|
270
270
|
((_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.rangeSlider) === null || _e === void 0 ? void 0 : _e.enabled) &&
|
|
271
271
|
preparedLegend &&
|
|
272
272
|
debouncedAllPreparedSeries &&
|
|
273
|
-
preparedSeriesOptions && (React.createElement(RangeSlider, { boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
|
|
273
|
+
preparedSeriesOptions && (React.createElement(RangeSlider, { activeLegendItems: activeLegendItems !== null && activeLegendItems !== void 0 ? activeLegendItems : [], boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
|
|
274
274
|
(preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))));
|
|
275
275
|
return (React.createElement("div", { className: b() },
|
|
276
276
|
React.createElement("svg", { ref: svgRef, width: width, height: height,
|
|
@@ -16,7 +16,7 @@ export function useDefaultState(props) {
|
|
|
16
16
|
// Defer dispatch so shape components (Area, Line, etc.) register their hover-shape.*
|
|
17
17
|
// listeners first; parent effects run before child effects in React.
|
|
18
18
|
queueMicrotask(() => {
|
|
19
|
-
var _a;
|
|
19
|
+
var _a, _b;
|
|
20
20
|
const x = calculateNumericProperty({ value: hoveredPosition.x, base: boundsWidth });
|
|
21
21
|
const y = calculateNumericProperty({ value: hoveredPosition.y, base: boundsHeight });
|
|
22
22
|
if (x === undefined || y === undefined) {
|
|
@@ -48,6 +48,9 @@ export function useDefaultState(props) {
|
|
|
48
48
|
clientX: rect.left + svgPointerX,
|
|
49
49
|
clientY: rect.top + svgPointerY,
|
|
50
50
|
});
|
|
51
|
+
if (syntheticEvent) {
|
|
52
|
+
(_b = svgRef.current) === null || _b === void 0 ? void 0 : _b.dispatchEvent(syntheticEvent);
|
|
53
|
+
}
|
|
51
54
|
dispatcher.call(EventType.POINTERMOVE_CHART, {}, {
|
|
52
55
|
hovered: closest,
|
|
53
56
|
xAxis,
|
|
@@ -3,5 +3,10 @@ import { getDefaultTooltipHeaderFormat } from '../../../utils/chart/tooltip';
|
|
|
3
3
|
export const getPreparedTooltip = (args) => {
|
|
4
4
|
var _a, _b;
|
|
5
5
|
const { tooltip, seriesData, yAxes, xAxis } = args;
|
|
6
|
-
return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0, headerFormat: (_b = tooltip === null || tooltip === void 0 ? void 0 : tooltip.headerFormat) !== null && _b !== void 0 ? _b : getDefaultTooltipHeaderFormat({
|
|
6
|
+
return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0, headerFormat: (_b = tooltip === null || tooltip === void 0 ? void 0 : tooltip.headerFormat) !== null && _b !== void 0 ? _b : getDefaultTooltipHeaderFormat({
|
|
7
|
+
dateTimeLabelFormats: tooltip === null || tooltip === void 0 ? void 0 : tooltip.dateTimeLabelFormats,
|
|
8
|
+
seriesData,
|
|
9
|
+
yAxes,
|
|
10
|
+
xAxis,
|
|
11
|
+
}) });
|
|
7
12
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { ChartSeriesData, ChartTooltip, ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
2
2
|
export type HoveredValue = string | number | null | undefined;
|
|
3
3
|
export declare function getXRowData(data: ChartSeriesData, xAxis?: ChartXAxis | null): string | number | null | undefined;
|
|
4
|
-
export declare function getDefaultValueFormat({ axis, closestPointsRange, }: {
|
|
4
|
+
export declare function getDefaultValueFormat({ axis, closestPointsRange, dateTimeLabelFormats, }: {
|
|
5
5
|
axis?: ChartXAxis | ChartYAxis | null;
|
|
6
6
|
closestPointsRange?: number;
|
|
7
|
+
dateTimeLabelFormats?: ChartTooltip['dateTimeLabelFormats'];
|
|
7
8
|
}): ValueFormat | undefined;
|
|
8
9
|
export declare const getMeasureValue: ({ data, xAxis, yAxis, headerFormat, }: {
|
|
9
10
|
data: TooltipDataChunk[];
|
|
@@ -21,7 +21,7 @@ export function getXRowData(data, xAxis) {
|
|
|
21
21
|
function getYRowData(data, yAxis) {
|
|
22
22
|
return getRowData('y', data, yAxis);
|
|
23
23
|
}
|
|
24
|
-
export function getDefaultValueFormat({ axis, closestPointsRange, }) {
|
|
24
|
+
export function getDefaultValueFormat({ axis, closestPointsRange, dateTimeLabelFormats, }) {
|
|
25
25
|
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
26
26
|
case 'linear':
|
|
27
27
|
case 'logarithmic': {
|
|
@@ -32,7 +32,7 @@ export function getDefaultValueFormat({ axis, closestPointsRange, }) {
|
|
|
32
32
|
case 'datetime': {
|
|
33
33
|
return {
|
|
34
34
|
type: 'date',
|
|
35
|
-
format: getDefaultDateFormat(closestPointsRange),
|
|
35
|
+
format: getDefaultDateFormat(closestPointsRange, dateTimeLabelFormats),
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
default:
|
|
@@ -17,15 +17,18 @@ const CLIP_PATH_BY_SERIES_TYPE = {
|
|
|
17
17
|
[SERIES_TYPE.Scatter]: true,
|
|
18
18
|
};
|
|
19
19
|
export function useRangeSlider(props) {
|
|
20
|
-
const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, legendConfig, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
20
|
+
const { activeLegendItems, boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, legendConfig, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
21
21
|
const filteredPreparedSeries = React.useMemo(() => {
|
|
22
22
|
return preparedSeries.filter((s) => {
|
|
23
|
+
if (s.legend.enabled && !activeLegendItems.includes(s.legend.groupId)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
23
26
|
if ('rangeSlider' in s && !s.rangeSlider.visible) {
|
|
24
27
|
return false;
|
|
25
28
|
}
|
|
26
29
|
return true;
|
|
27
30
|
});
|
|
28
|
-
}, [preparedSeries]);
|
|
31
|
+
}, [preparedSeries, activeLegendItems]);
|
|
29
32
|
const { xAxis: preparedXAxis, yAxis: preparedYAxis } = useAxis({
|
|
30
33
|
boundsHeight: preparedRangeSlider.height,
|
|
31
34
|
height,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TOOLTIP_TOTALS_BUILT_IN_AGGREGATION } from '../../constants';
|
|
2
|
+
import type { DateTimeLabelFormats } from '../../utils/chart/time';
|
|
2
3
|
import type { MeaningfulAny } from '../misc';
|
|
3
4
|
import type { AreaSeries, AreaSeriesData } from './area';
|
|
4
5
|
import type { AxisPlotBand, AxisPlotLine, ChartXAxis, ChartYAxis } from './axis';
|
|
@@ -201,4 +202,36 @@ export interface ChartTooltip<T = MeaningfulAny> {
|
|
|
201
202
|
*/
|
|
202
203
|
direction?: 'asc' | 'desc';
|
|
203
204
|
} | ChartTooltipSortComparator<T>;
|
|
205
|
+
/**
|
|
206
|
+
* Per-granularity display formats for the default datetime tooltip header.
|
|
207
|
+
* Ignored when `headerFormat` is set.
|
|
208
|
+
*
|
|
209
|
+
* Each value is a format string in the same form as the `format` argument to
|
|
210
|
+
* [`DateTime#format`](https://gravity-ui.github.io/date-utils/pages/api/DateTime/overview.html) in `@gravity-ui/date-utils`
|
|
211
|
+
* (see the **`FormatInput`** type there): Day.js–style tokens, e.g. `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`, `SSS`, `MMM`.
|
|
212
|
+
*
|
|
213
|
+
* Partial objects are merged with the built-in `DATETIME_LABEL_FORMATS`; omitted keys keep defaults.
|
|
214
|
+
* @example ISO-like date and time
|
|
215
|
+
* ```ts
|
|
216
|
+
* dateTimeLabelFormats: { day: 'YYYY-MM-DD', hour: 'YYYY-MM-DD HH:mm', minute: 'YYYY-MM-DD HH:mm' }
|
|
217
|
+
* ```
|
|
218
|
+
* @example US-style calendar date
|
|
219
|
+
* ```ts
|
|
220
|
+
* dateTimeLabelFormats: { day: 'MM/DD/YYYY', week: 'MM/DD/YYYY' }
|
|
221
|
+
* ```
|
|
222
|
+
* @example Only sub-day precision (other units stay defaults)
|
|
223
|
+
* ```ts
|
|
224
|
+
* dateTimeLabelFormats: { hour: 'HH:mm', minute: 'HH:mm', second: 'HH:mm:ss' }
|
|
225
|
+
* ```
|
|
226
|
+
* @example Coarse ranges: short month and full year
|
|
227
|
+
* ```ts
|
|
228
|
+
* dateTimeLabelFormats: { month: 'YYYY-MM', year: 'YYYY' }
|
|
229
|
+
* ```
|
|
230
|
+
* @example Localized-style month label with day precision unchanged
|
|
231
|
+
* ```ts
|
|
232
|
+
* dateTimeLabelFormats: { month: 'MMMM YYYY' }
|
|
233
|
+
* ```
|
|
234
|
+
* @see https://gravity-ui.github.io/date-utils/pages/api/DateTime/overview.html
|
|
235
|
+
*/
|
|
236
|
+
dateTimeLabelFormats?: DateTimeLabelFormats;
|
|
204
237
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
export declare const TIME_UNITS:
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export declare const TIME_UNITS: {
|
|
2
|
+
readonly millisecond: 1;
|
|
3
|
+
readonly second: 1000;
|
|
4
|
+
readonly minute: 60000;
|
|
5
|
+
readonly hour: 3600000;
|
|
6
|
+
readonly day: number;
|
|
7
|
+
readonly week: number;
|
|
8
|
+
readonly month: number;
|
|
9
|
+
readonly year: number;
|
|
10
|
+
};
|
|
11
|
+
export type TimeUnit = keyof typeof TIME_UNITS;
|
|
12
|
+
export declare const DATETIME_LABEL_FORMATS: Record<TimeUnit, string>;
|
|
13
|
+
export type DateTimeLabelFormats = Partial<Record<TimeUnit, string>>;
|
|
14
|
+
export declare function getDefaultDateFormat(range?: number, overrides?: DateTimeLabelFormats): string;
|
|
4
15
|
export declare function getDefaultTimeOnlyFormat(step: number): string;
|
|
@@ -23,14 +23,15 @@ function getTimeUnit(range) {
|
|
|
23
23
|
const index = units.findIndex((unit) => range < TIME_UNITS[unit]);
|
|
24
24
|
return index === -1 ? 'year' : units[index - 1];
|
|
25
25
|
}
|
|
26
|
-
export function getDefaultDateFormat(range) {
|
|
26
|
+
export function getDefaultDateFormat(range, overrides) {
|
|
27
|
+
const formats = Object.assign(Object.assign({}, DATETIME_LABEL_FORMATS), overrides);
|
|
27
28
|
if (range) {
|
|
28
29
|
const unit = getTimeUnit(range);
|
|
29
|
-
if (unit in
|
|
30
|
-
return
|
|
30
|
+
if (unit in formats) {
|
|
31
|
+
return formats[unit];
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
return
|
|
34
|
+
return formats.day;
|
|
34
35
|
}
|
|
35
36
|
export function getDefaultTimeOnlyFormat(step) {
|
|
36
37
|
if (step < TIME_UNITS.second) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { ChartSeries, ChartXAxis, ChartYAxis } from '../../types';
|
|
2
|
-
export declare function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, }: {
|
|
1
|
+
import type { ChartSeries, ChartTooltip, ChartXAxis, ChartYAxis } from '../../types';
|
|
2
|
+
export declare function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, dateTimeLabelFormats, }: {
|
|
3
3
|
seriesData: ChartSeries[];
|
|
4
4
|
yAxes?: ChartYAxis[];
|
|
5
5
|
xAxis?: ChartXAxis;
|
|
6
|
+
dateTimeLabelFormats?: ChartTooltip['dateTimeLabelFormats'];
|
|
6
7
|
}): import("../../types").ValueFormat | undefined;
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { getDefaultValueFormat } from '../../components/Tooltip/DefaultTooltipContent/utils';
|
|
2
2
|
import { getMinSpaceBetween } from './array';
|
|
3
3
|
import { getDomainDataXBySeries, getDomainDataYBySeries } from './common';
|
|
4
|
-
export function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, }) {
|
|
4
|
+
export function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, dateTimeLabelFormats, }) {
|
|
5
5
|
if (seriesData.every((item) => ['pie', 'treemap', 'waterfall', 'sankey', 'radar', 'heatmap', 'funnel'].includes(item.type))) {
|
|
6
6
|
return undefined;
|
|
7
7
|
}
|
|
8
8
|
if (seriesData.some((item) => item.type === 'bar-y')) {
|
|
9
9
|
const domainData = getDomainDataYBySeries(seriesData);
|
|
10
10
|
const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
|
|
11
|
-
return getDefaultValueFormat({
|
|
11
|
+
return getDefaultValueFormat({
|
|
12
|
+
axis: yAxes === null || yAxes === void 0 ? void 0 : yAxes[0],
|
|
13
|
+
closestPointsRange,
|
|
14
|
+
dateTimeLabelFormats,
|
|
15
|
+
});
|
|
12
16
|
}
|
|
13
17
|
const domainData = getDomainDataXBySeries(seriesData);
|
|
14
18
|
const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
|
|
15
|
-
return getDefaultValueFormat({ axis: xAxis, closestPointsRange });
|
|
19
|
+
return getDefaultValueFormat({ axis: xAxis, closestPointsRange, dateTimeLabelFormats });
|
|
16
20
|
}
|
|
@@ -61,7 +61,7 @@ export const ChartInner = (props) => {
|
|
|
61
61
|
preparedRangeSlider,
|
|
62
62
|
tooltip: preparedTooltip,
|
|
63
63
|
});
|
|
64
|
-
const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
64
|
+
const { activeLegendItems, allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
|
|
65
65
|
dispatcher,
|
|
66
66
|
htmlLayout, plotNode: plotRef.current, preparedChart,
|
|
67
67
|
rangeSliderState,
|
|
@@ -270,7 +270,7 @@ export const ChartInner = (props) => {
|
|
|
270
270
|
((_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.rangeSlider) === null || _e === void 0 ? void 0 : _e.enabled) &&
|
|
271
271
|
preparedLegend &&
|
|
272
272
|
debouncedAllPreparedSeries &&
|
|
273
|
-
preparedSeriesOptions && (React.createElement(RangeSlider, { boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
|
|
273
|
+
preparedSeriesOptions && (React.createElement(RangeSlider, { activeLegendItems: activeLegendItems !== null && activeLegendItems !== void 0 ? activeLegendItems : [], boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
|
|
274
274
|
(preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))));
|
|
275
275
|
return (React.createElement("div", { className: b() },
|
|
276
276
|
React.createElement("svg", { ref: svgRef, width: width, height: height,
|
|
@@ -16,7 +16,7 @@ export function useDefaultState(props) {
|
|
|
16
16
|
// Defer dispatch so shape components (Area, Line, etc.) register their hover-shape.*
|
|
17
17
|
// listeners first; parent effects run before child effects in React.
|
|
18
18
|
queueMicrotask(() => {
|
|
19
|
-
var _a;
|
|
19
|
+
var _a, _b;
|
|
20
20
|
const x = calculateNumericProperty({ value: hoveredPosition.x, base: boundsWidth });
|
|
21
21
|
const y = calculateNumericProperty({ value: hoveredPosition.y, base: boundsHeight });
|
|
22
22
|
if (x === undefined || y === undefined) {
|
|
@@ -48,6 +48,9 @@ export function useDefaultState(props) {
|
|
|
48
48
|
clientX: rect.left + svgPointerX,
|
|
49
49
|
clientY: rect.top + svgPointerY,
|
|
50
50
|
});
|
|
51
|
+
if (syntheticEvent) {
|
|
52
|
+
(_b = svgRef.current) === null || _b === void 0 ? void 0 : _b.dispatchEvent(syntheticEvent);
|
|
53
|
+
}
|
|
51
54
|
dispatcher.call(EventType.POINTERMOVE_CHART, {}, {
|
|
52
55
|
hovered: closest,
|
|
53
56
|
xAxis,
|
|
@@ -3,5 +3,10 @@ import { getDefaultTooltipHeaderFormat } from '../../../utils/chart/tooltip';
|
|
|
3
3
|
export const getPreparedTooltip = (args) => {
|
|
4
4
|
var _a, _b;
|
|
5
5
|
const { tooltip, seriesData, yAxes, xAxis } = args;
|
|
6
|
-
return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0, headerFormat: (_b = tooltip === null || tooltip === void 0 ? void 0 : tooltip.headerFormat) !== null && _b !== void 0 ? _b : getDefaultTooltipHeaderFormat({
|
|
6
|
+
return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0, headerFormat: (_b = tooltip === null || tooltip === void 0 ? void 0 : tooltip.headerFormat) !== null && _b !== void 0 ? _b : getDefaultTooltipHeaderFormat({
|
|
7
|
+
dateTimeLabelFormats: tooltip === null || tooltip === void 0 ? void 0 : tooltip.dateTimeLabelFormats,
|
|
8
|
+
seriesData,
|
|
9
|
+
yAxes,
|
|
10
|
+
xAxis,
|
|
11
|
+
}) });
|
|
7
12
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { ChartSeriesData, ChartTooltip, ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
2
2
|
export type HoveredValue = string | number | null | undefined;
|
|
3
3
|
export declare function getXRowData(data: ChartSeriesData, xAxis?: ChartXAxis | null): string | number | null | undefined;
|
|
4
|
-
export declare function getDefaultValueFormat({ axis, closestPointsRange, }: {
|
|
4
|
+
export declare function getDefaultValueFormat({ axis, closestPointsRange, dateTimeLabelFormats, }: {
|
|
5
5
|
axis?: ChartXAxis | ChartYAxis | null;
|
|
6
6
|
closestPointsRange?: number;
|
|
7
|
+
dateTimeLabelFormats?: ChartTooltip['dateTimeLabelFormats'];
|
|
7
8
|
}): ValueFormat | undefined;
|
|
8
9
|
export declare const getMeasureValue: ({ data, xAxis, yAxis, headerFormat, }: {
|
|
9
10
|
data: TooltipDataChunk[];
|
|
@@ -21,7 +21,7 @@ export function getXRowData(data, xAxis) {
|
|
|
21
21
|
function getYRowData(data, yAxis) {
|
|
22
22
|
return getRowData('y', data, yAxis);
|
|
23
23
|
}
|
|
24
|
-
export function getDefaultValueFormat({ axis, closestPointsRange, }) {
|
|
24
|
+
export function getDefaultValueFormat({ axis, closestPointsRange, dateTimeLabelFormats, }) {
|
|
25
25
|
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
26
26
|
case 'linear':
|
|
27
27
|
case 'logarithmic': {
|
|
@@ -32,7 +32,7 @@ export function getDefaultValueFormat({ axis, closestPointsRange, }) {
|
|
|
32
32
|
case 'datetime': {
|
|
33
33
|
return {
|
|
34
34
|
type: 'date',
|
|
35
|
-
format: getDefaultDateFormat(closestPointsRange),
|
|
35
|
+
format: getDefaultDateFormat(closestPointsRange, dateTimeLabelFormats),
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
default:
|
|
@@ -17,15 +17,18 @@ const CLIP_PATH_BY_SERIES_TYPE = {
|
|
|
17
17
|
[SERIES_TYPE.Scatter]: true,
|
|
18
18
|
};
|
|
19
19
|
export function useRangeSlider(props) {
|
|
20
|
-
const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, legendConfig, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
20
|
+
const { activeLegendItems, boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, legendConfig, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
21
21
|
const filteredPreparedSeries = React.useMemo(() => {
|
|
22
22
|
return preparedSeries.filter((s) => {
|
|
23
|
+
if (s.legend.enabled && !activeLegendItems.includes(s.legend.groupId)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
23
26
|
if ('rangeSlider' in s && !s.rangeSlider.visible) {
|
|
24
27
|
return false;
|
|
25
28
|
}
|
|
26
29
|
return true;
|
|
27
30
|
});
|
|
28
|
-
}, [preparedSeries]);
|
|
31
|
+
}, [preparedSeries, activeLegendItems]);
|
|
29
32
|
const { xAxis: preparedXAxis, yAxis: preparedYAxis } = useAxis({
|
|
30
33
|
boundsHeight: preparedRangeSlider.height,
|
|
31
34
|
height,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TOOLTIP_TOTALS_BUILT_IN_AGGREGATION } from '../../constants';
|
|
2
|
+
import type { DateTimeLabelFormats } from '../../utils/chart/time';
|
|
2
3
|
import type { MeaningfulAny } from '../misc';
|
|
3
4
|
import type { AreaSeries, AreaSeriesData } from './area';
|
|
4
5
|
import type { AxisPlotBand, AxisPlotLine, ChartXAxis, ChartYAxis } from './axis';
|
|
@@ -201,4 +202,36 @@ export interface ChartTooltip<T = MeaningfulAny> {
|
|
|
201
202
|
*/
|
|
202
203
|
direction?: 'asc' | 'desc';
|
|
203
204
|
} | ChartTooltipSortComparator<T>;
|
|
205
|
+
/**
|
|
206
|
+
* Per-granularity display formats for the default datetime tooltip header.
|
|
207
|
+
* Ignored when `headerFormat` is set.
|
|
208
|
+
*
|
|
209
|
+
* Each value is a format string in the same form as the `format` argument to
|
|
210
|
+
* [`DateTime#format`](https://gravity-ui.github.io/date-utils/pages/api/DateTime/overview.html) in `@gravity-ui/date-utils`
|
|
211
|
+
* (see the **`FormatInput`** type there): Day.js–style tokens, e.g. `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`, `SSS`, `MMM`.
|
|
212
|
+
*
|
|
213
|
+
* Partial objects are merged with the built-in `DATETIME_LABEL_FORMATS`; omitted keys keep defaults.
|
|
214
|
+
* @example ISO-like date and time
|
|
215
|
+
* ```ts
|
|
216
|
+
* dateTimeLabelFormats: { day: 'YYYY-MM-DD', hour: 'YYYY-MM-DD HH:mm', minute: 'YYYY-MM-DD HH:mm' }
|
|
217
|
+
* ```
|
|
218
|
+
* @example US-style calendar date
|
|
219
|
+
* ```ts
|
|
220
|
+
* dateTimeLabelFormats: { day: 'MM/DD/YYYY', week: 'MM/DD/YYYY' }
|
|
221
|
+
* ```
|
|
222
|
+
* @example Only sub-day precision (other units stay defaults)
|
|
223
|
+
* ```ts
|
|
224
|
+
* dateTimeLabelFormats: { hour: 'HH:mm', minute: 'HH:mm', second: 'HH:mm:ss' }
|
|
225
|
+
* ```
|
|
226
|
+
* @example Coarse ranges: short month and full year
|
|
227
|
+
* ```ts
|
|
228
|
+
* dateTimeLabelFormats: { month: 'YYYY-MM', year: 'YYYY' }
|
|
229
|
+
* ```
|
|
230
|
+
* @example Localized-style month label with day precision unchanged
|
|
231
|
+
* ```ts
|
|
232
|
+
* dateTimeLabelFormats: { month: 'MMMM YYYY' }
|
|
233
|
+
* ```
|
|
234
|
+
* @see https://gravity-ui.github.io/date-utils/pages/api/DateTime/overview.html
|
|
235
|
+
*/
|
|
236
|
+
dateTimeLabelFormats?: DateTimeLabelFormats;
|
|
204
237
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
export declare const TIME_UNITS:
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export declare const TIME_UNITS: {
|
|
2
|
+
readonly millisecond: 1;
|
|
3
|
+
readonly second: 1000;
|
|
4
|
+
readonly minute: 60000;
|
|
5
|
+
readonly hour: 3600000;
|
|
6
|
+
readonly day: number;
|
|
7
|
+
readonly week: number;
|
|
8
|
+
readonly month: number;
|
|
9
|
+
readonly year: number;
|
|
10
|
+
};
|
|
11
|
+
export type TimeUnit = keyof typeof TIME_UNITS;
|
|
12
|
+
export declare const DATETIME_LABEL_FORMATS: Record<TimeUnit, string>;
|
|
13
|
+
export type DateTimeLabelFormats = Partial<Record<TimeUnit, string>>;
|
|
14
|
+
export declare function getDefaultDateFormat(range?: number, overrides?: DateTimeLabelFormats): string;
|
|
4
15
|
export declare function getDefaultTimeOnlyFormat(step: number): string;
|
|
@@ -23,14 +23,15 @@ function getTimeUnit(range) {
|
|
|
23
23
|
const index = units.findIndex((unit) => range < TIME_UNITS[unit]);
|
|
24
24
|
return index === -1 ? 'year' : units[index - 1];
|
|
25
25
|
}
|
|
26
|
-
export function getDefaultDateFormat(range) {
|
|
26
|
+
export function getDefaultDateFormat(range, overrides) {
|
|
27
|
+
const formats = Object.assign(Object.assign({}, DATETIME_LABEL_FORMATS), overrides);
|
|
27
28
|
if (range) {
|
|
28
29
|
const unit = getTimeUnit(range);
|
|
29
|
-
if (unit in
|
|
30
|
-
return
|
|
30
|
+
if (unit in formats) {
|
|
31
|
+
return formats[unit];
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
return
|
|
34
|
+
return formats.day;
|
|
34
35
|
}
|
|
35
36
|
export function getDefaultTimeOnlyFormat(step) {
|
|
36
37
|
if (step < TIME_UNITS.second) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { ChartSeries, ChartXAxis, ChartYAxis } from '../../types';
|
|
2
|
-
export declare function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, }: {
|
|
1
|
+
import type { ChartSeries, ChartTooltip, ChartXAxis, ChartYAxis } from '../../types';
|
|
2
|
+
export declare function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, dateTimeLabelFormats, }: {
|
|
3
3
|
seriesData: ChartSeries[];
|
|
4
4
|
yAxes?: ChartYAxis[];
|
|
5
5
|
xAxis?: ChartXAxis;
|
|
6
|
+
dateTimeLabelFormats?: ChartTooltip['dateTimeLabelFormats'];
|
|
6
7
|
}): import("../..").ValueFormat | undefined;
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { getDefaultValueFormat } from '../../components/Tooltip/DefaultTooltipContent/utils';
|
|
2
2
|
import { getMinSpaceBetween } from './array';
|
|
3
3
|
import { getDomainDataXBySeries, getDomainDataYBySeries } from './common';
|
|
4
|
-
export function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, }) {
|
|
4
|
+
export function getDefaultTooltipHeaderFormat({ seriesData, yAxes, xAxis, dateTimeLabelFormats, }) {
|
|
5
5
|
if (seriesData.every((item) => ['pie', 'treemap', 'waterfall', 'sankey', 'radar', 'heatmap', 'funnel'].includes(item.type))) {
|
|
6
6
|
return undefined;
|
|
7
7
|
}
|
|
8
8
|
if (seriesData.some((item) => item.type === 'bar-y')) {
|
|
9
9
|
const domainData = getDomainDataYBySeries(seriesData);
|
|
10
10
|
const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
|
|
11
|
-
return getDefaultValueFormat({
|
|
11
|
+
return getDefaultValueFormat({
|
|
12
|
+
axis: yAxes === null || yAxes === void 0 ? void 0 : yAxes[0],
|
|
13
|
+
closestPointsRange,
|
|
14
|
+
dateTimeLabelFormats,
|
|
15
|
+
});
|
|
12
16
|
}
|
|
13
17
|
const domainData = getDomainDataXBySeries(seriesData);
|
|
14
18
|
const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
|
|
15
|
-
return getDefaultValueFormat({ axis: xAxis, closestPointsRange });
|
|
19
|
+
return getDefaultValueFormat({ axis: xAxis, closestPointsRange, dateTimeLabelFormats });
|
|
16
20
|
}
|