vccs 0.2.0 → 0.3.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.
Files changed (93) hide show
  1. package/README.md +151 -0
  2. package/dist/animation/Animate.d.ts +1 -1
  3. package/dist/cartesian/area/type.d.ts +3 -3
  4. package/dist/cartesian/bar/type.d.ts +1 -13
  5. package/dist/cartesian/brush/components/Slide.d.ts +1 -1
  6. package/dist/cartesian/brush/components/TravellerLayer.d.ts +1 -1
  7. package/dist/cartesian/brush/type.d.ts +2 -1
  8. package/dist/cartesian/cartesian-axis/CartesianAxis.d.ts +2 -1
  9. package/dist/cartesian/funnel/type.d.ts +4 -5
  10. package/dist/cartesian/index.d.ts +1 -0
  11. package/dist/cartesian/line/Line.d.ts +7 -13
  12. package/dist/cartesian/line/type.d.ts +4 -17
  13. package/dist/cartesian/reference-area/ReferenceArea.d.ts +16 -16
  14. package/dist/cartesian/reference-dot/ReferenceDot.d.ts +143 -0
  15. package/dist/cartesian/reference-dot/index.d.ts +2 -0
  16. package/dist/cartesian/reference-line/ReferenceLine.d.ts +8 -8
  17. package/dist/cartesian/scatter/Scatter.d.ts +1 -1
  18. package/dist/chart/RechartsWrapper.d.ts +7 -3
  19. package/dist/chart/Surface.d.ts +2 -1
  20. package/dist/chart/Treemap.d.ts +237 -0
  21. package/dist/chart/generateCategoricalChart.d.ts +2 -1
  22. package/dist/chart/index.d.ts +1 -0
  23. package/dist/chart/treemapUtils.d.ts +22 -0
  24. package/dist/components/Customized.d.ts +23 -0
  25. package/dist/components/Text.d.ts +4 -4
  26. package/dist/components/Tooltip.d.ts +1 -1
  27. package/dist/components/index.d.ts +2 -0
  28. package/dist/components/label/Label.d.ts +3 -3
  29. package/dist/components/label/types.d.ts +1 -1
  30. package/dist/container/Surface.d.ts +3 -2
  31. package/dist/es/cartesian/area/type.mjs +2 -4
  32. package/dist/es/cartesian/bar/Bar.mjs +2 -17
  33. package/dist/es/cartesian/bar/type.mjs +2 -16
  34. package/dist/es/cartesian/cartesian-grid/const.mjs +1 -1
  35. package/dist/es/cartesian/funnel/Funnel.mjs +3 -18
  36. package/dist/es/cartesian/funnel/type.mjs +3 -5
  37. package/dist/es/cartesian/line/type.mjs +2 -7
  38. package/dist/es/cartesian/reference-area/ReferenceArea.mjs +6 -22
  39. package/dist/es/cartesian/reference-dot/ReferenceDot.mjs +134 -0
  40. package/dist/es/cartesian/reference-line/ReferenceLine.mjs +6 -19
  41. package/dist/es/chart/RechartsWrapper.mjs +2 -1
  42. package/dist/es/chart/Treemap.mjs +379 -0
  43. package/dist/es/chart/generateCategoricalChart.mjs +3 -2
  44. package/dist/es/chart/treemapUtils.mjs +32 -0
  45. package/dist/es/components/Customized.mjs +43 -0
  46. package/dist/es/components/label/types.mjs +2 -1
  47. package/dist/es/components/legend/Legend.mjs +1 -1
  48. package/dist/es/components/legend/hooks/useLegend.mjs +8 -3
  49. package/dist/es/container/Surface.mjs +2 -4
  50. package/dist/es/hooks/publicHooks.mjs +207 -0
  51. package/dist/es/index.mjs +9 -1
  52. package/dist/es/polar/pie/Pie.mjs +1 -1
  53. package/dist/es/polar/pie/type.mjs +2 -4
  54. package/dist/es/shape/Curve.mjs +2 -1
  55. package/dist/es/shape/Polygon.mjs +19 -0
  56. package/dist/es/shape/Rectangle.mjs +0 -4
  57. package/dist/es/shape/Sector.mjs +4 -6
  58. package/dist/es/shape/Symbols.mjs +1 -1
  59. package/dist/es/shape/Trapezoid.mjs +5 -7
  60. package/dist/es/state/ReportChartProps.mjs +2 -4
  61. package/dist/es/state/hooks.mjs +21 -1
  62. package/dist/es/state/referenceElementsSlice.mjs +1 -1
  63. package/dist/es/state/selectors/axisSelectors.mjs +30 -1
  64. package/dist/es/state/selectors/tooltipSelectors.mjs +2 -2
  65. package/dist/es/types/common.mjs +12 -0
  66. package/dist/es/utils/VueUtils.mjs +1 -1
  67. package/dist/es/utils/cell.mjs +28 -0
  68. package/dist/es/utils/createCategoricalInverse.mjs +46 -0
  69. package/dist/es/utils/scale.mjs +46 -0
  70. package/dist/hooks/publicHooks.d.ts +143 -0
  71. package/dist/index.d.ts +1 -0
  72. package/dist/polar/pie/type.d.ts +2 -2
  73. package/dist/polar/radar/Radar.d.ts +4 -4
  74. package/dist/shape/Curve.d.ts +2 -1
  75. package/dist/shape/Polygon.d.ts +9 -0
  76. package/dist/shape/Rectangle.d.ts +0 -4
  77. package/dist/shape/Sector.d.ts +2 -2
  78. package/dist/shape/Symbols.d.ts +2 -1
  79. package/dist/shape/Trapezoid.d.ts +9 -10
  80. package/dist/shape/index.d.ts +1 -0
  81. package/dist/shape/types.d.ts +4 -5
  82. package/dist/state/ReportChartProps.d.ts +3 -3
  83. package/dist/state/rootPropsSlice.d.ts +2 -2
  84. package/dist/state/selectors/axisSelectors.d.ts +5 -0
  85. package/dist/types/axis.d.ts +2 -2
  86. package/dist/types/bar.d.ts +2 -6
  87. package/dist/types/categorical.d.ts +2 -2
  88. package/dist/types/common.d.ts +7 -1
  89. package/dist/types/tooltip.d.ts +2 -2
  90. package/dist/utils/cell.d.ts +11 -0
  91. package/dist/utils/createCategoricalInverse.d.ts +16 -0
  92. package/dist/utils/scale.d.ts +23 -0
  93. package/package.json +2 -1
@@ -1,4 +1,5 @@
1
- import { isNumOrStr, isWellBehavedNumber } from "../../utils/validate.mjs";
1
+ import { classProp } from "../../types/common.mjs";
2
+ import { isNumOrStr } from "../../utils/validate.mjs";
2
3
  import { useIsPanorama } from "../../context/PanoramaContextProvider.mjs";
3
4
  import { selectAxisScale } from "../../state/selectors/axisSelectors.mjs";
4
5
  import { useAppDispatch, useAppSelector } from "../../state/hooks.mjs";
@@ -7,22 +8,8 @@ import { Label } from "../../components/label/Label.mjs";
7
8
  import { Rectangle } from "../../shape/Rectangle.mjs";
8
9
  import { addArea, removeArea } from "../../state/referenceElementsSlice.mjs";
9
10
  import { useClipPathId } from "../../chart/provideClipPathId.mjs";
11
+ import { rangeMax, rangeMin, scaleValue } from "../../utils/scale.mjs";
10
12
  import { computed, createVNode, defineComponent, mergeProps, onMounted, onUnmounted, reactive } from "vue";
11
- //#region src/cartesian/reference-area/ReferenceArea.tsx
12
- function scaleValue(scale, value, position) {
13
- const coord = scale(value);
14
- if (!isWellBehavedNumber(coord)) return void 0;
15
- const bandwidth = scale.bandwidth?.() ?? 0;
16
- return position === "start" ? coord : coord + bandwidth;
17
- }
18
- function rangeMin(scale) {
19
- const r = scale.range();
20
- return Math.min(r[0], r[1]);
21
- }
22
- function rangeMax(scale) {
23
- const r = scale.range();
24
- return Math.max(r[0], r[1]);
25
- }
26
13
  var ReferenceArea = /* @__PURE__ */ defineComponent({
27
14
  name: "ReferenceArea",
28
15
  props: {
@@ -79,14 +66,11 @@ var ReferenceArea = /* @__PURE__ */ defineComponent({
79
66
  type: String,
80
67
  default: "discard"
81
68
  },
82
- className: {
83
- type: String,
84
- default: void 0
85
- },
86
69
  radius: {
87
70
  type: [Number, Array],
88
71
  default: 0
89
- }
72
+ },
73
+ class: classProp
90
74
  },
91
75
  inheritAttrs: false,
92
76
  setup(props, { attrs }) {
@@ -144,7 +128,7 @@ var ReferenceArea = /* @__PURE__ */ defineComponent({
144
128
  };
145
129
  const labelValue = props.label;
146
130
  const labelProps = typeof labelValue === "object" && labelValue !== null ? labelValue : {};
147
- return createVNode(Layer, { "class": ["v-charts-reference-area", props.className] }, { default: () => [createVNode(Rectangle, mergeProps(svgAttrs, {
131
+ return createVNode(Layer, { "class": ["v-charts-reference-area", props.class] }, { default: () => [createVNode(Rectangle, mergeProps(svgAttrs, {
148
132
  "clip-path": clipPath,
149
133
  "x": r.x,
150
134
  "y": r.y,
@@ -0,0 +1,134 @@
1
+ import { isNumOrStr } from "../../utils/validate.mjs";
2
+ import { useIsPanorama } from "../../context/PanoramaContextProvider.mjs";
3
+ import { selectAxisScale } from "../../state/selectors/axisSelectors.mjs";
4
+ import { useAppDispatch, useAppSelector } from "../../state/hooks.mjs";
5
+ import { Layer } from "../../container/Layer.mjs";
6
+ import { Dot } from "../../shape/Dot.mjs";
7
+ import { Label } from "../../components/label/Label.mjs";
8
+ import { addDot, removeDot } from "../../state/referenceElementsSlice.mjs";
9
+ import { useClipPathId } from "../../chart/provideClipPathId.mjs";
10
+ import { isInRange, scaleCoord } from "../../utils/scale.mjs";
11
+ import { computed, createVNode, defineComponent, mergeProps, onMounted, onUnmounted, reactive } from "vue";
12
+ var ReferenceDot = /* @__PURE__ */ defineComponent({
13
+ name: "ReferenceDot",
14
+ props: {
15
+ x: {
16
+ type: [Number, String],
17
+ default: void 0
18
+ },
19
+ y: {
20
+ type: [Number, String],
21
+ default: void 0
22
+ },
23
+ r: {
24
+ type: Number,
25
+ default: 10
26
+ },
27
+ xAxisId: {
28
+ type: [Number, String],
29
+ default: 0
30
+ },
31
+ yAxisId: {
32
+ type: [Number, String],
33
+ default: 0
34
+ },
35
+ fill: {
36
+ type: String,
37
+ default: "#fff"
38
+ },
39
+ stroke: {
40
+ type: String,
41
+ default: "#ccc"
42
+ },
43
+ label: {
44
+ type: [
45
+ String,
46
+ Number,
47
+ Boolean,
48
+ Object
49
+ ],
50
+ default: void 0
51
+ },
52
+ ifOverflow: {
53
+ type: String,
54
+ default: "discard"
55
+ }
56
+ },
57
+ inheritAttrs: false,
58
+ slots: Object,
59
+ setup(props, { attrs, slots }) {
60
+ const dispatch = useAppDispatch();
61
+ const isPanorama = useIsPanorama();
62
+ const clipPathId = useClipPathId();
63
+ const settings = reactive({
64
+ xAxisId: props.xAxisId,
65
+ yAxisId: props.yAxisId,
66
+ ifOverflow: props.ifOverflow,
67
+ x: props.x,
68
+ y: props.y,
69
+ r: props.r
70
+ });
71
+ onMounted(() => {
72
+ dispatch(addDot(settings));
73
+ });
74
+ onUnmounted(() => {
75
+ dispatch(removeDot(settings));
76
+ });
77
+ const xAxisScale = useAppSelector((state) => selectAxisScale(state, "xAxis", props.xAxisId, isPanorama));
78
+ const yAxisScale = useAppSelector((state) => selectAxisScale(state, "yAxis", props.yAxisId, isPanorama));
79
+ const dotCoord = computed(() => {
80
+ const xScale = xAxisScale.value;
81
+ const yScale = yAxisScale.value;
82
+ if (!xScale || !yScale) return null;
83
+ if (!isNumOrStr(props.x) || !isNumOrStr(props.y)) return null;
84
+ const cx = scaleCoord(xScale, props.x);
85
+ const cy = scaleCoord(yScale, props.y);
86
+ if (cx == null || cy == null) return null;
87
+ if (props.ifOverflow === "discard") {
88
+ if (!isInRange(xScale, cx) || !isInRange(yScale, cy)) return null;
89
+ }
90
+ return {
91
+ cx,
92
+ cy
93
+ };
94
+ });
95
+ return () => {
96
+ const coord = dotCoord.value;
97
+ if (!coord) return null;
98
+ const { cx, cy } = coord;
99
+ const clipPath = props.ifOverflow === "hidden" ? `url(#${clipPathId})` : void 0;
100
+ const { class: userClass, ...restAttrs } = attrs;
101
+ const svgAttrs = {
102
+ ...restAttrs,
103
+ fill: props.fill,
104
+ stroke: props.stroke
105
+ };
106
+ const labelViewBox = {
107
+ x: cx - props.r,
108
+ y: cy - props.r,
109
+ width: props.r * 2,
110
+ height: props.r * 2
111
+ };
112
+ const labelValue = props.label;
113
+ const labelProps = typeof labelValue === "object" && labelValue !== null ? labelValue : {};
114
+ const shapeProps = {
115
+ ...svgAttrs,
116
+ cx,
117
+ cy,
118
+ r: props.r,
119
+ clipPath
120
+ };
121
+ return createVNode(Layer, { "class": ["v-charts-reference-dot", userClass] }, { default: () => [slots.shape ? slots.shape(shapeProps) : createVNode(Dot, mergeProps(svgAttrs, {
122
+ "cx": cx,
123
+ "cy": cy,
124
+ "r": props.r,
125
+ "clip-path": clipPath
126
+ }), null), labelValue != null && labelValue !== false && createVNode(Label, mergeProps({
127
+ "viewBox": labelViewBox,
128
+ "value": typeof labelValue === "string" || typeof labelValue === "number" ? labelValue : void 0
129
+ }, labelProps), null)] });
130
+ };
131
+ }
132
+ });
133
+ //#endregion
134
+ export { ReferenceDot };
@@ -1,3 +1,4 @@
1
+ import { classProp } from "../../types/common.mjs";
1
2
  import { isNumOrStr, isWellBehavedNumber } from "../../utils/validate.mjs";
2
3
  import { useIsPanorama } from "../../context/PanoramaContextProvider.mjs";
3
4
  import { selectAxisScale, selectXAxisSettings, selectYAxisSettings } from "../../state/selectors/axisSelectors.mjs";
@@ -7,19 +8,8 @@ import { Layer } from "../../container/Layer.mjs";
7
8
  import { Label } from "../../components/label/Label.mjs";
8
9
  import { addLine, removeLine } from "../../state/referenceElementsSlice.mjs";
9
10
  import { useClipPathId } from "../../chart/provideClipPathId.mjs";
11
+ import { isInRange, scaleCoord } from "../../utils/scale.mjs";
10
12
  import { computed, createVNode, defineComponent, mergeProps, onMounted, onUnmounted, reactive } from "vue";
11
- //#region src/cartesian/reference-line/ReferenceLine.tsx
12
- function scaleCoord(scale, value) {
13
- const coord = scale(value);
14
- if (!isWellBehavedNumber(coord)) return;
15
- return coord + (scale.bandwidth?.() ?? 0) / 2;
16
- }
17
- function isInRange(scale, coord) {
18
- const r = scale.range();
19
- const min = Math.min(r[0], r[1]);
20
- const max = Math.max(r[0], r[1]);
21
- return coord >= min && coord <= max;
22
- }
23
13
  var ReferenceLine = /* @__PURE__ */ defineComponent({
24
14
  name: "ReferenceLine",
25
15
  props: {
@@ -64,10 +54,7 @@ var ReferenceLine = /* @__PURE__ */ defineComponent({
64
54
  type: String,
65
55
  default: "discard"
66
56
  },
67
- className: {
68
- type: String,
69
- default: void 0
70
- }
57
+ class: classProp
71
58
  },
72
59
  inheritAttrs: false,
73
60
  setup(props, { attrs }) {
@@ -135,9 +122,9 @@ var ReferenceLine = /* @__PURE__ */ defineComponent({
135
122
  const clipPath = props.ifOverflow === "hidden" ? `url(#${clipPathId})` : void 0;
136
123
  const svgAttrs = {
137
124
  ...attrs,
138
- stroke: props.stroke,
125
+ "stroke": props.stroke,
139
126
  "stroke-width": props.strokeWidth,
140
- fill: props.fill
127
+ "fill": props.fill
141
128
  };
142
129
  const labelViewBox = {
143
130
  x: Math.min(p1.x, p2.x),
@@ -147,7 +134,7 @@ var ReferenceLine = /* @__PURE__ */ defineComponent({
147
134
  };
148
135
  const labelValue = props.label;
149
136
  const labelProps = typeof labelValue === "object" && labelValue !== null ? labelValue : {};
150
- return createVNode(Layer, { "class": ["v-charts-reference-line", props.className] }, { default: () => [createVNode("line", mergeProps(svgAttrs, {
137
+ return createVNode(Layer, { "class": ["v-charts-reference-line", props.class] }, { default: () => [createVNode("line", mergeProps(svgAttrs, {
151
138
  "clip-path": clipPath,
152
139
  "x1": p1.x,
153
140
  "y1": p1.y,
@@ -1,3 +1,4 @@
1
+ import { classProp } from "../types/common.mjs";
1
2
  import { getChartPointer } from "../utils/chart.mjs";
2
3
  import { mouseLeaveChart } from "../state/tooltipSlice.mjs";
3
4
  import { useAppDispatch } from "../state/hooks.mjs";
@@ -14,7 +15,7 @@ import { createVNode, defineComponent, ref } from "vue";
14
15
  var RechartsWrapper = /* @__PURE__ */ defineComponent({
15
16
  name: "RechartsWrapper",
16
17
  props: {
17
- class: { type: String },
18
+ class: classProp,
18
19
  height: {
19
20
  type: Number,
20
21
  required: true
@@ -0,0 +1,379 @@
1
+ import { addTooltipEntrySettings, mouseLeaveItem, removeTooltipEntrySettings, setActiveClickItemIndex, setActiveMouseOverItemIndex } from "../state/tooltipSlice.mjs";
2
+ import { useAppDispatch } from "../state/hooks.mjs";
3
+ import { Layer } from "../container/Layer.mjs";
4
+ import { getStringSize } from "../utils/attrs.mjs";
5
+ import { Animate } from "../animation/Animate.mjs";
6
+ import { createRechartsStore } from "../state/store.mjs";
7
+ import { RechartsWrapper } from "./RechartsWrapper.mjs";
8
+ import Surface from "../container/Surface.mjs";
9
+ import { computeTreemapLayout } from "./treemapUtils.mjs";
10
+ import { Fragment, computed, createTextVNode, createVNode, defineComponent, ref, watchEffect } from "vue";
11
+ import { provideStore } from "@reduxjs/vue-redux";
12
+ import { get } from "lodash-es";
13
+ //#region src/chart/Treemap.tsx
14
+ var DEFAULT_COLORS = [
15
+ "#8889DD",
16
+ "#9597E4",
17
+ "#8DC77B",
18
+ "#A5D297",
19
+ "#E2CF45",
20
+ "#F8C12D",
21
+ "#F89C24",
22
+ "#F56E1A"
23
+ ];
24
+ /**
25
+ * Recursively sum all descendant values for a given dataKey.
26
+ */
27
+ function sumValues(item, dataKey) {
28
+ if (item.children && item.children.length > 0) return item.children.reduce((sum, child) => sum + sumValues(child, dataKey), 0);
29
+ const val = item[dataKey];
30
+ return typeof val === "number" && val > 0 ? val : 0;
31
+ }
32
+ /**
33
+ * Tooltip payload searcher for Treemap — navigates nested node structure
34
+ * using a path string like 'children[0].children[1]'.
35
+ */
36
+ var treemapPayloadSearcher = (data, activeIndex) => {
37
+ if (!data || !activeIndex) return void 0;
38
+ return get(data, activeIndex);
39
+ };
40
+ var treemapOptions = {
41
+ chartName: "Treemap",
42
+ defaultTooltipEventType: "item",
43
+ validateTooltipEventTypes: ["item"],
44
+ tooltipPayloadSearcher: treemapPayloadSearcher,
45
+ eventEmitter: void 0
46
+ };
47
+ /**
48
+ * Build a hierarchical node structure with tooltipIndex paths for tooltip lookup.
49
+ */
50
+ function buildNodeTree(data, dataKey, nameKey, parentIndex = "") {
51
+ return {
52
+ children: data.map((item, i) => {
53
+ const tooltipIndex = `${parentIndex}children[${i}]`;
54
+ if (item.children && item.children.length > 0) {
55
+ const childTree = buildNodeTree(item.children, dataKey, nameKey, `${tooltipIndex}.`);
56
+ return {
57
+ ...item,
58
+ tooltipIndex,
59
+ ...childTree
60
+ };
61
+ }
62
+ return {
63
+ ...item,
64
+ tooltipIndex,
65
+ value: sumValues(item, dataKey)
66
+ };
67
+ }),
68
+ name: "root",
69
+ tooltipIndex: parentIndex
70
+ };
71
+ }
72
+ var TreemapVueProps = {
73
+ data: {
74
+ type: Array,
75
+ required: true
76
+ },
77
+ dataKey: {
78
+ type: String,
79
+ default: "value"
80
+ },
81
+ nameKey: {
82
+ type: String,
83
+ default: "name"
84
+ },
85
+ width: {
86
+ type: Number,
87
+ required: true
88
+ },
89
+ height: {
90
+ type: Number,
91
+ required: true
92
+ },
93
+ aspectRatio: {
94
+ type: Number,
95
+ default: 4 / 3
96
+ },
97
+ fill: {
98
+ type: String,
99
+ default: "#808080"
100
+ },
101
+ stroke: {
102
+ type: String,
103
+ default: "#fff"
104
+ },
105
+ type: {
106
+ type: String,
107
+ default: "flat"
108
+ },
109
+ colorPanel: {
110
+ type: Array,
111
+ default: void 0
112
+ },
113
+ isAnimationActive: {
114
+ type: Boolean,
115
+ default: true
116
+ },
117
+ transition: {
118
+ type: Object,
119
+ default: () => ({
120
+ duration: .8,
121
+ ease: "easeOut"
122
+ })
123
+ },
124
+ onClick: {
125
+ type: Function,
126
+ default: void 0
127
+ },
128
+ onMouseEnter: {
129
+ type: Function,
130
+ default: void 0
131
+ },
132
+ onMouseLeave: {
133
+ type: Function,
134
+ default: void 0
135
+ }
136
+ };
137
+ /**
138
+ * Inner component that has access to the Redux store (provided by Treemap wrapper).
139
+ */
140
+ var TreemapInner = /* @__PURE__ */ defineComponent({
141
+ name: "TreemapInner",
142
+ props: TreemapVueProps,
143
+ slots: Object,
144
+ setup(props, { slots }) {
145
+ const dispatch = useAppDispatch();
146
+ const colors = computed(() => props.colorPanel ?? DEFAULT_COLORS);
147
+ const breadcrumbTrail = ref([]);
148
+ const currentData = ref(null);
149
+ const animationKey = ref(0);
150
+ const isNestMode = computed(() => props.type === "nest");
151
+ const nestCurrentData = computed(() => {
152
+ if (!isNestMode.value) return null;
153
+ return currentData.value ?? props.data;
154
+ });
155
+ function computeNestLevelData(data) {
156
+ return data.map((item) => {
157
+ const aggregatedValue = sumValues(item, props.dataKey);
158
+ const { children: _, ...rest } = item;
159
+ return {
160
+ ...rest,
161
+ [props.dataKey]: aggregatedValue
162
+ };
163
+ });
164
+ }
165
+ const nodes = computed(() => {
166
+ return computeTreemapLayout({
167
+ data: isNestMode.value ? computeNestLevelData(nestCurrentData.value ?? props.data) : props.data,
168
+ width: props.width,
169
+ height: props.height,
170
+ dataKey: props.dataKey,
171
+ nameKey: props.nameKey,
172
+ aspectRatio: props.aspectRatio,
173
+ colorPanel: colors.value
174
+ });
175
+ });
176
+ const nodeTree = computed(() => {
177
+ return buildNodeTree(isNestMode.value ? nestCurrentData.value ?? props.data : props.data, props.dataKey, props.nameKey);
178
+ });
179
+ watchEffect((onCleanup) => {
180
+ const tooltipEntrySettings = {
181
+ dataDefinedOnItem: nodeTree.value,
182
+ positions: void 0,
183
+ settings: {
184
+ stroke: props.stroke,
185
+ strokeWidth: void 0,
186
+ fill: props.fill,
187
+ dataKey: props.dataKey,
188
+ nameKey: props.nameKey,
189
+ name: void 0,
190
+ hide: false,
191
+ type: void 0,
192
+ color: props.fill,
193
+ unit: ""
194
+ }
195
+ };
196
+ dispatch(addTooltipEntrySettings(tooltipEntrySettings));
197
+ onCleanup(() => {
198
+ dispatch(removeTooltipEntrySettings(tooltipEntrySettings));
199
+ });
200
+ });
201
+ function getTooltipIndex(node) {
202
+ const data = isNestMode.value ? nestCurrentData.value ?? props.data : props.data;
203
+ const idx = data.findIndex((item) => item[props.nameKey] === node.name);
204
+ if (idx >= 0) return `children[${idx}]`;
205
+ for (let i = 0; i < data.length; i++) if (data[i].children) {
206
+ const childIdx = data[i].children.findIndex((c) => c[props.nameKey] === node.name);
207
+ if (childIdx >= 0) return `children[${i}].children[${childIdx}]`;
208
+ }
209
+ return `children[0]`;
210
+ }
211
+ function handleNestClick(node, e) {
212
+ const sourceData = nestCurrentData.value ?? props.data;
213
+ const clickedItem = sourceData.find((item) => item[props.nameKey] === node.name);
214
+ if (clickedItem?.children && clickedItem.children.length > 0) {
215
+ breadcrumbTrail.value = [...breadcrumbTrail.value, {
216
+ name: clickedItem[props.nameKey] ?? clickedItem.name,
217
+ data: sourceData
218
+ }];
219
+ currentData.value = clickedItem.children;
220
+ animationKey.value++;
221
+ }
222
+ props.onClick?.(node, e);
223
+ }
224
+ function navigateToBreadcrumb(index) {
225
+ if (index < 0) {
226
+ currentData.value = null;
227
+ breadcrumbTrail.value = [];
228
+ } else {
229
+ currentData.value = breadcrumbTrail.value[index].data;
230
+ breadcrumbTrail.value = breadcrumbTrail.value.slice(0, index);
231
+ }
232
+ animationKey.value++;
233
+ }
234
+ function getNodeFill(node) {
235
+ return node.color ?? props.fill;
236
+ }
237
+ function handleNodeMouseEnter(node, e) {
238
+ const tooltipIndex = getTooltipIndex(node);
239
+ const activeCoordinate = {
240
+ x: node.x + node.width / 2,
241
+ y: node.y + node.height / 2
242
+ };
243
+ dispatch(setActiveMouseOverItemIndex({
244
+ activeIndex: tooltipIndex,
245
+ activeDataKey: props.dataKey,
246
+ activeCoordinate
247
+ }));
248
+ props.onMouseEnter?.(node, e);
249
+ }
250
+ function handleNodeMouseLeave(node, e) {
251
+ dispatch(mouseLeaveItem());
252
+ props.onMouseLeave?.(node, e);
253
+ }
254
+ function handleNodeClick(node, e) {
255
+ if (isNestMode.value) handleNestClick(node, e);
256
+ else {
257
+ const tooltipIndex = getTooltipIndex(node);
258
+ const activeCoordinate = {
259
+ x: node.x + node.width / 2,
260
+ y: node.y + node.height / 2
261
+ };
262
+ dispatch(setActiveClickItemIndex({
263
+ activeIndex: tooltipIndex,
264
+ activeDataKey: props.dataKey,
265
+ activeCoordinate
266
+ }));
267
+ props.onClick?.(node, e);
268
+ }
269
+ }
270
+ function renderNodeAtProgress(node, index, progress) {
271
+ const nodeFill = getNodeFill(node);
272
+ const translateX = (-node.x - node.width) * (1 - progress);
273
+ const transform = progress < 1 ? `translate(${translateX}, 0)` : void 0;
274
+ const nodeProps = {
275
+ ...node,
276
+ index,
277
+ fill: nodeFill,
278
+ stroke: props.stroke
279
+ };
280
+ if (slots.content) return createVNode("g", {
281
+ "key": `node-${index}`,
282
+ "class": "v-charts-treemap-node",
283
+ "style": { transformOrigin: `${node.x}px ${node.y}px` },
284
+ "transform": transform,
285
+ "onClick": (e) => handleNodeClick(node, e),
286
+ "onMouseenter": (e) => handleNodeMouseEnter(node, e),
287
+ "onMouseleave": (e) => handleNodeMouseLeave(node, e)
288
+ }, [slots.content(nodeProps)]);
289
+ const arrow = isNestMode.value && (() => {
290
+ const item = (nestCurrentData.value ?? props.data).find((d) => d[props.nameKey] === node.name);
291
+ return item?.children && item.children.length > 0;
292
+ })() && node.width > 10 && node.height > 10 ? createVNode("polygon", {
293
+ "points": `${node.x + 2},${node.y + node.height / 2} ${node.x + 6},${node.y + node.height / 2 + 3} ${node.x + 2},${node.y + node.height / 2 + 6}`,
294
+ "fill": "#fff"
295
+ }, null) : null;
296
+ const nameSize = node.width > 20 && node.height > 20 ? getStringSize(node.name, { fontSize: "14px" }) : {
297
+ width: Infinity,
298
+ height: Infinity
299
+ };
300
+ const text = node.width > 20 && node.height > 20 && nameSize.width < node.width && nameSize.height < node.height ? createVNode("text", {
301
+ "x": node.x + 8,
302
+ "y": node.y + node.height / 2 + 7,
303
+ "fill": "#fff",
304
+ "font-size": 14
305
+ }, [node.name]) : null;
306
+ return createVNode("g", {
307
+ "key": `node-${index}`,
308
+ "class": "v-charts-treemap-node",
309
+ "style": { transformOrigin: `${node.x}px ${node.y}px` },
310
+ "transform": transform,
311
+ "onClick": (e) => handleNodeClick(node, e),
312
+ "onMouseenter": (e) => handleNodeMouseEnter(node, e),
313
+ "onMouseleave": (e) => handleNodeMouseLeave(node, e)
314
+ }, [
315
+ createVNode("rect", {
316
+ "x": node.x,
317
+ "y": node.y,
318
+ "width": node.width,
319
+ "height": node.height,
320
+ "fill": nodeFill,
321
+ "stroke": props.stroke
322
+ }, null),
323
+ arrow,
324
+ text
325
+ ]);
326
+ }
327
+ function renderBreadcrumb() {
328
+ if (!isNestMode.value || breadcrumbTrail.value.length === 0) return null;
329
+ return createVNode("div", { "class": "v-charts-treemap-breadcrumb" }, [createVNode("span", {
330
+ "class": "v-charts-treemap-breadcrumb-item",
331
+ "style": { cursor: "pointer" },
332
+ "onClick": () => navigateToBreadcrumb(-1)
333
+ }, [createTextVNode("Root")]), breadcrumbTrail.value.map((entry, i) => createVNode("span", { "key": i }, [createVNode("span", { "style": { margin: "0 4px" } }, [createTextVNode("/")]), createVNode("span", {
334
+ "class": "v-charts-treemap-breadcrumb-item",
335
+ "style": { cursor: "pointer" },
336
+ "onClick": () => navigateToBreadcrumb(i)
337
+ }, [entry.name])]))]);
338
+ }
339
+ return () => createVNode(Fragment, null, [renderBreadcrumb(), createVNode(Surface, {
340
+ "width": props.width,
341
+ "height": props.height
342
+ }, { default: () => [createVNode(Layer, { "class": "v-charts-treemap" }, { default: () => [createVNode(Animate, {
343
+ "key": animationKey.value,
344
+ "isActive": props.isAnimationActive,
345
+ "from": 0,
346
+ "to": 1,
347
+ "transition": props.transition
348
+ }, { default: (progress) => nodes.value.map((node, index) => renderNodeAtProgress(node, index, progress)) })] })] })]);
349
+ }
350
+ });
351
+ /**
352
+ * Treemap chart — hierarchical data visualization using nested rectangles.
353
+ *
354
+ * Supports `<Tooltip>` as a child component (same pattern as BarChart, LineChart, etc.).
355
+ *
356
+ * Usage:
357
+ * ```vue
358
+ * <Treemap :data="data" data-key="value" :width="600" :height="400">
359
+ * <Tooltip />
360
+ * </Treemap>
361
+ * ```
362
+ */
363
+ var Treemap = /* @__PURE__ */ defineComponent({
364
+ name: "Treemap",
365
+ props: TreemapVueProps,
366
+ slots: Object,
367
+ setup(props, { slots }) {
368
+ provideStore({ store: createRechartsStore({ options: treemapOptions }, "Treemap") });
369
+ return () => {
370
+ if (!props.data || props.data.length === 0) return null;
371
+ return createVNode(RechartsWrapper, {
372
+ "width": props.width,
373
+ "height": props.height
374
+ }, { default: () => [createVNode(TreemapInner, props, { content: slots.content }), slots.default?.()] });
375
+ };
376
+ }
377
+ });
378
+ //#endregion
379
+ export { Treemap, TreemapVueProps, treemapPayloadSearcher };
@@ -1,3 +1,4 @@
1
+ import { classProp } from "../types/common.mjs";
1
2
  import { validateWidthHeight } from "../utils/validate.mjs";
2
3
  import { provideClipPathId } from "./provideClipPathId.mjs";
3
4
  import { createRechartsStore } from "../state/store.mjs";
@@ -34,7 +35,7 @@ var CategoricalProps = {
34
35
  default: 4
35
36
  },
36
37
  barSize: { type: [Number, String] },
37
- class: { type: String },
38
+ class: classProp,
38
39
  compact: { type: Boolean },
39
40
  cx: { type: [Number, String] },
40
41
  cy: { type: [Number, String] },
@@ -130,7 +131,7 @@ function generateCategoricalChart({ chartName, defaultProps = {}, defaultTooltip
130
131
  }), { default: () => [createVNode(ClipPath_default, { "clipPathId": clipPathId }, null), slots.default?.()] })
131
132
  ]);
132
133
  if (props.accessibilityLayer) {
133
- attributes.tabIndex = props.tabIndex ?? 0;
134
+ attributes.tabindex = props.tabIndex ?? 0;
134
135
  attributes.role = props.role ?? "application";
135
136
  }
136
137
  const eventHandlerAttrs = {};
@@ -0,0 +1,32 @@
1
+ import { hierarchy, treemap, treemapSquarify } from "d3-hierarchy";
2
+ //#region src/chart/treemapUtils.ts
3
+ function computeTreemapLayout(options) {
4
+ const { data, width, height, dataKey, aspectRatio = 4 / 3, nameKey = "name", colorPanel } = options;
5
+ if (!data || data.length === 0 || width <= 0 || height <= 0) return [];
6
+ const root = hierarchy({ children: data }).sum((d) => {
7
+ if (d.children && d.children.length > 0) return 0;
8
+ const val = d[dataKey];
9
+ return typeof val === "number" && val > 0 ? val : 0;
10
+ }).sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
11
+ treemap().size([width, height]).tile(treemapSquarify.ratio(aspectRatio)).round(true)(root);
12
+ return root.leaves().map((leaf) => {
13
+ const d = leaf.data;
14
+ let ancestor = leaf;
15
+ while (ancestor.depth > 1 && ancestor.parent) ancestor = ancestor.parent;
16
+ const rootIndex = ancestor.parent ? ancestor.parent.children.indexOf(ancestor) : 0;
17
+ return {
18
+ x: leaf.x0,
19
+ y: leaf.y0,
20
+ width: leaf.x1 - leaf.x0,
21
+ height: leaf.y1 - leaf.y0,
22
+ depth: leaf.depth,
23
+ name: d[nameKey] ?? "",
24
+ value: leaf.value ?? 0,
25
+ payload: d,
26
+ root: rootIndex,
27
+ color: colorPanel ? colorPanel[rootIndex % colorPanel.length] : void 0
28
+ };
29
+ });
30
+ }
31
+ //#endregion
32
+ export { computeTreemapLayout };