vccs 0.5.0 → 0.6.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/cartesian/cartesian-axis/CartesianAxis.d.ts +1 -1
- package/dist/cartesian/cartesianPositionToCSSTranslate.d.ts +15 -0
- package/dist/cartesian/getCartesianPosition.d.ts +45 -0
- package/dist/cartesian/index.d.ts +1 -0
- package/dist/cartesian/type.d.ts +8 -0
- package/dist/components/Tooltip.d.ts +1 -1
- package/dist/components/legend/hooks/useLegend.d.ts +3 -0
- package/dist/components/legend/type.d.ts +18 -2
- package/dist/components/legend/utils.d.ts +9 -0
- package/dist/es/cartesian/axis/XAxis.mjs +11 -5
- package/dist/es/cartesian/axis/YAxis.mjs +11 -5
- package/dist/es/cartesian/cartesianPositionToCSSTranslate.mjs +28 -0
- package/dist/es/cartesian/getCartesianPosition.mjs +176 -0
- package/dist/es/chart/ChartsWrapper.mjs +6 -10
- package/dist/es/chart/generateCategoricalChart.mjs +32 -53
- package/dist/es/components/legend/Legend.mjs +5 -3
- package/dist/es/components/legend/hooks/useLegend.mjs +50 -9
- package/dist/es/components/legend/type.mjs +9 -1
- package/dist/es/components/legend/utils.mjs +12 -1
- package/dist/es/container/ResponsiveContainer.vue_vue_type_script_setup_true_lang.mjs +2 -11
- package/dist/es/hooks/useResponsiveSize.mjs +27 -0
- package/dist/es/hooks/useRoundedSize.mjs +31 -0
- package/dist/es/shape/Sector.mjs +1 -1
- package/dist/es/state/legendSlice.mjs +2 -0
- package/dist/es/state/selectors/axisSelectors.mjs +1 -1
- package/dist/es/state/selectors/barSelectors.mjs +1 -1
- package/dist/es/state/selectors/pieSelectors.mjs +1 -1
- package/dist/es/state/selectors/polarAxisSelectors.mjs +1 -1
- package/dist/es/state/selectors/radialBarSelectors.mjs +1 -1
- package/dist/es/state/selectors/selectLegendArea.mjs +19 -0
- package/dist/es/state/selectors/tooltipSelectors.mjs +1 -1
- package/dist/es/utils/chart.mjs +1 -1
- package/dist/es/utils/legend.mjs +23 -1
- package/dist/hooks/useResponsiveSize.d.ts +22 -0
- package/dist/hooks/useRoundedSize.d.ts +22 -0
- package/dist/state/legendSlice.d.ts +3 -0
- package/dist/state/selectors/selectLegendArea.d.ts +7 -0
- package/package.json +1 -1
|
@@ -205,9 +205,9 @@ export declare const CartesianAxis: import('vue').DefineComponent<import('vue').
|
|
|
205
205
|
height: number;
|
|
206
206
|
x: number;
|
|
207
207
|
y: number;
|
|
208
|
+
viewBox: Record<string, any>;
|
|
208
209
|
orientation: string;
|
|
209
210
|
stroke: string;
|
|
210
|
-
viewBox: Record<string, any>;
|
|
211
211
|
label: any;
|
|
212
212
|
ticks: readonly CartesianTickItem[];
|
|
213
213
|
hide: boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TextAnchor, TextVerticalAnchor } from './getCartesianPosition';
|
|
2
|
+
/**
|
|
3
|
+
* CalculatedCartesianPosition returns horizontalAnchor and verticalAnchor
|
|
4
|
+
* which work directly with an SVG text element
|
|
5
|
+
* but for use in HTML context we have to translate them into CSS transform(translate)
|
|
6
|
+
* so this is what this function is doing.
|
|
7
|
+
*
|
|
8
|
+
* horizontalPosition is type: 'start' | 'middle' | 'end' | 'inherit'
|
|
9
|
+
* verticalPosition is type: 'start' | 'middle' | 'end'
|
|
10
|
+
*
|
|
11
|
+
* @param horizontalPosition as returned from {@link getCartesianPosition}
|
|
12
|
+
* @param verticalPosition as returned from {@link getCartesianPosition}
|
|
13
|
+
* @return CSS transform string
|
|
14
|
+
*/
|
|
15
|
+
export declare function cartesianPositionToCSSTranslate(horizontalPosition: TextAnchor, verticalPosition: TextVerticalAnchor): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CartesianViewBoxRequired, TrapezoidViewBox } from './type';
|
|
2
|
+
export type TextAnchor = 'start' | 'middle' | 'end' | 'inherit';
|
|
3
|
+
export type TextVerticalAnchor = 'start' | 'middle' | 'end';
|
|
4
|
+
export declare function cartesianViewBoxToTrapezoid(box: undefined): undefined;
|
|
5
|
+
export declare function cartesianViewBoxToTrapezoid(box: CartesianViewBoxRequired | TrapezoidViewBox): TrapezoidViewBox;
|
|
6
|
+
/**
|
|
7
|
+
* @inline
|
|
8
|
+
*/
|
|
9
|
+
export type CartesianPosition = 'top' | 'left' | 'right' | 'bottom' | 'center' | 'insideLeft' | 'insideRight' | 'insideTop' | 'insideBottom' | 'insideTopLeft' | 'insideBottomLeft' | 'insideTopRight' | 'insideBottomRight' | {
|
|
10
|
+
x: number | string;
|
|
11
|
+
y: number | string;
|
|
12
|
+
};
|
|
13
|
+
export type GetCartesianPositionOptions = {
|
|
14
|
+
viewBox: TrapezoidViewBox | CartesianViewBoxRequired;
|
|
15
|
+
parentViewBox?: CartesianViewBoxRequired;
|
|
16
|
+
/**
|
|
17
|
+
* The offset to the specified "position". Direction of the offset depends on the position.
|
|
18
|
+
*/
|
|
19
|
+
offset?: number;
|
|
20
|
+
/**
|
|
21
|
+
* The position of the element relative to the view box.
|
|
22
|
+
*/
|
|
23
|
+
position?: CartesianPosition;
|
|
24
|
+
/**
|
|
25
|
+
* If true, the returned width and height will be clamped to keep the element within the parentViewBox.
|
|
26
|
+
* This is useful for preventing labels from overflowing the chart area.
|
|
27
|
+
*/
|
|
28
|
+
clamp?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export type CalculatedCartesianPosition = {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
horizontalAnchor: TextAnchor;
|
|
34
|
+
verticalAnchor: TextVerticalAnchor;
|
|
35
|
+
width?: number;
|
|
36
|
+
height?: number;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the position and alignment for a generic element in a Cartesian coordinate system.
|
|
40
|
+
*
|
|
41
|
+
* @param options - The options including viewBox, position, and offset.
|
|
42
|
+
* @returns The calculated x, y, alignment and size.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getCartesianPosition(options: GetCartesianPositionOptions): CalculatedCartesianPosition;
|
|
45
|
+
export declare function isOutsidePosition(position: CartesianPosition | undefined): boolean;
|
package/dist/cartesian/type.d.ts
CHANGED
|
@@ -18,4 +18,12 @@ export interface CartesianViewBox {
|
|
|
18
18
|
}
|
|
19
19
|
export type ViewBox = CartesianViewBox | PolarViewBox;
|
|
20
20
|
export type CartesianViewBoxRequired = Required<CartesianViewBox>;
|
|
21
|
+
export interface TrapezoidViewBox {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
upperWidth: number;
|
|
25
|
+
lowerWidth: number;
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}
|
|
21
29
|
export type Sign = 0 | 1 | -1;
|
|
@@ -268,8 +268,8 @@ export declare const Tooltip: import('vue').DefineComponent<import('vue').Extrac
|
|
|
268
268
|
readonly default: " : ";
|
|
269
269
|
};
|
|
270
270
|
}>> & Readonly<{}>, {
|
|
271
|
-
readonly cursor: boolean | object;
|
|
272
271
|
readonly offset: number;
|
|
272
|
+
readonly cursor: boolean | object;
|
|
273
273
|
readonly style: Record<string, any>;
|
|
274
274
|
readonly isAnimationActive: boolean;
|
|
275
275
|
readonly includeHidden: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CSSProperties } from 'vue';
|
|
2
|
+
import { LayoutType } from '../../../types';
|
|
2
3
|
import { LegendPayload } from '../../DefaultLegendContent';
|
|
3
4
|
import { LegendProps } from '../type';
|
|
4
5
|
export declare function useLegend(props: LegendProps): {
|
|
@@ -14,6 +15,8 @@ export declare function useLegend(props: LegendProps): {
|
|
|
14
15
|
processedPayload: import('vue').ComputedRef<LegendPayload[]>;
|
|
15
16
|
outerStyle: import('vue').ComputedRef<CSSProperties>;
|
|
16
17
|
legendPortal: import('vue').ComputedRef<HTMLElement>;
|
|
18
|
+
resolvedLayout: import('vue').ComputedRef<LayoutType>;
|
|
19
|
+
positionViewBox: import('vue').ComputedRef<Required<import('../../../cartesian/type').CartesianViewBox>>;
|
|
17
20
|
syncSettings: () => void;
|
|
18
21
|
syncSize: () => void;
|
|
19
22
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CSSProperties, PropType, VNode } from 'vue';
|
|
2
2
|
import { LayoutType, Margin } from '../../types';
|
|
3
|
+
import { CartesianPosition } from '../../cartesian/getCartesianPosition';
|
|
3
4
|
import { LegendType } from '../../types/legend';
|
|
4
5
|
import { HorizontalAlignmentType, LegendPayload, VerticalAlignmentType } from '../DefaultLegendContent';
|
|
5
6
|
import { VuePropsToType, WithSVGProps } from '../../types/common';
|
|
@@ -8,8 +9,8 @@ export interface LegendSlots {
|
|
|
8
9
|
}
|
|
9
10
|
export declare const LegendVueProps: {
|
|
10
11
|
readonly layout: {
|
|
11
|
-
readonly type: PropType<LayoutType>;
|
|
12
|
-
readonly default: "
|
|
12
|
+
readonly type: PropType<LayoutType | "auto">;
|
|
13
|
+
readonly default: "auto";
|
|
13
14
|
};
|
|
14
15
|
readonly align: {
|
|
15
16
|
readonly type: PropType<HorizontalAlignmentType>;
|
|
@@ -19,6 +20,21 @@ export declare const LegendVueProps: {
|
|
|
19
20
|
readonly type: PropType<VerticalAlignmentType>;
|
|
20
21
|
readonly default: "bottom";
|
|
21
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* The position of the legend relative to the chart.
|
|
25
|
+
* If this is defined, it overrides `align` and `verticalAlign`.
|
|
26
|
+
*/
|
|
27
|
+
readonly position: {
|
|
28
|
+
readonly type: PropType<CartesianPosition>;
|
|
29
|
+
readonly default: any;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The offset to the specified `position`. Direction of the offset depends on the position.
|
|
33
|
+
*/
|
|
34
|
+
readonly offset: {
|
|
35
|
+
readonly type: NumberConstructor;
|
|
36
|
+
readonly default: 0;
|
|
37
|
+
};
|
|
22
38
|
readonly width: NumberConstructor;
|
|
23
39
|
readonly height: NumberConstructor;
|
|
24
40
|
readonly iconSize: {
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { CSSProperties } from 'vue';
|
|
2
2
|
import { LayoutType, Margin } from '../../types';
|
|
3
|
+
import { CartesianPosition } from '../../cartesian/getCartesianPosition';
|
|
3
4
|
import { HorizontalAlignmentType, VerticalAlignmentType } from '../DefaultLegendContent';
|
|
4
5
|
type PositionInput = {
|
|
5
6
|
layout?: LayoutType;
|
|
6
7
|
align?: HorizontalAlignmentType;
|
|
7
8
|
verticalAlign?: VerticalAlignmentType;
|
|
8
9
|
};
|
|
10
|
+
export declare function getLayoutForPosition(position: CartesianPosition | undefined): LayoutType;
|
|
11
|
+
export declare function getOutsidePositionOffset(position: CartesianPosition | undefined, offset: number, box: {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}): {
|
|
15
|
+
top?: number;
|
|
16
|
+
left?: number;
|
|
17
|
+
};
|
|
9
18
|
export declare function getDefaultPosition(style: CSSProperties | undefined, props: PositionInput, margin: Margin, chartWidth: number, chartHeight: number, box: {
|
|
10
19
|
width: number;
|
|
11
20
|
height: number;
|
|
@@ -4,7 +4,7 @@ import { implicitXAxis, selectAxisScale, selectTicksOfAxis, selectXAxisPosition,
|
|
|
4
4
|
import { useAppDispatch, useAppSelector } from "../../state/hooks.mjs";
|
|
5
5
|
import { addXAxis, removeXAxis } from "../../state/cartesianAxisSlice.mjs";
|
|
6
6
|
import { CartesianAxis } from "../cartesian-axis/CartesianAxis.mjs";
|
|
7
|
-
import { createVNode, defineComponent, mergeProps, watchEffect } from "vue";
|
|
7
|
+
import { createVNode, defineComponent, mergeProps, onUnmounted, watchEffect } from "vue";
|
|
8
8
|
//#region src/cartesian/axis/XAxis.tsx
|
|
9
9
|
/**
|
|
10
10
|
* @fileOverview X Axis
|
|
@@ -78,7 +78,8 @@ var XAxisSettingsDispatcher = /* @__PURE__ */ defineComponent({
|
|
|
78
78
|
},
|
|
79
79
|
setup(props, { slots: dispatcherSlots }) {
|
|
80
80
|
const dispatch = useAppDispatch();
|
|
81
|
-
|
|
81
|
+
let registeredSettings;
|
|
82
|
+
watchEffect(() => {
|
|
82
83
|
const settings = {
|
|
83
84
|
interval: props.interval ?? "preserveEnd",
|
|
84
85
|
id: props.xAxisId,
|
|
@@ -105,10 +106,15 @@ var XAxisSettingsDispatcher = /* @__PURE__ */ defineComponent({
|
|
|
105
106
|
tick: props.tick ?? true,
|
|
106
107
|
tickFormatter: props.tickFormatter
|
|
107
108
|
};
|
|
109
|
+
if (registeredSettings && registeredSettings.id !== settings.id) dispatch(removeXAxis(registeredSettings));
|
|
108
110
|
dispatch(addXAxis(settings));
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
registeredSettings = settings;
|
|
112
|
+
});
|
|
113
|
+
onUnmounted(() => {
|
|
114
|
+
if (registeredSettings) {
|
|
115
|
+
dispatch(removeXAxis(registeredSettings));
|
|
116
|
+
registeredSettings = void 0;
|
|
117
|
+
}
|
|
112
118
|
});
|
|
113
119
|
return () => createVNode(XAxisImpl, props, { default: () => [dispatcherSlots.tick ? { tick: dispatcherSlots.tick } : void 0] });
|
|
114
120
|
}
|
|
@@ -5,7 +5,7 @@ import { useAppDispatch, useAppSelector } from "../../state/hooks.mjs";
|
|
|
5
5
|
import { addYAxis, removeYAxis, updateYAxisWidth } from "../../state/cartesianAxisSlice.mjs";
|
|
6
6
|
import { CartesianAxis } from "../cartesian-axis/CartesianAxis.mjs";
|
|
7
7
|
import { getCalculatedYAxisWidth } from "../../utils/YAxisUtils.mjs";
|
|
8
|
-
import { createVNode, defineComponent, isVNode, mergeProps, nextTick, ref, watch, watchEffect } from "vue";
|
|
8
|
+
import { createVNode, defineComponent, isVNode, mergeProps, nextTick, onUnmounted, ref, watch, watchEffect } from "vue";
|
|
9
9
|
//#region src/cartesian/axis/YAxis.tsx
|
|
10
10
|
var YAxisImpl = /* @__PURE__ */ defineComponent({
|
|
11
11
|
props: { yAxisId: {
|
|
@@ -125,7 +125,8 @@ var YAxisSettingsDispatcher = /* @__PURE__ */ defineComponent({
|
|
|
125
125
|
},
|
|
126
126
|
setup(props) {
|
|
127
127
|
const dispatch = useAppDispatch();
|
|
128
|
-
|
|
128
|
+
let registeredSettings;
|
|
129
|
+
watchEffect(() => {
|
|
129
130
|
const settings = {
|
|
130
131
|
...props,
|
|
131
132
|
interval: props.interval ?? "preserveEnd",
|
|
@@ -136,10 +137,15 @@ var YAxisSettingsDispatcher = /* @__PURE__ */ defineComponent({
|
|
|
136
137
|
minTickGap: props.minTickGap ?? 5,
|
|
137
138
|
tick: props.tick ?? true
|
|
138
139
|
};
|
|
140
|
+
if (registeredSettings && registeredSettings.id !== settings.id) dispatch(removeYAxis(registeredSettings));
|
|
139
141
|
dispatch(addYAxis(settings));
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
registeredSettings = settings;
|
|
143
|
+
});
|
|
144
|
+
onUnmounted(() => {
|
|
145
|
+
if (registeredSettings) {
|
|
146
|
+
dispatch(removeYAxis(registeredSettings));
|
|
147
|
+
registeredSettings = void 0;
|
|
148
|
+
}
|
|
143
149
|
});
|
|
144
150
|
return () => createVNode(YAxisImpl, props, null);
|
|
145
151
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/cartesian/cartesianPositionToCSSTranslate.ts
|
|
2
|
+
/**
|
|
3
|
+
* CalculatedCartesianPosition returns horizontalAnchor and verticalAnchor
|
|
4
|
+
* which work directly with an SVG text element
|
|
5
|
+
* but for use in HTML context we have to translate them into CSS transform(translate)
|
|
6
|
+
* so this is what this function is doing.
|
|
7
|
+
*
|
|
8
|
+
* horizontalPosition is type: 'start' | 'middle' | 'end' | 'inherit'
|
|
9
|
+
* verticalPosition is type: 'start' | 'middle' | 'end'
|
|
10
|
+
*
|
|
11
|
+
* @param horizontalPosition as returned from {@link getCartesianPosition}
|
|
12
|
+
* @param verticalPosition as returned from {@link getCartesianPosition}
|
|
13
|
+
* @return CSS transform string
|
|
14
|
+
*/
|
|
15
|
+
function cartesianPositionToCSSTranslate(horizontalPosition, verticalPosition) {
|
|
16
|
+
if (horizontalPosition === "start" && verticalPosition === "start") return "";
|
|
17
|
+
return `translate(${horizontalPosition === "inherit" ? "0" : {
|
|
18
|
+
start: "0",
|
|
19
|
+
middle: "-50%",
|
|
20
|
+
end: "-100%"
|
|
21
|
+
}[horizontalPosition]}, ${{
|
|
22
|
+
start: "0",
|
|
23
|
+
middle: "-50%",
|
|
24
|
+
end: "-100%"
|
|
25
|
+
}[verticalPosition] ?? "0"})`;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { cartesianPositionToCSSTranslate };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { isNumber, isPercent } from "../utils/validate.mjs";
|
|
2
|
+
import { getPercentValue } from "../utils/data.mjs";
|
|
3
|
+
//#region src/cartesian/getCartesianPosition.ts
|
|
4
|
+
function cartesianViewBoxToTrapezoid(box) {
|
|
5
|
+
if (!box) return;
|
|
6
|
+
return {
|
|
7
|
+
x: box.x,
|
|
8
|
+
y: box.y,
|
|
9
|
+
upperWidth: "upperWidth" in box ? box.upperWidth : box.width,
|
|
10
|
+
lowerWidth: "lowerWidth" in box ? box.lowerWidth : box.width,
|
|
11
|
+
width: box.width,
|
|
12
|
+
height: box.height
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Calculates the position and alignment for a generic element in a Cartesian coordinate system.
|
|
17
|
+
*
|
|
18
|
+
* @param options - The options including viewBox, position, and offset.
|
|
19
|
+
* @returns The calculated x, y, alignment and size.
|
|
20
|
+
*/
|
|
21
|
+
function getCartesianPosition(options) {
|
|
22
|
+
const { viewBox, position, offset = 0, parentViewBox, clamp } = options;
|
|
23
|
+
const { x, y, height, upperWidth, lowerWidth } = cartesianViewBoxToTrapezoid(viewBox);
|
|
24
|
+
const upperX = x;
|
|
25
|
+
const lowerX = x + (upperWidth - lowerWidth) / 2;
|
|
26
|
+
const middleX = (upperX + lowerX) / 2;
|
|
27
|
+
const midHeightWidth = (upperWidth + lowerWidth) / 2;
|
|
28
|
+
const centerX = upperX + upperWidth / 2;
|
|
29
|
+
const verticalSign = height >= 0 ? 1 : -1;
|
|
30
|
+
const verticalOffset = verticalSign * offset;
|
|
31
|
+
const verticalEnd = verticalSign > 0 ? "end" : "start";
|
|
32
|
+
const verticalStart = verticalSign > 0 ? "start" : "end";
|
|
33
|
+
const horizontalSign = upperWidth >= 0 ? 1 : -1;
|
|
34
|
+
const horizontalOffset = horizontalSign * offset;
|
|
35
|
+
const horizontalEnd = horizontalSign > 0 ? "end" : "start";
|
|
36
|
+
const horizontalStart = horizontalSign > 0 ? "start" : "end";
|
|
37
|
+
if (position === "top") {
|
|
38
|
+
const result = {
|
|
39
|
+
x: upperX + upperWidth / 2,
|
|
40
|
+
y: y - verticalOffset,
|
|
41
|
+
horizontalAnchor: "middle",
|
|
42
|
+
verticalAnchor: verticalEnd
|
|
43
|
+
};
|
|
44
|
+
if (clamp && parentViewBox) {
|
|
45
|
+
result.height = Math.max(y - parentViewBox.y, 0);
|
|
46
|
+
result.width = upperWidth;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
if (position === "bottom") {
|
|
51
|
+
const result = {
|
|
52
|
+
x: lowerX + lowerWidth / 2,
|
|
53
|
+
y: y + height + verticalOffset,
|
|
54
|
+
horizontalAnchor: "middle",
|
|
55
|
+
verticalAnchor: verticalStart
|
|
56
|
+
};
|
|
57
|
+
if (clamp && parentViewBox) {
|
|
58
|
+
result.height = Math.max(parentViewBox.y + parentViewBox.height - (y + height), 0);
|
|
59
|
+
result.width = lowerWidth;
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
if (position === "left") {
|
|
64
|
+
const result = {
|
|
65
|
+
x: middleX - horizontalOffset,
|
|
66
|
+
y: y + height / 2,
|
|
67
|
+
horizontalAnchor: horizontalEnd,
|
|
68
|
+
verticalAnchor: "middle"
|
|
69
|
+
};
|
|
70
|
+
if (clamp && parentViewBox) {
|
|
71
|
+
result.width = Math.max(result.x - parentViewBox.x, 0);
|
|
72
|
+
result.height = height;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
if (position === "right") {
|
|
77
|
+
const result = {
|
|
78
|
+
x: middleX + midHeightWidth + horizontalOffset,
|
|
79
|
+
y: y + height / 2,
|
|
80
|
+
horizontalAnchor: horizontalStart,
|
|
81
|
+
verticalAnchor: "middle"
|
|
82
|
+
};
|
|
83
|
+
if (clamp && parentViewBox) {
|
|
84
|
+
result.width = Math.max(parentViewBox.x + parentViewBox.width - result.x, 0);
|
|
85
|
+
result.height = height;
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
const sizeAttrs = clamp && parentViewBox ? {
|
|
90
|
+
width: midHeightWidth,
|
|
91
|
+
height
|
|
92
|
+
} : {};
|
|
93
|
+
if (position === "insideLeft") return {
|
|
94
|
+
x: middleX + horizontalOffset,
|
|
95
|
+
y: y + height / 2,
|
|
96
|
+
horizontalAnchor: horizontalStart,
|
|
97
|
+
verticalAnchor: "middle",
|
|
98
|
+
...sizeAttrs
|
|
99
|
+
};
|
|
100
|
+
if (position === "insideRight") return {
|
|
101
|
+
x: middleX + midHeightWidth - horizontalOffset,
|
|
102
|
+
y: y + height / 2,
|
|
103
|
+
horizontalAnchor: horizontalEnd,
|
|
104
|
+
verticalAnchor: "middle",
|
|
105
|
+
...sizeAttrs
|
|
106
|
+
};
|
|
107
|
+
if (position === "insideTop") return {
|
|
108
|
+
x: upperX + upperWidth / 2,
|
|
109
|
+
y: y + verticalOffset,
|
|
110
|
+
horizontalAnchor: "middle",
|
|
111
|
+
verticalAnchor: verticalStart,
|
|
112
|
+
...sizeAttrs
|
|
113
|
+
};
|
|
114
|
+
if (position === "insideBottom") return {
|
|
115
|
+
x: lowerX + lowerWidth / 2,
|
|
116
|
+
y: y + height - verticalOffset,
|
|
117
|
+
horizontalAnchor: "middle",
|
|
118
|
+
verticalAnchor: verticalEnd,
|
|
119
|
+
...sizeAttrs
|
|
120
|
+
};
|
|
121
|
+
if (position === "insideTopLeft") return {
|
|
122
|
+
x: upperX + horizontalOffset,
|
|
123
|
+
y: y + verticalOffset,
|
|
124
|
+
horizontalAnchor: horizontalStart,
|
|
125
|
+
verticalAnchor: verticalStart,
|
|
126
|
+
...sizeAttrs
|
|
127
|
+
};
|
|
128
|
+
if (position === "insideTopRight") return {
|
|
129
|
+
x: upperX + upperWidth - horizontalOffset,
|
|
130
|
+
y: y + verticalOffset,
|
|
131
|
+
horizontalAnchor: horizontalEnd,
|
|
132
|
+
verticalAnchor: verticalStart,
|
|
133
|
+
...sizeAttrs
|
|
134
|
+
};
|
|
135
|
+
if (position === "insideBottomLeft") return {
|
|
136
|
+
x: lowerX + horizontalOffset,
|
|
137
|
+
y: y + height - verticalOffset,
|
|
138
|
+
horizontalAnchor: horizontalStart,
|
|
139
|
+
verticalAnchor: verticalEnd,
|
|
140
|
+
...sizeAttrs
|
|
141
|
+
};
|
|
142
|
+
if (position === "insideBottomRight") return {
|
|
143
|
+
x: lowerX + lowerWidth - horizontalOffset,
|
|
144
|
+
y: y + height - verticalOffset,
|
|
145
|
+
horizontalAnchor: horizontalEnd,
|
|
146
|
+
verticalAnchor: verticalEnd,
|
|
147
|
+
...sizeAttrs
|
|
148
|
+
};
|
|
149
|
+
if (!!position && typeof position === "object" && (isNumber(position.x) || isPercent(position.x)) && (isNumber(position.y) || isPercent(position.y))) return {
|
|
150
|
+
x: x + getPercentValue(position.x, midHeightWidth),
|
|
151
|
+
y: y + getPercentValue(position.y, height),
|
|
152
|
+
horizontalAnchor: "end",
|
|
153
|
+
verticalAnchor: "end",
|
|
154
|
+
...sizeAttrs
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
x: centerX,
|
|
158
|
+
y: y + height / 2,
|
|
159
|
+
horizontalAnchor: "middle",
|
|
160
|
+
verticalAnchor: "middle",
|
|
161
|
+
...sizeAttrs
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
var absolutePositions = [
|
|
165
|
+
"top",
|
|
166
|
+
"left",
|
|
167
|
+
"right",
|
|
168
|
+
"bottom"
|
|
169
|
+
];
|
|
170
|
+
function isOutsidePosition(position) {
|
|
171
|
+
if (position == null) return false;
|
|
172
|
+
if (typeof position === "object") return true;
|
|
173
|
+
return absolutePositions.includes(position);
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
export { getCartesianPosition, isOutsidePosition };
|
|
@@ -10,7 +10,7 @@ import { useSynchronisedEventsFromOtherCharts } from "../events/useChartSynchron
|
|
|
10
10
|
import { useReportScale } from "../state/utils/useReportScale.mjs";
|
|
11
11
|
import { providePortalRaw } from "./TooltipPortalContext.mjs";
|
|
12
12
|
import { provideLegendPortalRaw } from "./LegendPortalContext.mjs";
|
|
13
|
-
import { createVNode, defineComponent,
|
|
13
|
+
import { createVNode, defineComponent, ref, watch } from "vue";
|
|
14
14
|
import { useResizeObserver } from "@vueuse/core";
|
|
15
15
|
//#region src/chart/ChartsWrapper.tsx
|
|
16
16
|
var ChartsWrapper = /* @__PURE__ */ defineComponent({
|
|
@@ -62,17 +62,13 @@ var ChartsWrapper = /* @__PURE__ */ defineComponent({
|
|
|
62
62
|
legendPortal.value = node;
|
|
63
63
|
wrapperEl.value = node;
|
|
64
64
|
};
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
watch(() => props.responsive, (responsive, _, onCleanup) => {
|
|
66
|
+
if (!responsive) return;
|
|
67
|
+
onCleanup(useResizeObserver(wrapperEl, (entries) => {
|
|
67
68
|
const { width, height } = entries[0].contentRect;
|
|
68
69
|
props.onResize?.(width, height);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
if (!wrapperEl.value) return;
|
|
72
|
-
const { width, height } = wrapperEl.value.getBoundingClientRect();
|
|
73
|
-
props.onResize?.(width, height);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
70
|
+
}).stop);
|
|
71
|
+
}, { immediate: true });
|
|
76
72
|
const myOnClick = (e) => {
|
|
77
73
|
const chartPointer = getChartPointer(e);
|
|
78
74
|
if (chartPointer) dispatch(mouseClickAction(chartPointer));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { classProp } from "../types/common.mjs";
|
|
2
|
-
import { validateWidthHeight } from "../utils/validate.mjs";
|
|
3
2
|
import { provideClipPathId } from "./provideClipPathId.mjs";
|
|
4
3
|
import { createRechartsStore } from "../state/store.mjs";
|
|
5
4
|
import Surface_default from "./Surface.mjs";
|
|
@@ -11,7 +10,8 @@ import { ReportMainChartProps } from "../state/ReportMainChartProps.mjs";
|
|
|
11
10
|
import ReportChartProps_default from "../state/ReportChartProps.mjs";
|
|
12
11
|
import { applyDefaultProps } from "../utils/props.mjs";
|
|
13
12
|
import { ReportPolarOptions } from "../state/ReportPolarOptions.mjs";
|
|
14
|
-
import {
|
|
13
|
+
import { useResponsiveSize } from "../hooks/useResponsiveSize.mjs";
|
|
14
|
+
import { Fragment, createVNode, defineComponent, mergeProps } from "vue";
|
|
15
15
|
import { provideStore } from "@reduxjs/vue-redux";
|
|
16
16
|
//#region src/chart/generateCategoricalChart.tsx
|
|
17
17
|
var defaultLayout = "horizontal";
|
|
@@ -106,57 +106,43 @@ function generateCategoricalChart({ chartName, defaultProps = {}, defaultTooltip
|
|
|
106
106
|
eventEmitter: void 0
|
|
107
107
|
} }, props.id ?? chartName) });
|
|
108
108
|
const clipPathId = provideClipPathId(props);
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
109
|
+
const { effectiveWidth, effectiveHeight, hasValidSize, handleResize } = useResponsiveSize(props);
|
|
110
|
+
function renderPolarOptions(isPolarChart) {
|
|
111
|
+
if (!isPolarChart) return null;
|
|
112
|
+
return createVNode(ReportPolarOptions, {
|
|
113
|
+
"cx": props.cx ?? "50%",
|
|
114
|
+
"cy": props.cy ?? "50%",
|
|
115
|
+
"startAngle": props.startAngle ?? defaultProps.startAngle ?? 90,
|
|
116
|
+
"endAngle": props.endAngle ?? defaultProps.endAngle ?? -270,
|
|
117
|
+
"innerRadius": props.innerRadius ?? 0,
|
|
118
|
+
"outerRadius": props.outerRadius ?? "80%"
|
|
119
|
+
}, null);
|
|
121
120
|
}
|
|
122
121
|
return () => {
|
|
123
122
|
const { compact, width, height, title, desc, responsive, ...rest } = props;
|
|
124
123
|
const attributes = { ...attrs };
|
|
125
|
-
const effectiveWidth = responsive ? responsiveSize.value.width : width;
|
|
126
|
-
const effectiveHeight = responsive ? responsiveSize.value.height : height;
|
|
127
|
-
const hasValidSize = validateWidthHeight({
|
|
128
|
-
width: effectiveWidth,
|
|
129
|
-
height: effectiveHeight
|
|
130
|
-
});
|
|
131
124
|
const layout = props.layout ?? defaultProps.layout ?? defaultLayout;
|
|
132
125
|
const isPolarChart = layout === "centric" || layout === "radial";
|
|
133
126
|
if (compact) {
|
|
134
|
-
if (!hasValidSize) return null;
|
|
127
|
+
if (!hasValidSize.value) return null;
|
|
135
128
|
return createVNode(Fragment, null, [
|
|
136
129
|
createVNode(ChartDataContextProvider, { "chartData": props.data }, null),
|
|
137
130
|
createVNode(ReportMainChartProps, {
|
|
138
|
-
"width": effectiveWidth,
|
|
139
|
-
"height": effectiveHeight,
|
|
131
|
+
"width": effectiveWidth.value,
|
|
132
|
+
"height": effectiveHeight.value,
|
|
140
133
|
"layout": layout,
|
|
141
|
-
"margin": props.margin
|
|
142
|
-
}, null),
|
|
143
|
-
isPolarChart && createVNode(ReportPolarOptions, {
|
|
144
|
-
"cx": props.cx ?? "50%",
|
|
145
|
-
"cy": props.cy ?? "50%",
|
|
146
|
-
"startAngle": props.startAngle ?? defaultProps.startAngle ?? 90,
|
|
147
|
-
"endAngle": props.endAngle ?? defaultProps.endAngle ?? -270,
|
|
148
|
-
"innerRadius": props.innerRadius ?? 0,
|
|
149
|
-
"outerRadius": props.outerRadius ?? "80%"
|
|
134
|
+
"margin": props.margin
|
|
150
135
|
}, null),
|
|
136
|
+
renderPolarOptions(isPolarChart),
|
|
151
137
|
createVNode(Surface_default, mergeProps(attrs, rest, {
|
|
152
|
-
"width": effectiveWidth,
|
|
153
|
-
"height": effectiveHeight,
|
|
138
|
+
"width": effectiveWidth.value,
|
|
139
|
+
"height": effectiveHeight.value,
|
|
154
140
|
"title": title,
|
|
155
141
|
"desc": desc
|
|
156
142
|
}), { default: () => [createVNode(ClipPath_default, { "clipPathId": clipPathId }, null), slots.default?.()] })
|
|
157
143
|
]);
|
|
158
144
|
}
|
|
159
|
-
if (!responsive && !hasValidSize) return null;
|
|
145
|
+
if (!responsive && !hasValidSize.value) return null;
|
|
160
146
|
if (props.accessibilityLayer) {
|
|
161
147
|
attributes.tabindex = props.tabIndex ?? 0;
|
|
162
148
|
attributes.role = props.role ?? "application";
|
|
@@ -166,36 +152,29 @@ function generateCategoricalChart({ chartName, defaultProps = {}, defaultTooltip
|
|
|
166
152
|
for (const [key, value] of Object.entries(attributes)) if (key.startsWith("on") && typeof value === "function") eventHandlerAttrs[key] = value;
|
|
167
153
|
else svgAttributes[key] = value;
|
|
168
154
|
return createVNode(Fragment, null, [
|
|
169
|
-
hasValidSize && createVNode(ChartDataContextProvider, { "chartData": props.data }, null),
|
|
170
|
-
hasValidSize && createVNode(ReportMainChartProps, {
|
|
171
|
-
"width": effectiveWidth,
|
|
172
|
-
"height": effectiveHeight,
|
|
155
|
+
hasValidSize.value && createVNode(ChartDataContextProvider, { "chartData": props.data }, null),
|
|
156
|
+
hasValidSize.value && createVNode(ReportMainChartProps, {
|
|
157
|
+
"width": effectiveWidth.value,
|
|
158
|
+
"height": effectiveHeight.value,
|
|
173
159
|
"layout": layout,
|
|
174
160
|
"margin": props.margin ?? defaultMargin
|
|
175
161
|
}, null),
|
|
176
|
-
hasValidSize && isPolarChart
|
|
177
|
-
"cx": props.cx ?? "50%",
|
|
178
|
-
"cy": props.cy ?? "50%",
|
|
179
|
-
"startAngle": props.startAngle ?? defaultProps.startAngle ?? 90,
|
|
180
|
-
"endAngle": props.endAngle ?? defaultProps.endAngle ?? -270,
|
|
181
|
-
"innerRadius": props.innerRadius ?? 0,
|
|
182
|
-
"outerRadius": props.outerRadius ?? "80%"
|
|
183
|
-
}, null),
|
|
162
|
+
hasValidSize.value && renderPolarOptions(isPolarChart),
|
|
184
163
|
createVNode(ChartsWrapper, mergeProps({
|
|
185
164
|
"responsive": responsive,
|
|
186
165
|
"onResize": handleResize,
|
|
187
166
|
"style": props.style,
|
|
188
167
|
"class": props.class,
|
|
189
|
-
"width": effectiveWidth,
|
|
190
|
-
"height": effectiveHeight
|
|
191
|
-
}, eventHandlerAttrs), { default: () => [hasValidSize && createVNode(Surface_default, mergeProps(svgAttributes, {
|
|
192
|
-
"width": effectiveWidth,
|
|
193
|
-
"height": effectiveHeight,
|
|
168
|
+
"width": effectiveWidth.value,
|
|
169
|
+
"height": effectiveHeight.value
|
|
170
|
+
}, eventHandlerAttrs), { default: () => [hasValidSize.value && createVNode(Surface_default, mergeProps(svgAttributes, {
|
|
171
|
+
"width": effectiveWidth.value,
|
|
172
|
+
"height": effectiveHeight.value,
|
|
194
173
|
"title": title,
|
|
195
174
|
"desc": desc,
|
|
196
175
|
"style": FULL_WIDTH_AND_HEIGHT
|
|
197
176
|
}), { default: () => [createVNode(ClipPath_default, { "clipPathId": clipPathId }, null), slots.default?.()] }), slots.tooltip?.()] }),
|
|
198
|
-
hasValidSize && createVNode(ReportChartProps_default, props, null)
|
|
177
|
+
hasValidSize.value && createVNode(ReportChartProps_default, props, null)
|
|
199
178
|
]);
|
|
200
179
|
};
|
|
201
180
|
}
|
|
@@ -12,7 +12,7 @@ var Legend_default = /* @__PURE__ */ defineComponent({
|
|
|
12
12
|
name: "Legend",
|
|
13
13
|
props: LegendVueProps,
|
|
14
14
|
setup(props, { slots }) {
|
|
15
|
-
const { legendRef, processedPayload, outerStyle, legendPortal, syncSettings, syncSize } = useLegend(props);
|
|
15
|
+
const { legendRef, processedPayload, outerStyle, legendPortal, resolvedLayout, positionViewBox, syncSettings, syncSize } = useLegend(props);
|
|
16
16
|
const { getItemStyle, getSvgStyle, formatValue, handleClick, handleMouseEnter, handleMouseLeave } = useLegendContent(props);
|
|
17
17
|
watchEffect(() => {
|
|
18
18
|
syncSettings();
|
|
@@ -20,7 +20,8 @@ var Legend_default = /* @__PURE__ */ defineComponent({
|
|
|
20
20
|
});
|
|
21
21
|
const renderDefaultContent = () => {
|
|
22
22
|
if (!processedPayload.value || processedPayload.value.length === 0) return null;
|
|
23
|
-
const {
|
|
23
|
+
const { align = "center", iconSize = 14 } = props;
|
|
24
|
+
const layout = resolvedLayout.value;
|
|
24
25
|
const finalStyle = {
|
|
25
26
|
padding: 0,
|
|
26
27
|
margin: 0,
|
|
@@ -73,13 +74,14 @@ var Legend_default = /* @__PURE__ */ defineComponent({
|
|
|
73
74
|
if (!processedPayload.value || processedPayload.value.length === 0) return null;
|
|
74
75
|
const contentProps = {
|
|
75
76
|
...props,
|
|
77
|
+
layout: resolvedLayout.value,
|
|
76
78
|
payload: processedPayload.value
|
|
77
79
|
};
|
|
78
80
|
if (slots.content) return slots.content(contentProps);
|
|
79
81
|
return renderDefaultContent();
|
|
80
82
|
};
|
|
81
83
|
return () => {
|
|
82
|
-
if (legendPortal.value == null) return null;
|
|
84
|
+
if (legendPortal.value == null || props.position != null && positionViewBox.value == null) return null;
|
|
83
85
|
const legendElement = createVNode("div", {
|
|
84
86
|
"class": "v-charts-legend-wrapper",
|
|
85
87
|
"style": outerStyle.value,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { selectLegendPayload } from "../../../state/selectors/legendSelectors.mjs";
|
|
2
|
+
import { getCartesianPosition, isOutsidePosition } from "../../../cartesian/getCartesianPosition.mjs";
|
|
2
3
|
import { useAppDispatch, useAppSelector } from "../../../state/hooks.mjs";
|
|
3
|
-
import { useChartHeight, useChartWidth, useMargin } from "../../../context/chartLayoutContext.mjs";
|
|
4
|
+
import { useChartHeight, useChartWidth, useMargin, useViewBox } from "../../../context/chartLayoutContext.mjs";
|
|
4
5
|
import { setLegendSettings, setLegendSize } from "../../../state/legendSlice.mjs";
|
|
5
6
|
import { useLegendPortal } from "../../../chart/LegendPortalContext.mjs";
|
|
7
|
+
import { selectLegendArea } from "../../../state/selectors/selectLegendArea.mjs";
|
|
6
8
|
import { getUniqPayload } from "../../../utils/payload/getUniqPayload.mjs";
|
|
7
|
-
import {
|
|
9
|
+
import { cartesianPositionToCSSTranslate } from "../../../cartesian/cartesianPositionToCSSTranslate.mjs";
|
|
10
|
+
import { defaultUniqBy, getDefaultPosition, getLayoutForPosition, getOutsidePositionOffset, getWidthOrHeight } from "../utils.mjs";
|
|
8
11
|
import { computed, ref } from "vue";
|
|
9
12
|
import { sortBy } from "es-toolkit/compat";
|
|
10
13
|
import { useElementBounding } from "@vueuse/core";
|
|
@@ -16,14 +19,22 @@ function useLegend(props) {
|
|
|
16
19
|
const margin = useMargin();
|
|
17
20
|
const chartWidth = useChartWidth();
|
|
18
21
|
const chartHeight = useChartHeight();
|
|
22
|
+
const viewBox = useViewBox();
|
|
23
|
+
const legendArea = useAppSelector(selectLegendArea);
|
|
19
24
|
const legendRef = ref();
|
|
20
25
|
const { width: boundingWidth, height: boundingHeight } = useElementBounding(legendRef);
|
|
26
|
+
const resolvedLayout = computed(() => props.layout && props.layout !== "auto" ? props.layout : getLayoutForPosition(props.position));
|
|
21
27
|
const maxWidth = computed(() => chartWidth.value - (margin.value.left || 0) - (margin.value.right || 0));
|
|
22
|
-
const widthOrHeight = computed(() => getWidthOrHeight(
|
|
28
|
+
const widthOrHeight = computed(() => getWidthOrHeight(resolvedLayout.value, props.height, props.width, maxWidth.value));
|
|
23
29
|
const boundingBox = computed(() => ({
|
|
24
30
|
width: boundingWidth.value,
|
|
25
31
|
height: boundingHeight.value
|
|
26
32
|
}));
|
|
33
|
+
const positionViewBox = computed(() => {
|
|
34
|
+
if (props.position == null) return null;
|
|
35
|
+
return isOutsidePosition(props.position) ? legendArea.value : viewBox.value;
|
|
36
|
+
});
|
|
37
|
+
const shouldReportDimensions = computed(() => props.portal == null && (props.position == null || isOutsidePosition(props.position)));
|
|
27
38
|
const processedPayload = computed(() => {
|
|
28
39
|
if (!contextPayload.value || contextPayload.value.length === 0) return [];
|
|
29
40
|
let finalPayload = getUniqPayload(contextPayload.value, props.payloadUniqBy, defaultUniqBy);
|
|
@@ -33,30 +44,58 @@ function useLegend(props) {
|
|
|
33
44
|
}
|
|
34
45
|
return Array.from(finalPayload);
|
|
35
46
|
});
|
|
47
|
+
const positionStyle = computed(() => {
|
|
48
|
+
if (props.position == null || positionViewBox.value == null) return;
|
|
49
|
+
const positionResult = getCartesianPosition({
|
|
50
|
+
viewBox: positionViewBox.value,
|
|
51
|
+
position: props.position,
|
|
52
|
+
offset: props.offset ?? 0
|
|
53
|
+
});
|
|
54
|
+
const outsidePositionOffset = getOutsidePositionOffset(props.position, props.offset ?? 0, boundingBox.value);
|
|
55
|
+
const positionMaxWidth = resolvedLayout.value === "vertical" ? (positionViewBox.value.width ?? 0) / 2 : positionViewBox.value.width ?? 0;
|
|
56
|
+
const positionMaxHeight = resolvedLayout.value === "horizontal" ? (positionViewBox.value.height ?? 0) / 2 : positionViewBox.value.height ?? 0;
|
|
57
|
+
return {
|
|
58
|
+
width: "max-content",
|
|
59
|
+
height: "max-content",
|
|
60
|
+
maxWidth: `${positionMaxWidth}px`,
|
|
61
|
+
maxHeight: `${positionMaxHeight}px`,
|
|
62
|
+
overflowY: "auto",
|
|
63
|
+
top: `${positionResult.y + (outsidePositionOffset.top ?? 0)}px`,
|
|
64
|
+
left: `${positionResult.x + (outsidePositionOffset.left ?? 0)}px`,
|
|
65
|
+
transform: cartesianPositionToCSSTranslate(positionResult.horizontalAnchor, positionResult.verticalAnchor)
|
|
66
|
+
};
|
|
67
|
+
});
|
|
36
68
|
const outerStyle = computed(() => {
|
|
37
69
|
const userStyle = props.wrapperStyle ? { ...props.wrapperStyle } : {};
|
|
38
70
|
if (props.portal) return userStyle;
|
|
39
71
|
const baseStyle = {
|
|
40
72
|
position: "absolute",
|
|
41
|
-
width: widthOrHeight.value?.width
|
|
42
|
-
height: widthOrHeight.value?.height
|
|
73
|
+
width: widthOrHeight.value?.width || props.width || "auto",
|
|
74
|
+
height: widthOrHeight.value?.height || props.height || "auto"
|
|
43
75
|
};
|
|
44
|
-
const
|
|
76
|
+
const calculatedPositionStyle = positionStyle.value ?? getDefaultPosition(userStyle, {
|
|
77
|
+
layout: resolvedLayout.value,
|
|
78
|
+
align: props.align,
|
|
79
|
+
verticalAlign: props.verticalAlign
|
|
80
|
+
}, margin.value, chartWidth.value, chartHeight.value, boundingBox.value);
|
|
45
81
|
return {
|
|
46
82
|
...baseStyle,
|
|
47
|
-
...
|
|
83
|
+
...calculatedPositionStyle,
|
|
48
84
|
...userStyle
|
|
49
85
|
};
|
|
50
86
|
});
|
|
51
87
|
const legendPortal = computed(() => props.portal ?? legendPortalFromContext?.value);
|
|
52
88
|
const syncSettings = () => {
|
|
53
89
|
dispatch(setLegendSettings({
|
|
54
|
-
layout:
|
|
90
|
+
layout: resolvedLayout.value,
|
|
55
91
|
align: props.align,
|
|
56
|
-
verticalAlign: props.verticalAlign
|
|
92
|
+
verticalAlign: props.verticalAlign,
|
|
93
|
+
position: props.position,
|
|
94
|
+
offset: props.offset
|
|
57
95
|
}));
|
|
58
96
|
};
|
|
59
97
|
const syncSize = () => {
|
|
98
|
+
if (!shouldReportDimensions.value) return;
|
|
60
99
|
dispatch(setLegendSize({
|
|
61
100
|
width: boundingBox.value.width,
|
|
62
101
|
height: boundingBox.value.height
|
|
@@ -69,6 +108,8 @@ function useLegend(props) {
|
|
|
69
108
|
processedPayload,
|
|
70
109
|
outerStyle,
|
|
71
110
|
legendPortal,
|
|
111
|
+
resolvedLayout,
|
|
112
|
+
positionViewBox,
|
|
72
113
|
syncSettings,
|
|
73
114
|
syncSize
|
|
74
115
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var LegendVueProps = {
|
|
3
3
|
layout: {
|
|
4
4
|
type: String,
|
|
5
|
-
default: "
|
|
5
|
+
default: "auto"
|
|
6
6
|
},
|
|
7
7
|
align: {
|
|
8
8
|
type: String,
|
|
@@ -12,6 +12,14 @@ var LegendVueProps = {
|
|
|
12
12
|
type: String,
|
|
13
13
|
default: "bottom"
|
|
14
14
|
},
|
|
15
|
+
position: {
|
|
16
|
+
type: [String, Object],
|
|
17
|
+
default: void 0
|
|
18
|
+
},
|
|
19
|
+
offset: {
|
|
20
|
+
type: Number,
|
|
21
|
+
default: 0
|
|
22
|
+
},
|
|
15
23
|
width: Number,
|
|
16
24
|
height: Number,
|
|
17
25
|
iconSize: {
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { isNumber } from "../../utils/validate.mjs";
|
|
2
2
|
//#region src/components/legend/utils.ts
|
|
3
|
+
function getLayoutForPosition(position) {
|
|
4
|
+
if (position === "left" || position === "right" || position === "insideLeft" || position === "insideRight") return "vertical";
|
|
5
|
+
return "horizontal";
|
|
6
|
+
}
|
|
7
|
+
function getOutsidePositionOffset(position, offset, box) {
|
|
8
|
+
if (position === "top") return { top: box.height + offset };
|
|
9
|
+
if (position === "bottom") return { top: -box.height - offset };
|
|
10
|
+
if (position === "left") return { left: box.width + offset };
|
|
11
|
+
if (position === "right") return { left: -box.width - offset };
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
3
14
|
function getDefaultPosition(style, props, margin, chartWidth, chartHeight, box) {
|
|
4
15
|
const { layout, align, verticalAlign } = props;
|
|
5
16
|
let hPos = {};
|
|
@@ -22,4 +33,4 @@ function defaultUniqBy(entry) {
|
|
|
22
33
|
return entry.value;
|
|
23
34
|
}
|
|
24
35
|
//#endregion
|
|
25
|
-
export { defaultUniqBy, getDefaultPosition, getWidthOrHeight };
|
|
36
|
+
export { defaultUniqBy, getDefaultPosition, getLayoutForPosition, getOutsidePositionOffset, getWidthOrHeight };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isPercent } from "../utils/validate.mjs";
|
|
2
2
|
import { normalizeStyle as normalizeStyle$1 } from "../utils/style.mjs";
|
|
3
|
+
import { useRoundedSize } from "../hooks/useRoundedSize.mjs";
|
|
3
4
|
import { provideSizeContext } from "./useSizeContext.mjs";
|
|
4
5
|
import { Fragment, cloneVNode, computed, createElementBlock, createVNode, defineComponent, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, ref, toRef, useSlots } from "vue";
|
|
5
6
|
import { useThrottleFn } from "@vueuse/core";
|
|
@@ -30,7 +31,7 @@ var ResponsiveContainer_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
30
31
|
const props = __props;
|
|
31
32
|
const slots = useSlots();
|
|
32
33
|
const debounce = toRef(props, "debounce");
|
|
33
|
-
const sizes =
|
|
34
|
+
const { size: sizes, setSize: setContainerSize } = useRoundedSize({
|
|
34
35
|
width: props.initialDimension.width,
|
|
35
36
|
height: props.initialDimension.height
|
|
36
37
|
});
|
|
@@ -57,16 +58,6 @@ var ResponsiveContainer_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
57
58
|
calculatedWidth: finalCalculatedWidth,
|
|
58
59
|
calculatedHeight
|
|
59
60
|
});
|
|
60
|
-
function setContainerSize(width, height) {
|
|
61
|
-
const roundedWidth = Math.round(width);
|
|
62
|
-
const roundedHeight = Math.round(height);
|
|
63
|
-
const { width: containerWidth, height: containerHeight } = sizes.value;
|
|
64
|
-
if (containerWidth === roundedWidth && containerHeight === roundedHeight) return;
|
|
65
|
-
sizes.value = {
|
|
66
|
-
width: roundedWidth,
|
|
67
|
-
height: roundedHeight
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
61
|
const handleResize = useThrottleFn((entries) => {
|
|
71
62
|
const { width: containerWidth, height: containerHeight } = entries[0].contentRect;
|
|
72
63
|
setContainerSize(containerWidth, containerHeight);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { validateWidthHeight } from "../utils/validate.mjs";
|
|
2
|
+
import { useRoundedSize } from "./useRoundedSize.mjs";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
//#region src/hooks/useResponsiveSize.ts
|
|
5
|
+
/**
|
|
6
|
+
* Owns the chart's size resolution: in responsive mode the size is measured
|
|
7
|
+
* from the wrapper div (via `handleResize`), otherwise it comes from props.
|
|
8
|
+
*
|
|
9
|
+
* Render gating (`return null` when the size is invalid) stays with the
|
|
10
|
+
* caller — the rules differ between the compact and normal branches.
|
|
11
|
+
*/
|
|
12
|
+
function useResponsiveSize(props) {
|
|
13
|
+
const { size: responsiveSize, setSize: handleResize } = useRoundedSize();
|
|
14
|
+
const effectiveWidth = computed(() => props.responsive ? responsiveSize.value.width : props.width ?? 0);
|
|
15
|
+
const effectiveHeight = computed(() => props.responsive ? responsiveSize.value.height : props.height ?? 0);
|
|
16
|
+
return {
|
|
17
|
+
effectiveWidth,
|
|
18
|
+
effectiveHeight,
|
|
19
|
+
hasValidSize: computed(() => validateWidthHeight({
|
|
20
|
+
width: effectiveWidth.value,
|
|
21
|
+
height: effectiveHeight.value
|
|
22
|
+
})),
|
|
23
|
+
handleResize
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { useResponsiveSize };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
//#region src/hooks/useRoundedSize.ts
|
|
3
|
+
/**
|
|
4
|
+
* Shared size-state core: a size ref plus a setter that rounds to
|
|
5
|
+
* integers and ignores no-change updates.
|
|
6
|
+
*
|
|
7
|
+
* Adapters: `useResponsiveSize` (chart sizing) and `ResponsiveContainer`.
|
|
8
|
+
* ResponsiveContainer is planned for removal (see ADR-0001); when it goes,
|
|
9
|
+
* this module stays behind as the chart's size-state implementation.
|
|
10
|
+
*/
|
|
11
|
+
function useRoundedSize(initial = {
|
|
12
|
+
width: 0,
|
|
13
|
+
height: 0
|
|
14
|
+
}) {
|
|
15
|
+
const size = ref(initial);
|
|
16
|
+
function setSize(width, height) {
|
|
17
|
+
const roundedWidth = Math.round(width);
|
|
18
|
+
const roundedHeight = Math.round(height);
|
|
19
|
+
if (size.value.width === roundedWidth && size.value.height === roundedHeight) return;
|
|
20
|
+
size.value = {
|
|
21
|
+
width: roundedWidth,
|
|
22
|
+
height: roundedHeight
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
size,
|
|
27
|
+
setSize
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { useRoundedSize };
|
package/dist/es/shape/Sector.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { classProp } from "../types/common.mjs";
|
|
2
|
-
import { RADIAN, polarToCartesian } from "../utils/polar.mjs";
|
|
3
2
|
import { getPercentValue, mathSign } from "../utils/data.mjs";
|
|
3
|
+
import { RADIAN, polarToCartesian } from "../utils/polar.mjs";
|
|
4
4
|
import { createVNode, defineComponent, mergeProps } from "vue";
|
|
5
5
|
//#region src/shape/Sector.tsx
|
|
6
6
|
/**
|
|
@@ -24,6 +24,8 @@ var legendSlice = createSlice({
|
|
|
24
24
|
state.settings.align = action.payload.align;
|
|
25
25
|
state.settings.layout = action.payload.layout;
|
|
26
26
|
state.settings.verticalAlign = action.payload.verticalAlign;
|
|
27
|
+
state.settings.position = action.payload.position;
|
|
28
|
+
state.settings.offset = action.payload.offset;
|
|
27
29
|
},
|
|
28
30
|
addLegendPayload(state, action) {
|
|
29
31
|
state.payload.push(castDraft(action.payload));
|
|
@@ -2,11 +2,11 @@ import { isCategoricalAxis, isNan, isNumOrStr, isNumber, isWellBehavedNumber } f
|
|
|
2
2
|
import { selectChartDataWithIndexes, selectChartDataWithIndexesIfNotInPanorama } from "./dataSelectors.mjs";
|
|
3
3
|
import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
|
|
4
4
|
import { selectAllXAxes, selectAllYAxes } from "./selectAllAxes.mjs";
|
|
5
|
+
import { getPercentValue, hasDuplicate, mathSign } from "../../utils/data.mjs";
|
|
5
6
|
import { selectChartOffset } from "./selectChartOffset.mjs";
|
|
6
7
|
import { selectBrushDimensions, selectBrushSettings } from "./brushSelectors.mjs";
|
|
7
8
|
import { selectBarCategoryGap, selectChartName, selectStackOffsetType } from "./rootPropsSelectors.mjs";
|
|
8
9
|
import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
|
|
9
|
-
import { getPercentValue, hasDuplicate, mathSign } from "../../utils/data.mjs";
|
|
10
10
|
import { selectChartLayout } from "./common.mjs";
|
|
11
11
|
import { selectAngleAxis, selectAngleAxisRange, selectRadiusAxis, selectRadiusAxisRange } from "./polarAxisSelectors.mjs";
|
|
12
12
|
import { pickAxisType } from "./pickAxisType.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isNullish } from "../../utils/validate.mjs";
|
|
2
2
|
import { selectChartDataWithIndexesIfNotInPanorama } from "./dataSelectors.mjs";
|
|
3
|
+
import { getPercentValue } from "../../utils/data.mjs";
|
|
3
4
|
import { selectChartOffset } from "./selectChartOffset.mjs";
|
|
4
5
|
import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize } from "./rootPropsSelectors.mjs";
|
|
5
|
-
import { getPercentValue } from "../../utils/data.mjs";
|
|
6
6
|
import { selectChartLayout } from "./common.mjs";
|
|
7
7
|
import { getBandSizeOfAxis } from "../../utils/chart.mjs";
|
|
8
8
|
import { selectAxisWithScale, selectCartesianAxisSize, selectStackGroups, selectTicksOfGraphicalItem, selectUnfilteredCartesianItems } from "./axisSelectors.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isNumber } from "../../utils/validate.mjs";
|
|
2
2
|
import { selectChartDataAndAlwaysIgnoreIndexes } from "./dataSelectors.mjs";
|
|
3
|
+
import { getPercentValue, mathSign } from "../../utils/data.mjs";
|
|
3
4
|
import { selectChartOffset } from "./selectChartOffset.mjs";
|
|
4
5
|
import { getMaxRadius, polarToCartesian } from "../../utils/polar.mjs";
|
|
5
|
-
import { getPercentValue, mathSign } from "../../utils/data.mjs";
|
|
6
6
|
import { getValueByDataKey } from "../../utils/chart.mjs";
|
|
7
7
|
import { selectUnfilteredPolarItems } from "./polarSelectors.mjs";
|
|
8
8
|
import { createSelector } from "@reduxjs/toolkit";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
|
|
2
|
+
import { getPercentValue } from "../../utils/data.mjs";
|
|
2
3
|
import { selectChartOffset } from "./selectChartOffset.mjs";
|
|
3
4
|
import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
|
|
4
5
|
import { getMaxRadius } from "../../utils/polar.mjs";
|
|
5
|
-
import { getPercentValue } from "../../utils/data.mjs";
|
|
6
6
|
import { selectChartLayout } from "./common.mjs";
|
|
7
7
|
import { createSelector } from "@reduxjs/toolkit";
|
|
8
8
|
//#region src/state/selectors/polarAxisSelectors.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isCategoricalAxis, isNullish } from "../../utils/validate.mjs";
|
|
2
2
|
import { selectChartDataAndAlwaysIgnoreIndexes, selectChartDataWithIndexes } from "./dataSelectors.mjs";
|
|
3
|
-
import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize, selectStackOffsetType } from "./rootPropsSelectors.mjs";
|
|
4
3
|
import { mathSign } from "../../utils/data.mjs";
|
|
4
|
+
import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize, selectStackOffsetType } from "./rootPropsSelectors.mjs";
|
|
5
5
|
import { selectChartLayout } from "./common.mjs";
|
|
6
6
|
import { selectAngleAxis, selectPolarViewBox, selectRadiusAxis } from "./polarAxisSelectors.mjs";
|
|
7
7
|
import { getBandSizeOfAxis, getBaseValueOfBar, getCateCoordinateOfBar, getValueByDataKey, truncateByDomain } from "../../utils/chart.mjs";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { selectChartHeight, selectChartWidth, selectMargin } from "./containerSelectors.mjs";
|
|
2
|
+
import { createSelector } from "@reduxjs/toolkit";
|
|
3
|
+
//#region src/state/selectors/selectLegendArea.ts
|
|
4
|
+
/**
|
|
5
|
+
* The margin-inset chart area. Outside-positioned legends are placed here,
|
|
6
|
+
* beyond any axes.
|
|
7
|
+
*/
|
|
8
|
+
var selectLegendArea = createSelector([
|
|
9
|
+
selectChartWidth,
|
|
10
|
+
selectChartHeight,
|
|
11
|
+
selectMargin
|
|
12
|
+
], (chartWidth, chartHeight, margin) => ({
|
|
13
|
+
x: margin?.left || 0,
|
|
14
|
+
y: margin?.top || 0,
|
|
15
|
+
width: Math.max(chartWidth - (margin?.left || 0) - (margin?.right || 0), 0),
|
|
16
|
+
height: Math.max(chartHeight - (margin?.top || 0) - (margin?.bottom || 0), 0)
|
|
17
|
+
}));
|
|
18
|
+
//#endregion
|
|
19
|
+
export { selectLegendArea };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isCategoricalAxis } from "../../utils/validate.mjs";
|
|
2
2
|
import { selectChartDataWithIndexes } from "./dataSelectors.mjs";
|
|
3
3
|
import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
|
|
4
|
+
import { findEntryInArray, mathSign } from "../../utils/data.mjs";
|
|
4
5
|
import { selectChartOffset } from "./selectChartOffset.mjs";
|
|
5
6
|
import { selectChartName, selectStackOffsetType } from "./rootPropsSelectors.mjs";
|
|
6
7
|
import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
|
|
7
|
-
import { findEntryInArray, mathSign } from "../../utils/data.mjs";
|
|
8
8
|
import { selectChartLayout } from "./common.mjs";
|
|
9
9
|
import { getTooltipEntry, getValueByDataKey } from "../../utils/chart.mjs";
|
|
10
10
|
import { combineAppliedNumericalValuesIncludingErrorValues, combineAppliedValues, combineAreasDomain, combineAxisDomain, combineAxisDomainWithNiceTicks, combineCategoricalDomain, combineDisplayedData, combineDomainOfStackGroups, combineDotsDomain, combineDuplicateDomain, combineGraphicalItemsData, combineGraphicalItemsSettings, combineLinesDomain, combineNiceTicks, combineNumericalDomain, combineRealScaleType, combineScaleFunction, combineStackGroups, filterGraphicalNotStackedItems, filterReferenceElements, getDomainDefinition, itemAxisPredicate, mergeDomains, selectAxisRange, selectAxisSettings, selectHasBar, selectReferenceAreas, selectReferenceDots, selectReferenceLines } from "./axisSelectors.mjs";
|
package/dist/es/utils/chart.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isNan, isNullish, isNumOrStr, isNumber } from "./validate.mjs";
|
|
2
|
-
import { formatAngleOfSector, getAngleOfPoint, polarToCartesian, reverseFormatAngleOfSector } from "./polar.mjs";
|
|
3
2
|
import { findEntryInArray, mathSign } from "./data.mjs";
|
|
3
|
+
import { formatAngleOfSector, getAngleOfPoint, polarToCartesian, reverseFormatAngleOfSector } from "./polar.mjs";
|
|
4
4
|
import { toRaw } from "vue";
|
|
5
5
|
import { stack, stackOffsetExpand, stackOffsetNone, stackOffsetSilhouette, stackOffsetWiggle, stackOrderNone } from "victory-vendor/d3-shape";
|
|
6
6
|
import { get, isNaN, sortBy } from "lodash-es";
|
package/dist/es/utils/legend.mjs
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
import { isNumber } from "./validate.mjs";
|
|
2
|
+
import { isOutsidePosition } from "../cartesian/getCartesianPosition.mjs";
|
|
2
3
|
//#region src/utils/legend.ts
|
|
3
4
|
function appendOffsetOfLegend(offset, legendSettings, legendSize) {
|
|
4
5
|
if (legendSettings && legendSize) {
|
|
5
6
|
const { width: boxWidth, height: boxHeight } = legendSize;
|
|
6
|
-
const { align, verticalAlign, layout } = legendSettings;
|
|
7
|
+
const { align, verticalAlign, layout, position, offset: legendOffset = 0 } = legendSettings;
|
|
8
|
+
if (position != null) {
|
|
9
|
+
if (isOutsidePosition(position)) {
|
|
10
|
+
if (position === "top" && isNumber(offset.top)) return {
|
|
11
|
+
...offset,
|
|
12
|
+
top: offset.top + (boxHeight || 0) + legendOffset
|
|
13
|
+
};
|
|
14
|
+
if (position === "bottom" && isNumber(offset.bottom)) return {
|
|
15
|
+
...offset,
|
|
16
|
+
bottom: offset.bottom + (boxHeight || 0) + legendOffset
|
|
17
|
+
};
|
|
18
|
+
if (position === "left" && isNumber(offset.left)) return {
|
|
19
|
+
...offset,
|
|
20
|
+
left: offset.left + (boxWidth || 0) + legendOffset
|
|
21
|
+
};
|
|
22
|
+
if (position === "right" && isNumber(offset.right)) return {
|
|
23
|
+
...offset,
|
|
24
|
+
right: offset.right + (boxWidth || 0) + legendOffset
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return offset;
|
|
28
|
+
}
|
|
7
29
|
if ((layout === "vertical" || layout === "horizontal" && verticalAlign === "middle") && align !== "center" && isNumber(offset[align])) return {
|
|
8
30
|
...offset,
|
|
9
31
|
[align]: offset[align] + (boxWidth || 0)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
2
|
+
import { CategoricalChartPropsWithOutSvg } from '../chart/generateCategoricalChart';
|
|
3
|
+
type ResponsiveSizeProps = Pick<CategoricalChartPropsWithOutSvg, 'responsive' | 'width' | 'height'>;
|
|
4
|
+
interface UseResponsiveSizeResult {
|
|
5
|
+
/** Final width: measured from the wrapper when `responsive`, otherwise from props. */
|
|
6
|
+
effectiveWidth: ComputedRef<number>;
|
|
7
|
+
/** Final height: measured from the wrapper when `responsive`, otherwise from props. */
|
|
8
|
+
effectiveHeight: ComputedRef<number>;
|
|
9
|
+
/** Whether the effective size passes validateWidthHeight. Render policy is the caller's decision. */
|
|
10
|
+
hasValidSize: ComputedRef<boolean>;
|
|
11
|
+
/** Feeds the wrapper's ResizeObserver callback. Rounds and ignores no-change updates. */
|
|
12
|
+
handleResize: (width: number, height: number) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Owns the chart's size resolution: in responsive mode the size is measured
|
|
16
|
+
* from the wrapper div (via `handleResize`), otherwise it comes from props.
|
|
17
|
+
*
|
|
18
|
+
* Render gating (`return null` when the size is invalid) stays with the
|
|
19
|
+
* caller — the rules differ between the compact and normal branches.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useResponsiveSize(props: ResponsiveSizeProps): UseResponsiveSizeResult;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface RoundedSize {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Shared size-state core: a size ref plus a setter that rounds to
|
|
7
|
+
* integers and ignores no-change updates.
|
|
8
|
+
*
|
|
9
|
+
* Adapters: `useResponsiveSize` (chart sizing) and `ResponsiveContainer`.
|
|
10
|
+
* ResponsiveContainer is planned for removal (see ADR-0001); when it goes,
|
|
11
|
+
* this module stays behind as the chart's size-state implementation.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useRoundedSize(initial?: RoundedSize): {
|
|
14
|
+
size: import('vue').Ref<{
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}, RoundedSize | {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}>;
|
|
21
|
+
setSize: (width: number, height: number) => void;
|
|
22
|
+
};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { HorizontalAlignmentType, LegendPayload, VerticalAlignmentType } from '../components/DefaultLegendContent';
|
|
2
|
+
import { CartesianPosition } from '../cartesian/getCartesianPosition';
|
|
2
3
|
import { LayoutType, Size } from '../types';
|
|
3
4
|
export type LegendSettings = {
|
|
4
5
|
layout: LayoutType;
|
|
5
6
|
align: HorizontalAlignmentType;
|
|
6
7
|
verticalAlign: VerticalAlignmentType;
|
|
8
|
+
position?: CartesianPosition;
|
|
9
|
+
offset?: number;
|
|
7
10
|
};
|
|
8
11
|
/**
|
|
9
12
|
* The properties inside this state update independently of each other and quite often.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CartesianViewBoxRequired } from '../../cartesian/type';
|
|
2
|
+
import { RechartsRootState } from '../store';
|
|
3
|
+
/**
|
|
4
|
+
* The margin-inset chart area. Outside-positioned legends are placed here,
|
|
5
|
+
* beyond any axes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const selectLegendArea: (state: RechartsRootState) => CartesianViewBoxRequired;
|