vccs 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/chart/RechartsWrapper.d.ts +3 -3
- package/dist/chart/Sankey.d.ts +327 -0
- package/dist/chart/SunburstChart.d.ts +249 -0
- package/dist/chart/generateCategoricalChart.d.ts +2 -2
- package/dist/chart/index.d.ts +2 -0
- package/dist/chart/sankeyUtils.d.ts +36 -0
- package/dist/chart/sunburstUtils.d.ts +34 -0
- package/dist/es/cartesian/utils/get-ticks.mjs +3 -2
- package/dist/es/chart/RechartsWrapper.mjs +8 -5
- package/dist/es/chart/Sankey.mjs +332 -0
- package/dist/es/chart/SunburstChart.mjs +229 -0
- package/dist/es/chart/generateCategoricalChart.mjs +5 -1
- package/dist/es/chart/sankeyUtils.mjs +28 -0
- package/dist/es/chart/sunburstUtils.mjs +67 -0
- package/dist/es/components/Tooltip.mjs +15 -6
- package/dist/es/container/ResponsiveContainer.vue_vue_type_script_setup_true_lang.mjs +15 -2
- package/dist/es/index.mjs +5 -2
- package/dist/es/polar/pie/Pie.mjs +1 -1
- package/dist/es/polar/pie/type.mjs +7 -0
- package/dist/es/polar/radar/Radar.mjs +9 -1
- package/dist/es/polar/radial-bar/RadialBar.mjs +1 -0
- package/dist/es/polar/radial-bar/type.mjs +7 -0
- package/dist/es/utils/Global.mjs +18 -0
- package/dist/es/utils/attrs.mjs +2 -2
- package/dist/es/utils/validate.mjs +1 -2
- package/dist/hooks/publicHooks.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/polar/pie/type.d.ts +8 -0
- package/dist/polar/radar/Radar.d.ts +16 -0
- package/dist/polar/radial-bar/type.d.ts +8 -0
- package/dist/state/selectors/combiners/combineActiveLabel.d.ts +1 -1
- package/dist/state/selectors/selectors.d.ts +1 -1
- package/dist/state/selectors/tooltipSelectors.d.ts +1 -1
- package/dist/types/common.d.ts +1 -1
- package/dist/utils/Global.d.ts +9 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/validate.d.ts +0 -1
- package/package.json +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { isNumber,
|
|
1
|
+
import { isNumber, isVisible } from "../../utils/validate.mjs";
|
|
2
|
+
import { Global } from "../../utils/Global.mjs";
|
|
2
3
|
import { mathSign } from "../../utils/data.mjs";
|
|
3
4
|
import { getStringSize } from "../../utils/attrs.mjs";
|
|
4
5
|
import { getAngledTickWidth, getNumberIntervalTicks, getTickBoundaries } from "../../utils/tick.mjs";
|
|
@@ -87,7 +88,7 @@ function getTicksStart(sign, boundaries, getTickSize, ticks, minTickGap, preserv
|
|
|
87
88
|
function getTicks(props, fontSize, letterSpacing) {
|
|
88
89
|
const { tick, ticks, viewBox, minTickGap, orientation, interval, tickFormatter, unit, angle } = props;
|
|
89
90
|
if (!ticks || !ticks.length || !tick) return [];
|
|
90
|
-
if (isNumber(interval) || isSsr) return getNumberIntervalTicks(ticks, isNumber(interval) ? interval : 0) ?? [];
|
|
91
|
+
if (isNumber(interval) || Global.isSsr) return getNumberIntervalTicks(ticks, isNumber(interval) ? interval : 0) ?? [];
|
|
91
92
|
let candidates = [];
|
|
92
93
|
const sizeKey = orientation === "top" || orientation === "bottom" ? "width" : "height";
|
|
93
94
|
const unitSize = unit && sizeKey === "width" ? getStringSize(unit, {
|
|
@@ -31,7 +31,11 @@ var RechartsWrapper = /* @__PURE__ */ defineComponent({
|
|
|
31
31
|
onTouchEnd: { type: Function },
|
|
32
32
|
onTouchMove: { type: Function },
|
|
33
33
|
onTouchStart: { type: Function },
|
|
34
|
-
style: { type:
|
|
34
|
+
style: { type: [
|
|
35
|
+
String,
|
|
36
|
+
Object,
|
|
37
|
+
Array
|
|
38
|
+
] },
|
|
35
39
|
width: {
|
|
36
40
|
type: Number,
|
|
37
41
|
required: true
|
|
@@ -132,13 +136,12 @@ var RechartsWrapper = /* @__PURE__ */ defineComponent({
|
|
|
132
136
|
};
|
|
133
137
|
return () => createVNode("div", {
|
|
134
138
|
"class": ["v-charts-wrapper", props.class],
|
|
135
|
-
"style": {
|
|
139
|
+
"style": [{
|
|
136
140
|
position: "relative",
|
|
137
141
|
cursor: "default",
|
|
138
142
|
width: `${props.width}px`,
|
|
139
|
-
height: `${props.height}px
|
|
140
|
-
|
|
141
|
-
},
|
|
143
|
+
height: `${props.height}px`
|
|
144
|
+
}, props.style],
|
|
142
145
|
"role": "application",
|
|
143
146
|
"onClick": myOnClick,
|
|
144
147
|
"onContextmenu": myOnContextMenu,
|
|
@@ -0,0 +1,332 @@
|
|
|
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 { Animate } from "../animation/Animate.mjs";
|
|
5
|
+
import { createRechartsStore } from "../state/store.mjs";
|
|
6
|
+
import { RechartsWrapper } from "./RechartsWrapper.mjs";
|
|
7
|
+
import Surface from "../container/Surface.mjs";
|
|
8
|
+
import { computeSankeyLayout, linkPathGenerator } from "./sankeyUtils.mjs";
|
|
9
|
+
import { Fragment, computed, createVNode, defineComponent, watchEffect } from "vue";
|
|
10
|
+
import { provideStore } from "@reduxjs/vue-redux";
|
|
11
|
+
import { get } from "lodash-es";
|
|
12
|
+
//#region src/chart/Sankey.tsx
|
|
13
|
+
var sankeyPayloadSearcher = (data, activeIndex) => {
|
|
14
|
+
if (!data || activeIndex == null) return void 0;
|
|
15
|
+
return get(data, activeIndex);
|
|
16
|
+
};
|
|
17
|
+
var sankeyOptions = {
|
|
18
|
+
chartName: "Sankey",
|
|
19
|
+
defaultTooltipEventType: "item",
|
|
20
|
+
validateTooltipEventTypes: ["item"],
|
|
21
|
+
tooltipPayloadSearcher: sankeyPayloadSearcher,
|
|
22
|
+
eventEmitter: void 0
|
|
23
|
+
};
|
|
24
|
+
var SankeyVueProps = {
|
|
25
|
+
data: {
|
|
26
|
+
type: Object,
|
|
27
|
+
required: true
|
|
28
|
+
},
|
|
29
|
+
width: {
|
|
30
|
+
type: Number,
|
|
31
|
+
required: true
|
|
32
|
+
},
|
|
33
|
+
height: {
|
|
34
|
+
type: Number,
|
|
35
|
+
required: true
|
|
36
|
+
},
|
|
37
|
+
nameKey: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: "name"
|
|
40
|
+
},
|
|
41
|
+
dataKey: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: "value"
|
|
44
|
+
},
|
|
45
|
+
nodePadding: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 10
|
|
48
|
+
},
|
|
49
|
+
nodeWidth: {
|
|
50
|
+
type: Number,
|
|
51
|
+
default: 10
|
|
52
|
+
},
|
|
53
|
+
iterations: {
|
|
54
|
+
type: Number,
|
|
55
|
+
default: 32
|
|
56
|
+
},
|
|
57
|
+
margin: {
|
|
58
|
+
type: Object,
|
|
59
|
+
default: () => ({
|
|
60
|
+
top: 5,
|
|
61
|
+
right: 5,
|
|
62
|
+
bottom: 5,
|
|
63
|
+
left: 5
|
|
64
|
+
})
|
|
65
|
+
},
|
|
66
|
+
nodeFill: {
|
|
67
|
+
type: String,
|
|
68
|
+
default: "#0088fe"
|
|
69
|
+
},
|
|
70
|
+
nodeStroke: {
|
|
71
|
+
type: String,
|
|
72
|
+
default: "#fff"
|
|
73
|
+
},
|
|
74
|
+
linkFill: {
|
|
75
|
+
type: String,
|
|
76
|
+
default: "#0088fe"
|
|
77
|
+
},
|
|
78
|
+
linkStroke: {
|
|
79
|
+
type: String,
|
|
80
|
+
default: "none"
|
|
81
|
+
},
|
|
82
|
+
isAnimationActive: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: true
|
|
85
|
+
},
|
|
86
|
+
transition: {
|
|
87
|
+
type: Object,
|
|
88
|
+
default: () => ({
|
|
89
|
+
duration: .8,
|
|
90
|
+
ease: "easeOut"
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
onClick: {
|
|
94
|
+
type: Function,
|
|
95
|
+
default: void 0
|
|
96
|
+
},
|
|
97
|
+
onMouseEnter: {
|
|
98
|
+
type: Function,
|
|
99
|
+
default: void 0
|
|
100
|
+
},
|
|
101
|
+
onMouseLeave: {
|
|
102
|
+
type: Function,
|
|
103
|
+
default: void 0
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var SankeyInner = /* @__PURE__ */ defineComponent({
|
|
107
|
+
name: "SankeyInner",
|
|
108
|
+
props: SankeyVueProps,
|
|
109
|
+
slots: Object,
|
|
110
|
+
setup(props, { slots }) {
|
|
111
|
+
const dispatch = useAppDispatch();
|
|
112
|
+
const layout = computed(() => {
|
|
113
|
+
const m = props.margin;
|
|
114
|
+
return computeSankeyLayout({
|
|
115
|
+
data: props.data,
|
|
116
|
+
width: props.width,
|
|
117
|
+
height: props.height,
|
|
118
|
+
nodePadding: props.nodePadding,
|
|
119
|
+
nodeWidth: props.nodeWidth,
|
|
120
|
+
iterations: props.iterations,
|
|
121
|
+
margin: {
|
|
122
|
+
top: m.top ?? 5,
|
|
123
|
+
right: m.right ?? 5,
|
|
124
|
+
bottom: m.bottom ?? 5,
|
|
125
|
+
left: m.left ?? 5
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
const payloadTree = computed(() => {
|
|
130
|
+
return {
|
|
131
|
+
nodes: layout.value.nodes.map((n, i) => ({
|
|
132
|
+
tooltipIndex: `nodes[${i}]`,
|
|
133
|
+
name: n[props.nameKey] ?? n.name,
|
|
134
|
+
value: n.value,
|
|
135
|
+
x0: n.x0,
|
|
136
|
+
x1: n.x1,
|
|
137
|
+
y0: n.y0,
|
|
138
|
+
y1: n.y1
|
|
139
|
+
})),
|
|
140
|
+
links: layout.value.links.map((l, i) => {
|
|
141
|
+
const src = l.source;
|
|
142
|
+
const tgt = l.target;
|
|
143
|
+
return {
|
|
144
|
+
tooltipIndex: `links[${i}]`,
|
|
145
|
+
name: `${src[props.nameKey] ?? src.name} - ${tgt[props.nameKey] ?? tgt.name}`,
|
|
146
|
+
value: l.value
|
|
147
|
+
};
|
|
148
|
+
})
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
watchEffect((onCleanup) => {
|
|
152
|
+
const settings = {
|
|
153
|
+
dataDefinedOnItem: payloadTree.value,
|
|
154
|
+
positions: void 0,
|
|
155
|
+
settings: {
|
|
156
|
+
stroke: props.nodeStroke,
|
|
157
|
+
strokeWidth: void 0,
|
|
158
|
+
fill: props.nodeFill,
|
|
159
|
+
dataKey: props.dataKey,
|
|
160
|
+
nameKey: props.nameKey,
|
|
161
|
+
name: void 0,
|
|
162
|
+
hide: false,
|
|
163
|
+
type: void 0,
|
|
164
|
+
color: props.nodeFill,
|
|
165
|
+
unit: ""
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
dispatch(addTooltipEntrySettings(settings));
|
|
169
|
+
onCleanup(() => {
|
|
170
|
+
dispatch(removeTooltipEntrySettings(settings));
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
function handleNodeMouseEnter(node, index, e) {
|
|
174
|
+
const coord = {
|
|
175
|
+
x: ((node.x0 ?? 0) + (node.x1 ?? 0)) / 2,
|
|
176
|
+
y: ((node.y0 ?? 0) + (node.y1 ?? 0)) / 2
|
|
177
|
+
};
|
|
178
|
+
dispatch(setActiveMouseOverItemIndex({
|
|
179
|
+
activeIndex: `nodes[${index}]`,
|
|
180
|
+
activeDataKey: props.dataKey,
|
|
181
|
+
activeCoordinate: coord
|
|
182
|
+
}));
|
|
183
|
+
props.onMouseEnter?.(node, "node", e);
|
|
184
|
+
}
|
|
185
|
+
function handleLinkMouseEnter(link, index, e) {
|
|
186
|
+
const sx = link.source.x1 ?? 0;
|
|
187
|
+
const tx = link.target.x0 ?? 0;
|
|
188
|
+
const sy = link.y0 ?? 0;
|
|
189
|
+
const ty = link.y1 ?? 0;
|
|
190
|
+
const coord = {
|
|
191
|
+
x: (sx + tx) / 2,
|
|
192
|
+
y: (sy + ty) / 2
|
|
193
|
+
};
|
|
194
|
+
dispatch(setActiveMouseOverItemIndex({
|
|
195
|
+
activeIndex: `links[${index}]`,
|
|
196
|
+
activeDataKey: props.dataKey,
|
|
197
|
+
activeCoordinate: coord
|
|
198
|
+
}));
|
|
199
|
+
props.onMouseEnter?.(link, "link", e);
|
|
200
|
+
}
|
|
201
|
+
function handleMouseLeave(item, type, e) {
|
|
202
|
+
dispatch(mouseLeaveItem());
|
|
203
|
+
props.onMouseLeave?.(item, type, e);
|
|
204
|
+
}
|
|
205
|
+
function handleNodeClick(node, index, e) {
|
|
206
|
+
const coord = {
|
|
207
|
+
x: ((node.x0 ?? 0) + (node.x1 ?? 0)) / 2,
|
|
208
|
+
y: ((node.y0 ?? 0) + (node.y1 ?? 0)) / 2
|
|
209
|
+
};
|
|
210
|
+
dispatch(setActiveClickItemIndex({
|
|
211
|
+
activeIndex: `nodes[${index}]`,
|
|
212
|
+
activeDataKey: props.dataKey,
|
|
213
|
+
activeCoordinate: coord
|
|
214
|
+
}));
|
|
215
|
+
props.onClick?.(node, "node", e);
|
|
216
|
+
}
|
|
217
|
+
function handleLinkClick(link, index, e) {
|
|
218
|
+
const coord = {
|
|
219
|
+
x: ((link.source.x1 ?? 0) + (link.target.x0 ?? 0)) / 2,
|
|
220
|
+
y: ((link.y0 ?? 0) + (link.y1 ?? 0)) / 2
|
|
221
|
+
};
|
|
222
|
+
dispatch(setActiveClickItemIndex({
|
|
223
|
+
activeIndex: `links[${index}]`,
|
|
224
|
+
activeDataKey: props.dataKey,
|
|
225
|
+
activeCoordinate: coord
|
|
226
|
+
}));
|
|
227
|
+
props.onClick?.(link, "link", e);
|
|
228
|
+
}
|
|
229
|
+
function renderNode(node, index, opacity) {
|
|
230
|
+
const x = node.x0 ?? 0;
|
|
231
|
+
const y = node.y0 ?? 0;
|
|
232
|
+
const width = (node.x1 ?? 0) - x;
|
|
233
|
+
const height = (node.y1 ?? 0) - y;
|
|
234
|
+
if (slots.node) {
|
|
235
|
+
const slotProps = {
|
|
236
|
+
payload: node,
|
|
237
|
+
index,
|
|
238
|
+
x,
|
|
239
|
+
y,
|
|
240
|
+
width,
|
|
241
|
+
height,
|
|
242
|
+
fill: props.nodeFill
|
|
243
|
+
};
|
|
244
|
+
return createVNode("g", {
|
|
245
|
+
"key": `node-${index}`,
|
|
246
|
+
"class": "v-charts-sankey-node",
|
|
247
|
+
"style": { opacity },
|
|
248
|
+
"onClick": (e) => handleNodeClick(node, index, e),
|
|
249
|
+
"onMouseenter": (e) => handleNodeMouseEnter(node, index, e),
|
|
250
|
+
"onMouseleave": (e) => handleMouseLeave(node, "node", e)
|
|
251
|
+
}, [slots.node(slotProps)]);
|
|
252
|
+
}
|
|
253
|
+
return createVNode("g", {
|
|
254
|
+
"key": `node-${index}`,
|
|
255
|
+
"class": "v-charts-sankey-node",
|
|
256
|
+
"style": { opacity },
|
|
257
|
+
"onClick": (e) => handleNodeClick(node, index, e),
|
|
258
|
+
"onMouseenter": (e) => handleNodeMouseEnter(node, index, e),
|
|
259
|
+
"onMouseleave": (e) => handleMouseLeave(node, "node", e)
|
|
260
|
+
}, [createVNode("rect", {
|
|
261
|
+
"x": x,
|
|
262
|
+
"y": y,
|
|
263
|
+
"width": width,
|
|
264
|
+
"height": height,
|
|
265
|
+
"fill": props.nodeFill,
|
|
266
|
+
"stroke": props.nodeStroke
|
|
267
|
+
}, null)]);
|
|
268
|
+
}
|
|
269
|
+
function renderLink(link, index, opacity) {
|
|
270
|
+
const d = linkPathGenerator(link) ?? "";
|
|
271
|
+
const linkWidth = link.width ?? 0;
|
|
272
|
+
if (slots.link) {
|
|
273
|
+
const slotProps = {
|
|
274
|
+
payload: link,
|
|
275
|
+
index,
|
|
276
|
+
d,
|
|
277
|
+
linkWidth,
|
|
278
|
+
fill: props.linkFill
|
|
279
|
+
};
|
|
280
|
+
return createVNode("g", {
|
|
281
|
+
"key": `link-${index}`,
|
|
282
|
+
"style": { opacity },
|
|
283
|
+
"onClick": (e) => handleLinkClick(link, index, e),
|
|
284
|
+
"onMouseenter": (e) => handleLinkMouseEnter(link, index, e),
|
|
285
|
+
"onMouseleave": (e) => handleMouseLeave(link, "link", e)
|
|
286
|
+
}, [slots.link(slotProps)]);
|
|
287
|
+
}
|
|
288
|
+
return createVNode("path", {
|
|
289
|
+
"key": `link-${index}`,
|
|
290
|
+
"class": "v-charts-sankey-link",
|
|
291
|
+
"d": d,
|
|
292
|
+
"fill": "none",
|
|
293
|
+
"stroke": props.linkStroke === "none" ? props.linkFill : props.linkStroke,
|
|
294
|
+
"stroke-width": linkWidth,
|
|
295
|
+
"stroke-opacity": .2,
|
|
296
|
+
"style": { opacity },
|
|
297
|
+
"onClick": (e) => handleLinkClick(link, index, e),
|
|
298
|
+
"onMouseenter": (e) => handleLinkMouseEnter(link, index, e),
|
|
299
|
+
"onMouseleave": (e) => handleMouseLeave(link, "link", e)
|
|
300
|
+
}, null);
|
|
301
|
+
}
|
|
302
|
+
return () => createVNode(Surface, {
|
|
303
|
+
"width": props.width,
|
|
304
|
+
"height": props.height
|
|
305
|
+
}, { default: () => [createVNode(Layer, { "class": "v-charts-sankey" }, { default: () => [createVNode(Animate, {
|
|
306
|
+
"isActive": props.isAnimationActive,
|
|
307
|
+
"from": 0,
|
|
308
|
+
"to": 1,
|
|
309
|
+
"transition": props.transition
|
|
310
|
+
}, { default: (progress) => createVNode(Fragment, null, [createVNode("g", { "class": "v-charts-sankey-links" }, [layout.value.links.map((link, i) => renderLink(link, i, progress))]), createVNode("g", { "class": "v-charts-sankey-nodes" }, [layout.value.nodes.map((node, i) => renderNode(node, i, progress))])]) })] })] });
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
var Sankey = /* @__PURE__ */ defineComponent({
|
|
314
|
+
name: "Sankey",
|
|
315
|
+
props: SankeyVueProps,
|
|
316
|
+
slots: Object,
|
|
317
|
+
setup(props, { slots }) {
|
|
318
|
+
provideStore({ store: createRechartsStore({ options: sankeyOptions }, "Sankey") });
|
|
319
|
+
return () => {
|
|
320
|
+
if (!props.data || !props.data.nodes || props.data.nodes.length === 0) return null;
|
|
321
|
+
return createVNode(RechartsWrapper, {
|
|
322
|
+
"width": props.width,
|
|
323
|
+
"height": props.height
|
|
324
|
+
}, { default: () => [createVNode(SankeyInner, props, {
|
|
325
|
+
node: slots.node,
|
|
326
|
+
link: slots.link
|
|
327
|
+
}), slots.default?.()] });
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
//#endregion
|
|
332
|
+
export { Sankey, SankeyVueProps, sankeyPayloadSearcher };
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { polarToCartesian } from "../utils/polar.mjs";
|
|
2
|
+
import { addTooltipEntrySettings, mouseLeaveItem, removeTooltipEntrySettings, setActiveClickItemIndex, setActiveMouseOverItemIndex } from "../state/tooltipSlice.mjs";
|
|
3
|
+
import { useAppDispatch } from "../state/hooks.mjs";
|
|
4
|
+
import { Layer } from "../container/Layer.mjs";
|
|
5
|
+
import { createRechartsStore } from "../state/store.mjs";
|
|
6
|
+
import { RechartsWrapper } from "./RechartsWrapper.mjs";
|
|
7
|
+
import Surface from "../container/Surface.mjs";
|
|
8
|
+
import { Sector } from "../shape/Sector.mjs";
|
|
9
|
+
import { computeSunburstLayout } from "./sunburstUtils.mjs";
|
|
10
|
+
import { computed, createVNode, defineComponent, isVNode, watchEffect } from "vue";
|
|
11
|
+
import { provideStore } from "@reduxjs/vue-redux";
|
|
12
|
+
import { get } from "lodash-es";
|
|
13
|
+
//#region src/chart/SunburstChart.tsx
|
|
14
|
+
function _isSlot(s) {
|
|
15
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
16
|
+
}
|
|
17
|
+
var sunburstPayloadSearcher = (data, activeIndex) => {
|
|
18
|
+
if (!data || !activeIndex) return void 0;
|
|
19
|
+
return get(data, activeIndex);
|
|
20
|
+
};
|
|
21
|
+
var sunburstOptions = {
|
|
22
|
+
chartName: "SunburstChart",
|
|
23
|
+
defaultTooltipEventType: "item",
|
|
24
|
+
validateTooltipEventTypes: ["item"],
|
|
25
|
+
tooltipPayloadSearcher: sunburstPayloadSearcher,
|
|
26
|
+
eventEmitter: void 0
|
|
27
|
+
};
|
|
28
|
+
var SunburstChartVueProps = {
|
|
29
|
+
data: {
|
|
30
|
+
type: Object,
|
|
31
|
+
required: true
|
|
32
|
+
},
|
|
33
|
+
dataKey: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: "value"
|
|
36
|
+
},
|
|
37
|
+
nameKey: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: "name"
|
|
40
|
+
},
|
|
41
|
+
width: {
|
|
42
|
+
type: Number,
|
|
43
|
+
required: true
|
|
44
|
+
},
|
|
45
|
+
height: {
|
|
46
|
+
type: Number,
|
|
47
|
+
required: true
|
|
48
|
+
},
|
|
49
|
+
cx: {
|
|
50
|
+
type: Number,
|
|
51
|
+
default: void 0
|
|
52
|
+
},
|
|
53
|
+
cy: {
|
|
54
|
+
type: Number,
|
|
55
|
+
default: void 0
|
|
56
|
+
},
|
|
57
|
+
innerRadius: {
|
|
58
|
+
type: Number,
|
|
59
|
+
default: 50
|
|
60
|
+
},
|
|
61
|
+
outerRadius: {
|
|
62
|
+
type: Number,
|
|
63
|
+
default: void 0
|
|
64
|
+
},
|
|
65
|
+
startAngle: {
|
|
66
|
+
type: Number,
|
|
67
|
+
default: 0
|
|
68
|
+
},
|
|
69
|
+
endAngle: {
|
|
70
|
+
type: Number,
|
|
71
|
+
default: 360
|
|
72
|
+
},
|
|
73
|
+
ringPadding: {
|
|
74
|
+
type: Number,
|
|
75
|
+
default: 2
|
|
76
|
+
},
|
|
77
|
+
padding: {
|
|
78
|
+
type: Number,
|
|
79
|
+
default: 2
|
|
80
|
+
},
|
|
81
|
+
fill: {
|
|
82
|
+
type: String,
|
|
83
|
+
default: "#333"
|
|
84
|
+
},
|
|
85
|
+
stroke: {
|
|
86
|
+
type: String,
|
|
87
|
+
default: "#fff"
|
|
88
|
+
},
|
|
89
|
+
onClick: {
|
|
90
|
+
type: Function,
|
|
91
|
+
default: void 0
|
|
92
|
+
},
|
|
93
|
+
onMouseEnter: {
|
|
94
|
+
type: Function,
|
|
95
|
+
default: void 0
|
|
96
|
+
},
|
|
97
|
+
onMouseLeave: {
|
|
98
|
+
type: Function,
|
|
99
|
+
default: void 0
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var SunburstInner = /* @__PURE__ */ defineComponent({
|
|
103
|
+
name: "SunburstInner",
|
|
104
|
+
props: SunburstChartVueProps,
|
|
105
|
+
slots: Object,
|
|
106
|
+
setup(props, { slots }) {
|
|
107
|
+
const dispatch = useAppDispatch();
|
|
108
|
+
const resolvedCx = computed(() => props.cx ?? props.width / 2);
|
|
109
|
+
const resolvedCy = computed(() => props.cy ?? props.height / 2);
|
|
110
|
+
const resolvedOuterRadius = computed(() => props.outerRadius ?? Math.min(props.width, props.height) / 2);
|
|
111
|
+
const nodes = computed(() => computeSunburstLayout({
|
|
112
|
+
data: props.data,
|
|
113
|
+
cx: resolvedCx.value,
|
|
114
|
+
cy: resolvedCy.value,
|
|
115
|
+
innerRadius: props.innerRadius,
|
|
116
|
+
outerRadius: resolvedOuterRadius.value,
|
|
117
|
+
startAngle: props.startAngle,
|
|
118
|
+
endAngle: props.endAngle,
|
|
119
|
+
dataKey: props.dataKey,
|
|
120
|
+
ringPadding: props.ringPadding,
|
|
121
|
+
padding: props.padding
|
|
122
|
+
}));
|
|
123
|
+
watchEffect((onCleanup) => {
|
|
124
|
+
const tooltipEntrySettings = {
|
|
125
|
+
dataDefinedOnItem: props.data,
|
|
126
|
+
positions: void 0,
|
|
127
|
+
settings: {
|
|
128
|
+
stroke: props.stroke,
|
|
129
|
+
strokeWidth: void 0,
|
|
130
|
+
fill: props.fill,
|
|
131
|
+
dataKey: props.dataKey,
|
|
132
|
+
nameKey: props.nameKey,
|
|
133
|
+
name: void 0,
|
|
134
|
+
hide: false,
|
|
135
|
+
type: void 0,
|
|
136
|
+
color: props.fill,
|
|
137
|
+
unit: ""
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
dispatch(addTooltipEntrySettings(tooltipEntrySettings));
|
|
141
|
+
onCleanup(() => {
|
|
142
|
+
dispatch(removeTooltipEntrySettings(tooltipEntrySettings));
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
function getNodeFill(node) {
|
|
146
|
+
if (node.fill) return node.fill;
|
|
147
|
+
return props.fill;
|
|
148
|
+
}
|
|
149
|
+
function getTooltipCoordinate(node) {
|
|
150
|
+
const midAngle = (node.startAngle + node.endAngle) / 2;
|
|
151
|
+
const midRadius = (node.innerRadius + node.outerRadius) / 2;
|
|
152
|
+
return polarToCartesian(node.cx, node.cy, midRadius, midAngle);
|
|
153
|
+
}
|
|
154
|
+
function handleMouseEnter(node, e) {
|
|
155
|
+
dispatch(setActiveMouseOverItemIndex({
|
|
156
|
+
activeIndex: node.tooltipIndex,
|
|
157
|
+
activeDataKey: props.dataKey,
|
|
158
|
+
activeCoordinate: getTooltipCoordinate(node)
|
|
159
|
+
}));
|
|
160
|
+
props.onMouseEnter?.(node.payload, e);
|
|
161
|
+
}
|
|
162
|
+
function handleMouseLeave(node, e) {
|
|
163
|
+
dispatch(mouseLeaveItem());
|
|
164
|
+
props.onMouseLeave?.(node.payload, e);
|
|
165
|
+
}
|
|
166
|
+
function handleClick(node, e) {
|
|
167
|
+
dispatch(setActiveClickItemIndex({
|
|
168
|
+
activeIndex: node.tooltipIndex,
|
|
169
|
+
activeDataKey: props.dataKey,
|
|
170
|
+
activeCoordinate: getTooltipCoordinate(node)
|
|
171
|
+
}));
|
|
172
|
+
props.onClick?.(node.payload, e);
|
|
173
|
+
}
|
|
174
|
+
function renderSector(node, index) {
|
|
175
|
+
const nodeFill = getNodeFill(node);
|
|
176
|
+
const slotProps = {
|
|
177
|
+
...node,
|
|
178
|
+
index
|
|
179
|
+
};
|
|
180
|
+
if (slots.content) return createVNode("g", {
|
|
181
|
+
"key": `sector-${index}`,
|
|
182
|
+
"class": "v-charts-sunburst-sector",
|
|
183
|
+
"onClick": (e) => handleClick(node, e),
|
|
184
|
+
"onMouseenter": (e) => handleMouseEnter(node, e),
|
|
185
|
+
"onMouseleave": (e) => handleMouseLeave(node, e)
|
|
186
|
+
}, [slots.content(slotProps)]);
|
|
187
|
+
return createVNode("g", {
|
|
188
|
+
"key": `sector-${index}`,
|
|
189
|
+
"class": "v-charts-sunburst-sector",
|
|
190
|
+
"onClick": (e) => handleClick(node, e),
|
|
191
|
+
"onMouseenter": (e) => handleMouseEnter(node, e),
|
|
192
|
+
"onMouseleave": (e) => handleMouseLeave(node, e)
|
|
193
|
+
}, [createVNode(Sector, {
|
|
194
|
+
"cx": node.cx,
|
|
195
|
+
"cy": node.cy,
|
|
196
|
+
"innerRadius": node.innerRadius,
|
|
197
|
+
"outerRadius": node.outerRadius,
|
|
198
|
+
"startAngle": node.startAngle,
|
|
199
|
+
"endAngle": node.endAngle,
|
|
200
|
+
"fill": nodeFill,
|
|
201
|
+
"stroke": props.stroke
|
|
202
|
+
}, null)]);
|
|
203
|
+
}
|
|
204
|
+
return () => {
|
|
205
|
+
let _slot;
|
|
206
|
+
return createVNode(Surface, {
|
|
207
|
+
"width": props.width,
|
|
208
|
+
"height": props.height
|
|
209
|
+
}, { default: () => [createVNode(Layer, { "class": "v-charts-sunburst" }, _isSlot(_slot = nodes.value.map((node, index) => renderSector(node, index))) ? _slot : { default: () => [_slot] })] });
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
var SunburstChart = /* @__PURE__ */ defineComponent({
|
|
214
|
+
name: "SunburstChart",
|
|
215
|
+
props: SunburstChartVueProps,
|
|
216
|
+
slots: Object,
|
|
217
|
+
setup(props, { slots }) {
|
|
218
|
+
provideStore({ store: createRechartsStore({ options: sunburstOptions }, "SunburstChart") });
|
|
219
|
+
return () => {
|
|
220
|
+
if (!props.data?.children || props.data.children.length === 0) return null;
|
|
221
|
+
return createVNode(RechartsWrapper, {
|
|
222
|
+
"width": props.width,
|
|
223
|
+
"height": props.height
|
|
224
|
+
}, { default: () => [createVNode(SunburstInner, props, { content: slots.content }), slots.default?.()] });
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
//#endregion
|
|
229
|
+
export { SunburstChart, SunburstChartVueProps, sunburstPayloadSearcher };
|
|
@@ -73,7 +73,11 @@ var CategoricalProps = {
|
|
|
73
73
|
default: "none"
|
|
74
74
|
},
|
|
75
75
|
startAngle: { type: Number },
|
|
76
|
-
style: { type:
|
|
76
|
+
style: { type: [
|
|
77
|
+
String,
|
|
78
|
+
Object,
|
|
79
|
+
Array
|
|
80
|
+
] },
|
|
77
81
|
syncId: { type: [Number, String] },
|
|
78
82
|
syncMethod: {
|
|
79
83
|
type: [String, Function],
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { toRaw } from "vue";
|
|
2
|
+
import { sankey, sankeyLinkHorizontal } from "d3-sankey";
|
|
3
|
+
//#region src/chart/sankeyUtils.ts
|
|
4
|
+
function computeSankeyLayout(args) {
|
|
5
|
+
const { data, width, height, nodePadding, nodeWidth, iterations, margin } = args;
|
|
6
|
+
const cloned = {
|
|
7
|
+
nodes: data.nodes.map((n) => ({ ...toRaw(n) })),
|
|
8
|
+
links: data.links.map((l) => ({ ...toRaw(l) }))
|
|
9
|
+
};
|
|
10
|
+
const result = sankey().nodeWidth(nodeWidth).nodePadding(nodePadding).extent([[margin.left, margin.top], [Math.max(margin.left + 1, width - margin.right), Math.max(margin.top + 1, height - margin.bottom)]]).iterations(iterations)(cloned);
|
|
11
|
+
const x0Min = margin.left;
|
|
12
|
+
const x1Max = Math.max(margin.left + 1, width - margin.right);
|
|
13
|
+
const y0Min = margin.top;
|
|
14
|
+
const y1Max = Math.max(margin.top + 1, height - margin.bottom);
|
|
15
|
+
for (const n of result.nodes) {
|
|
16
|
+
if (n.x0 != null && n.x0 < x0Min) n.x0 = x0Min;
|
|
17
|
+
if (n.x1 != null && n.x1 > x1Max) n.x1 = x1Max;
|
|
18
|
+
if (n.y0 != null && n.y0 < y0Min) n.y0 = y0Min;
|
|
19
|
+
if (n.y1 != null && n.y1 > y1Max) n.y1 = y1Max;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
nodes: result.nodes,
|
|
23
|
+
links: result.links
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
var linkPathGenerator = sankeyLinkHorizontal();
|
|
27
|
+
//#endregion
|
|
28
|
+
export { computeSankeyLayout, linkPathGenerator };
|