@gravity-ui/charts 0.7.0 → 0.8.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/README.md +1 -1
- package/dist/cjs/components/Axis/AxisY.d.ts +1 -0
- package/dist/cjs/components/Axis/AxisY.js +55 -13
- package/dist/cjs/components/ChartInner/index.js +3 -2
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +4 -0
- package/dist/cjs/components/Legend/index.js +1 -2
- package/dist/cjs/components/PlotTitle/index.js +1 -1
- package/dist/cjs/components/PlotTitle/styles.css +1 -1
- package/dist/cjs/components/Tooltip/DefaultContent.js +19 -3
- package/dist/cjs/constants/index.d.ts +1 -0
- package/dist/cjs/constants/index.js +1 -0
- package/dist/cjs/hooks/useChartOptions/types.d.ts +11 -1
- package/dist/cjs/hooks/useChartOptions/x-axis.js +1 -0
- package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -1
- package/dist/cjs/hooks/useSeries/prepare-bar-x.d.ts +2 -1
- package/dist/cjs/hooks/useSeries/prepare-bar-x.js +2 -1
- package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +2 -1
- package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
- package/dist/cjs/hooks/useSeries/prepare-pie.js +2 -2
- package/dist/cjs/hooks/useSeries/prepare-sankey.d.ts +11 -0
- package/dist/cjs/hooks/useSeries/prepare-sankey.js +38 -0
- package/dist/cjs/hooks/useSeries/prepareSeries.js +21 -2
- package/dist/cjs/hooks/useSeries/types.d.ts +12 -2
- package/dist/cjs/hooks/useSeries/utils.js +1 -1
- package/dist/cjs/hooks/useShapes/bar-x/index.js +16 -2
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +2 -1
- package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-y/index.js +16 -2
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +2 -1
- package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/index.js +19 -0
- package/dist/cjs/hooks/useShapes/line/index.js +2 -2
- package/dist/cjs/hooks/useShapes/pie/index.js +3 -3
- package/dist/cjs/hooks/useShapes/pie/prepare-data.js +37 -35
- package/dist/cjs/hooks/useShapes/pie/types.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/sankey/index.d.ts +12 -0
- package/dist/cjs/hooks/useShapes/sankey/index.js +67 -0
- package/dist/cjs/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
- package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +72 -0
- package/dist/cjs/hooks/useShapes/sankey/types.d.ts +33 -0
- package/dist/cjs/hooks/useShapes/sankey/types.js +1 -0
- package/dist/cjs/hooks/useShapes/styles.css +2 -2
- package/dist/cjs/hooks/useShapes/utils.d.ts +7 -2
- package/dist/cjs/hooks/useShapes/utils.js +22 -17
- package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -2
- package/dist/cjs/types/chart/axis.d.ts +24 -0
- package/dist/cjs/types/chart/bar-x.d.ts +5 -0
- package/dist/cjs/types/chart/bar-y.d.ts +5 -0
- package/dist/cjs/types/chart/pie.d.ts +2 -0
- package/dist/cjs/types/chart/sankey.d.ts +22 -0
- package/dist/cjs/types/chart/sankey.js +1 -0
- package/dist/cjs/types/chart/series.d.ts +13 -2
- package/dist/cjs/types/chart/tooltip.d.ts +7 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/utils/chart/get-closest-data.d.ts +2 -0
- package/dist/cjs/utils/chart/get-closest-data.js +39 -3
- package/dist/cjs/utils/chart/index.js +1 -1
- package/dist/cjs/utils/chart/series/index.d.ts +1 -0
- package/dist/cjs/utils/chart/series/index.js +1 -0
- package/dist/cjs/utils/chart/series/line.d.ts +2 -0
- package/dist/cjs/utils/chart/series/line.js +17 -0
- package/dist/esm/components/Axis/AxisY.d.ts +1 -0
- package/dist/esm/components/Axis/AxisY.js +55 -13
- package/dist/esm/components/ChartInner/index.js +3 -2
- package/dist/esm/components/ChartInner/useChartInnerHandlers.js +4 -0
- package/dist/esm/components/Legend/index.js +1 -2
- package/dist/esm/components/PlotTitle/index.js +1 -1
- package/dist/esm/components/PlotTitle/styles.css +1 -1
- package/dist/esm/components/Tooltip/DefaultContent.js +19 -3
- package/dist/esm/constants/index.d.ts +1 -0
- package/dist/esm/constants/index.js +1 -0
- package/dist/esm/hooks/useChartOptions/types.d.ts +11 -1
- package/dist/esm/hooks/useChartOptions/x-axis.js +1 -0
- package/dist/esm/hooks/useChartOptions/y-axis.js +9 -1
- package/dist/esm/hooks/useSeries/prepare-bar-x.d.ts +2 -1
- package/dist/esm/hooks/useSeries/prepare-bar-x.js +2 -1
- package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +2 -1
- package/dist/esm/hooks/useSeries/prepare-bar-y.js +3 -1
- package/dist/esm/hooks/useSeries/prepare-pie.js +2 -2
- package/dist/esm/hooks/useSeries/prepare-sankey.d.ts +11 -0
- package/dist/esm/hooks/useSeries/prepare-sankey.js +38 -0
- package/dist/esm/hooks/useSeries/prepareSeries.js +21 -2
- package/dist/esm/hooks/useSeries/types.d.ts +12 -2
- package/dist/esm/hooks/useSeries/utils.js +1 -1
- package/dist/esm/hooks/useShapes/bar-x/index.js +16 -2
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +2 -1
- package/dist/esm/hooks/useShapes/bar-x/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-y/index.js +16 -2
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +2 -1
- package/dist/esm/hooks/useShapes/bar-y/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/index.d.ts +2 -1
- package/dist/esm/hooks/useShapes/index.js +19 -0
- package/dist/esm/hooks/useShapes/line/index.js +2 -2
- package/dist/esm/hooks/useShapes/pie/index.js +3 -3
- package/dist/esm/hooks/useShapes/pie/prepare-data.js +37 -35
- package/dist/esm/hooks/useShapes/pie/types.d.ts +1 -1
- package/dist/esm/hooks/useShapes/sankey/index.d.ts +12 -0
- package/dist/esm/hooks/useShapes/sankey/index.js +67 -0
- package/dist/esm/hooks/useShapes/sankey/prepare-data.d.ts +7 -0
- package/dist/esm/hooks/useShapes/sankey/prepare-data.js +72 -0
- package/dist/esm/hooks/useShapes/sankey/types.d.ts +33 -0
- package/dist/esm/hooks/useShapes/sankey/types.js +1 -0
- package/dist/esm/hooks/useShapes/styles.css +2 -2
- package/dist/esm/hooks/useShapes/utils.d.ts +7 -2
- package/dist/esm/hooks/useShapes/utils.js +22 -17
- package/dist/esm/hooks/useShapes/waterfall/index.js +1 -2
- package/dist/esm/types/chart/axis.d.ts +24 -0
- package/dist/esm/types/chart/bar-x.d.ts +5 -0
- package/dist/esm/types/chart/bar-y.d.ts +5 -0
- package/dist/esm/types/chart/pie.d.ts +2 -0
- package/dist/esm/types/chart/sankey.d.ts +22 -0
- package/dist/esm/types/chart/sankey.js +1 -0
- package/dist/esm/types/chart/series.d.ts +13 -2
- package/dist/esm/types/chart/tooltip.d.ts +7 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/utils/chart/get-closest-data.d.ts +2 -0
- package/dist/esm/utils/chart/get-closest-data.js +39 -3
- package/dist/esm/utils/chart/index.js +1 -1
- package/dist/esm/utils/chart/series/index.d.ts +1 -0
- package/dist/esm/utils/chart/series/index.js +1 -0
- package/dist/esm/utils/chart/series/line.d.ts +2 -0
- package/dist/esm/utils/chart/series/line.js +17 -0
- package/package.json +3 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SeriesType } from '../../constants';
|
|
2
|
+
import type { MeaningfulAny } from '../misc';
|
|
3
|
+
import type { BaseSeries, BaseSeriesData } from './base';
|
|
4
|
+
import type { ChartLegend, RectLegendSymbolOptions } from './legend';
|
|
5
|
+
export interface SankeySeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
|
|
6
|
+
name: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
links: {
|
|
9
|
+
name: string;
|
|
10
|
+
value: number;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
export interface SankeySeries<T = MeaningfulAny> extends BaseSeries {
|
|
14
|
+
type: typeof SeriesType.Sankey;
|
|
15
|
+
/** The name of the series (used in legend, tooltip etc). */
|
|
16
|
+
name: string;
|
|
17
|
+
data: SankeySeriesData<T>[];
|
|
18
|
+
/** Individual series legend options. Has higher priority than legend options in widget data. */
|
|
19
|
+
legend?: ChartLegend & {
|
|
20
|
+
symbol?: RectLegendSymbolOptions;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,11 +8,12 @@ import type { Halo } from './halo';
|
|
|
8
8
|
import type { LineSeries, LineSeriesData } from './line';
|
|
9
9
|
import type { PointMarkerOptions } from './marker';
|
|
10
10
|
import type { PieSeries, PieSeriesData } from './pie';
|
|
11
|
+
import type { SankeySeries, SankeySeriesData } from './sankey';
|
|
11
12
|
import type { ScatterSeries, ScatterSeriesData } from './scatter';
|
|
12
13
|
import type { TreemapSeries, TreemapSeriesData } from './treemap';
|
|
13
14
|
import type { WaterfallSeries, WaterfallSeriesData } from './waterfall';
|
|
14
|
-
export type ChartSeries<T = MeaningfulAny> = ScatterSeries<T> | PieSeries<T> | BarXSeries<T> | BarYSeries<T> | LineSeries<T> | AreaSeries<T> | TreemapSeries<T> | WaterfallSeries<T>;
|
|
15
|
-
export type ChartSeriesData<T = MeaningfulAny> = ScatterSeriesData<T> | PieSeriesData<T> | BarXSeriesData<T> | BarYSeriesData<T> | LineSeriesData<T> | AreaSeriesData<T> | TreemapSeriesData<T> | WaterfallSeriesData<T>;
|
|
15
|
+
export type ChartSeries<T = MeaningfulAny> = ScatterSeries<T> | PieSeries<T> | BarXSeries<T> | BarYSeries<T> | LineSeries<T> | AreaSeries<T> | TreemapSeries<T> | WaterfallSeries<T> | SankeySeries<T>;
|
|
16
|
+
export type ChartSeriesData<T = MeaningfulAny> = ScatterSeriesData<T> | PieSeriesData<T> | BarXSeriesData<T> | BarYSeriesData<T> | LineSeriesData<T> | AreaSeriesData<T> | TreemapSeriesData<T> | WaterfallSeriesData<T> | SankeySeriesData<T>;
|
|
16
17
|
export interface DataLabelRendererData<T = MeaningfulAny> {
|
|
17
18
|
data: ChartSeriesData<T>;
|
|
18
19
|
}
|
|
@@ -72,6 +73,11 @@ export interface ChartSeriesOptions {
|
|
|
72
73
|
* @default 0.2
|
|
73
74
|
*/
|
|
74
75
|
groupPadding?: number;
|
|
76
|
+
/**
|
|
77
|
+
* The corner radius of the border surrounding each bar.
|
|
78
|
+
* @default 0
|
|
79
|
+
*/
|
|
80
|
+
borderRadius?: number;
|
|
75
81
|
dataSorting?: {
|
|
76
82
|
/** Determines what data value should be used to sort by.
|
|
77
83
|
* Possible values are undefined to disable, "name" to sort by series name or "y"
|
|
@@ -108,6 +114,11 @@ export interface ChartSeriesOptions {
|
|
|
108
114
|
* @default 0.2
|
|
109
115
|
*/
|
|
110
116
|
groupPadding?: number;
|
|
117
|
+
/**
|
|
118
|
+
* The corner radius of the border surrounding each bar.
|
|
119
|
+
* @default 0
|
|
120
|
+
*/
|
|
121
|
+
borderRadius?: number;
|
|
111
122
|
dataSorting?: {
|
|
112
123
|
/** Determines what data value should be used to sort by.
|
|
113
124
|
* Possible values are undefined to disable, "name" to sort by series name or "x"
|
|
@@ -5,6 +5,7 @@ import type { BarXSeries, BarXSeriesData } from './bar-x';
|
|
|
5
5
|
import type { BarYSeries, BarYSeriesData } from './bar-y';
|
|
6
6
|
import type { LineSeries, LineSeriesData } from './line';
|
|
7
7
|
import type { PieSeries, PieSeriesData } from './pie';
|
|
8
|
+
import type { SankeySeries, SankeySeriesData } from './sankey';
|
|
8
9
|
import type { ScatterSeries, ScatterSeriesData } from './scatter';
|
|
9
10
|
import type { TreemapSeries, TreemapSeriesData } from './treemap';
|
|
10
11
|
import type { WaterfallSeries, WaterfallSeriesData } from './waterfall';
|
|
@@ -52,11 +53,16 @@ export interface TooltipDataChunkTreemap<T = MeaningfulAny> {
|
|
|
52
53
|
data: TreemapSeriesData<T>;
|
|
53
54
|
series: TreemapSeries<T>;
|
|
54
55
|
}
|
|
56
|
+
export interface TooltipDataChunkSankey<T = MeaningfulAny> {
|
|
57
|
+
data: SankeySeriesData<T>;
|
|
58
|
+
target?: SankeySeriesData<T>;
|
|
59
|
+
series: SankeySeries<T>;
|
|
60
|
+
}
|
|
55
61
|
export interface TooltipDataChunkWaterfall<T = MeaningfulAny> {
|
|
56
62
|
data: WaterfallSeriesData<T>;
|
|
57
63
|
series: WaterfallSeries<T>;
|
|
58
64
|
}
|
|
59
|
-
export type TooltipDataChunk<T = MeaningfulAny> = (TooltipDataChunkBarX<T> | TooltipDataChunkBarY<T> | TooltipDataChunkPie<T> | TooltipDataChunkScatter<T> | TooltipDataChunkLine<T> | TooltipDataChunkArea<T> | TooltipDataChunkTreemap<T> | TooltipDataChunkWaterfall<T>) & {
|
|
65
|
+
export type TooltipDataChunk<T = MeaningfulAny> = (TooltipDataChunkBarX<T> | TooltipDataChunkBarY<T> | TooltipDataChunkPie<T> | TooltipDataChunkScatter<T> | TooltipDataChunkLine<T> | TooltipDataChunkArea<T> | TooltipDataChunkTreemap<T> | TooltipDataChunkSankey<T> | TooltipDataChunkWaterfall<T>) & {
|
|
60
66
|
closest?: boolean;
|
|
61
67
|
};
|
|
62
68
|
export interface ChartTooltipRendererArgs<T = MeaningfulAny> {
|
|
@@ -25,6 +25,7 @@ export * from './chart/tooltip';
|
|
|
25
25
|
export * from './chart/halo';
|
|
26
26
|
export * from './chart/treemap';
|
|
27
27
|
export * from './chart/waterfall';
|
|
28
|
+
export * from './chart/sankey';
|
|
28
29
|
export interface ChartData<T = MeaningfulAny> {
|
|
29
30
|
/**
|
|
30
31
|
* General options for the chart.
|
package/dist/cjs/types/index.js
CHANGED
|
@@ -35,7 +35,7 @@ function getSeriesType(shapeData) {
|
|
|
35
35
|
return get(shapeData, 'series.type') || get(shapeData, 'point.series.type');
|
|
36
36
|
}
|
|
37
37
|
export function getClosestPoints(args) {
|
|
38
|
-
const { position, shapesData } = args;
|
|
38
|
+
const { position, shapesData, boundsHeight, boundsWidth } = args;
|
|
39
39
|
const [pointerX, pointerY] = position;
|
|
40
40
|
const result = [];
|
|
41
41
|
const groups = groupBy(shapesData, getSeriesType);
|
|
@@ -135,13 +135,13 @@ export function getClosestPoints(args) {
|
|
|
135
135
|
case 'pie': {
|
|
136
136
|
const points = list.map((d) => d.segments).flat();
|
|
137
137
|
const closestPoint = points.find((p) => {
|
|
138
|
-
const { center
|
|
138
|
+
const { center } = p.data.pie;
|
|
139
139
|
const x = pointerX - center[0];
|
|
140
140
|
const y = pointerY - center[1];
|
|
141
141
|
let angle = Math.atan2(y, x) + 0.5 * Math.PI;
|
|
142
142
|
angle = angle < 0 ? Math.PI * 2 + angle : angle;
|
|
143
143
|
const polarRadius = Math.sqrt(x * x + y * y);
|
|
144
|
-
return angle >= p.startAngle && angle <= p.endAngle && polarRadius < radius;
|
|
144
|
+
return (angle >= p.startAngle && angle <= p.endAngle && polarRadius < p.data.radius);
|
|
145
145
|
});
|
|
146
146
|
if (closestPoint) {
|
|
147
147
|
result.push({
|
|
@@ -166,7 +166,43 @@ export function getClosestPoints(args) {
|
|
|
166
166
|
}
|
|
167
167
|
break;
|
|
168
168
|
}
|
|
169
|
+
case 'sankey': {
|
|
170
|
+
const [data] = list;
|
|
171
|
+
const closestLink = data.links.find((d) => {
|
|
172
|
+
var _a;
|
|
173
|
+
return isInsidePath({
|
|
174
|
+
path: (_a = d.path) !== null && _a !== void 0 ? _a : '',
|
|
175
|
+
strokeWidth: d.strokeWidth,
|
|
176
|
+
point: [pointerX, pointerY],
|
|
177
|
+
width: boundsWidth,
|
|
178
|
+
height: boundsHeight,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
if (closestLink) {
|
|
182
|
+
result.push({
|
|
183
|
+
data: closestLink.source,
|
|
184
|
+
target: closestLink.target,
|
|
185
|
+
series: data.series,
|
|
186
|
+
closest: true,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
169
191
|
}
|
|
170
192
|
});
|
|
171
193
|
return result;
|
|
172
194
|
}
|
|
195
|
+
function isInsidePath(args) {
|
|
196
|
+
const { path, point, width, height, strokeWidth } = args;
|
|
197
|
+
const canvas = document.createElement('canvas');
|
|
198
|
+
canvas.width = width;
|
|
199
|
+
canvas.height = height;
|
|
200
|
+
const ctx = canvas.getContext('2d');
|
|
201
|
+
if (ctx) {
|
|
202
|
+
ctx.lineWidth = strokeWidth;
|
|
203
|
+
const path2D = new Path2D(path);
|
|
204
|
+
ctx.stroke(path2D);
|
|
205
|
+
return ctx.isPointInPath(path2D, ...point) || ctx.isPointInStroke(path2D, ...point);
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
@@ -15,7 +15,7 @@ export * from './legend';
|
|
|
15
15
|
export * from './symbol';
|
|
16
16
|
export * from './series';
|
|
17
17
|
export * from './color';
|
|
18
|
-
const CHARTS_WITHOUT_AXIS = ['pie', 'treemap'];
|
|
18
|
+
const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey'];
|
|
19
19
|
export const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS = [
|
|
20
20
|
'bar-x',
|
|
21
21
|
'area',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function getLineDashArray(dashStyle, strokeWidth = 2) {
|
|
2
|
+
const value = dashStyle.toLowerCase();
|
|
3
|
+
const arrayValue = value
|
|
4
|
+
.replace('shortdashdotdot', '3,1,1,1,1,1,')
|
|
5
|
+
.replace('shortdashdot', '3,1,1,1')
|
|
6
|
+
.replace('shortdot', '1,1,')
|
|
7
|
+
.replace('shortdash', '3,1,')
|
|
8
|
+
.replace('longdash', '8,3,')
|
|
9
|
+
.replace(/dot/g, '1,3,')
|
|
10
|
+
.replace('dash', '4,3,')
|
|
11
|
+
.replace(/,$/, '')
|
|
12
|
+
.split(',')
|
|
13
|
+
.map((part) => {
|
|
14
|
+
return `${parseInt(part, 10) * strokeWidth}`;
|
|
15
|
+
});
|
|
16
|
+
return arrayValue.join(',').replace(/NaN/g, 'none');
|
|
17
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { axisLeft, axisRight, line, select } from 'd3';
|
|
3
|
-
import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getClosestPointsRange, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
|
|
3
|
+
import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
|
|
4
4
|
import './styles.css';
|
|
5
5
|
const b = block('d3-axis');
|
|
6
6
|
function transformLabel(args) {
|
|
@@ -79,7 +79,7 @@ function getTitlePosition(args) {
|
|
|
79
79
|
return { x, y };
|
|
80
80
|
}
|
|
81
81
|
export const AxisY = (props) => {
|
|
82
|
-
const { axes, width, height: totalHeight, scale, split } = props;
|
|
82
|
+
const { axes, width, height: totalHeight, scale, split, plotRef } = props;
|
|
83
83
|
const height = getAxisHeight({ split, boundsHeight: totalHeight });
|
|
84
84
|
const ref = React.useRef(null);
|
|
85
85
|
React.useEffect(() => {
|
|
@@ -88,26 +88,34 @@ export const AxisY = (props) => {
|
|
|
88
88
|
}
|
|
89
89
|
const svgElement = select(ref.current);
|
|
90
90
|
svgElement.selectAll('*').remove();
|
|
91
|
+
const getAxisPosition = (axis) => {
|
|
92
|
+
var _a;
|
|
93
|
+
const top = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
|
|
94
|
+
if (axis.position === 'left') {
|
|
95
|
+
return `translate(0, ${top}px)`;
|
|
96
|
+
}
|
|
97
|
+
return `translate(${width}px, 0)`;
|
|
98
|
+
};
|
|
99
|
+
const plotLines = axes.reduce((acc, axis) => {
|
|
100
|
+
if (axis.plotLines.length) {
|
|
101
|
+
acc.push(...axis.plotLines.map((plotLine) => {
|
|
102
|
+
return Object.assign(Object.assign({}, plotLine), { transform: getAxisPosition(axis) });
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
return acc;
|
|
106
|
+
}, []);
|
|
91
107
|
const axisSelection = svgElement
|
|
92
108
|
.selectAll('axis')
|
|
93
109
|
.data(axes)
|
|
94
110
|
.join('g')
|
|
95
111
|
.attr('class', b())
|
|
96
|
-
.style('transform', (d) =>
|
|
97
|
-
var _a;
|
|
98
|
-
const top = ((_a = split.plots[d.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
|
|
99
|
-
if (d.position === 'left') {
|
|
100
|
-
return `translate(0, ${top}px)`;
|
|
101
|
-
}
|
|
102
|
-
return `translate(${width}px, 0)`;
|
|
103
|
-
});
|
|
112
|
+
.style('transform', (d) => getAxisPosition(d));
|
|
104
113
|
axisSelection.each((d, index, node) => {
|
|
105
114
|
const seriesScale = scale[index];
|
|
106
115
|
const axisItem = select(node[index]);
|
|
116
|
+
const axisScale = seriesScale;
|
|
107
117
|
const yAxisGenerator = getAxisGenerator({
|
|
108
|
-
axisGenerator: d.position === 'left'
|
|
109
|
-
? axisLeft(seriesScale)
|
|
110
|
-
: axisRight(seriesScale),
|
|
118
|
+
axisGenerator: d.position === 'left' ? axisLeft(axisScale) : axisRight(axisScale),
|
|
111
119
|
preparedAxis: d,
|
|
112
120
|
height,
|
|
113
121
|
width,
|
|
@@ -148,6 +156,40 @@ export const AxisY = (props) => {
|
|
|
148
156
|
})
|
|
149
157
|
.remove();
|
|
150
158
|
}
|
|
159
|
+
if (plotRef && d.plotLines.length > 0) {
|
|
160
|
+
const plotLineClassName = b('plotLine');
|
|
161
|
+
const plotLineContainer = select(plotRef.current);
|
|
162
|
+
plotLineContainer.selectAll(`.${plotLineClassName}`).remove();
|
|
163
|
+
const plotLinesSelection = plotLineContainer
|
|
164
|
+
.selectAll(`.${plotLineClassName}`)
|
|
165
|
+
.data(plotLines)
|
|
166
|
+
.join('g')
|
|
167
|
+
.attr('class', plotLineClassName)
|
|
168
|
+
.style('transform', (plotLine) => plotLine.transform);
|
|
169
|
+
plotLinesSelection
|
|
170
|
+
.append('path')
|
|
171
|
+
.attr('d', (plotLine) => {
|
|
172
|
+
const plotLineValue = Number(axisScale(plotLine.value));
|
|
173
|
+
const points = [
|
|
174
|
+
[0, plotLineValue],
|
|
175
|
+
[width, plotLineValue],
|
|
176
|
+
];
|
|
177
|
+
return line()(points);
|
|
178
|
+
})
|
|
179
|
+
.attr('stroke', (plotLine) => plotLine.color)
|
|
180
|
+
.attr('stroke-width', (plotLine) => plotLine.width)
|
|
181
|
+
.attr('stroke-dasharray', (plotLine) => getLineDashArray(plotLine.dashStyle, plotLine.width))
|
|
182
|
+
.attr('opacity', (plotLine) => plotLine.opacity);
|
|
183
|
+
plotLinesSelection.each((plotLineData, i, nodes) => {
|
|
184
|
+
const plotLineSelection = select(nodes[i]);
|
|
185
|
+
if (plotLineData.layerPlacement === 'before') {
|
|
186
|
+
plotLineSelection.lower();
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
plotLineSelection.raise();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
151
193
|
return axisItem;
|
|
152
194
|
});
|
|
153
195
|
axisSelection
|
|
@@ -15,6 +15,7 @@ export const ChartInner = (props) => {
|
|
|
15
15
|
const { width, height, data } = props;
|
|
16
16
|
const svgRef = React.useRef(null);
|
|
17
17
|
const htmlLayerRef = React.useRef(null);
|
|
18
|
+
const plotRef = React.useRef(null);
|
|
18
19
|
const dispatcher = React.useMemo(() => getD3Dispatcher(), []);
|
|
19
20
|
const { boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, legendConfig, legendItems, preparedSeries, preparedSplit, preparedLegend, prevHeight, prevWidth, shapes, shapesData, title, tooltip, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { dispatcher, htmlLayout: htmlLayerRef.current }));
|
|
20
21
|
const { tooltipPinned, togglePinTooltip, unpinTooltip } = useChartInnerState({
|
|
@@ -63,9 +64,9 @@ export const ChartInner = (props) => {
|
|
|
63
64
|
React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit.plots.map((plot, index) => {
|
|
64
65
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
65
66
|
})),
|
|
66
|
-
React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})
|
|
67
|
+
React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
|
|
67
68
|
xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length) && (React.createElement(React.Fragment, null,
|
|
68
|
-
React.createElement(AxisY, { axes: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale, split: preparedSplit }),
|
|
69
|
+
React.createElement(AxisY, { axes: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale, split: preparedSplit, plotRef: plotRef }),
|
|
69
70
|
React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
|
|
70
71
|
React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, split: preparedSplit })))),
|
|
71
72
|
shapes),
|
|
@@ -24,6 +24,8 @@ export function useChartInnerHandlers(props) {
|
|
|
24
24
|
const closest = getClosestPoints({
|
|
25
25
|
position: [x, y],
|
|
26
26
|
shapesData,
|
|
27
|
+
boundsHeight,
|
|
28
|
+
boundsWidth,
|
|
27
29
|
});
|
|
28
30
|
dispatcher.call(EventType.HOVER_SHAPE, event.target, closest, [pointerX, pointerY]);
|
|
29
31
|
dispatcher.call(EventType.POINTERMOVE_CHART, {}, {
|
|
@@ -65,6 +67,8 @@ export function useChartInnerHandlers(props) {
|
|
|
65
67
|
const items = getClosestPoints({
|
|
66
68
|
position: [x, y],
|
|
67
69
|
shapesData,
|
|
70
|
+
boundsHeight,
|
|
71
|
+
boundsWidth,
|
|
68
72
|
});
|
|
69
73
|
const selected = items === null || items === void 0 ? void 0 : items.find((item) => item.closest);
|
|
70
74
|
if (!selected) {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { line as lineGenerator, scaleLinear, select, symbol } from 'd3';
|
|
3
3
|
import { CONTINUOUS_LEGEND_SIZE } from '../../constants';
|
|
4
|
-
import { getLineDashArray } from '../../hooks/useShapes/utils';
|
|
5
4
|
import { formatNumber } from '../../libs';
|
|
6
|
-
import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getSymbol, } from '../../utils';
|
|
5
|
+
import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getLineDashArray, getSymbol, } from '../../utils';
|
|
7
6
|
import { axisBottom } from '../../utils/chart/axis-generators';
|
|
8
7
|
import './styles.css';
|
|
9
8
|
const b = block('d3-legend');
|
|
@@ -3,7 +3,7 @@ import { dateTime } from '@gravity-ui/date-utils';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { formatNumber } from '../../libs';
|
|
5
5
|
import { block, getDataCategoryValue, getWaterfallPointSubtotal } from '../../utils';
|
|
6
|
-
const b = block('
|
|
6
|
+
const b = block('tooltip');
|
|
7
7
|
const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
|
|
8
8
|
const getRowData = (fieldName, data, axis) => {
|
|
9
9
|
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
@@ -29,7 +29,7 @@ const getXRowData = (data, xAxis) => getRowData('x', data, xAxis);
|
|
|
29
29
|
const getYRowData = (data, yAxis) => getRowData('y', data, yAxis);
|
|
30
30
|
const getMeasureValue = (data, xAxis, yAxis) => {
|
|
31
31
|
var _a, _b;
|
|
32
|
-
if (data.every((item) => ['pie', 'treemap', 'waterfall'].includes(item.series.type))) {
|
|
32
|
+
if (data.every((item) => ['pie', 'treemap', 'waterfall', 'sankey'].includes(item.series.type))) {
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
if (data.some((item) => item.series.type === 'bar-y')) {
|
|
@@ -41,7 +41,9 @@ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
|
|
|
41
41
|
const measureValue = getMeasureValue(hovered, xAxis, yAxis);
|
|
42
42
|
return (React.createElement(React.Fragment, null,
|
|
43
43
|
measureValue && React.createElement("div", null, measureValue),
|
|
44
|
-
hovered.map((
|
|
44
|
+
hovered.map((seriesItem, i) => {
|
|
45
|
+
var _a;
|
|
46
|
+
const { data, series, closest } = seriesItem;
|
|
45
47
|
const id = `${get(series, 'id')}_${i}`;
|
|
46
48
|
const color = get(series, 'color');
|
|
47
49
|
switch (series.type) {
|
|
@@ -93,6 +95,20 @@ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
|
|
|
93
95
|
"\u00A0"),
|
|
94
96
|
React.createElement("span", null, seriesData.value)));
|
|
95
97
|
}
|
|
98
|
+
case 'sankey': {
|
|
99
|
+
const { target, data: source } = seriesItem;
|
|
100
|
+
const value = (_a = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _a === void 0 ? void 0 : _a.value;
|
|
101
|
+
return (React.createElement("div", { key: id, className: b('content-row') },
|
|
102
|
+
React.createElement("div", { className: b('color'), style: { backgroundColor: source.color } }),
|
|
103
|
+
React.createElement("div", { style: { display: 'flex', gap: 8, verticalAlign: 'center' } },
|
|
104
|
+
source.name,
|
|
105
|
+
" ",
|
|
106
|
+
React.createElement("span", null, "\u2192"),
|
|
107
|
+
" ", target === null || target === void 0 ? void 0 :
|
|
108
|
+
target.name,
|
|
109
|
+
": ",
|
|
110
|
+
value)));
|
|
111
|
+
}
|
|
96
112
|
default: {
|
|
97
113
|
return null;
|
|
98
114
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DashStyle } from 'src/constants';
|
|
2
|
+
import type { AxisPlotLine, BaseTextStyle, ChartAxis, ChartAxisLabels, ChartAxisTitleAlignment, ChartAxisType, ChartData, ChartMargin } from '../../types';
|
|
2
3
|
type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style' | 'autoRotation'> & Required<Pick<ChartAxisLabels, 'enabled' | 'padding' | 'margin' | 'rotation'>> & {
|
|
3
4
|
style: BaseTextStyle;
|
|
4
5
|
rotation: number;
|
|
@@ -10,6 +11,14 @@ type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style'
|
|
|
10
11
|
export type PreparedChart = {
|
|
11
12
|
margin: ChartMargin;
|
|
12
13
|
};
|
|
14
|
+
export type PreparedAxisPlotLine = {
|
|
15
|
+
value: number;
|
|
16
|
+
color: string;
|
|
17
|
+
width: number;
|
|
18
|
+
dashStyle: DashStyle;
|
|
19
|
+
opacity: number;
|
|
20
|
+
layerPlacement: AxisPlotLine['layerPlacement'];
|
|
21
|
+
};
|
|
13
22
|
export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels'> & {
|
|
14
23
|
type: ChartAxisType;
|
|
15
24
|
labels: PreparedAxisLabels;
|
|
@@ -32,6 +41,7 @@ export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels'> & {
|
|
|
32
41
|
};
|
|
33
42
|
position: 'left' | 'right' | 'top' | 'bottom';
|
|
34
43
|
plotIndex: number;
|
|
44
|
+
plotLines: PreparedAxisPlotLine[];
|
|
35
45
|
};
|
|
36
46
|
export type PreparedTitle = ChartData['title'] & {
|
|
37
47
|
height: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import { DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
2
|
+
import { DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, DashStyle, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
3
3
|
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, getWaterfallPointSubtotal, wrapText, } from '../../utils';
|
|
4
4
|
import { createYScale } from '../useAxisScales';
|
|
5
5
|
const getAxisLabelMaxWidth = (args) => {
|
|
@@ -108,6 +108,14 @@ export const getPreparedYAxis = ({ series, yAxis, height, }) => {
|
|
|
108
108
|
},
|
|
109
109
|
position: get(axisItem, 'position', defaultAxisPosition),
|
|
110
110
|
plotIndex: get(axisItem, 'plotIndex', 0),
|
|
111
|
+
plotLines: get(axisItem, 'plotLines', []).map((d) => ({
|
|
112
|
+
value: get(d, 'value', 0),
|
|
113
|
+
color: get(d, 'color', 'var(--g-color-base-brand)'),
|
|
114
|
+
width: get(d, 'width', 1),
|
|
115
|
+
dashStyle: get(d, 'dashStyle', DashStyle.Solid),
|
|
116
|
+
opacity: get(d, 'opacity', 1),
|
|
117
|
+
layerPlacement: get(d, 'layerPlacement', 'before'),
|
|
118
|
+
})),
|
|
111
119
|
};
|
|
112
120
|
if (labelsEnabled) {
|
|
113
121
|
preparedAxis.labels.width = getAxisLabelMaxWidth({ axis: preparedAxis, series });
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ScaleOrdinal } from 'd3';
|
|
2
|
-
import type { BarXSeries } from '../../types';
|
|
2
|
+
import type { BarXSeries, ChartSeriesOptions } from '../../types';
|
|
3
3
|
import type { PreparedLegend, PreparedSeries } from './types';
|
|
4
4
|
type PrepareBarXSeriesArgs = {
|
|
5
5
|
colorScale: ScaleOrdinal<string, string>;
|
|
6
6
|
series: BarXSeries[];
|
|
7
7
|
legend: PreparedLegend;
|
|
8
|
+
seriesOptions?: ChartSeriesOptions;
|
|
8
9
|
};
|
|
9
10
|
export declare function prepareBarXSeries(args: PrepareBarXSeriesArgs): PreparedSeries[];
|
|
10
11
|
export {};
|
|
@@ -3,7 +3,7 @@ import { getUniqId } from '../../utils';
|
|
|
3
3
|
import { DEFAULT_DATALABELS_PADDING, DEFAULT_DATALABELS_STYLE } from './constants';
|
|
4
4
|
import { getSeriesStackId, prepareLegendSymbol } from './utils';
|
|
5
5
|
export function prepareBarXSeries(args) {
|
|
6
|
-
const { colorScale, series: seriesList, legend } = args;
|
|
6
|
+
const { colorScale, series: seriesList, seriesOptions, legend } = args;
|
|
7
7
|
return seriesList.map((series) => {
|
|
8
8
|
var _a, _b, _c, _d, _e;
|
|
9
9
|
const name = series.name || '';
|
|
@@ -33,6 +33,7 @@ export function prepareBarXSeries(args) {
|
|
|
33
33
|
},
|
|
34
34
|
cursor: get(series, 'cursor', null),
|
|
35
35
|
yAxis: get(series, 'yAxis', 0),
|
|
36
|
+
borderRadius: get(series, 'borderRadius', get(seriesOptions, 'bar-x.borderRadius', 0)),
|
|
36
37
|
};
|
|
37
38
|
}, []);
|
|
38
39
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ScaleOrdinal } from 'd3';
|
|
2
|
-
import type { BarYSeries } from '../../types';
|
|
2
|
+
import type { BarYSeries, ChartSeriesOptions } from '../../types';
|
|
3
3
|
import type { PreparedLegend, PreparedSeries } from './types';
|
|
4
4
|
type PrepareBarYSeriesArgs = {
|
|
5
5
|
colorScale: ScaleOrdinal<string, string>;
|
|
6
6
|
series: BarYSeries[];
|
|
7
7
|
legend: PreparedLegend;
|
|
8
|
+
seriesOptions?: ChartSeriesOptions;
|
|
8
9
|
};
|
|
9
10
|
export declare function prepareBarYSeries(args: PrepareBarYSeriesArgs): PreparedSeries[];
|
|
10
11
|
export {};
|
|
@@ -24,8 +24,9 @@ function prepareDataLabels(series) {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
export function prepareBarYSeries(args) {
|
|
27
|
-
const { colorScale, series: seriesList, legend } = args;
|
|
27
|
+
const { colorScale, series: seriesList, seriesOptions, legend } = args;
|
|
28
28
|
return seriesList.map((series) => {
|
|
29
|
+
var _a, _b, _c;
|
|
29
30
|
const name = series.name || '';
|
|
30
31
|
const color = series.color || colorScale(name);
|
|
31
32
|
return {
|
|
@@ -43,6 +44,7 @@ export function prepareBarYSeries(args) {
|
|
|
43
44
|
stackId: getSeriesStackId(series),
|
|
44
45
|
dataLabels: prepareDataLabels(series),
|
|
45
46
|
cursor: get(series, 'cursor', null),
|
|
47
|
+
borderRadius: (_c = (_a = series.borderRadius) !== null && _a !== void 0 ? _a : (_b = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _b === void 0 ? void 0 : _b.borderRadius) !== null && _c !== void 0 ? _c : 0,
|
|
46
48
|
};
|
|
47
49
|
}, []);
|
|
48
50
|
}
|
|
@@ -11,7 +11,7 @@ export function preparePieSeries(args) {
|
|
|
11
11
|
const stackId = getUniqId();
|
|
12
12
|
const seriesHoverState = get(seriesOptions, 'pie.states.hover');
|
|
13
13
|
const preparedSeries = series.data.map((dataItem, i) => {
|
|
14
|
-
var _a, _b, _c;
|
|
14
|
+
var _a, _b, _c, _d, _e;
|
|
15
15
|
const result = {
|
|
16
16
|
type: 'pie',
|
|
17
17
|
data: dataItem,
|
|
@@ -40,7 +40,7 @@ export function preparePieSeries(args) {
|
|
|
40
40
|
borderColor: series.borderColor || '',
|
|
41
41
|
borderRadius: (_b = series.borderRadius) !== null && _b !== void 0 ? _b : 0,
|
|
42
42
|
borderWidth: (_c = series.borderWidth) !== null && _c !== void 0 ? _c : 1,
|
|
43
|
-
radius: series.radius
|
|
43
|
+
radius: (_e = (_d = dataItem.radius) !== null && _d !== void 0 ? _d : series.radius) !== null && _e !== void 0 ? _e : '100%',
|
|
44
44
|
innerRadius: series.innerRadius || 0,
|
|
45
45
|
stackId,
|
|
46
46
|
states: {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScaleOrdinal } from 'd3';
|
|
2
|
+
import type { ChartSeriesOptions, SankeySeries } from '../../types';
|
|
3
|
+
import type { PreparedLegend, PreparedSankeySeries } from './types';
|
|
4
|
+
type PrepareSankeySeriesArgs = {
|
|
5
|
+
colorScale: ScaleOrdinal<string, string>;
|
|
6
|
+
legend: PreparedLegend;
|
|
7
|
+
series: SankeySeries[];
|
|
8
|
+
seriesOptions?: ChartSeriesOptions;
|
|
9
|
+
};
|
|
10
|
+
export declare function prepareSankeySeries(args: PrepareSankeySeriesArgs): PreparedSankeySeries[];
|
|
11
|
+
export {};
|