@meonode/canvas 1.1.0 → 1.3.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 → README.md} +320 -215
- package/dist/cjs/canvas/canvas.type.d.ts +50 -7
- package/dist/cjs/canvas/canvas.type.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.js +75 -8
- package/dist/cjs/canvas/chart.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.d.ts +25 -18
- package/dist/cjs/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.js +298 -210
- package/dist/cjs/canvas/grid.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.js +84 -51
- package/dist/cjs/canvas/text.canvas.util.js.map +1 -1
- package/dist/esm/canvas/canvas.type.d.ts +50 -7
- package/dist/esm/canvas/canvas.type.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.js +75 -8
- package/dist/esm/canvas/grid.canvas.util.d.ts +25 -18
- package/dist/esm/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.js +298 -210
- package/dist/esm/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/text.canvas.util.js +84 -51
- package/package.json +25 -17
package/{Readme.md → README.md}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @meonode/canvas
|
|
2
2
|
|
|
3
|
-
A declarative, component-based library for
|
|
4
|
-
the
|
|
3
|
+
A declarative, component-based library for server-side canvas image generation. Write complex visuals with simple
|
|
4
|
+
functions, similar to the composition style of @meonode/ui.
|
|
5
5
|
It uses `skia-canvas` for drawing and `yoga-layout` for flexbox-based layouts.
|
|
6
6
|
|
|
7
7
|
This library allows you to build complex image layouts using a familiar component-based approach. You can define your
|
|
@@ -24,15 +24,16 @@ rendering to a canvas.
|
|
|
24
24
|
|
|
25
25
|
<table>
|
|
26
26
|
<tr>
|
|
27
|
-
<td><img src="https://i.ibb.co/VpPZybzF/profile-card.webp" alt="Image 1"></td>
|
|
28
|
-
<td><img src="https://i.ibb.co/zTgrBWpT/profile-card-1.webp" alt="Image 2"></td>
|
|
27
|
+
<td width="50%"><img src="https://i.ibb.co/VpPZybzF/profile-card.webp" alt="Image 1"></td>
|
|
28
|
+
<td width="50%"><img src="https://i.ibb.co/zTgrBWpT/profile-card-1.webp" alt="Image 2"></td>
|
|
29
29
|
</tr>
|
|
30
30
|
<tr>
|
|
31
|
-
<td><img src="https://i.ibb.co/F4xfHdBp/daily-notes.webp" alt="Image 3"></td>
|
|
32
|
-
<td><img src="https://i.ibb.co/Jj0x6khB/character-archive-base.webp" alt="Image 4"></td>
|
|
31
|
+
<td width="50%"><img src="https://i.ibb.co/F4xfHdBp/daily-notes.webp" alt="Image 3"></td>
|
|
32
|
+
<td width="50%"><img src="https://i.ibb.co/Jj0x6khB/character-archive-base.webp" alt="Image 4"></td>
|
|
33
33
|
</tr>
|
|
34
34
|
<tr>
|
|
35
|
-
<td
|
|
35
|
+
<td width="50%"><img src="https://i.ibb.co.com/B24SZ0C9/charts.webp" alt="Image 5"/></td>
|
|
36
|
+
<td width="50%"><img src="https://i.ibb.co.com/q3sy9r2L/sample-grids.png" alt="Image 6"/></td>
|
|
36
37
|
</tr>
|
|
37
38
|
</table>
|
|
38
39
|
|
|
@@ -51,41 +52,41 @@ import {Root, Box, Text} from '@meonode/canvas';
|
|
|
51
52
|
import {writeFile} from 'fs/promises';
|
|
52
53
|
|
|
53
54
|
async function generateImage() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
children: [
|
|
64
|
-
Box({
|
|
65
|
-
width: '100%',
|
|
66
|
-
height: '100%',
|
|
67
|
-
backgroundColor: '#f0f0f0',
|
|
68
|
-
padding: 20,
|
|
55
|
+
const canvas = await Root({
|
|
56
|
+
width: 500,
|
|
57
|
+
height: 300,
|
|
58
|
+
fonts: [
|
|
59
|
+
{
|
|
60
|
+
family: 'Roboto',
|
|
61
|
+
paths: ['./fonts/Roboto-Regular.ttf', './fonts/Roboto-Bold.ttf'],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
69
64
|
children: [
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
Box({
|
|
66
|
+
width: '100%',
|
|
67
|
+
height: '100%',
|
|
68
|
+
backgroundColor: '#f0f0f0',
|
|
69
|
+
padding: 20,
|
|
70
|
+
children: [
|
|
71
|
+
Text('Hello, World!', {
|
|
72
|
+
fontSize: 32,
|
|
73
|
+
fontWeight: 'bold',
|
|
74
|
+
fontFamily: 'Roboto',
|
|
75
|
+
color: '#333',
|
|
76
|
+
}),
|
|
77
|
+
Text('This is a basic example of using @meonode/canvas.', {
|
|
78
|
+
fontSize: 18,
|
|
79
|
+
fontFamily: 'Roboto',
|
|
80
|
+
color: '#666',
|
|
81
|
+
margin: {Top: 10},
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
}),
|
|
82
85
|
],
|
|
83
|
-
|
|
84
|
-
],
|
|
85
|
-
});
|
|
86
|
+
});
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
const buffer = await canvas.toBuffer('png');
|
|
89
|
+
await writeFile('output.png', buffer);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
generateImage().catch(console.error);
|
|
@@ -101,109 +102,109 @@ import {Root, Column, Row, Text, Image, Style} from '@meonode/canvas';
|
|
|
101
102
|
import {writeFile} from 'fs/promises';
|
|
102
103
|
|
|
103
104
|
async function generateComplexImage() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
children: [
|
|
118
|
-
Column({
|
|
119
|
-
width: '100%',
|
|
120
|
-
height: '100%',
|
|
121
|
-
backgroundColor: '#f0f0f0',
|
|
122
|
-
padding: 20,
|
|
123
|
-
justifyContent: Style.Justify.SpaceBetween,
|
|
105
|
+
const canvas = await Root({
|
|
106
|
+
width: 800,
|
|
107
|
+
height: 600,
|
|
108
|
+
fonts: [
|
|
109
|
+
{
|
|
110
|
+
family: 'Roboto',
|
|
111
|
+
paths: ['./fonts/Roboto-Regular.ttf', './fonts/Roboto-Bold.ttf'],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
family: 'Open Sans',
|
|
115
|
+
paths: ['./fonts/OpenSans-Regular.ttf'],
|
|
116
|
+
},
|
|
117
|
+
],
|
|
124
118
|
children: [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
119
|
+
Column({
|
|
120
|
+
width: '100%',
|
|
121
|
+
height: '100%',
|
|
122
|
+
backgroundColor: '#f0f0f0',
|
|
123
|
+
padding: 20,
|
|
124
|
+
justifyContent: Style.Justify.SpaceBetween,
|
|
125
|
+
children: [
|
|
126
|
+
// Header Section
|
|
127
|
+
Row({
|
|
128
|
+
width: '100%',
|
|
129
|
+
alignItems: Style.Align.Center,
|
|
130
|
+
marginBottom: 20,
|
|
131
|
+
children: [
|
|
132
|
+
Image({
|
|
133
|
+
src: 'https://via.placeholder.com/80x80/FF0000/FFFFFF?text=Logo',
|
|
134
|
+
width: 80,
|
|
135
|
+
height: 80,
|
|
136
|
+
borderRadius: 40,
|
|
137
|
+
marginRight: 20,
|
|
138
|
+
objectFit: 'cover',
|
|
139
|
+
}),
|
|
140
|
+
Text('Welcome to MeoNode Canvas!', {
|
|
141
|
+
fontSize: 40,
|
|
142
|
+
fontWeight: 'bold',
|
|
143
|
+
fontFamily: 'Roboto',
|
|
144
|
+
color: '#333',
|
|
145
|
+
}),
|
|
146
|
+
],
|
|
147
|
+
}),
|
|
148
|
+
|
|
149
|
+
// Main Content Section
|
|
150
|
+
Column({
|
|
151
|
+
flexGrow: 1,
|
|
152
|
+
width: '100%',
|
|
153
|
+
backgroundColor: '#ffffff',
|
|
154
|
+
borderRadius: 10,
|
|
155
|
+
padding: 30,
|
|
156
|
+
boxShadow: {blur: 10, color: 'rgba(0,0,0,0.1)'},
|
|
157
|
+
children: [
|
|
158
|
+
Text('A New Way to Render Graphics', {
|
|
159
|
+
fontSize: 28,
|
|
160
|
+
fontWeight: 'bold',
|
|
161
|
+
fontFamily: 'Open Sans',
|
|
162
|
+
color: '#555',
|
|
163
|
+
marginBottom: 15,
|
|
164
|
+
}),
|
|
165
|
+
Text(
|
|
166
|
+
`This example demonstrates a more complex layout using various components.
|
|
166
167
|
We have a header with a logo and title, a main content area with text,
|
|
167
168
|
and a footer. Notice how flexbox properties are used to arrange elements.`,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
169
|
+
{
|
|
170
|
+
fontSize: 18,
|
|
171
|
+
fontFamily: 'Open Sans',
|
|
172
|
+
color: '#777',
|
|
173
|
+
lineHeight: 24,
|
|
174
|
+
},
|
|
175
|
+
),
|
|
176
|
+
Image({
|
|
177
|
+
src: 'https://via.placeholder.com/600x200/007bff/ffffff?text=Feature+Image',
|
|
178
|
+
width: '100%',
|
|
179
|
+
height: 200,
|
|
180
|
+
marginTop: 20,
|
|
181
|
+
borderRadius: 8,
|
|
182
|
+
objectFit: 'contain',
|
|
183
|
+
objectPosition: {Top: '50%', Left: '50%'},
|
|
184
|
+
}),
|
|
185
|
+
],
|
|
186
|
+
}),
|
|
187
|
+
|
|
188
|
+
// Footer Section
|
|
189
|
+
Row({
|
|
190
|
+
width: '100%',
|
|
191
|
+
marginTop: 20,
|
|
192
|
+
justifyContent: Style.Justify.Center,
|
|
193
|
+
children: [
|
|
194
|
+
Text('© 2025 MeoNode Canvas. All rights reserved.', {
|
|
195
|
+
fontSize: 14,
|
|
196
|
+
fontFamily: 'Open Sans',
|
|
197
|
+
color: '#999',
|
|
198
|
+
}),
|
|
199
|
+
],
|
|
200
|
+
}),
|
|
201
|
+
],
|
|
202
|
+
}),
|
|
200
203
|
],
|
|
201
|
-
|
|
202
|
-
],
|
|
203
|
-
});
|
|
204
|
+
});
|
|
204
205
|
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
const buffer = await canvas.toBuffer('png');
|
|
207
|
+
await writeFile('complex_output.png', buffer);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
generateComplexImage().catch(console.error);
|
|
@@ -220,35 +221,39 @@ import {Root, Chart} from '@meonode/canvas';
|
|
|
220
221
|
import {writeFile} from 'fs/promises';
|
|
221
222
|
|
|
222
223
|
async function generateBarChart() {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
224
|
+
const canvas = await Root({
|
|
225
|
+
width: 600,
|
|
226
|
+
height: 400,
|
|
227
|
+
children: [
|
|
228
|
+
Chart({
|
|
229
|
+
type: 'bar',
|
|
230
|
+
width: '100%',
|
|
231
|
+
height: '100%',
|
|
232
|
+
data: {
|
|
233
|
+
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
|
|
234
|
+
datasets: [
|
|
235
|
+
{
|
|
236
|
+
label: 'Sales',
|
|
237
|
+
data: [120, 150, 180, 90, 200],
|
|
238
|
+
color: '#36A2EB',
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
options: {
|
|
243
|
+
gridOptions: {show: true, style: 'dashed'},
|
|
244
|
+
axisColor: '#333',
|
|
245
|
+
labelColor: '#333',
|
|
246
|
+
showValues: true,
|
|
247
|
+
valueFontSize: 12,
|
|
248
|
+
showYAxis: true,
|
|
249
|
+
yAxisColor: '#666',
|
|
250
|
+
},
|
|
251
|
+
}),
|
|
252
|
+
],
|
|
253
|
+
});
|
|
249
254
|
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
const buffer = await canvas.toBuffer('png');
|
|
256
|
+
await writeFile('bar_chart.png', buffer);
|
|
252
257
|
}
|
|
253
258
|
|
|
254
259
|
generateBarChart().catch(console.error);
|
|
@@ -261,42 +266,128 @@ import {Root, Chart, Row, Box, Text} from '@meonode/canvas';
|
|
|
261
266
|
import {writeFile} from 'fs/promises';
|
|
262
267
|
|
|
263
268
|
async function generateDoughnutChart() {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
269
|
+
const canvas = await Root({
|
|
270
|
+
width: 600,
|
|
271
|
+
height: 400,
|
|
272
|
+
children: [
|
|
273
|
+
Chart({
|
|
274
|
+
type: 'doughnut',
|
|
275
|
+
width: '100%',
|
|
276
|
+
height: '100%',
|
|
277
|
+
data: [
|
|
278
|
+
{label: 'Red', value: 300, color: '#FF6384'},
|
|
279
|
+
{label: 'Blue', value: 50, color: '#36A2EB'},
|
|
280
|
+
{label: 'Yellow', value: 100, color: '#FFCE56'},
|
|
281
|
+
],
|
|
282
|
+
options: {
|
|
283
|
+
innerRadius: 0.7,
|
|
284
|
+
sliceBorderRadius: 5,
|
|
285
|
+
renderLegendItem: ({item, color}) =>
|
|
286
|
+
Row({
|
|
287
|
+
alignItems: 'center',
|
|
288
|
+
children: [
|
|
289
|
+
Box({width: 12, height: 12, backgroundColor: color, borderRadius: 6}),
|
|
290
|
+
Text(`${item.label}: ${item.value}`, {fontSize: 16, marginLeft: 8}),
|
|
291
|
+
],
|
|
292
|
+
}),
|
|
293
|
+
},
|
|
287
294
|
}),
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
],
|
|
291
|
-
});
|
|
295
|
+
],
|
|
296
|
+
});
|
|
292
297
|
|
|
293
|
-
|
|
294
|
-
|
|
298
|
+
const buffer = await canvas.toBuffer('png');
|
|
299
|
+
await writeFile('doughnut_chart.png', buffer);
|
|
295
300
|
}
|
|
296
301
|
|
|
297
302
|
generateDoughnutChart().catch(console.error);
|
|
298
303
|
```
|
|
299
304
|
|
|
305
|
+
## Grid Layout Examples
|
|
306
|
+
|
|
307
|
+
The `Grid` component simplifies creating complex layouts. It mimics CSS Grid Layout.
|
|
308
|
+
|
|
309
|
+
### Basic Grid
|
|
310
|
+
|
|
311
|
+
A simple grid with 3 columns, each 100 pixels wide.
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import {Root, Grid, Box, Text} from '@meonode/canvas';
|
|
315
|
+
import {writeFile} from 'fs/promises';
|
|
316
|
+
|
|
317
|
+
async function generateBasicGrid() {
|
|
318
|
+
const canvas = await Root({
|
|
319
|
+
width: 400,
|
|
320
|
+
height: 300,
|
|
321
|
+
children: [
|
|
322
|
+
Grid({
|
|
323
|
+
columns: 3,
|
|
324
|
+
templateColumns: [100, 100, 100], // or ['100px', '100px', '100px']
|
|
325
|
+
gap: 10,
|
|
326
|
+
children: [
|
|
327
|
+
Box({backgroundColor: 'red', height: 50, children: [Text('1')]}),
|
|
328
|
+
Box({backgroundColor: 'blue', height: 50, children: [Text('2')]}),
|
|
329
|
+
Box({backgroundColor: 'green', height: 50, children: [Text('3')]}),
|
|
330
|
+
Box({backgroundColor: 'yellow', height: 50, children: [Text('4')]}),
|
|
331
|
+
],
|
|
332
|
+
}),
|
|
333
|
+
],
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
await canvas.toFile('grid_basic.png');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
generateBasicGrid();
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Responsive Grid (Fractional Units)
|
|
343
|
+
|
|
344
|
+
Using fractional units (`fr`) allows columns to take up proportional space.
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
Grid({
|
|
348
|
+
// First column takes 1 part, second takes 2 parts, third takes 1 part
|
|
349
|
+
templateColumns: ['1fr', '2fr', '1fr'],
|
|
350
|
+
gap: 10,
|
|
351
|
+
children: [
|
|
352
|
+
Box({backgroundColor: 'red', height: 50, children: [Text('1fr')]}),
|
|
353
|
+
Box({backgroundColor: 'blue', height: 50, children: [Text('2fr')]}),
|
|
354
|
+
Box({backgroundColor: 'green', height: 50, children: [Text('1fr')]}),
|
|
355
|
+
],
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Spanning Items
|
|
360
|
+
|
|
361
|
+
Use `GridItem` (or just passing `gridColumn`/`gridRow` props to any child) to span multiple columns or rows.
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import {Grid, GridItem, Box, Text} from '@meonode/canvas';
|
|
365
|
+
|
|
366
|
+
Grid({
|
|
367
|
+
templateColumns: ['1fr', '1fr', '1fr'],
|
|
368
|
+
gap: 10,
|
|
369
|
+
children: [
|
|
370
|
+
// Spans all 3 columns
|
|
371
|
+
GridItem({
|
|
372
|
+
gridColumn: 'span 3',
|
|
373
|
+
height: 50,
|
|
374
|
+
backgroundColor: '#333',
|
|
375
|
+
children: [Text('Header', {color: 'white'})],
|
|
376
|
+
}),
|
|
377
|
+
// Standard items
|
|
378
|
+
Box({backgroundColor: '#eee', height: 100, children: [Text('Content')]}),
|
|
379
|
+
Box({backgroundColor: '#ccc', height: 100, children: [Text('Sidebar')]}),
|
|
380
|
+
// Spans 2 columns
|
|
381
|
+
GridItem({
|
|
382
|
+
gridColumn: 'span 2',
|
|
383
|
+
height: 50,
|
|
384
|
+
backgroundColor: '#555',
|
|
385
|
+
children: [Text('Footer', {color: 'white'})],
|
|
386
|
+
}),
|
|
387
|
+
],
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
300
391
|
## Using Yoga Layout Properties
|
|
301
392
|
|
|
302
393
|
This library leverages `yoga-layout` for its powerful flexbox engine. Many layout properties directly map to Yoga's
|
|
@@ -308,19 +399,19 @@ For example, to set `flexDirection` to `row` or `positionType` to `absolute`, yo
|
|
|
308
399
|
import {Box, Style} from '@meonode/canvas';
|
|
309
400
|
|
|
310
401
|
Box({
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
402
|
+
flexDirection: Style.FlexDirection.Row,
|
|
403
|
+
justifyContent: Style.Justify.Center,
|
|
404
|
+
alignItems: Style.Align.Center,
|
|
405
|
+
children: [
|
|
406
|
+
Box({
|
|
407
|
+
width: 100,
|
|
408
|
+
height: 100,
|
|
409
|
+
backgroundColor: 'red',
|
|
410
|
+
positionType: Style.PositionType.Absolute,
|
|
411
|
+
position: {Top: 10, Left: 10},
|
|
412
|
+
}),
|
|
413
|
+
// ... other children
|
|
414
|
+
],
|
|
324
415
|
});
|
|
325
416
|
```
|
|
326
417
|
|
|
@@ -439,10 +530,17 @@ The `Grid` component arranges its children in a grid layout. It is a specialized
|
|
|
439
530
|
|
|
440
531
|
#### Grid-Specific Props
|
|
441
532
|
|
|
442
|
-
| Prop
|
|
443
|
-
|
|
444
|
-
| `columns`
|
|
445
|
-
| `
|
|
533
|
+
| Prop | Type | Description |
|
|
534
|
+
|-------------------|----------------------------------------------------------|---------------------------------------------------------|
|
|
535
|
+
| `columns` | `number` | The number of columns in the grid. Default is 1. |
|
|
536
|
+
| `templateColumns` | `GridTrackSize[]` | Defines the columns of the grid (e.g., `[100, '1fr']`). |
|
|
537
|
+
| `templateRows` | `GridTrackSize[]` | Defines the rows of the grid. |
|
|
538
|
+
| `autoRows` | `GridTrackSize` | Specifies the size of implicitly created rows. |
|
|
539
|
+
| `autoFlow` | `'row' \| 'column' \| 'row-dense' \| 'column-dense'` | Controls how the auto-placement algorithm works. |
|
|
540
|
+
| `gap` | `number \| string` | Defines the gap between grid items. |
|
|
541
|
+
| `rowGap` | `number \| string` | Defines the row gap. |
|
|
542
|
+
| `columnGap` | `number \| string` | Defines the column gap. |
|
|
543
|
+
| `direction` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | The direction of the grid layout. Default is 'row'. |
|
|
446
544
|
|
|
447
545
|
---
|
|
448
546
|
|
|
@@ -476,10 +574,17 @@ The `options` prop is a conditional type that changes based on the chart `type`.
|
|
|
476
574
|
|
|
477
575
|
##### Cartesian Chart Options (`bar`, `line`)
|
|
478
576
|
|
|
479
|
-
| Prop
|
|
480
|
-
|
|
481
|
-
| `gridOptions`
|
|
482
|
-
| `axisColor`
|
|
577
|
+
| Prop | Type | Description |
|
|
578
|
+
|-----------------------|-----------------------------|-------------------------------------------------------------------|
|
|
579
|
+
| `gridOptions` | `GridOptions` | An object to configure the grid lines (`show`, `color`, `style`). |
|
|
580
|
+
| `axisColor` | `string` | The color of the chart axes. |
|
|
581
|
+
| `showValues` | `boolean` | If `true`, displays values on top of bars or points. |
|
|
582
|
+
| `valueColor` | `string` | Color of the value labels. |
|
|
583
|
+
| `valueFontSize` | `number` | Font size of the value labels. |
|
|
584
|
+
| `showYAxis` | `boolean` | If `true`, displays the Y-axis labels on the left. |
|
|
585
|
+
| `yAxisColor` | `string` | Color of the Y-axis labels. |
|
|
586
|
+
| `yAxisFontSize` | `number` | Font size of the Y-axis labels. |
|
|
587
|
+
| `yAxisLabelFormatter` | `(value: number) => string` | Custom formatter for Y-axis labels. |
|
|
483
588
|
|
|
484
589
|
##### Pie & Doughnut Chart Options (`pie`, `doughnut`)
|
|
485
590
|
|