@meonode/canvas 1.3.1 → 1.5.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 +281 -253
- package/dist/cjs/canvas/canvas.type.d.ts +1 -0
- package/dist/cjs/canvas/canvas.type.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.d.ts +1 -0
- package/dist/cjs/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.js +34 -8
- package/dist/cjs/canvas/chart.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.js +0 -10
- package/dist/cjs/canvas/grid.canvas.util.js.map +1 -1
- package/dist/esm/canvas/canvas.type.d.ts +1 -0
- package/dist/esm/canvas/canvas.type.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.d.ts +1 -0
- package/dist/esm/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.js +34 -8
- package/dist/esm/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/grid.canvas.util.js +0 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ rendering to a canvas.
|
|
|
33
33
|
</tr>
|
|
34
34
|
<tr>
|
|
35
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/
|
|
36
|
+
<td width="50%"><img src="https://i.ibb.co.com/jkBJMRgT/sample-nested-grids.png" alt="Image 6"/></td>
|
|
37
37
|
</tr>
|
|
38
38
|
</table>
|
|
39
39
|
|
|
@@ -52,41 +52,41 @@ import {Root, Box, Text} from '@meonode/canvas';
|
|
|
52
52
|
import {writeFile} from 'fs/promises';
|
|
53
53
|
|
|
54
54
|
async function generateImage() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
],
|
|
64
|
+
children: [
|
|
65
|
+
Box({
|
|
66
|
+
width: '100%',
|
|
67
|
+
height: '100%',
|
|
68
|
+
backgroundColor: '#f0f0f0',
|
|
69
|
+
padding: 20,
|
|
64
70
|
children: [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
}),
|
|
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
|
+
}),
|
|
85
83
|
],
|
|
86
|
-
|
|
84
|
+
}),
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const buffer = await canvas.toBuffer('png');
|
|
89
|
+
await writeFile('output.png', buffer);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
generateImage().catch(console.error);
|
|
@@ -102,109 +102,109 @@ import {Root, Column, Row, Text, Image, Style} from '@meonode/canvas';
|
|
|
102
102
|
import {writeFile} from 'fs/promises';
|
|
103
103
|
|
|
104
104
|
async function generateComplexImage() {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
+
],
|
|
118
|
+
children: [
|
|
119
|
+
Column({
|
|
120
|
+
width: '100%',
|
|
121
|
+
height: '100%',
|
|
122
|
+
backgroundColor: '#f0f0f0',
|
|
123
|
+
padding: 20,
|
|
124
|
+
justifyContent: Style.Justify.SpaceBetween,
|
|
118
125
|
children: [
|
|
119
|
-
|
|
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.
|
|
167
|
+
We have a header with a logo and title, a main content area with text,
|
|
168
|
+
and a footer. Notice how flexbox properties are used to arrange elements.`,
|
|
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',
|
|
120
178
|
width: '100%',
|
|
121
|
-
height:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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.
|
|
167
|
-
We have a header with a logo and title, a main content area with text,
|
|
168
|
-
and a footer. Notice how flexbox properties are used to arrange elements.`,
|
|
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
|
-
}),
|
|
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
|
+
}),
|
|
203
201
|
],
|
|
204
|
-
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
});
|
|
205
205
|
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
const buffer = await canvas.toBuffer('png');
|
|
207
|
+
await writeFile('complex_output.png', buffer);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
generateComplexImage().catch(console.error);
|
|
@@ -221,39 +221,39 @@ import {Root, Chart} from '@meonode/canvas';
|
|
|
221
221
|
import {writeFile} from 'fs/promises';
|
|
222
222
|
|
|
223
223
|
async function generateBarChart() {
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
+
});
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
const buffer = await canvas.toBuffer('png');
|
|
256
|
+
await writeFile('bar_chart.png', buffer);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
generateBarChart().catch(console.error);
|
|
@@ -266,37 +266,37 @@ import {Root, Chart, Row, Box, Text} from '@meonode/canvas';
|
|
|
266
266
|
import {writeFile} from 'fs/promises';
|
|
267
267
|
|
|
268
268
|
async function generateDoughnutChart() {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
-
},
|
|
294
|
-
}),
|
|
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'},
|
|
295
281
|
],
|
|
296
|
-
|
|
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
|
+
},
|
|
294
|
+
}),
|
|
295
|
+
],
|
|
296
|
+
});
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
const buffer = await canvas.toBuffer('png');
|
|
299
|
+
await writeFile('doughnut_chart.png', buffer);
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
generateDoughnutChart().catch(console.error);
|
|
@@ -315,25 +315,25 @@ import {Root, Grid, Box, Text} from '@meonode/canvas';
|
|
|
315
315
|
import {writeFile} from 'fs/promises';
|
|
316
316
|
|
|
317
317
|
async function generateBasicGrid() {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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,
|
|
321
326
|
children: [
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
}),
|
|
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')]}),
|
|
333
331
|
],
|
|
334
|
-
|
|
332
|
+
}),
|
|
333
|
+
],
|
|
334
|
+
});
|
|
335
335
|
|
|
336
|
-
|
|
336
|
+
await canvas.toFile('grid_basic.png');
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
generateBasicGrid();
|
|
@@ -345,14 +345,14 @@ Using fractional units (`fr`) allows columns to take up proportional space.
|
|
|
345
345
|
|
|
346
346
|
```typescript
|
|
347
347
|
Grid({
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
356
|
});
|
|
357
357
|
```
|
|
358
358
|
|
|
@@ -364,27 +364,27 @@ Use `GridItem` (or just passing `gridColumn`/`gridRow` props to any child) to sp
|
|
|
364
364
|
import {Grid, GridItem, Box, Text} from '@meonode/canvas';
|
|
365
365
|
|
|
366
366
|
Grid({
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
388
|
});
|
|
389
389
|
```
|
|
390
390
|
|
|
@@ -399,19 +399,19 @@ For example, to set `flexDirection` to `row` or `positionType` to `absolute`, yo
|
|
|
399
399
|
import {Box, Style} from '@meonode/canvas';
|
|
400
400
|
|
|
401
401
|
Box({
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
+
],
|
|
415
415
|
});
|
|
416
416
|
```
|
|
417
417
|
|
|
@@ -584,7 +584,36 @@ The `options` prop is a conditional type that changes based on the chart `type`.
|
|
|
584
584
|
| `showYAxis` | `boolean` | If `true`, displays the Y-axis labels on the left. |
|
|
585
585
|
| `yAxisColor` | `string` | Color of the Y-axis labels. |
|
|
586
586
|
| `yAxisFontSize` | `number` | Font size of the Y-axis labels. |
|
|
587
|
-
| `yAxisLabelFormatter` | `(value: number) => string` | Custom formatter for Y-axis labels.
|
|
587
|
+
| `yAxisLabelFormatter` | `(value: number) => string` | Custom formatter for Y-axis labels. Smart defaults adjust decimal precision based on value range. |
|
|
588
|
+
| `xAxisLabelFormatter` | `(value: string, index: number) => string` | Custom formatter for X-axis labels. Useful for truncating or transforming labels. |
|
|
589
|
+
|
|
590
|
+
###### Y-Axis Label Formatter
|
|
591
|
+
|
|
592
|
+
The `yAxisLabelFormatter` enables custom Y-axis label formatting. By default, it uses smart formatting:
|
|
593
|
+
- **Values < 1**: 4 decimals (e.g., `0.0025`)
|
|
594
|
+
- **Values 1-100**: 2 decimals (e.g., `25.43`)
|
|
595
|
+
- **Values 100-1000**: 1 decimal (e.g., `250.5`)
|
|
596
|
+
- **Values 1000-1M**: 0 decimals (e.g., `50000`)
|
|
597
|
+
- **Values ≥ 1M**: 1 decimal with "M" suffix (e.g., `1.5M`)
|
|
598
|
+
|
|
599
|
+
Custom example:
|
|
600
|
+
```typescript
|
|
601
|
+
options: {
|
|
602
|
+
yAxisLabelFormatter: (value) => `$${value.toFixed(2)}`,
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
###### X-Axis Label Formatter
|
|
607
|
+
|
|
608
|
+
The `xAxisLabelFormatter` allows custom X-axis label transformations. It receives the label string and its index.
|
|
609
|
+
|
|
610
|
+
Custom example:
|
|
611
|
+
```typescript
|
|
612
|
+
options: {
|
|
613
|
+
xAxisLabelFormatter: (label, index) =>
|
|
614
|
+
label.length > 5 ? label.substring(0, 5) + '...' : label,
|
|
615
|
+
}
|
|
616
|
+
```
|
|
588
617
|
|
|
589
618
|
##### Pie & Doughnut Chart Options (`pie`, `doughnut`)
|
|
590
619
|
|
|
@@ -616,4 +645,3 @@ started.
|
|
|
616
645
|
## License
|
|
617
646
|
|
|
618
647
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
619
|
-
|
|
@@ -755,6 +755,7 @@ interface CartesianChartSpecificOptions {
|
|
|
755
755
|
yAxisFontSize?: number;
|
|
756
756
|
yAxisColor?: string;
|
|
757
757
|
yAxisLabelFormatter?: (value: number) => string;
|
|
758
|
+
xAxisLabelFormatter?: (value: string, index: number) => string;
|
|
758
759
|
}
|
|
759
760
|
interface PieChartSpecificOptions {
|
|
760
761
|
/**
|