@codehz/draw-call 0.2.2 → 0.4.1

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.
@@ -398,4 +398,55 @@ interface DrawCallCanvas {
398
398
  */
399
399
  declare function createCanvas(options: CanvasOptions): DrawCallCanvas;
400
400
  //#endregion
401
- export { GradientDescriptor as $, SvgRectChild as A, ContainerLayoutProps as B, SvgEllipseChild as C, SvgPolygonChild as D, SvgPathChild as E, TextProps as F, LayoutProps as G, JustifyContent as H, TransformElement as I, Border as J, MeasureContext as K, TransformProps as L, SvgTextChild as M, SvgTransformProps as N, SvgPolylineChild as O, TextElement as P, FontProps as Q, AlignItems as R, SvgElement as S, SvgLineChild as T, LayoutConstraints as U, FlexDirection as V, LayoutNode as W, Color as X, Bounds as Y, ColorStop as Z, StackElement as _, BoxElement as a, StrokeProps as at, SvgChild as b, CustomDrawProps as c, ImageProps as d, LinearGradientDescriptor as et, ProxiedCanvasContextOptions as f, StackAlign as g, RichTextSpan as h, createCanvas as i, Spacing as it, SvgStyleProps as j, SvgProps as k, Element as l, RichTextProps as m, DrawCallCanvas as n, Shadow as nt, BoxProps as o, linearGradient as ot, RichTextElement as p, createCanvasMeasureContext as q, LayoutSize as r, Size as rt, CustomDrawElement as s, radialGradient as st, CanvasOptions as t, RadialGradientDescriptor as tt, ImageElement as u, StackProps as v, SvgGroupChild as w, SvgCircleChild as x, SvgAlign as y, AlignSelf as z };
401
+ //#region src/components/Box.d.ts
402
+ declare function Box(props: BoxProps): BoxElement;
403
+ //#endregion
404
+ //#region src/components/CustomDraw.d.ts
405
+ declare function CustomDraw(props: CustomDrawProps): CustomDrawElement;
406
+ //#endregion
407
+ //#region src/components/Image.d.ts
408
+ declare function Image(props: ImageProps): ImageElement;
409
+ //#endregion
410
+ //#region src/components/RichText.d.ts
411
+ declare function RichText(props: RichTextProps): RichTextElement;
412
+ //#endregion
413
+ //#region src/components/Stack.d.ts
414
+ declare function Stack(props: StackProps): StackElement;
415
+ //#endregion
416
+ //#region src/components/Svg.d.ts
417
+ declare function Svg(props: SvgProps): SvgElement;
418
+ declare const svg: {
419
+ rect: (props: Omit<SvgRectChild, "type">) => SvgRectChild;
420
+ circle: (props: Omit<SvgCircleChild, "type">) => SvgCircleChild;
421
+ ellipse: (props: Omit<SvgEllipseChild, "type">) => SvgEllipseChild;
422
+ line: (props: Omit<SvgLineChild, "type">) => SvgLineChild;
423
+ polyline: (props: Omit<SvgPolylineChild, "type">) => SvgPolylineChild;
424
+ polygon: (props: Omit<SvgPolygonChild, "type">) => SvgPolygonChild;
425
+ path: (props: Omit<SvgPathChild, "type">) => SvgPathChild;
426
+ text: (props: Omit<SvgTextChild, "type">) => SvgTextChild;
427
+ g: (props: Omit<SvgGroupChild, "type">) => SvgGroupChild;
428
+ };
429
+ //#endregion
430
+ //#region src/components/Text.d.ts
431
+ declare function Text(props: TextProps): TextElement;
432
+ //#endregion
433
+ //#region src/components/Transform.d.ts
434
+ declare function Transform(props: TransformProps): TransformElement;
435
+ //#endregion
436
+ //#region src/layout/engine.d.ts
437
+ declare function computeLayout(element: Element, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
438
+ //#endregion
439
+ //#region src/layout/utils/print.d.ts
440
+ /**
441
+ * 打印 LayoutNode 树结构到控制台
442
+ */
443
+ declare function printLayout(node: LayoutNode): void;
444
+ /**
445
+ * 将 LayoutNode 转换为美观的字符串
446
+ * @param node LayoutNode 根节点
447
+ * @param indent 缩进字符串,默认为两个空格
448
+ * @returns 格式化的字符串
449
+ */
450
+ declare function layoutToString(node: LayoutNode, _indent?: string): string;
451
+ //#endregion
452
+ export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutNode, type LayoutProps, type LayoutSize, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
@@ -398,4 +398,55 @@ interface DrawCallCanvas {
398
398
  */
399
399
  declare function createCanvas(options: CanvasOptions): DrawCallCanvas;
400
400
  //#endregion
401
- export { GradientDescriptor as $, SvgRectChild as A, ContainerLayoutProps as B, SvgEllipseChild as C, SvgPolygonChild as D, SvgPathChild as E, TextProps as F, LayoutProps as G, JustifyContent as H, TransformElement as I, Border as J, MeasureContext as K, TransformProps as L, SvgTextChild as M, SvgTransformProps as N, SvgPolylineChild as O, TextElement as P, FontProps as Q, AlignItems as R, SvgElement as S, SvgLineChild as T, LayoutConstraints as U, FlexDirection as V, LayoutNode as W, Color as X, Bounds as Y, ColorStop as Z, StackElement as _, BoxElement as a, StrokeProps as at, SvgChild as b, CustomDrawProps as c, ImageProps as d, LinearGradientDescriptor as et, ProxiedCanvasContextOptions as f, StackAlign as g, RichTextSpan as h, createCanvas as i, Spacing as it, SvgStyleProps as j, SvgProps as k, Element as l, RichTextProps as m, DrawCallCanvas as n, Shadow as nt, BoxProps as o, linearGradient as ot, RichTextElement as p, createCanvasMeasureContext as q, LayoutSize as r, Size as rt, CustomDrawElement as s, radialGradient as st, CanvasOptions as t, RadialGradientDescriptor as tt, ImageElement as u, StackProps as v, SvgGroupChild as w, SvgCircleChild as x, SvgAlign as y, AlignSelf as z };
401
+ //#region src/components/Box.d.ts
402
+ declare function Box(props: BoxProps): BoxElement;
403
+ //#endregion
404
+ //#region src/components/CustomDraw.d.ts
405
+ declare function CustomDraw(props: CustomDrawProps): CustomDrawElement;
406
+ //#endregion
407
+ //#region src/components/Image.d.ts
408
+ declare function Image(props: ImageProps): ImageElement;
409
+ //#endregion
410
+ //#region src/components/RichText.d.ts
411
+ declare function RichText(props: RichTextProps): RichTextElement;
412
+ //#endregion
413
+ //#region src/components/Stack.d.ts
414
+ declare function Stack(props: StackProps): StackElement;
415
+ //#endregion
416
+ //#region src/components/Svg.d.ts
417
+ declare function Svg(props: SvgProps): SvgElement;
418
+ declare const svg: {
419
+ rect: (props: Omit<SvgRectChild, "type">) => SvgRectChild;
420
+ circle: (props: Omit<SvgCircleChild, "type">) => SvgCircleChild;
421
+ ellipse: (props: Omit<SvgEllipseChild, "type">) => SvgEllipseChild;
422
+ line: (props: Omit<SvgLineChild, "type">) => SvgLineChild;
423
+ polyline: (props: Omit<SvgPolylineChild, "type">) => SvgPolylineChild;
424
+ polygon: (props: Omit<SvgPolygonChild, "type">) => SvgPolygonChild;
425
+ path: (props: Omit<SvgPathChild, "type">) => SvgPathChild;
426
+ text: (props: Omit<SvgTextChild, "type">) => SvgTextChild;
427
+ g: (props: Omit<SvgGroupChild, "type">) => SvgGroupChild;
428
+ };
429
+ //#endregion
430
+ //#region src/components/Text.d.ts
431
+ declare function Text(props: TextProps): TextElement;
432
+ //#endregion
433
+ //#region src/components/Transform.d.ts
434
+ declare function Transform(props: TransformProps): TransformElement;
435
+ //#endregion
436
+ //#region src/layout/engine.d.ts
437
+ declare function computeLayout(element: Element, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
438
+ //#endregion
439
+ //#region src/layout/utils/print.d.ts
440
+ /**
441
+ * 打印 LayoutNode 树结构到控制台
442
+ */
443
+ declare function printLayout(node: LayoutNode): void;
444
+ /**
445
+ * 将 LayoutNode 转换为美观的字符串
446
+ * @param node LayoutNode 根节点
447
+ * @param indent 缩进字符串,默认为两个空格
448
+ * @returns 格式化的字符串
449
+ */
450
+ declare function layoutToString(node: LayoutNode, _indent?: string): string;
451
+ //#endregion
452
+ export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutNode, type LayoutProps, type LayoutSize, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
@@ -1,4 +1,14 @@
1
+ //#region src/compat/index.ts
2
+ const DOMMatrix = window.DOMMatrix;
3
+ const Path2D = window.Path2D;
4
+ function createRawCanvas(width, height) {
5
+ const canvas = document.createElement("canvas");
6
+ canvas.width = width;
7
+ canvas.height = height;
8
+ return canvas;
9
+ }
1
10
 
11
+ //#endregion
2
12
  //#region src/types/base.ts
3
13
  function linearGradient(angle, ...stops) {
4
14
  return {
@@ -1106,17 +1116,6 @@ function renderBox(ctx, node) {
1106
1116
  if (element.opacity !== void 0 && element.opacity < 1) ctx.globalAlpha = 1;
1107
1117
  }
1108
1118
 
1109
- //#endregion
1110
- //#region src/compat/DOMMatrix.ts
1111
- const DOMMatrixCompat = (() => {
1112
- if (typeof DOMMatrix !== "undefined") return DOMMatrix;
1113
- try {
1114
- return require("@napi-rs/canvas").DOMMatrix;
1115
- } catch {
1116
- throw new Error("DOMMatrix is not available. In Node.js, install @napi-rs/canvas.");
1117
- }
1118
- })();
1119
-
1120
1119
  //#endregion
1121
1120
  //#region src/render/components/ProxiedCanvasContext.ts
1122
1121
  /**
@@ -1153,7 +1152,7 @@ var ProxiedCanvasContext = class {
1153
1152
  constructor(ctx, baseTransform) {
1154
1153
  this.ctx = ctx;
1155
1154
  this.baseTransform = baseTransform;
1156
- this.relativeTransform = new DOMMatrixCompat();
1155
+ this.relativeTransform = new DOMMatrix();
1157
1156
  }
1158
1157
  /**
1159
1158
  * save() - 保存当前状态并增加计数
@@ -1176,8 +1175,8 @@ var ProxiedCanvasContext = class {
1176
1175
  */
1177
1176
  setTransform(...args) {
1178
1177
  let matrix;
1179
- if (args.length === 1 && args[0] instanceof DOMMatrixCompat) matrix = args[0];
1180
- else if (args.length === 6) matrix = new DOMMatrixCompat([
1178
+ if (args.length === 1 && args[0] instanceof DOMMatrix) matrix = args[0];
1179
+ else if (args.length === 6) matrix = new DOMMatrix([
1181
1180
  args[0],
1182
1181
  args[1],
1183
1182
  args[2],
@@ -1400,17 +1399,6 @@ function renderRichText(ctx, node) {
1400
1399
  }
1401
1400
  }
1402
1401
 
1403
- //#endregion
1404
- //#region src/compat/Path2D.ts
1405
- const Path2DCompat = (() => {
1406
- if (typeof Path2D !== "undefined") return Path2D;
1407
- try {
1408
- return require("@napi-rs/canvas").Path2D;
1409
- } catch {
1410
- throw new Error("Path2D is not available. In Node.js, install @napi-rs/canvas.");
1411
- }
1412
- })();
1413
-
1414
1402
  //#endregion
1415
1403
  //#region src/render/components/svg.ts
1416
1404
  function isGradientDescriptor(color) {
@@ -1448,7 +1436,7 @@ function resolveColor(ctx, color, x, y, width, height) {
1448
1436
  }
1449
1437
  function applyTransform(base, transform) {
1450
1438
  if (!transform) return base;
1451
- let result = new DOMMatrixCompat([
1439
+ let result = new DOMMatrix([
1452
1440
  base.a,
1453
1441
  base.b,
1454
1442
  base.c,
@@ -1458,7 +1446,7 @@ function applyTransform(base, transform) {
1458
1446
  ]);
1459
1447
  if (transform.matrix) {
1460
1448
  const [a, b, c, d, e, f] = transform.matrix;
1461
- result = result.multiply(new DOMMatrixCompat([
1449
+ result = result.multiply(new DOMMatrix([
1462
1450
  a,
1463
1451
  b,
1464
1452
  c,
@@ -1547,7 +1535,7 @@ function renderSvgPolygon(ctx, polygon, bounds) {
1547
1535
  applyFillAndStroke(ctx, polygon, bounds);
1548
1536
  }
1549
1537
  function renderSvgPath(ctx, path, bounds) {
1550
- const path2d = new Path2DCompat(path.d);
1538
+ const path2d = new Path2D(path.d);
1551
1539
  if (path.fill && path.fill !== "none") {
1552
1540
  ctx.fillStyle = resolveColor(ctx, path.fill, bounds.x, bounds.y, bounds.width, bounds.height);
1553
1541
  ctx.fill(path2d);
@@ -1629,7 +1617,7 @@ function calculateViewBoxTransform(x, y, width, height, viewBox, preserveAspectR
1629
1617
  const scaleY = height / vbHeight;
1630
1618
  const align = preserveAspectRatio?.align ?? "xMidYMid";
1631
1619
  const meetOrSlice = preserveAspectRatio?.meetOrSlice ?? "meet";
1632
- if (align === "none") return new DOMMatrixCompat().translate(x, y).scale(scaleX, scaleY).translate(-vbX, -vbY);
1620
+ if (align === "none") return new DOMMatrix().translate(x, y).scale(scaleX, scaleY).translate(-vbX, -vbY);
1633
1621
  const scale = meetOrSlice === "meet" ? Math.min(scaleX, scaleY) : Math.max(scaleX, scaleY);
1634
1622
  const scaledWidth = vbWidth * scale;
1635
1623
  const scaledHeight = vbHeight * scale;
@@ -1639,7 +1627,7 @@ function calculateViewBoxTransform(x, y, width, height, viewBox, preserveAspectR
1639
1627
  else if (align.includes("xMax")) translateX += width - scaledWidth;
1640
1628
  if (align.includes("YMid")) translateY += (height - scaledHeight) / 2;
1641
1629
  else if (align.includes("YMax")) translateY += height - scaledHeight;
1642
- return new DOMMatrixCompat().translate(translateX, translateY).scale(scale, scale).translate(-vbX, -vbY);
1630
+ return new DOMMatrix().translate(translateX, translateY).scale(scale, scale).translate(-vbX, -vbY);
1643
1631
  }
1644
1632
  function applyShadow(ctx, shadow) {
1645
1633
  ctx.shadowOffsetX = shadow.offsetX ?? 0;
@@ -1728,13 +1716,13 @@ function renderText(ctx, node) {
1728
1716
  * - 简易对象: { translate, rotate, scale, skewX, skewY }
1729
1717
  */
1730
1718
  function parseTransformValue(transform) {
1731
- if (transform === void 0) return new DOMMatrixCompat();
1732
- if (Array.isArray(transform)) return new DOMMatrixCompat(transform);
1719
+ if (transform === void 0) return new DOMMatrix();
1720
+ if (Array.isArray(transform)) return new DOMMatrix(transform);
1733
1721
  const hasDOMMatrixInit = "a" in transform || "b" in transform || "c" in transform || "d" in transform || "e" in transform || "f" in transform;
1734
1722
  const hasSimpleTransform = "translate" in transform || "rotate" in transform || "scale" in transform || "skewX" in transform || "skewY" in transform;
1735
1723
  if (hasDOMMatrixInit && !hasSimpleTransform) {
1736
1724
  const init = transform;
1737
- return new DOMMatrixCompat([
1725
+ return new DOMMatrix([
1738
1726
  init.a ?? 1,
1739
1727
  init.b ?? 0,
1740
1728
  init.c ?? 0,
@@ -1744,7 +1732,7 @@ function parseTransformValue(transform) {
1744
1732
  ]);
1745
1733
  }
1746
1734
  const simpleObj = transform;
1747
- let result = new DOMMatrixCompat();
1735
+ let result = new DOMMatrix();
1748
1736
  if (simpleObj.translate) result = result.translate(simpleObj.translate[0], simpleObj.translate[1]);
1749
1737
  if (simpleObj.rotate !== void 0) if (typeof simpleObj.rotate === "number") result = result.rotate(simpleObj.rotate);
1750
1738
  else {
@@ -1786,7 +1774,7 @@ function renderTransform(ctx, node) {
1786
1774
  const ox = childNode.layout.x + relativeOx;
1787
1775
  const oy = childNode.layout.y + relativeOy;
1788
1776
  const targetMatrix = parseTransformValue(element.transform);
1789
- const finalMatrix = new DOMMatrixCompat().translate(ox, oy).multiply(targetMatrix).translate(-ox, -oy);
1777
+ const finalMatrix = new DOMMatrix().translate(ox, oy).multiply(targetMatrix).translate(-ox, -oy);
1790
1778
  ctx.save();
1791
1779
  const composedTransform = ctx.getTransform().multiply(finalMatrix);
1792
1780
  ctx.setTransform(composedTransform);
@@ -1835,33 +1823,220 @@ function renderNode(ctx, node) {
1835
1823
  }
1836
1824
 
1837
1825
  //#endregion
1838
- Object.defineProperty(exports, 'computeLayout', {
1839
- enumerable: true,
1840
- get: function () {
1841
- return computeLayout;
1842
- }
1843
- });
1844
- Object.defineProperty(exports, 'createCanvasMeasureContext', {
1845
- enumerable: true,
1846
- get: function () {
1847
- return createCanvasMeasureContext;
1848
- }
1849
- });
1850
- Object.defineProperty(exports, 'linearGradient', {
1851
- enumerable: true,
1852
- get: function () {
1853
- return linearGradient;
1854
- }
1855
- });
1856
- Object.defineProperty(exports, 'radialGradient', {
1857
- enumerable: true,
1858
- get: function () {
1859
- return radialGradient;
1860
- }
1861
- });
1862
- Object.defineProperty(exports, 'renderNode', {
1863
- enumerable: true,
1864
- get: function () {
1865
- return renderNode;
1866
- }
1867
- });
1826
+ //#region src/canvas.ts
1827
+ /**
1828
+ * 创建适用于浏览器环境的 Canvas
1829
+ *
1830
+ * 在浏览器环境中使用,支持传入已有的 canvas 实例
1831
+ */
1832
+ function createCanvas(options) {
1833
+ const { width, height, pixelRatio = 1 } = options;
1834
+ const canvas = options.canvas ?? createRawCanvas(width * pixelRatio, height * pixelRatio);
1835
+ const ctx = canvas.getContext("2d");
1836
+ if (!ctx) throw new Error("Failed to get 2d context");
1837
+ if (options.imageSmoothingEnabled !== void 0) ctx.imageSmoothingEnabled = options.imageSmoothingEnabled;
1838
+ if (options.imageSmoothingQuality !== void 0) ctx.imageSmoothingQuality = options.imageSmoothingQuality;
1839
+ if (pixelRatio !== 1) ctx.scale(pixelRatio, pixelRatio);
1840
+ const measureCtx = createCanvasMeasureContext(ctx);
1841
+ return {
1842
+ width,
1843
+ height,
1844
+ pixelRatio,
1845
+ canvas,
1846
+ render(element) {
1847
+ const layoutTree = computeLayout(element, measureCtx, {
1848
+ minWidth: 0,
1849
+ maxWidth: width,
1850
+ minHeight: 0,
1851
+ maxHeight: height
1852
+ });
1853
+ renderNode(ctx, layoutTree);
1854
+ return layoutTree;
1855
+ },
1856
+ clear() {
1857
+ ctx.clearRect(0, 0, width, height);
1858
+ },
1859
+ getContext() {
1860
+ return ctx;
1861
+ },
1862
+ toDataURL(type, quality) {
1863
+ if ("toDataURL" in canvas && typeof canvas.toDataURL === "function") return canvas.toDataURL(type, quality);
1864
+ throw new Error("toDataURL not supported");
1865
+ },
1866
+ toBuffer(type = "image/png") {
1867
+ if ("toBuffer" in canvas && typeof canvas.toBuffer === "function") return canvas.toBuffer(type);
1868
+ throw new Error("toBuffer not supported in this environment");
1869
+ }
1870
+ };
1871
+ }
1872
+
1873
+ //#endregion
1874
+ //#region src/components/Box.ts
1875
+ function Box(props) {
1876
+ return {
1877
+ type: "box",
1878
+ ...props
1879
+ };
1880
+ }
1881
+
1882
+ //#endregion
1883
+ //#region src/components/CustomDraw.ts
1884
+ function CustomDraw(props) {
1885
+ return {
1886
+ type: "customdraw",
1887
+ ...props
1888
+ };
1889
+ }
1890
+
1891
+ //#endregion
1892
+ //#region src/components/Image.ts
1893
+ function Image(props) {
1894
+ return {
1895
+ type: "image",
1896
+ ...props
1897
+ };
1898
+ }
1899
+
1900
+ //#endregion
1901
+ //#region src/components/RichText.ts
1902
+ function RichText(props) {
1903
+ return {
1904
+ type: "richtext",
1905
+ ...props
1906
+ };
1907
+ }
1908
+
1909
+ //#endregion
1910
+ //#region src/components/Stack.ts
1911
+ function Stack(props) {
1912
+ return {
1913
+ type: "stack",
1914
+ ...props
1915
+ };
1916
+ }
1917
+
1918
+ //#endregion
1919
+ //#region src/components/Svg.ts
1920
+ function Svg(props) {
1921
+ return {
1922
+ type: "svg",
1923
+ ...props
1924
+ };
1925
+ }
1926
+ const svg = {
1927
+ rect: (props) => ({
1928
+ type: "rect",
1929
+ ...props
1930
+ }),
1931
+ circle: (props) => ({
1932
+ type: "circle",
1933
+ ...props
1934
+ }),
1935
+ ellipse: (props) => ({
1936
+ type: "ellipse",
1937
+ ...props
1938
+ }),
1939
+ line: (props) => ({
1940
+ type: "line",
1941
+ ...props
1942
+ }),
1943
+ polyline: (props) => ({
1944
+ type: "polyline",
1945
+ ...props
1946
+ }),
1947
+ polygon: (props) => ({
1948
+ type: "polygon",
1949
+ ...props
1950
+ }),
1951
+ path: (props) => ({
1952
+ type: "path",
1953
+ ...props
1954
+ }),
1955
+ text: (props) => ({
1956
+ type: "text",
1957
+ ...props
1958
+ }),
1959
+ g: (props) => ({
1960
+ type: "g",
1961
+ ...props
1962
+ })
1963
+ };
1964
+
1965
+ //#endregion
1966
+ //#region src/components/Text.ts
1967
+ function Text(props) {
1968
+ return {
1969
+ type: "text",
1970
+ ...props
1971
+ };
1972
+ }
1973
+
1974
+ //#endregion
1975
+ //#region src/components/Transform.ts
1976
+ function Transform(props) {
1977
+ return {
1978
+ type: "transform",
1979
+ ...props
1980
+ };
1981
+ }
1982
+
1983
+ //#endregion
1984
+ //#region src/layout/utils/print.ts
1985
+ /**
1986
+ * 获取元素类型的显示名称
1987
+ */
1988
+ function getElementType(element) {
1989
+ switch (element.type) {
1990
+ case "box": return "Box";
1991
+ case "text": return `Text "${element.content.slice(0, 20)}${element.content.length > 20 ? "..." : ""}"`;
1992
+ case "stack": return "Stack";
1993
+ case "image": return "Image";
1994
+ case "svg": return "Svg";
1995
+ default: return element.type;
1996
+ }
1997
+ }
1998
+ /**
1999
+ * 递归打印布局树
2000
+ */
2001
+ function printLayoutToString(node, prefix = "", isLast = true, depth = 0) {
2002
+ const lines = [];
2003
+ const connector = isLast ? "└─ " : "├─ ";
2004
+ const type = getElementType(node.element);
2005
+ const { x, y, width, height } = node.layout;
2006
+ const childCount = node.children.length;
2007
+ lines.push(`${prefix}${connector}${type} @(${Math.round(x)},${Math.round(y)}) size:${Math.round(width)}x${Math.round(height)}`);
2008
+ if (node.element.type === "text" && node.lines) {
2009
+ const contentPrefix = prefix + (isLast ? " " : "│ ");
2010
+ for (let i = 0; i < node.lines.length; i++) {
2011
+ const lineText = node.lines[i];
2012
+ const isLastLine = i === node.lines.length - 1 && childCount === 0;
2013
+ lines.push(`${contentPrefix}${isLastLine ? "└─ " : "├─ "}${JSON.stringify(lineText)}`);
2014
+ }
2015
+ }
2016
+ for (let i = 0; i < node.children.length; i++) {
2017
+ const child = node.children[i];
2018
+ const isChildLast = i === node.children.length - 1;
2019
+ const childPrefix = prefix + (isLast ? " " : "│ ");
2020
+ lines.push(...printLayoutToString(child, childPrefix, isChildLast, depth + 1));
2021
+ }
2022
+ return lines;
2023
+ }
2024
+ /**
2025
+ * 打印 LayoutNode 树结构到控制台
2026
+ */
2027
+ function printLayout(node) {
2028
+ const lines = printLayoutToString(node, "", true);
2029
+ console.log(lines.join("\n"));
2030
+ }
2031
+ /**
2032
+ * 将 LayoutNode 转换为美观的字符串
2033
+ * @param node LayoutNode 根节点
2034
+ * @param indent 缩进字符串,默认为两个空格
2035
+ * @returns 格式化的字符串
2036
+ */
2037
+ function layoutToString(node, _indent = " ") {
2038
+ return printLayoutToString(node, "", true).join("\n");
2039
+ }
2040
+
2041
+ //#endregion
2042
+ export { Box, CustomDraw, Image, RichText, Stack, Svg, Text, Transform, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
package/examples/card.ts CHANGED
@@ -2,14 +2,13 @@
2
2
  * 示例:使用 draw-call 绘制一个卡片
3
3
  * 运行: bun examples/card.ts
4
4
  */
5
- import { Box, linearGradient, printLayout, Svg, svg, Text } from "@codehz/draw-call";
6
- import { createNodeCanvas } from "@codehz/draw-call/node";
5
+ import { Box, createCanvas, linearGradient, printLayout, Svg, svg, Text } from "@codehz/draw-call";
7
6
  import { GlobalFonts } from "@napi-rs/canvas";
8
7
  import { fileURLToPath } from "bun";
9
8
 
10
9
  GlobalFonts.registerFromPath(fileURLToPath(import.meta.resolve("@fontpkg/unifont/unifont-15.0.01.ttf")), "unifont");
11
10
 
12
- const canvas = createNodeCanvas({
11
+ const canvas = createCanvas({
13
12
  width: 400,
14
13
  height: 320,
15
14
  pixelRatio: 2,
@@ -3,14 +3,13 @@
3
3
  * 展示如何使用 CustomDraw 进行简单的自定义绘制
4
4
  * 运行: bun examples/customdraw-basic.ts
5
5
  */
6
- import { Box, CustomDraw, printLayout, Text } from "@codehz/draw-call";
7
- import { createNodeCanvas } from "@codehz/draw-call/node";
6
+ import { Box, createCanvas, CustomDraw, printLayout, Text } from "@codehz/draw-call";
8
7
  import { GlobalFonts } from "@napi-rs/canvas";
9
8
  import { fileURLToPath } from "bun";
10
9
 
11
10
  GlobalFonts.registerFromPath(fileURLToPath(import.meta.resolve("@fontpkg/unifont/unifont-15.0.01.ttf")), "unifont");
12
11
 
13
- const canvas = createNodeCanvas({
12
+ const canvas = createCanvas({
14
13
  width: 600,
15
14
  height: 1000,
16
15
  pixelRatio: 2,
@@ -3,14 +3,13 @@
3
3
  * 展示直接调用 Canvas API、Transform 管理和子元素渲染功能
4
4
  * 运行: bun examples/customdraw.ts
5
5
  */
6
- import { Box, CustomDraw, printLayout, Text } from "@codehz/draw-call";
7
- import { createNodeCanvas } from "@codehz/draw-call/node";
6
+ import { Box, createCanvas, CustomDraw, printLayout, Text } from "@codehz/draw-call";
8
7
  import { GlobalFonts } from "@napi-rs/canvas";
9
8
  import { fileURLToPath } from "bun";
10
9
 
11
10
  GlobalFonts.registerFromPath(fileURLToPath(import.meta.resolve("@fontpkg/unifont/unifont-15.0.01.ttf")), "unifont");
12
11
 
13
- const canvas = createNodeCanvas({
12
+ const canvas = createCanvas({
14
13
  width: 800,
15
14
  height: 1000,
16
15
  pixelRatio: 2,
@@ -2,14 +2,13 @@
2
2
  * 示例:使用 draw-call 的 RichText 组件
3
3
  * 运行: bun examples/richtext.ts
4
4
  */
5
- import { Box, RichText, Text } from "@codehz/draw-call";
6
- import { createNodeCanvas } from "@codehz/draw-call/node";
5
+ import { Box, createCanvas, RichText, Text } from "@codehz/draw-call";
7
6
  import { GlobalFonts } from "@napi-rs/canvas";
8
7
  import { fileURLToPath } from "bun";
9
8
 
10
9
  GlobalFonts.registerFromPath(fileURLToPath(import.meta.resolve("@fontpkg/unifont/unifont-15.0.01.ttf")), "unifont");
11
10
 
12
- const canvas = createNodeCanvas({
11
+ const canvas = createCanvas({
13
12
  width: 400,
14
13
  height: 820,
15
14
  pixelRatio: 2,
@@ -3,14 +3,13 @@
3
3
  * 展示移动(translate)、旋转(rotate)、放大(scale)等变换效果
4
4
  * 运行: bun examples/transform.ts
5
5
  */
6
- import { Box, Text, Transform, printLayout } from "@codehz/draw-call";
7
- import { createNodeCanvas } from "@codehz/draw-call/node";
6
+ import { Box, createCanvas, printLayout, Text, Transform } from "@codehz/draw-call";
8
7
  import { GlobalFonts } from "@napi-rs/canvas";
9
8
  import { fileURLToPath } from "bun";
10
9
 
11
10
  GlobalFonts.registerFromPath(fileURLToPath(import.meta.resolve("@fontpkg/unifont/unifont-15.0.01.ttf")), "unifont");
12
11
 
13
- const canvas = createNodeCanvas({
12
+ const canvas = createCanvas({
14
13
  width: 800,
15
14
  height: 1000,
16
15
  pixelRatio: 2,