@nmmty/lazycanvas 0.6.5 → 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 +25 -38
- package/dist/structures/components/BezierLayer.js +88 -53
- package/dist/structures/components/{Group.d.ts → Div.d.ts} +37 -18
- package/dist/structures/components/Div.js +202 -0
- package/dist/structures/components/ImageLayer.d.ts +1 -1
- package/dist/structures/components/ImageLayer.js +28 -29
- package/dist/structures/components/LineLayer.d.ts +18 -36
- package/dist/structures/components/LineLayer.js +43 -45
- package/dist/structures/components/MorphLayer.d.ts +4 -33
- package/dist/structures/components/MorphLayer.js +37 -51
- package/dist/structures/components/Path2DLayer.d.ts +7 -35
- package/dist/structures/components/Path2DLayer.js +32 -41
- package/dist/structures/components/PolygonLayer.d.ts +3 -32
- package/dist/structures/components/PolygonLayer.js +37 -42
- package/dist/structures/components/QuadraticLayer.d.ts +25 -34
- package/dist/structures/components/QuadraticLayer.js +83 -47
- package/dist/structures/components/TextLayer.d.ts +5 -34
- package/dist/structures/components/TextLayer.js +88 -71
- package/dist/structures/components/index.d.ts +10 -11
- package/dist/structures/components/index.js +1 -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 +44 -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 +1 -2
- package/dist/types/enum.js +1 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +257 -107
- 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 +4 -7
- package/dist/utils/utils.js +140 -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
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LayoutManager = void 0;
|
|
4
|
+
const components_1 = require("../components");
|
|
5
|
+
const types_1 = require("../../types");
|
|
6
|
+
const LazyUtil_1 = require("../../utils/LazyUtil");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
class LayoutManager {
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this.yoga = null;
|
|
11
|
+
this.debug = opts?.debug || false;
|
|
12
|
+
this.ready = this.init();
|
|
13
|
+
}
|
|
14
|
+
async init() {
|
|
15
|
+
try {
|
|
16
|
+
// Initialize Yoga
|
|
17
|
+
// Use dynamic import to avoid issues with CJS/ESM interop and TLA
|
|
18
|
+
const yogaPkg = await import("yoga-layout");
|
|
19
|
+
const loadYoga = yogaPkg.default || yogaPkg;
|
|
20
|
+
if (typeof loadYoga === "function") {
|
|
21
|
+
this.yoga = await loadYoga((0, fs_1.readFileSync)(require.resolve("yoga-layout/dist/yoga.wasm")));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.yoga = loadYoga;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
// Fallback
|
|
29
|
+
try {
|
|
30
|
+
const yoga = require("yoga-layout");
|
|
31
|
+
this.yoga = yoga;
|
|
32
|
+
}
|
|
33
|
+
catch (e2) {
|
|
34
|
+
console.error("Failed to initialize Yoga Layout", e, e2);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
calculateLayout(root, width, height, ctx, canvas) {
|
|
39
|
+
if (!this.yoga) {
|
|
40
|
+
if (this.debug)
|
|
41
|
+
LazyUtil_1.LazyLog.log("warn", "LayoutManager: Yoga not initialized yet");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const rootNode = this.createNode(root, ctx, canvas);
|
|
45
|
+
if (!rootNode)
|
|
46
|
+
return;
|
|
47
|
+
rootNode.setWidth(width);
|
|
48
|
+
rootNode.setHeight(height);
|
|
49
|
+
rootNode.calculateLayout(width, height, this.yoga.DIRECTION_LTR);
|
|
50
|
+
this.applyLayout(rootNode, root);
|
|
51
|
+
// Clean up
|
|
52
|
+
this.freeNode(rootNode);
|
|
53
|
+
}
|
|
54
|
+
createNode(layer, ctx, canvas) {
|
|
55
|
+
if (!this.yoga)
|
|
56
|
+
return null;
|
|
57
|
+
const node = this.yoga.Node.create();
|
|
58
|
+
const layout = layer.props?.layout || {};
|
|
59
|
+
const size = layer.props?.size || {};
|
|
60
|
+
// Apply explicit layout properties first
|
|
61
|
+
if (layout.width !== undefined) {
|
|
62
|
+
this.setDimension(node, "width", layout.width);
|
|
63
|
+
}
|
|
64
|
+
else if (size.width !== undefined && layer.type !== types_1.LayerType.Text) {
|
|
65
|
+
// For TextLayer, skip size.width to allow measureFunc to work
|
|
66
|
+
this.setDimension(node, "width", size.width);
|
|
67
|
+
}
|
|
68
|
+
else if ((layer instanceof components_1.Div || layer.type === "group") && !layout.flexDirection) {
|
|
69
|
+
// For Div without explicit width and not a flex container, stretch to parent
|
|
70
|
+
// Flex containers should shrink-wrap their content by default
|
|
71
|
+
node.setWidthPercent(100);
|
|
72
|
+
}
|
|
73
|
+
if (layout.height !== undefined) {
|
|
74
|
+
this.setDimension(node, "height", layout.height);
|
|
75
|
+
}
|
|
76
|
+
else if (size.height !== undefined && layer.type !== types_1.LayerType.Text) {
|
|
77
|
+
// For TextLayer, skip size.height to allow measureFunc to work
|
|
78
|
+
this.setDimension(node, "height", size.height);
|
|
79
|
+
}
|
|
80
|
+
else if ((layer instanceof components_1.Div || layer.type === "group") && !layout.flexDirection) {
|
|
81
|
+
// For Div without explicit height and not a flex container, stretch to parent
|
|
82
|
+
// Flex containers should shrink-wrap their content by default
|
|
83
|
+
node.setHeightPercent(100);
|
|
84
|
+
}
|
|
85
|
+
if (layout.flexDirection)
|
|
86
|
+
node.setFlexDirection(this.getFlexDirection(layout.flexDirection));
|
|
87
|
+
if (layout.justifyContent)
|
|
88
|
+
node.setJustifyContent(this.getJustifyContent(layout.justifyContent));
|
|
89
|
+
if (layout.alignItems)
|
|
90
|
+
node.setAlignItems(this.getAlignItems(layout.alignItems));
|
|
91
|
+
if (layout.flexGrow !== undefined)
|
|
92
|
+
node.setFlexGrow(layout.flexGrow);
|
|
93
|
+
if (layout.flexShrink !== undefined)
|
|
94
|
+
node.setFlexShrink(layout.flexShrink);
|
|
95
|
+
if (layout.flexBasis !== undefined)
|
|
96
|
+
node.setFlexBasis(layout.flexBasis);
|
|
97
|
+
if (layout.padding)
|
|
98
|
+
this.setPadding(node, layout.padding);
|
|
99
|
+
if (layout.margin)
|
|
100
|
+
this.setMargin(node, layout.margin);
|
|
101
|
+
if (layout.gap !== undefined)
|
|
102
|
+
node.setGap(this.yoga.GUTTER_ALL, layout.gap);
|
|
103
|
+
// Position type (relative/absolute)
|
|
104
|
+
const isAbsolute = layout.position === "absolute";
|
|
105
|
+
if (isAbsolute) {
|
|
106
|
+
node.setPositionType(this.yoga.POSITION_TYPE_ABSOLUTE);
|
|
107
|
+
// Position values (top, left, right, bottom) - only for absolute positioning
|
|
108
|
+
if (layout.top !== undefined)
|
|
109
|
+
node.setPosition(this.yoga.EDGE_TOP, layout.top);
|
|
110
|
+
if (layout.left !== undefined)
|
|
111
|
+
node.setPosition(this.yoga.EDGE_LEFT, layout.left);
|
|
112
|
+
if (layout.right !== undefined)
|
|
113
|
+
node.setPosition(this.yoga.EDGE_RIGHT, layout.right);
|
|
114
|
+
if (layout.bottom !== undefined)
|
|
115
|
+
node.setPosition(this.yoga.EDGE_BOTTOM, layout.bottom);
|
|
116
|
+
}
|
|
117
|
+
// If not absolute, ignore top/left/right/bottom as they break flexbox layout
|
|
118
|
+
// Handle TextLayer measurement
|
|
119
|
+
if (layer.type === types_1.LayerType.Text && ctx && canvas) {
|
|
120
|
+
node.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
121
|
+
const textLayer = layer;
|
|
122
|
+
// Save original align/baseline for accurate measurement
|
|
123
|
+
const originalAlign = textLayer.props.align;
|
|
124
|
+
const originalBaseline = textLayer.props.baseline;
|
|
125
|
+
// Set to top-left for measurement (Yoga expects top-left coordinates)
|
|
126
|
+
textLayer.props.align = "left";
|
|
127
|
+
textLayer.props.baseline = "top";
|
|
128
|
+
// Temporarily disable multiline and width to measure natural size
|
|
129
|
+
const originalSize = textLayer.props.size ? { ...textLayer.props.size } : undefined;
|
|
130
|
+
const originalMultiline = textLayer.props.multiline
|
|
131
|
+
? { ...textLayer.props.multiline }
|
|
132
|
+
: undefined;
|
|
133
|
+
// Disable multiline for measurement
|
|
134
|
+
if (textLayer.props.multiline) {
|
|
135
|
+
textLayer.props.multiline.enabled = false;
|
|
136
|
+
}
|
|
137
|
+
// Don't set width constraint for natural measurement
|
|
138
|
+
if (textLayer.props.size) {
|
|
139
|
+
textLayer.props.size.width = undefined;
|
|
140
|
+
}
|
|
141
|
+
const size = textLayer.measureText(ctx, canvas);
|
|
142
|
+
// Restore original props
|
|
143
|
+
if (originalSize)
|
|
144
|
+
textLayer.props.size = originalSize;
|
|
145
|
+
if (originalMultiline)
|
|
146
|
+
textLayer.props.multiline = originalMultiline;
|
|
147
|
+
textLayer.props.align = originalAlign;
|
|
148
|
+
textLayer.props.baseline = originalBaseline;
|
|
149
|
+
return { width: Math.ceil(size.width), height: Math.ceil(size.height) };
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Handle children
|
|
153
|
+
if (layer instanceof components_1.Div || (layer.type === "group" && "layers" in layer)) {
|
|
154
|
+
const children = layer.layers;
|
|
155
|
+
let childIndex = 0;
|
|
156
|
+
children.forEach((child) => {
|
|
157
|
+
const childLayout = child.props?.layout;
|
|
158
|
+
const childPosition = child.props?.position;
|
|
159
|
+
// IMPORTANT: Logic for deciding if child participates in Yoga layout:
|
|
160
|
+
// 1. Div/containers always participate (they manage their own children)
|
|
161
|
+
// 2. If layer has explicit position prop (x or y set), skip Yoga - use position-based positioning
|
|
162
|
+
// 3. If layer has explicit layout prop, use Yoga layout
|
|
163
|
+
// 4. Otherwise (no position, no layout), use Yoga layout by default for proper flow
|
|
164
|
+
const isContainer = child instanceof components_1.Div || child.type === "group";
|
|
165
|
+
const hasExplicitPosition = childPosition && (childPosition.x !== undefined || childPosition.y !== undefined);
|
|
166
|
+
const hasExplicitLayout = childLayout !== undefined && Object.keys(childLayout).length > 0;
|
|
167
|
+
// Skip Yoga layout if:
|
|
168
|
+
// - Not a container AND has explicit position set (user wants manual positioning)
|
|
169
|
+
if (!isContainer && hasExplicitPosition && !hasExplicitLayout) {
|
|
170
|
+
return; // Skip this child - it will use position-based positioning
|
|
171
|
+
}
|
|
172
|
+
const childNode = this.createNode(child, ctx, canvas);
|
|
173
|
+
if (childNode) {
|
|
174
|
+
node.insertChild(childNode, childIndex++);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
else if ("children" in layer && Array.isArray(layer.children)) {
|
|
179
|
+
const children = layer.children;
|
|
180
|
+
let childIndex = 0;
|
|
181
|
+
children.forEach((child) => {
|
|
182
|
+
const childLayout = child.props?.layout;
|
|
183
|
+
const childPosition = child.props?.position;
|
|
184
|
+
const isContainer = child instanceof components_1.Div || child.type === "group";
|
|
185
|
+
const hasExplicitPosition = childPosition && (childPosition.x !== undefined || childPosition.y !== undefined);
|
|
186
|
+
const hasExplicitLayout = childLayout !== undefined && Object.keys(childLayout).length > 0;
|
|
187
|
+
if (!isContainer && hasExplicitPosition && !hasExplicitLayout) {
|
|
188
|
+
return; // Skip this child - it will use position-based positioning
|
|
189
|
+
}
|
|
190
|
+
const childNode = this.createNode(child, ctx, canvas);
|
|
191
|
+
if (childNode) {
|
|
192
|
+
node.insertChild(childNode, childIndex++);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return node;
|
|
197
|
+
}
|
|
198
|
+
applyLayout(node, layer) {
|
|
199
|
+
const layout = node.getComputedLayout();
|
|
200
|
+
// Debug logging if enabled
|
|
201
|
+
if (this.debug) {
|
|
202
|
+
console.log(`[Layout] ${layer.id}: left=${layout.left}, top=${layout.top}, width=${layout.width}, height=${layout.height}`);
|
|
203
|
+
}
|
|
204
|
+
// Apply computed layout to layer props
|
|
205
|
+
// We need to be careful not to overwrite original props if we want to recalculate
|
|
206
|
+
// But for rendering, we need the absolute positions.
|
|
207
|
+
// Maybe we should store computed layout separately or update position?
|
|
208
|
+
// For now, let's update position and size if they are not fixed?
|
|
209
|
+
// Or better, update a specific 'computedLayout' property if we added one.
|
|
210
|
+
// Since we didn't add 'computedLayout', let's update position.
|
|
211
|
+
// Note: Yoga calculates relative positions. We might need to convert to absolute if the renderer expects absolute.
|
|
212
|
+
// But if the renderer handles hierarchy (Div draws children), relative is fine.
|
|
213
|
+
if (!layer.props)
|
|
214
|
+
layer.props = {};
|
|
215
|
+
if (!layer.props.position)
|
|
216
|
+
layer.props.position = { x: 0, y: 0 };
|
|
217
|
+
// Mark that this layer has computed layout from Yoga
|
|
218
|
+
// This will be used by TextLayer to know it should use top-left alignment
|
|
219
|
+
layer.props._computedLayout = true;
|
|
220
|
+
// Update position
|
|
221
|
+
layer.props.position.x = layout.left;
|
|
222
|
+
layer.props.position.y = layout.top;
|
|
223
|
+
// If layout is applied, we should probably force centring to top-left (start-top)
|
|
224
|
+
// to match Yoga's coordinate system
|
|
225
|
+
if ("centring" in layer.props) {
|
|
226
|
+
layer.props.centring = "start-top"; // or "none" depending on implementation
|
|
227
|
+
}
|
|
228
|
+
// Update size if applicable (e.g. Div or layers that support size)
|
|
229
|
+
if ("size" in layer.props) {
|
|
230
|
+
// @ts-ignore
|
|
231
|
+
const currentSize = layer.props.size;
|
|
232
|
+
// @ts-ignore
|
|
233
|
+
layer.props.size = { ...currentSize, width: layout.width, height: layout.height };
|
|
234
|
+
}
|
|
235
|
+
else if (layer instanceof components_1.Div) {
|
|
236
|
+
// Div doesn't have size prop usually, but maybe it should?
|
|
237
|
+
}
|
|
238
|
+
// Recursively apply to children
|
|
239
|
+
if (layer instanceof components_1.Div || (layer.type === "group" && "layers" in layer)) {
|
|
240
|
+
const children = layer.layers;
|
|
241
|
+
let yogaChildIndex = 0;
|
|
242
|
+
for (let i = 0; i < children.length; i++) {
|
|
243
|
+
const child = children[i];
|
|
244
|
+
// Check if this child was added to Yoga tree
|
|
245
|
+
// Must match the logic in createNode
|
|
246
|
+
const childLayout = child.props?.layout;
|
|
247
|
+
const childPosition = child.props?.position;
|
|
248
|
+
const isContainer = child instanceof components_1.Div || child.type === "group";
|
|
249
|
+
const hasExplicitPosition = childPosition && (childPosition.x !== undefined || childPosition.y !== undefined);
|
|
250
|
+
const hasExplicitLayout = childLayout !== undefined && Object.keys(childLayout).length > 0;
|
|
251
|
+
// Skip if this child wasn't added to Yoga tree
|
|
252
|
+
if (!isContainer && hasExplicitPosition && !hasExplicitLayout) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const childNode = node.getChild(yogaChildIndex++);
|
|
256
|
+
if (childNode) {
|
|
257
|
+
this.applyLayout(childNode, child);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if ("children" in layer && Array.isArray(layer.children)) {
|
|
262
|
+
const children = layer.children;
|
|
263
|
+
let yogaChildIndex = 0;
|
|
264
|
+
for (let i = 0; i < children.length; i++) {
|
|
265
|
+
const child = children[i];
|
|
266
|
+
const childLayout = child.props?.layout;
|
|
267
|
+
const childPosition = child.props?.position;
|
|
268
|
+
const isContainer = child instanceof components_1.Div || child.type === "group";
|
|
269
|
+
const hasExplicitPosition = childPosition && (childPosition.x !== undefined || childPosition.y !== undefined);
|
|
270
|
+
const hasExplicitLayout = childLayout !== undefined && Object.keys(childLayout).length > 0;
|
|
271
|
+
if (!isContainer && hasExplicitPosition && !hasExplicitLayout) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const childNode = node.getChild(yogaChildIndex++);
|
|
275
|
+
if (childNode) {
|
|
276
|
+
this.applyLayout(childNode, child);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
freeNode(node) {
|
|
282
|
+
// Recursively free nodes? Yoga might handle this if we free root?
|
|
283
|
+
// Yoga JS usually requires manual freeing.
|
|
284
|
+
// node.freeRecursive(); // if available
|
|
285
|
+
if (node.freeRecursive) {
|
|
286
|
+
node.freeRecursive();
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
node.free();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Helpers for Yoga enums
|
|
293
|
+
getFlexDirection(dir) {
|
|
294
|
+
switch (dir) {
|
|
295
|
+
case "row":
|
|
296
|
+
return this.yoga.FLEX_DIRECTION_ROW;
|
|
297
|
+
case "column":
|
|
298
|
+
return this.yoga.FLEX_DIRECTION_COLUMN;
|
|
299
|
+
case "row-reverse":
|
|
300
|
+
return this.yoga.FLEX_DIRECTION_ROW_REVERSE;
|
|
301
|
+
case "column-reverse":
|
|
302
|
+
return this.yoga.FLEX_DIRECTION_COLUMN_REVERSE;
|
|
303
|
+
default:
|
|
304
|
+
return this.yoga.FLEX_DIRECTION_ROW;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
getJustifyContent(justify) {
|
|
308
|
+
switch (justify) {
|
|
309
|
+
case "flex-start":
|
|
310
|
+
return this.yoga.JUSTIFY_FLEX_START;
|
|
311
|
+
case "center":
|
|
312
|
+
return this.yoga.JUSTIFY_CENTER;
|
|
313
|
+
case "flex-end":
|
|
314
|
+
return this.yoga.JUSTIFY_FLEX_END;
|
|
315
|
+
case "space-between":
|
|
316
|
+
return this.yoga.JUSTIFY_SPACE_BETWEEN;
|
|
317
|
+
case "space-around":
|
|
318
|
+
return this.yoga.JUSTIFY_SPACE_AROUND;
|
|
319
|
+
case "space-evenly":
|
|
320
|
+
return this.yoga.JUSTIFY_SPACE_EVENLY;
|
|
321
|
+
default:
|
|
322
|
+
return this.yoga.JUSTIFY_FLEX_START;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
getAlignItems(align) {
|
|
326
|
+
switch (align) {
|
|
327
|
+
case "flex-start":
|
|
328
|
+
return this.yoga.ALIGN_FLEX_START;
|
|
329
|
+
case "center":
|
|
330
|
+
return this.yoga.ALIGN_CENTER;
|
|
331
|
+
case "flex-end":
|
|
332
|
+
return this.yoga.ALIGN_FLEX_END;
|
|
333
|
+
case "stretch":
|
|
334
|
+
return this.yoga.ALIGN_STRETCH;
|
|
335
|
+
case "baseline":
|
|
336
|
+
return this.yoga.ALIGN_BASELINE;
|
|
337
|
+
default:
|
|
338
|
+
return this.yoga.ALIGN_STRETCH;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
getPositionType(position) {
|
|
342
|
+
if (position === "absolute")
|
|
343
|
+
return this.yoga.POSITION_TYPE_ABSOLUTE;
|
|
344
|
+
return this.yoga.POSITION_TYPE_RELATIVE;
|
|
345
|
+
}
|
|
346
|
+
setDimension(node, prop, value) {
|
|
347
|
+
if (typeof value === "number") {
|
|
348
|
+
if (prop === "width")
|
|
349
|
+
node.setWidth(value);
|
|
350
|
+
else
|
|
351
|
+
node.setHeight(value);
|
|
352
|
+
}
|
|
353
|
+
else if (typeof value === "string") {
|
|
354
|
+
if (value.endsWith("%")) {
|
|
355
|
+
const val = parseFloat(value);
|
|
356
|
+
if (prop === "width")
|
|
357
|
+
node.setWidthPercent(val);
|
|
358
|
+
else
|
|
359
|
+
node.setHeightPercent(val);
|
|
360
|
+
}
|
|
361
|
+
else if (value === "auto") {
|
|
362
|
+
if (prop === "width")
|
|
363
|
+
node.setWidthAuto();
|
|
364
|
+
else
|
|
365
|
+
node.setHeightAuto();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
setPadding(node, padding) {
|
|
370
|
+
if (typeof padding === "number") {
|
|
371
|
+
node.setPadding(this.yoga.EDGE_ALL, padding);
|
|
372
|
+
}
|
|
373
|
+
else if (Array.isArray(padding)) {
|
|
374
|
+
// CSS order: top, right, bottom, left
|
|
375
|
+
if (padding.length === 1)
|
|
376
|
+
node.setPadding(this.yoga.EDGE_ALL, padding[0]);
|
|
377
|
+
else if (padding.length === 2) {
|
|
378
|
+
node.setPadding(this.yoga.EDGE_VERTICAL, padding[0]);
|
|
379
|
+
node.setPadding(this.yoga.EDGE_HORIZONTAL, padding[1]);
|
|
380
|
+
}
|
|
381
|
+
else if (padding.length === 4) {
|
|
382
|
+
node.setPadding(this.yoga.EDGE_TOP, padding[0]);
|
|
383
|
+
node.setPadding(this.yoga.EDGE_RIGHT, padding[1]);
|
|
384
|
+
node.setPadding(this.yoga.EDGE_BOTTOM, padding[2]);
|
|
385
|
+
node.setPadding(this.yoga.EDGE_LEFT, padding[3]);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
setMargin(node, margin) {
|
|
390
|
+
if (typeof margin === "number") {
|
|
391
|
+
node.setMargin(this.yoga.EDGE_ALL, margin);
|
|
392
|
+
}
|
|
393
|
+
else if (Array.isArray(margin)) {
|
|
394
|
+
if (margin.length === 1)
|
|
395
|
+
node.setMargin(this.yoga.EDGE_ALL, margin[0]);
|
|
396
|
+
else if (margin.length === 2) {
|
|
397
|
+
node.setMargin(this.yoga.EDGE_VERTICAL, margin[0]);
|
|
398
|
+
node.setMargin(this.yoga.EDGE_HORIZONTAL, margin[1]);
|
|
399
|
+
}
|
|
400
|
+
else if (margin.length === 4) {
|
|
401
|
+
node.setMargin(this.yoga.EDGE_TOP, margin[0]);
|
|
402
|
+
node.setMargin(this.yoga.EDGE_RIGHT, margin[1]);
|
|
403
|
+
node.setMargin(this.yoga.EDGE_BOTTOM, margin[2]);
|
|
404
|
+
node.setMargin(this.yoga.EDGE_LEFT, margin[3]);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
exports.LayoutManager = LayoutManager;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from './RenderManager';
|
|
5
|
-
export * from './AnimationManager';
|
|
1
|
+
export * from "./LayersManager";
|
|
2
|
+
export * from "./FontsManager";
|
|
3
|
+
export * from "./piplines";
|
|
@@ -15,7 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./LayersManager"), exports);
|
|
18
|
-
__exportStar(require("./PluginManager"), exports);
|
|
19
18
|
__exportStar(require("./FontsManager"), exports);
|
|
20
|
-
__exportStar(require("./
|
|
21
|
-
__exportStar(require("./AnimationManager"), exports);
|
|
19
|
+
__exportStar(require("./piplines"), exports);
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import { AnyExport } from "
|
|
2
|
-
import { LazyCanvas } from "
|
|
1
|
+
import { AnyExport } from "../../../types";
|
|
2
|
+
import { LazyCanvas } from "../../LazyCanvas";
|
|
3
3
|
import { Canvas, SKRSContext2D, SvgCanvas } from "@napi-rs/canvas";
|
|
4
|
-
|
|
5
|
-
* Interface representing the RenderManager.
|
|
6
|
-
*/
|
|
7
|
-
export interface IRenderManager {
|
|
8
|
-
/**
|
|
9
|
-
* The LazyCanvas instance used for rendering.
|
|
10
|
-
*/
|
|
11
|
-
lazyCanvas: LazyCanvas;
|
|
12
|
-
/**
|
|
13
|
-
* Whether debugging is enabled.
|
|
14
|
-
*/
|
|
15
|
-
debug: boolean;
|
|
16
|
-
}
|
|
4
|
+
import { IRenderManager } from "./index";
|
|
17
5
|
/**
|
|
18
6
|
* Class responsible for managing rendering operations, including static and animated exports.
|
|
19
7
|
*/
|
|
20
|
-
export declare class
|
|
8
|
+
export declare class ClassicRenderPipeline implements IRenderManager {
|
|
21
9
|
/**
|
|
22
10
|
* The LazyCanvas instance used for rendering.
|
|
23
11
|
*/
|
|
@@ -35,15 +23,6 @@ export declare class RenderManager implements IRenderManager {
|
|
|
35
23
|
constructor(lazyCanvas: LazyCanvas, opts?: {
|
|
36
24
|
debug?: boolean;
|
|
37
25
|
});
|
|
38
|
-
/**
|
|
39
|
-
* Merges multiple ImageData objects into a single ImageData object.
|
|
40
|
-
* @param {SKRSContext2D} [ctx] - The canvas rendering context.
|
|
41
|
-
* @param {ImageData[]} [imageDataList] - The list of ImageData objects to merge.
|
|
42
|
-
* @param {number} [width] - The width of the resulting ImageData.
|
|
43
|
-
* @param {number} [height] - The height of the resulting ImageData.
|
|
44
|
-
* @returns {ImageData} The merged ImageData object.
|
|
45
|
-
*/
|
|
46
|
-
private mergeImageData;
|
|
47
26
|
/**
|
|
48
27
|
* Renders a single layer or group of layers.
|
|
49
28
|
* @param {AnyLayer | Group} [layer] - The layer or group to render.
|
|
@@ -56,11 +35,6 @@ export declare class RenderManager implements IRenderManager {
|
|
|
56
35
|
* @returns {Promise<Buffer | SKRSContext2D | string>} The rendered output in the specified format.
|
|
57
36
|
*/
|
|
58
37
|
private renderStatic;
|
|
59
|
-
/**
|
|
60
|
-
* Renders an animated sequence of layers and exports it as a GIF.
|
|
61
|
-
* @returns {Promise<Buffer>} The rendered animation as a Buffer.
|
|
62
|
-
*/
|
|
63
|
-
private renderAnimation;
|
|
64
38
|
/**
|
|
65
39
|
* Renders all layers and exports the result in the specified format.
|
|
66
40
|
* @param {AnyExport} [format] - The export format (e.g., buffer, context, SVG, or canvas).
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClassicRenderPipeline = void 0;
|
|
4
|
+
const types_1 = require("../../../types");
|
|
5
|
+
const LazyUtil_1 = require("../../../utils/LazyUtil");
|
|
6
|
+
/**
|
|
7
|
+
* Class responsible for managing rendering operations, including static and animated exports.
|
|
8
|
+
*/
|
|
9
|
+
class ClassicRenderPipeline {
|
|
10
|
+
/**
|
|
11
|
+
* Constructs a new RenderManager instance.
|
|
12
|
+
* @param {LazyCanvas} [lazyCanvas] - The LazyCanvas instance to use for rendering.
|
|
13
|
+
* @param {Object} [opts] - Optional settings for the RenderManager.
|
|
14
|
+
* @param {boolean} [opts.debug] - Whether debugging is enabled.
|
|
15
|
+
*/
|
|
16
|
+
constructor(lazyCanvas, opts) {
|
|
17
|
+
this.lazyCanvas = lazyCanvas;
|
|
18
|
+
this.debug = opts?.debug || false;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Renders a single layer or group of layers.
|
|
22
|
+
* @param {AnyLayer | Group} [layer] - The layer or group to render.
|
|
23
|
+
* @returns {Promise<SKRSContext2D>} The canvas rendering context after rendering.
|
|
24
|
+
*/
|
|
25
|
+
async renderLayer(layer) {
|
|
26
|
+
if (this.debug)
|
|
27
|
+
LazyUtil_1.LazyLog.log("info", `Rendering ${layer.id}...\nData:`, layer.toJSON());
|
|
28
|
+
if (layer.visible) {
|
|
29
|
+
this.lazyCanvas.ctx.globalCompositeOperation = layer.props?.globalComposite || "source-over";
|
|
30
|
+
await layer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.manager.layers, this.debug);
|
|
31
|
+
this.lazyCanvas.ctx.shadowColor = "transparent";
|
|
32
|
+
}
|
|
33
|
+
return this.lazyCanvas.ctx;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Renders all layers statically and exports the result in the specified format.
|
|
37
|
+
* @param {AnyExport} [exportType] - The export format (e.g., buffer, SVG, or context).
|
|
38
|
+
* @returns {Promise<Buffer | SKRSContext2D | string>} The rendered output in the specified format.
|
|
39
|
+
*/
|
|
40
|
+
async renderStatic(exportType) {
|
|
41
|
+
if (this.debug)
|
|
42
|
+
LazyUtil_1.LazyLog.log("info", `Rendering static...`);
|
|
43
|
+
for (const layer of this.lazyCanvas.manager.layers.toArray()) {
|
|
44
|
+
await this.renderLayer(layer);
|
|
45
|
+
}
|
|
46
|
+
switch (exportType) {
|
|
47
|
+
case types_1.Export.BUFFER:
|
|
48
|
+
case "buffer":
|
|
49
|
+
case types_1.Export.SVG:
|
|
50
|
+
case "svg":
|
|
51
|
+
if ("getContent" in this.lazyCanvas.canvas) {
|
|
52
|
+
return this.lazyCanvas.canvas.getContent().toString("utf8");
|
|
53
|
+
}
|
|
54
|
+
return this.lazyCanvas.canvas.toBuffer("image/png");
|
|
55
|
+
case types_1.Export.CTX:
|
|
56
|
+
case "ctx":
|
|
57
|
+
return this.lazyCanvas.ctx;
|
|
58
|
+
default:
|
|
59
|
+
if ("getContent" in this.lazyCanvas.canvas) {
|
|
60
|
+
return this.lazyCanvas.canvas.getContent().toString("utf8");
|
|
61
|
+
}
|
|
62
|
+
return this.lazyCanvas.canvas.toBuffer("image/png");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Renders all layers and exports the result in the specified format.
|
|
67
|
+
* @param {AnyExport} [format] - The export format (e.g., buffer, context, SVG, or canvas).
|
|
68
|
+
* @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The rendered output in the specified format.
|
|
69
|
+
*/
|
|
70
|
+
async render(format) {
|
|
71
|
+
switch (format) {
|
|
72
|
+
case types_1.Export.BUFFER:
|
|
73
|
+
case "buffer":
|
|
74
|
+
return await this.renderStatic(types_1.Export.BUFFER);
|
|
75
|
+
case types_1.Export.CTX:
|
|
76
|
+
case "ctx":
|
|
77
|
+
return await this.renderStatic(types_1.Export.CTX);
|
|
78
|
+
case types_1.Export.SVG:
|
|
79
|
+
case "svg":
|
|
80
|
+
return await this.renderStatic(types_1.Export.SVG);
|
|
81
|
+
case types_1.Export.CANVAS:
|
|
82
|
+
case "canvas":
|
|
83
|
+
await this.renderStatic(this.lazyCanvas.options.exportType === "svg" ? types_1.Export.SVG : types_1.Export.BUFFER);
|
|
84
|
+
return this.lazyCanvas.canvas;
|
|
85
|
+
default:
|
|
86
|
+
return await this.renderStatic(types_1.Export.BUFFER);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.ClassicRenderPipeline = ClassicRenderPipeline;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AnyExport } from "../../../types";
|
|
2
|
+
import { LazyCanvas } from "../../LazyCanvas";
|
|
3
|
+
import { Canvas, SKRSContext2D, SvgCanvas } from "@napi-rs/canvas";
|
|
4
|
+
import { IRenderManager } from "./index";
|
|
5
|
+
/**
|
|
6
|
+
* Class responsible for managing rendering operations, including static and animated exports.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ModernRenderPipeline implements IRenderManager {
|
|
9
|
+
/**
|
|
10
|
+
* The LazyCanvas instance used for rendering.
|
|
11
|
+
*/
|
|
12
|
+
lazyCanvas: LazyCanvas;
|
|
13
|
+
/**
|
|
14
|
+
* Whether debugging is enabled.
|
|
15
|
+
*/
|
|
16
|
+
debug: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Constructs a new RenderManager instance.
|
|
19
|
+
* @param {LazyCanvas} [lazyCanvas] - The LazyCanvas instance to use for rendering.
|
|
20
|
+
* @param {Object} [opts] - Optional settings for the RenderManager.
|
|
21
|
+
* @param {boolean} [opts.debug] - Whether debugging is enabled.
|
|
22
|
+
*/
|
|
23
|
+
constructor(lazyCanvas: LazyCanvas, opts?: {
|
|
24
|
+
debug?: boolean;
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Renders a single layer or group of layers.
|
|
28
|
+
* @param {AnyLayer | Div} [layer] - The layer or group to render.
|
|
29
|
+
* @returns {Promise<SKRSContext2D>} The canvas rendering context after rendering.
|
|
30
|
+
*/
|
|
31
|
+
private renderLayer;
|
|
32
|
+
/**
|
|
33
|
+
* Renders all layers statically and exports the result in the specified format.
|
|
34
|
+
* @param {AnyExport} [exportType] - The export format (e.g., buffer, SVG, or context).
|
|
35
|
+
* @returns {Promise<Buffer | SKRSContext2D | string>} The rendered output in the specified format.
|
|
36
|
+
*/
|
|
37
|
+
private renderStatic;
|
|
38
|
+
/**
|
|
39
|
+
* Renders all layers and exports the result in the specified format.
|
|
40
|
+
* @param {AnyExport} [format] - The export format (e.g., buffer, context, SVG, or canvas).
|
|
41
|
+
* @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The rendered output in the specified format.
|
|
42
|
+
*/
|
|
43
|
+
render(format: AnyExport): Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>;
|
|
44
|
+
}
|