@antv/infographic 0.2.13 → 0.2.15
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 +12 -5
- package/README.zh-CN.md +12 -5
- package/dist/infographic.min.js +180 -171
- package/dist/infographic.min.js.map +1 -1
- package/esm/designs/structures/index.d.ts +1 -0
- package/esm/designs/structures/index.js +1 -0
- package/esm/designs/structures/relation-dagre-flow.js +4 -139
- package/esm/designs/structures/sequence-interaction.d.ts +54 -0
- package/esm/designs/structures/sequence-interaction.js +440 -0
- package/esm/designs/utils/geometry.d.ts +44 -0
- package/esm/designs/utils/geometry.js +244 -0
- package/esm/designs/utils/index.d.ts +1 -0
- package/esm/designs/utils/index.js +1 -0
- package/esm/editor/commands/UpdateOptions.d.ts +4 -4
- package/esm/editor/commands/UpdateOptions.js +6 -3
- package/esm/editor/editor.d.ts +5 -1
- package/esm/editor/editor.js +16 -5
- package/esm/editor/index.d.ts +1 -0
- package/esm/editor/index.js +1 -0
- package/esm/editor/interactions/brush-select.d.ts +0 -1
- package/esm/editor/interactions/brush-select.js +2 -10
- package/esm/editor/interactions/drag-canvas.d.ts +35 -0
- package/esm/editor/interactions/drag-canvas.js +161 -0
- package/esm/editor/interactions/drag-element.js +4 -3
- package/esm/editor/interactions/index.d.ts +1 -0
- package/esm/editor/interactions/index.js +1 -0
- package/esm/editor/interactions/zoom-wheel.d.ts +9 -0
- package/esm/editor/interactions/zoom-wheel.js +32 -15
- package/esm/editor/managers/index.d.ts +1 -0
- package/esm/editor/managers/index.js +1 -0
- package/esm/editor/managers/state.d.ts +4 -2
- package/esm/editor/managers/state.js +14 -13
- package/esm/editor/managers/sync-registry.d.ts +16 -0
- package/esm/editor/managers/sync-registry.js +51 -0
- package/esm/editor/plugins/{edit-bar/components → components}/button.js +1 -1
- package/esm/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
- package/esm/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
- package/esm/editor/plugins/{edit-bar/components → components}/icons.js +1 -0
- package/esm/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
- package/esm/editor/plugins/{edit-bar/components → components}/select.js +1 -1
- package/esm/editor/plugins/core-sync.d.ts +8 -0
- package/esm/editor/plugins/core-sync.js +30 -0
- package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
- package/esm/editor/plugins/edit-bar/index.d.ts +2 -2
- package/esm/editor/plugins/edit-bar/index.js +1 -1
- package/esm/editor/plugins/index.d.ts +2 -0
- package/esm/editor/plugins/index.js +2 -0
- package/esm/editor/plugins/reset-viewbox.d.ts +33 -0
- package/esm/editor/plugins/reset-viewbox.js +186 -0
- package/esm/editor/types/editor.d.ts +14 -0
- package/esm/editor/types/index.d.ts +1 -0
- package/esm/editor/types/interaction.d.ts +9 -0
- package/esm/editor/types/state.d.ts +4 -2
- package/esm/editor/types/sync.d.ts +27 -0
- package/esm/editor/types/sync.js +1 -0
- package/esm/editor/utils/data.js +3 -1
- package/esm/editor/utils/event.d.ts +1 -0
- package/esm/editor/utils/event.js +8 -0
- package/esm/editor/utils/index.d.ts +1 -0
- package/esm/editor/utils/index.js +1 -0
- package/esm/editor/utils/object.d.ts +15 -0
- package/esm/editor/utils/object.js +77 -0
- package/esm/index.d.ts +4 -3
- package/esm/index.js +3 -2
- package/esm/options/types.d.ts +7 -0
- package/esm/runtime/Infographic.js +20 -7
- package/esm/runtime/options.js +7 -2
- package/esm/syntax/index.js +40 -20
- package/esm/syntax/relations.js +26 -2
- package/esm/syntax/schema.js +1 -0
- package/esm/templates/built-in.js +27 -2
- package/esm/templates/sequence-interaction.d.ts +2 -0
- package/esm/templates/sequence-interaction.js +76 -0
- package/esm/types/data.d.ts +1 -0
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.js +1 -0
- package/esm/utils/measure-text.js +40 -9
- package/esm/utils/padding.d.ts +1 -0
- package/esm/utils/padding.js +6 -2
- package/esm/utils/types.d.ts +16 -0
- package/esm/utils/types.js +12 -0
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/lib/designs/structures/index.d.ts +1 -0
- package/lib/designs/structures/index.js +1 -0
- package/lib/designs/structures/relation-dagre-flow.js +5 -140
- package/lib/designs/structures/sequence-interaction.d.ts +54 -0
- package/lib/designs/structures/sequence-interaction.js +444 -0
- package/lib/designs/utils/geometry.d.ts +44 -0
- package/lib/designs/utils/geometry.js +256 -0
- package/lib/designs/utils/index.d.ts +1 -0
- package/lib/designs/utils/index.js +1 -0
- package/lib/editor/commands/UpdateOptions.d.ts +4 -4
- package/lib/editor/commands/UpdateOptions.js +6 -3
- package/lib/editor/editor.d.ts +5 -1
- package/lib/editor/editor.js +16 -5
- package/lib/editor/index.d.ts +1 -0
- package/lib/editor/index.js +1 -0
- package/lib/editor/interactions/brush-select.d.ts +0 -1
- package/lib/editor/interactions/brush-select.js +1 -9
- package/lib/editor/interactions/drag-canvas.d.ts +35 -0
- package/lib/editor/interactions/drag-canvas.js +165 -0
- package/lib/editor/interactions/drag-element.js +4 -3
- package/lib/editor/interactions/index.d.ts +1 -0
- package/lib/editor/interactions/index.js +3 -1
- package/lib/editor/interactions/zoom-wheel.d.ts +9 -0
- package/lib/editor/interactions/zoom-wheel.js +32 -15
- package/lib/editor/managers/index.d.ts +1 -0
- package/lib/editor/managers/index.js +1 -0
- package/lib/editor/managers/state.d.ts +4 -2
- package/lib/editor/managers/state.js +12 -11
- package/lib/editor/managers/sync-registry.d.ts +16 -0
- package/lib/editor/managers/sync-registry.js +55 -0
- package/lib/editor/plugins/{edit-bar/components → components}/button.js +1 -1
- package/lib/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
- package/lib/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
- package/lib/editor/plugins/{edit-bar/components → components}/icons.js +2 -1
- package/lib/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
- package/lib/editor/plugins/{edit-bar/components → components}/select.js +1 -1
- package/lib/editor/plugins/core-sync.d.ts +8 -0
- package/lib/editor/plugins/core-sync.js +34 -0
- package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
- package/lib/editor/plugins/edit-bar/index.d.ts +2 -2
- package/lib/editor/plugins/edit-bar/index.js +1 -1
- package/lib/editor/plugins/index.d.ts +2 -0
- package/lib/editor/plugins/index.js +5 -1
- package/lib/editor/plugins/reset-viewbox.d.ts +33 -0
- package/lib/editor/plugins/reset-viewbox.js +190 -0
- package/lib/editor/types/editor.d.ts +14 -0
- package/lib/editor/types/index.d.ts +1 -0
- package/lib/editor/types/interaction.d.ts +9 -0
- package/lib/editor/types/state.d.ts +4 -2
- package/lib/editor/types/sync.d.ts +27 -0
- package/lib/editor/types/sync.js +2 -0
- package/lib/editor/utils/data.js +3 -1
- package/lib/editor/utils/event.d.ts +1 -0
- package/lib/editor/utils/event.js +9 -0
- package/lib/editor/utils/index.d.ts +1 -0
- package/lib/editor/utils/index.js +1 -0
- package/lib/editor/utils/object.d.ts +15 -0
- package/lib/editor/utils/object.js +80 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.js +9 -2
- package/lib/options/types.d.ts +7 -0
- package/lib/runtime/Infographic.js +19 -6
- package/lib/runtime/options.js +6 -1
- package/lib/syntax/index.js +40 -20
- package/lib/syntax/relations.js +26 -2
- package/lib/syntax/schema.js +1 -0
- package/lib/templates/built-in.js +27 -2
- package/lib/templates/sequence-interaction.d.ts +2 -0
- package/lib/templates/sequence-interaction.js +79 -0
- package/lib/types/data.d.ts +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/measure-text.js +39 -8
- package/lib/utils/padding.d.ts +1 -0
- package/lib/utils/padding.js +7 -2
- package/lib/utils/types.d.ts +16 -0
- package/lib/utils/types.js +13 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/designs/structures/index.ts +1 -0
- package/src/designs/structures/relation-dagre-flow.tsx +14 -178
- package/src/designs/structures/sequence-interaction.tsx +885 -0
- package/src/designs/utils/geometry.tsx +315 -0
- package/src/designs/utils/index.ts +1 -0
- package/src/editor/commands/UpdateOptions.ts +11 -6
- package/src/editor/editor.ts +26 -5
- package/src/editor/index.ts +1 -0
- package/src/editor/interactions/brush-select.ts +2 -8
- package/src/editor/interactions/drag-canvas.ts +203 -0
- package/src/editor/interactions/drag-element.ts +5 -4
- package/src/editor/interactions/index.ts +1 -0
- package/src/editor/interactions/zoom-wheel.ts +49 -13
- package/src/editor/managers/index.ts +1 -0
- package/src/editor/managers/state.ts +21 -21
- package/src/editor/managers/sync-registry.ts +66 -0
- package/src/editor/plugins/{edit-bar/components → components}/button.ts +1 -1
- package/src/editor/plugins/{edit-bar/components → components}/color-picker.ts +1 -1
- package/src/editor/plugins/{edit-bar/components → components}/icons.ts +4 -0
- package/src/editor/plugins/{edit-bar/components → components}/popover.ts +2 -2
- package/src/editor/plugins/{edit-bar/components → components}/select.ts +1 -1
- package/src/editor/plugins/core-sync.ts +44 -0
- package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +2 -2
- package/src/editor/plugins/edit-bar/edit-items/font-align.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-color.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-family.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-size.ts +3 -3
- package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +1 -1
- package/src/editor/plugins/edit-bar/index.ts +2 -2
- package/src/editor/plugins/index.ts +2 -0
- package/src/editor/plugins/reset-viewbox.ts +258 -0
- package/src/editor/types/editor.ts +18 -0
- package/src/editor/types/index.ts +1 -0
- package/src/editor/types/interaction.ts +31 -0
- package/src/editor/types/state.ts +14 -2
- package/src/editor/types/sync.ts +33 -0
- package/src/editor/utils/data.ts +2 -1
- package/src/editor/utils/event.ts +7 -0
- package/src/editor/utils/index.ts +1 -0
- package/src/editor/utils/object.ts +116 -0
- package/src/index.ts +26 -2
- package/src/options/types.ts +11 -0
- package/src/runtime/Infographic.tsx +27 -17
- package/src/runtime/options.ts +8 -1
- package/src/syntax/index.ts +51 -18
- package/src/syntax/relations.ts +29 -2
- package/src/syntax/schema.ts +1 -0
- package/src/templates/built-in.ts +30 -0
- package/src/templates/sequence-interaction.ts +101 -0
- package/src/types/data.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/measure-text.ts +41 -9
- package/src/utils/padding.ts +10 -2
- package/src/utils/types.ts +61 -0
- package/src/version.ts +1 -1
- /package/esm/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/index.js +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/index.js +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
- /package/src/editor/plugins/{edit-bar/components → components}/index.ts +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { COMPONENT_ROLE } from '../../constants/index.js';
|
|
2
|
+
import { getBoundViewBox, getViewBox, injectStyleOnce, parsePadding, setElementRole, viewBoxToString, } from '../../utils/index.js';
|
|
3
|
+
import { UpdateOptionsCommand } from '../commands/index.js';
|
|
4
|
+
import { Plugin } from './base.js';
|
|
5
|
+
import { IconButton } from './components/index.js';
|
|
6
|
+
import { RESET_ICON } from './components/icons.js';
|
|
7
|
+
const MARGIN_X = 25;
|
|
8
|
+
const MARGIN_Y = 25;
|
|
9
|
+
const BUTTON_SIZE = 40;
|
|
10
|
+
export class ResetViewBox extends Plugin {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super();
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.name = 'reset-viewBox';
|
|
15
|
+
this.viewBoxChanged = false;
|
|
16
|
+
this.handleResize = () => {
|
|
17
|
+
this.updateOriginViewBox();
|
|
18
|
+
this.updatePosition();
|
|
19
|
+
};
|
|
20
|
+
this.handleViewBoxChange = (viewBox) => {
|
|
21
|
+
const svg = this.editor.getDocument();
|
|
22
|
+
this.viewBoxChanged = viewBox !== this.originViewBox;
|
|
23
|
+
if (!this.viewBoxChanged) {
|
|
24
|
+
if (this.resetButton)
|
|
25
|
+
this.hideButton(this.resetButton);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const button = this.getOrCreateResetButton();
|
|
29
|
+
this.placeButton(button, svg);
|
|
30
|
+
this.showButton(button);
|
|
31
|
+
};
|
|
32
|
+
this.getOrCreateResetButton = () => {
|
|
33
|
+
if (this.resetButton)
|
|
34
|
+
return this.resetButton;
|
|
35
|
+
const { style, className } = this.options || {};
|
|
36
|
+
const button = IconButton({
|
|
37
|
+
icon: RESET_ICON,
|
|
38
|
+
onClick: this.resetViewBox,
|
|
39
|
+
});
|
|
40
|
+
button.classList.add(RESET_BUTTON_CLASS);
|
|
41
|
+
if (className) {
|
|
42
|
+
button.classList.add(className);
|
|
43
|
+
}
|
|
44
|
+
if (style) {
|
|
45
|
+
Object.assign(button.style, style);
|
|
46
|
+
}
|
|
47
|
+
setElementRole(button, COMPONENT_ROLE);
|
|
48
|
+
this.resetButton = button;
|
|
49
|
+
const { getContainer } = this.options || {};
|
|
50
|
+
const resolvedContainer = typeof getContainer === 'function' ? getContainer() : getContainer;
|
|
51
|
+
const containerParent = resolvedContainer !== null && resolvedContainer !== void 0 ? resolvedContainer : document.body;
|
|
52
|
+
containerParent === null || containerParent === void 0 ? void 0 : containerParent.appendChild(button);
|
|
53
|
+
return button;
|
|
54
|
+
};
|
|
55
|
+
/** Get CSS transform scale of an element */
|
|
56
|
+
this.getTransformScale = (element) => {
|
|
57
|
+
const rect = element.getBoundingClientRect();
|
|
58
|
+
const scaleX = element.offsetWidth > 0 ? rect.width / element.offsetWidth : 1;
|
|
59
|
+
const scaleY = element.offsetHeight > 0 ? rect.height / element.offsetHeight : 1;
|
|
60
|
+
return { scaleX, scaleY };
|
|
61
|
+
};
|
|
62
|
+
/** Find the nearest stable overflow container */
|
|
63
|
+
this.findStableContainer = (svg) => {
|
|
64
|
+
let current = svg.parentElement;
|
|
65
|
+
while (current) {
|
|
66
|
+
if (current instanceof HTMLElement) {
|
|
67
|
+
const style = window.getComputedStyle(current);
|
|
68
|
+
// Look for overflow container or positioned element as stable reference
|
|
69
|
+
if ((style.overflow && style.overflow !== 'visible') ||
|
|
70
|
+
(style.overflowX && style.overflowX !== 'visible') ||
|
|
71
|
+
(style.overflowY && style.overflowY !== 'visible')) {
|
|
72
|
+
return current;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
current = current.parentElement;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
};
|
|
79
|
+
this.placeButton = (button, svg) => {
|
|
80
|
+
var _a;
|
|
81
|
+
if (!svg.isConnected)
|
|
82
|
+
return;
|
|
83
|
+
const svgRect = svg.getBoundingClientRect();
|
|
84
|
+
const offsetParent = (_a = button.offsetParent) !== null && _a !== void 0 ? _a : document.documentElement;
|
|
85
|
+
// Use stable container bounds to clamp button position when SVG overflows
|
|
86
|
+
const stableContainer = this.findStableContainer(svg);
|
|
87
|
+
const containerRect = stableContainer === null || stableContainer === void 0 ? void 0 : stableContainer.getBoundingClientRect();
|
|
88
|
+
// Prefer SVG bounds, but clamp to container if SVG overflows
|
|
89
|
+
const effectiveRect = containerRect
|
|
90
|
+
? {
|
|
91
|
+
right: Math.min(svgRect.right, containerRect.right),
|
|
92
|
+
bottom: Math.min(svgRect.bottom, containerRect.bottom),
|
|
93
|
+
}
|
|
94
|
+
: svgRect;
|
|
95
|
+
if (offsetParent === document.body ||
|
|
96
|
+
offsetParent === document.documentElement) {
|
|
97
|
+
const scrollX = window.scrollX || document.documentElement.scrollLeft;
|
|
98
|
+
const scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
99
|
+
const left = scrollX + effectiveRect.right - MARGIN_X - BUTTON_SIZE;
|
|
100
|
+
const top = scrollY + effectiveRect.bottom - MARGIN_Y - BUTTON_SIZE;
|
|
101
|
+
button.style.left = `${left}px`;
|
|
102
|
+
button.style.top = `${top}px`;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const parentRect = offsetParent.getBoundingClientRect();
|
|
106
|
+
// Compensate for parent transform scale
|
|
107
|
+
const { scaleX, scaleY } = this.getTransformScale(offsetParent);
|
|
108
|
+
// Convert to offsetParent local coordinates
|
|
109
|
+
const left = (effectiveRect.right - parentRect.left) / scaleX - MARGIN_X - BUTTON_SIZE;
|
|
110
|
+
const top = (effectiveRect.bottom - parentRect.top) / scaleY - MARGIN_Y - BUTTON_SIZE;
|
|
111
|
+
button.style.left = `${left}px`;
|
|
112
|
+
button.style.top = `${top}px`;
|
|
113
|
+
};
|
|
114
|
+
this.updatePosition = () => {
|
|
115
|
+
if (this.resetButton && this.viewBoxChanged) {
|
|
116
|
+
this.placeButton(this.resetButton, this.editor.getDocument());
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
this.resetViewBox = () => {
|
|
120
|
+
const command = new UpdateOptionsCommand({
|
|
121
|
+
viewBox: this.originViewBox,
|
|
122
|
+
});
|
|
123
|
+
void this.commander.execute(command);
|
|
124
|
+
};
|
|
125
|
+
this.showButton = (button) => {
|
|
126
|
+
button.style.display = 'flex';
|
|
127
|
+
button.style.visibility = 'visible';
|
|
128
|
+
};
|
|
129
|
+
this.hideButton = (button) => {
|
|
130
|
+
button.style.display = 'none';
|
|
131
|
+
};
|
|
132
|
+
this.removeButton = () => {
|
|
133
|
+
var _a;
|
|
134
|
+
this.viewBoxChanged = false;
|
|
135
|
+
(_a = this.resetButton) === null || _a === void 0 ? void 0 : _a.remove();
|
|
136
|
+
this.resetButton = undefined;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
init(options) {
|
|
140
|
+
super.init(options);
|
|
141
|
+
// Initialize originViewBox
|
|
142
|
+
this.ensureButtonStyle();
|
|
143
|
+
this.updateOriginViewBox();
|
|
144
|
+
this.unregisterSync = this.editor.registerSync('viewBox', this.handleViewBoxChange);
|
|
145
|
+
window.addEventListener('resize', this.handleResize);
|
|
146
|
+
}
|
|
147
|
+
destroy() {
|
|
148
|
+
var _a;
|
|
149
|
+
(_a = this.unregisterSync) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
150
|
+
window.removeEventListener('resize', this.handleResize);
|
|
151
|
+
this.removeButton();
|
|
152
|
+
}
|
|
153
|
+
updateOriginViewBox() {
|
|
154
|
+
const svg = this.editor.getDocument();
|
|
155
|
+
// In Node env or before render, fallback to current viewBox attribute
|
|
156
|
+
if (!svg.getBBox) {
|
|
157
|
+
this.originViewBox = viewBoxToString(getViewBox(svg));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// In Browser, calculate fit
|
|
161
|
+
const { padding } = this.state.getOptions();
|
|
162
|
+
this.originViewBox = getBoundViewBox(svg, parsePadding(padding));
|
|
163
|
+
}
|
|
164
|
+
ensureButtonStyle() {
|
|
165
|
+
injectStyleOnce(RESET_BUTTON_STYLE_ID, `
|
|
166
|
+
button.${RESET_BUTTON_CLASS} {
|
|
167
|
+
visibility: hidden;
|
|
168
|
+
position: absolute;
|
|
169
|
+
display: flex;
|
|
170
|
+
justify-content: center;
|
|
171
|
+
align-items: center;
|
|
172
|
+
width: ${BUTTON_SIZE}px;
|
|
173
|
+
height: ${BUTTON_SIZE}px;
|
|
174
|
+
border-radius: 50%;
|
|
175
|
+
padding: 4px;
|
|
176
|
+
background-color: #fff;
|
|
177
|
+
border: 1px solid #e5e7eb;
|
|
178
|
+
z-index: 1000;
|
|
179
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
}
|
|
182
|
+
`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const RESET_BUTTON_CLASS = 'infographic-reset-viewbox-btn';
|
|
186
|
+
const RESET_BUTTON_STYLE_ID = 'infographic-reset-viewbox-btn-style';
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
import type { InfographicOptionPath } from '../../options';
|
|
2
|
+
import type { ICommandManager } from './command';
|
|
3
|
+
import type { IInteractionManager } from './interaction';
|
|
4
|
+
import type { IPluginManager } from './plugin';
|
|
5
|
+
import type { IStateManager } from './state';
|
|
6
|
+
import type { ISyncRegistry, SyncHandler } from './sync';
|
|
1
7
|
export interface IEditor {
|
|
8
|
+
commander: ICommandManager;
|
|
9
|
+
interaction: IInteractionManager;
|
|
10
|
+
plugin: IPluginManager;
|
|
11
|
+
state: IStateManager;
|
|
12
|
+
syncRegistry: ISyncRegistry;
|
|
2
13
|
getDocument(): SVGSVGElement;
|
|
14
|
+
registerSync(path: InfographicOptionPath | (string & {}), handler: SyncHandler, options?: {
|
|
15
|
+
immediate?: boolean;
|
|
16
|
+
}): () => void;
|
|
3
17
|
destroy(): void;
|
|
4
18
|
}
|
|
@@ -3,6 +3,11 @@ import type { ICommandManager } from './command';
|
|
|
3
3
|
import type { IEditor } from './editor';
|
|
4
4
|
import type { Selection } from './selection';
|
|
5
5
|
import type { IStateManager } from './state';
|
|
6
|
+
/**
|
|
7
|
+
* Union type of common key codes, using (string & {}) trick to provide completion suggestions without limiting specific strings
|
|
8
|
+
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
|
|
9
|
+
*/
|
|
10
|
+
export type KeyCode = 'Space' | 'ShiftLeft' | 'ShiftRight' | 'ControlLeft' | 'ControlRight' | 'AltLeft' | 'AltRight' | 'MetaLeft' | 'MetaRight' | 'CapsLock' | 'Tab' | 'Enter' | 'Escape' | 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | `Key${string}` | `Digit${number}` | (string & {});
|
|
6
11
|
export interface IInteraction {
|
|
7
12
|
name: string;
|
|
8
13
|
init(options: InteractionInitOptions): void;
|
|
@@ -17,6 +22,10 @@ export interface SelectionChangePayload {
|
|
|
17
22
|
removed: Selection;
|
|
18
23
|
mode: SelectMode;
|
|
19
24
|
}
|
|
25
|
+
export interface viewBoxChangePayload {
|
|
26
|
+
type: 'viewBox:change';
|
|
27
|
+
viewBox: string | undefined;
|
|
28
|
+
}
|
|
20
29
|
export interface IInteractionManager {
|
|
21
30
|
isActive(): boolean;
|
|
22
31
|
select(items: Selection, mode: SelectMode): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ParsedInfographicOptions } from '../../options';
|
|
1
|
+
import type { ParsedInfographicOptions, UpdatableInfographicOptions } from '../../options';
|
|
2
2
|
import type { Element, IEventEmitter, ItemDatum } from '../../types';
|
|
3
3
|
import type { ICommandManager } from './command';
|
|
4
4
|
import type { IEditor } from './editor';
|
|
@@ -21,7 +21,9 @@ export interface IStateManager {
|
|
|
21
21
|
removeItemDatum(indexes: number[], count?: number): void;
|
|
22
22
|
updateData(key: string, value: any): void;
|
|
23
23
|
updateElement(element: Element, props: Partial<ElementProps>): void;
|
|
24
|
-
updateOptions(options:
|
|
24
|
+
updateOptions(options: UpdatableInfographicOptions, execOptions?: {
|
|
25
|
+
bubbleUp?: boolean;
|
|
26
|
+
}): void;
|
|
25
27
|
getOptions(): ParsedInfographicOptions;
|
|
26
28
|
destroy(): void;
|
|
27
29
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { InfographicOptionPath } from '../../options';
|
|
2
|
+
/**
|
|
3
|
+
* Sync callback
|
|
4
|
+
* @param newValue The new value after modification
|
|
5
|
+
* @param oldValue The old value before modification. Note: This value is undefined when triggered by parent path bubbling notification (i.e., listening to a non-leaf node).
|
|
6
|
+
*/
|
|
7
|
+
export type SyncHandler = (newValue: any, oldValue: any) => void;
|
|
8
|
+
export interface ISyncRegistry {
|
|
9
|
+
/**
|
|
10
|
+
* Register synchronization logic
|
|
11
|
+
* @param path Configuration path, such as 'design.background'
|
|
12
|
+
* @param handler Sync callback
|
|
13
|
+
* @param options.immediate Whether to execute immediately (used for view initialization)
|
|
14
|
+
* @returns unregister function
|
|
15
|
+
*/
|
|
16
|
+
register(path: InfographicOptionPath | (string & {}), handler: SyncHandler, options?: {
|
|
17
|
+
immediate?: boolean;
|
|
18
|
+
}): () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Trigger synchronization (usually called by StateManager)
|
|
21
|
+
* @param path Configuration path
|
|
22
|
+
* @param newVal New value
|
|
23
|
+
* @param oldVal Old value
|
|
24
|
+
*/
|
|
25
|
+
trigger(path: string, newVal: any, oldVal: any): void;
|
|
26
|
+
destroy(): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/esm/editor/utils/data.js
CHANGED
|
@@ -4,8 +4,10 @@ import { getDatumByIndexes } from '../../utils/index.js';
|
|
|
4
4
|
*/
|
|
5
5
|
export function getChildrenDataByIndexes(data, indexes) {
|
|
6
6
|
if (indexes.length === 0)
|
|
7
|
-
return data.
|
|
7
|
+
return data.items;
|
|
8
8
|
const datum = getDatumByIndexes(data, indexes);
|
|
9
|
+
if (datum == null)
|
|
10
|
+
return [];
|
|
9
11
|
datum.children || (datum.children = []);
|
|
10
12
|
return datum.children;
|
|
11
13
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { Element } from '../../types';
|
|
2
2
|
export declare function getEventTarget(element: SVGElement | null): Element | null;
|
|
3
3
|
export declare function getSelectableTarget(element: SVGElement | null): Element | null;
|
|
4
|
+
export declare function isTextSelectionTarget(target: EventTarget | null): boolean;
|
|
@@ -62,3 +62,11 @@ const getIconEventTarget = (element) => {
|
|
|
62
62
|
}
|
|
63
63
|
return null;
|
|
64
64
|
};
|
|
65
|
+
export function isTextSelectionTarget(target) {
|
|
66
|
+
if (!(target instanceof HTMLElement))
|
|
67
|
+
return false;
|
|
68
|
+
if (target.isContentEditable)
|
|
69
|
+
return true;
|
|
70
|
+
const tag = target.tagName.toLowerCase();
|
|
71
|
+
return tag === 'input' || tag === 'textarea';
|
|
72
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ApplyOptionUpdatesOptions {
|
|
2
|
+
/** Whether to notify parent paths of changes (bubbling) */
|
|
3
|
+
bubbleUp?: boolean;
|
|
4
|
+
/** Callback triggered whenever a property value changes */
|
|
5
|
+
collector?: (path: string, newVal: any, oldVal: any) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Recursively applies properties from 'source' to 'target' and collects changes.
|
|
9
|
+
*
|
|
10
|
+
* @param target - The object to be updated
|
|
11
|
+
* @param source - The source object containing partial updates
|
|
12
|
+
* @param basePath - Current path prefix for nested properties
|
|
13
|
+
* @param options - Configuration options
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyOptionUpdates(target: any, source: any, basePath?: string, options?: ApplyOptionUpdatesOptions): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { cloneDeep, isEqual, isPlainObject } from 'lodash-es';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively applies properties from 'source' to 'target' and collects changes.
|
|
4
|
+
*
|
|
5
|
+
* @param target - The object to be updated
|
|
6
|
+
* @param source - The source object containing partial updates
|
|
7
|
+
* @param basePath - Current path prefix for nested properties
|
|
8
|
+
* @param options - Configuration options
|
|
9
|
+
*/
|
|
10
|
+
export function applyOptionUpdates(target, source, basePath = '', options) {
|
|
11
|
+
const { bubbleUp = false, collector } = options !== null && options !== void 0 ? options : {};
|
|
12
|
+
const hasChange = applyOptionUpdatesInternal(target, source, basePath, collector, bubbleUp);
|
|
13
|
+
if (basePath === '' && hasChange && bubbleUp && collector) {
|
|
14
|
+
collector('', cloneDeep(target), undefined);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Internal recursive function.
|
|
19
|
+
* Returns true if any change occurred within this branch (or its children).
|
|
20
|
+
*/
|
|
21
|
+
function applyOptionUpdatesInternal(target, source, basePath, collector, bubbleUp) {
|
|
22
|
+
let hasChange = false;
|
|
23
|
+
Object.keys(source).forEach((key) => {
|
|
24
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const fullPath = basePath ? `${basePath}.${key}` : key;
|
|
28
|
+
const updateValue = source[key];
|
|
29
|
+
const oldValue = target[key];
|
|
30
|
+
let childChanged = false;
|
|
31
|
+
if (updateValue === undefined) {
|
|
32
|
+
// Handle deletion: Only delete and notify if the key actually exists
|
|
33
|
+
if (key in target) {
|
|
34
|
+
delete target[key];
|
|
35
|
+
collector === null || collector === void 0 ? void 0 : collector(fullPath, undefined, oldValue);
|
|
36
|
+
childChanged = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (isPlainObject(updateValue)) {
|
|
40
|
+
// Handle nested object
|
|
41
|
+
const oldValueIsObject = isPlainObject(target[key]);
|
|
42
|
+
if (!oldValueIsObject) {
|
|
43
|
+
target[key] = {};
|
|
44
|
+
}
|
|
45
|
+
const grandChildChanged = applyOptionUpdatesInternal(target[key], updateValue, fullPath, collector, bubbleUp);
|
|
46
|
+
if (!oldValueIsObject) {
|
|
47
|
+
// Overwriting a primitive with an object is always a change.
|
|
48
|
+
childChanged = true;
|
|
49
|
+
// If the object was empty (grandChildChanged is false), we still need to report it.
|
|
50
|
+
if (!grandChildChanged) {
|
|
51
|
+
collector === null || collector === void 0 ? void 0 : collector(fullPath, target[key], oldValue);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
childChanged = grandChildChanged;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Handle primitive update
|
|
60
|
+
target[key] = updateValue;
|
|
61
|
+
if (!isEqual(updateValue, oldValue)) {
|
|
62
|
+
collector === null || collector === void 0 ? void 0 : collector(fullPath, updateValue, oldValue);
|
|
63
|
+
childChanged = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (childChanged) {
|
|
67
|
+
hasChange = true;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// Bubbling: Notify if any child changed in this branch
|
|
71
|
+
// The recursion naturally ensures this happens in "deepest-first" (post-order) sequence.
|
|
72
|
+
if (hasChange && bubbleUp && basePath !== '') {
|
|
73
|
+
// Current target is now fully updated for this scope.
|
|
74
|
+
collector === null || collector === void 0 ? void 0 : collector(basePath, cloneDeep(target), undefined);
|
|
75
|
+
}
|
|
76
|
+
return hasChange;
|
|
77
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from './designs';
|
|
2
2
|
export { getItemProps, getThemeColors } from './designs/utils';
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
3
|
+
export { BatchCommand, UpdateElementCommand, UpdateOptionsCommand, UpdateTextCommand, } from './editor/commands';
|
|
4
|
+
export { BrushSelect, ClickSelect, DblClickEditText, DragCanvas, DragElement, HotkeyHistory, Interaction, SelectHighlight, ZoomWheel, } from './editor/interactions';
|
|
5
|
+
export { EditBar, Plugin, ResetViewBox, ResizeElement } from './editor/plugins';
|
|
5
6
|
export { exportToSVG } from './exporter';
|
|
6
7
|
export { Defs, Ellipse, Fragment, Group, Path, Polygon, Rect, Text, cloneElement, createFragment, createLayout, getCombinedBounds, getElementBounds, getElementsBounds, jsx, jsxDEV, jsxs, renderSVG, } from './jsx';
|
|
7
8
|
export { getFont, getFonts, getPalette, getPaletteColor, getPalettes, registerFont, registerPalette, registerPattern, setDefaultFont, } from './renderer';
|
|
@@ -12,7 +13,7 @@ export { getTemplate, getTemplates, registerTemplate } from './templates';
|
|
|
12
13
|
export { getTheme, getThemes, registerTheme } from './themes';
|
|
13
14
|
export { parseSVG, setFontExtendFactor } from './utils';
|
|
14
15
|
export { VERSION } from './version';
|
|
15
|
-
export type { EditBarOptions } from './editor';
|
|
16
|
+
export type { EditBarOptions, ICommand, ICommandManager, IEditor, IInteraction, IInteractionManager, IPlugin, IPluginManager, IStateManager, ISyncRegistry, InteractionInitOptions, KeyCode, PluginInitOptions, SelectMode, Selection, SyncHandler, } from './editor';
|
|
16
17
|
export type { ExportOptions, PNGExportOptions, SVGExportOptions, } from './exporter';
|
|
17
18
|
export type { Bounds, ComponentType, DefsProps, EllipseProps, FragmentProps, GroupProps, JSXElement, JSXElementConstructor, JSXNode, PathProps, Point, PolygonProps, RectProps, RenderableNode, SVGAttributes, SVGProps, TextProps, WithChildren, } from './jsx';
|
|
18
19
|
export type { InfographicOptions, ParsedInfographicOptions } from './options';
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from './designs/index.js';
|
|
2
2
|
export { getItemProps, getThemeColors } from './designs/utils/index.js';
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
3
|
+
export { BatchCommand, UpdateElementCommand, UpdateOptionsCommand, UpdateTextCommand, } from './editor/commands/index.js';
|
|
4
|
+
export { BrushSelect, ClickSelect, DblClickEditText, DragCanvas, DragElement, HotkeyHistory, Interaction, SelectHighlight, ZoomWheel, } from './editor/interactions/index.js';
|
|
5
|
+
export { EditBar, Plugin, ResetViewBox, ResizeElement } from './editor/plugins/index.js';
|
|
5
6
|
export { exportToSVG } from './exporter/index.js';
|
|
6
7
|
export { Defs, Ellipse, Fragment, Group, Path, Polygon, Rect, Text, cloneElement, createFragment, createLayout, getCombinedBounds, getElementBounds, getElementsBounds, jsx, jsxDEV, jsxs, renderSVG, } from './jsx/index.js';
|
|
7
8
|
export { getFont, getFonts, getPalette, getPaletteColor, getPalettes, registerFont, registerPalette, registerPattern, setDefaultFont, } from './renderer/index.js';
|
package/esm/options/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { DesignOptions, ParsedDesignsOptions } from '../designs';
|
|
|
2
2
|
import type { ElementProps, IInteraction, IPlugin } from '../editor';
|
|
3
3
|
import type { ThemeConfig } from '../themes';
|
|
4
4
|
import type { Data, Padding, ParsedData } from '../types';
|
|
5
|
+
import type { Path } from '../utils';
|
|
5
6
|
export interface InfographicOptions {
|
|
6
7
|
/** 容器,可以是选择器或者 HTMLElement */
|
|
7
8
|
container?: string | HTMLElement;
|
|
@@ -49,6 +50,7 @@ export interface ParsedInfographicOptions {
|
|
|
49
50
|
interactions?: IInteraction[];
|
|
50
51
|
shapes?: ElementProps[];
|
|
51
52
|
}
|
|
53
|
+
export type UpdatableInfographicOptions = Partial<Omit<ParsedInfographicOptions, 'container'>>;
|
|
52
54
|
interface SVGOptions {
|
|
53
55
|
style?: Record<string, string | number>;
|
|
54
56
|
attributes?: Record<string, string | number | boolean>;
|
|
@@ -57,4 +59,9 @@ interface SVGOptions {
|
|
|
57
59
|
/** 是否启用背景 */
|
|
58
60
|
background?: boolean;
|
|
59
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* All valid property paths for Infographic Options.
|
|
64
|
+
* Use this to validate paths in SyncRegistry and other places.
|
|
65
|
+
*/
|
|
66
|
+
export type InfographicOptionPath = Path<UpdatableInfographicOptions>;
|
|
60
67
|
export {};
|
|
@@ -13,7 +13,7 @@ import { Editor } from '../editor/index.js';
|
|
|
13
13
|
import { exportToPNGString, exportToSVGString, } from '../exporter/index.js';
|
|
14
14
|
import { renderSVG } from '../jsx/index.js';
|
|
15
15
|
import { parseOptions, } from '../options/index.js';
|
|
16
|
-
import { Renderer } from '../renderer/index.js';
|
|
16
|
+
import { DEFAULT_FONT, Renderer, setDefaultFont } from '../renderer/index.js';
|
|
17
17
|
import { waitForSvgLoads } from '../resource/index.js';
|
|
18
18
|
import { parseSyntax } from '../syntax/index.js';
|
|
19
19
|
import { getTypes, parseSVG } from '../utils/index.js';
|
|
@@ -99,18 +99,31 @@ export class Infographic {
|
|
|
99
99
|
* Compose the SVG template
|
|
100
100
|
*/
|
|
101
101
|
compose(parsedOptions) {
|
|
102
|
-
|
|
102
|
+
var _a, _b;
|
|
103
|
+
const { design, data, themeConfig } = parsedOptions;
|
|
103
104
|
const { title, item, items, structure } = design;
|
|
104
105
|
const { component: Structure, props: structureProps } = structure;
|
|
105
106
|
const Title = title.component;
|
|
106
107
|
const Item = item.component;
|
|
107
108
|
const Items = items.map((it) => it.component);
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
// Apply theme font-family before measurement so measureText uses the correct font
|
|
110
|
+
const themeFontFamily = (_b = (_a = themeConfig === null || themeConfig === void 0 ? void 0 : themeConfig.base) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b['font-family'];
|
|
111
|
+
const previousDefaultFont = DEFAULT_FONT;
|
|
112
|
+
if (themeFontFamily)
|
|
113
|
+
setDefaultFont(themeFontFamily);
|
|
114
|
+
try {
|
|
115
|
+
const svg = renderSVG(_jsx(Structure, Object.assign({ data: data, Title: Title, Item: Item, Items: Items, options: parsedOptions }, structureProps)));
|
|
116
|
+
const template = parseSVG(svg);
|
|
117
|
+
if (!template) {
|
|
118
|
+
throw new Error('Failed to parse SVG template');
|
|
119
|
+
}
|
|
120
|
+
return template;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
// Restore previous default font
|
|
124
|
+
if (themeFontFamily)
|
|
125
|
+
setDefaultFont(previousDefaultFont);
|
|
112
126
|
}
|
|
113
|
-
return template;
|
|
114
127
|
}
|
|
115
128
|
getTypes() {
|
|
116
129
|
const parsedOptions = this.parsedOptions;
|
package/esm/runtime/options.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { BrushSelect, ClickSelect, DblClickEditText, DragElement, EditBar, HotkeyHistory, ResizeElement, SelectHighlight, ZoomWheel, } from '../editor/index.js';
|
|
2
|
-
const createDefaultPlugins = () => [
|
|
1
|
+
import { BrushSelect, ClickSelect, DblClickEditText, DragCanvas, DragElement, EditBar, HotkeyHistory, ResetViewBox, ResizeElement, SelectHighlight, ZoomWheel, } from '../editor/index.js';
|
|
2
|
+
const createDefaultPlugins = () => [
|
|
3
|
+
new EditBar(),
|
|
4
|
+
new ResizeElement(),
|
|
5
|
+
new ResetViewBox(),
|
|
6
|
+
];
|
|
3
7
|
const createDefaultInteractions = () => [
|
|
8
|
+
new DragCanvas(),
|
|
4
9
|
new DblClickEditText(),
|
|
5
10
|
new BrushSelect(),
|
|
6
11
|
new ClickSelect(),
|
package/esm/syntax/index.js
CHANGED
|
@@ -111,27 +111,47 @@ export function parseSyntax(input) {
|
|
|
111
111
|
const parsed = parseRelationsNode(relationsNode, errors, 'data.relations');
|
|
112
112
|
if (parsed.relations.length > 0 || parsed.items.length > 0) {
|
|
113
113
|
const current = ((_a = options.data) !== null && _a !== void 0 ? _a : {});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
123
|
-
parsed.items.forEach((item) => {
|
|
124
|
-
const existing = itemMap.get(item.id);
|
|
125
|
-
if (existing) {
|
|
126
|
-
if (!existing.label && item.label)
|
|
127
|
-
existing.label = item.label;
|
|
114
|
+
// 优先使用已存在的数据列表 (sequences, lists, etc.)
|
|
115
|
+
const dataKeys = Object.keys(DataSchema.fields).filter((key) => key !== 'items' && key !== 'relations');
|
|
116
|
+
let hasStructuredData = false;
|
|
117
|
+
// 尝试找到一个非空的数据源
|
|
118
|
+
for (const key of dataKeys) {
|
|
119
|
+
if (Array.isArray(current[key]) && current[key].length > 0) {
|
|
120
|
+
hasStructuredData = true;
|
|
121
|
+
break;
|
|
128
122
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
}
|
|
124
|
+
// 如果 items 已包含层级结构数据(带 children),也视为结构化数据
|
|
125
|
+
if (!hasStructuredData &&
|
|
126
|
+
Array.isArray(current.items) &&
|
|
127
|
+
current.items.length > 0 &&
|
|
128
|
+
current.items.some((item) => Array.isArray(item.children) && item.children.length > 0)) {
|
|
129
|
+
hasStructuredData = true;
|
|
130
|
+
}
|
|
131
|
+
// 如果没有找到其他数据源,才尝试合并 items
|
|
132
|
+
if (!hasStructuredData) {
|
|
133
|
+
const existingItems = Array.isArray(current.items)
|
|
134
|
+
? current.items
|
|
135
|
+
: [];
|
|
136
|
+
const normalizedItems = normalizeItems(existingItems);
|
|
137
|
+
const itemMap = new Map();
|
|
138
|
+
normalizedItems.forEach((item) => {
|
|
139
|
+
if (item.id)
|
|
140
|
+
itemMap.set(item.id, item);
|
|
141
|
+
});
|
|
142
|
+
parsed.items.forEach((item) => {
|
|
143
|
+
const existing = itemMap.get(item.id);
|
|
144
|
+
if (existing) {
|
|
145
|
+
if (!existing.label && item.label)
|
|
146
|
+
existing.label = item.label;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
normalizedItems.push(item);
|
|
150
|
+
itemMap.set(item.id, item);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
current.items = normalizedItems;
|
|
154
|
+
}
|
|
135
155
|
current.relations = parsed.relations;
|
|
136
156
|
options.data = current;
|
|
137
157
|
}
|