@gravity-ui/charts 0.8.0 → 0.10.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 +0 -3
- package/dist/cjs/components/Axis/AxisX.d.ts +1 -0
- package/dist/cjs/components/Axis/AxisX.js +43 -6
- package/dist/cjs/components/Axis/AxisY.js +9 -5
- package/dist/cjs/components/Axis/styles.css +5 -5
- package/dist/cjs/components/ChartInner/index.js +5 -4
- package/dist/cjs/components/ChartInner/styles.css +4 -4
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +3 -4
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +3 -2
- package/dist/cjs/components/Legend/index.js +1 -1
- package/dist/cjs/components/Legend/styles.css +14 -14
- package/dist/cjs/components/Title/index.js +1 -1
- package/dist/cjs/components/Title/styles.css +1 -1
- package/dist/cjs/components/Tooltip/DefaultContent.js +18 -3
- package/dist/cjs/constants/defaults/series-options.js +12 -0
- package/dist/cjs/constants/index.d.ts +1 -0
- package/dist/cjs/constants/index.js +1 -0
- package/dist/cjs/hooks/useChartOptions/tooltip.js +2 -1
- package/dist/cjs/hooks/useChartOptions/types.d.ts +2 -1
- package/dist/cjs/hooks/useChartOptions/x-axis.js +9 -2
- package/dist/cjs/hooks/useSeries/constants.js +1 -1
- package/dist/cjs/hooks/useSeries/prepare-radar.d.ts +16 -0
- package/dist/cjs/hooks/useSeries/prepare-radar.js +63 -0
- package/dist/cjs/hooks/useSeries/prepareSeries.js +8 -0
- package/dist/cjs/hooks/useSeries/types.d.ts +35 -2
- package/dist/cjs/hooks/useShapes/area/index.js +1 -1
- package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/index.js +12 -0
- package/dist/cjs/hooks/useShapes/line/index.js +1 -1
- package/dist/cjs/hooks/useShapes/marker.d.ts +3 -2
- package/dist/cjs/hooks/useShapes/marker.js +1 -1
- package/dist/cjs/hooks/useShapes/pie/index.js +1 -1
- package/dist/cjs/hooks/useShapes/radar/index.d.ts +12 -0
- package/dist/cjs/hooks/useShapes/radar/index.js +136 -0
- package/dist/cjs/hooks/useShapes/radar/prepare-data.d.ts +9 -0
- package/dist/cjs/hooks/useShapes/radar/prepare-data.js +155 -0
- package/dist/cjs/hooks/useShapes/radar/types.d.ts +58 -0
- package/dist/cjs/hooks/useShapes/radar/types.js +1 -0
- package/dist/cjs/hooks/useShapes/scatter/index.js +1 -1
- package/dist/cjs/hooks/useShapes/styles.css +9 -5
- package/dist/cjs/hooks/useShapes/treemap/index.js +1 -1
- package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/types/chart/axis.d.ts +2 -2
- package/dist/cjs/types/chart/radar.d.ts +50 -0
- package/dist/cjs/types/chart/radar.js +1 -0
- package/dist/cjs/types/chart/series.d.ts +17 -2
- package/dist/cjs/types/chart/tooltip.d.ts +10 -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.js +39 -2
- package/dist/cjs/utils/chart/index.js +1 -1
- package/dist/cjs/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
- package/dist/cjs/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.js +1 -1
- package/dist/esm/components/Axis/AxisX.d.ts +1 -0
- package/dist/esm/components/Axis/AxisX.js +43 -6
- package/dist/esm/components/Axis/AxisY.js +9 -5
- package/dist/esm/components/Axis/styles.css +5 -5
- package/dist/esm/components/ChartInner/index.js +5 -4
- package/dist/esm/components/ChartInner/styles.css +4 -4
- package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +1 -0
- package/dist/esm/components/ChartInner/useChartInnerHandlers.js +3 -4
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +3 -2
- package/dist/esm/components/Legend/index.js +1 -1
- package/dist/esm/components/Legend/styles.css +14 -14
- package/dist/esm/components/Title/index.js +1 -1
- package/dist/esm/components/Title/styles.css +1 -1
- package/dist/esm/components/Tooltip/DefaultContent.js +18 -3
- package/dist/esm/constants/defaults/series-options.js +12 -0
- package/dist/esm/constants/index.d.ts +1 -0
- package/dist/esm/constants/index.js +1 -0
- package/dist/esm/hooks/useChartOptions/tooltip.js +2 -1
- package/dist/esm/hooks/useChartOptions/types.d.ts +2 -1
- package/dist/esm/hooks/useChartOptions/x-axis.js +9 -2
- package/dist/esm/hooks/useSeries/constants.js +1 -1
- package/dist/esm/hooks/useSeries/prepare-radar.d.ts +16 -0
- package/dist/esm/hooks/useSeries/prepare-radar.js +63 -0
- package/dist/esm/hooks/useSeries/prepareSeries.js +8 -0
- package/dist/esm/hooks/useSeries/types.d.ts +35 -2
- package/dist/esm/hooks/useShapes/area/index.js +1 -1
- package/dist/esm/hooks/useShapes/index.d.ts +2 -1
- package/dist/esm/hooks/useShapes/index.js +12 -0
- package/dist/esm/hooks/useShapes/line/index.js +1 -1
- package/dist/esm/hooks/useShapes/marker.d.ts +3 -2
- package/dist/esm/hooks/useShapes/marker.js +1 -1
- package/dist/esm/hooks/useShapes/pie/index.js +1 -1
- package/dist/esm/hooks/useShapes/radar/index.d.ts +12 -0
- package/dist/esm/hooks/useShapes/radar/index.js +136 -0
- package/dist/esm/hooks/useShapes/radar/prepare-data.d.ts +9 -0
- package/dist/esm/hooks/useShapes/radar/prepare-data.js +155 -0
- package/dist/esm/hooks/useShapes/radar/types.d.ts +58 -0
- package/dist/esm/hooks/useShapes/radar/types.js +1 -0
- package/dist/esm/hooks/useShapes/scatter/index.js +1 -1
- package/dist/esm/hooks/useShapes/styles.css +9 -5
- package/dist/esm/hooks/useShapes/treemap/index.js +1 -1
- package/dist/esm/hooks/useShapes/waterfall/index.js +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/types/chart/axis.d.ts +2 -2
- package/dist/esm/types/chart/radar.d.ts +50 -0
- package/dist/esm/types/chart/radar.js +1 -0
- package/dist/esm/types/chart/series.d.ts +17 -2
- package/dist/esm/types/chart/tooltip.d.ts +10 -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.js +39 -2
- package/dist/esm/utils/chart/index.js +1 -1
- package/dist/esm/utils/{d3-dispatcher.d.ts → dispatcher.d.ts} +1 -1
- package/dist/esm/utils/{d3-dispatcher.js → dispatcher.js} +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/package.json +11 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
|
|
2
|
-
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
2
|
+
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
3
3
|
export type RectLegendSymbol = {
|
|
4
4
|
shape: 'rect';
|
|
5
5
|
} & Required<RectLegendSymbolOptions>;
|
|
@@ -258,7 +258,40 @@ export type PreparedSankeySeries = {
|
|
|
258
258
|
style: BaseTextStyle;
|
|
259
259
|
};
|
|
260
260
|
} & BasePreparedSeries & Omit<SankeySeries, keyof BasePreparedSeries>;
|
|
261
|
-
export type
|
|
261
|
+
export type PreparedRadarSeries = {
|
|
262
|
+
type: RadarSeries['type'];
|
|
263
|
+
data: RadarSeriesData[];
|
|
264
|
+
categories: RadarSeriesCategory[];
|
|
265
|
+
borderColor: string;
|
|
266
|
+
borderWidth: number;
|
|
267
|
+
fillOpacity: number;
|
|
268
|
+
dataLabels: {
|
|
269
|
+
enabled: boolean;
|
|
270
|
+
style: BaseTextStyle;
|
|
271
|
+
padding: number;
|
|
272
|
+
allowOverlap: boolean;
|
|
273
|
+
html: boolean;
|
|
274
|
+
};
|
|
275
|
+
marker: {
|
|
276
|
+
states: {
|
|
277
|
+
normal: {
|
|
278
|
+
symbol: `${SymbolType}`;
|
|
279
|
+
enabled: boolean;
|
|
280
|
+
radius: number;
|
|
281
|
+
borderWidth: number;
|
|
282
|
+
borderColor: string;
|
|
283
|
+
};
|
|
284
|
+
hover: {
|
|
285
|
+
enabled: boolean;
|
|
286
|
+
radius: number;
|
|
287
|
+
borderWidth: number;
|
|
288
|
+
borderColor: string;
|
|
289
|
+
halo: PreparedHaloOptions;
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
} & BasePreparedSeries;
|
|
294
|
+
export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries | PreparedSankeySeries | PreparedRadarSeries;
|
|
262
295
|
export type PreparedSeriesOptions = SeriesOptionsDefaults;
|
|
263
296
|
export type StackedSeries = BarXSeries | AreaSeries | BarYSeries;
|
|
264
297
|
export {};
|
|
@@ -5,7 +5,7 @@ import { block, filterOverlappingLabels } from '../../..//utils';
|
|
|
5
5
|
import { HtmlLayer } from '../HtmlLayer';
|
|
6
6
|
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
7
7
|
import { setActiveState } from '../utils';
|
|
8
|
-
const b = block('
|
|
8
|
+
const b = block('area');
|
|
9
9
|
export const AreaSeriesShapes = (args) => {
|
|
10
10
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
11
|
const hoveredDataRef = React.useRef(null);
|
|
@@ -8,13 +8,14 @@ import type { PreparedBarXData } from './bar-x';
|
|
|
8
8
|
import type { PreparedBarYData } from './bar-y/types';
|
|
9
9
|
import type { PreparedLineData } from './line/types';
|
|
10
10
|
import type { PreparedPieData } from './pie/types';
|
|
11
|
+
import type { PreparedRadarData } from './radar/types';
|
|
11
12
|
import type { PreparedSankeyData } from './sankey/types';
|
|
12
13
|
import type { PreparedScatterData } from './scatter/types';
|
|
13
14
|
export type { PreparedBarXData } from './bar-x';
|
|
14
15
|
export type { PreparedScatterData } from './scatter/types';
|
|
15
16
|
import type { PreparedWaterfallData } from './waterfall';
|
|
16
17
|
import './styles.css';
|
|
17
|
-
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData;
|
|
18
|
+
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData;
|
|
18
19
|
type Args = {
|
|
19
20
|
boundsWidth: number;
|
|
20
21
|
boundsHeight: number;
|
|
@@ -10,6 +10,8 @@ import { LineSeriesShapes } from './line';
|
|
|
10
10
|
import { prepareLineData } from './line/prepare-data';
|
|
11
11
|
import { PieSeriesShapes } from './pie';
|
|
12
12
|
import { preparePieData } from './pie/prepare-data';
|
|
13
|
+
import { RadarSeriesShapes } from './radar';
|
|
14
|
+
import { prepareRadarData } from './radar/prepare-data';
|
|
13
15
|
import { SankeySeriesShape } from './sankey';
|
|
14
16
|
import { prepareSankeyData } from './sankey/prepare-data';
|
|
15
17
|
import { ScatterSeriesShape, prepareScatterData } from './scatter';
|
|
@@ -149,6 +151,16 @@ export const useShapes = (args) => {
|
|
|
149
151
|
shapesData.push(preparedData);
|
|
150
152
|
break;
|
|
151
153
|
}
|
|
154
|
+
case 'radar': {
|
|
155
|
+
const preparedData = prepareRadarData({
|
|
156
|
+
series: chartSeries,
|
|
157
|
+
boundsWidth,
|
|
158
|
+
boundsHeight,
|
|
159
|
+
});
|
|
160
|
+
acc.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
161
|
+
shapesData.push(...preparedData);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
152
164
|
default: {
|
|
153
165
|
throw new ChartError({
|
|
154
166
|
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
@@ -5,7 +5,7 @@ import { block, filterOverlappingLabels, getLineDashArray } from '../../../utils
|
|
|
5
5
|
import { HtmlLayer } from '../HtmlLayer';
|
|
6
6
|
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
7
7
|
import { setActiveState } from '../utils';
|
|
8
|
-
const b = block('
|
|
8
|
+
const b = block('line');
|
|
9
9
|
export const LineSeriesShapes = (args) => {
|
|
10
10
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
11
|
const hoveredDataRef = React.useRef(null);
|
|
@@ -2,9 +2,10 @@ import type { BaseType, Selection } from 'd3';
|
|
|
2
2
|
import { SymbolType } from '../../constants';
|
|
3
3
|
import type { MarkerData as AreaMarkerData } from './area/types';
|
|
4
4
|
import type { MarkerData as LineMarkerData } from './line/types';
|
|
5
|
+
import type { RadarMarkerData } from './radar/types';
|
|
5
6
|
import type { MarkerData as ScatterMarkerData } from './scatter/types';
|
|
6
|
-
type MarkerData = LineMarkerData | AreaMarkerData | ScatterMarkerData;
|
|
7
|
-
export declare function renderMarker<T extends MarkerData>(selection: Selection<BaseType
|
|
7
|
+
type MarkerData = LineMarkerData | AreaMarkerData | ScatterMarkerData | RadarMarkerData;
|
|
8
|
+
export declare function renderMarker<T extends MarkerData>(selection: Selection<BaseType, T, BaseType, unknown>): Selection<BaseType, T, BaseType, unknown>;
|
|
8
9
|
export declare function getMarkerVisibility(d: MarkerData): "" | "hidden";
|
|
9
10
|
export declare function getMarkerHaloVisibility(d: MarkerData): "" | "hidden";
|
|
10
11
|
export declare function setMarker<T extends BaseType, D extends MarkerData>(selection: Selection<T, D, BaseType | null, unknown>, state: 'normal' | 'hover'): void;
|
|
@@ -2,7 +2,7 @@ import { symbol } from 'd3';
|
|
|
2
2
|
import get from 'lodash/get';
|
|
3
3
|
import { SymbolType } from '../../constants';
|
|
4
4
|
import { block, getSymbol } from '../../utils';
|
|
5
|
-
const b = block('
|
|
5
|
+
const b = block('marker');
|
|
6
6
|
const haloClassName = b('halo');
|
|
7
7
|
const symbolClassName = b('symbol');
|
|
8
8
|
export function renderMarker(selection) {
|
|
@@ -4,7 +4,7 @@ import get from 'lodash/get';
|
|
|
4
4
|
import { block, setEllipsisForOverflowTexts } from '../../../utils';
|
|
5
5
|
import { HtmlLayer } from '../HtmlLayer';
|
|
6
6
|
import { setActiveState } from '../utils';
|
|
7
|
-
const b = block('
|
|
7
|
+
const b = block('pie');
|
|
8
8
|
export function getHaloVisibility(d) {
|
|
9
9
|
const enabled = d.data.pie.halo.enabled && d.data.hovered;
|
|
10
10
|
return enabled ? '' : 'hidden';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Dispatch } from 'd3';
|
|
3
|
+
import type { PreparedSeriesOptions } from '../../useSeries/types';
|
|
4
|
+
import type { PreparedRadarData } from './types';
|
|
5
|
+
type PrepareRadarSeriesArgs = {
|
|
6
|
+
dispatcher: Dispatch<object>;
|
|
7
|
+
series: PreparedRadarData[];
|
|
8
|
+
seriesOptions: PreparedSeriesOptions;
|
|
9
|
+
htmlLayout: HTMLElement | null;
|
|
10
|
+
};
|
|
11
|
+
export declare function RadarSeriesShapes(args: PrepareRadarSeriesArgs): React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { color, line, select } from 'd3';
|
|
3
|
+
import get from 'lodash/get';
|
|
4
|
+
import { block } from '../../../utils';
|
|
5
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
6
|
+
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
7
|
+
import { setActiveState } from '../utils';
|
|
8
|
+
const b = block('radar');
|
|
9
|
+
export function RadarSeriesShapes(args) {
|
|
10
|
+
const { dispatcher, series: preparedData, seriesOptions, htmlLayout } = args;
|
|
11
|
+
const ref = React.useRef(null);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
if (!ref.current) {
|
|
14
|
+
return () => { };
|
|
15
|
+
}
|
|
16
|
+
const svgElement = select(ref.current);
|
|
17
|
+
svgElement.selectAll('*').remove();
|
|
18
|
+
const areaSelector = `.${b('area')}`;
|
|
19
|
+
const radarSelection = svgElement
|
|
20
|
+
.selectAll('radar')
|
|
21
|
+
.data(preparedData)
|
|
22
|
+
.join('g')
|
|
23
|
+
.attr('id', (radarData) => radarData.id)
|
|
24
|
+
.attr('class', b('item'))
|
|
25
|
+
.attr('cursor', (radarData) => radarData.cursor);
|
|
26
|
+
// render axes
|
|
27
|
+
radarSelection
|
|
28
|
+
.selectAll(`.${b('axis')}`)
|
|
29
|
+
.data((radarData) => radarData.axes)
|
|
30
|
+
.join('line')
|
|
31
|
+
.attr('class', b('axis'))
|
|
32
|
+
.attr('x1', (d) => d.radar.center[0])
|
|
33
|
+
.attr('y1', (d) => d.radar.center[1])
|
|
34
|
+
.attr('x2', (d) => d.point[0])
|
|
35
|
+
.attr('y2', (d) => d.point[1])
|
|
36
|
+
.attr('stroke', (d) => d.strokeColor)
|
|
37
|
+
.attr('stroke-width', (d) => d.strokeWidth);
|
|
38
|
+
// render grid lines
|
|
39
|
+
radarSelection
|
|
40
|
+
.selectAll(`.${b('grid')}`)
|
|
41
|
+
.data((radarData) => radarData.grid)
|
|
42
|
+
.join('path')
|
|
43
|
+
.attr('class', b('grid'))
|
|
44
|
+
.attr('d', (d) => `${line()(d.path)} Z`)
|
|
45
|
+
.attr('fill', 'none')
|
|
46
|
+
.attr('stroke', (d) => d.strokeColor)
|
|
47
|
+
.attr('stroke-width', (d) => d.strokeWidth);
|
|
48
|
+
// render radar area
|
|
49
|
+
const shapesSelection = radarSelection
|
|
50
|
+
.selectAll(areaSelector)
|
|
51
|
+
.data((radarData) => radarData.shapes)
|
|
52
|
+
.join('g')
|
|
53
|
+
.attr('class', b('area'));
|
|
54
|
+
shapesSelection
|
|
55
|
+
.append('path')
|
|
56
|
+
.attr('d', (d) => d.path)
|
|
57
|
+
.attr('fill', (d) => d.color)
|
|
58
|
+
.attr('fill-opacity', (d) => d.fillOpacity)
|
|
59
|
+
.attr('stroke', (d) => d.borderColor)
|
|
60
|
+
.attr('stroke-width', (d) => d.borderWidth);
|
|
61
|
+
// render markers
|
|
62
|
+
const markerSelection = shapesSelection
|
|
63
|
+
.selectAll('marker')
|
|
64
|
+
.data((radarData) => radarData.points)
|
|
65
|
+
.join('g')
|
|
66
|
+
.call(renderMarker);
|
|
67
|
+
// Render labels
|
|
68
|
+
radarSelection
|
|
69
|
+
.selectAll('text')
|
|
70
|
+
.data((radarData) => radarData.labels)
|
|
71
|
+
.join('text')
|
|
72
|
+
.text((d) => d.text)
|
|
73
|
+
.attr('class', b('label'))
|
|
74
|
+
.attr('x', (d) => d.x)
|
|
75
|
+
.attr('y', (d) => d.y)
|
|
76
|
+
.attr('text-anchor', (d) => d.textAnchor)
|
|
77
|
+
.style('font-size', (d) => d.style.fontSize)
|
|
78
|
+
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
79
|
+
.style('fill', (d) => d.style.fontColor || null);
|
|
80
|
+
// Handle hover events
|
|
81
|
+
const eventName = `hover-shape.radar`;
|
|
82
|
+
const hoverOptions = get(seriesOptions, 'radar.states.hover');
|
|
83
|
+
const inactiveOptions = get(seriesOptions, 'radar.states.inactive');
|
|
84
|
+
dispatcher.on(eventName, (data) => {
|
|
85
|
+
const closest = data === null || data === void 0 ? void 0 : data.find((d) => d.closest);
|
|
86
|
+
const selectedSeries = closest === null || closest === void 0 ? void 0 : closest.series;
|
|
87
|
+
const selectedSeriesData = closest === null || closest === void 0 ? void 0 : closest.data;
|
|
88
|
+
const selectedSeriesId = selectedSeries === null || selectedSeries === void 0 ? void 0 : selectedSeries.id;
|
|
89
|
+
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
90
|
+
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
91
|
+
shapesSelection.datum((d, i, elements) => {
|
|
92
|
+
var _a;
|
|
93
|
+
const hovered = Boolean(hoverEnabled && ((_a = d.series) === null || _a === void 0 ? void 0 : _a.id) === selectedSeriesId);
|
|
94
|
+
if (d.hovered !== hovered) {
|
|
95
|
+
d.hovered = hovered;
|
|
96
|
+
select(elements[i]).attr('fill', () => {
|
|
97
|
+
var _a;
|
|
98
|
+
const initialColor = d.color;
|
|
99
|
+
if (d.hovered) {
|
|
100
|
+
return (((_a = color(initialColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness).toString()) || initialColor);
|
|
101
|
+
}
|
|
102
|
+
return initialColor;
|
|
103
|
+
});
|
|
104
|
+
if (hovered) {
|
|
105
|
+
select(elements[i]).raise();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
setActiveState({
|
|
109
|
+
element: elements[i],
|
|
110
|
+
state: inactiveOptions,
|
|
111
|
+
active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.series.id),
|
|
112
|
+
datum: d,
|
|
113
|
+
});
|
|
114
|
+
markerSelection.datum((markerData, index, markers) => {
|
|
115
|
+
const hoveredState = Boolean(hoverEnabled && markerData.data === selectedSeriesData);
|
|
116
|
+
if (markerData.hovered !== hoveredState) {
|
|
117
|
+
markerData.hovered = hoveredState;
|
|
118
|
+
const elementSelection = select(markers[index]);
|
|
119
|
+
elementSelection.attr('visibility', getMarkerVisibility(markerData));
|
|
120
|
+
selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
|
|
121
|
+
selectMarkerSymbol(elementSelection).call(setMarker, hoveredState ? 'hover' : 'normal');
|
|
122
|
+
}
|
|
123
|
+
return markerData;
|
|
124
|
+
});
|
|
125
|
+
return d;
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
return () => {
|
|
129
|
+
dispatcher.on(eventName, null);
|
|
130
|
+
};
|
|
131
|
+
}, [dispatcher, preparedData, seriesOptions]);
|
|
132
|
+
const htmlElements = preparedData.map((d) => d.htmlLabels).flat();
|
|
133
|
+
return (React.createElement(React.Fragment, null,
|
|
134
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
135
|
+
React.createElement(HtmlLayer, { preparedData: { htmlElements }, htmlLayout: htmlLayout })));
|
|
136
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PreparedRadarSeries } from '../../useSeries/types';
|
|
2
|
+
import type { PreparedRadarData } from './types';
|
|
3
|
+
type Args = {
|
|
4
|
+
series: PreparedRadarSeries[];
|
|
5
|
+
boundsWidth: number;
|
|
6
|
+
boundsHeight: number;
|
|
7
|
+
};
|
|
8
|
+
export declare function prepareRadarData(args: Args): PreparedRadarData[];
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { curveLinearClosed, line, range, scaleLinear } from 'd3';
|
|
2
|
+
import { getLabelsSize } from '../../../utils';
|
|
3
|
+
export function prepareRadarData(args) {
|
|
4
|
+
const { series: preparedSeries, boundsWidth, boundsHeight } = args;
|
|
5
|
+
const maxRadius = Math.min(boundsWidth, boundsHeight) / 2;
|
|
6
|
+
const center = [boundsWidth / 2, boundsHeight / 2];
|
|
7
|
+
const result = [];
|
|
8
|
+
const gridStepsCount = 5;
|
|
9
|
+
const radius = maxRadius * 0.8; // Leave some space for labels
|
|
10
|
+
// Create scale for values
|
|
11
|
+
const valueScale = scaleLinear()
|
|
12
|
+
.domain([0, Math.max(...preparedSeries.map((s) => s.data.map((d) => d.value)).flat())])
|
|
13
|
+
.range([0, radius]);
|
|
14
|
+
const [, finalRadius] = valueScale.range();
|
|
15
|
+
const data = {
|
|
16
|
+
type: 'radar',
|
|
17
|
+
id: preparedSeries[0].id,
|
|
18
|
+
center,
|
|
19
|
+
radius: finalRadius,
|
|
20
|
+
shapes: [],
|
|
21
|
+
labels: [],
|
|
22
|
+
axes: [],
|
|
23
|
+
htmlLabels: [],
|
|
24
|
+
grid: [],
|
|
25
|
+
cursor: preparedSeries[0].cursor,
|
|
26
|
+
};
|
|
27
|
+
const categories = preparedSeries[0].categories;
|
|
28
|
+
const axisStrokeColor = 'var(--g-color-line-generic)';
|
|
29
|
+
const axisStrokeWidth = 1;
|
|
30
|
+
// Create axes based on categories
|
|
31
|
+
const axesCount = categories.length;
|
|
32
|
+
const angleStep = (2 * Math.PI) / axesCount;
|
|
33
|
+
data.axes = categories.map((_category, index) => {
|
|
34
|
+
const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
|
|
35
|
+
return {
|
|
36
|
+
point: [
|
|
37
|
+
center[0] + Math.cos(angle) * data.radius,
|
|
38
|
+
center[1] + Math.sin(angle) * data.radius,
|
|
39
|
+
],
|
|
40
|
+
radar: data,
|
|
41
|
+
strokeColor: axisStrokeColor,
|
|
42
|
+
strokeWidth: axisStrokeWidth,
|
|
43
|
+
angle,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
const gridStepInc = data.radius / gridStepsCount;
|
|
47
|
+
const gridSteps = range(gridStepInc, data.radius + gridStepInc, gridStepInc);
|
|
48
|
+
gridSteps.forEach((gridStep) => {
|
|
49
|
+
const gridLines = {
|
|
50
|
+
path: [],
|
|
51
|
+
strokeColor: axisStrokeColor,
|
|
52
|
+
strokeWidth: axisStrokeWidth,
|
|
53
|
+
};
|
|
54
|
+
categories.forEach((_category, index) => {
|
|
55
|
+
const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
|
|
56
|
+
gridLines.path.push([
|
|
57
|
+
center[0] + Math.cos(angle) * gridStep,
|
|
58
|
+
center[1] + Math.sin(angle) * gridStep,
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
61
|
+
data.grid.push(gridLines);
|
|
62
|
+
});
|
|
63
|
+
const radarAreaLine = line().curve(curveLinearClosed);
|
|
64
|
+
preparedSeries.forEach((series) => {
|
|
65
|
+
var _a;
|
|
66
|
+
const { dataLabels } = series;
|
|
67
|
+
const markers = [];
|
|
68
|
+
categories.forEach((category, index) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const dataItem = series.data[index];
|
|
71
|
+
const angle = index * angleStep - Math.PI / 2; // Start from top (negative PI/2)
|
|
72
|
+
const pointValueScale = scaleLinear()
|
|
73
|
+
.domain([
|
|
74
|
+
0,
|
|
75
|
+
(_a = category.maxValue) !== null && _a !== void 0 ? _a : Math.max(...preparedSeries.map((s) => s.data[index].value)),
|
|
76
|
+
])
|
|
77
|
+
.range([0, radius]);
|
|
78
|
+
const pointRadius = pointValueScale(dataItem.value);
|
|
79
|
+
const x = center[0] + Math.cos(angle) * pointRadius;
|
|
80
|
+
const y = center[1] + Math.sin(angle) * pointRadius;
|
|
81
|
+
markers.push({
|
|
82
|
+
point: {
|
|
83
|
+
x,
|
|
84
|
+
y,
|
|
85
|
+
series,
|
|
86
|
+
data: dataItem,
|
|
87
|
+
},
|
|
88
|
+
index,
|
|
89
|
+
position: [x, y],
|
|
90
|
+
color: series.color,
|
|
91
|
+
opacity: 1,
|
|
92
|
+
radius: 2,
|
|
93
|
+
data: dataItem,
|
|
94
|
+
series: series,
|
|
95
|
+
hovered: false,
|
|
96
|
+
active: false,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
data.shapes.push({
|
|
100
|
+
borderWidth: series.borderWidth,
|
|
101
|
+
borderColor: series.borderColor,
|
|
102
|
+
fillOpacity: series.fillOpacity,
|
|
103
|
+
points: markers,
|
|
104
|
+
path: (_a = radarAreaLine(markers.map((p) => p.position))) !== null && _a !== void 0 ? _a : '',
|
|
105
|
+
series: series,
|
|
106
|
+
color: series.color,
|
|
107
|
+
hovered: false,
|
|
108
|
+
active: true,
|
|
109
|
+
});
|
|
110
|
+
// Create labels if enabled
|
|
111
|
+
if (dataLabels.enabled) {
|
|
112
|
+
const { style } = dataLabels;
|
|
113
|
+
const shouldUseHtml = dataLabels.html;
|
|
114
|
+
data.labels = categories.map((category, index) => {
|
|
115
|
+
const text = category.key;
|
|
116
|
+
const labelSize = getLabelsSize({ labels: [text], style });
|
|
117
|
+
const angle = index * angleStep - Math.PI / 2;
|
|
118
|
+
// Position label slightly outside the point
|
|
119
|
+
const labelRadius = data.radius + 10;
|
|
120
|
+
let x = center[0] + Math.cos(angle) * labelRadius;
|
|
121
|
+
let y = center[1] + Math.sin(angle) * labelRadius;
|
|
122
|
+
if (shouldUseHtml) {
|
|
123
|
+
x = x < center[0] ? x - labelSize.maxWidth : x;
|
|
124
|
+
y = y - labelSize.maxHeight;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
y = y < center[1] ? y - labelSize.maxHeight : y;
|
|
128
|
+
}
|
|
129
|
+
x = Math.max(-boundsWidth / 2, x);
|
|
130
|
+
return {
|
|
131
|
+
text,
|
|
132
|
+
x,
|
|
133
|
+
y,
|
|
134
|
+
style,
|
|
135
|
+
size: { width: labelSize.maxWidth, height: labelSize.maxHeight },
|
|
136
|
+
maxWidth: labelSize.maxWidth,
|
|
137
|
+
textAnchor: angle > Math.PI / 2 && angle < (3 * Math.PI) / 2 ? 'end' : 'start',
|
|
138
|
+
series: { id: series.id },
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
// Create HTML labels if needed
|
|
142
|
+
if (dataLabels.html) {
|
|
143
|
+
data.htmlLabels = data.labels.map((label) => ({
|
|
144
|
+
x: label.x,
|
|
145
|
+
y: label.y,
|
|
146
|
+
content: label.text,
|
|
147
|
+
size: label.size,
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return data;
|
|
152
|
+
});
|
|
153
|
+
result.push(data);
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { HtmlItem, LabelData, RadarSeriesData } from '../../../types';
|
|
2
|
+
import type { PreparedRadarSeries } from '../../useSeries/types';
|
|
3
|
+
export type RadarLabelData = LabelData & {
|
|
4
|
+
maxWidth: number;
|
|
5
|
+
};
|
|
6
|
+
export type RadarAxisData = {
|
|
7
|
+
point: [number, number];
|
|
8
|
+
angle: number;
|
|
9
|
+
strokeColor: string;
|
|
10
|
+
strokeWidth: number;
|
|
11
|
+
radar: PreparedRadarData;
|
|
12
|
+
};
|
|
13
|
+
export type RadarGridData = {
|
|
14
|
+
path: [number, number][];
|
|
15
|
+
strokeColor: string;
|
|
16
|
+
strokeWidth: number;
|
|
17
|
+
};
|
|
18
|
+
export type PointData = {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
data: RadarSeriesData;
|
|
22
|
+
series: PreparedRadarSeries;
|
|
23
|
+
};
|
|
24
|
+
export type RadarMarkerData = {
|
|
25
|
+
point: PointData;
|
|
26
|
+
radius: number;
|
|
27
|
+
position: [number, number];
|
|
28
|
+
index: number;
|
|
29
|
+
color: string;
|
|
30
|
+
opacity: number;
|
|
31
|
+
data: RadarSeriesData;
|
|
32
|
+
series: PreparedRadarSeries;
|
|
33
|
+
hovered: boolean;
|
|
34
|
+
active: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type RadarShapeData = {
|
|
37
|
+
points: RadarMarkerData[];
|
|
38
|
+
path: string;
|
|
39
|
+
color: string;
|
|
40
|
+
series: PreparedRadarSeries;
|
|
41
|
+
hovered: boolean;
|
|
42
|
+
active: boolean;
|
|
43
|
+
borderColor: string;
|
|
44
|
+
borderWidth: number;
|
|
45
|
+
fillOpacity: number;
|
|
46
|
+
};
|
|
47
|
+
export type PreparedRadarData = {
|
|
48
|
+
type: 'radar';
|
|
49
|
+
id: string;
|
|
50
|
+
shapes: RadarShapeData[];
|
|
51
|
+
labels: RadarLabelData[];
|
|
52
|
+
axes: RadarAxisData[];
|
|
53
|
+
grid: RadarGridData[];
|
|
54
|
+
center: [number, number];
|
|
55
|
+
radius: number;
|
|
56
|
+
htmlLabels: HtmlItem[];
|
|
57
|
+
cursor: string | null;
|
|
58
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,7 +6,7 @@ import { HtmlLayer } from '../HtmlLayer';
|
|
|
6
6
|
import { getMarkerHaloVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
7
7
|
import { setActiveState, shapeKey } from '../utils';
|
|
8
8
|
export { prepareScatterData } from './prepare-data';
|
|
9
|
-
const b = block('
|
|
9
|
+
const b = block('scatter');
|
|
10
10
|
export function ScatterSeriesShape(props) {
|
|
11
11
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
12
12
|
const hoveredDataRef = React.useRef(null);
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
.gcharts-
|
|
1
|
+
.gcharts-scatter__point {
|
|
2
2
|
stroke-width: 1px;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
.gcharts-
|
|
5
|
+
.gcharts-pie__segment {
|
|
6
6
|
stroke: var(--g-color-base-background);
|
|
7
7
|
}
|
|
8
|
-
.gcharts-
|
|
8
|
+
.gcharts-pie__label {
|
|
9
9
|
font-size: 11px;
|
|
10
10
|
font-weight: bold;
|
|
11
11
|
fill: var(--g-color-text-complementary);
|
|
12
12
|
alignment-baseline: before-edge;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
.gcharts-radar__label {
|
|
16
|
+
alignment-baseline: before-edge;
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
.gcharts-bar-x__label {
|
|
16
20
|
user-select: none;
|
|
17
21
|
fill: var(--g-color-text-complementary);
|
|
@@ -23,13 +27,13 @@
|
|
|
23
27
|
alignment-baseline: after-edge;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
.gcharts-
|
|
30
|
+
.gcharts-treemap__label {
|
|
27
31
|
user-select: none;
|
|
28
32
|
pointer-events: none;
|
|
29
33
|
fill: var(--g-color-text-complementary);
|
|
30
34
|
alignment-baseline: text-before-edge;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
.gcharts-
|
|
37
|
+
.gcharts-waterfall__connector {
|
|
34
38
|
stroke: var(--g-color-line-generic-active);
|
|
35
39
|
}
|
|
@@ -3,7 +3,7 @@ import { color, select } from 'd3';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block, setEllipsisForOverflowTexts } from '../../../utils';
|
|
5
5
|
import { HtmlLayer } from '../HtmlLayer';
|
|
6
|
-
const b = block('
|
|
6
|
+
const b = block('treemap');
|
|
7
7
|
export const TreemapSeriesShape = (props) => {
|
|
8
8
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
9
9
|
const hoveredDataRef = React.useRef(null);
|
|
@@ -6,7 +6,7 @@ import { block, filterOverlappingLabels, getLineDashArray, getWaterfallPointColo
|
|
|
6
6
|
import { HtmlLayer } from '../HtmlLayer';
|
|
7
7
|
export { prepareWaterfallData } from './prepare-data';
|
|
8
8
|
export * from './types';
|
|
9
|
-
const b = block('
|
|
9
|
+
const b = block('waterfall');
|
|
10
10
|
export const WaterfallSeriesShapes = (args) => {
|
|
11
11
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
12
12
|
const hoveredDataRef = React.useRef(null);
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -73,6 +73,8 @@ export interface ChartAxis {
|
|
|
73
73
|
* Defaults to 0.05 for Y axis and to 0.01 for X axis.
|
|
74
74
|
* */
|
|
75
75
|
maxPadding?: number;
|
|
76
|
+
/** An array of lines stretching across the plot area, marking a specific value */
|
|
77
|
+
plotLines?: AxisPlotLine[];
|
|
76
78
|
}
|
|
77
79
|
export interface ChartXAxis extends ChartAxis {
|
|
78
80
|
}
|
|
@@ -105,6 +107,4 @@ export interface ChartYAxis extends ChartAxis {
|
|
|
105
107
|
/** Property for splitting charts. Determines which area the axis is located in.
|
|
106
108
|
* */
|
|
107
109
|
plotIndex?: number;
|
|
108
|
-
/** An array of lines stretching across the plot area, marking a specific value */
|
|
109
|
-
plotLines?: AxisPlotLine[];
|
|
110
110
|
}
|