@meonode/canvas 1.0.0-beta.4 → 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/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 +39 -47
- package/dist/cjs/canvas/canvas.helper.js.map +1 -1
- package/dist/cjs/canvas/canvas.type.d.ts +1 -1
- 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 +39 -47
- package/dist/esm/canvas/canvas.type.d.ts +1 -1
- 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 +5 -9
|
@@ -6,6 +6,7 @@ var canvas_helper = require('./canvas.helper.js');
|
|
|
6
6
|
var fs = require('fs');
|
|
7
7
|
var common_const = require('../constant/common.const.js');
|
|
8
8
|
|
|
9
|
+
// TODO: Add comprehensive unit tests for this file.
|
|
9
10
|
/**
|
|
10
11
|
* Calculates pixel offset for image positioning based on percentage or pixel values.
|
|
11
12
|
* This handles centering, edge alignment, and percentage-based positioning.
|
|
@@ -45,7 +46,6 @@ class ImageNode extends layout_canvas_util.BoxNode {
|
|
|
45
46
|
/**
|
|
46
47
|
* Loads and processes an image from various sources (URL, file path, or Buffer).
|
|
47
48
|
* Handles SVG color modifications and sets natural dimensions with an aspect ratio.
|
|
48
|
-
*
|
|
49
49
|
* @returns Promise that resolves when image loading completes
|
|
50
50
|
* @throws Error if image loading fails
|
|
51
51
|
*/
|
|
@@ -61,92 +61,92 @@ class ImageNode extends layout_canvas_util.BoxNode {
|
|
|
61
61
|
this.naturalHeight = 0;
|
|
62
62
|
return Promise.resolve();
|
|
63
63
|
}
|
|
64
|
-
return new Promise(
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (this.props.src
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
isSvg = detectedMime === 'image/svg+xml';
|
|
83
|
-
if ((!detectedMime || detectedMime === 'application/xml') &&
|
|
84
|
-
contentBuffer.toString('utf-8').includes('<svg')) {
|
|
85
|
-
isSvg = true;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
finalSource = this.props.src;
|
|
90
|
-
const filePath = this.props.src;
|
|
91
|
-
try {
|
|
92
|
-
const fileTypeResult = await fileTypeFromFile(filePath);
|
|
64
|
+
return new Promise(resolve => {
|
|
65
|
+
const load = async () => {
|
|
66
|
+
const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type');
|
|
67
|
+
let finalSource = this.props.src;
|
|
68
|
+
let isSvg = false;
|
|
69
|
+
let contentBuffer = null;
|
|
70
|
+
let detectedMime;
|
|
71
|
+
try {
|
|
72
|
+
if (typeof this.props.src === 'string') {
|
|
73
|
+
if (this.props.src.startsWith('http')) {
|
|
74
|
+
const response = await fetch(this.props.src);
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`);
|
|
77
|
+
}
|
|
78
|
+
const imageArrayBuffer = await response.arrayBuffer();
|
|
79
|
+
contentBuffer = Buffer.from(imageArrayBuffer);
|
|
80
|
+
finalSource = contentBuffer;
|
|
81
|
+
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
93
82
|
detectedMime = fileTypeResult?.mime;
|
|
94
83
|
isSvg = detectedMime === 'image/svg+xml';
|
|
95
|
-
if ((!detectedMime || detectedMime === 'application/xml') &&
|
|
84
|
+
if ((!detectedMime || detectedMime === 'application/xml') && contentBuffer.toString('utf-8').includes('<svg')) {
|
|
96
85
|
isSvg = true;
|
|
97
86
|
}
|
|
98
87
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (isSvg && this.props.color) {
|
|
88
|
+
else {
|
|
89
|
+
finalSource = this.props.src;
|
|
90
|
+
const filePath = this.props.src;
|
|
103
91
|
try {
|
|
104
|
-
|
|
92
|
+
const fileTypeResult = await fileTypeFromFile(filePath);
|
|
93
|
+
detectedMime = fileTypeResult?.mime;
|
|
94
|
+
isSvg = detectedMime === 'image/svg+xml';
|
|
95
|
+
if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {
|
|
96
|
+
isSvg = true;
|
|
97
|
+
}
|
|
105
98
|
}
|
|
106
99
|
catch {
|
|
107
|
-
isSvg =
|
|
108
|
-
|
|
100
|
+
isSvg = filePath.toLowerCase().endsWith('.svg');
|
|
101
|
+
}
|
|
102
|
+
if (isSvg && this.props.color) {
|
|
103
|
+
try {
|
|
104
|
+
contentBuffer = await fs.promises.readFile(filePath);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
isSvg = false;
|
|
108
|
+
contentBuffer = null;
|
|
109
|
+
}
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
contentBuffer = this.props.src;
|
|
115
|
-
finalSource = contentBuffer;
|
|
116
|
-
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
117
|
-
detectedMime = fileTypeResult?.mime;
|
|
118
|
-
isSvg = detectedMime === 'image/svg+xml';
|
|
119
|
-
}
|
|
120
|
-
if (isSvg && this.props.color && contentBuffer) {
|
|
121
|
-
const svgString = contentBuffer.toString('utf-8');
|
|
122
|
-
const modifiedSvgString = svgString.replace(/fill="[^"]*"/g, `fill="${this.props.color}"`);
|
|
123
|
-
if (modifiedSvgString !== svgString) {
|
|
124
|
-
finalSource = Buffer.from(modifiedSvgString);
|
|
125
|
-
}
|
|
126
113
|
else {
|
|
114
|
+
contentBuffer = this.props.src;
|
|
127
115
|
finalSource = contentBuffer;
|
|
116
|
+
const fileTypeResult = await fileTypeFromBuffer(contentBuffer);
|
|
117
|
+
detectedMime = fileTypeResult?.mime;
|
|
118
|
+
isSvg = detectedMime === 'image/svg+xml';
|
|
128
119
|
}
|
|
120
|
+
if (isSvg && this.props.color && contentBuffer) {
|
|
121
|
+
const svgString = contentBuffer.toString('utf-8');
|
|
122
|
+
const modifiedSvgString = svgString.replace(/fill="[^"]*"/g, `fill="${this.props.color}"`);
|
|
123
|
+
if (modifiedSvgString !== svgString) {
|
|
124
|
+
finalSource = Buffer.from(modifiedSvgString);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
finalSource = contentBuffer;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const img = await skiaCanvas.loadImage(finalSource);
|
|
131
|
+
this.loadedImage = img;
|
|
132
|
+
this.naturalWidth = img.width;
|
|
133
|
+
this.naturalHeight = img.height;
|
|
134
|
+
const calculatedAspectRatio = this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined;
|
|
135
|
+
const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio;
|
|
136
|
+
this.node.setAspectRatio(finalAspectRatio);
|
|
137
|
+
this.props.onLoad?.();
|
|
138
|
+
resolve();
|
|
129
139
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
resolve();
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
this.naturalWidth = 0;
|
|
144
|
-
this.naturalHeight = 0;
|
|
145
|
-
const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined;
|
|
146
|
-
this.node.setAspectRatio(finalAspectRatioOnError);
|
|
147
|
-
this.props.onError?.(error);
|
|
148
|
-
resolve();
|
|
149
|
-
}
|
|
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
|
+
}
|
|
148
|
+
};
|
|
149
|
+
load();
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
getLoadingPromise() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.canvas.util.js","sources":["../../../../src/canvas/image.canvas.util.ts"],"sourcesContent":["import type { BaseProps, ImageProps } from '@/canvas/canvas.type.js'\nimport { type CanvasRenderingContext2D, Image as CanvasImage, loadImage } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.util.js'\nimport { drawRoundedRectPath, parseBorderRadius } from '@/canvas/canvas.helper.js'\nimport { promises as fs } from 'fs'\nimport { Style } from '@/constant/common.const.js'\n\n/**\n * Calculates pixel offset for image positioning based on percentage or pixel values.\n * This handles centering, edge alignment, and percentage-based positioning.\n */\nfunction calculateOffsetFromValue(positionValue: number | `${number}%` | undefined, availableSpace: number): number {\n const value = positionValue ?? '50%'\n if (typeof value === 'number') {\n return value\n }\n if (typeof value === 'string' && value.endsWith('%')) {\n const percentage = parseFloat(value) / 100\n return availableSpace * percentage\n }\n console.warn(`[ImageNode] Invalid objectPosition value format: ${value}. Defaulting to 50%.`)\n return availableSpace * 0.5\n}\n\n/**\n * Renders images with configurable sizing, positioning, and effects.\n * Supports object-fit modes, positioning, border radius, and saturation filters.\n */\nexport class ImageNode extends BoxNode {\n declare props: ImageProps & BaseProps\n private loadedImage: CanvasImage | null = null\n private naturalWidth = 0\n private naturalHeight = 0\n private readonly loadingPromise: Promise<void> | null = null\n\n constructor(props: ImageProps) {\n super({ name: 'Image', ...props, children: undefined })\n\n this.props = {\n objectFit: 'fill',\n overflow: Style.Overflow.Hidden,\n saturate: 1,\n objectPosition: { Left: '50%', Top: '50%' },\n ...props,\n }\n\n this.loadingPromise = this._loadImage()\n }\n\n /**\n * Loads and processes an image from various sources (URL, file path, or Buffer).\n * Handles SVG color modifications and sets natural dimensions with an aspect ratio.\n *\n * @returns Promise that resolves when image loading completes\n * @throws Error if image loading fails\n */\n private _loadImage(): Promise<void> {\n if (this.loadingPromise) return this.loadingPromise\n if (this.loadedImage) return Promise.resolve()\n\n if (!this.props.src) {\n const aspectRatioFromProps =\n typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(aspectRatioFromProps)\n this.naturalWidth = 0\n this.naturalHeight = 0\n\n return Promise.resolve()\n }\n\n return new Promise(async resolve => {\n const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type')\n let finalSource: string | Buffer = this.props.src\n let isSvg = false\n let contentBuffer: Buffer | null = null\n let detectedMime: string | undefined\n\n try {\n if (typeof this.props.src === 'string') {\n if (this.props.src.startsWith('http')) {\n const response = await fetch(this.props.src)\n if (!response.ok) {\n throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`)\n }\n const imageArrayBuffer = await response.arrayBuffer()\n contentBuffer = Buffer.from(imageArrayBuffer)\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if (\n (!detectedMime || detectedMime === 'application/xml') &&\n contentBuffer.toString('utf-8').includes('<svg')\n ) {\n isSvg = true\n }\n } else {\n finalSource = this.props.src\n const filePath = this.props.src\n\n try {\n const fileTypeResult = await fileTypeFromFile(filePath)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {\n isSvg = true\n }\n } catch {\n isSvg = filePath.toLowerCase().endsWith('.svg')\n }\n\n if (isSvg && this.props.color) {\n try {\n contentBuffer = await fs.readFile(filePath)\n } catch {\n isSvg = false\n contentBuffer = null\n }\n }\n }\n } else {\n contentBuffer = this.props.src\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n }\n\n if (isSvg && this.props.color && contentBuffer) {\n const svgString = contentBuffer.toString('utf-8')\n const modifiedSvgString = svgString.replace(/fill=\"[^\"]*\"/g, `fill=\"${this.props.color}\"`)\n\n if (modifiedSvgString !== svgString) {\n finalSource = Buffer.from(modifiedSvgString)\n } else {\n finalSource = contentBuffer\n }\n }\n\n const img = await loadImage(finalSource as never)\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n\n const calculatedAspectRatio =\n this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined\n\n const finalAspectRatio =\n typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0\n ? this.props.aspectRatio\n : calculatedAspectRatio\n\n this.node.setAspectRatio(finalAspectRatio)\n\n this.props.onLoad?.()\n resolve()\n } catch (error: any) {\n this.naturalWidth = 0\n this.naturalHeight = 0\n const finalAspectRatioOnError =\n typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(finalAspectRatioOnError)\n this.props.onError?.(error)\n resolve()\n }\n })\n }\n\n public getLoadingPromise(): Promise<void> {\n return this.loadingPromise ?? Promise.resolve()\n }\n\n /**\n * Renders the image with correct sizing, clipping, and positioning.\n * Handles object-fit, object-position, and visual effects like saturation.\n */\n protected override _renderContent(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n ) {\n super._renderContent(ctx, x, y, width, height)\n\n if (!this.loadedImage || width <= 0 || height <= 0) return\n const img = this.loadedImage\n const imgW = this.naturalWidth\n const imgH = this.naturalHeight\n if (imgW <= 0 || imgH <= 0) return\n\n // Calculate content box accounting for padding and borders\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n const borderLeft = this.node.getComputedBorder(Style.Edge.Left)\n const borderTop = this.node.getComputedBorder(Style.Edge.Top)\n const borderRight = this.node.getComputedBorder(Style.Edge.Right)\n const borderBottom = this.node.getComputedBorder(Style.Edge.Bottom)\n const contentX = x + borderLeft + paddingLeft\n const contentY = y + borderTop + paddingTop\n const contentWidth = Math.max(0, width - borderLeft - paddingLeft - borderRight - paddingRight)\n const contentHeight = Math.max(0, height - borderTop - paddingTop - borderBottom - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) return\n\n // Apply clipping for border radius\n ctx.save()\n const outerRadii = parseBorderRadius(this.props.borderRadius)\n const innerBorderRadii = {\n TopLeft: Math.max(0, outerRadii.TopLeft - borderTop),\n TopRight: Math.max(0, outerRadii.TopRight - borderTop),\n BottomRight: Math.max(0, outerRadii.BottomRight - borderBottom),\n BottomLeft: Math.max(0, outerRadii.BottomLeft - borderBottom),\n }\n const contentRadii = {\n TopLeft: Math.max(0, innerBorderRadii.TopLeft - Math.max(paddingLeft, paddingTop)),\n TopRight: Math.max(0, innerBorderRadii.TopRight - Math.max(paddingRight, paddingTop)),\n BottomRight: Math.max(0, innerBorderRadii.BottomRight - Math.max(paddingRight, paddingBottom)),\n BottomLeft: Math.max(0, innerBorderRadii.BottomLeft - Math.max(paddingLeft, paddingBottom)),\n }\n drawRoundedRectPath(ctx, contentX, contentY, contentWidth, contentHeight, contentRadii)\n ctx.clip()\n\n // Calculate image dimensions based on object-fit\n const nodeRatio = contentWidth / contentHeight\n const imgRatio = imgW / imgH\n const objectFit = this.props.objectFit\n let dw = contentWidth\n let dh = contentHeight\n\n if (objectFit === 'contain') {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n } else if (objectFit === 'cover') {\n if (imgRatio > nodeRatio) {\n dh = contentHeight\n dw = contentHeight * imgRatio\n } else {\n dw = contentWidth\n dh = contentWidth / imgRatio\n }\n } else if (objectFit === 'none') {\n dw = imgW\n dh = imgH\n } else if (objectFit === 'scale-down') {\n if (imgW <= contentWidth && imgH <= contentHeight) {\n dw = imgW\n dh = imgH\n } else {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n }\n }\n\n // Calculate image position based on object-position\n const sx = 0\n const sy = 0\n const sw = imgW\n const sh = imgH\n\n const availableWidth = contentWidth - dw\n const availableHeight = contentHeight - dh\n const posProps = this.props.objectPosition || {}\n const horizontalValue =\n posProps.Left !== undefined ? posProps.Left : posProps.Right !== undefined ? posProps.Right : '50%'\n const verticalValue =\n posProps.Top !== undefined ? posProps.Top : posProps.Bottom !== undefined ? posProps.Bottom : '50%'\n\n let offsetX = calculateOffsetFromValue(horizontalValue, availableWidth)\n let offsetY = calculateOffsetFromValue(verticalValue, availableHeight)\n\n if (posProps.Left === undefined && posProps.Right !== undefined) {\n offsetX = availableWidth - offsetX\n }\n if (posProps.Top === undefined && posProps.Bottom !== undefined) {\n offsetY = availableHeight - offsetY\n }\n\n const dx = contentX + offsetX\n const dy = contentY + offsetY\n\n // Draw image with filters\n ctx.save()\n try {\n if (this.props.dropShadow) {\n const shadow = this.props.dropShadow\n const shadowBlur = Math.max(shadow.offsetX ?? 0, shadow.offsetY ?? 0)\n ctx.shadowOffsetX = shadow.offsetX ?? 0\n ctx.shadowOffsetY = shadow.offsetY ?? 0\n ctx.shadowBlur = Math.max(0, shadow.blur ?? shadowBlur)\n ctx.shadowColor = shadow.color ?? 'black'\n }\n\n const saturateValue = this.props.saturate ?? 1\n let filterString = ''\n if (saturateValue !== 1) {\n filterString += `saturate(${saturateValue * 100}%) `\n }\n\n if (filterString) {\n const currentFilter = ctx.filter && ctx.filter !== 'none' ? ctx.filter + ' ' : ''\n ctx.filter = currentFilter + filterString.trim()\n }\n\n const finalDX = Math.floor(dx)\n const finalDY = Math.floor(dy)\n const finalDW = Math.ceil(dw + (dx - finalDX))\n const finalDH = Math.ceil(dh + (dy - finalDY))\n\n if (finalDW > 0 && finalDH > 0) {\n ctx.drawImage(img, sx, sy, sw, sh, finalDX, finalDY, finalDW, finalDH)\n }\n } catch (drawError) {\n console.error('[ImageNode] Error drawing image:', drawError)\n } finally {\n ctx.restore()\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Factory function to create ImageNode instances\n */\nexport const Image = (props: ImageProps) => new ImageNode(props)\n"],"names":["BoxNode","Style","fs","loadImage","parseBorderRadius","drawRoundedRectPath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"image.canvas.util.js","sources":["../../../../src/canvas/image.canvas.util.ts"],"sourcesContent":["// TODO: Add comprehensive unit tests for this file.\n\nimport type { BaseProps, ImageProps } from '@/canvas/canvas.type.js'\nimport { type CanvasRenderingContext2D, Image as CanvasImage, loadImage } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.util.js'\nimport { drawRoundedRectPath, parseBorderRadius } from '@/canvas/canvas.helper.js'\nimport { promises as fs } from 'fs'\nimport { Style } from '@/constant/common.const.js'\n\n/**\n * Calculates pixel offset for image positioning based on percentage or pixel values.\n * This handles centering, edge alignment, and percentage-based positioning.\n */\nfunction calculateOffsetFromValue(positionValue: number | `${number}%` | undefined, availableSpace: number): number {\n const value = positionValue ?? '50%'\n if (typeof value === 'number') {\n return value\n }\n if (typeof value === 'string' && value.endsWith('%')) {\n const percentage = parseFloat(value) / 100\n return availableSpace * percentage\n }\n console.warn(`[ImageNode] Invalid objectPosition value format: ${value}. Defaulting to 50%.`)\n return availableSpace * 0.5\n}\n\n/**\n * Renders images with configurable sizing, positioning, and effects.\n * Supports object-fit modes, positioning, border radius, and saturation filters.\n */\nexport class ImageNode extends BoxNode {\n declare props: ImageProps & BaseProps\n private loadedImage: CanvasImage | null = null\n private naturalWidth = 0\n private naturalHeight = 0\n private readonly loadingPromise: Promise<void> | null = null\n\n constructor(props: ImageProps) {\n super({ name: 'Image', ...props, children: undefined })\n\n this.props = {\n objectFit: 'fill',\n overflow: Style.Overflow.Hidden,\n saturate: 1,\n objectPosition: { Left: '50%', Top: '50%' },\n ...props,\n }\n\n this.loadingPromise = this._loadImage()\n }\n\n /**\n * Loads and processes an image from various sources (URL, file path, or Buffer).\n * Handles SVG color modifications and sets natural dimensions with an aspect ratio.\n * @returns Promise that resolves when image loading completes\n * @throws Error if image loading fails\n */\n private _loadImage(): Promise<void> {\n if (this.loadingPromise) return this.loadingPromise\n if (this.loadedImage) return Promise.resolve()\n\n if (!this.props.src) {\n const aspectRatioFromProps = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(aspectRatioFromProps)\n this.naturalWidth = 0\n this.naturalHeight = 0\n\n return Promise.resolve()\n }\n\n return new Promise(resolve => {\n const load = async () => {\n const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type')\n let finalSource: string | Buffer = this.props.src\n let isSvg = false\n let contentBuffer: Buffer | null = null\n let detectedMime: string | undefined\n\n try {\n if (typeof this.props.src === 'string') {\n if (this.props.src.startsWith('http')) {\n const response = await fetch(this.props.src)\n if (!response.ok) {\n throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`)\n }\n const imageArrayBuffer = await response.arrayBuffer()\n contentBuffer = Buffer.from(imageArrayBuffer)\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && contentBuffer.toString('utf-8').includes('<svg')) {\n isSvg = true\n }\n } else {\n finalSource = this.props.src\n const filePath = this.props.src\n\n try {\n const fileTypeResult = await fileTypeFromFile(filePath)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {\n isSvg = true\n }\n } catch {\n isSvg = filePath.toLowerCase().endsWith('.svg')\n }\n\n if (isSvg && this.props.color) {\n try {\n contentBuffer = await fs.readFile(filePath)\n } catch {\n isSvg = false\n contentBuffer = null\n }\n }\n }\n } else {\n contentBuffer = this.props.src\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n }\n\n if (isSvg && this.props.color && contentBuffer) {\n const svgString = contentBuffer.toString('utf-8')\n const modifiedSvgString = svgString.replace(/fill=\"[^\"]*\"/g, `fill=\"${this.props.color}\"`)\n\n if (modifiedSvgString !== svgString) {\n finalSource = Buffer.from(modifiedSvgString)\n } else {\n finalSource = contentBuffer\n }\n }\n\n const img = await loadImage(finalSource as never)\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n\n const calculatedAspectRatio = this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined\n\n const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio\n\n this.node.setAspectRatio(finalAspectRatio)\n\n this.props.onLoad?.()\n resolve()\n } catch (error: any) {\n this.naturalWidth = 0\n this.naturalHeight = 0\n const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(finalAspectRatioOnError)\n this.props.onError?.(error)\n resolve()\n }\n }\n load()\n })\n }\n\n public getLoadingPromise(): Promise<void> {\n return this.loadingPromise ?? Promise.resolve()\n }\n\n /**\n * Renders the image with correct sizing, clipping, and positioning.\n * Handles object-fit, object-position, and visual effects like saturation.\n */\n protected override _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n super._renderContent(ctx, x, y, width, height)\n\n if (!this.loadedImage || width <= 0 || height <= 0) return\n const img = this.loadedImage\n const imgW = this.naturalWidth\n const imgH = this.naturalHeight\n if (imgW <= 0 || imgH <= 0) return\n\n // Calculate content box accounting for padding and borders\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n const borderLeft = this.node.getComputedBorder(Style.Edge.Left)\n const borderTop = this.node.getComputedBorder(Style.Edge.Top)\n const borderRight = this.node.getComputedBorder(Style.Edge.Right)\n const borderBottom = this.node.getComputedBorder(Style.Edge.Bottom)\n const contentX = x + borderLeft + paddingLeft\n const contentY = y + borderTop + paddingTop\n const contentWidth = Math.max(0, width - borderLeft - paddingLeft - borderRight - paddingRight)\n const contentHeight = Math.max(0, height - borderTop - paddingTop - borderBottom - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) return\n\n // Apply clipping for border radius\n ctx.save()\n const outerRadii = parseBorderRadius(this.props.borderRadius)\n const innerBorderRadii = {\n TopLeft: Math.max(0, outerRadii.TopLeft - borderTop),\n TopRight: Math.max(0, outerRadii.TopRight - borderTop),\n BottomRight: Math.max(0, outerRadii.BottomRight - borderBottom),\n BottomLeft: Math.max(0, outerRadii.BottomLeft - borderBottom),\n }\n const contentRadii = {\n TopLeft: Math.max(0, innerBorderRadii.TopLeft - Math.max(paddingLeft, paddingTop)),\n TopRight: Math.max(0, innerBorderRadii.TopRight - Math.max(paddingRight, paddingTop)),\n BottomRight: Math.max(0, innerBorderRadii.BottomRight - Math.max(paddingRight, paddingBottom)),\n BottomLeft: Math.max(0, innerBorderRadii.BottomLeft - Math.max(paddingLeft, paddingBottom)),\n }\n drawRoundedRectPath(ctx, contentX, contentY, contentWidth, contentHeight, contentRadii)\n ctx.clip()\n\n // Calculate image dimensions based on object-fit\n const nodeRatio = contentWidth / contentHeight\n const imgRatio = imgW / imgH\n const objectFit = this.props.objectFit\n let dw = contentWidth\n let dh = contentHeight\n\n if (objectFit === 'contain') {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n } else if (objectFit === 'cover') {\n if (imgRatio > nodeRatio) {\n dh = contentHeight\n dw = contentHeight * imgRatio\n } else {\n dw = contentWidth\n dh = contentWidth / imgRatio\n }\n } else if (objectFit === 'none') {\n dw = imgW\n dh = imgH\n } else if (objectFit === 'scale-down') {\n if (imgW <= contentWidth && imgH <= contentHeight) {\n dw = imgW\n dh = imgH\n } else {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n }\n }\n\n // Calculate image position based on object-position\n const sx = 0\n const sy = 0\n const sw = imgW\n const sh = imgH\n\n const availableWidth = contentWidth - dw\n const availableHeight = contentHeight - dh\n const posProps = this.props.objectPosition || {}\n const horizontalValue = posProps.Left !== undefined ? posProps.Left : posProps.Right !== undefined ? posProps.Right : '50%'\n const verticalValue = posProps.Top !== undefined ? posProps.Top : posProps.Bottom !== undefined ? posProps.Bottom : '50%'\n\n let offsetX = calculateOffsetFromValue(horizontalValue, availableWidth)\n let offsetY = calculateOffsetFromValue(verticalValue, availableHeight)\n\n if (posProps.Left === undefined && posProps.Right !== undefined) {\n offsetX = availableWidth - offsetX\n }\n if (posProps.Top === undefined && posProps.Bottom !== undefined) {\n offsetY = availableHeight - offsetY\n }\n\n const dx = contentX + offsetX\n const dy = contentY + offsetY\n\n // Draw image with filters\n ctx.save()\n try {\n if (this.props.dropShadow) {\n const shadow = this.props.dropShadow\n const shadowBlur = Math.max(shadow.offsetX ?? 0, shadow.offsetY ?? 0)\n ctx.shadowOffsetX = shadow.offsetX ?? 0\n ctx.shadowOffsetY = shadow.offsetY ?? 0\n ctx.shadowBlur = Math.max(0, shadow.blur ?? shadowBlur)\n ctx.shadowColor = shadow.color ?? 'black'\n }\n\n const saturateValue = this.props.saturate ?? 1\n let filterString = ''\n if (saturateValue !== 1) {\n filterString += `saturate(${saturateValue * 100}%) `\n }\n\n if (filterString) {\n const currentFilter = ctx.filter && ctx.filter !== 'none' ? ctx.filter + ' ' : ''\n ctx.filter = currentFilter + filterString.trim()\n }\n\n const finalDX = Math.floor(dx)\n const finalDY = Math.floor(dy)\n const finalDW = Math.ceil(dw + (dx - finalDX))\n const finalDH = Math.ceil(dh + (dy - finalDY))\n\n if (finalDW > 0 && finalDH > 0) {\n ctx.drawImage(img, sx, sy, sw, sh, finalDX, finalDY, finalDW, finalDH)\n }\n } catch (drawError) {\n console.error('[ImageNode] Error drawing image:', drawError)\n } finally {\n ctx.restore()\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Factory function to create ImageNode instances\n */\nexport const Image = (props: ImageProps) => new ImageNode(props)\n"],"names":["BoxNode","Style","fs","loadImage","parseBorderRadius","drawRoundedRectPath"],"mappings":"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"}
|
|
@@ -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"}
|
|
@@ -39,7 +39,7 @@ class BoxNode {
|
|
|
39
39
|
key;
|
|
40
40
|
/**
|
|
41
41
|
* Creates a new BoxNode instance
|
|
42
|
-
* @param props
|
|
42
|
+
* @param props Initial box properties and styling
|
|
43
43
|
*/
|
|
44
44
|
constructor(props = {}) {
|
|
45
45
|
const children = (Array.isArray(props?.children) ? props.children : [props.children]).filter(child => child);
|
|
@@ -74,7 +74,7 @@ class BoxNode {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Inherits styles from the parent node.
|
|
77
|
-
* @param {BoxProps & BaseProps} parentProps
|
|
77
|
+
* @param {BoxProps & BaseProps} parentProps Parent node properties to inherit from.
|
|
78
78
|
*/
|
|
79
79
|
resolveInheritedStyles(parentProps) {
|
|
80
80
|
if (parentProps.key) {
|
|
@@ -114,8 +114,8 @@ class BoxNode {
|
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Appends a child node at the specified index.
|
|
117
|
-
* @param {BoxNode} child
|
|
118
|
-
* @param index
|
|
117
|
+
* @param {BoxNode} child Child node to append.
|
|
118
|
+
* @param index Index to insert child at
|
|
119
119
|
*/
|
|
120
120
|
appendChild(child, index) {
|
|
121
121
|
if (!child || !child.node) {
|
|
@@ -154,7 +154,7 @@ class BoxNode {
|
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
156
|
* Applies layout properties to the Yoga node.
|
|
157
|
-
* @param props
|
|
157
|
+
* @param props Box properties containing layout values
|
|
158
158
|
*/
|
|
159
159
|
setLayout(props) {
|
|
160
160
|
// --- Yoga layout property application ---
|
|
@@ -297,9 +297,9 @@ class BoxNode {
|
|
|
297
297
|
}
|
|
298
298
|
/**
|
|
299
299
|
* Renders the node and its children to the canvas.
|
|
300
|
-
* @param {CanvasRenderingContext2D} ctx
|
|
301
|
-
* @param {number} offsetX
|
|
302
|
-
* @param {number} offsetY
|
|
300
|
+
* @param {CanvasRenderingContext2D} ctx Canvas rendering context (from skia-canvas).
|
|
301
|
+
* @param {number} offsetX X offset for rendering.
|
|
302
|
+
* @param {number} offsetY Y offset for rendering.
|
|
303
303
|
*/
|
|
304
304
|
render(ctx, offsetX = 0, offsetY = 0) {
|
|
305
305
|
const layout = this.node.getComputedLayout();
|
|
@@ -324,13 +324,7 @@ class BoxNode {
|
|
|
324
324
|
try {
|
|
325
325
|
// --- Transformation Setup ---
|
|
326
326
|
const transform = this.props.transform;
|
|
327
|
-
const needsTransform = transform &&
|
|
328
|
-
(transform.translateX ||
|
|
329
|
-
transform.translateY ||
|
|
330
|
-
transform.rotate ||
|
|
331
|
-
transform.scale ||
|
|
332
|
-
transform.scaleX ||
|
|
333
|
-
transform.scaleY);
|
|
327
|
+
const needsTransform = transform && (transform.translateX || transform.translateY || transform.rotate || transform.scale || transform.scaleX || transform.scaleY);
|
|
334
328
|
let savedContextForTransform = false;
|
|
335
329
|
if (needsTransform) {
|
|
336
330
|
ctx.save();
|
|
@@ -457,12 +451,11 @@ class BoxNode {
|
|
|
457
451
|
/**
|
|
458
452
|
* Renders the node's visual content including background fills, shadows, and borders.
|
|
459
453
|
* This is an internal method used by the render() pipeline.
|
|
460
|
-
*
|
|
461
|
-
* @param
|
|
462
|
-
* @param
|
|
463
|
-
* @param
|
|
464
|
-
* @param
|
|
465
|
-
* @param height - The height of the content area to render
|
|
454
|
+
* @param ctx The skia-canvas 2D rendering context to draw into
|
|
455
|
+
* @param x The absolute x-coordinate where drawing should begin
|
|
456
|
+
* @param y The absolute y-coordinate where drawing should begin
|
|
457
|
+
* @param width The width of the content area to render
|
|
458
|
+
* @param height The height of the content area to render
|
|
466
459
|
*/
|
|
467
460
|
_renderContent(ctx, x, y, width, height) {
|
|
468
461
|
// Calculate border radius values for all corners
|
|
@@ -729,7 +722,7 @@ class BoxNode {
|
|
|
729
722
|
}
|
|
730
723
|
/**
|
|
731
724
|
* Creates a new BoxNode instance.
|
|
732
|
-
* @param {BoxProps} props
|
|
725
|
+
* @param {BoxProps} props Box properties and configuration.
|
|
733
726
|
* @returns {BoxNode} New BoxNode instance.
|
|
734
727
|
*/
|
|
735
728
|
const Box = (props) => new BoxNode(props);
|
|
@@ -750,7 +743,7 @@ class ColumnNode extends BoxNode {
|
|
|
750
743
|
}
|
|
751
744
|
/**
|
|
752
745
|
* Creates a new ColumnNode instance.
|
|
753
|
-
* @param {BoxProps} props
|
|
746
|
+
* @param {BoxProps} props Column properties and configuration.
|
|
754
747
|
* @returns {ColumnNode} New ColumnNode instance.
|
|
755
748
|
*/
|
|
756
749
|
const Column = (props) => new ColumnNode(props);
|
|
@@ -771,7 +764,7 @@ class RowNode extends BoxNode {
|
|
|
771
764
|
}
|
|
772
765
|
/**
|
|
773
766
|
* Creates a new RowNode instance.
|
|
774
|
-
* @param {BoxProps} props
|
|
767
|
+
* @param {BoxProps} props Row properties and configuration.
|
|
775
768
|
* @returns {RowNode} New RowNode instance.
|
|
776
769
|
*/
|
|
777
770
|
const Row = (props) => new RowNode(props);
|