@meonode/canvas 2.0.2 → 2.0.4

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.
Files changed (119) hide show
  1. package/dist/cjs/{src/canvas → canvas}/canvas.helper.d.ts +1 -20
  2. package/dist/cjs/canvas/canvas.helper.d.ts.map +1 -0
  3. package/dist/cjs/canvas/canvas.helper.js +0 -230
  4. package/dist/cjs/canvas/canvas.helper.js.map +1 -1
  5. package/dist/{esm/src → cjs}/canvas/canvas.type.d.ts +1 -12
  6. package/dist/cjs/canvas/canvas.type.d.ts.map +1 -0
  7. package/dist/cjs/{src/canvas → canvas}/chart.canvas.d.ts +1 -1
  8. package/dist/cjs/canvas/chart.canvas.d.ts.map +1 -0
  9. package/dist/cjs/canvas/chart.canvas.js +70 -144
  10. package/dist/cjs/canvas/chart.canvas.js.map +1 -1
  11. package/dist/cjs/canvas/grid.canvas.d.ts.map +1 -0
  12. package/dist/cjs/canvas/grid.canvas.js.map +1 -1
  13. package/dist/{esm/src → cjs}/canvas/image.canvas.d.ts +1 -1
  14. package/dist/cjs/canvas/image.canvas.d.ts.map +1 -0
  15. package/dist/cjs/canvas/image.canvas.js +2 -2
  16. package/dist/cjs/canvas/image.canvas.js.map +1 -1
  17. package/dist/{esm/src → cjs}/canvas/layout.canvas.d.ts +2 -2
  18. package/dist/cjs/canvas/layout.canvas.d.ts.map +1 -0
  19. package/dist/cjs/canvas/layout.canvas.js +6 -6
  20. package/dist/cjs/canvas/layout.canvas.js.map +1 -1
  21. package/dist/{esm/src → cjs}/canvas/root.canvas.d.ts +3 -2
  22. package/dist/cjs/canvas/root.canvas.d.ts.map +1 -0
  23. package/dist/cjs/canvas/root.canvas.js +23 -117
  24. package/dist/cjs/canvas/root.canvas.js.map +1 -1
  25. package/dist/cjs/{src/canvas → canvas}/text.canvas.d.ts +1 -1
  26. package/dist/cjs/canvas/text.canvas.d.ts.map +1 -0
  27. package/dist/cjs/canvas/text.canvas.js +2 -2
  28. package/dist/cjs/canvas/text.canvas.js.map +1 -1
  29. package/dist/cjs/constant/common.const.d.ts.map +1 -0
  30. package/dist/cjs/constant/common.const.js.map +1 -1
  31. package/dist/cjs/index.d.ts.map +1 -0
  32. package/dist/cjs/util/disk.cache.d.ts.map +1 -0
  33. package/dist/cjs/util/disk.cache.js.map +1 -1
  34. package/dist/cjs/worker/comlink.pool.d.ts +30 -0
  35. package/dist/cjs/worker/comlink.pool.d.ts.map +1 -0
  36. package/dist/cjs/worker/comlink.pool.js +164 -0
  37. package/dist/cjs/worker/comlink.pool.js.map +1 -0
  38. package/dist/cjs/worker/comlink.setup.d.ts +4 -0
  39. package/dist/cjs/worker/comlink.setup.d.ts.map +1 -0
  40. package/dist/cjs/worker/comlink.setup.js +53 -0
  41. package/dist/cjs/worker/comlink.setup.js.map +1 -0
  42. package/dist/cjs/worker/render.worker.d.ts.map +1 -0
  43. package/dist/cjs/worker/render.worker.js +58 -61
  44. package/dist/cjs/worker/render.worker.js.map +1 -1
  45. package/dist/cjs/worker/worker.types.d.ts +13 -0
  46. package/dist/cjs/worker/worker.types.d.ts.map +1 -0
  47. package/dist/esm/{src/canvas → canvas}/canvas.helper.d.ts +1 -20
  48. package/dist/esm/canvas/canvas.helper.d.ts.map +1 -0
  49. package/dist/esm/canvas/canvas.helper.js +1 -230
  50. package/dist/{cjs/src → esm}/canvas/canvas.type.d.ts +1 -12
  51. package/dist/esm/canvas/canvas.type.d.ts.map +1 -0
  52. package/dist/esm/{src/canvas → canvas}/chart.canvas.d.ts +1 -1
  53. package/dist/esm/canvas/chart.canvas.d.ts.map +1 -0
  54. package/dist/esm/canvas/chart.canvas.js +71 -145
  55. package/dist/esm/canvas/grid.canvas.d.ts.map +1 -0
  56. package/dist/{cjs/src → esm}/canvas/image.canvas.d.ts +1 -1
  57. package/dist/esm/canvas/image.canvas.d.ts.map +1 -0
  58. package/dist/esm/canvas/image.canvas.js +2 -2
  59. package/dist/{cjs/src → esm}/canvas/layout.canvas.d.ts +2 -2
  60. package/dist/esm/canvas/layout.canvas.d.ts.map +1 -0
  61. package/dist/esm/canvas/layout.canvas.js +6 -6
  62. package/dist/{cjs/src → esm}/canvas/root.canvas.d.ts +3 -2
  63. package/dist/esm/canvas/root.canvas.d.ts.map +1 -0
  64. package/dist/esm/canvas/root.canvas.js +23 -116
  65. package/dist/esm/{src/canvas → canvas}/text.canvas.d.ts +1 -1
  66. package/dist/esm/canvas/text.canvas.d.ts.map +1 -0
  67. package/dist/esm/canvas/text.canvas.js +2 -2
  68. package/dist/esm/constant/common.const.d.ts.map +1 -0
  69. package/dist/esm/index.d.ts.map +1 -0
  70. package/dist/esm/util/disk.cache.d.ts.map +1 -0
  71. package/dist/esm/worker/comlink.pool.d.ts +30 -0
  72. package/dist/esm/worker/comlink.pool.d.ts.map +1 -0
  73. package/dist/esm/worker/comlink.pool.js +139 -0
  74. package/dist/esm/worker/comlink.setup.d.ts +4 -0
  75. package/dist/esm/worker/comlink.setup.d.ts.map +1 -0
  76. package/dist/esm/worker/comlink.setup.js +30 -0
  77. package/dist/esm/worker/render.worker.d.ts.map +1 -0
  78. package/dist/esm/worker/render.worker.js +38 -60
  79. package/dist/esm/worker/worker.types.d.ts +13 -0
  80. package/dist/esm/worker/worker.types.d.ts.map +1 -0
  81. package/package.json +2 -1
  82. package/dist/cjs/src/canvas/canvas.helper.d.ts.map +0 -1
  83. package/dist/cjs/src/canvas/canvas.type.d.ts.map +0 -1
  84. package/dist/cjs/src/canvas/chart.canvas.d.ts.map +0 -1
  85. package/dist/cjs/src/canvas/grid.canvas.d.ts.map +0 -1
  86. package/dist/cjs/src/canvas/image.canvas.d.ts.map +0 -1
  87. package/dist/cjs/src/canvas/layout.canvas.d.ts.map +0 -1
  88. package/dist/cjs/src/canvas/root.canvas.d.ts.map +0 -1
  89. package/dist/cjs/src/canvas/text.canvas.d.ts.map +0 -1
  90. package/dist/cjs/src/constant/common.const.d.ts.map +0 -1
  91. package/dist/cjs/src/index.d.ts.map +0 -1
  92. package/dist/cjs/src/util/disk.cache.d.ts.map +0 -1
  93. package/dist/cjs/src/worker/render.worker.d.ts.map +0 -1
  94. package/dist/cjs/src/worker/worker.types.d.ts +0 -76
  95. package/dist/cjs/src/worker/worker.types.d.ts.map +0 -1
  96. package/dist/esm/src/canvas/canvas.helper.d.ts.map +0 -1
  97. package/dist/esm/src/canvas/canvas.type.d.ts.map +0 -1
  98. package/dist/esm/src/canvas/chart.canvas.d.ts.map +0 -1
  99. package/dist/esm/src/canvas/grid.canvas.d.ts.map +0 -1
  100. package/dist/esm/src/canvas/image.canvas.d.ts.map +0 -1
  101. package/dist/esm/src/canvas/layout.canvas.d.ts.map +0 -1
  102. package/dist/esm/src/canvas/root.canvas.d.ts.map +0 -1
  103. package/dist/esm/src/canvas/text.canvas.d.ts.map +0 -1
  104. package/dist/esm/src/constant/common.const.d.ts.map +0 -1
  105. package/dist/esm/src/index.d.ts.map +0 -1
  106. package/dist/esm/src/util/disk.cache.d.ts.map +0 -1
  107. package/dist/esm/src/worker/render.worker.d.ts.map +0 -1
  108. package/dist/esm/src/worker/worker.types.d.ts +0 -76
  109. package/dist/esm/src/worker/worker.types.d.ts.map +0 -1
  110. /package/dist/cjs/{src/canvas → canvas}/grid.canvas.d.ts +0 -0
  111. /package/dist/cjs/{src/constant → constant}/common.const.d.ts +0 -0
  112. /package/dist/cjs/{src/index.d.ts → index.d.ts} +0 -0
  113. /package/dist/cjs/{src/util → util}/disk.cache.d.ts +0 -0
  114. /package/dist/cjs/{src/worker → worker}/render.worker.d.ts +0 -0
  115. /package/dist/esm/{src/canvas → canvas}/grid.canvas.d.ts +0 -0
  116. /package/dist/esm/{src/constant → constant}/common.const.d.ts +0 -0
  117. /package/dist/esm/{src/index.d.ts → index.d.ts} +0 -0
  118. /package/dist/esm/{src/util → util}/disk.cache.d.ts +0 -0
  119. /package/dist/esm/{src/worker → worker}/render.worker.d.ts +0 -0
@@ -3,29 +3,7 @@
3
3
  var layout_canvas = require('./layout.canvas.js');
4
4
  var common_const = require('../constant/common.const.js');
5
5
  var text_canvas = require('./text.canvas.js');
6
- var image_canvas = require('./image.canvas.js');
7
6
 
8
- /**
9
- * Local buildTree for pre-computed render function results.
10
- * Handles only node types that render functions would return (Box, Column, Row, Text, Image).
11
- * Avoids circular dependency with root.canvas.ts.
12
- */
13
- function buildDescriptorTree(descriptor) {
14
- switch (descriptor.__type) {
15
- case 'Box':
16
- return new layout_canvas.BoxNode({ ...descriptor.props, children: descriptor.children?.map(buildDescriptorTree) });
17
- case 'Column':
18
- return new layout_canvas.ColumnNode({ ...descriptor.props, children: descriptor.children?.map(buildDescriptorTree) });
19
- case 'Row':
20
- return new layout_canvas.RowNode({ ...descriptor.props, children: descriptor.children?.map(buildDescriptorTree) });
21
- case 'Image':
22
- return new image_canvas.ImageNode(descriptor.props);
23
- case 'Text':
24
- return new text_canvas.TextNode(descriptor.text, descriptor.props);
25
- default:
26
- return new layout_canvas.BoxNode({});
27
- }
28
- }
29
7
  class ChartNode extends layout_canvas.BoxNode {
30
8
  chartData;
31
9
  chartType;
@@ -70,9 +48,9 @@ class ChartNode extends layout_canvas.BoxNode {
70
48
  }
71
49
  }
72
50
  }
73
- _renderContent(ctx, x, y, width, height) {
51
+ async _renderContent(ctx, x, y, width, height) {
74
52
  // First render background/borders from parent
75
- super._renderContent(ctx, x, y, width, height);
53
+ await super._renderContent(ctx, x, y, width, height);
76
54
  // Then render chart-specific content
77
55
  const paddingLeft = this.node.getComputedPadding(common_const.Style.Edge.Left);
78
56
  const paddingRight = this.node.getComputedPadding(common_const.Style.Edge.Right);
@@ -84,16 +62,16 @@ class ChartNode extends layout_canvas.BoxNode {
84
62
  const contentHeight = height - paddingTop - paddingBottom;
85
63
  switch (this.chartType) {
86
64
  case 'bar':
87
- this.renderBarChart(ctx, contentX, contentY, contentWidth, contentHeight);
65
+ await this.renderBarChart(ctx, contentX, contentY, contentWidth, contentHeight);
88
66
  break;
89
67
  case 'line':
90
- this.renderLineChart(ctx, contentX, contentY, contentWidth, contentHeight);
68
+ await this.renderLineChart(ctx, contentX, contentY, contentWidth, contentHeight);
91
69
  break;
92
70
  case 'pie':
93
- this.renderPieChart(ctx, contentX, contentY, contentWidth, contentHeight);
71
+ await this.renderPieChart(ctx, contentX, contentY, contentWidth, contentHeight);
94
72
  break;
95
73
  case 'doughnut':
96
- this.renderDoughnutChart(ctx, contentX, contentY, contentWidth, contentHeight);
74
+ await this.renderDoughnutChart(ctx, contentX, contentY, contentWidth, contentHeight);
97
75
  break;
98
76
  }
99
77
  }
@@ -213,7 +191,7 @@ class ChartNode extends layout_canvas.BoxNode {
213
191
  chartY: chartAreaY,
214
192
  };
215
193
  }
216
- renderBarChart(ctx, x, y, width, height) {
194
+ async renderBarChart(ctx, x, y, width, height) {
217
195
  if (this.chartType !== 'bar')
218
196
  return;
219
197
  const chartData = this.chartData;
@@ -228,8 +206,7 @@ class ChartNode extends layout_canvas.BoxNode {
228
206
  if (chartOptions?.showYAxis) {
229
207
  const fontSize = chartOptions.yAxisFontSize || 12;
230
208
  ctx.font = `${fontSize}px ${this.props.fontFamily || 'sans-serif'}`;
231
- const maxLabel = chartOptions._preComputedYAxisLabels?.[0] ??
232
- (chartOptions.yAxisLabelFormatter ? chartOptions.yAxisLabelFormatter(maxValue) : this.getSmartYAxisFormatter(maxValue)(maxValue));
209
+ const maxLabel = chartOptions.yAxisLabelFormatter ? await chartOptions.yAxisLabelFormatter(maxValue) : this.getSmartYAxisFormatter(maxValue)(maxValue);
233
210
  const yAxisWidth = ctx.measureText(maxLabel).width + 10;
234
211
  chartX += yAxisWidth;
235
212
  chartWidth -= yAxisWidth;
@@ -263,8 +240,7 @@ class ChartNode extends layout_canvas.BoxNode {
263
240
  ctx.stroke();
264
241
  if (chartOptions?.showYAxis) {
265
242
  const value = maxValue - (maxValue / 5) * i;
266
- const label = chartOptions._preComputedYAxisLabels?.[i] ??
267
- (chartOptions.yAxisLabelFormatter ? chartOptions.yAxisLabelFormatter(value) : this.getSmartYAxisFormatter(maxValue)(value));
243
+ const label = chartOptions.yAxisLabelFormatter ? await chartOptions.yAxisLabelFormatter(value) : this.getSmartYAxisFormatter(maxValue)(value);
268
244
  text_canvas.TextNode.renderSimpleText(ctx, label, chartX - 5, gridY, {
269
245
  color: chartOptions.yAxisColor || chartOptions.axisColor || '#000',
270
246
  fontSize: chartOptions.yAxisFontSize || 12,
@@ -277,9 +253,11 @@ class ChartNode extends layout_canvas.BoxNode {
277
253
  ctx.setLineDash([]);
278
254
  }
279
255
  // Render bars
280
- labels.forEach((label, index) => {
256
+ for (let index = 0; index < labels.length; index++) {
257
+ const label = labels[index];
281
258
  const groupX = chartX + index * groupWidth + barSpacing / 2;
282
- datasets.forEach((dataset, datasetIndex) => {
259
+ for (let datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
260
+ const dataset = datasets[datasetIndex];
283
261
  const barHeight = (dataset.data[index] / maxValue) * finalChartHeight;
284
262
  const barX = groupX + datasetIndex * barWidth;
285
263
  const barY = chartY + finalChartHeight - barHeight;
@@ -290,21 +268,13 @@ class ChartNode extends layout_canvas.BoxNode {
290
268
  const value = dataset.data[index];
291
269
  const valueX = barX + barWidth / 2;
292
270
  const valueY = barY - 5; // 5px padding above bar
293
- const preComputedValueDesc = chartOptions._preComputedValueItems?.[datasetIndex]?.[index];
294
- if (preComputedValueDesc) {
295
- const valueNode = buildDescriptorTree(preComputedValueDesc);
296
- valueNode.processInitialChildren();
297
- valueNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
298
- const layout = valueNode.node.getComputedLayout();
299
- valueNode.render(ctx, valueX - layout.width / 2, valueY - layout.height);
300
- }
301
- else if (chartOptions.renderValueItem) {
302
- const valueNode = chartOptions.renderValueItem({ item: value, index, datasetIndex });
271
+ if (chartOptions.renderValueItem) {
272
+ const valueNode = await chartOptions.renderValueItem({ item: value, index, datasetIndex });
303
273
  if (valueNode) {
304
274
  valueNode.processInitialChildren();
305
275
  valueNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
306
276
  const layout = valueNode.node.getComputedLayout();
307
- valueNode.render(ctx, valueX - layout.width / 2, valueY - layout.height);
277
+ await valueNode.render(ctx, valueX - layout.width / 2, valueY - layout.height);
308
278
  }
309
279
  }
310
280
  else {
@@ -317,25 +287,17 @@ class ChartNode extends layout_canvas.BoxNode {
317
287
  });
318
288
  }
319
289
  }
320
- });
290
+ }
321
291
  // Render labels
322
292
  if (chartOptions?.showLabels) {
323
- const displayLabel = chartOptions._preComputedXAxisLabels?.[index] ?? (chartOptions.xAxisLabelFormatter ? chartOptions.xAxisLabelFormatter(label, index) : label);
324
- const preComputedLabelDesc = chartOptions._preComputedLabelItems?.[index];
325
- if (preComputedLabelDesc) {
326
- const labelNode = buildDescriptorTree(preComputedLabelDesc);
327
- labelNode.processInitialChildren();
328
- labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
329
- const layout = labelNode.node.getComputedLayout();
330
- labelNode.render(ctx, groupX + (groupWidth - barSpacing) / 2 - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
331
- }
332
- else if (chartOptions.renderLabelItem) {
333
- const labelNode = chartOptions.renderLabelItem({ item: label, index });
293
+ const displayLabel = chartOptions.xAxisLabelFormatter ? await chartOptions.xAxisLabelFormatter(label, index) : label;
294
+ if (chartOptions.renderLabelItem) {
295
+ const labelNode = await chartOptions.renderLabelItem({ item: label, index });
334
296
  if (labelNode) {
335
297
  labelNode.processInitialChildren();
336
298
  labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
337
299
  const layout = labelNode.node.getComputedLayout();
338
- labelNode.render(ctx, groupX + (groupWidth - barSpacing) / 2 - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
300
+ await labelNode.render(ctx, groupX + (groupWidth - barSpacing) / 2 - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
339
301
  }
340
302
  }
341
303
  else {
@@ -348,13 +310,13 @@ class ChartNode extends layout_canvas.BoxNode {
348
310
  });
349
311
  }
350
312
  }
351
- });
313
+ }
352
314
  // Render legend
353
315
  if (chartOptions?.showLegend) {
354
- this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
316
+ await this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
355
317
  }
356
318
  }
357
- renderLineChart(ctx, x, y, width, height) {
319
+ async renderLineChart(ctx, x, y, width, height) {
358
320
  if (this.chartType !== 'line')
359
321
  return;
360
322
  const chartData = this.chartData;
@@ -369,8 +331,7 @@ class ChartNode extends layout_canvas.BoxNode {
369
331
  if (chartOptions?.showYAxis) {
370
332
  const fontSize = chartOptions.yAxisFontSize || 12;
371
333
  ctx.font = `${fontSize}px ${this.props.fontFamily || 'sans-serif'}`;
372
- const maxLabel = chartOptions._preComputedYAxisLabels?.[0] ??
373
- (chartOptions.yAxisLabelFormatter ? chartOptions.yAxisLabelFormatter(maxValue) : this.getSmartYAxisFormatter(maxValue)(maxValue));
334
+ const maxLabel = chartOptions.yAxisLabelFormatter ? await chartOptions.yAxisLabelFormatter(maxValue) : this.getSmartYAxisFormatter(maxValue)(maxValue);
374
335
  const yAxisWidth = ctx.measureText(maxLabel).width + 10;
375
336
  chartX += yAxisWidth;
376
337
  chartWidth -= yAxisWidth;
@@ -402,8 +363,7 @@ class ChartNode extends layout_canvas.BoxNode {
402
363
  ctx.stroke();
403
364
  if (chartOptions?.showYAxis) {
404
365
  const value = maxValue - (maxValue / 5) * i;
405
- const label = chartOptions._preComputedYAxisLabels?.[i] ??
406
- (chartOptions.yAxisLabelFormatter ? chartOptions.yAxisLabelFormatter(value) : this.getSmartYAxisFormatter(maxValue)(value));
366
+ const label = chartOptions.yAxisLabelFormatter ? await chartOptions.yAxisLabelFormatter(value) : this.getSmartYAxisFormatter(maxValue)(value);
407
367
  text_canvas.TextNode.renderSimpleText(ctx, label, chartX - 5, gridY, {
408
368
  color: chartOptions.yAxisColor || chartOptions.axisColor || '#000',
409
369
  fontSize: chartOptions.yAxisFontSize || 12,
@@ -416,11 +376,13 @@ class ChartNode extends layout_canvas.BoxNode {
416
376
  ctx.setLineDash([]);
417
377
  }
418
378
  // Render lines and points
419
- datasets.forEach((dataset, datasetIndex) => {
379
+ for (let datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
380
+ const dataset = datasets[datasetIndex];
420
381
  ctx.strokeStyle = dataset.color || this.generateColor(datasetIndex);
421
382
  ctx.lineWidth = 2;
422
383
  ctx.beginPath();
423
- dataset.data.forEach((value, index) => {
384
+ for (let index = 0; index < dataset.data.length; index++) {
385
+ const value = dataset.data[index];
424
386
  const pointX = chartX + index * pointSpacing;
425
387
  const pointY = chartY + finalChartHeight - (value / maxValue) * finalChartHeight;
426
388
  if (index === 0) {
@@ -429,38 +391,31 @@ class ChartNode extends layout_canvas.BoxNode {
429
391
  else {
430
392
  ctx.lineTo(pointX, pointY);
431
393
  }
432
- });
394
+ }
433
395
  ctx.stroke();
434
396
  // Render points
435
- dataset.data.forEach((value, index) => {
397
+ for (let index = 0; index < dataset.data.length; index++) {
436
398
  const pointX = chartX + index * pointSpacing;
437
- const pointY = chartY + finalChartHeight - (value / maxValue) * finalChartHeight;
399
+ const pointY = chartY + finalChartHeight - (dataset.data[index] / maxValue) * finalChartHeight;
438
400
  ctx.fillStyle = dataset.color || this.generateColor(datasetIndex);
439
401
  ctx.beginPath();
440
402
  ctx.arc(pointX, pointY, 4, 0, Math.PI * 2);
441
403
  ctx.fill();
442
- });
443
- });
404
+ }
405
+ }
444
406
  // Render labels
445
407
  if (chartOptions?.showLabels) {
446
- labels.forEach((label, index) => {
408
+ for (let index = 0; index < labels.length; index++) {
409
+ const label = labels[index];
447
410
  const pointX = chartX + index * pointSpacing;
448
- const displayLabel = chartOptions._preComputedXAxisLabels?.[index] ?? (chartOptions.xAxisLabelFormatter ? chartOptions.xAxisLabelFormatter(label, index) : label);
449
- const preComputedLabelDesc = chartOptions._preComputedLabelItems?.[index];
450
- if (preComputedLabelDesc) {
451
- const labelNode = buildDescriptorTree(preComputedLabelDesc);
452
- labelNode.processInitialChildren();
453
- labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
454
- const layout = labelNode.node.getComputedLayout();
455
- labelNode.render(ctx, pointX - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
456
- }
457
- else if (chartOptions.renderLabelItem) {
458
- const labelNode = chartOptions.renderLabelItem({ item: label, index });
411
+ const displayLabel = chartOptions.xAxisLabelFormatter ? await chartOptions.xAxisLabelFormatter(label, index) : label;
412
+ if (chartOptions.renderLabelItem) {
413
+ const labelNode = await chartOptions.renderLabelItem({ item: label, index });
459
414
  if (labelNode) {
460
415
  labelNode.processInitialChildren();
461
416
  labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
462
417
  const layout = labelNode.node.getComputedLayout();
463
- labelNode.render(ctx, pointX - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
418
+ await labelNode.render(ctx, pointX - layout.width / 2, chartY + finalChartHeight + labelHeight / 2 - layout.height / 2);
464
419
  }
465
420
  }
466
421
  else {
@@ -472,13 +427,13 @@ class ChartNode extends layout_canvas.BoxNode {
472
427
  textBaseline: 'middle',
473
428
  });
474
429
  }
475
- });
430
+ }
476
431
  }
477
432
  if (chartOptions?.showLegend) {
478
- this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
433
+ await this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
479
434
  }
480
435
  }
481
- renderPieChart(ctx, x, y, width, height) {
436
+ async renderPieChart(ctx, x, y, width, height) {
482
437
  if (this.chartType !== 'pie')
483
438
  return;
484
439
  const data = this.chartData;
@@ -493,7 +448,8 @@ class ChartNode extends layout_canvas.BoxNode {
493
448
  const radius = Math.min(chartWidth, chartHeight) / 2 - 10;
494
449
  const total = data.reduce((sum, point) => sum + point.value, 0);
495
450
  let currentAngle = -Math.PI / 2; // Start at top
496
- data.forEach((point, index) => {
451
+ for (let index = 0; index < data.length; index++) {
452
+ const point = data[index];
497
453
  const sliceAngle = (point.value / total) * Math.PI * 2;
498
454
  const startAngle = currentAngle;
499
455
  const endAngle = currentAngle + sliceAngle;
@@ -513,21 +469,13 @@ class ChartNode extends layout_canvas.BoxNode {
513
469
  const labelRadius = radius * 0.7;
514
470
  const labelX = centerX + Math.cos(labelAngle) * labelRadius;
515
471
  const labelY = centerY + Math.sin(labelAngle) * labelRadius;
516
- const preComputedLabelDesc = chartOptions._preComputedLabelItems?.[index];
517
- if (preComputedLabelDesc) {
518
- const labelNode = buildDescriptorTree(preComputedLabelDesc);
519
- labelNode.processInitialChildren();
520
- labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
521
- const layout = labelNode.node.getComputedLayout();
522
- labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
523
- }
524
- else if (chartOptions.renderLabelItem) {
525
- const labelNode = chartOptions.renderLabelItem({ item: point, index });
472
+ if (chartOptions.renderLabelItem) {
473
+ const labelNode = await chartOptions.renderLabelItem({ item: point, index });
526
474
  if (labelNode) {
527
475
  labelNode.processInitialChildren();
528
476
  labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
529
477
  const layout = labelNode.node.getComputedLayout();
530
- labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
478
+ await labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
531
479
  }
532
480
  }
533
481
  else {
@@ -541,12 +489,12 @@ class ChartNode extends layout_canvas.BoxNode {
541
489
  }
542
490
  }
543
491
  currentAngle = endAngle;
544
- });
492
+ }
545
493
  if (chartOptions?.showLegend) {
546
- this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
494
+ await this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
547
495
  }
548
496
  }
549
- renderDoughnutChart(ctx, x, y, width, height) {
497
+ async renderDoughnutChart(ctx, x, y, width, height) {
550
498
  if (this.chartType !== 'doughnut')
551
499
  return;
552
500
  const data = this.chartData;
@@ -562,7 +510,8 @@ class ChartNode extends layout_canvas.BoxNode {
562
510
  const innerRadius = outerRadius * (chartOptions?.innerRadius ?? 0.6);
563
511
  const total = data.reduce((sum, point) => sum + point.value, 0);
564
512
  let currentAngle = -Math.PI / 2;
565
- data.forEach((point, index) => {
513
+ for (let index = 0; index < data.length; index++) {
514
+ const point = data[index];
566
515
  const sliceAngle = (point.value / total) * Math.PI * 2;
567
516
  const startAngle = currentAngle;
568
517
  const endAngle = currentAngle + sliceAngle;
@@ -581,21 +530,13 @@ class ChartNode extends layout_canvas.BoxNode {
581
530
  const labelRadius = innerRadius + (outerRadius - innerRadius) / 2;
582
531
  const labelX = centerX + Math.cos(labelAngle) * labelRadius;
583
532
  const labelY = centerY + Math.sin(labelAngle) * labelRadius;
584
- const preComputedLabelDesc = chartOptions._preComputedLabelItems?.[index];
585
- if (preComputedLabelDesc) {
586
- const labelNode = buildDescriptorTree(preComputedLabelDesc);
587
- labelNode.processInitialChildren();
588
- labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
589
- const layout = labelNode.node.getComputedLayout();
590
- labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
591
- }
592
- else if (chartOptions.renderLabelItem) {
593
- const labelNode = chartOptions.renderLabelItem({ item: point, index });
533
+ if (chartOptions.renderLabelItem) {
534
+ const labelNode = await chartOptions.renderLabelItem({ item: point, index });
594
535
  if (labelNode) {
595
536
  labelNode.processInitialChildren();
596
537
  labelNode.node.calculateLayout(undefined, undefined, common_const.Style.Direction.LTR);
597
538
  const layout = labelNode.node.getComputedLayout();
598
- labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
539
+ await labelNode.render(ctx, labelX - layout.width / 2, labelY - layout.height / 2);
599
540
  }
600
541
  }
601
542
  else {
@@ -609,48 +550,31 @@ class ChartNode extends layout_canvas.BoxNode {
609
550
  }
610
551
  }
611
552
  currentAngle = endAngle;
612
- });
553
+ }
613
554
  if (chartOptions?.showLegend) {
614
- this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
555
+ await this.renderLegend(ctx, x + legendLayout.x, y + legendLayout.y, legendLayout.width, legendLayout.height);
615
556
  }
616
557
  }
617
- renderLegend(ctx, x, y, width, height) {
618
- const { renderLegendItem, _preComputedLegendItems } = this.chartOptions;
619
- if (_preComputedLegendItems) {
620
- const finalNodes = _preComputedLegendItems.filter((desc) => !!desc).map(desc => buildDescriptorTree(desc));
621
- if (finalNodes.length > 0) {
622
- const legendContainer = new layout_canvas.RowNode({
623
- children: finalNodes,
624
- width,
625
- height,
626
- justifyContent: common_const.Style.Justify.Center,
627
- alignItems: common_const.Style.Align.Center,
628
- flexWrap: common_const.Style.Wrap.Wrap,
629
- gap: 10,
630
- });
631
- legendContainer.processInitialChildren();
632
- legendContainer.node.calculateLayout(width, height, common_const.Style.Direction.LTR);
633
- legendContainer.render(ctx, x, y);
634
- }
635
- return;
636
- }
558
+ async renderLegend(ctx, x, y, width, height) {
559
+ const chartOptions = this.chartOptions;
560
+ const renderLegendItem = chartOptions?.renderLegendItem;
637
561
  if (renderLegendItem) {
638
562
  let legendNodes;
639
563
  if (this.chartType === 'bar' || this.chartType === 'line') {
640
564
  const items = this.chartData.datasets;
641
565
  const render = renderLegendItem;
642
- legendNodes = items.map((item, index) => {
566
+ legendNodes = await Promise.all(items.map(async (item, index) => {
643
567
  const color = item.color || this.generateColor(index);
644
568
  return render({ item, index, color });
645
- });
569
+ }));
646
570
  }
647
571
  else {
648
572
  const items = this.chartData;
649
573
  const render = renderLegendItem;
650
- legendNodes = items.map((item, index) => {
574
+ legendNodes = await Promise.all(items.map(async (item, index) => {
651
575
  const color = item.color || this.generateColor(index);
652
576
  return render({ item, index, color });
653
- });
577
+ }));
654
578
  }
655
579
  const finalNodes = legendNodes.filter((node) => !!node);
656
580
  if (finalNodes.length > 0) {
@@ -665,11 +589,13 @@ class ChartNode extends layout_canvas.BoxNode {
665
589
  });
666
590
  legendContainer.processInitialChildren();
667
591
  legendContainer.node.calculateLayout(width, height, common_const.Style.Direction.LTR);
668
- legendContainer.render(ctx, x, y);
592
+ await legendContainer.render(ctx, x, y);
669
593
  }
670
594
  return;
671
595
  }
672
596
  // Fallback to default rendering if renderLegendItem is not provided
597
+ if (!this.chartData)
598
+ return;
673
599
  const legendItems = 'datasets' in this.chartData
674
600
  ? this.chartData.datasets.map(d => ({ label: d.label, value: d.data.reduce((a, b) => a + b, 0) }))
675
601
  : this.chartData;
@@ -679,7 +605,7 @@ class ChartNode extends layout_canvas.BoxNode {
679
605
  const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
680
606
  const itemHeight = Math.ceil(textHeight + 8);
681
607
  const boxSize = Math.min(15, itemHeight - 2);
682
- const position = this.chartOptions.legendPosition;
608
+ const position = this.chartOptions?.legendPosition;
683
609
  if (position === 'top' || position === 'bottom') {
684
610
  const itemPadding = 20; // horizontal padding between items
685
611
  const rows = [];