@nmmty/lazycanvas 0.6.4 → 1.0.0-dev.10
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/dist/core/Interpolation.d.ts +30 -0
- package/dist/core/Interpolation.js +200 -0
- package/dist/core/Scene.d.ts +94 -0
- package/dist/core/Scene.js +157 -0
- package/dist/core/Signal.d.ts +133 -0
- package/dist/core/Signal.js +255 -0
- package/dist/core/SignalUtils.d.ts +133 -0
- package/dist/core/SignalUtils.js +333 -0
- package/dist/core/ThreadScheduler.d.ts +38 -0
- package/dist/core/ThreadScheduler.js +74 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +21 -0
- package/dist/helpers/Filters.js +1 -1
- package/dist/helpers/FontsList.js +18 -18
- package/dist/helpers/Utlis.d.ts +3 -3
- package/dist/helpers/Utlis.js +25 -36
- package/dist/helpers/index.d.ts +3 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/jsx-runtime.d.ts +17 -0
- package/dist/jsx-runtime.js +111 -0
- package/dist/structures/LazyCanvas.d.ts +10 -48
- package/dist/structures/LazyCanvas.js +17 -78
- package/dist/structures/components/BaseLayer.d.ts +78 -32
- package/dist/structures/components/BaseLayer.js +106 -37
- package/dist/structures/components/BezierLayer.d.ts +27 -40
- package/dist/structures/components/BezierLayer.js +90 -55
- package/dist/structures/components/{Group.d.ts → Div.d.ts} +41 -22
- package/dist/structures/components/Div.js +202 -0
- package/dist/structures/components/ImageLayer.d.ts +2 -2
- package/dist/structures/components/ImageLayer.js +29 -30
- package/dist/structures/components/LineLayer.d.ts +20 -38
- package/dist/structures/components/LineLayer.js +45 -47
- package/dist/structures/components/MorphLayer.d.ts +5 -34
- package/dist/structures/components/MorphLayer.js +38 -52
- package/dist/structures/components/Path2DLayer.d.ts +7 -35
- package/dist/structures/components/Path2DLayer.js +32 -41
- package/dist/structures/components/PolygonLayer.d.ts +95 -0
- package/dist/structures/components/PolygonLayer.js +203 -0
- package/dist/structures/components/QuadraticLayer.d.ts +36 -45
- package/dist/structures/components/QuadraticLayer.js +90 -54
- package/dist/structures/components/TextLayer.d.ts +17 -46
- package/dist/structures/components/TextLayer.js +94 -77
- package/dist/structures/components/index.d.ts +10 -10
- package/dist/structures/components/index.js +2 -2
- package/dist/structures/helpers/Exporter.d.ts +13 -4
- package/dist/structures/helpers/Exporter.js +82 -46
- package/dist/structures/helpers/Font.js +1 -17
- package/dist/structures/helpers/Gradient.js +35 -49
- package/dist/structures/helpers/Link.js +2 -14
- package/dist/structures/helpers/Pattern.js +10 -18
- package/dist/structures/helpers/index.d.ts +7 -7
- package/dist/structures/helpers/readers/JSONReader.d.ts +4 -4
- package/dist/structures/helpers/readers/JSONReader.js +46 -48
- package/dist/structures/helpers/readers/YAMLReader.js +11 -11
- package/dist/structures/managers/FontsManager.js +9 -18
- package/dist/structures/managers/LayersManager.d.ts +18 -28
- package/dist/structures/managers/LayersManager.js +14 -36
- package/dist/structures/managers/LayoutManager.d.ts +23 -0
- package/dist/structures/managers/LayoutManager.js +409 -0
- package/dist/structures/managers/index.d.ts +3 -5
- package/dist/structures/managers/index.js +1 -3
- package/dist/structures/managers/{RenderManager.d.ts → piplines/ClassicRenderPipeline.d.ts} +4 -30
- package/dist/structures/managers/piplines/ClassicRenderPipeline.js +90 -0
- package/dist/structures/managers/piplines/ModernRenderPipeline.d.ts +44 -0
- package/dist/structures/managers/piplines/ModernRenderPipeline.js +123 -0
- package/dist/structures/managers/piplines/index.d.ts +24 -0
- package/dist/structures/managers/piplines/index.js +18 -0
- package/dist/types/enum.d.ts +4 -3
- package/dist/types/enum.js +3 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +257 -105
- package/dist/utils/APNGEncoder.d.ts +67 -0
- package/dist/utils/APNGEncoder.js +205 -0
- package/dist/utils/DrawUtils.d.ts +9 -0
- package/dist/utils/DrawUtils.js +42 -0
- package/dist/utils/LazyUtil.js +1 -2
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/utils.d.ts +5 -9
- package/dist/utils/utils.js +154 -78
- package/package.json +61 -59
- package/dist/structures/components/ClearLayer.d.ts +0 -147
- package/dist/structures/components/ClearLayer.js +0 -158
- package/dist/structures/components/Group.js +0 -153
- package/dist/structures/managers/AnimationManager.d.ts +0 -120
- package/dist/structures/managers/AnimationManager.js +0 -99
- package/dist/structures/managers/PluginManager.d.ts +0 -230
- package/dist/structures/managers/PluginManager.js +0 -182
- package/dist/structures/managers/RenderManager.js +0 -183
|
@@ -3,19 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TextLayer = void 0;
|
|
4
4
|
const BaseLayer_1 = require("./BaseLayer");
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
|
-
const
|
|
7
|
-
const utils_1 = require("../../utils/utils");
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
8
7
|
/**
|
|
9
|
-
* Class representing a Text
|
|
8
|
+
* Class representing a Text layer, extending the BaseLayer class.
|
|
10
9
|
*/
|
|
11
10
|
class TextLayer extends BaseLayer_1.BaseLayer {
|
|
12
|
-
/**
|
|
13
|
-
* The properties of the Text Layer.
|
|
14
|
-
*/
|
|
15
|
-
props;
|
|
16
11
|
/**
|
|
17
12
|
* Constructs a new TextLayer instance.
|
|
18
|
-
* @param {ITextLayerProps} [props] - The properties of the Text
|
|
13
|
+
* @param {ITextLayerProps} [props] - The properties of the Text layer.
|
|
19
14
|
* @param {IBaseLayerMisc} [misc] - Miscellaneous options for the layer.
|
|
20
15
|
*/
|
|
21
16
|
constructor(props, misc) {
|
|
@@ -43,9 +38,9 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
43
38
|
setFont(familyOrConfig, size, weight) {
|
|
44
39
|
if (typeof familyOrConfig === "string") {
|
|
45
40
|
if (!size)
|
|
46
|
-
throw new
|
|
41
|
+
throw new utils_1.LazyError("The size of the font must be provided");
|
|
47
42
|
if (!weight)
|
|
48
|
-
throw new
|
|
43
|
+
throw new utils_1.LazyError("The weight of the font must be provided");
|
|
49
44
|
this.props.font = {
|
|
50
45
|
family: familyOrConfig,
|
|
51
46
|
size,
|
|
@@ -88,10 +83,10 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
88
83
|
*/
|
|
89
84
|
setColor(color, ...sub) {
|
|
90
85
|
if (!color)
|
|
91
|
-
throw new
|
|
86
|
+
throw new utils_1.LazyError("The color of the layer must be provided");
|
|
92
87
|
if (!(0, utils_1.isColor)(color))
|
|
93
|
-
throw new
|
|
94
|
-
this.props.
|
|
88
|
+
throw new utils_1.LazyError("The color of the layer must be a valid color");
|
|
89
|
+
this.props.color = color;
|
|
95
90
|
if (sub && sub.length > 0) {
|
|
96
91
|
this.props.subStringColors = sub;
|
|
97
92
|
}
|
|
@@ -137,13 +132,12 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
137
132
|
setStroke(width, cap, join, dash, dashOffset, miterLimit) {
|
|
138
133
|
this.props.stroke = {
|
|
139
134
|
width,
|
|
140
|
-
cap: cap ||
|
|
141
|
-
join: join ||
|
|
135
|
+
cap: cap || "butt",
|
|
136
|
+
join: join || "miter",
|
|
142
137
|
dash: dash || [],
|
|
143
138
|
dashOffset: dashOffset || 0,
|
|
144
139
|
miterLimit: miterLimit || 10,
|
|
145
140
|
};
|
|
146
|
-
this.props.filled = false; // Ensure filled is false when stroke is set
|
|
147
141
|
return this;
|
|
148
142
|
}
|
|
149
143
|
/**
|
|
@@ -171,13 +165,32 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
171
165
|
* @returns {Object} The width and height of the text.
|
|
172
166
|
*/
|
|
173
167
|
measureText(ctx, canvas) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
168
|
+
ctx.font = `${this.props.font.weight} ${this.props.font.size}px ${this.props.font.family}`;
|
|
169
|
+
if (this.props?.multiline?.enabled) {
|
|
170
|
+
const w = (0, utils_1.parseToNormal)(this.props.size?.width || "vw", ctx, canvas);
|
|
171
|
+
// Calculate actual height based on text wrapping
|
|
172
|
+
const words = this.props.text.split(" ");
|
|
173
|
+
let line = "";
|
|
174
|
+
let linesCount = 1;
|
|
175
|
+
for (let word of words) {
|
|
176
|
+
let linePlus = line + word + " ";
|
|
177
|
+
if (ctx.measureText(linePlus).width > w) {
|
|
178
|
+
linesCount++;
|
|
179
|
+
line = word + " ";
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
line = linePlus;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const lineHeight = this.props.font.size * (this.props.multiline.spacing || 1.1);
|
|
186
|
+
const calculatedHeight = linesCount * lineHeight;
|
|
187
|
+
// If height is fixed in props, use it, otherwise use calculated height
|
|
188
|
+
const fixedHeight = this.props.size?.height
|
|
189
|
+
? (0, utils_1.parseToNormal)(this.props.size.height, ctx, canvas, { width: w, height: 0 }, { vertical: true })
|
|
190
|
+
: 0;
|
|
191
|
+
return { width: w, height: fixedHeight || calculatedHeight };
|
|
178
192
|
}
|
|
179
193
|
else {
|
|
180
|
-
ctx.font = `${this.props.font.weight} ${this.props.font.size}px ${this.props.font.family}`;
|
|
181
194
|
let data = ctx.measureText(this.props.text);
|
|
182
195
|
return { width: data.width, height: this.props.font.size };
|
|
183
196
|
}
|
|
@@ -186,37 +199,50 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
186
199
|
* Draws the text layer on the canvas.
|
|
187
200
|
* @param {SKRSContext2D} [ctx] - The canvas rendering context.
|
|
188
201
|
* @param {Canvas | SvgCanvas} [canvas] - The canvas instance.
|
|
189
|
-
* @param {LayersManager} [manager] - The
|
|
202
|
+
* @param {LayersManager} [manager] - The layer's manager.
|
|
190
203
|
* @param {boolean} [debug] - Whether to enable debug logging.
|
|
191
204
|
*/
|
|
192
205
|
async draw(ctx, canvas, manager, debug) {
|
|
193
206
|
const parcer = (0, utils_1.parser)(ctx, canvas, manager);
|
|
194
207
|
const { x, y, w } = parcer.parseBatch({
|
|
195
|
-
x: { v: this.props.x },
|
|
196
|
-
y: { v: this.props.y, options:
|
|
197
|
-
w: { v: this.props.size?.width },
|
|
208
|
+
x: { v: this.props.position?.x || 0 },
|
|
209
|
+
y: { v: this.props.position?.y || 0, options: utils_1.defaultArg.vl(true) },
|
|
210
|
+
w: { v: this.props.size?.width || "vw" },
|
|
198
211
|
});
|
|
199
|
-
const h = parcer.parse(this.props.size?.height,
|
|
212
|
+
const h = parcer.parse(this.props.size?.height || 0, utils_1.defaultArg.wh(w), utils_1.defaultArg.vl(true));
|
|
200
213
|
if (debug)
|
|
201
|
-
|
|
214
|
+
utils_1.LazyLog.log("none", `TextLayer:`, { x, y, w, h });
|
|
202
215
|
ctx.save();
|
|
203
|
-
|
|
216
|
+
if (this.props.transform) {
|
|
217
|
+
(0, utils_1.transform)(ctx, this.props.transform, { width: w, height: h, x, y, type: this.type }, {
|
|
218
|
+
text: this.props.text,
|
|
219
|
+
textAlign: this.props.align,
|
|
220
|
+
fontSize: this.props.font.size,
|
|
221
|
+
multiline: this.props?.multiline?.enabled || false,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
204
224
|
ctx.beginPath();
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
225
|
+
utils_1.DrawUtils.drawShadow(ctx, this.props.shadow);
|
|
226
|
+
utils_1.DrawUtils.opacity(ctx, this.props.opacity);
|
|
227
|
+
utils_1.DrawUtils.filters(ctx, this.props.filter);
|
|
228
|
+
// When layout is managed by Yoga, always use top-left alignment
|
|
229
|
+
// since Yoga calculates position as top-left corner
|
|
230
|
+
const useLayoutAlignment = this.props._computedLayout === true;
|
|
231
|
+
ctx.textAlign = useLayoutAlignment ? "left" : this.props.align;
|
|
209
232
|
if (this.props.letterSpacing)
|
|
210
233
|
ctx.letterSpacing = `${this.props.letterSpacing}px`;
|
|
211
234
|
if (this.props.wordSpacing)
|
|
212
235
|
ctx.wordSpacing = `${this.props.wordSpacing}px`;
|
|
213
|
-
|
|
214
|
-
ctx.textBaseline = this.props.baseline;
|
|
236
|
+
ctx.textBaseline = useLayoutAlignment ? "top" : this.props.baseline || "alphabetic";
|
|
215
237
|
if (this.props.direction)
|
|
216
238
|
ctx.direction = this.props.direction;
|
|
217
|
-
let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.
|
|
218
|
-
|
|
219
|
-
|
|
239
|
+
let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.color, {
|
|
240
|
+
debug,
|
|
241
|
+
layer: { width: w, height: h, x, y, align: "center" },
|
|
242
|
+
manager,
|
|
243
|
+
});
|
|
244
|
+
if (this.props?.multiline?.enabled) {
|
|
245
|
+
const words = this.props.text.split(" ");
|
|
220
246
|
let lines = [];
|
|
221
247
|
for (let fontSize = 1; fontSize <= this.props.font.size; fontSize++) {
|
|
222
248
|
let lineHeight = fontSize * (this.props.multiline.spacing || 1.1);
|
|
@@ -224,14 +250,14 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
224
250
|
let xm = x;
|
|
225
251
|
let ym = y;
|
|
226
252
|
lines = [];
|
|
227
|
-
let line =
|
|
253
|
+
let line = "";
|
|
228
254
|
let charOffset = 0; // Track position in original text
|
|
229
255
|
for (let word of words) {
|
|
230
|
-
let linePlus = line + word +
|
|
256
|
+
let linePlus = line + word + " ";
|
|
231
257
|
if (ctx.measureText(linePlus).width > w) {
|
|
232
258
|
lines.push({ text: line, x: xm, y: ym, startOffset: charOffset });
|
|
233
259
|
charOffset += line.length;
|
|
234
|
-
line = word +
|
|
260
|
+
line = word + " ";
|
|
235
261
|
ym += lineHeight;
|
|
236
262
|
}
|
|
237
263
|
else {
|
|
@@ -267,19 +293,12 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
267
293
|
drawText(props, ctx, fillStyle, text, x, y, w, textOffset = 0) {
|
|
268
294
|
// If no substring colors are defined, draw normally
|
|
269
295
|
if (!props.subStringColors || props.subStringColors.length === 0) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
ctx.
|
|
296
|
+
utils_1.DrawUtils.fillStyle(ctx, fillStyle, this.props.stroke);
|
|
297
|
+
if (props.stroke) {
|
|
298
|
+
ctx.strokeText(text, x, y, w);
|
|
273
299
|
}
|
|
274
300
|
else {
|
|
275
|
-
ctx.
|
|
276
|
-
ctx.lineWidth = props.stroke?.width || 1;
|
|
277
|
-
ctx.lineCap = props.stroke?.cap || 'butt';
|
|
278
|
-
ctx.lineJoin = props.stroke?.join || 'miter';
|
|
279
|
-
ctx.miterLimit = props.stroke?.miterLimit || 10;
|
|
280
|
-
ctx.lineDashOffset = props.stroke?.dashOffset || 0;
|
|
281
|
-
ctx.setLineDash(props.stroke?.dash || []);
|
|
282
|
-
ctx.strokeText(text, x, y, w);
|
|
301
|
+
ctx.fillText(text, x, y, w);
|
|
283
302
|
}
|
|
284
303
|
return;
|
|
285
304
|
}
|
|
@@ -288,14 +307,17 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
288
307
|
let currentX = x;
|
|
289
308
|
// Save original text alignment and set to left for manual positioning
|
|
290
309
|
const originalAlign = ctx.textAlign;
|
|
291
|
-
ctx.textAlign =
|
|
310
|
+
ctx.textAlign = "left";
|
|
292
311
|
// Adjust starting X based on text alignment
|
|
293
312
|
const alignValue = props.align;
|
|
294
|
-
if (alignValue === types_1.TextAlign.Center || alignValue ===
|
|
313
|
+
if (alignValue === types_1.TextAlign.Center || alignValue === "center") {
|
|
295
314
|
const totalWidth = ctx.measureText(text).width;
|
|
296
315
|
currentX = x - totalWidth / 2;
|
|
297
316
|
}
|
|
298
|
-
else if (alignValue === types_1.TextAlign.Right ||
|
|
317
|
+
else if (alignValue === types_1.TextAlign.Right ||
|
|
318
|
+
alignValue === "right" ||
|
|
319
|
+
alignValue === types_1.TextAlign.End ||
|
|
320
|
+
alignValue === "end") {
|
|
299
321
|
const totalWidth = ctx.measureText(text).width;
|
|
300
322
|
currentX = x - totalWidth;
|
|
301
323
|
}
|
|
@@ -323,16 +345,19 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
323
345
|
text: text.substring(currentIndex, localStart),
|
|
324
346
|
color: fillStyle,
|
|
325
347
|
start: currentIndex,
|
|
326
|
-
end: localStart
|
|
348
|
+
end: localStart,
|
|
327
349
|
});
|
|
328
350
|
}
|
|
329
351
|
// Add colored substring
|
|
330
352
|
if (localStart < localEnd) {
|
|
331
353
|
segments.push({
|
|
332
354
|
text: text.substring(localStart, localEnd),
|
|
333
|
-
color: subColor.color,
|
|
355
|
+
color: (0, utils_1.parseFillStyle)(ctx, subColor.color, {
|
|
356
|
+
debug: false,
|
|
357
|
+
layer: { width: w, height: 0, x: 0, y: 0, align: "center" },
|
|
358
|
+
}),
|
|
334
359
|
start: localStart,
|
|
335
|
-
end: localEnd
|
|
360
|
+
end: localEnd,
|
|
336
361
|
});
|
|
337
362
|
currentIndex = localEnd;
|
|
338
363
|
}
|
|
@@ -343,7 +368,7 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
343
368
|
text: text.substring(currentIndex),
|
|
344
369
|
color: fillStyle,
|
|
345
370
|
start: currentIndex,
|
|
346
|
-
end: textLength
|
|
371
|
+
end: textLength,
|
|
347
372
|
});
|
|
348
373
|
}
|
|
349
374
|
// Draw each segment
|
|
@@ -351,19 +376,12 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
351
376
|
if (segment.text.length === 0)
|
|
352
377
|
continue;
|
|
353
378
|
const segmentWidth = ctx.measureText(segment.text).width;
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
ctx.
|
|
379
|
+
utils_1.DrawUtils.fillStyle(ctx, segment.color, this.props.stroke);
|
|
380
|
+
if (props.stroke) {
|
|
381
|
+
ctx.strokeText(segment.text, currentX, y);
|
|
357
382
|
}
|
|
358
383
|
else {
|
|
359
|
-
ctx.
|
|
360
|
-
ctx.lineWidth = props.stroke?.width || 1;
|
|
361
|
-
ctx.lineCap = props.stroke?.cap || 'butt';
|
|
362
|
-
ctx.lineJoin = props.stroke?.join || 'miter';
|
|
363
|
-
ctx.miterLimit = props.stroke?.miterLimit || 10;
|
|
364
|
-
ctx.lineDashOffset = props.stroke?.dashOffset || 0;
|
|
365
|
-
ctx.setLineDash(props.stroke?.dash || []);
|
|
366
|
-
ctx.strokeText(segment.text, currentX, y);
|
|
384
|
+
ctx.fillText(segment.text, currentX, y);
|
|
367
385
|
}
|
|
368
386
|
currentX += segmentWidth;
|
|
369
387
|
}
|
|
@@ -371,29 +389,28 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
371
389
|
ctx.textAlign = originalAlign;
|
|
372
390
|
}
|
|
373
391
|
/**
|
|
374
|
-
* Converts the Text
|
|
375
|
-
* @returns {ITextLayer} The JSON representation of the Text
|
|
392
|
+
* Converts the Text layer to a JSON representation.
|
|
393
|
+
* @returns {ITextLayer} The JSON representation of the Text layer.
|
|
376
394
|
*/
|
|
377
395
|
toJSON() {
|
|
378
396
|
let data = super.toJSON();
|
|
379
397
|
let copy = { ...this.props };
|
|
380
|
-
for (const key of [
|
|
381
|
-
if (copy[key] && typeof copy[key] ===
|
|
398
|
+
for (const key of ["x", "y", "size.width", "size.height", "fillStyle"]) {
|
|
399
|
+
if (copy[key] && typeof copy[key] === "object" && "toJSON" in copy[key]) {
|
|
382
400
|
copy[key] = copy[key].toJSON();
|
|
383
401
|
}
|
|
384
402
|
}
|
|
385
403
|
return { ...data, props: copy };
|
|
386
404
|
}
|
|
387
405
|
/**
|
|
388
|
-
* Validates the properties of the Text
|
|
406
|
+
* Validates the properties of the Text layer.
|
|
389
407
|
* @param {ITextLayerProps} [data] - The properties to validate.
|
|
390
408
|
* @returns {ITextLayerProps} The validated properties.
|
|
391
409
|
*/
|
|
392
410
|
validateProps(data) {
|
|
393
411
|
return {
|
|
394
412
|
...super.validateProps(data),
|
|
395
|
-
|
|
396
|
-
fillStyle: data.fillStyle || '#000000',
|
|
413
|
+
color: data.color || "#000000",
|
|
397
414
|
text: data.text || "",
|
|
398
415
|
font: {
|
|
399
416
|
family: data.font?.family || "Arial",
|
|
@@ -405,7 +422,7 @@ class TextLayer extends BaseLayer_1.BaseLayer {
|
|
|
405
422
|
spacing: data.multiline?.spacing || 1.1,
|
|
406
423
|
},
|
|
407
424
|
size: {
|
|
408
|
-
width: data.size?.width ||
|
|
425
|
+
width: data.size?.width || 0,
|
|
409
426
|
height: data.size?.height || 0,
|
|
410
427
|
},
|
|
411
428
|
align: data.align || types_1.TextAlign.Left,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
1
|
+
export * from "./BaseLayer";
|
|
2
|
+
export * from "./BezierLayer";
|
|
3
|
+
export * from "./ImageLayer";
|
|
4
|
+
export * from "./TextLayer";
|
|
5
|
+
export * from "./MorphLayer";
|
|
6
|
+
export * from "./Div";
|
|
7
|
+
export * from "./LineLayer";
|
|
8
|
+
export * from "./QuadraticLayer";
|
|
9
|
+
export * from "./Path2DLayer";
|
|
10
|
+
export * from "./PolygonLayer";
|
|
@@ -16,11 +16,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./BaseLayer"), exports);
|
|
18
18
|
__exportStar(require("./BezierLayer"), exports);
|
|
19
|
-
__exportStar(require("./ClearLayer"), exports);
|
|
20
19
|
__exportStar(require("./ImageLayer"), exports);
|
|
21
20
|
__exportStar(require("./TextLayer"), exports);
|
|
22
21
|
__exportStar(require("./MorphLayer"), exports);
|
|
23
|
-
__exportStar(require("./
|
|
22
|
+
__exportStar(require("./Div"), exports);
|
|
24
23
|
__exportStar(require("./LineLayer"), exports);
|
|
25
24
|
__exportStar(require("./QuadraticLayer"), exports);
|
|
26
25
|
__exportStar(require("./Path2DLayer"), exports);
|
|
26
|
+
__exportStar(require("./PolygonLayer"), exports);
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { IOLazyCanvas, LazyCanvas } from "../LazyCanvas";
|
|
2
2
|
import { AnyExport } from "../../types";
|
|
3
3
|
import { Canvas, SKRSContext2D, SvgCanvas } from "@napi-rs/canvas";
|
|
4
|
+
import { Scene } from "../../core";
|
|
4
5
|
/**
|
|
5
|
-
* Class responsible for exporting a LazyCanvas instance to various formats.
|
|
6
|
+
* Class responsible for exporting a LazyCanvas or Scene instance to various formats.
|
|
6
7
|
*/
|
|
7
8
|
export declare class Exporter {
|
|
8
9
|
/**
|
|
9
10
|
* The LazyCanvas instance to be exported.
|
|
10
11
|
*/
|
|
11
|
-
canvas
|
|
12
|
+
canvas?: LazyCanvas;
|
|
13
|
+
/**
|
|
14
|
+
* The Scene instance to be exported.
|
|
15
|
+
*/
|
|
16
|
+
scene?: Scene;
|
|
12
17
|
/**
|
|
13
18
|
* Constructs a new Exporter instance.
|
|
14
|
-
* @param
|
|
19
|
+
* @param source {LazyCanvas | Scene} - The LazyCanvas or Scene instance to be exported.
|
|
15
20
|
*/
|
|
16
|
-
constructor(
|
|
21
|
+
constructor(source: LazyCanvas | Scene);
|
|
17
22
|
/**
|
|
18
23
|
* Saves a file to the filesystem.
|
|
19
24
|
* @param {any} [buffer] - The data to be saved.
|
|
@@ -34,12 +39,16 @@ export declare class Exporter {
|
|
|
34
39
|
* @param {Object} [opts] - Optional settings.
|
|
35
40
|
* @param {string} [opts.name] - The name of the file (optional).
|
|
36
41
|
* @param {boolean} [opts.saveAsFile] - Whether to save the export as a file (optional).
|
|
42
|
+
* @param {number} [opts.duration] - Duration of the animation in seconds (Scene only).
|
|
43
|
+
* @param {number} [opts.fps] - Frames per second for animation (default: 60, Scene only).
|
|
37
44
|
* @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The exported data.
|
|
38
45
|
* @throws {LazyError} If the export type is not supported.
|
|
39
46
|
*/
|
|
40
47
|
export(exportType: AnyExport, opts?: {
|
|
41
48
|
name?: string;
|
|
42
49
|
saveAsFile?: boolean;
|
|
50
|
+
duration?: number;
|
|
51
|
+
fps?: number;
|
|
43
52
|
}): Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>;
|
|
44
53
|
/**
|
|
45
54
|
* Synchronously exports the canvas to the specified format.
|
|
@@ -32,27 +32,33 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
exports.Exporter = void 0;
|
|
37
40
|
const types_1 = require("../../types");
|
|
38
|
-
const
|
|
39
|
-
const fs = __importStar(require("fs"));
|
|
40
|
-
const utils_1 = require("../../utils/utils");
|
|
41
|
+
const utils_1 = require("../../utils");
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
41
43
|
const _yaml = __importStar(require("js-yaml"));
|
|
44
|
+
const APNGEncoder_1 = __importDefault(require("../../utils/APNGEncoder"));
|
|
45
|
+
const core_1 = require("../../core");
|
|
42
46
|
/**
|
|
43
|
-
* Class responsible for exporting a LazyCanvas instance to various formats.
|
|
47
|
+
* Class responsible for exporting a LazyCanvas or Scene instance to various formats.
|
|
44
48
|
*/
|
|
45
49
|
class Exporter {
|
|
46
|
-
/**
|
|
47
|
-
* The LazyCanvas instance to be exported.
|
|
48
|
-
*/
|
|
49
|
-
canvas;
|
|
50
50
|
/**
|
|
51
51
|
* Constructs a new Exporter instance.
|
|
52
|
-
* @param
|
|
52
|
+
* @param source {LazyCanvas | Scene} - The LazyCanvas or Scene instance to be exported.
|
|
53
53
|
*/
|
|
54
|
-
constructor(
|
|
55
|
-
|
|
54
|
+
constructor(source) {
|
|
55
|
+
if (source instanceof core_1.Scene) {
|
|
56
|
+
this.scene = source;
|
|
57
|
+
this.canvas = source.lazyCanvas;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.canvas = source;
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
/**
|
|
58
64
|
* Saves a file to the filesystem.
|
|
@@ -63,9 +69,9 @@ class Exporter {
|
|
|
63
69
|
*/
|
|
64
70
|
async saveFile(buffer, extension, name) {
|
|
65
71
|
if (!buffer)
|
|
66
|
-
throw new
|
|
72
|
+
throw new utils_1.LazyError("Buffer must be provided");
|
|
67
73
|
if (!extension)
|
|
68
|
-
throw new
|
|
74
|
+
throw new utils_1.LazyError("Extension must be provided");
|
|
69
75
|
fs.writeFileSync(`${name === undefined ? (0, utils_1.generateRandomName)() : name}.${extension}`, buffer);
|
|
70
76
|
}
|
|
71
77
|
/**
|
|
@@ -86,12 +92,15 @@ class Exporter {
|
|
|
86
92
|
* @param {Object} [opts] - Optional settings.
|
|
87
93
|
* @param {string} [opts.name] - The name of the file (optional).
|
|
88
94
|
* @param {boolean} [opts.saveAsFile] - Whether to save the export as a file (optional).
|
|
95
|
+
* @param {number} [opts.duration] - Duration of the animation in seconds (Scene only).
|
|
96
|
+
* @param {number} [opts.fps] - Frames per second for animation (default: 60, Scene only).
|
|
89
97
|
* @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The exported data.
|
|
90
98
|
* @throws {LazyError} If the export type is not supported.
|
|
91
99
|
*/
|
|
92
100
|
async export(exportType, opts) {
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
if (!this.canvas) {
|
|
102
|
+
throw new utils_1.LazyError("Canvas is not initialized");
|
|
103
|
+
}
|
|
95
104
|
let result;
|
|
96
105
|
switch (exportType) {
|
|
97
106
|
case types_1.Export.CTX:
|
|
@@ -100,69 +109,94 @@ class Exporter {
|
|
|
100
109
|
break;
|
|
101
110
|
case types_1.Export.SVG:
|
|
102
111
|
case "svg":
|
|
103
|
-
result = await this.canvas.manager.render.render(
|
|
112
|
+
result = await this.canvas.manager.render.render("svg");
|
|
104
113
|
if (opts?.saveAsFile) {
|
|
105
|
-
await this.saveFile(result,
|
|
114
|
+
await this.saveFile(result, "svg", opts.name);
|
|
106
115
|
}
|
|
107
116
|
break;
|
|
108
117
|
case types_1.Export.BUFFER:
|
|
109
118
|
case "buffer":
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
if (this.scene) {
|
|
120
|
+
result = await this.scene.renderFirstFrame().then((frame) => frame.toBuffer("image/png"));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
result = (await this.canvas.manager.render.render("buffer"));
|
|
113
124
|
}
|
|
114
|
-
break;
|
|
115
|
-
case types_1.Export.GIF:
|
|
116
|
-
case "gif":
|
|
117
|
-
result = await this.canvas.manager.render.render('buffer');
|
|
118
125
|
if (opts?.saveAsFile) {
|
|
119
|
-
await this.saveFile(result,
|
|
126
|
+
await this.saveFile(result, "png", opts.name);
|
|
120
127
|
}
|
|
121
128
|
break;
|
|
122
129
|
case types_1.Export.WEBP:
|
|
123
130
|
case "webp":
|
|
124
|
-
|
|
131
|
+
if (this.scene) {
|
|
132
|
+
result = await this.scene
|
|
133
|
+
.renderFirstFrame()
|
|
134
|
+
.then((frame) => frame.toBuffer("image/webp"));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
result = await this.canvas.manager.render.render("webp");
|
|
138
|
+
}
|
|
125
139
|
if (opts?.saveAsFile) {
|
|
126
|
-
await this.saveFile(result,
|
|
140
|
+
await this.saveFile(result, "webp", opts.name);
|
|
127
141
|
}
|
|
128
142
|
break;
|
|
129
|
-
case types_1.Export.JPEG:
|
|
130
|
-
case "jpeg":
|
|
131
|
-
result = await this.canvas.manager.render.render('buffer');
|
|
132
|
-
await this.saveFile(result, 'jpeg', opts?.name);
|
|
133
|
-
break;
|
|
134
143
|
case types_1.Export.JPG:
|
|
135
144
|
case "jpg":
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
if (this.scene) {
|
|
146
|
+
result = await this.scene
|
|
147
|
+
.renderFirstFrame()
|
|
148
|
+
.then((frame) => frame.toBuffer("image/jpeg"));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
result = await this.canvas.manager.render.render("jpg");
|
|
152
|
+
}
|
|
153
|
+
await this.saveFile(result, "jpg", opts?.name);
|
|
154
|
+
return result;
|
|
139
155
|
case types_1.Export.PNG:
|
|
140
156
|
case "png":
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
if (this.scene) {
|
|
158
|
+
result = await this.scene.renderFirstFrame().then((frame) => frame.toBuffer("image/png"));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
result = await this.canvas.manager.render.render("png");
|
|
162
|
+
}
|
|
163
|
+
await this.saveFile(result, "png", opts?.name);
|
|
164
|
+
return result;
|
|
165
|
+
case types_1.Export.APNG:
|
|
166
|
+
case "apng":
|
|
167
|
+
if (!this.scene) {
|
|
168
|
+
throw new utils_1.LazyError("APNG export requires a Scene instance. Use: new Exporter(scene)");
|
|
169
|
+
}
|
|
170
|
+
const duration = opts?.duration ?? 0;
|
|
171
|
+
const timeNow = Date.now();
|
|
172
|
+
const fps = opts?.fps ?? 60;
|
|
173
|
+
const frameData = await this.scene.renderAnimationData(timeNow, timeNow + duration, fps);
|
|
174
|
+
const encoder = new APNGEncoder_1.default(this.scene.width, this.scene.height, fps).addFrames(...frameData);
|
|
175
|
+
const buffer = encoder.encode();
|
|
176
|
+
if (opts?.saveAsFile !== false) {
|
|
177
|
+
fs.writeFileSync(`${opts?.name ?? "animation"}.png`, buffer);
|
|
178
|
+
}
|
|
179
|
+
return buffer;
|
|
144
180
|
case types_1.Export.JSON:
|
|
145
181
|
case "json":
|
|
146
182
|
const json = this.syncExport(exportType);
|
|
147
183
|
if (opts?.saveAsFile) {
|
|
148
|
-
await this.saveFile(JSON.stringify(json),
|
|
184
|
+
await this.saveFile(JSON.stringify(json), "json", opts.name);
|
|
149
185
|
}
|
|
150
186
|
return JSON.stringify(json);
|
|
151
187
|
case types_1.Export.CANVAS:
|
|
152
188
|
case "canvas":
|
|
153
|
-
return await this.canvas.manager.render.render(exportType);
|
|
189
|
+
return (await this.canvas.manager.render.render(exportType));
|
|
154
190
|
case types_1.Export.YAML:
|
|
155
191
|
case "yaml":
|
|
156
192
|
const yaml = _yaml.dump(this.syncExport(types_1.Export.JSON));
|
|
157
193
|
if (opts?.saveAsFile) {
|
|
158
|
-
await this.saveFile(yaml,
|
|
194
|
+
await this.saveFile(yaml, "yaml", opts.name);
|
|
159
195
|
}
|
|
160
196
|
return yaml;
|
|
161
197
|
default:
|
|
162
|
-
throw new
|
|
198
|
+
throw new utils_1.LazyError(`Export type ${exportType} is not supported`);
|
|
163
199
|
}
|
|
164
|
-
// afterExport hook
|
|
165
|
-
this.canvas.manager.plugins.executeHook('afterExport', this.canvas, result);
|
|
166
200
|
return result;
|
|
167
201
|
}
|
|
168
202
|
/**
|
|
@@ -171,13 +205,15 @@ class Exporter {
|
|
|
171
205
|
* @returns {IOLazyCanvas | void} The exported data or void if the export type is unsupported.
|
|
172
206
|
*/
|
|
173
207
|
syncExport(exportType) {
|
|
208
|
+
if (!this.canvas) {
|
|
209
|
+
throw new utils_1.LazyError("Canvas is not initialized");
|
|
210
|
+
}
|
|
174
211
|
switch (exportType) {
|
|
175
212
|
case types_1.Export.JSON:
|
|
176
213
|
case "json":
|
|
177
214
|
return {
|
|
178
215
|
options: this.canvas.options,
|
|
179
|
-
|
|
180
|
-
layers: this.exportLayers(this.canvas.manager.layers)
|
|
216
|
+
layers: this.exportLayers(this.canvas.manager.layers),
|
|
181
217
|
};
|
|
182
218
|
}
|
|
183
219
|
}
|