@meonode/canvas 1.0.0-beta.3 → 1.0.0-beta.5
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/cjs/canvas/canvas.helper.d.ts +9 -11
- package/dist/cjs/canvas/canvas.helper.d.ts.map +1 -1
- package/dist/cjs/canvas/canvas.helper.js +47 -48
- package/dist/cjs/canvas/canvas.helper.js.map +1 -1
- package/dist/cjs/canvas/canvas.type.d.ts +31 -31
- package/dist/cjs/canvas/canvas.type.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.d.ts +4 -4
- package/dist/cjs/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.js +21 -4
- package/dist/cjs/canvas/grid.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/image.canvas.util.d.ts +0 -1
- package/dist/cjs/canvas/image.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/image.canvas.util.js +72 -72
- package/dist/cjs/canvas/image.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/layout.canvas.util.d.ts +16 -17
- package/dist/cjs/canvas/layout.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/layout.canvas.util.js +17 -24
- package/dist/cjs/canvas/layout.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/root.canvas.util.d.ts +4 -2
- package/dist/cjs/canvas/root.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/root.canvas.util.js +7 -3
- package/dist/cjs/canvas/root.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.d.ts +20 -27
- package/dist/cjs/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.js +27 -45
- package/dist/cjs/canvas/text.canvas.util.js.map +1 -1
- package/dist/esm/canvas/canvas.helper.d.ts +9 -11
- package/dist/esm/canvas/canvas.helper.d.ts.map +1 -1
- package/dist/esm/canvas/canvas.helper.js +47 -48
- package/dist/esm/canvas/canvas.type.d.ts +31 -31
- package/dist/esm/canvas/canvas.type.d.ts.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.d.ts +4 -4
- package/dist/esm/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.js +21 -4
- package/dist/esm/canvas/image.canvas.util.d.ts +0 -1
- package/dist/esm/canvas/image.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/image.canvas.util.js +72 -72
- package/dist/esm/canvas/layout.canvas.util.d.ts +16 -17
- package/dist/esm/canvas/layout.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/layout.canvas.util.js +17 -24
- package/dist/esm/canvas/root.canvas.util.d.ts +4 -2
- package/dist/esm/canvas/root.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/root.canvas.util.js +7 -3
- package/dist/esm/canvas/text.canvas.util.d.ts +20 -27
- package/dist/esm/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/text.canvas.util.js +27 -45
- package/package.json +16 -9
|
@@ -4,6 +4,7 @@ import { parseBorderRadius, drawRoundedRectPath } from './canvas.helper.js';
|
|
|
4
4
|
import { promises } from 'fs';
|
|
5
5
|
import { Style } from '../constant/common.const.js';
|
|
6
6
|
|
|
7
|
+
// TODO: Add comprehensive unit tests for this file.
|
|
7
8
|
/**
|
|
8
9
|
* Calculates pixel offset for image positioning based on percentage or pixel values.
|
|
9
10
|
* This handles centering, edge alignment, and percentage-based positioning.
|
|
@@ -43,7 +44,6 @@ class ImageNode extends BoxNode {
|
|
|
43
44
|
/**
|
|
44
45
|
* Loads and processes an image from various sources (URL, file path, or Buffer).
|
|
45
46
|
* Handles SVG color modifications and sets natural dimensions with an aspect ratio.
|
|
46
|
-
*
|
|
47
47
|
* @returns Promise that resolves when image loading completes
|
|
48
48
|
* @throws Error if image loading fails
|
|
49
49
|
*/
|
|
@@ -59,92 +59,92 @@ class ImageNode extends BoxNode {
|
|
|
59
59
|
this.naturalHeight = 0;
|
|
60
60
|
return Promise.resolve();
|
|
61
61
|
}
|
|
62
|
-
return new Promise(
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (this.props.src
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
isSvg = detectedMime === 'image/svg+xml';
|
|
81
|
-
if ((!detectedMime || detectedMime === 'application/xml') &&
|
|
82
|
-
contentBuffer.toString('utf-8').includes('<svg')) {
|
|
83
|
-
isSvg = true;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
finalSource = this.props.src;
|
|
88
|
-
const filePath = this.props.src;
|
|
89
|
-
try {
|
|
90
|
-
const fileTypeResult = await fileTypeFromFile(filePath);
|
|
62
|
+
return new Promise(resolve => {
|
|
63
|
+
const load = async () => {
|
|
64
|
+
const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type');
|
|
65
|
+
let finalSource = this.props.src;
|
|
66
|
+
let isSvg = false;
|
|
67
|
+
let contentBuffer = null;
|
|
68
|
+
let detectedMime;
|
|
69
|
+
try {
|
|
70
|
+
if (typeof this.props.src === 'string') {
|
|
71
|
+
if (this.props.src.startsWith('http')) {
|
|
72
|
+
const response = await fetch(this.props.src);
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`);
|
|
75
|
+
}
|
|
76
|
+
const imageArrayBuffer = await response.arrayBuffer();
|
|
77
|
+
contentBuffer = Buffer.from(imageArrayBuffer);
|
|
78
|
+
finalSource = contentBuffer;
|
|
79
|
+
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
91
80
|
detectedMime = fileTypeResult?.mime;
|
|
92
81
|
isSvg = detectedMime === 'image/svg+xml';
|
|
93
|
-
if ((!detectedMime || detectedMime === 'application/xml') &&
|
|
82
|
+
if ((!detectedMime || detectedMime === 'application/xml') && contentBuffer.toString('utf-8').includes('<svg')) {
|
|
94
83
|
isSvg = true;
|
|
95
84
|
}
|
|
96
85
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (isSvg && this.props.color) {
|
|
86
|
+
else {
|
|
87
|
+
finalSource = this.props.src;
|
|
88
|
+
const filePath = this.props.src;
|
|
101
89
|
try {
|
|
102
|
-
|
|
90
|
+
const fileTypeResult = await fileTypeFromFile(filePath);
|
|
91
|
+
detectedMime = fileTypeResult?.mime;
|
|
92
|
+
isSvg = detectedMime === 'image/svg+xml';
|
|
93
|
+
if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {
|
|
94
|
+
isSvg = true;
|
|
95
|
+
}
|
|
103
96
|
}
|
|
104
97
|
catch {
|
|
105
|
-
isSvg =
|
|
106
|
-
|
|
98
|
+
isSvg = filePath.toLowerCase().endsWith('.svg');
|
|
99
|
+
}
|
|
100
|
+
if (isSvg && this.props.color) {
|
|
101
|
+
try {
|
|
102
|
+
contentBuffer = await promises.readFile(filePath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
isSvg = false;
|
|
106
|
+
contentBuffer = null;
|
|
107
|
+
}
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
contentBuffer = this.props.src;
|
|
113
|
-
finalSource = contentBuffer;
|
|
114
|
-
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
115
|
-
detectedMime = fileTypeResult?.mime;
|
|
116
|
-
isSvg = detectedMime === 'image/svg+xml';
|
|
117
|
-
}
|
|
118
|
-
if (isSvg && this.props.color && contentBuffer) {
|
|
119
|
-
const svgString = contentBuffer.toString('utf-8');
|
|
120
|
-
const modifiedSvgString = svgString.replace(/fill="[^"]*"/g, `fill="${this.props.color}"`);
|
|
121
|
-
if (modifiedSvgString !== svgString) {
|
|
122
|
-
finalSource = Buffer.from(modifiedSvgString);
|
|
123
|
-
}
|
|
124
111
|
else {
|
|
112
|
+
contentBuffer = this.props.src;
|
|
125
113
|
finalSource = contentBuffer;
|
|
114
|
+
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
115
|
+
detectedMime = fileTypeResult?.mime;
|
|
116
|
+
isSvg = detectedMime === 'image/svg+xml';
|
|
126
117
|
}
|
|
118
|
+
if (isSvg && this.props.color && contentBuffer) {
|
|
119
|
+
const svgString = contentBuffer.toString('utf-8');
|
|
120
|
+
const modifiedSvgString = svgString.replace(/fill="[^"]*"/g, `fill="${this.props.color}"`);
|
|
121
|
+
if (modifiedSvgString !== svgString) {
|
|
122
|
+
finalSource = Buffer.from(modifiedSvgString);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
finalSource = contentBuffer;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const img = await loadImage(finalSource);
|
|
129
|
+
this.loadedImage = img;
|
|
130
|
+
this.naturalWidth = img.width;
|
|
131
|
+
this.naturalHeight = img.height;
|
|
132
|
+
const calculatedAspectRatio = this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined;
|
|
133
|
+
const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio;
|
|
134
|
+
this.node.setAspectRatio(finalAspectRatio);
|
|
135
|
+
this.props.onLoad?.();
|
|
136
|
+
resolve();
|
|
127
137
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
resolve();
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
this.naturalWidth = 0;
|
|
142
|
-
this.naturalHeight = 0;
|
|
143
|
-
const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined;
|
|
144
|
-
this.node.setAspectRatio(finalAspectRatioOnError);
|
|
145
|
-
this.props.onError?.(error);
|
|
146
|
-
resolve();
|
|
147
|
-
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.naturalWidth = 0;
|
|
140
|
+
this.naturalHeight = 0;
|
|
141
|
+
const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined;
|
|
142
|
+
this.node.setAspectRatio(finalAspectRatioOnError);
|
|
143
|
+
this.props.onError?.(error);
|
|
144
|
+
resolve();
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
load();
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
150
|
getLoadingPromise() {
|
|
@@ -33,7 +33,7 @@ export declare class BoxNode {
|
|
|
33
33
|
key?: string;
|
|
34
34
|
/**
|
|
35
35
|
* Creates a new BoxNode instance
|
|
36
|
-
* @param props
|
|
36
|
+
* @param props Initial box properties and styling
|
|
37
37
|
*/
|
|
38
38
|
constructor(props?: BoxProps & BaseProps);
|
|
39
39
|
/**
|
|
@@ -42,7 +42,7 @@ export declare class BoxNode {
|
|
|
42
42
|
processInitialChildren(): void;
|
|
43
43
|
/**
|
|
44
44
|
* Inherits styles from the parent node.
|
|
45
|
-
* @param {BoxProps & BaseProps} parentProps
|
|
45
|
+
* @param {BoxProps & BaseProps} parentProps Parent node properties to inherit from.
|
|
46
46
|
*/
|
|
47
47
|
protected resolveInheritedStyles(parentProps: BoxProps & BaseProps): void;
|
|
48
48
|
/**
|
|
@@ -51,8 +51,8 @@ export declare class BoxNode {
|
|
|
51
51
|
protected applyDefaults(): void;
|
|
52
52
|
/**
|
|
53
53
|
* Appends a child node at the specified index.
|
|
54
|
-
* @param {BoxNode} child
|
|
55
|
-
* @param index
|
|
54
|
+
* @param {BoxNode} child Child node to append.
|
|
55
|
+
* @param index Index to insert child at
|
|
56
56
|
*/
|
|
57
57
|
protected appendChild(child: BoxNode, index: number): void;
|
|
58
58
|
/**
|
|
@@ -66,31 +66,30 @@ export declare class BoxNode {
|
|
|
66
66
|
protected updateLayoutBasedOnComputedSize(): void;
|
|
67
67
|
/**
|
|
68
68
|
* Applies layout properties to the Yoga node.
|
|
69
|
-
* @param props
|
|
69
|
+
* @param props Box properties containing layout values
|
|
70
70
|
*/
|
|
71
71
|
protected setLayout(props: BoxProps): void;
|
|
72
72
|
/**
|
|
73
73
|
* Renders the node and its children to the canvas.
|
|
74
|
-
* @param {CanvasRenderingContext2D} ctx
|
|
75
|
-
* @param {number} offsetX
|
|
76
|
-
* @param {number} offsetY
|
|
74
|
+
* @param {CanvasRenderingContext2D} ctx Canvas rendering context (from skia-canvas).
|
|
75
|
+
* @param {number} offsetX X offset for rendering.
|
|
76
|
+
* @param {number} offsetY Y offset for rendering.
|
|
77
77
|
*/
|
|
78
78
|
render(ctx: CanvasRenderingContext2D, offsetX?: number, offsetY?: number): void;
|
|
79
79
|
/**
|
|
80
80
|
* Renders the node's visual content including background fills, shadows, and borders.
|
|
81
81
|
* This is an internal method used by the render() pipeline.
|
|
82
|
-
*
|
|
83
|
-
* @param
|
|
84
|
-
* @param
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @param height - The height of the content area to render
|
|
82
|
+
* @param ctx The skia-canvas 2D rendering context to draw into
|
|
83
|
+
* @param x The absolute x-coordinate where drawing should begin
|
|
84
|
+
* @param y The absolute y-coordinate where drawing should begin
|
|
85
|
+
* @param width The width of the content area to render
|
|
86
|
+
* @param height The height of the content area to render
|
|
88
87
|
*/
|
|
89
88
|
protected _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number): void;
|
|
90
89
|
}
|
|
91
90
|
/**
|
|
92
91
|
* Creates a new BoxNode instance.
|
|
93
|
-
* @param {BoxProps} props
|
|
92
|
+
* @param {BoxProps} props Box properties and configuration.
|
|
94
93
|
* @returns {BoxNode} New BoxNode instance.
|
|
95
94
|
*/
|
|
96
95
|
export declare const Box: (props: BoxProps) => BoxNode;
|
|
@@ -103,7 +102,7 @@ export declare class ColumnNode extends BoxNode {
|
|
|
103
102
|
}
|
|
104
103
|
/**
|
|
105
104
|
* Creates a new ColumnNode instance.
|
|
106
|
-
* @param {BoxProps} props
|
|
105
|
+
* @param {BoxProps} props Column properties and configuration.
|
|
107
106
|
* @returns {ColumnNode} New ColumnNode instance.
|
|
108
107
|
*/
|
|
109
108
|
export declare const Column: (props: BoxProps) => ColumnNode;
|
|
@@ -116,7 +115,7 @@ export declare class RowNode extends BoxNode {
|
|
|
116
115
|
}
|
|
117
116
|
/**
|
|
118
117
|
* Creates a new RowNode instance.
|
|
119
|
-
* @param {BoxProps} props
|
|
118
|
+
* @param {BoxProps} props Row properties and configuration.
|
|
120
119
|
* @returns {RowNode} New RowNode instance.
|
|
121
120
|
*/
|
|
122
121
|
export declare const Row: (props: BoxProps) => RowNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/layout.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,yBAAyB,CAAA;AAGlF,OAAa,EAAS,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;;;GAIG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"layout.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/layout.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,yBAAyB,CAAA;AAGlF,OAAa,EAAS,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;;;GAIG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE/B;;OAEG;IACH,IAAI,EAAE,IAAI,CAAA;IAEV;;OAEG;IACH,QAAQ,EAAE,OAAO,EAAE,CAAA;IAEnB;;OAEG;IACH,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAA;IAE3B;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;OAGG;gBACS,KAAK,GAAE,QAAQ,GAAG,SAAc;IAqB5C;;OAEG;IACI,sBAAsB;IAW7B;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,WAAW,EAAE,QAAQ,GAAG,SAAS;IAkClE;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAI/B;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;IAanD;;;OAGG;IACI,cAAc,IAAI,OAAO;IAiBhC;;OAEG;IACH,SAAS,CAAC,+BAA+B;IAIzC;;;OAGG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ;IAqInC;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,wBAAwB,EAAE,OAAO,GAAE,MAAU,EAAE,OAAO,GAAE,MAAU;IA+J9E;;;;;;;;OAQG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAoR5G;AAED;;;;GAIG;AACH,eAAO,MAAM,GAAG,GAAI,OAAO,QAAQ,KAAG,OAA6B,CAAA;AAEnE;;;GAGG;AACH,qBAAa,UAAW,SAAQ,OAAO;gBACzB,KAAK,GAAE,QAAQ,GAAG,SAAc;CAS7C;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,QAAQ,KAAG,UAAmC,CAAA;AAE5E;;;GAGG;AACH,qBAAa,OAAQ,SAAQ,OAAO;gBACtB,KAAK,GAAE,QAAQ,GAAG,SAAc;CAS7C;AAED;;;;GAIG;AACH,eAAO,MAAM,GAAG,GAAI,OAAO,QAAQ,KAAG,OAA6B,CAAA"}
|
|
@@ -37,7 +37,7 @@ class BoxNode {
|
|
|
37
37
|
key;
|
|
38
38
|
/**
|
|
39
39
|
* Creates a new BoxNode instance
|
|
40
|
-
* @param props
|
|
40
|
+
* @param props Initial box properties and styling
|
|
41
41
|
*/
|
|
42
42
|
constructor(props = {}) {
|
|
43
43
|
const children = (Array.isArray(props?.children) ? props.children : [props.children]).filter(child => child);
|
|
@@ -72,7 +72,7 @@ class BoxNode {
|
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
74
|
* Inherits styles from the parent node.
|
|
75
|
-
* @param {BoxProps & BaseProps} parentProps
|
|
75
|
+
* @param {BoxProps & BaseProps} parentProps Parent node properties to inherit from.
|
|
76
76
|
*/
|
|
77
77
|
resolveInheritedStyles(parentProps) {
|
|
78
78
|
if (parentProps.key) {
|
|
@@ -112,8 +112,8 @@ class BoxNode {
|
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
114
|
* Appends a child node at the specified index.
|
|
115
|
-
* @param {BoxNode} child
|
|
116
|
-
* @param index
|
|
115
|
+
* @param {BoxNode} child Child node to append.
|
|
116
|
+
* @param index Index to insert child at
|
|
117
117
|
*/
|
|
118
118
|
appendChild(child, index) {
|
|
119
119
|
if (!child || !child.node) {
|
|
@@ -152,7 +152,7 @@ class BoxNode {
|
|
|
152
152
|
}
|
|
153
153
|
/**
|
|
154
154
|
* Applies layout properties to the Yoga node.
|
|
155
|
-
* @param props
|
|
155
|
+
* @param props Box properties containing layout values
|
|
156
156
|
*/
|
|
157
157
|
setLayout(props) {
|
|
158
158
|
// --- Yoga layout property application ---
|
|
@@ -295,9 +295,9 @@ class BoxNode {
|
|
|
295
295
|
}
|
|
296
296
|
/**
|
|
297
297
|
* Renders the node and its children to the canvas.
|
|
298
|
-
* @param {CanvasRenderingContext2D} ctx
|
|
299
|
-
* @param {number} offsetX
|
|
300
|
-
* @param {number} offsetY
|
|
298
|
+
* @param {CanvasRenderingContext2D} ctx Canvas rendering context (from skia-canvas).
|
|
299
|
+
* @param {number} offsetX X offset for rendering.
|
|
300
|
+
* @param {number} offsetY Y offset for rendering.
|
|
301
301
|
*/
|
|
302
302
|
render(ctx, offsetX = 0, offsetY = 0) {
|
|
303
303
|
const layout = this.node.getComputedLayout();
|
|
@@ -322,13 +322,7 @@ class BoxNode {
|
|
|
322
322
|
try {
|
|
323
323
|
// --- Transformation Setup ---
|
|
324
324
|
const transform = this.props.transform;
|
|
325
|
-
const needsTransform = transform &&
|
|
326
|
-
(transform.translateX ||
|
|
327
|
-
transform.translateY ||
|
|
328
|
-
transform.rotate ||
|
|
329
|
-
transform.scale ||
|
|
330
|
-
transform.scaleX ||
|
|
331
|
-
transform.scaleY);
|
|
325
|
+
const needsTransform = transform && (transform.translateX || transform.translateY || transform.rotate || transform.scale || transform.scaleX || transform.scaleY);
|
|
332
326
|
let savedContextForTransform = false;
|
|
333
327
|
if (needsTransform) {
|
|
334
328
|
ctx.save();
|
|
@@ -455,12 +449,11 @@ class BoxNode {
|
|
|
455
449
|
/**
|
|
456
450
|
* Renders the node's visual content including background fills, shadows, and borders.
|
|
457
451
|
* This is an internal method used by the render() pipeline.
|
|
458
|
-
*
|
|
459
|
-
* @param
|
|
460
|
-
* @param
|
|
461
|
-
* @param
|
|
462
|
-
* @param
|
|
463
|
-
* @param height - The height of the content area to render
|
|
452
|
+
* @param ctx The skia-canvas 2D rendering context to draw into
|
|
453
|
+
* @param x The absolute x-coordinate where drawing should begin
|
|
454
|
+
* @param y The absolute y-coordinate where drawing should begin
|
|
455
|
+
* @param width The width of the content area to render
|
|
456
|
+
* @param height The height of the content area to render
|
|
464
457
|
*/
|
|
465
458
|
_renderContent(ctx, x, y, width, height) {
|
|
466
459
|
// Calculate border radius values for all corners
|
|
@@ -727,7 +720,7 @@ class BoxNode {
|
|
|
727
720
|
}
|
|
728
721
|
/**
|
|
729
722
|
* Creates a new BoxNode instance.
|
|
730
|
-
* @param {BoxProps} props
|
|
723
|
+
* @param {BoxProps} props Box properties and configuration.
|
|
731
724
|
* @returns {BoxNode} New BoxNode instance.
|
|
732
725
|
*/
|
|
733
726
|
const Box = (props) => new BoxNode(props);
|
|
@@ -748,7 +741,7 @@ class ColumnNode extends BoxNode {
|
|
|
748
741
|
}
|
|
749
742
|
/**
|
|
750
743
|
* Creates a new ColumnNode instance.
|
|
751
|
-
* @param {BoxProps} props
|
|
744
|
+
* @param {BoxProps} props Column properties and configuration.
|
|
752
745
|
* @returns {ColumnNode} New ColumnNode instance.
|
|
753
746
|
*/
|
|
754
747
|
const Column = (props) => new ColumnNode(props);
|
|
@@ -769,7 +762,7 @@ class RowNode extends BoxNode {
|
|
|
769
762
|
}
|
|
770
763
|
/**
|
|
771
764
|
* Creates a new RowNode instance.
|
|
772
|
-
* @param {BoxProps} props
|
|
765
|
+
* @param {BoxProps} props Row properties and configuration.
|
|
773
766
|
* @returns {RowNode} New RowNode instance.
|
|
774
767
|
*/
|
|
775
768
|
const Row = (props) => new RowNode(props);
|
|
@@ -13,11 +13,13 @@ export declare class RootNode extends ColumnNode {
|
|
|
13
13
|
private ctx;
|
|
14
14
|
/** Target width for the canvas in pixels */
|
|
15
15
|
private readonly targetWidth;
|
|
16
|
+
/** Target height for the canvas in pixels */
|
|
17
|
+
private readonly targetHeight;
|
|
16
18
|
/** Scale factor for rendering (e.g. 2 for 2x resolution) */
|
|
17
19
|
private readonly scale;
|
|
18
20
|
/**
|
|
19
21
|
* Creates a new root node for canvas rendering
|
|
20
|
-
* @param props
|
|
22
|
+
* @param props Configuration properties for the root node
|
|
21
23
|
* @throws Error if width property is not provided
|
|
22
24
|
*/
|
|
23
25
|
constructor(props: RootProps & BaseProps);
|
|
@@ -35,7 +37,7 @@ export declare class RootNode extends ColumnNode {
|
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Creates and renders a new root node with the given properties
|
|
38
|
-
* @param props
|
|
40
|
+
* @param props Configuration properties for the root node
|
|
39
41
|
* @returns Promise resolving to the rendered Canvas instance
|
|
40
42
|
*/
|
|
41
43
|
export declare const Root: (props: RootProps) => Promise<Canvas>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/root.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA8C,MAAM,aAAa,CAAA;AAChF,OAAO,EAAE,UAAU,EAAW,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAUnE,eAAO,MAAM,qBAAqB,YAEjC,CAAA;AAED;;;GAGG;AACH,qBAAa,QAAS,SAAQ,UAAU;IACtC,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAwC;IACnD,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAE9B;;;;OAIG;gBACS,KAAK,EAAE,SAAS,GAAG,SAAS;
|
|
1
|
+
{"version":3,"file":"root.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/root.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA8C,MAAM,aAAa,CAAA;AAChF,OAAO,EAAE,UAAU,EAAW,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAUnE,eAAO,MAAM,qBAAqB,YAEjC,CAAA;AAED;;;GAGG;AACH,qBAAa,QAAS,SAAQ,UAAU;IACtC,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAwC;IACnD,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAE9B;;;;OAIG;gBACS,KAAK,EAAE,SAAS,GAAG,SAAS;IAyCxC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;CAqChC;AAED;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAU,OAAO,SAAS,oBAAuC,CAAA"}
|
|
@@ -18,16 +18,19 @@ class RootNode extends ColumnNode {
|
|
|
18
18
|
ctx = null;
|
|
19
19
|
/** Target width for the canvas in pixels */
|
|
20
20
|
targetWidth;
|
|
21
|
+
/** Target height for the canvas in pixels */
|
|
22
|
+
targetHeight;
|
|
21
23
|
/** Scale factor for rendering (e.g. 2 for 2x resolution) */
|
|
22
24
|
scale;
|
|
23
25
|
/**
|
|
24
26
|
* Creates a new root node for canvas rendering
|
|
25
|
-
* @param props
|
|
27
|
+
* @param props Configuration properties for the root node
|
|
26
28
|
* @throws Error if width property is not provided
|
|
27
29
|
*/
|
|
28
30
|
constructor(props) {
|
|
29
31
|
// Call the parent constructor with root name and props
|
|
30
32
|
super({ name: 'Root', ...props });
|
|
33
|
+
this.props = props;
|
|
31
34
|
// Validate the required width property
|
|
32
35
|
if (!props.width) {
|
|
33
36
|
throw new Error('Width and height are required for Root');
|
|
@@ -51,6 +54,7 @@ class RootNode extends ColumnNode {
|
|
|
51
54
|
// Set up scale and width
|
|
52
55
|
this.scale = props.scale || 1;
|
|
53
56
|
this.targetWidth = props.width;
|
|
57
|
+
this.targetHeight = props.height;
|
|
54
58
|
this.node.setWidth(this.targetWidth);
|
|
55
59
|
// Initialize children nodes
|
|
56
60
|
this.processInitialChildren();
|
|
@@ -93,7 +97,7 @@ class RootNode extends ColumnNode {
|
|
|
93
97
|
// Step 4: Create a canvas with calculated dimensions
|
|
94
98
|
const calculatedContentHeight = this.node.getComputedHeight();
|
|
95
99
|
const finalCanvasWidth = Math.ceil(this.targetWidth * this.scale);
|
|
96
|
-
const finalCanvasHeight = Math.max(1, Math.ceil(calculatedContentHeight * this.scale));
|
|
100
|
+
const finalCanvasHeight = this.targetHeight ? Math.ceil(this.targetHeight * this.scale) : Math.max(1, Math.ceil(calculatedContentHeight * this.scale));
|
|
97
101
|
// Step 5: Set up canvas context
|
|
98
102
|
this.canvas = new Canvas(finalCanvasWidth, finalCanvasHeight);
|
|
99
103
|
this.ctx = this.canvas.getContext('2d');
|
|
@@ -108,7 +112,7 @@ class RootNode extends ColumnNode {
|
|
|
108
112
|
}
|
|
109
113
|
/**
|
|
110
114
|
* Creates and renders a new root node with the given properties
|
|
111
|
-
* @param props
|
|
115
|
+
* @param props Configuration properties for the root node
|
|
112
116
|
* @returns Promise resolving to the rendered Canvas instance
|
|
113
117
|
*/
|
|
114
118
|
const Root = async (props) => await new RootNode(props).render();
|
|
@@ -33,8 +33,7 @@ export declare class TextNode extends BoxNode {
|
|
|
33
33
|
* - \b - Backspace (removed)
|
|
34
34
|
* - \f - Form feed (treated as newline)
|
|
35
35
|
* - \v - Vertical tab (treated as newline)
|
|
36
|
-
*
|
|
37
|
-
* @param input - Raw text string potentially containing escape sequences
|
|
36
|
+
* @param input Raw text string potentially containing escape sequences
|
|
38
37
|
* @returns Processed string with escape sequences converted
|
|
39
38
|
*/
|
|
40
39
|
private processEscapeSequences;
|
|
@@ -52,9 +51,8 @@ export declare class TextNode extends BoxNode {
|
|
|
52
51
|
* <color="red">, <color='red'>, <color=red>
|
|
53
52
|
*
|
|
54
53
|
* Tags can be nested and must be properly closed with </tag>
|
|
55
|
-
*
|
|
56
|
-
* @param
|
|
57
|
-
* @param baseStyle - Default style properties to apply to all segments
|
|
54
|
+
* @param input Text string containing markup tags
|
|
55
|
+
* @param baseStyle Default style properties to apply to all segments
|
|
58
56
|
* @returns Array of styled text segments with consistent style properties
|
|
59
57
|
*/
|
|
60
58
|
private parseRichText;
|
|
@@ -69,8 +67,7 @@ export declare class TextNode extends BoxNode {
|
|
|
69
67
|
* - Style: segment <i> > base fontStyle
|
|
70
68
|
* - Size: segment size > base fontSize
|
|
71
69
|
* - Family: base fontFamily
|
|
72
|
-
*
|
|
73
|
-
* @param segmentStyle - Optional TextSegment styling to override base props
|
|
70
|
+
* @param segmentStyle Optional TextSegment styling to override base props
|
|
74
71
|
* @returns Formatted CSS font string for canvas context
|
|
75
72
|
*/
|
|
76
73
|
private getFontString;
|
|
@@ -87,33 +84,30 @@ export declare class TextNode extends BoxNode {
|
|
|
87
84
|
* 2. Otherwise calculating dynamic height based on largest font size per line
|
|
88
85
|
* 3. Adding leading space above/below text content
|
|
89
86
|
* 4. Including specified line gaps between lines
|
|
90
|
-
*
|
|
91
|
-
* @param
|
|
92
|
-
* @param widthMode - YogaLayout mode determining how width constraint is applied
|
|
87
|
+
* @param widthConstraint Maximum allowed width in pixels for text layout
|
|
88
|
+
* @param widthMode YogaLayout mode determining how width constraint is applied
|
|
93
89
|
* @returns Calculated minimum dimensions required to render text content
|
|
94
|
-
*
|
|
95
|
-
*
|
|
90
|
+
* - width: Total width needed for text layout
|
|
91
|
+
* - height: Total height including line heights and gaps
|
|
96
92
|
*/
|
|
97
93
|
private measureText;
|
|
98
94
|
/**
|
|
99
95
|
* Wraps text segments into multiple lines while respecting width constraints and preserving styling.
|
|
100
96
|
* Handles rich text attributes (color, weight, size, bold, italic) and proper word wrapping.
|
|
101
97
|
* Also respects explicit newline characters (\n) for forced line breaks.
|
|
102
|
-
*
|
|
103
|
-
* @param
|
|
104
|
-
* @param
|
|
105
|
-
* @param
|
|
106
|
-
* @param parsedWordSpacingPx - Additional spacing to add between words in pixels
|
|
98
|
+
* @param ctx Canvas rendering context used for text measurements
|
|
99
|
+
* @param segments Array of text segments with styling information
|
|
100
|
+
* @param maxWidth Maximum allowed width for each line in pixels
|
|
101
|
+
* @param parsedWordSpacingPx Additional spacing to add between words in pixels
|
|
107
102
|
* @returns Array of lines, where each line contains styled text segments
|
|
108
103
|
*/
|
|
109
104
|
private wrapTextRich;
|
|
110
105
|
/**
|
|
111
106
|
* Breaks a word segment into multiple segments that each fit within the specified width constraint.
|
|
112
107
|
* Maintains all styling properties (color, weight, size, bold, italic) across broken segments.
|
|
113
|
-
*
|
|
114
|
-
* @param
|
|
115
|
-
* @param
|
|
116
|
-
* @param maxWidth - Maximum width allowed for each resulting segment
|
|
108
|
+
* @param ctx Canvas rendering context used for text measurements
|
|
109
|
+
* @param segmentToBreak Original text segment to split
|
|
110
|
+
* @param maxWidth Maximum width allowed for each resulting segment
|
|
117
111
|
* @returns Array of TextSegments, each fitting maxWidth, or original segment if no breaking needed
|
|
118
112
|
*/
|
|
119
113
|
private breakWordRich;
|
|
@@ -132,12 +126,11 @@ export declare class TextNode extends BoxNode {
|
|
|
132
126
|
* - Ellipsis truncation
|
|
133
127
|
* - Rich text styling per segment (color, weight, size, etc)
|
|
134
128
|
* - Performance optimizations (clipping, visibility checks)
|
|
135
|
-
*
|
|
136
|
-
* @param
|
|
137
|
-
* @param
|
|
138
|
-
* @param
|
|
139
|
-
* @param
|
|
140
|
-
* @param height - Content box total height including padding
|
|
129
|
+
* @param ctx Canvas rendering context
|
|
130
|
+
* @param x Content box left position in pixels
|
|
131
|
+
* @param y Content box top position in pixels
|
|
132
|
+
* @param width Content box total width including padding
|
|
133
|
+
* @param height Content box total height including padding
|
|
141
134
|
*/
|
|
142
135
|
protected _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number): void;
|
|
143
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;cAuB1C,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;IA8NnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IAuKpB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAmErB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;;;;;;;;;;;;;OAgBG;cACgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CA8UrH;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,SAAS,aAA8B,CAAA"}
|