@gravity-ui/charts 1.44.0 → 1.46.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/styles.css +2 -2
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +1 -1
- package/dist/cjs/components/ChartInner/utils/title.d.ts +2 -1
- package/dist/cjs/components/ChartInner/utils/title.js +51 -14
- package/dist/cjs/components/Title/index.d.ts +4 -2
- package/dist/cjs/components/Title/index.js +9 -2
- package/dist/cjs/core/constants/defaults/annotation.d.ts +12 -0
- package/dist/cjs/core/constants/defaults/annotation.js +12 -0
- package/dist/cjs/core/constants/defaults/index.d.ts +1 -0
- package/dist/cjs/core/constants/defaults/index.js +1 -0
- package/dist/cjs/core/series/constants.d.ts +1 -1
- package/dist/cjs/core/series/constants.js +1 -1
- package/dist/cjs/core/series/prepare-annotation.d.ts +12 -0
- package/dist/cjs/core/series/prepare-annotation.js +31 -0
- package/dist/cjs/core/series/types.d.ts +16 -0
- package/dist/cjs/core/types/chart/annotation.d.ts +45 -0
- package/dist/cjs/core/types/chart/annotation.js +1 -0
- package/dist/cjs/core/types/chart/area.d.ts +8 -0
- package/dist/cjs/core/types/chart/bar-x.d.ts +6 -0
- package/dist/cjs/core/types/chart/line.d.ts +8 -0
- package/dist/cjs/core/types/chart/marker.d.ts +6 -4
- package/dist/cjs/core/types/chart/series.d.ts +7 -0
- package/dist/cjs/core/types/chart/title.d.ts +18 -0
- package/dist/cjs/core/types/chart/tooltip.d.ts +1 -0
- package/dist/cjs/core/types/index.d.ts +1 -0
- package/dist/cjs/core/types/index.js +1 -0
- package/dist/cjs/core/utils/text.d.ts +8 -0
- package/dist/cjs/core/utils/text.js +9 -1
- package/dist/cjs/hooks/types.d.ts +6 -3
- package/dist/cjs/hooks/useShapes/HtmlLayer.js +4 -3
- package/dist/cjs/hooks/useShapes/annotation/index.d.ts +14 -0
- package/dist/cjs/hooks/useShapes/annotation/index.js +200 -0
- package/dist/cjs/hooks/useShapes/area/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/area/index.js +21 -2
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +38 -20
- package/dist/cjs/hooks/useShapes/area/types.d.ts +4 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.js +30 -2
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +10 -2
- package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/index.js +5 -3
- package/dist/cjs/hooks/useShapes/line/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/line/index.js +18 -4
- package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +28 -10
- package/dist/cjs/hooks/useShapes/line/types.d.ts +4 -0
- package/dist/cjs/types/chart-ui.d.ts +2 -0
- package/dist/esm/components/ChartInner/index.js +2 -2
- package/dist/esm/components/ChartInner/styles.css +2 -2
- package/dist/esm/components/ChartInner/useChartInnerProps.js +1 -1
- package/dist/esm/components/ChartInner/utils/title.d.ts +2 -1
- package/dist/esm/components/ChartInner/utils/title.js +51 -14
- package/dist/esm/components/Title/index.d.ts +4 -2
- package/dist/esm/components/Title/index.js +9 -2
- package/dist/esm/core/constants/defaults/annotation.d.ts +12 -0
- package/dist/esm/core/constants/defaults/annotation.js +12 -0
- package/dist/esm/core/constants/defaults/index.d.ts +1 -0
- package/dist/esm/core/constants/defaults/index.js +1 -0
- package/dist/esm/core/series/constants.d.ts +1 -1
- package/dist/esm/core/series/constants.js +1 -1
- package/dist/esm/core/series/prepare-annotation.d.ts +12 -0
- package/dist/esm/core/series/prepare-annotation.js +31 -0
- package/dist/esm/core/series/types.d.ts +16 -0
- package/dist/esm/core/types/chart/annotation.d.ts +45 -0
- package/dist/esm/core/types/chart/annotation.js +1 -0
- package/dist/esm/core/types/chart/area.d.ts +8 -0
- package/dist/esm/core/types/chart/bar-x.d.ts +6 -0
- package/dist/esm/core/types/chart/line.d.ts +8 -0
- package/dist/esm/core/types/chart/marker.d.ts +6 -4
- package/dist/esm/core/types/chart/series.d.ts +7 -0
- package/dist/esm/core/types/chart/title.d.ts +18 -0
- package/dist/esm/core/types/chart/tooltip.d.ts +1 -0
- package/dist/esm/core/types/index.d.ts +1 -0
- package/dist/esm/core/types/index.js +1 -0
- package/dist/esm/core/utils/text.d.ts +8 -0
- package/dist/esm/core/utils/text.js +9 -1
- package/dist/esm/hooks/types.d.ts +6 -3
- package/dist/esm/hooks/useShapes/HtmlLayer.js +4 -3
- package/dist/esm/hooks/useShapes/annotation/index.d.ts +14 -0
- package/dist/esm/hooks/useShapes/annotation/index.js +200 -0
- package/dist/esm/hooks/useShapes/area/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/area/index.js +21 -2
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +2 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.js +38 -20
- package/dist/esm/hooks/useShapes/area/types.d.ts +4 -0
- package/dist/esm/hooks/useShapes/bar-x/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/bar-x/index.js +30 -2
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +10 -2
- package/dist/esm/hooks/useShapes/bar-x/types.d.ts +2 -0
- package/dist/esm/hooks/useShapes/index.js +5 -3
- package/dist/esm/hooks/useShapes/line/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/line/index.js +18 -4
- package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +2 -1
- package/dist/esm/hooks/useShapes/line/prepare-data.js +28 -10
- package/dist/esm/hooks/useShapes/line/types.d.ts +4 -0
- package/dist/esm/types/chart-ui.d.ts +2 -0
- package/package.json +2 -2
|
@@ -256,7 +256,7 @@ export const ChartInner = (props) => {
|
|
|
256
256
|
React.createElement("rect", { x: 0, y: 0, width: boundsWidth, height: boundsHeight })),
|
|
257
257
|
React.createElement("clipPath", { id: getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' }) },
|
|
258
258
|
React.createElement("rect", { x: 0, y: -boundsHeight, width: boundsWidth, height: boundsHeight * 3 }))),
|
|
259
|
-
preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle)),
|
|
259
|
+
preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle, { htmlLayout: htmlLayout })),
|
|
260
260
|
React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit === null || preparedSplit === void 0 ? void 0 : preparedSplit.plots.map((plot, index) => {
|
|
261
261
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
262
262
|
})),
|
|
@@ -285,7 +285,7 @@ export const ChartInner = (props) => {
|
|
|
285
285
|
// when starting to select an area, the tooltip remains in the position where the selection began
|
|
286
286
|
onPointerMove: throttledHandlePointerMove, onPointerLeave: handlePointerLeave, onTouchStart: throttledHandleTouchMove, onTouchMove: throttledHandleTouchMove, onClick: handleChartClick }, initialized ? chartContent : null),
|
|
287
287
|
React.createElement("div", { className: b('html-layer'), ref: setHtmlLayout, style: {
|
|
288
|
-
'--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
|
|
288
|
+
'--g-html-layout-plot-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
|
|
289
289
|
} }),
|
|
290
290
|
Object.keys(zoomState).length > 0 && (preparedChart === null || preparedChart === void 0 ? void 0 : preparedChart.zoom) && (React.createElement(Button, { className: b('reset-zoom-button'), onClick: () => {
|
|
291
291
|
var _a;
|
|
@@ -53,6 +53,7 @@ export function useChartInnerProps(props) {
|
|
|
53
53
|
const preparedTitle = await getPreparedTitle({
|
|
54
54
|
title: data.title,
|
|
55
55
|
chartWidth: width,
|
|
56
|
+
chartHeight: height,
|
|
56
57
|
chartMargin: (_a = data.chart) === null || _a === void 0 ? void 0 : _a.margin,
|
|
57
58
|
});
|
|
58
59
|
const preparedChart = getPreparedChart({
|
|
@@ -203,7 +204,6 @@ export function useChartInnerProps(props) {
|
|
|
203
204
|
getYAxisWidth,
|
|
204
205
|
legendConfig,
|
|
205
206
|
});
|
|
206
|
-
//end
|
|
207
207
|
const newStateValue = {
|
|
208
208
|
allPreparedSeries,
|
|
209
209
|
boundsHeight,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { PreparedTitle } from '../../../hooks/types';
|
|
2
2
|
import type { ChartData, ChartMargin } from '../../../types';
|
|
3
|
-
export declare const getPreparedTitle: ({ title, chartWidth, chartMargin, }: {
|
|
3
|
+
export declare const getPreparedTitle: ({ title, chartWidth, chartHeight, chartMargin, }: {
|
|
4
4
|
title: ChartData["title"];
|
|
5
5
|
chartWidth: number;
|
|
6
|
+
chartHeight: number;
|
|
6
7
|
chartMargin?: Partial<ChartMargin>;
|
|
7
8
|
}) => Promise<PreparedTitle | undefined>;
|
|
@@ -1,26 +1,64 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { getTextSizeFn, getTextWithElipsis, wrapText } from '../../../core/utils';
|
|
1
|
+
import { calculateNumericProperty, getLabelsSize, getTextSizeFn, getTextWithElipsis, wrapText, } from '../../../core/utils';
|
|
3
2
|
const DEFAULT_TITLE_FONT_SIZE = '15px';
|
|
4
3
|
const DEFAULT_TITLE_MARGIN = 10;
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const DEFAULT_TITLE_MAX_HEIGHT = '50%';
|
|
5
|
+
export const getPreparedTitle = async ({ title, chartWidth, chartHeight, chartMargin, }) => {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
7
|
+
const titleText = title === null || title === void 0 ? void 0 : title.text;
|
|
8
|
+
if (!titleText) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
7
11
|
const chartMarginTop = (_a = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.top) !== null && _a !== void 0 ? _a : 0;
|
|
8
12
|
const chartMarginLeft = (_b = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.left) !== null && _b !== void 0 ? _b : 0;
|
|
9
13
|
const chartMarginRight = (_c = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.right) !== null && _c !== void 0 ? _c : 0;
|
|
10
|
-
const titleText = get(title, 'text');
|
|
11
14
|
const titleStyle = {
|
|
12
15
|
fontSize: (_e = (_d = title === null || title === void 0 ? void 0 : title.style) === null || _d === void 0 ? void 0 : _d.fontSize) !== null && _e !== void 0 ? _e : DEFAULT_TITLE_FONT_SIZE,
|
|
13
16
|
fontWeight: (_g = (_f = title === null || title === void 0 ? void 0 : title.style) === null || _f === void 0 ? void 0 : _f.fontWeight) !== null && _g !== void 0 ? _g : 'var(--g-text-subheader-font-weight)',
|
|
14
17
|
fontColor: (_j = (_h = title === null || title === void 0 ? void 0 : title.style) === null || _h === void 0 ? void 0 : _h.fontColor) !== null && _j !== void 0 ? _j : 'var(--g-color-text-primary)',
|
|
15
18
|
};
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
const usableWidth = chartWidth - chartMarginLeft - chartMarginRight;
|
|
20
|
+
const titleMargin = (_k = title === null || title === void 0 ? void 0 : title.margin) !== null && _k !== void 0 ? _k : DEFAULT_TITLE_MARGIN;
|
|
21
|
+
if (title === null || title === void 0 ? void 0 : title.html) {
|
|
22
|
+
const titleSize = await getLabelsSize({
|
|
23
|
+
labels: [titleText],
|
|
24
|
+
style: Object.assign(Object.assign({}, titleStyle), { maxWidth: `${usableWidth}px` }),
|
|
25
|
+
html: true,
|
|
26
|
+
});
|
|
27
|
+
const resolvedMaxHeight = calculateNumericProperty({
|
|
28
|
+
value: (_l = title.maxHeight) !== null && _l !== void 0 ? _l : DEFAULT_TITLE_MAX_HEIGHT,
|
|
29
|
+
base: chartHeight,
|
|
30
|
+
});
|
|
31
|
+
const titleHeight = resolvedMaxHeight === undefined
|
|
32
|
+
? titleSize.maxHeight
|
|
33
|
+
: Math.min(titleSize.maxHeight, resolvedMaxHeight);
|
|
34
|
+
const qa = title === null || title === void 0 ? void 0 : title.qa;
|
|
35
|
+
const qaAttr = qa ? ` data-qa="${qa}"` : '';
|
|
36
|
+
const maxHeightStyle = resolvedMaxHeight === undefined ? '' : ` max-height: ${resolvedMaxHeight}px;`;
|
|
37
|
+
const htmlContent = `<div${qaAttr} style="max-width: ${usableWidth}px; overflow: hidden;${maxHeightStyle}">${titleText}</div>`;
|
|
38
|
+
const titleWidth = Math.min(titleSize.maxWidth, usableWidth);
|
|
39
|
+
return {
|
|
40
|
+
text: titleText,
|
|
41
|
+
style: titleStyle,
|
|
42
|
+
height: titleHeight,
|
|
43
|
+
margin: titleMargin,
|
|
44
|
+
qa,
|
|
45
|
+
html: true,
|
|
46
|
+
htmlElements: [
|
|
47
|
+
{
|
|
48
|
+
x: chartMarginLeft + (usableWidth - titleWidth) / 2,
|
|
49
|
+
y: chartMarginTop,
|
|
50
|
+
content: htmlContent,
|
|
51
|
+
size: { width: titleWidth, height: titleHeight },
|
|
52
|
+
style: titleStyle,
|
|
53
|
+
scope: 'chart',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
18
57
|
}
|
|
58
|
+
const xCenter = chartMarginLeft + usableWidth / 2;
|
|
19
59
|
const getTitleTextSize = getTextSizeFn({ style: titleStyle });
|
|
20
|
-
const maxRowCount = (
|
|
60
|
+
const maxRowCount = (_m = title === null || title === void 0 ? void 0 : title.maxRowCount) !== null && _m !== void 0 ? _m : 1;
|
|
21
61
|
const contentRows = [];
|
|
22
|
-
const usableWidth = chartWidth - chartMarginLeft - chartMarginRight;
|
|
23
|
-
const xCenter = chartMarginLeft + usableWidth / 2;
|
|
24
62
|
if (maxRowCount > 1) {
|
|
25
63
|
let titleTextRows = await wrapText({
|
|
26
64
|
text: titleText,
|
|
@@ -33,7 +71,7 @@ export const getPreparedTitle = async ({ title, chartWidth, chartMargin, }) => {
|
|
|
33
71
|
acc.push(row);
|
|
34
72
|
}
|
|
35
73
|
else {
|
|
36
|
-
acc[maxRowCount - 1].text
|
|
74
|
+
acc[maxRowCount - 1] = Object.assign(Object.assign({}, acc[maxRowCount - 1]), { text: acc[maxRowCount - 1].text + row.text });
|
|
37
75
|
}
|
|
38
76
|
return acc;
|
|
39
77
|
}, []);
|
|
@@ -71,12 +109,11 @@ export const getPreparedTitle = async ({ title, chartWidth, chartMargin, }) => {
|
|
|
71
109
|
});
|
|
72
110
|
}
|
|
73
111
|
const totalTextHeight = contentRows.reduce((acc, row) => acc + row.size.height, 0);
|
|
74
|
-
const titleHeight = totalTextHeight;
|
|
75
112
|
return {
|
|
76
113
|
text: titleText,
|
|
77
114
|
style: titleStyle,
|
|
78
|
-
height:
|
|
79
|
-
margin:
|
|
115
|
+
height: totalTextHeight,
|
|
116
|
+
margin: titleMargin,
|
|
80
117
|
qa: title === null || title === void 0 ? void 0 : title.qa,
|
|
81
118
|
contentRows,
|
|
82
119
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { PreparedTitle } from '../../hooks';
|
|
3
|
-
type Props = PreparedTitle
|
|
4
|
-
|
|
3
|
+
type Props = PreparedTitle & {
|
|
4
|
+
htmlLayout?: HTMLElement | null;
|
|
5
|
+
};
|
|
6
|
+
export declare const Title: (props: Props) => React.JSX.Element | null;
|
|
5
7
|
export {};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { HtmlLayer } from '../../hooks/useShapes/HtmlLayer';
|
|
2
3
|
export const Title = (props) => {
|
|
3
|
-
const { style, qa, contentRows } = props;
|
|
4
|
+
const { style, qa, contentRows, html, htmlElements, htmlLayout } = props;
|
|
5
|
+
if (html) {
|
|
6
|
+
if (!htmlLayout || !htmlElements) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return React.createElement(HtmlLayer, { htmlLayout: htmlLayout, preparedData: { htmlElements } });
|
|
10
|
+
}
|
|
4
11
|
return (React.createElement("text", { dominantBaseline: "hanging", textAnchor: "middle", style: {
|
|
5
12
|
fill: style === null || style === void 0 ? void 0 : style.fontColor,
|
|
6
13
|
fontSize: style === null || style === void 0 ? void 0 : style.fontSize,
|
|
7
14
|
fontWeight: style === null || style === void 0 ? void 0 : style.fontWeight,
|
|
8
|
-
}, "data-qa": qa }, contentRows.map((row, i) => (React.createElement("tspan", { key: i, x: row.x, y: row.y, dominantBaseline: "hanging", dangerouslySetInnerHTML: { __html: row.text } })))));
|
|
15
|
+
}, "data-qa": qa }, contentRows === null || contentRows === void 0 ? void 0 : contentRows.map((row, i) => (React.createElement("tspan", { key: i, x: row.x, y: row.y, dominantBaseline: "hanging", dangerouslySetInnerHTML: { __html: row.text } })))));
|
|
9
16
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const annotationLabelDefaults: {
|
|
2
|
+
style: {
|
|
3
|
+
fontSize: string;
|
|
4
|
+
fontColor: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
export declare const annotationPopupDefaults: {
|
|
8
|
+
backgroundColor: string;
|
|
9
|
+
borderRadius: number;
|
|
10
|
+
offset: number;
|
|
11
|
+
padding: [number, number];
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const annotationLabelDefaults = {
|
|
2
|
+
style: {
|
|
3
|
+
fontSize: '13px',
|
|
4
|
+
fontColor: 'var(--g-color-text-light-primary)',
|
|
5
|
+
},
|
|
6
|
+
};
|
|
7
|
+
export const annotationPopupDefaults = {
|
|
8
|
+
backgroundColor: 'var(--g-color-base-float-heavy)',
|
|
9
|
+
borderRadius: 4,
|
|
10
|
+
offset: 5,
|
|
11
|
+
padding: [4, 8],
|
|
12
|
+
};
|
|
@@ -4,4 +4,4 @@ export declare const DEFAULT_LEGEND_SYMBOL_SIZE = 8;
|
|
|
4
4
|
export declare const DEFAULT_LEGEND_SYMBOL_PADDING = 5;
|
|
5
5
|
export declare const DEFAULT_DATALABELS_PADDING = 5;
|
|
6
6
|
export declare const DEFAULT_HALO_OPTIONS: Required<Halo>;
|
|
7
|
-
export declare const DEFAULT_POINT_MARKER_OPTIONS: Omit<Required<PointMarkerOptions>, 'enabled'>;
|
|
7
|
+
export declare const DEFAULT_POINT_MARKER_OPTIONS: Omit<Required<PointMarkerOptions>, 'color' | 'enabled'>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChartAnnotationLabel, ChartAnnotationPopup } from '../../types';
|
|
2
|
+
import type { PreparedAnnotation } from './types';
|
|
3
|
+
type AnnotationOptionsLabel = Omit<ChartAnnotationLabel, 'text'> | undefined;
|
|
4
|
+
export declare function prepareAnnotation(args: {
|
|
5
|
+
annotation: {
|
|
6
|
+
label: ChartAnnotationLabel;
|
|
7
|
+
popup?: ChartAnnotationPopup;
|
|
8
|
+
};
|
|
9
|
+
optionsLabel?: AnnotationOptionsLabel;
|
|
10
|
+
optionsPopup?: ChartAnnotationPopup;
|
|
11
|
+
}): Promise<PreparedAnnotation>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { annotationLabelDefaults, annotationPopupDefaults } from '../constants';
|
|
2
|
+
import { getTextSizeFn } from '../utils';
|
|
3
|
+
function resolvePadding(padding) {
|
|
4
|
+
if (padding === undefined) {
|
|
5
|
+
return annotationPopupDefaults.padding;
|
|
6
|
+
}
|
|
7
|
+
if (typeof padding === 'number') {
|
|
8
|
+
return [padding, padding];
|
|
9
|
+
}
|
|
10
|
+
return padding;
|
|
11
|
+
}
|
|
12
|
+
export async function prepareAnnotation(args) {
|
|
13
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
14
|
+
const { annotation, optionsLabel, optionsPopup } = args;
|
|
15
|
+
const style = Object.assign(Object.assign(Object.assign({}, annotationLabelDefaults.style), optionsLabel === null || optionsLabel === void 0 ? void 0 : optionsLabel.style), annotation.label.style);
|
|
16
|
+
const getTextSize = getTextSizeFn({ style });
|
|
17
|
+
const textSize = await getTextSize(annotation.label.text);
|
|
18
|
+
return {
|
|
19
|
+
label: {
|
|
20
|
+
style,
|
|
21
|
+
text: annotation.label.text,
|
|
22
|
+
size: { height: textSize.height, width: textSize.width },
|
|
23
|
+
},
|
|
24
|
+
popup: {
|
|
25
|
+
backgroundColor: (_c = (_b = (_a = annotation.popup) === null || _a === void 0 ? void 0 : _a.backgroundColor) !== null && _b !== void 0 ? _b : optionsPopup === null || optionsPopup === void 0 ? void 0 : optionsPopup.backgroundColor) !== null && _c !== void 0 ? _c : annotationPopupDefaults.backgroundColor,
|
|
26
|
+
borderRadius: (_f = (_e = (_d = annotation.popup) === null || _d === void 0 ? void 0 : _d.borderRadius) !== null && _e !== void 0 ? _e : optionsPopup === null || optionsPopup === void 0 ? void 0 : optionsPopup.borderRadius) !== null && _f !== void 0 ? _f : annotationPopupDefaults.borderRadius,
|
|
27
|
+
offset: (_j = (_h = (_g = annotation.popup) === null || _g === void 0 ? void 0 : _g.offset) !== null && _h !== void 0 ? _h : optionsPopup === null || optionsPopup === void 0 ? void 0 : optionsPopup.offset) !== null && _j !== void 0 ? _j : annotationPopupDefaults.offset,
|
|
28
|
+
padding: resolvePadding((_l = (_k = annotation.popup) === null || _k === void 0 ? void 0 : _k.padding) !== null && _l !== void 0 ? _l : optionsPopup === null || optionsPopup === void 0 ? void 0 : optionsPopup.padding),
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData, XRangeSeries, XRangeSeriesData } from '../../types';
|
|
2
2
|
import type { DashStyle, LayoutAlgorithm, LineCap, LineJoin, SeriesOptionsDefaults, SymbolType } from '../constants';
|
|
3
|
+
export type PreparedAnnotation = {
|
|
4
|
+
label: {
|
|
5
|
+
size: {
|
|
6
|
+
height: number;
|
|
7
|
+
width: number;
|
|
8
|
+
};
|
|
9
|
+
style: BaseTextStyle;
|
|
10
|
+
text: string;
|
|
11
|
+
};
|
|
12
|
+
popup: {
|
|
13
|
+
backgroundColor: string;
|
|
14
|
+
borderRadius: number;
|
|
15
|
+
offset: number;
|
|
16
|
+
padding: [number, number];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
3
19
|
export type RectLegendSymbol = {
|
|
4
20
|
shape: 'rect';
|
|
5
21
|
} & Required<RectLegendSymbolOptions>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { BaseTextStyle } from './base';
|
|
2
|
+
export interface ChartAnnotationLabel {
|
|
3
|
+
/** Annotation text */
|
|
4
|
+
text: string;
|
|
5
|
+
/** Text style. fontColor defaults to 'var(--g-color-text-light-primary)' */
|
|
6
|
+
style?: Partial<BaseTextStyle>;
|
|
7
|
+
}
|
|
8
|
+
export interface ChartAnnotationPopup {
|
|
9
|
+
/**
|
|
10
|
+
* Background color of the popup.
|
|
11
|
+
* @default 'var(--g-color-base-float-heavy)'
|
|
12
|
+
*/
|
|
13
|
+
backgroundColor?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Border radius of the popup.
|
|
16
|
+
* @default 4
|
|
17
|
+
*/
|
|
18
|
+
borderRadius?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Distance in pixels between the anchor point and the popup edge along the main axis.
|
|
21
|
+
* The main axis depends on the automatically chosen placement:
|
|
22
|
+
* for top/bottom — vertical distance, for left/right — horizontal distance.
|
|
23
|
+
* @default 5
|
|
24
|
+
*/
|
|
25
|
+
offset?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Popup padding. Number or [vertical, horizontal].
|
|
28
|
+
* @default [4, 8]
|
|
29
|
+
*/
|
|
30
|
+
padding?: number | [number, number];
|
|
31
|
+
}
|
|
32
|
+
/** Default annotation settings applied to all data points in a series */
|
|
33
|
+
export interface ChartAnnotationSeriesOptions {
|
|
34
|
+
/** Default label style for annotations */
|
|
35
|
+
label?: Omit<ChartAnnotationLabel, 'text'>;
|
|
36
|
+
/** Default popup settings for annotations */
|
|
37
|
+
popup?: ChartAnnotationPopup;
|
|
38
|
+
}
|
|
39
|
+
/** Annotation for a specific data point. Renders as a popup with text label near the data point. */
|
|
40
|
+
export interface ChartPointAnnotation {
|
|
41
|
+
/** Text content and style of the annotation */
|
|
42
|
+
label: ChartAnnotationLabel;
|
|
43
|
+
/** Visual settings for the annotation popup container (background, padding, etc.) */
|
|
44
|
+
popup?: ChartAnnotationPopup;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SERIES_TYPE } from '../../constants';
|
|
2
2
|
import type { MeaningfulAny } from '../misc';
|
|
3
|
+
import type { ChartPointAnnotation } from './annotation';
|
|
3
4
|
import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
|
|
4
5
|
import type { RectLegendSymbolOptions } from './legend';
|
|
5
6
|
import type { PointMarkerOptions } from './marker';
|
|
@@ -23,6 +24,8 @@ export interface AreaSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
|
|
|
23
24
|
label?: string | number;
|
|
24
25
|
/** Individual marker options for the point. */
|
|
25
26
|
marker?: {
|
|
27
|
+
/** Fill color of the marker for this point */
|
|
28
|
+
color?: string;
|
|
26
29
|
/** States for a single point marker. */
|
|
27
30
|
states?: {
|
|
28
31
|
/** The normal state of a single point marker. */
|
|
@@ -35,6 +38,11 @@ export interface AreaSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
|
|
|
35
38
|
};
|
|
36
39
|
};
|
|
37
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Annotation displayed near this data point as a bubble with text label and optional marker.
|
|
43
|
+
* Useful for highlighting specific values, events, or adding contextual notes.
|
|
44
|
+
*/
|
|
45
|
+
annotation?: ChartPointAnnotation;
|
|
38
46
|
}
|
|
39
47
|
export type AreaMarkerSymbol = 'circle' | 'square';
|
|
40
48
|
export interface AreaMarkerOptions extends PointMarkerOptions {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SERIES_TYPE } from '../../constants';
|
|
2
2
|
import type { MeaningfulAny } from '../misc';
|
|
3
|
+
import type { ChartPointAnnotation } from './annotation';
|
|
3
4
|
import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
|
|
4
5
|
import type { RectLegendSymbolOptions } from './legend';
|
|
5
6
|
import type { ChartSeriesOptions, ChartSeriesRangeSliderOptions } from './series';
|
|
@@ -27,6 +28,11 @@ export interface BarXSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
|
|
|
27
28
|
label?: string | number;
|
|
28
29
|
/** Individual opacity for the bar-x column. */
|
|
29
30
|
opacity?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Annotation displayed near this data point as a bubble with text label.
|
|
33
|
+
* Useful for highlighting specific values, events, or adding contextual notes.
|
|
34
|
+
*/
|
|
35
|
+
annotation?: ChartPointAnnotation;
|
|
30
36
|
}
|
|
31
37
|
export interface BarXSeries<T = MeaningfulAny> extends BaseSeries {
|
|
32
38
|
type: typeof SERIES_TYPE.BarX;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DashStyle, LineCap, LineJoin, SERIES_TYPE } from '../../constants';
|
|
2
2
|
import type { MeaningfulAny } from '../misc';
|
|
3
|
+
import type { ChartPointAnnotation } from './annotation';
|
|
3
4
|
import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
|
|
4
5
|
import type { RectLegendSymbolOptions } from './legend';
|
|
5
6
|
import type { PointMarkerOptions } from './marker';
|
|
@@ -22,12 +23,19 @@ export interface LineSeriesData<T = MeaningfulAny> extends BaseSeriesData<T> {
|
|
|
22
23
|
/** Data label value of the point. If not specified, the y value is used. */
|
|
23
24
|
label?: string | number;
|
|
24
25
|
marker?: {
|
|
26
|
+
/** Fill color of the marker for this point */
|
|
27
|
+
color?: string;
|
|
25
28
|
states?: {
|
|
26
29
|
normal?: {
|
|
27
30
|
enabled: boolean;
|
|
28
31
|
};
|
|
29
32
|
};
|
|
30
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Annotation displayed near this data point as a bubble with text label and optional marker.
|
|
36
|
+
* Useful for highlighting specific values, events, or adding contextual notes.
|
|
37
|
+
*/
|
|
38
|
+
annotation?: ChartPointAnnotation;
|
|
31
39
|
}
|
|
32
40
|
export interface LineSeriesLineBaseStyle {
|
|
33
41
|
/**
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { SymbolType } from '../../constants';
|
|
2
2
|
export interface PointMarkerOptions {
|
|
3
|
-
/** Enable or disable the point marker */
|
|
4
|
-
enabled?: boolean;
|
|
5
|
-
/** The radius of the point marker */
|
|
6
|
-
radius?: number;
|
|
7
3
|
/** The color of the point marker's border */
|
|
8
4
|
borderColor?: string;
|
|
9
5
|
/** The width of the point marker's border */
|
|
10
6
|
borderWidth?: number;
|
|
7
|
+
/** Fill color of the marker */
|
|
8
|
+
color?: string;
|
|
9
|
+
/** Enable or disable the point marker */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
/** The radius of the point marker */
|
|
12
|
+
radius?: number;
|
|
11
13
|
symbol?: `${SymbolType}`;
|
|
12
14
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { DashStyle, LineCap, LineJoin } from '../../constants';
|
|
3
3
|
import type { MeaningfulAny } from '../misc';
|
|
4
|
+
import type { ChartAnnotationSeriesOptions } from './annotation';
|
|
4
5
|
import type { AreaSeries, AreaSeriesData } from './area';
|
|
5
6
|
import type { BarXSeries, BarXSeriesData } from './bar-x';
|
|
6
7
|
import type { BarYSeries, BarYSeriesData } from './bar-y';
|
|
@@ -101,6 +102,8 @@ export interface ChartSeriesOptions {
|
|
|
101
102
|
hover?: BasicHoverState;
|
|
102
103
|
inactive?: BasicInactiveState;
|
|
103
104
|
};
|
|
105
|
+
/** Default annotation settings for all bar-x data points */
|
|
106
|
+
annotation?: ChartAnnotationSeriesOptions;
|
|
104
107
|
};
|
|
105
108
|
'bar-y'?: {
|
|
106
109
|
/**
|
|
@@ -212,6 +215,8 @@ export interface ChartSeriesOptions {
|
|
|
212
215
|
* @default 'round' when dashStyle is not 'solid', 'unset' when dashStyle is not 'solid'
|
|
213
216
|
*/
|
|
214
217
|
linejoin?: `${LineJoin}`;
|
|
218
|
+
/** Default annotation settings for all line data points */
|
|
219
|
+
annotation?: ChartAnnotationSeriesOptions;
|
|
215
220
|
};
|
|
216
221
|
area?: {
|
|
217
222
|
/**
|
|
@@ -231,6 +236,8 @@ export interface ChartSeriesOptions {
|
|
|
231
236
|
};
|
|
232
237
|
/** Options for the point markers of line series */
|
|
233
238
|
marker?: PointMarkerOptions;
|
|
239
|
+
/** Default annotation settings for all area data points */
|
|
240
|
+
annotation?: ChartAnnotationSeriesOptions;
|
|
234
241
|
};
|
|
235
242
|
treemap?: {
|
|
236
243
|
/** Options for the series states that provide additional styling information to the series. */
|
|
@@ -5,6 +5,7 @@ export interface ChartTitle {
|
|
|
5
5
|
/**
|
|
6
6
|
* Maximum number of text rows. If the text exceeds this limit, it is truncated with an ellipsis.
|
|
7
7
|
* Default: 1
|
|
8
|
+
* Not applicable when `html: true` — HTML content manages its own layout.
|
|
8
9
|
*/
|
|
9
10
|
maxRowCount?: number;
|
|
10
11
|
/**
|
|
@@ -17,4 +18,21 @@ export interface ChartTitle {
|
|
|
17
18
|
* It is assigned as a data-qa attribute to an element.
|
|
18
19
|
*/
|
|
19
20
|
qa?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Enables HTML rendering for the chart title.
|
|
23
|
+
* When true, the title is rendered as an HTML element on top of the SVG
|
|
24
|
+
* instead of an SVG text node. This allows using arbitrary HTML tags
|
|
25
|
+
* (e.g. links, styled spans) that cannot be embedded in SVG.
|
|
26
|
+
* The element will be displayed outside the box of the SVG element.
|
|
27
|
+
*/
|
|
28
|
+
html?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum height of the title area. Accepts a pixel value (`number` or `"100px"`)
|
|
31
|
+
* or a percentage string (`"50%"`) relative to the full chart height.
|
|
32
|
+
* When the title content exceeds this height, it is clipped.
|
|
33
|
+
* Only applicable when `html: true`.
|
|
34
|
+
*
|
|
35
|
+
* Default: 50%
|
|
36
|
+
*/
|
|
37
|
+
maxHeight?: string | number;
|
|
20
38
|
}
|
|
@@ -7,6 +7,7 @@ import type { ChartTitle } from './chart/title';
|
|
|
7
7
|
import type { ChartTooltip } from './chart/tooltip';
|
|
8
8
|
import type { MeaningfulAny } from './misc';
|
|
9
9
|
export * from './misc';
|
|
10
|
+
export * from './chart/annotation';
|
|
10
11
|
export * from './chart/axis';
|
|
11
12
|
export * from './chart/base';
|
|
12
13
|
export * from './chart/chart';
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { Selection } from 'd3-selection';
|
|
2
2
|
import type { BaseTextStyle, MeaningfulAny } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Approximate ratio of descenders relative to the full font em height.
|
|
5
|
+
* Based on the Chromium hanging baseline algorithm where hanging offset ≈ ascent × 0.2.
|
|
6
|
+
* This means ascent ≈ 80% of em height, descenders ≈ 20%.
|
|
7
|
+
*
|
|
8
|
+
* @see https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/canvas/text_metrics.cc;l=32
|
|
9
|
+
*/
|
|
10
|
+
export declare const DESCENDER_RATIO = 0.2;
|
|
3
11
|
export declare function handleOverflowingText(tSpan: SVGTSpanElement | null, maxWidth: number, textWidth?: number): void;
|
|
4
12
|
export declare function setEllipsisForOverflowText<T>(selection: Selection<SVGTextElement, T, null, unknown>, maxWidth: number, textWidth?: number): void;
|
|
5
13
|
export declare function setEllipsisForOverflowTexts<T>(selection: Selection<SVGTextElement, T, MeaningfulAny, unknown>, maxWidth: ((datum: T) => number) | number, currentWidth?: (datum: T) => number): void;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { select } from 'd3-selection';
|
|
2
2
|
import { block } from '../../utils/cn';
|
|
3
3
|
const b = block('chart');
|
|
4
|
+
/**
|
|
5
|
+
* Approximate ratio of descenders relative to the full font em height.
|
|
6
|
+
* Based on the Chromium hanging baseline algorithm where hanging offset ≈ ascent × 0.2.
|
|
7
|
+
* This means ascent ≈ 80% of em height, descenders ≈ 20%.
|
|
8
|
+
*
|
|
9
|
+
* @see https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/canvas/text_metrics.cc;l=32
|
|
10
|
+
*/
|
|
11
|
+
export const DESCENDER_RATIO = 0.2;
|
|
4
12
|
export function handleOverflowingText(tSpan, maxWidth, textWidth) {
|
|
5
13
|
var _a, _b, _c;
|
|
6
14
|
if (!tSpan) {
|
|
@@ -210,7 +218,7 @@ export function getTextSizeFn({ style }) {
|
|
|
210
218
|
return {
|
|
211
219
|
width: textMetric.width,
|
|
212
220
|
height: textMetric.fontBoundingBoxDescent + textMetric.fontBoundingBoxAscent,
|
|
213
|
-
hangingOffset: textMetric.fontBoundingBoxAscent *
|
|
221
|
+
hangingOffset: textMetric.fontBoundingBoxAscent * DESCENDER_RATIO,
|
|
214
222
|
};
|
|
215
223
|
};
|
|
216
224
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TextRowData } from '../components/types';
|
|
2
|
-
import type { ChartBrush, ChartData, ChartMargin, ChartTitle, ChartZoom, DeepRequired } from '../types';
|
|
2
|
+
import type { BaseTextStyle, ChartBrush, ChartData, ChartMargin, ChartTitle, ChartZoom, DeepRequired } from '../types';
|
|
3
|
+
import type { HtmlItem } from '../types/chart-ui';
|
|
3
4
|
export type PreparedZoom = DeepRequired<Omit<ChartZoom, 'enabled' | 'brush'>> & DeepRequired<{
|
|
4
5
|
brush: ChartBrush;
|
|
5
6
|
}>;
|
|
@@ -7,10 +8,12 @@ export type PreparedChart = {
|
|
|
7
8
|
margin: ChartMargin;
|
|
8
9
|
zoom: PreparedZoom | null;
|
|
9
10
|
};
|
|
10
|
-
export type PreparedTitle = Omit<ChartTitle, 'margin'> & {
|
|
11
|
+
export type PreparedTitle = Omit<ChartTitle, 'margin' | 'style'> & {
|
|
11
12
|
height: number;
|
|
12
13
|
margin: number;
|
|
13
|
-
|
|
14
|
+
style: BaseTextStyle;
|
|
15
|
+
contentRows?: TextRowData[];
|
|
16
|
+
htmlElements?: HtmlItem[];
|
|
14
17
|
};
|
|
15
18
|
export type PreparedTooltip = ChartData['tooltip'] & {
|
|
16
19
|
enabled: boolean;
|
|
@@ -19,8 +19,9 @@ export const HtmlLayer = (props) => {
|
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
21
|
return (React.createElement(Portal, { container: htmlLayout }, items.map((item, index) => {
|
|
22
|
-
var _a, _b, _c;
|
|
23
|
-
const
|
|
24
|
-
|
|
22
|
+
var _a, _b, _c, _d;
|
|
23
|
+
const scope = (_a = item.scope) !== null && _a !== void 0 ? _a : 'plot';
|
|
24
|
+
const style = Object.assign(Object.assign({}, item.style), { color: (_c = (_b = item.style) === null || _b === void 0 ? void 0 : _b.color) !== null && _c !== void 0 ? _c : (_d = item.style) === null || _d === void 0 ? void 0 : _d.fontColor, position: 'absolute', left: item.x, top: item.y });
|
|
25
|
+
return (React.createElement("div", { className: b('html-layer-item', { plot: scope === 'plot' }), key: index, dangerouslySetInnerHTML: { __html: item.content }, style: style }));
|
|
25
26
|
})));
|
|
26
27
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Selection } from 'd3-selection';
|
|
2
|
+
import type { PreparedAnnotation } from '../../../core/series/types';
|
|
3
|
+
type AnnotationAnchor = {
|
|
4
|
+
annotation: PreparedAnnotation;
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
export { type AnnotationAnchor };
|
|
9
|
+
export declare function renderAnnotations(args: {
|
|
10
|
+
anchors: AnnotationAnchor[];
|
|
11
|
+
container: Selection<SVGGElement, unknown, null, undefined>;
|
|
12
|
+
plotHeight: number;
|
|
13
|
+
plotWidth: number;
|
|
14
|
+
}): void;
|