@antv/infographic 0.2.17 → 0.2.19
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/infographic.min.js +110 -110
- package/dist/infographic.min.js.map +1 -1
- package/esm/constants/service.d.ts +1 -1
- package/esm/constants/service.js +1 -1
- package/esm/designs/structures/chart-line.js +5 -3
- package/esm/editor/interactions/dblclick-edit-text.js +3 -3
- package/esm/editor/managers/interaction.js +6 -4
- package/esm/editor/plugins/components/button.d.ts +2 -1
- package/esm/editor/plugins/components/button.js +4 -4
- package/esm/editor/plugins/components/color-picker.d.ts +1 -0
- package/esm/editor/plugins/components/color-picker.js +3 -3
- package/esm/editor/plugins/components/popover.d.ts +3 -1
- package/esm/editor/plugins/components/popover.js +29 -9
- package/esm/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
- package/esm/editor/plugins/edit-bar/edit-bar.js +17 -7
- package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
- package/esm/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
- package/esm/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
- package/esm/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
- package/esm/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
- package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
- package/esm/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
- package/esm/editor/plugins/reset-viewbox.d.ts +4 -1
- package/esm/editor/plugins/reset-viewbox.js +12 -6
- package/esm/editor/utils/index.d.ts +1 -0
- package/esm/editor/utils/index.js +1 -0
- package/esm/editor/utils/root.d.ts +3 -0
- package/esm/editor/utils/root.js +18 -0
- package/esm/exporter/svg.js +192 -52
- package/esm/resource/loaders/search.js +0 -3
- package/esm/templates/utils.js +11 -6
- package/esm/utils/padding.js +1 -1
- package/esm/utils/style.d.ts +3 -1
- package/esm/utils/style.js +27 -4
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/lib/constants/service.d.ts +1 -1
- package/lib/constants/service.js +1 -1
- package/lib/designs/structures/chart-line.js +5 -3
- package/lib/editor/interactions/dblclick-edit-text.js +3 -3
- package/lib/editor/managers/interaction.js +7 -5
- package/lib/editor/plugins/components/button.d.ts +2 -1
- package/lib/editor/plugins/components/button.js +4 -4
- package/lib/editor/plugins/components/color-picker.d.ts +1 -0
- package/lib/editor/plugins/components/color-picker.js +3 -3
- package/lib/editor/plugins/components/popover.d.ts +3 -1
- package/lib/editor/plugins/components/popover.js +32 -12
- package/lib/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
- package/lib/editor/plugins/edit-bar/edit-bar.js +17 -7
- package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
- package/lib/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
- package/lib/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
- package/lib/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
- package/lib/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
- package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
- package/lib/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
- package/lib/editor/plugins/reset-viewbox.d.ts +4 -1
- package/lib/editor/plugins/reset-viewbox.js +12 -6
- package/lib/editor/utils/index.d.ts +1 -0
- package/lib/editor/utils/index.js +1 -0
- package/lib/editor/utils/root.d.ts +3 -0
- package/lib/editor/utils/root.js +22 -0
- package/lib/exporter/svg.js +192 -52
- package/lib/resource/loaders/search.js +0 -3
- package/lib/templates/utils.js +11 -6
- package/lib/utils/padding.js +1 -1
- package/lib/utils/style.d.ts +3 -1
- package/lib/utils/style.js +27 -4
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/constants/service.ts +1 -1
- package/src/designs/structures/chart-line.tsx +5 -3
- package/src/editor/interactions/dblclick-edit-text.ts +3 -2
- package/src/editor/managers/interaction.ts +9 -7
- package/src/editor/plugins/components/button.ts +5 -2
- package/src/editor/plugins/components/color-picker.ts +4 -2
- package/src/editor/plugins/components/popover.ts +31 -12
- package/src/editor/plugins/edit-bar/edit-bar.ts +26 -11
- package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/font-align.ts +8 -3
- package/src/editor/plugins/edit-bar/edit-items/font-color.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/font-family.ts +11 -7
- package/src/editor/plugins/edit-bar/edit-items/font-size.ts +8 -3
- package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/types.ts +6 -1
- package/src/editor/plugins/reset-viewbox.ts +17 -8
- package/src/editor/utils/index.ts +1 -0
- package/src/editor/utils/root.ts +26 -0
- package/src/exporter/svg.ts +267 -62
- package/src/resource/loaders/search.ts +0 -3
- package/src/templates/utils.ts +30 -6
- package/src/utils/padding.ts +1 -1
- package/src/utils/style.ts +31 -4
- package/src/version.ts +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { COMPONENT_ROLE } from '../../constants/index.js';
|
|
2
2
|
import { getBoundViewBox, getViewBox, injectStyleOnce, parsePadding, setElementRole, viewBoxToString, } from '../../utils/index.js';
|
|
3
3
|
import { UpdateOptionsCommand } from '../commands/index.js';
|
|
4
|
+
import { getOverlayContainer } from '../utils/index.js';
|
|
4
5
|
import { Plugin } from './base.js';
|
|
5
6
|
import { IconButton } from './components/index.js';
|
|
6
7
|
import { RESET_ICON } from './components/icons.js';
|
|
@@ -33,9 +34,12 @@ export class ResetViewBox extends Plugin {
|
|
|
33
34
|
if (this.resetButton)
|
|
34
35
|
return this.resetButton;
|
|
35
36
|
const { style, className } = this.options || {};
|
|
37
|
+
const containerParent = this.resolveOverlayRoot();
|
|
38
|
+
this.ensureButtonStyle(containerParent);
|
|
36
39
|
const button = IconButton({
|
|
37
40
|
icon: RESET_ICON,
|
|
38
41
|
onClick: this.resetViewBox,
|
|
42
|
+
root: containerParent,
|
|
39
43
|
});
|
|
40
44
|
button.classList.add(RESET_BUTTON_CLASS);
|
|
41
45
|
if (className) {
|
|
@@ -46,9 +50,6 @@ export class ResetViewBox extends Plugin {
|
|
|
46
50
|
}
|
|
47
51
|
setElementRole(button, COMPONENT_ROLE);
|
|
48
52
|
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
53
|
containerParent === null || containerParent === void 0 ? void 0 : containerParent.appendChild(button);
|
|
53
54
|
return button;
|
|
54
55
|
};
|
|
@@ -139,7 +140,7 @@ export class ResetViewBox extends Plugin {
|
|
|
139
140
|
init(options) {
|
|
140
141
|
super.init(options);
|
|
141
142
|
// Initialize originViewBox
|
|
142
|
-
this.ensureButtonStyle();
|
|
143
|
+
this.ensureButtonStyle(this.resolveOverlayRoot());
|
|
143
144
|
this.updateOriginViewBox();
|
|
144
145
|
this.unregisterSync = this.editor.registerSync('viewBox', this.handleViewBoxChange);
|
|
145
146
|
window.addEventListener('resize', this.handleResize);
|
|
@@ -161,7 +162,12 @@ export class ResetViewBox extends Plugin {
|
|
|
161
162
|
const { padding } = this.state.getOptions();
|
|
162
163
|
this.originViewBox = getBoundViewBox(svg, parsePadding(padding));
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
+
resolveOverlayRoot() {
|
|
166
|
+
const { getContainer } = this.options || {};
|
|
167
|
+
const resolvedContainer = typeof getContainer === 'function' ? getContainer() : getContainer;
|
|
168
|
+
return resolvedContainer !== null && resolvedContainer !== void 0 ? resolvedContainer : getOverlayContainer(this.editor.getDocument());
|
|
169
|
+
}
|
|
170
|
+
ensureButtonStyle(target) {
|
|
165
171
|
injectStyleOnce(RESET_BUTTON_STYLE_ID, `
|
|
166
172
|
button.${RESET_BUTTON_CLASS} {
|
|
167
173
|
visibility: hidden;
|
|
@@ -179,7 +185,7 @@ export class ResetViewBox extends Plugin {
|
|
|
179
185
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
180
186
|
cursor: pointer;
|
|
181
187
|
}
|
|
182
|
-
|
|
188
|
+
`, target);
|
|
183
189
|
}
|
|
184
190
|
}
|
|
185
191
|
const RESET_BUTTON_CLASS = 'infographic-reset-viewbox-btn';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function getConnectedRoot(node) {
|
|
2
|
+
if (!(node === null || node === void 0 ? void 0 : node.isConnected))
|
|
3
|
+
return document;
|
|
4
|
+
const root = node.getRootNode();
|
|
5
|
+
return root instanceof ShadowRoot ? root : document;
|
|
6
|
+
}
|
|
7
|
+
export function getOverlayContainer(node) {
|
|
8
|
+
const root = getConnectedRoot(node);
|
|
9
|
+
return root instanceof ShadowRoot ? root : document.body;
|
|
10
|
+
}
|
|
11
|
+
export function eventPathContains(event, node) {
|
|
12
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
13
|
+
if (path.length > 0) {
|
|
14
|
+
return path.some((current) => current === node || (current instanceof Node && node.contains(current)));
|
|
15
|
+
}
|
|
16
|
+
const target = event.target;
|
|
17
|
+
return target instanceof Node && (target === node || node.contains(target));
|
|
18
|
+
}
|
package/esm/exporter/svg.js
CHANGED
|
@@ -22,7 +22,10 @@ function getExportViewBox(svg) {
|
|
|
22
22
|
return getViewBox(svg);
|
|
23
23
|
const width = parseAbsoluteLength(svg.getAttribute('width'));
|
|
24
24
|
const height = parseAbsoluteLength(svg.getAttribute('height'));
|
|
25
|
-
if (width
|
|
25
|
+
if (!Number.isNaN(width) &&
|
|
26
|
+
width > 0 &&
|
|
27
|
+
!Number.isNaN(height) &&
|
|
28
|
+
height > 0) {
|
|
26
29
|
return { x: 0, y: 0, width, height };
|
|
27
30
|
}
|
|
28
31
|
const rect = svg.getBoundingClientRect();
|
|
@@ -41,38 +44,69 @@ function parseAbsoluteLength(value) {
|
|
|
41
44
|
return Number.NaN;
|
|
42
45
|
return Number.parseFloat(trimmed);
|
|
43
46
|
}
|
|
44
|
-
function
|
|
47
|
+
function parseCoordinate(value) {
|
|
48
|
+
const parsed = parseAbsoluteLength(value);
|
|
49
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
50
|
+
}
|
|
51
|
+
function measureSpanContentDimensions(span, measureWidth) {
|
|
45
52
|
const prevHeight = span.style.height;
|
|
53
|
+
const prevWidth = span.style.width;
|
|
46
54
|
const prevOverflow = span.style.overflow;
|
|
47
55
|
try {
|
|
48
56
|
span.style.height = 'max-content';
|
|
49
57
|
span.style.overflow = 'hidden';
|
|
50
58
|
void span.offsetHeight; // force reflow
|
|
51
|
-
|
|
59
|
+
const scrollHeight = span.scrollHeight;
|
|
60
|
+
const rectHeight = span.getBoundingClientRect().height;
|
|
61
|
+
let width = span.scrollWidth;
|
|
62
|
+
if (measureWidth) {
|
|
63
|
+
span.style.width = 'max-content';
|
|
64
|
+
void span.offsetWidth; // force reflow
|
|
65
|
+
width = span.scrollWidth;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
height: Math.max(scrollHeight, rectHeight),
|
|
69
|
+
width,
|
|
70
|
+
};
|
|
52
71
|
}
|
|
53
72
|
finally {
|
|
54
73
|
span.style.height = prevHeight;
|
|
55
|
-
span.style.overflow = prevOverflow;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function measureSpanContentWidth(span) {
|
|
59
|
-
const prevWidth = span.style.width;
|
|
60
|
-
const prevOverflow = span.style.overflow;
|
|
61
|
-
try {
|
|
62
|
-
span.style.width = 'max-content';
|
|
63
|
-
span.style.overflow = 'hidden';
|
|
64
|
-
void span.offsetWidth; // force reflow
|
|
65
|
-
return span.scrollWidth;
|
|
66
|
-
}
|
|
67
|
-
finally {
|
|
68
74
|
span.style.width = prevWidth;
|
|
69
75
|
span.style.overflow = prevOverflow;
|
|
70
76
|
}
|
|
71
77
|
}
|
|
72
|
-
|
|
78
|
+
function shouldKeepForeignObjectWidth(style) {
|
|
79
|
+
const whiteSpace = style.whiteSpace;
|
|
80
|
+
const flexWrap = style.flexWrap;
|
|
81
|
+
const wordBreak = style.wordBreak;
|
|
82
|
+
const overflowWrap = style.overflowWrap;
|
|
83
|
+
return (flexWrap === 'wrap' ||
|
|
84
|
+
flexWrap === 'wrap-reverse' ||
|
|
85
|
+
whiteSpace === 'pre-wrap' ||
|
|
86
|
+
whiteSpace === 'pre-line' ||
|
|
87
|
+
whiteSpace === 'normal' ||
|
|
88
|
+
overflowWrap === 'break-word' ||
|
|
89
|
+
wordBreak === 'break-word' ||
|
|
90
|
+
wordBreak === 'break-all');
|
|
91
|
+
}
|
|
92
|
+
function createCoordConverter(svg, element) {
|
|
93
|
+
if (typeof element.getScreenCTM !== 'function')
|
|
94
|
+
return null;
|
|
95
|
+
const screenCTM = element.getScreenCTM();
|
|
96
|
+
if (!screenCTM)
|
|
97
|
+
return null;
|
|
98
|
+
const inverseCTM = screenCTM.inverse();
|
|
99
|
+
return (clientX, clientY) => {
|
|
100
|
+
const pt = svg.createSVGPoint();
|
|
101
|
+
pt.x = clientX;
|
|
102
|
+
pt.y = clientY;
|
|
103
|
+
return pt.matrixTransform(inverseCTM);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Returns [left, top, right, bottom] in target coordinates for a foreignObject,
|
|
73
107
|
// accounting for flex alignment: bottom/center-aligned content can overflow,
|
|
74
108
|
// and horizontally aligned content can overflow as well.
|
|
75
|
-
function getFOContentBoundsInSVG(fo,
|
|
109
|
+
function getFOContentBoundsInSVG(fo, toSVGCoord, { contentHeight, contentWidth, keepForeignObjectWidth, }) {
|
|
76
110
|
const foRect = fo.getBoundingClientRect();
|
|
77
111
|
const foTopLeft = toSVGCoord(foRect.left, foRect.top);
|
|
78
112
|
const foBottomRight = toSVGCoord(foRect.right, foRect.bottom);
|
|
@@ -84,16 +118,15 @@ function getFOContentBoundsInSVG(fo, content, toSVGCoord) {
|
|
|
84
118
|
const foHeightSVG = foBottomSVG - foTopSVG;
|
|
85
119
|
const svgUnitsPerClientPxY = foRect.height > 0 ? foHeightSVG / foRect.height : 1;
|
|
86
120
|
const svgUnitsPerClientPxX = foRect.width > 0 ? foWidthSVG / foRect.width : 1;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const contentHeightSVG = realScrollHeight > 0
|
|
90
|
-
? realScrollHeight * svgUnitsPerClientPxY
|
|
121
|
+
const contentHeightSVG = contentHeight > 0
|
|
122
|
+
? contentHeight * svgUnitsPerClientPxY
|
|
91
123
|
: foHeightSVG;
|
|
92
|
-
const
|
|
93
|
-
const contentWidthSVG = realScrollWidth > 0 ? realScrollWidth * svgUnitsPerClientPxX : foWidthSVG;
|
|
94
|
-
const computedStyle = window.getComputedStyle(content);
|
|
124
|
+
const computedStyle = window.getComputedStyle(fo.firstElementChild);
|
|
95
125
|
const alignItems = computedStyle.alignItems;
|
|
96
126
|
const justifyContent = computedStyle.justifyContent;
|
|
127
|
+
const contentWidthSVG = keepForeignObjectWidth
|
|
128
|
+
? foWidthSVG
|
|
129
|
+
: Math.max(foWidthSVG, contentWidth * svgUnitsPerClientPxX);
|
|
97
130
|
// Calculate vertical bounds
|
|
98
131
|
let top, bottom;
|
|
99
132
|
if (alignItems === 'flex-end' || alignItems === 'end') {
|
|
@@ -128,38 +161,75 @@ function getFOContentBoundsInSVG(fo, content, toSVGCoord) {
|
|
|
128
161
|
}
|
|
129
162
|
return [left, top, right, bottom];
|
|
130
163
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
164
|
+
function collectForeignObjectExportAdjustments(svg) {
|
|
165
|
+
const toSVGCoord = createCoordConverter(svg, svg);
|
|
166
|
+
if (!toSVGCoord)
|
|
167
|
+
return [];
|
|
168
|
+
return Array.from(svg.querySelectorAll('foreignObject')).map((fo) => {
|
|
169
|
+
const content = fo.firstElementChild;
|
|
170
|
+
if (!content)
|
|
171
|
+
return null;
|
|
172
|
+
const computedStyle = window.getComputedStyle(content);
|
|
173
|
+
const keepForeignObjectWidth = shouldKeepForeignObjectWidth(computedStyle);
|
|
174
|
+
const measuredContent = measureSpanContentDimensions(content, !keepForeignObjectWidth);
|
|
175
|
+
const parent = fo.parentElement instanceof SVGGraphicsElement ? fo.parentElement : svg;
|
|
176
|
+
const toParentCoord = createCoordConverter(svg, parent);
|
|
177
|
+
const toLocalCoord = createCoordConverter(svg, fo);
|
|
178
|
+
if (!toParentCoord)
|
|
179
|
+
return null;
|
|
180
|
+
const parentBounds = getFOContentBoundsInSVG(fo, toParentCoord, {
|
|
181
|
+
contentHeight: measuredContent.height,
|
|
182
|
+
contentWidth: measuredContent.width,
|
|
183
|
+
keepForeignObjectWidth,
|
|
184
|
+
});
|
|
185
|
+
const originalX = parseCoordinate(fo.getAttribute('x'));
|
|
186
|
+
const originalY = parseCoordinate(fo.getAttribute('y'));
|
|
187
|
+
const localBounds = toLocalCoord
|
|
188
|
+
? getFOContentBoundsInSVG(fo, toLocalCoord, {
|
|
189
|
+
contentHeight: measuredContent.height,
|
|
190
|
+
contentWidth: measuredContent.width,
|
|
191
|
+
keepForeignObjectWidth,
|
|
192
|
+
})
|
|
193
|
+
: null;
|
|
194
|
+
const hasTransform = fo.hasAttribute('transform');
|
|
195
|
+
if (hasTransform && !localBounds)
|
|
196
|
+
return null;
|
|
197
|
+
const exportBounds = localBounds
|
|
198
|
+
? {
|
|
199
|
+
x: originalX + localBounds[0],
|
|
200
|
+
y: originalY + localBounds[1],
|
|
201
|
+
width: localBounds[2] - localBounds[0],
|
|
202
|
+
height: localBounds[3] - localBounds[1],
|
|
203
|
+
}
|
|
204
|
+
: {
|
|
205
|
+
x: parentBounds[0],
|
|
206
|
+
y: parentBounds[1],
|
|
207
|
+
width: parentBounds[2] - parentBounds[0],
|
|
208
|
+
height: parentBounds[3] - parentBounds[1],
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
rootBounds: getFOContentBoundsInSVG(fo, toSVGCoord, {
|
|
212
|
+
contentHeight: measuredContent.height,
|
|
213
|
+
contentWidth: measuredContent.width,
|
|
214
|
+
keepForeignObjectWidth,
|
|
215
|
+
}),
|
|
216
|
+
exportBounds,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function computeFullViewBox(svg, adjustments) {
|
|
137
221
|
const viewBox = getExportViewBox(svg);
|
|
138
222
|
if (!viewBox)
|
|
139
223
|
return null;
|
|
140
|
-
if (typeof svg.getScreenCTM !== 'function')
|
|
141
|
-
return null;
|
|
142
|
-
const screenCTM = svg.getScreenCTM();
|
|
143
|
-
if (!screenCTM)
|
|
144
|
-
return null;
|
|
145
|
-
const inverseCTM = screenCTM.inverse();
|
|
146
|
-
const toSVGCoord = (clientX, clientY) => {
|
|
147
|
-
const pt = svg.createSVGPoint();
|
|
148
|
-
pt.x = clientX;
|
|
149
|
-
pt.y = clientY;
|
|
150
|
-
return pt.matrixTransform(inverseCTM);
|
|
151
|
-
};
|
|
152
224
|
let minX = viewBox.x;
|
|
153
225
|
let minY = viewBox.y;
|
|
154
226
|
let maxX = viewBox.x + viewBox.width;
|
|
155
227
|
let maxY = viewBox.y + viewBox.height;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
.forEach((fo) => {
|
|
159
|
-
const content = fo.firstElementChild;
|
|
160
|
-
if (!content)
|
|
228
|
+
adjustments.forEach((adjustment) => {
|
|
229
|
+
if (!adjustment)
|
|
161
230
|
return;
|
|
162
|
-
const
|
|
231
|
+
const { rootBounds } = adjustment;
|
|
232
|
+
const [left, top, right, bottom] = rootBounds;
|
|
163
233
|
minX = Math.min(minX, left);
|
|
164
234
|
minY = Math.min(minY, top);
|
|
165
235
|
maxX = Math.max(maxX, right);
|
|
@@ -176,12 +246,25 @@ function computeFullViewBox(svg) {
|
|
|
176
246
|
return null;
|
|
177
247
|
return `${newX} ${newY} ${newWidth} ${newHeight}`;
|
|
178
248
|
}
|
|
249
|
+
function applyForeignObjectExportAdjustments(svg, adjustments) {
|
|
250
|
+
const clonedForeignObjects = Array.from(svg.querySelectorAll('foreignObject'));
|
|
251
|
+
adjustments.forEach((adjustment, index) => {
|
|
252
|
+
if (!adjustment)
|
|
253
|
+
return;
|
|
254
|
+
const clonedForeignObject = clonedForeignObjects[index];
|
|
255
|
+
if (!clonedForeignObject)
|
|
256
|
+
return;
|
|
257
|
+
setAttributes(clonedForeignObject, adjustment.exportBounds);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
179
260
|
export function exportToSVG(svg_1) {
|
|
180
261
|
return __awaiter(this, arguments, void 0, function* (svg, options = {}) {
|
|
181
262
|
const { removeBackground = false, embedResources = true, removeIds = false, } = options;
|
|
182
263
|
const clonedSVG = svg.cloneNode(true);
|
|
183
264
|
if (typeof document !== 'undefined') {
|
|
184
|
-
const
|
|
265
|
+
const adjustments = collectForeignObjectExportAdjustments(svg);
|
|
266
|
+
applyForeignObjectExportAdjustments(clonedSVG, adjustments);
|
|
267
|
+
const fullViewBox = computeFullViewBox(svg, adjustments);
|
|
185
268
|
if (fullViewBox) {
|
|
186
269
|
clonedSVG.setAttribute('viewBox', fullViewBox);
|
|
187
270
|
}
|
|
@@ -214,8 +297,9 @@ function embedIcons(svg) {
|
|
|
214
297
|
const existsSymbol = svg.querySelector(href);
|
|
215
298
|
if (!existsSymbol) {
|
|
216
299
|
const symbolElement = document.querySelector(href);
|
|
217
|
-
if (symbolElement)
|
|
300
|
+
if (symbolElement) {
|
|
218
301
|
defs.appendChild(symbolElement.cloneNode(true));
|
|
302
|
+
}
|
|
219
303
|
}
|
|
220
304
|
});
|
|
221
305
|
});
|
|
@@ -423,6 +507,8 @@ function collectDefElements(svg, ids) {
|
|
|
423
507
|
};
|
|
424
508
|
while (queue.length) {
|
|
425
509
|
const id = queue.shift();
|
|
510
|
+
if (!id)
|
|
511
|
+
continue;
|
|
426
512
|
if (visited.has(id))
|
|
427
513
|
continue;
|
|
428
514
|
visited.add(id);
|
|
@@ -437,11 +523,65 @@ function collectDefElements(svg, ids) {
|
|
|
437
523
|
}
|
|
438
524
|
return collected;
|
|
439
525
|
}
|
|
526
|
+
// Fallback implementation based on the CSS.escape algorithm
|
|
527
|
+
function cssEscape(value) {
|
|
528
|
+
const string = String(value);
|
|
529
|
+
const length = string.length;
|
|
530
|
+
let result = '';
|
|
531
|
+
if (length === 0) {
|
|
532
|
+
return '';
|
|
533
|
+
}
|
|
534
|
+
for (let i = 0; i < length; i++) {
|
|
535
|
+
const codeUnit = string.charCodeAt(i);
|
|
536
|
+
// Null character
|
|
537
|
+
if (codeUnit === 0x0000) {
|
|
538
|
+
result += '\uFFFD';
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
// Control characters or DEL
|
|
542
|
+
if ((codeUnit >= 0x0001 && codeUnit <= 0x001f) || codeUnit === 0x007f) {
|
|
543
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
// Escape if first character is a digit
|
|
547
|
+
if (i === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) {
|
|
548
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
// Escape if second character is a digit and first is a hyphen
|
|
552
|
+
if (i === 1 &&
|
|
553
|
+
codeUnit >= 0x0030 &&
|
|
554
|
+
codeUnit <= 0x0039 &&
|
|
555
|
+
string.charCodeAt(0) === 0x002d) {
|
|
556
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
// If the character is the first and is a hyphen followed by end of string, escape it
|
|
560
|
+
if (i === 0 && length === 1 && codeUnit === 0x002d) {
|
|
561
|
+
result += '\\' + string.charAt(i);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
// Characters that are safe to use unescaped
|
|
565
|
+
if (codeUnit >= 0x0080 ||
|
|
566
|
+
(codeUnit >= 0x0030 && codeUnit <= 0x0039) || // 0-9
|
|
567
|
+
(codeUnit >= 0x0041 && codeUnit <= 0x005a) || // A-Z
|
|
568
|
+
(codeUnit >= 0x0061 && codeUnit <= 0x007a) || // a-z
|
|
569
|
+
codeUnit === 0x002d || // -
|
|
570
|
+
codeUnit === 0x005f // _
|
|
571
|
+
) {
|
|
572
|
+
result += string.charAt(i);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
// All other characters
|
|
576
|
+
result += '\\' + string.charAt(i);
|
|
577
|
+
}
|
|
578
|
+
return result;
|
|
579
|
+
}
|
|
440
580
|
function escapeCssId(id) {
|
|
441
581
|
if (globalThis.CSS && typeof globalThis.CSS.escape === 'function') {
|
|
442
582
|
return globalThis.CSS.escape(id);
|
|
443
583
|
}
|
|
444
|
-
return id
|
|
584
|
+
return cssEscape(id);
|
|
445
585
|
}
|
|
446
586
|
function removeDefs(svg) {
|
|
447
587
|
const defsList = Array.from(svg.querySelectorAll('defs'));
|
|
@@ -54,9 +54,6 @@ export function loadSearchResource(query, format) {
|
|
|
54
54
|
const svgText = commaIndex >= 0 ? result.slice(commaIndex + 1) : result;
|
|
55
55
|
return loadSVGResource(svgText);
|
|
56
56
|
}
|
|
57
|
-
if (mimeType === 'image/svg+xml' && format === 'svg' && isBase64) {
|
|
58
|
-
return loadImageBase64Resource(result);
|
|
59
|
-
}
|
|
60
57
|
return loadImageBase64Resource(result);
|
|
61
58
|
}
|
|
62
59
|
return loadRemoteResource(result, format);
|
package/esm/templates/utils.js
CHANGED
|
@@ -30,11 +30,20 @@ function getLevenshteinDistance(source, target) {
|
|
|
30
30
|
function getCommonPrefixLength(source, target) {
|
|
31
31
|
const limit = Math.min(source.length, target.length);
|
|
32
32
|
let index = 0;
|
|
33
|
-
while (index < limit &&
|
|
33
|
+
while (index < limit &&
|
|
34
|
+
source.charCodeAt(index) === target.charCodeAt(index)) {
|
|
34
35
|
index += 1;
|
|
35
36
|
}
|
|
36
37
|
return index;
|
|
37
38
|
}
|
|
39
|
+
function isBetterMatch(bestMatch, bestDistance, bestPrefixLength, candidateKey, candidateDistance, candidatePrefixLength) {
|
|
40
|
+
return (candidateDistance < bestDistance ||
|
|
41
|
+
(candidateDistance === bestDistance &&
|
|
42
|
+
candidatePrefixLength > bestPrefixLength) ||
|
|
43
|
+
(candidateDistance === bestDistance &&
|
|
44
|
+
candidatePrefixLength === bestPrefixLength &&
|
|
45
|
+
(!bestMatch || candidateKey < bestMatch)));
|
|
46
|
+
}
|
|
38
47
|
export function findClosestTemplateKey(type, keys) {
|
|
39
48
|
const normalizedType = normalizeTemplateKey(type);
|
|
40
49
|
if (!normalizedType)
|
|
@@ -49,11 +58,7 @@ export function findClosestTemplateKey(type, keys) {
|
|
|
49
58
|
}
|
|
50
59
|
const distance = getLevenshteinDistance(normalizedType, normalizedKey);
|
|
51
60
|
const prefixLength = getCommonPrefixLength(normalizedType, normalizedKey);
|
|
52
|
-
if (distance
|
|
53
|
-
(distance === bestDistance && prefixLength > bestPrefixLength) ||
|
|
54
|
-
(distance === bestDistance &&
|
|
55
|
-
prefixLength === bestPrefixLength &&
|
|
56
|
-
(!bestMatch || key < bestMatch))) {
|
|
61
|
+
if (isBetterMatch(bestMatch, bestDistance, bestPrefixLength, key, distance, prefixLength)) {
|
|
57
62
|
bestMatch = key;
|
|
58
63
|
bestDistance = distance;
|
|
59
64
|
bestPrefixLength = prefixLength;
|
package/esm/utils/padding.js
CHANGED
package/esm/utils/style.d.ts
CHANGED
package/esm/utils/style.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
if (
|
|
1
|
+
function resolveStyleRoot(target) {
|
|
2
|
+
if (!target)
|
|
3
|
+
return document;
|
|
4
|
+
if (target instanceof Document || target instanceof ShadowRoot)
|
|
5
|
+
return target;
|
|
6
|
+
if (!target.isConnected)
|
|
7
|
+
return document;
|
|
8
|
+
const root = target.getRootNode();
|
|
9
|
+
return root instanceof ShadowRoot ? root : document;
|
|
10
|
+
}
|
|
11
|
+
function hasStyle(root, id) {
|
|
12
|
+
if (root instanceof Document)
|
|
13
|
+
return Boolean(root.getElementById(id));
|
|
14
|
+
return Boolean(root.querySelector(`#${id}`));
|
|
15
|
+
}
|
|
16
|
+
export function injectStyleOnce(id, styles, target) {
|
|
17
|
+
var _a;
|
|
18
|
+
const root = resolveStyleRoot(target);
|
|
19
|
+
if (hasStyle(root, id))
|
|
3
20
|
return;
|
|
4
|
-
const
|
|
21
|
+
const doc = root instanceof Document ? root : ((_a = root.ownerDocument) !== null && _a !== void 0 ? _a : document);
|
|
22
|
+
const style = doc.createElement('style');
|
|
5
23
|
style.id = id;
|
|
6
24
|
style.textContent = styles;
|
|
7
|
-
|
|
25
|
+
if (root instanceof Document) {
|
|
26
|
+
root.head.appendChild(style);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
root.appendChild(style);
|
|
30
|
+
}
|
|
8
31
|
}
|
package/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.
|
|
1
|
+
export declare const VERSION = "0.2.19";
|
package/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.
|
|
1
|
+
export const VERSION = '0.2.19';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ICON_SERVICE_URL = "https://
|
|
1
|
+
export declare const ICON_SERVICE_URL = "https://www.weavefox.cn/api/v1/infographic/icon";
|
package/lib/constants/service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ICON_SERVICE_URL = void 0;
|
|
4
|
-
exports.ICON_SERVICE_URL = 'https://
|
|
4
|
+
exports.ICON_SERVICE_URL = 'https://www.weavefox.cn/api/v1/infographic/icon';
|
|
@@ -9,6 +9,8 @@ const components_1 = require("../components");
|
|
|
9
9
|
const layouts_1 = require("../layouts");
|
|
10
10
|
const utils_2 = require("../utils");
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
|
+
const ITEM_POSITION_H = 'center';
|
|
13
|
+
const ITEM_POSITION_V = 'normal';
|
|
12
14
|
const ChartLine = (props) => {
|
|
13
15
|
const { Title, Item, data, width, height = 260, gap = 10, padding = 24, showValue = true, options, valueFormatter = (value) => value.toString(), } = props;
|
|
14
16
|
const { title, desc, items = [], xTitle, yTitle } = data;
|
|
@@ -21,8 +23,8 @@ const ChartLine = (props) => {
|
|
|
21
23
|
indexes: [0],
|
|
22
24
|
datum: items[0],
|
|
23
25
|
data,
|
|
24
|
-
positionH:
|
|
25
|
-
positionV:
|
|
26
|
+
positionH: ITEM_POSITION_H,
|
|
27
|
+
positionV: ITEM_POSITION_V,
|
|
26
28
|
};
|
|
27
29
|
const sampleBounds = (0, jsx_1.getElementBounds)((0, jsx_runtime_1.jsx)(Item, Object.assign({}, itemProps)));
|
|
28
30
|
const labelWidth = sampleBounds.width;
|
|
@@ -162,7 +164,7 @@ const ChartLine = (props) => {
|
|
|
162
164
|
if (yTitle) {
|
|
163
165
|
titleElements.push((0, jsx_runtime_1.jsx)(jsx_1.Text, { x: paddingLeft + yTitleSpace / 2, y: chartOriginY + height / 2, alignHorizontal: "center", alignVertical: "middle", fontSize: 14, fontWeight: "bold", fill: axisColor, children: yTitle }));
|
|
164
166
|
}
|
|
165
|
-
return ((0, jsx_runtime_1.jsxs)(layouts_1.FlexLayout, { id: "infographic-container", flexDirection: "column", justifyContent: "center", alignItems: "center", children: [titleContent, (0, jsx_runtime_1.jsxs)(jsx_1.Group, { width: totalWidth, height: totalHeight, children: [(0, jsx_runtime_1.jsxs)(jsx_1.Defs, { children: [(0, jsx_runtime_1.jsx)("linearGradient", { id: gradientStrokeId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: gradientStops }), (0, jsx_runtime_1.
|
|
167
|
+
return ((0, jsx_runtime_1.jsxs)(layouts_1.FlexLayout, { id: "infographic-container", flexDirection: "column", justifyContent: "center", alignItems: "center", children: [titleContent, (0, jsx_runtime_1.jsxs)(jsx_1.Group, { width: totalWidth, height: totalHeight, children: [(0, jsx_runtime_1.jsxs)(jsx_1.Defs, { children: [(0, jsx_runtime_1.jsx)("linearGradient", { id: gradientStrokeId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: gradientStops }), (0, jsx_runtime_1.jsx)("linearGradient", { id: gradientAreaId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: areaStops })] }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: gridElements }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: [...axisElements, ...tickElements] }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: lineElements }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: pointElements }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: valueElements }), (0, jsx_runtime_1.jsx)(jsx_1.Group, { children: titleElements }), (0, jsx_runtime_1.jsx)(components_1.ItemsGroup, { children: xLabels })] })] }));
|
|
166
168
|
};
|
|
167
169
|
exports.ChartLine = ChartLine;
|
|
168
170
|
(0, registry_1.registerStructure)('chart-line', {
|
|
@@ -76,7 +76,7 @@ function editText(text, options) {
|
|
|
76
76
|
const entity = (0, utils_1.getTextEntity)(text);
|
|
77
77
|
if (!entity)
|
|
78
78
|
return;
|
|
79
|
-
ensureEditorStyles();
|
|
79
|
+
ensureEditorStyles(entity);
|
|
80
80
|
new InlineTextEditor(entity, options).start();
|
|
81
81
|
}
|
|
82
82
|
class InlineTextEditor {
|
|
@@ -207,7 +207,7 @@ class InlineTextEditor {
|
|
|
207
207
|
return this.entity.textContent || '';
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
-
function ensureEditorStyles() {
|
|
210
|
+
function ensureEditorStyles(target) {
|
|
211
211
|
(0, utils_1.injectStyleOnce)(EDITOR_STYLE_ID, `
|
|
212
212
|
.${EDITOR_BASE_CLASS} {
|
|
213
213
|
margin: 0;
|
|
@@ -220,5 +220,5 @@ function ensureEditorStyles() {
|
|
|
220
220
|
.${EDITOR_BASE_CLASS}::selection {
|
|
221
221
|
background-color: #b3d4fc;
|
|
222
222
|
}
|
|
223
|
-
|
|
223
|
+
`, target);
|
|
224
224
|
}
|
|
@@ -12,9 +12,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.InteractionManager = void 0;
|
|
13
13
|
const utils_1 = require("../../utils");
|
|
14
14
|
const utils_2 = require("../utils");
|
|
15
|
+
const utils_3 = require("../utils");
|
|
15
16
|
class InteractionManager {
|
|
16
17
|
constructor() {
|
|
17
|
-
this.extensions = new
|
|
18
|
+
this.extensions = new utils_3.Extension();
|
|
18
19
|
this.interactions = [];
|
|
19
20
|
this.active = false;
|
|
20
21
|
this.running = null;
|
|
@@ -22,14 +23,15 @@ class InteractionManager {
|
|
|
22
23
|
this.selection = new Set();
|
|
23
24
|
this.handleClick = (event) => {
|
|
24
25
|
const doc = this.editor.getDocument();
|
|
25
|
-
const
|
|
26
|
-
|
|
26
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
27
|
+
const insideInfographic = (0, utils_2.eventPathContains)(event, doc) ||
|
|
28
|
+
path.some((node) => node instanceof HTMLElement && (0, utils_1.isInfographicComponent)(node));
|
|
29
|
+
if (!event.target) {
|
|
27
30
|
this.deactivate();
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
33
|
// 点击画布 SVG 或者标记为组件的元素
|
|
31
|
-
if (
|
|
32
|
-
(0, utils_1.isInfographicComponent)(target))
|
|
34
|
+
if (insideInfographic)
|
|
33
35
|
this.activate();
|
|
34
36
|
else
|
|
35
37
|
this.deactivate();
|
|
@@ -4,9 +4,10 @@ export interface IconButtonProps {
|
|
|
4
4
|
icon: Icon;
|
|
5
5
|
onClick?: () => void;
|
|
6
6
|
activate?: boolean;
|
|
7
|
+
root?: Node;
|
|
7
8
|
}
|
|
8
9
|
export interface IconButtonHandle {
|
|
9
10
|
activate: boolean;
|
|
10
11
|
setActivate: (activate: boolean) => void;
|
|
11
12
|
}
|
|
12
|
-
export declare const IconButton: ({ icon, onClick, activate, }: IconButtonProps) => Button;
|
|
13
|
+
export declare const IconButton: ({ icon, onClick, activate, root, }: IconButtonProps) => Button;
|