@codehz/draw-call 0.1.1 → 0.2.0
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 +374 -6
- package/{canvas-BYrCq8eS.d.mts → canvas.d.cts} +145 -34
- package/{canvas-CkpP3RNK.d.cts → canvas.d.mts} +145 -34
- package/examples/card.ts +155 -0
- package/examples/demo.ts +478 -0
- package/examples/richtext.ts +284 -0
- package/index.cjs +139 -9
- package/index.d.cts +51 -2
- package/index.d.mts +51 -2
- package/index.mjs +127 -3
- package/node.cjs +8 -7
- package/node.d.cts +3 -3
- package/node.d.mts +3 -3
- package/node.mjs +7 -6
- package/package.json +1 -1
- package/render.cjs +1555 -0
- package/render.mjs +1531 -0
- package/engine-C88lMGbX.mjs +0 -606
- package/engine-OyKoV7Gn.cjs +0 -636
package/README.md
CHANGED
|
@@ -1,15 +1,383 @@
|
|
|
1
1
|
# @codehz/draw-call
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个声明式 Canvas 绘图库,提供 Flexbox 布局引擎和组件化渲染系统。使用类似 UI 框架的方式来绘制 Canvas 内容,让 Canvas 绘图变得简单直观。
|
|
4
|
+
|
|
5
|
+
## ✨ 特性
|
|
6
|
+
|
|
7
|
+
- **Flexbox 布局引擎** - 支持完整的 Flexbox 布局,包括方向、对齐、间距等
|
|
8
|
+
- **组件化渲染** - 提供 Box、Text、Image、Svg、Stack 等组件
|
|
9
|
+
- **丰富的样式支持** - 渐变、阴影、边框、圆角等
|
|
10
|
+
- **文本排版** - 自动换行、省略号、行高控制等
|
|
11
|
+
- **SVG 图形** - 支持矩形、圆形、椭圆、路径等 SVG 图形
|
|
12
|
+
- **跨平台** - 支持浏览器和 Node.js 环境
|
|
13
|
+
- **TypeScript** - 完整的类型支持
|
|
14
|
+
|
|
15
|
+
## 📦 安装
|
|
4
16
|
|
|
5
17
|
```bash
|
|
6
|
-
bun install
|
|
18
|
+
bun install @codehz/draw-call
|
|
7
19
|
```
|
|
8
20
|
|
|
9
|
-
|
|
21
|
+
## 🚀 快速开始
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
23
|
+
### 浏览器环境
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createCanvas, Box, Text } from "@codehz/draw-call";
|
|
27
|
+
|
|
28
|
+
// 获取 canvas 元素
|
|
29
|
+
const canvasEl = document.getElementById("canvas") as HTMLCanvasElement;
|
|
30
|
+
|
|
31
|
+
// 创建 Canvas 实例
|
|
32
|
+
const canvas = createCanvas({
|
|
33
|
+
width: 400,
|
|
34
|
+
height: 300,
|
|
35
|
+
pixelRatio: window.devicePixelRatio || 1,
|
|
36
|
+
canvas: canvasEl,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// 渲染内容
|
|
40
|
+
canvas.render(
|
|
41
|
+
Box({
|
|
42
|
+
width: "fill",
|
|
43
|
+
height: "fill",
|
|
44
|
+
background: "#ffffff",
|
|
45
|
+
padding: 20,
|
|
46
|
+
children: [
|
|
47
|
+
Text({
|
|
48
|
+
content: "Hello, draw-call!",
|
|
49
|
+
font: { size: 24, weight: "bold" },
|
|
50
|
+
color: "#333333",
|
|
51
|
+
}),
|
|
52
|
+
],
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Node.js 环境
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { createCanvas, Box, Text } from "@codehz/draw-call";
|
|
61
|
+
import { createNodeCanvas } from "@codehz/draw-call/node";
|
|
62
|
+
|
|
63
|
+
// 创建 Canvas 实例
|
|
64
|
+
const canvas = createNodeCanvas({
|
|
65
|
+
width: 400,
|
|
66
|
+
height: 300,
|
|
67
|
+
pixelRatio: 2,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// 渲染内容
|
|
71
|
+
canvas.render(
|
|
72
|
+
Box({
|
|
73
|
+
width: "fill",
|
|
74
|
+
height: "fill",
|
|
75
|
+
background: "#ffffff",
|
|
76
|
+
padding: 20,
|
|
77
|
+
children: [
|
|
78
|
+
Text({
|
|
79
|
+
content: "Hello, draw-call!",
|
|
80
|
+
font: { size: 24, weight: "bold" },
|
|
81
|
+
color: "#333333",
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// 保存为图片
|
|
88
|
+
const buffer = await canvas.toBuffer("image/png");
|
|
89
|
+
await Bun.write("output.png", buffer);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 📚 组件
|
|
93
|
+
|
|
94
|
+
### Box
|
|
95
|
+
|
|
96
|
+
容器组件,支持 Flexbox 布局和丰富的样式。
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
Box({
|
|
100
|
+
width: 200,
|
|
101
|
+
height: 100,
|
|
102
|
+
background: "#ffffff",
|
|
103
|
+
border: { radius: 8, width: 1, color: "#e0e0e0" },
|
|
104
|
+
shadow: { offsetY: 2, blur: 8, color: "rgba(0,0,0,0.08)" },
|
|
105
|
+
padding: 20,
|
|
106
|
+
direction: "row",
|
|
107
|
+
justify: "center",
|
|
108
|
+
align: "center",
|
|
109
|
+
children: [...],
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Text
|
|
114
|
+
|
|
115
|
+
文本组件,支持自动换行、行高控制等。
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
Text({
|
|
119
|
+
content: "这是一段文本",
|
|
120
|
+
font: { size: 16, weight: "bold", family: "sans-serif" },
|
|
121
|
+
color: "#333333",
|
|
122
|
+
align: "center",
|
|
123
|
+
lineHeight: 1.5,
|
|
124
|
+
wrap: true,
|
|
125
|
+
maxLines: 3,
|
|
126
|
+
ellipsis: true,
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### RichText
|
|
131
|
+
|
|
132
|
+
富文本组件,支持同时展示多种样式的文本,每个文本段落可以有不同的字体、颜色、背景、装饰等。
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
RichText({
|
|
136
|
+
spans: [
|
|
137
|
+
{
|
|
138
|
+
text: "普通文本 ",
|
|
139
|
+
color: "#333333",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
text: "加粗文本 ",
|
|
143
|
+
font: { size: 16, weight: "bold" },
|
|
144
|
+
color: "#333333",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
text: "彩色文本 ",
|
|
148
|
+
font: { size: 16, weight: "bold" },
|
|
149
|
+
color: "#667eea",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
text: "带背景 ",
|
|
153
|
+
color: "#ffffff",
|
|
154
|
+
background: "#764ba2",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
text: "带下划线",
|
|
158
|
+
underline: true,
|
|
159
|
+
color: "#333333",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
text: "删除线",
|
|
163
|
+
strikethrough: true,
|
|
164
|
+
color: "#999999",
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
lineHeight: 1.5,
|
|
168
|
+
align: "left",
|
|
169
|
+
maxLines: 5,
|
|
170
|
+
ellipsis: true,
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Image
|
|
175
|
+
|
|
176
|
+
图片组件,支持多种适配模式。
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
Image({
|
|
180
|
+
src: imageBitmap,
|
|
181
|
+
width: 200,
|
|
182
|
+
height: 150,
|
|
183
|
+
fit: "cover", // contain | cover | fill | none | scale-down
|
|
184
|
+
position: { x: "center", y: "center" },
|
|
185
|
+
border: { radius: 8 },
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Svg
|
|
190
|
+
|
|
191
|
+
SVG 图形组件,支持多种图形元素。
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { svg } from "@codehz/draw-call";
|
|
195
|
+
|
|
196
|
+
Svg({
|
|
197
|
+
width: 200,
|
|
198
|
+
height: 100,
|
|
199
|
+
viewBox: { width: 200, height: 100 },
|
|
200
|
+
children: [
|
|
201
|
+
svg.rect({ x: 10, y: 10, width: 50, height: 30, fill: "#667eea" }),
|
|
202
|
+
svg.circle({ cx: 100, cy: 50, r: 20, fill: "#764ba2" }),
|
|
203
|
+
svg.path({ d: "M150 50 Q170 30, 190 50", stroke: { color: "#333", width: 2 } }),
|
|
204
|
+
],
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Stack
|
|
209
|
+
|
|
210
|
+
堆叠组件,子元素绝对定位。
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
Stack({
|
|
214
|
+
width: 200,
|
|
215
|
+
height: 200,
|
|
216
|
+
align: "center",
|
|
217
|
+
justify: "center",
|
|
218
|
+
children: [
|
|
219
|
+
Box({ width: 100, height: 100, background: "#ff0000" }),
|
|
220
|
+
Box({ width: 50, height: 50, background: "#00ff00" }),
|
|
221
|
+
],
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 🎨 样式
|
|
226
|
+
|
|
227
|
+
### 尺寸
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// 固定像素值
|
|
231
|
+
width: 100;
|
|
232
|
+
|
|
233
|
+
// 百分比
|
|
234
|
+
width: "50%";
|
|
235
|
+
|
|
236
|
+
// 自动计算
|
|
237
|
+
width: "auto";
|
|
238
|
+
|
|
239
|
+
// 填充可用空间
|
|
240
|
+
width: "fill";
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 颜色
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// CSS 颜色字符串
|
|
247
|
+
background: "#ff0000";
|
|
248
|
+
background: "rgb(255, 0, 0)";
|
|
249
|
+
background: "red";
|
|
250
|
+
|
|
251
|
+
// 渐变
|
|
252
|
+
import { linearGradient, radialGradient } from "@codehz/draw-call";
|
|
253
|
+
|
|
254
|
+
// 线性渐变
|
|
255
|
+
background: linearGradient(135, "#667eea", "#764ba2");
|
|
256
|
+
|
|
257
|
+
// 带位置色标的线性渐变
|
|
258
|
+
background: linearGradient(90, [0, "#667eea"], [0.5, "#764ba2"], [1, "#f093fb"]);
|
|
259
|
+
|
|
260
|
+
// 径向渐变
|
|
261
|
+
background: radialGradient({ startX: 0.5, startY: 0.5, endRadius: 0.5 }, "#667eea", "#764ba2");
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 边框
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
border: {
|
|
268
|
+
width: 2,
|
|
269
|
+
color: "#e0e0e0",
|
|
270
|
+
radius: 8, // 或 [8, 8, 8, 8] 分别对应左上、右上、右下、左下
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 阴影
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
shadow: {
|
|
278
|
+
offsetX: 0,
|
|
279
|
+
offsetY: 4,
|
|
280
|
+
blur: 16,
|
|
281
|
+
color: "rgba(0,0,0,0.12)",
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 间距
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// 四边相同
|
|
289
|
+
padding: 20
|
|
290
|
+
margin: 10
|
|
291
|
+
|
|
292
|
+
// 分别设置
|
|
293
|
+
padding: { top: 10, right: 20, bottom: 10, left: 20 }
|
|
294
|
+
margin: { top: 5, right: 10, bottom: 5, left: 10 }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## 📐 布局
|
|
298
|
+
|
|
299
|
+
### Flexbox 布局
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
Box({
|
|
303
|
+
direction: "row", // row | column
|
|
304
|
+
justify: "center", // flex-start | center | flex-end | space-between | space-around | space-evenly
|
|
305
|
+
align: "center", // flex-start | center | flex-end | stretch | baseline
|
|
306
|
+
gap: 10,
|
|
307
|
+
wrap: true,
|
|
308
|
+
children: [...],
|
|
309
|
+
})
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 弹性布局
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
Box({
|
|
316
|
+
direction: "row",
|
|
317
|
+
children: [
|
|
318
|
+
Box({ width: 100 }), // 固定宽度
|
|
319
|
+
Box({ flex: 1 }), // 占据剩余空间
|
|
320
|
+
Box({ flex: 2 }), // 占据 2 份剩余空间
|
|
321
|
+
],
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## 🔧 高级用法
|
|
326
|
+
|
|
327
|
+
### 自定义字体(Node.js)
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { GlobalFonts } from "@napi-rs/canvas";
|
|
331
|
+
|
|
332
|
+
GlobalFonts.registerFromPath("/path/to/font.ttf", "CustomFont");
|
|
333
|
+
|
|
334
|
+
Text({
|
|
335
|
+
content: "自定义字体",
|
|
336
|
+
font: { family: "CustomFont", size: 16 },
|
|
337
|
+
});
|
|
13
338
|
```
|
|
14
339
|
|
|
15
|
-
|
|
340
|
+
### 导出图片
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// 导出为 PNG
|
|
344
|
+
const buffer = await canvas.toBuffer("image/png");
|
|
345
|
+
|
|
346
|
+
// 导出为 JPEG
|
|
347
|
+
const buffer = await canvas.toBuffer("image/jpeg", { quality: 0.9 });
|
|
348
|
+
|
|
349
|
+
// 导出为 WebP
|
|
350
|
+
const buffer = await canvas.toBuffer("image/webp", { quality: 0.8 });
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 获取布局信息
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
const layoutNode = canvas.render(
|
|
357
|
+
Box({
|
|
358
|
+
width: 200,
|
|
359
|
+
height: 100,
|
|
360
|
+
children: [...],
|
|
361
|
+
})
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
console.log(layoutNode.layout.width); // 200
|
|
365
|
+
console.log(layoutNode.layout.height); // 100
|
|
366
|
+
console.log(layoutNode.layout.x); // 0
|
|
367
|
+
console.log(layoutNode.layout.y); // 0
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 📖 示例
|
|
371
|
+
|
|
372
|
+
查看 [examples](examples) 目录获取更多示例:
|
|
373
|
+
|
|
374
|
+
- [demo.ts](examples/demo.ts) - 浏览器环境演示
|
|
375
|
+
- [card.ts](examples/card.ts) - Node.js 环境卡片示例
|
|
376
|
+
|
|
377
|
+
## 🤝 贡献
|
|
378
|
+
|
|
379
|
+
欢迎提交 Issue 和 Pull Request!
|
|
380
|
+
|
|
381
|
+
## 📄 许可证
|
|
382
|
+
|
|
383
|
+
MIT
|
|
@@ -101,6 +101,33 @@ interface ComputedLayout {
|
|
|
101
101
|
contentWidth: number;
|
|
102
102
|
contentHeight: number;
|
|
103
103
|
}
|
|
104
|
+
interface RichTextSpanSegment {
|
|
105
|
+
text: string;
|
|
106
|
+
font: FontProps;
|
|
107
|
+
color: Color;
|
|
108
|
+
background: Color;
|
|
109
|
+
underline: boolean;
|
|
110
|
+
strikethrough: boolean;
|
|
111
|
+
width: number;
|
|
112
|
+
height: number;
|
|
113
|
+
ascent: number;
|
|
114
|
+
descent: number;
|
|
115
|
+
offset: number;
|
|
116
|
+
}
|
|
117
|
+
interface RichTextLine {
|
|
118
|
+
segments: RichTextSpanSegment[];
|
|
119
|
+
width: number;
|
|
120
|
+
height: number;
|
|
121
|
+
baseline: number;
|
|
122
|
+
}
|
|
123
|
+
interface LayoutNode {
|
|
124
|
+
element: Element;
|
|
125
|
+
layout: ComputedLayout;
|
|
126
|
+
children: LayoutNode[];
|
|
127
|
+
lines?: string[];
|
|
128
|
+
lineOffsets?: number[];
|
|
129
|
+
richLines?: RichTextLine[];
|
|
130
|
+
}
|
|
104
131
|
interface LayoutConstraints {
|
|
105
132
|
minWidth: number;
|
|
106
133
|
maxWidth: number;
|
|
@@ -109,7 +136,7 @@ interface LayoutConstraints {
|
|
|
109
136
|
}
|
|
110
137
|
//#endregion
|
|
111
138
|
//#region src/types/components.d.ts
|
|
112
|
-
type ElementType = "box" | "text" | "image" | "
|
|
139
|
+
type ElementType = "box" | "text" | "richtext" | "image" | "svg" | "stack";
|
|
113
140
|
interface ElementBase {
|
|
114
141
|
type: ElementType;
|
|
115
142
|
}
|
|
@@ -140,8 +167,29 @@ interface TextProps extends LayoutProps {
|
|
|
140
167
|
interface TextElement extends ElementBase, TextProps {
|
|
141
168
|
type: "text";
|
|
142
169
|
}
|
|
170
|
+
interface RichTextStyleProps {
|
|
171
|
+
font?: FontProps;
|
|
172
|
+
color?: Color;
|
|
173
|
+
background?: Color;
|
|
174
|
+
underline?: boolean;
|
|
175
|
+
strikethrough?: boolean;
|
|
176
|
+
}
|
|
177
|
+
interface RichTextSpan extends RichTextStyleProps {
|
|
178
|
+
text: string;
|
|
179
|
+
}
|
|
180
|
+
interface RichTextProps extends LayoutProps, RichTextStyleProps {
|
|
181
|
+
spans: RichTextSpan[];
|
|
182
|
+
lineHeight?: number;
|
|
183
|
+
align?: "left" | "center" | "right";
|
|
184
|
+
verticalAlign?: "top" | "middle" | "bottom";
|
|
185
|
+
maxLines?: number;
|
|
186
|
+
ellipsis?: boolean;
|
|
187
|
+
}
|
|
188
|
+
interface RichTextElement extends ElementBase, RichTextProps {
|
|
189
|
+
type: "richtext";
|
|
190
|
+
}
|
|
143
191
|
interface ImageProps extends LayoutProps {
|
|
144
|
-
src:
|
|
192
|
+
src: ImageBitmap | CanvasImageSource;
|
|
145
193
|
fit?: "contain" | "cover" | "fill" | "none" | "scale-down";
|
|
146
194
|
position?: {
|
|
147
195
|
x?: "left" | "center" | "right" | number;
|
|
@@ -154,50 +202,112 @@ interface ImageProps extends LayoutProps {
|
|
|
154
202
|
interface ImageElement extends ElementBase, ImageProps {
|
|
155
203
|
type: "image";
|
|
156
204
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
shape: ShapeType;
|
|
160
|
-
fill?: Color;
|
|
205
|
+
interface SvgStyleProps {
|
|
206
|
+
fill?: Color | "none";
|
|
161
207
|
stroke?: StrokeProps;
|
|
208
|
+
opacity?: number;
|
|
209
|
+
}
|
|
210
|
+
interface SvgTransformProps {
|
|
211
|
+
transform?: {
|
|
212
|
+
translate?: [number, number];
|
|
213
|
+
rotate?: number | [number, number, number];
|
|
214
|
+
scale?: number | [number, number];
|
|
215
|
+
skewX?: number;
|
|
216
|
+
skewY?: number;
|
|
217
|
+
matrix?: [number, number, number, number, number, number];
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
interface SvgRectChild extends SvgStyleProps, SvgTransformProps {
|
|
221
|
+
type: "rect";
|
|
222
|
+
x?: number;
|
|
223
|
+
y?: number;
|
|
224
|
+
width: number;
|
|
225
|
+
height: number;
|
|
226
|
+
rx?: number;
|
|
227
|
+
ry?: number;
|
|
228
|
+
}
|
|
229
|
+
interface SvgCircleChild extends SvgStyleProps, SvgTransformProps {
|
|
230
|
+
type: "circle";
|
|
231
|
+
cx: number;
|
|
232
|
+
cy: number;
|
|
233
|
+
r: number;
|
|
234
|
+
}
|
|
235
|
+
interface SvgEllipseChild extends SvgStyleProps, SvgTransformProps {
|
|
236
|
+
type: "ellipse";
|
|
237
|
+
cx: number;
|
|
238
|
+
cy: number;
|
|
239
|
+
rx: number;
|
|
240
|
+
ry: number;
|
|
241
|
+
}
|
|
242
|
+
interface SvgLineChild extends SvgStyleProps, SvgTransformProps {
|
|
243
|
+
type: "line";
|
|
244
|
+
x1: number;
|
|
245
|
+
y1: number;
|
|
246
|
+
x2: number;
|
|
247
|
+
y2: number;
|
|
248
|
+
}
|
|
249
|
+
interface SvgPolylineChild extends SvgStyleProps, SvgTransformProps {
|
|
250
|
+
type: "polyline";
|
|
251
|
+
points: [number, number][];
|
|
252
|
+
}
|
|
253
|
+
interface SvgPolygonChild extends SvgStyleProps, SvgTransformProps {
|
|
254
|
+
type: "polygon";
|
|
255
|
+
points: [number, number][];
|
|
256
|
+
}
|
|
257
|
+
interface SvgPathChild extends SvgStyleProps, SvgTransformProps {
|
|
258
|
+
type: "path";
|
|
259
|
+
d: string;
|
|
260
|
+
}
|
|
261
|
+
interface SvgTextChild extends SvgStyleProps, SvgTransformProps {
|
|
262
|
+
type: "text";
|
|
263
|
+
x?: number;
|
|
264
|
+
y?: number;
|
|
265
|
+
content: string;
|
|
266
|
+
font?: FontProps;
|
|
267
|
+
textAnchor?: "start" | "middle" | "end";
|
|
268
|
+
dominantBaseline?: "auto" | "middle" | "hanging";
|
|
269
|
+
}
|
|
270
|
+
interface SvgGroupChild extends SvgStyleProps, SvgTransformProps {
|
|
271
|
+
type: "g";
|
|
272
|
+
children: SvgChild[];
|
|
273
|
+
}
|
|
274
|
+
type SvgChild = SvgRectChild | SvgCircleChild | SvgEllipseChild | SvgLineChild | SvgPolylineChild | SvgPolygonChild | SvgPathChild | SvgTextChild | SvgGroupChild;
|
|
275
|
+
type SvgAlign = "none" | "xMinYMin" | "xMidYMin" | "xMaxYMin" | "xMinYMid" | "xMidYMid" | "xMaxYMid" | "xMinYMax" | "xMidYMax" | "xMaxYMax";
|
|
276
|
+
interface SvgProps extends LayoutProps {
|
|
277
|
+
viewBox?: {
|
|
278
|
+
x?: number;
|
|
279
|
+
y?: number;
|
|
280
|
+
width: number;
|
|
281
|
+
height: number;
|
|
282
|
+
};
|
|
283
|
+
preserveAspectRatio?: {
|
|
284
|
+
align?: SvgAlign;
|
|
285
|
+
meetOrSlice?: "meet" | "slice";
|
|
286
|
+
};
|
|
287
|
+
children: SvgChild[];
|
|
288
|
+
background?: Color;
|
|
162
289
|
shadow?: Shadow;
|
|
163
|
-
points?: [number, number][];
|
|
164
|
-
path?: string;
|
|
165
290
|
}
|
|
166
|
-
interface
|
|
167
|
-
type: "
|
|
291
|
+
interface SvgElement extends ElementBase, SvgProps {
|
|
292
|
+
type: "svg";
|
|
168
293
|
}
|
|
169
|
-
|
|
294
|
+
type StackAlign = "start" | "end" | "center";
|
|
295
|
+
interface StackProps extends LayoutProps {
|
|
170
296
|
children: Element[];
|
|
171
297
|
background?: Color;
|
|
172
298
|
border?: Border;
|
|
173
299
|
shadow?: Shadow;
|
|
174
300
|
opacity?: number;
|
|
175
301
|
clip?: boolean;
|
|
302
|
+
/** 水平对齐方式(默认 start) */
|
|
303
|
+
align?: StackAlign;
|
|
304
|
+
/** 垂直对齐方式(默认 start) */
|
|
305
|
+
justify?: StackAlign;
|
|
176
306
|
}
|
|
177
307
|
interface StackElement extends ElementBase, StackProps {
|
|
178
308
|
type: "stack";
|
|
179
309
|
}
|
|
180
|
-
type Element = BoxElement | TextElement | ImageElement |
|
|
181
|
-
//#endregion
|
|
182
|
-
//#region src/layout/measure.d.ts
|
|
183
|
-
interface MeasureContext {
|
|
184
|
-
measureText(text: string, font: FontProps): {
|
|
185
|
-
width: number;
|
|
186
|
-
height: number;
|
|
187
|
-
offset: number;
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
declare function createCanvasMeasureContext(ctx: CanvasRenderingContext2D): MeasureContext;
|
|
191
|
-
//#endregion
|
|
192
|
-
//#region src/layout/engine.d.ts
|
|
193
|
-
interface LayoutNode {
|
|
194
|
-
element: Element;
|
|
195
|
-
layout: ComputedLayout;
|
|
196
|
-
children: LayoutNode[];
|
|
197
|
-
lines?: string[];
|
|
198
|
-
lineOffsets?: number[];
|
|
199
|
-
}
|
|
200
|
-
declare function computeLayout(element: Element, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
|
|
310
|
+
type Element = BoxElement | TextElement | RichTextElement | ImageElement | SvgElement | StackElement;
|
|
201
311
|
//#endregion
|
|
202
312
|
//#region src/canvas.d.ts
|
|
203
313
|
interface CanvasOptions {
|
|
@@ -218,11 +328,12 @@ interface DrawCallCanvas {
|
|
|
218
328
|
readonly width: number;
|
|
219
329
|
readonly height: number;
|
|
220
330
|
readonly pixelRatio: number;
|
|
331
|
+
readonly canvas: HTMLCanvasElement;
|
|
221
332
|
render(element: Element): LayoutNode;
|
|
222
333
|
clear(): void;
|
|
223
334
|
getContext(): CanvasRenderingContext2D;
|
|
224
335
|
toDataURL(type?: string, quality?: number): string;
|
|
225
|
-
toBuffer(type?: "image/png" | "image/jpeg"):
|
|
336
|
+
toBuffer(type?: "image/png" | "image/jpeg"): Buffer;
|
|
226
337
|
}
|
|
227
338
|
/**
|
|
228
339
|
* 创建适用于浏览器环境的 Canvas
|
|
@@ -231,4 +342,4 @@ interface DrawCallCanvas {
|
|
|
231
342
|
*/
|
|
232
343
|
declare function createCanvas(options: CanvasOptions): DrawCallCanvas;
|
|
233
344
|
//#endregion
|
|
234
|
-
export {
|
|
345
|
+
export { linearGradient as $, SvgTransformProps as A, LayoutProps as B, SvgPathChild as C, SvgRectChild as D, SvgProps as E, ContainerLayoutProps as F, FontProps as G, Bounds as H, FlexDirection as I, RadialGradientDescriptor as J, GradientDescriptor as K, JustifyContent as L, TextProps as M, AlignItems as N, SvgStyleProps as O, AlignSelf as P, StrokeProps as Q, LayoutConstraints as R, SvgLineChild as S, SvgPolylineChild as T, Color as U, Border as V, ColorStop as W, Size as X, Shadow as Y, Spacing as Z, SvgChild as _, BoxElement as a, SvgEllipseChild as b, ImageElement as c, RichTextProps as d, radialGradient as et, RichTextSpan as f, SvgAlign as g, StackProps as h, createCanvas as i, TextElement as j, SvgTextChild as k, ImageProps as l, StackElement as m, DrawCallCanvas as n, BoxProps as o, StackAlign as p, LinearGradientDescriptor as q, LayoutSize as r, Element as s, CanvasOptions as t, RichTextElement as u, SvgCircleChild as v, SvgPolygonChild as w, SvgGroupChild as x, SvgElement as y, LayoutNode as z };
|