locusing 0.1.2
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/LICENSE +21 -0
- package/README.md +147 -0
- package/dist/chunk-3XW6GBD6.mjs +445 -0
- package/dist/chunk-HNU2F3GX.mjs +586 -0
- package/dist/chunk-TQQRYA5H.mjs +58 -0
- package/dist/chunk-Y4M467JV.mjs +607 -0
- package/dist/diagram-Djxa_kGR.d.mts +1945 -0
- package/dist/diagram-Djxa_kGR.d.ts +1945 -0
- package/dist/export.d.mts +194 -0
- package/dist/export.d.ts +194 -0
- package/dist/export.js +528 -0
- package/dist/export.mjs +305 -0
- package/dist/index.d.mts +6883 -0
- package/dist/index.d.ts +6883 -0
- package/dist/index.global.js +79540 -0
- package/dist/index.js +15785 -0
- package/dist/index.mjs +14350 -0
- package/dist/transform-4WYIJSLH.mjs +23 -0
- package/dist/transform-7YKZIQ3I.mjs +22 -0
- package/package.json +117 -0
package/dist/export.js
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __objRest = (source, exclude) => {
|
|
26
|
+
var target = {};
|
|
27
|
+
for (var prop in source)
|
|
28
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
if (source != null && __getOwnPropSymbols)
|
|
31
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
32
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
33
|
+
target[prop] = source[prop];
|
|
34
|
+
}
|
|
35
|
+
return target;
|
|
36
|
+
};
|
|
37
|
+
var __export = (target, all) => {
|
|
38
|
+
for (var name in all)
|
|
39
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
40
|
+
};
|
|
41
|
+
var __copyProps = (to, from, except, desc) => {
|
|
42
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
43
|
+
for (let key of __getOwnPropNames(from))
|
|
44
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
45
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
46
|
+
}
|
|
47
|
+
return to;
|
|
48
|
+
};
|
|
49
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
50
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
51
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
52
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
53
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
54
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
55
|
+
mod
|
|
56
|
+
));
|
|
57
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
58
|
+
|
|
59
|
+
// src/export.ts
|
|
60
|
+
var export_exports = {};
|
|
61
|
+
__export(export_exports, {
|
|
62
|
+
PlaywrightExporter: () => PlaywrightExporter,
|
|
63
|
+
exportSVGToPNG: () => exportSVGToPNG,
|
|
64
|
+
exportToPNG: () => exportToPNG,
|
|
65
|
+
generateExportHTML: () => generateExportHTML,
|
|
66
|
+
generateExportHTMLWithInlineCSS: () => generateExportHTMLWithInlineCSS
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(export_exports);
|
|
69
|
+
|
|
70
|
+
// src/core/render-svg.ts
|
|
71
|
+
var DEFAULT_FRAME = {
|
|
72
|
+
width: 16,
|
|
73
|
+
height: 9
|
|
74
|
+
};
|
|
75
|
+
var XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|
76
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
77
|
+
function toSVGString(diagram, options = {}) {
|
|
78
|
+
const { width = 800, height = 600, background, frame } = options;
|
|
79
|
+
const frameConfig = frame ? typeof frame === "boolean" ? DEFAULT_FRAME : frame : null;
|
|
80
|
+
if (frameConfig) {
|
|
81
|
+
const { width: fw, height: fh } = frameConfig;
|
|
82
|
+
const viewBox = `${-fw / 2} ${-fh / 2} ${fw} ${fh}`;
|
|
83
|
+
let content2 = "";
|
|
84
|
+
if (background) {
|
|
85
|
+
content2 += `<rect x="${-fw / 2}" y="${-fh / 2}" width="${fw}" height="${fh}" fill="${background}"/>`;
|
|
86
|
+
}
|
|
87
|
+
content2 += `<g transform="scale(1,-1)">${shapeToSVGString(diagram.shape)}</g>`;
|
|
88
|
+
return `<svg xmlns="${SVG_NS}" width="${width}" height="${height}" viewBox="${viewBox}">${content2}</svg>`;
|
|
89
|
+
}
|
|
90
|
+
let content = "";
|
|
91
|
+
if (background) {
|
|
92
|
+
content += `<rect width="100%" height="100%" fill="${background}"/>`;
|
|
93
|
+
}
|
|
94
|
+
content += shapeToSVGString(diagram.shape);
|
|
95
|
+
return `<svg xmlns="${SVG_NS}" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${content}</svg>`;
|
|
96
|
+
}
|
|
97
|
+
function shapeToSVGString(shape) {
|
|
98
|
+
const attrs = [`id="${shape.id}"`];
|
|
99
|
+
const style = styleToString(shape.style);
|
|
100
|
+
const transform = transformToString(shape.transform);
|
|
101
|
+
if (style) attrs.push(style);
|
|
102
|
+
if (transform) attrs.push(`transform="${transform}"`);
|
|
103
|
+
switch (shape.type) {
|
|
104
|
+
case "rect":
|
|
105
|
+
attrs.push(`x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}"`);
|
|
106
|
+
if (shape.rx) attrs.push(`rx="${shape.rx}"`);
|
|
107
|
+
if (shape.ry) attrs.push(`ry="${shape.ry}"`);
|
|
108
|
+
return `<rect ${attrs.join(" ")}/>`;
|
|
109
|
+
case "circle":
|
|
110
|
+
attrs.push(`cx="${shape.cx}" cy="${shape.cy}" r="${shape.r}"`);
|
|
111
|
+
return `<circle ${attrs.join(" ")}/>`;
|
|
112
|
+
case "ellipse":
|
|
113
|
+
attrs.push(`cx="${shape.cx}" cy="${shape.cy}" rx="${shape.rx}" ry="${shape.ry}"`);
|
|
114
|
+
return `<ellipse ${attrs.join(" ")}/>`;
|
|
115
|
+
case "line":
|
|
116
|
+
attrs.push(`x1="${shape.x1}" y1="${shape.y1}" x2="${shape.x2}" y2="${shape.y2}"`);
|
|
117
|
+
return `<line ${attrs.join(" ")}/>`;
|
|
118
|
+
case "polyline":
|
|
119
|
+
attrs.push(`points="${shape.points.map((p) => `${p[0]},${p[1]}`).join(" ")}"`);
|
|
120
|
+
return `<polyline ${attrs.join(" ")}/>`;
|
|
121
|
+
case "polygon":
|
|
122
|
+
attrs.push(`points="${shape.points.map((p) => `${p[0]},${p[1]}`).join(" ")}"`);
|
|
123
|
+
return `<polygon ${attrs.join(" ")}/>`;
|
|
124
|
+
case "path":
|
|
125
|
+
attrs.push(`d="${commandsToPath(shape.commands)}"`);
|
|
126
|
+
return `<path ${attrs.join(" ")}/>`;
|
|
127
|
+
case "arc":
|
|
128
|
+
attrs.push(`d="${arcToPath(shape.cx, shape.cy, shape.r, shape.startAngle, shape.endAngle)}"`);
|
|
129
|
+
return `<path ${attrs.join(" ")}/>`;
|
|
130
|
+
case "text":
|
|
131
|
+
const textStyle = textStyleToString(shape.style);
|
|
132
|
+
if (textStyle) attrs.push(textStyle);
|
|
133
|
+
attrs.push(`x="${shape.x}" y="${shape.y}"`);
|
|
134
|
+
return `<text ${attrs.join(" ")}>${escapeXML(shape.content)}</text>`;
|
|
135
|
+
case "tex":
|
|
136
|
+
const texShape = shape;
|
|
137
|
+
return `<foreignObject x="${texShape.x}" y="${texShape.y}" width="1000" height="200" overflow="visible"><div xmlns="${XHTML_NS}" style="font-size:${texShape.fontSize}px;color:${texShape.color};display:inline-block;white-space:nowrap">${texShape.html}</div></foreignObject>`;
|
|
138
|
+
case "group":
|
|
139
|
+
const children = shape.children.map(shapeToSVGString).join("");
|
|
140
|
+
return `<g ${attrs.join(" ")}>${children}</g>`;
|
|
141
|
+
case "svg":
|
|
142
|
+
const svgShapeStr = shape;
|
|
143
|
+
const scaleXStr = shape.width / svgShapeStr.originalWidth;
|
|
144
|
+
const scaleYStr = shape.height / svgShapeStr.originalHeight;
|
|
145
|
+
return `<g ${attrs.join(" ")} transform="scale(${scaleXStr}, ${scaleYStr})">${svgShapeStr.content}</g>`;
|
|
146
|
+
case "image":
|
|
147
|
+
const imgShapeStr = shape;
|
|
148
|
+
attrs.push(`href="${imgShapeStr.src}"`);
|
|
149
|
+
attrs.push(`x="${-shape.width / 2}" y="${-shape.height / 2}"`);
|
|
150
|
+
attrs.push(`width="${shape.width}" height="${shape.height}"`);
|
|
151
|
+
attrs.push('preserveAspectRatio="xMidYMid meet"');
|
|
152
|
+
return `<image ${attrs.join(" ")}/>`;
|
|
153
|
+
default:
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function styleToString(style) {
|
|
158
|
+
const parts = [];
|
|
159
|
+
if (style.fill) parts.push(`fill="${style.fill}"`);
|
|
160
|
+
if (style.fillOpacity !== void 0) parts.push(`fill-opacity="${style.fillOpacity}"`);
|
|
161
|
+
if (style.stroke) parts.push(`stroke="${style.stroke}"`);
|
|
162
|
+
if (style.strokeWidth !== void 0) parts.push(`stroke-width="${style.strokeWidth}"`);
|
|
163
|
+
if (style.strokeOpacity !== void 0) parts.push(`stroke-opacity="${style.strokeOpacity}"`);
|
|
164
|
+
if (style.strokeDasharray) parts.push(`stroke-dasharray="${style.strokeDasharray}"`);
|
|
165
|
+
if (style.strokeLinecap) parts.push(`stroke-linecap="${style.strokeLinecap}"`);
|
|
166
|
+
if (style.strokeLinejoin) parts.push(`stroke-linejoin="${style.strokeLinejoin}"`);
|
|
167
|
+
if (style.opacity !== void 0) parts.push(`opacity="${style.opacity}"`);
|
|
168
|
+
return parts.join(" ");
|
|
169
|
+
}
|
|
170
|
+
function textStyleToString(style) {
|
|
171
|
+
const parts = [];
|
|
172
|
+
if (style.fontSize) parts.push(`font-size="${style.fontSize}"`);
|
|
173
|
+
if (style.fontFamily) parts.push(`font-family="${style.fontFamily}"`);
|
|
174
|
+
if (style.fontWeight) parts.push(`font-weight="${style.fontWeight}"`);
|
|
175
|
+
if (style.textAnchor) parts.push(`text-anchor="${style.textAnchor}"`);
|
|
176
|
+
if (style.dominantBaseline) parts.push(`dominant-baseline="${style.dominantBaseline}"`);
|
|
177
|
+
return parts.join(" ");
|
|
178
|
+
}
|
|
179
|
+
function transformToString(matrix) {
|
|
180
|
+
const [a, b, c, d, e, f] = [
|
|
181
|
+
matrix[0],
|
|
182
|
+
matrix[3],
|
|
183
|
+
matrix[1],
|
|
184
|
+
matrix[4],
|
|
185
|
+
matrix[2],
|
|
186
|
+
matrix[5]
|
|
187
|
+
];
|
|
188
|
+
if (a === 1 && b === 0 && c === 0 && d === 1 && e === 0 && f === 0) {
|
|
189
|
+
return "";
|
|
190
|
+
}
|
|
191
|
+
return `matrix(${a},${b},${c},${d},${e},${f})`;
|
|
192
|
+
}
|
|
193
|
+
function commandsToPath(commands, _frameMode = false) {
|
|
194
|
+
return commands.map((cmd) => {
|
|
195
|
+
switch (cmd.type) {
|
|
196
|
+
case "M":
|
|
197
|
+
return `M${cmd.x},${cmd.y}`;
|
|
198
|
+
case "L":
|
|
199
|
+
return `L${cmd.x},${cmd.y}`;
|
|
200
|
+
case "H":
|
|
201
|
+
return `H${cmd.x}`;
|
|
202
|
+
case "V":
|
|
203
|
+
return `V${cmd.y}`;
|
|
204
|
+
case "C":
|
|
205
|
+
return `C${cmd.x1},${cmd.y1} ${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
|
|
206
|
+
case "S":
|
|
207
|
+
return `S${cmd.x2},${cmd.y2} ${cmd.x},${cmd.y}`;
|
|
208
|
+
case "Q":
|
|
209
|
+
return `Q${cmd.x1},${cmd.y1} ${cmd.x},${cmd.y}`;
|
|
210
|
+
case "T":
|
|
211
|
+
return `T${cmd.x},${cmd.y}`;
|
|
212
|
+
case "A": {
|
|
213
|
+
return `A${cmd.rx},${cmd.ry} ${cmd.angle} ${cmd.largeArc ? 1 : 0},${cmd.sweep ? 1 : 0} ${cmd.x},${cmd.y}`;
|
|
214
|
+
}
|
|
215
|
+
case "Z":
|
|
216
|
+
return "Z";
|
|
217
|
+
}
|
|
218
|
+
}).join(" ");
|
|
219
|
+
}
|
|
220
|
+
function arcToPath(cx, cy, r, startAngle, endAngle) {
|
|
221
|
+
const startX = cx + r * Math.cos(startAngle);
|
|
222
|
+
const startY = cy + r * Math.sin(startAngle);
|
|
223
|
+
const endX = cx + r * Math.cos(endAngle);
|
|
224
|
+
const endY = cy + r * Math.sin(endAngle);
|
|
225
|
+
const largeArc = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
|
|
226
|
+
const sweep = endAngle > startAngle ? 1 : 0;
|
|
227
|
+
return `M${startX},${startY} A${r},${r} 0 ${largeArc},${sweep} ${endX},${endY}`;
|
|
228
|
+
}
|
|
229
|
+
function escapeXML(str) {
|
|
230
|
+
if (typeof str !== "string") {
|
|
231
|
+
str = String(str != null ? str : "");
|
|
232
|
+
}
|
|
233
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/export/html-template.ts
|
|
237
|
+
var KATEX_CSS_URL = "https://cdn.jsdelivr.net/npm/katex@0.16.27/dist/katex.min.css";
|
|
238
|
+
function generateExportHTML(svgContent, options) {
|
|
239
|
+
const {
|
|
240
|
+
width = 1920,
|
|
241
|
+
height = 1080,
|
|
242
|
+
background = "transparent"
|
|
243
|
+
} = options;
|
|
244
|
+
return `<!DOCTYPE html>
|
|
245
|
+
<html>
|
|
246
|
+
<head>
|
|
247
|
+
<meta charset="UTF-8">
|
|
248
|
+
<meta name="viewport" content="width=${width}, height=${height}">
|
|
249
|
+
<link rel="stylesheet" href="${KATEX_CSS_URL}" crossorigin="anonymous">
|
|
250
|
+
<style>
|
|
251
|
+
* {
|
|
252
|
+
margin: 0;
|
|
253
|
+
padding: 0;
|
|
254
|
+
box-sizing: border-box;
|
|
255
|
+
}
|
|
256
|
+
html, body {
|
|
257
|
+
width: ${width}px;
|
|
258
|
+
height: ${height}px;
|
|
259
|
+
overflow: hidden;
|
|
260
|
+
}
|
|
261
|
+
body {
|
|
262
|
+
background: ${background};
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
justify-content: center;
|
|
266
|
+
}
|
|
267
|
+
svg {
|
|
268
|
+
width: 100%;
|
|
269
|
+
height: 100%;
|
|
270
|
+
display: block;
|
|
271
|
+
}
|
|
272
|
+
/* KaTeX \u5728 SVG foreignObject \u4E2D\u7684\u6837\u5F0F\u4FEE\u6B63 */
|
|
273
|
+
.katex {
|
|
274
|
+
font-size: inherit;
|
|
275
|
+
line-height: 1;
|
|
276
|
+
}
|
|
277
|
+
.katex-html {
|
|
278
|
+
white-space: nowrap;
|
|
279
|
+
}
|
|
280
|
+
</style>
|
|
281
|
+
</head>
|
|
282
|
+
<body>
|
|
283
|
+
${svgContent}
|
|
284
|
+
</body>
|
|
285
|
+
</html>`;
|
|
286
|
+
}
|
|
287
|
+
function generateExportHTMLWithInlineCSS(katexCSS, svgContent, options) {
|
|
288
|
+
const {
|
|
289
|
+
width = 1920,
|
|
290
|
+
height = 1080,
|
|
291
|
+
background = "transparent"
|
|
292
|
+
} = options;
|
|
293
|
+
return `<!DOCTYPE html>
|
|
294
|
+
<html>
|
|
295
|
+
<head>
|
|
296
|
+
<meta charset="UTF-8">
|
|
297
|
+
<meta name="viewport" content="width=${width}, height=${height}">
|
|
298
|
+
<style>
|
|
299
|
+
${katexCSS}
|
|
300
|
+
</style>
|
|
301
|
+
<style>
|
|
302
|
+
* {
|
|
303
|
+
margin: 0;
|
|
304
|
+
padding: 0;
|
|
305
|
+
box-sizing: border-box;
|
|
306
|
+
}
|
|
307
|
+
html, body {
|
|
308
|
+
width: ${width}px;
|
|
309
|
+
height: ${height}px;
|
|
310
|
+
overflow: hidden;
|
|
311
|
+
}
|
|
312
|
+
body {
|
|
313
|
+
background: ${background};
|
|
314
|
+
display: flex;
|
|
315
|
+
align-items: center;
|
|
316
|
+
justify-content: center;
|
|
317
|
+
}
|
|
318
|
+
svg {
|
|
319
|
+
width: 100%;
|
|
320
|
+
height: 100%;
|
|
321
|
+
display: block;
|
|
322
|
+
}
|
|
323
|
+
.katex {
|
|
324
|
+
font-size: inherit;
|
|
325
|
+
line-height: 1;
|
|
326
|
+
}
|
|
327
|
+
.katex-html {
|
|
328
|
+
white-space: nowrap;
|
|
329
|
+
}
|
|
330
|
+
</style>
|
|
331
|
+
</head>
|
|
332
|
+
<body>
|
|
333
|
+
${svgContent}
|
|
334
|
+
</body>
|
|
335
|
+
</html>`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/export/playwright-exporter.ts
|
|
339
|
+
var PlaywrightExporter = class {
|
|
340
|
+
constructor(options = {}) {
|
|
341
|
+
this.browser = null;
|
|
342
|
+
this.page = null;
|
|
343
|
+
var _a, _b;
|
|
344
|
+
this.options = {
|
|
345
|
+
headless: (_a = options.headless) != null ? _a : true,
|
|
346
|
+
browser: (_b = options.browser) != null ? _b : "chromium"
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 启动浏览器
|
|
351
|
+
*
|
|
352
|
+
* @throws 如果 Playwright 未安装
|
|
353
|
+
*/
|
|
354
|
+
async launch() {
|
|
355
|
+
if (this.browser) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
let playwright;
|
|
359
|
+
try {
|
|
360
|
+
playwright = await import("playwright");
|
|
361
|
+
} catch (e) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
"Playwright is not installed. Please install it with: pnpm add -D playwright"
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
const browserType = playwright[this.options.browser];
|
|
367
|
+
if (!browserType) {
|
|
368
|
+
throw new Error(`Unknown browser type: ${this.options.browser}`);
|
|
369
|
+
}
|
|
370
|
+
this.browser = await browserType.launch({
|
|
371
|
+
headless: this.options.headless
|
|
372
|
+
});
|
|
373
|
+
this.page = await this.browser.newPage();
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* 关闭浏览器
|
|
377
|
+
*/
|
|
378
|
+
async close() {
|
|
379
|
+
if (this.page) {
|
|
380
|
+
await this.page.close();
|
|
381
|
+
this.page = null;
|
|
382
|
+
}
|
|
383
|
+
if (this.browser) {
|
|
384
|
+
await this.browser.close();
|
|
385
|
+
this.browser = null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* 获取页面实例,确保已启动
|
|
390
|
+
*/
|
|
391
|
+
getPage() {
|
|
392
|
+
if (!this.browser || !this.page) {
|
|
393
|
+
throw new Error("Browser not launched. Call launch() first.");
|
|
394
|
+
}
|
|
395
|
+
return this.page;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* 导出 Diagram 为图片
|
|
399
|
+
*
|
|
400
|
+
* @param diagram - 要导出的 Diagram
|
|
401
|
+
* @param options - 导出选项
|
|
402
|
+
* @returns 导出结果
|
|
403
|
+
*/
|
|
404
|
+
async exportDiagram(diagram, options = {}) {
|
|
405
|
+
const {
|
|
406
|
+
width = 1920,
|
|
407
|
+
height = 1080,
|
|
408
|
+
frame = true
|
|
409
|
+
} = options;
|
|
410
|
+
const svgString = toSVGString(diagram, {
|
|
411
|
+
width,
|
|
412
|
+
height,
|
|
413
|
+
frame,
|
|
414
|
+
background: "transparent"
|
|
415
|
+
// HTML 背景会处理
|
|
416
|
+
});
|
|
417
|
+
return this.exportSVGString(svgString, options);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* 导出 Scene 为图片(静态帧)
|
|
421
|
+
*
|
|
422
|
+
* @param SceneClass - Scene 类
|
|
423
|
+
* @param options - 导出选项
|
|
424
|
+
* @returns 导出结果
|
|
425
|
+
*/
|
|
426
|
+
async exportScene(SceneClass, options = {}) {
|
|
427
|
+
const _a = options, { frameTime: _frameTime = 0 } = _a, exportOptions = __objRest(_a, ["frameTime"]);
|
|
428
|
+
const scene = new SceneClass();
|
|
429
|
+
if (typeof scene.construct === "function") {
|
|
430
|
+
if (typeof scene.toSVGString === "function") {
|
|
431
|
+
const svgString = scene.toSVGString();
|
|
432
|
+
return this.exportSVGString(svgString, exportOptions);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
throw new Error(
|
|
436
|
+
"Scene export requires the Scene to have a toSVGString() method. For animated scenes, use browser-based export."
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* 导出 SVG 字符串为图片
|
|
441
|
+
*
|
|
442
|
+
* @param svgString - SVG 字符串
|
|
443
|
+
* @param options - 导出选项
|
|
444
|
+
* @returns 导出结果
|
|
445
|
+
*/
|
|
446
|
+
async exportSVGString(svgString, options = {}) {
|
|
447
|
+
const page = this.getPage();
|
|
448
|
+
const {
|
|
449
|
+
format = "png",
|
|
450
|
+
quality = 90,
|
|
451
|
+
deviceScaleFactor = 2,
|
|
452
|
+
width = 1920,
|
|
453
|
+
height = 1080,
|
|
454
|
+
background = "transparent",
|
|
455
|
+
waitForFonts = true,
|
|
456
|
+
renderDelay = 100
|
|
457
|
+
} = options;
|
|
458
|
+
await page.setViewportSize({
|
|
459
|
+
width,
|
|
460
|
+
height
|
|
461
|
+
});
|
|
462
|
+
await page.emulateMedia({ colorScheme: "light" });
|
|
463
|
+
const html = generateExportHTML(svgString, { width, height, background });
|
|
464
|
+
await page.setContent(html, {
|
|
465
|
+
waitUntil: "networkidle"
|
|
466
|
+
});
|
|
467
|
+
if (waitForFonts) {
|
|
468
|
+
await page.waitForFunction(
|
|
469
|
+
() => document.fonts.ready.then(() => true),
|
|
470
|
+
{ timeout: 1e4 }
|
|
471
|
+
).catch(() => {
|
|
472
|
+
console.warn("Font loading timeout, continuing with available fonts");
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
if (renderDelay > 0) {
|
|
476
|
+
await page.waitForTimeout(renderDelay);
|
|
477
|
+
}
|
|
478
|
+
const buffer = await page.screenshot({
|
|
479
|
+
type: format,
|
|
480
|
+
quality: format !== "png" ? quality : void 0,
|
|
481
|
+
fullPage: false,
|
|
482
|
+
omitBackground: background === "transparent",
|
|
483
|
+
scale: "device"
|
|
484
|
+
});
|
|
485
|
+
const actualWidth = width * deviceScaleFactor;
|
|
486
|
+
const actualHeight = height * deviceScaleFactor;
|
|
487
|
+
return {
|
|
488
|
+
buffer: Buffer.from(buffer),
|
|
489
|
+
mimeType: `image/${format}`,
|
|
490
|
+
width: actualWidth,
|
|
491
|
+
height: actualHeight
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
async function exportToPNG(diagram, outputPath, options = {}) {
|
|
496
|
+
const fs = await import("fs/promises");
|
|
497
|
+
const exporter = new PlaywrightExporter();
|
|
498
|
+
try {
|
|
499
|
+
await exporter.launch();
|
|
500
|
+
const result = await exporter.exportDiagram(diagram, __spreadProps(__spreadValues({}, options), {
|
|
501
|
+
format: "png"
|
|
502
|
+
}));
|
|
503
|
+
await fs.writeFile(outputPath, result.buffer);
|
|
504
|
+
} finally {
|
|
505
|
+
await exporter.close();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
async function exportSVGToPNG(svgString, outputPath, options = {}) {
|
|
509
|
+
const fs = await import("fs/promises");
|
|
510
|
+
const exporter = new PlaywrightExporter();
|
|
511
|
+
try {
|
|
512
|
+
await exporter.launch();
|
|
513
|
+
const result = await exporter.exportSVGString(svgString, __spreadProps(__spreadValues({}, options), {
|
|
514
|
+
format: "png"
|
|
515
|
+
}));
|
|
516
|
+
await fs.writeFile(outputPath, result.buffer);
|
|
517
|
+
} finally {
|
|
518
|
+
await exporter.close();
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
522
|
+
0 && (module.exports = {
|
|
523
|
+
PlaywrightExporter,
|
|
524
|
+
exportSVGToPNG,
|
|
525
|
+
exportToPNG,
|
|
526
|
+
generateExportHTML,
|
|
527
|
+
generateExportHTMLWithInlineCSS
|
|
528
|
+
});
|