evui 3.1.38 → 3.1.42

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 (33) hide show
  1. package/dist/evui.common.js +2699 -970
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +2699 -970
  4. package/dist/evui.umd.js.map +1 -1
  5. package/dist/evui.umd.min.js +1 -1
  6. package/dist/evui.umd.min.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/components/calendar/Calendar.vue +194 -82
  9. package/src/components/calendar/uses.js +457 -138
  10. package/src/components/chart/chart.core.js +27 -23
  11. package/src/components/chart/element/element.bar.js +28 -20
  12. package/src/components/chart/element/element.line.js +13 -0
  13. package/src/components/chart/helpers/helpers.constant.js +27 -0
  14. package/src/components/chart/helpers/helpers.util.js +2 -2
  15. package/src/components/chart/plugins/plugins.interaction.js +5 -5
  16. package/src/components/chart/plugins/plugins.legend.js +6 -3
  17. package/src/components/chart/plugins/plugins.tooltip.js +14 -1
  18. package/src/components/chart/scale/scale.js +520 -56
  19. package/src/components/chart/scale/scale.linear.js +8 -0
  20. package/src/components/chart/scale/scale.logarithmic.js +8 -0
  21. package/src/components/chart/scale/scale.step.js +148 -69
  22. package/src/components/chart/scale/scale.time.category.js +8 -0
  23. package/src/components/chart/scale/scale.time.js +8 -0
  24. package/src/components/chart/uses.js +2 -2
  25. package/src/components/contextMenu/MenuList.vue +1 -1
  26. package/src/components/datePicker/DatePicker.vue +91 -29
  27. package/src/components/datePicker/uses.js +231 -21
  28. package/src/components/grid/Grid.vue +15 -10
  29. package/src/components/tabs/Tabs.vue +12 -11
  30. package/src/components/treeGrid/TreeGrid.vue +56 -2
  31. package/src/components/treeGrid/TreeGridNode.vue +10 -1
  32. package/src/components/treeGrid/treeGrid.toolbar.vue +26 -0
  33. package/src/components/treeGrid/uses.js +66 -6
@@ -1,5 +1,12 @@
1
+ import Canvas from '@/components/chart/helpers/helpers.canvas';
1
2
  import { defaultsDeep } from 'lodash-es';
2
- import { AXIS_OPTION, AXIS_UNITS } from '../helpers/helpers.constant';
3
+ import {
4
+ AXIS_OPTION,
5
+ AXIS_UNITS,
6
+ PLOT_LINE_OPTION,
7
+ PLOT_LINE_LABEL_OPTION,
8
+ PLOT_BAND_OPTION,
9
+ } from '../helpers/helpers.constant';
3
10
  import Util from '../helpers/helpers.util';
4
11
 
5
12
  class Scale {
@@ -213,80 +220,537 @@ class Scale {
213
220
  return;
214
221
  }
215
222
 
216
- const labelGap = (endPoint - startPoint) / steps;
217
- const ticks = [];
218
- let labelCenter = null;
219
- let linePosition = null;
223
+ if (this.labelStyle?.show) {
224
+ const labelGap = (endPoint - startPoint) / steps;
225
+ const ticks = [];
226
+ let labelCenter = null;
227
+ let linePosition = null;
220
228
 
221
- ctx.strokeStyle = this.gridLineColor;
222
- ctx.lineWidth = 1;
223
- aliasPixel = Util.aliasPixel(ctx.lineWidth);
224
-
225
- let labelText;
226
- for (let ix = 0; ix <= steps; ix++) {
227
- ctx.beginPath();
228
- ticks[ix] = axisMin + (ix * stepValue);
229
+ ctx.strokeStyle = this.gridLineColor;
230
+ ctx.lineWidth = 1;
231
+ aliasPixel = Util.aliasPixel(ctx.lineWidth);
229
232
 
230
- labelCenter = Math.round(startPoint + (labelGap * ix));
231
- linePosition = labelCenter + aliasPixel;
232
- labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix]));
233
+ let labelText;
234
+ for (let ix = 0; ix <= steps; ix++) {
235
+ ctx.beginPath();
236
+ ticks[ix] = axisMin + (ix * stepValue);
237
+
238
+ labelCenter = Math.round(startPoint + (labelGap * ix));
239
+ linePosition = labelCenter + aliasPixel;
240
+ labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix]));
241
+
242
+ let labelPoint;
243
+
244
+ if (this.type === 'x') {
245
+ labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
246
+ ctx.fillText(labelText, labelCenter, labelPoint);
247
+ if (options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) {
248
+ const selectedLabel = this.getLabelFormat(
249
+ Math.min(axisMax, hitInfo.label + (0 * stepValue)),
250
+ );
251
+ if (selectedLabel === labelText) {
252
+ const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
253
+ Util.showLabelTip({
254
+ ctx: this.ctx,
255
+ width: Math.round(ctx.measureText(selectedLabel).width) + 10,
256
+ height,
257
+ x: labelCenter,
258
+ y: labelPoint + (height - 2),
259
+ borderRadius: 2,
260
+ arrowSize: 3,
261
+ text: labelText,
262
+ backgroundColor: options?.selectItem?.labelTipStyle?.backgroundColor,
263
+ textColor: options?.selectItem?.labelTipStyle?.textColor,
264
+ });
265
+ }
266
+ }
267
+ if (ix !== 0 && this.showGrid) {
268
+ ctx.moveTo(linePosition, offsetPoint);
269
+ ctx.lineTo(linePosition, offsetCounterPoint);
270
+ }
271
+ } else {
272
+ labelPoint = this.position === 'left' ? offsetPoint - 10 : offsetPoint + 10;
273
+ ctx.fillText(labelText, labelPoint, labelCenter);
233
274
 
234
- let labelPoint;
275
+ if (ix === steps) {
276
+ linePosition += 1;
277
+ }
235
278
 
236
- if (this.type === 'x') {
237
- labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
238
- ctx.fillText(labelText, labelCenter, labelPoint);
239
- if (options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) {
240
- const selectedLabel = this.getLabelFormat(
241
- Math.min(axisMax, hitInfo.label + (0 * stepValue)),
242
- );
243
- if (selectedLabel === labelText) {
244
- const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
245
- Util.showLabelTip({
246
- ctx: this.ctx,
247
- width: Math.round(ctx.measureText(selectedLabel).width) + 10,
248
- height,
249
- x: labelCenter,
250
- y: labelPoint + (height - 2),
251
- borderRadius: 2,
252
- arrowSize: 3,
253
- text: labelText,
254
- backgroundColor: options?.selectItem?.labelTipStyle?.backgroundColor,
255
- textColor: options?.selectItem?.labelTipStyle?.textColor,
256
- });
279
+ if (ix !== 0 && this.showGrid) {
280
+ ctx.moveTo(offsetPoint, linePosition);
281
+ ctx.lineTo(offsetCounterPoint, linePosition);
257
282
  }
258
283
  }
259
- if (this.showIndicator) {
260
- ctx.moveTo(linePosition, offsetPoint + 6);
261
- ctx.lineTo(linePosition, offsetPoint);
284
+
285
+ ctx.stroke();
286
+ ctx.closePath();
287
+ }
288
+ }
289
+
290
+ // Draw plot lines and plot bands
291
+ if (this.plotBands?.length || this.plotLines?.length) {
292
+ const xArea = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
293
+ const yArea = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
294
+ const padding = aliasPixel + 1;
295
+ const minX = aPos.x1 + padding;
296
+ const maxX = aPos.x2;
297
+ const minY = aPos.y1 + padding; // top
298
+ const maxY = aPos.y2; // bottom
299
+
300
+ this.plotBands?.forEach((plotBand) => {
301
+ if (!plotBand.from && !plotBand.to) {
302
+ return;
262
303
  }
263
304
 
264
- if (ix !== 0 && this.showGrid) {
265
- ctx.moveTo(linePosition, offsetPoint);
266
- ctx.lineTo(linePosition, offsetCounterPoint);
305
+ const mergedPlotBandOpt = defaultsDeep({}, plotBand, PLOT_BAND_OPTION);
306
+ const { from, to, label: labelOpt } = mergedPlotBandOpt;
307
+
308
+ this.setPlotBandStyle(mergedPlotBandOpt);
309
+
310
+ let fromPos;
311
+ let toPos;
312
+ if (this.type === 'x') {
313
+ fromPos = Canvas.calculateX(from ?? minX, axisMin, axisMax, xArea, minX);
314
+ toPos = Canvas.calculateX(to ?? maxX, axisMin, axisMax, xArea, minX);
315
+ this.drawXPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
316
+ } else {
317
+ fromPos = Canvas.calculateY(from ?? axisMin, axisMin, axisMax, yArea, maxY);
318
+ toPos = Canvas.calculateY(to ?? axisMax, axisMin, axisMax, yArea, maxY);
319
+ this.drawYPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
267
320
  }
268
- } else {
269
- labelPoint = this.position === 'left' ? offsetPoint - 10 : offsetPoint + 10;
270
- ctx.fillText(labelText, labelPoint, labelCenter);
271
321
 
272
- if (ix === steps) {
273
- linePosition += 1;
322
+ if (labelOpt.show) {
323
+ const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
324
+ const textXY = this.getPlotBandLabelPosition(fromPos, toPos, labelOptions, maxX, minY);
325
+ this.drawPlotLabel(labelOptions, textXY);
274
326
  }
275
327
 
276
- if (this.showIndicator) {
277
- ctx.moveTo(offsetPoint - 6, linePosition);
278
- ctx.lineTo(offsetPoint, linePosition);
328
+ ctx.restore();
329
+ });
330
+
331
+ this.plotLines?.forEach((plotLine) => {
332
+ if (!plotLine.value) {
333
+ return;
334
+ }
335
+
336
+ const mergedPlotLineOpt = defaultsDeep({}, plotLine, PLOT_LINE_OPTION);
337
+ const { value, label: labelOpt } = mergedPlotLineOpt;
338
+
339
+ this.setPlotLineStyle(mergedPlotLineOpt);
340
+
341
+ let dataPos;
342
+ if (this.type === 'x') {
343
+ dataPos = Canvas.calculateX(value, axisMin, axisMax, xArea, minX);
344
+ this.drawXPlotLine(dataPos, minX, maxX, minY, maxY);
345
+ } else {
346
+ dataPos = Canvas.calculateY(value, axisMin, axisMax, yArea, maxY);
347
+ this.drawYPlotLine(dataPos, minX, maxX, minY, maxY);
279
348
  }
280
349
 
281
- if (ix !== 0 && this.showGrid) {
282
- ctx.moveTo(offsetPoint, linePosition);
283
- ctx.lineTo(offsetCounterPoint, linePosition);
350
+ if (labelOpt.show) {
351
+ const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
352
+ const textXY = this.getPlotLineLabelPosition(dataPos, labelOptions, maxX, minY);
353
+ this.drawPlotLabel(labelOptions, textXY);
284
354
  }
355
+
356
+ ctx.restore();
357
+ });
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Set plot line style
363
+ * @param {object} plotLine plotLine Options
364
+ *
365
+ * @returns {undefined}
366
+ */
367
+ setPlotLineStyle(plotLine) {
368
+ const ctx = this.ctx;
369
+ const { color, lineWidth } = plotLine;
370
+
371
+ ctx.beginPath();
372
+ ctx.save();
373
+ ctx.lineWidth = lineWidth;
374
+ ctx.strokeStyle = color;
375
+
376
+ if (plotLine.segments) {
377
+ ctx.setLineDash(plotLine.segments);
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Set plot band style
383
+ * @param {object} plotBand plotBand Options
384
+ *
385
+ * @returns {undefined}
386
+ */
387
+ setPlotBandStyle(plotBand) {
388
+ const ctx = this.ctx;
389
+ const { color } = plotBand;
390
+
391
+ ctx.beginPath();
392
+ ctx.save();
393
+ ctx.fillStyle = color;
394
+ }
395
+
396
+ /**
397
+ * Draw X Plot band
398
+ * @param {number} fromDataX From data's X Position
399
+ * @param {number} toDataX To data's X Position
400
+ * @param {number} minX Min X Position
401
+ * @param {number} maxX Max X Position
402
+ * @param {number} minY Min Y Position
403
+ * @param {number} maxY Max Y Position
404
+ *
405
+ * @returns {undefined}
406
+ */
407
+ drawXPlotBand(fromDataX, toDataX, minX, maxX, minY, maxY) {
408
+ const ctx = this.ctx;
409
+
410
+ const checkValidPosition = x => x || x > minX || x < maxX;
411
+
412
+ if (!checkValidPosition(fromDataX) || !checkValidPosition(toDataX)) {
413
+ ctx.closePath();
414
+ ctx.restore();
415
+ return;
416
+ }
417
+
418
+ ctx.moveTo(fromDataX, minY);
419
+ ctx.lineTo(fromDataX, maxY);
420
+ ctx.lineTo(toDataX, maxY);
421
+ ctx.lineTo(toDataX, minY);
422
+ ctx.lineTo(fromDataX, minY);
423
+
424
+ ctx.stroke();
425
+ ctx.fill();
426
+ ctx.restore();
427
+ ctx.closePath();
428
+ }
429
+
430
+ /**
431
+ * Draw X Plot line
432
+ * @param {object} dataX Data's X Position
433
+ * @param {number} minX Min X Position
434
+ * @param {number} maxX Max X Position
435
+ * @param {number} minY Min Y Position
436
+ * @param {number} maxY Max Y Position
437
+ *
438
+ * @returns {undefined}
439
+ */
440
+ drawXPlotLine(dataX, minX, maxX, minY, maxY) {
441
+ const ctx = this.ctx;
442
+
443
+ if (!dataX || dataX < minX || dataX > maxX) {
444
+ ctx.closePath();
445
+ ctx.restore();
446
+ return;
447
+ }
448
+
449
+ ctx.moveTo(dataX, maxY);
450
+ ctx.lineTo(dataX, minY);
451
+
452
+ ctx.stroke();
453
+ ctx.restore();
454
+ ctx.closePath();
455
+ }
456
+
457
+ /**
458
+ * Draw Y Plot line
459
+ * @param {object} dataY Data's Y Position
460
+ * @param {number} minX Min X Position
461
+ * @param {number} maxX Max X Position
462
+ * @param {number} minY Min Y Position
463
+ * @param {number} maxY Max Y Position
464
+ *
465
+ * @returns {undefined}
466
+ */
467
+ drawYPlotLine(dataY, minX, maxX, minY, maxY) {
468
+ const ctx = this.ctx;
469
+
470
+ if (!dataY || dataY > maxY || dataY < minY) {
471
+ ctx.closePath();
472
+ ctx.restore();
473
+ return;
474
+ }
475
+
476
+ ctx.moveTo(minX, dataY);
477
+ ctx.lineTo(maxX, dataY);
478
+
479
+ ctx.stroke();
480
+ ctx.restore();
481
+ ctx.closePath();
482
+ }
483
+
484
+ /**
485
+ * Draw Y Plot band
486
+ * @param {number} fromDataY From data's Y Position (bottom)
487
+ * @param {number} toDataY To data's Y Position (top)
488
+ * @param {number} minX Min X Position
489
+ * @param {number} maxX Max X Position
490
+ * @param {number} minY Min Y Position
491
+ * @param {number} maxY Max Y Position
492
+ *
493
+ * @returns {undefined}
494
+ */
495
+ drawYPlotBand(fromDataY, toDataY, minX, maxX, minY, maxY) {
496
+ const ctx = this.ctx;
497
+
498
+ const checkValidPosition = y => y || y > minY || y < maxY;
499
+
500
+ if (!checkValidPosition(fromDataY) || !checkValidPosition(toDataY)) {
501
+ ctx.closePath();
502
+ ctx.restore();
503
+ return;
504
+ }
505
+
506
+ ctx.moveTo(minX, fromDataY);
507
+ ctx.lineTo(minX, toDataY);
508
+ ctx.lineTo(maxX, toDataY);
509
+ ctx.lineTo(maxX, fromDataY);
510
+ ctx.lineTo(minX, fromDataY);
511
+
512
+ ctx.fill();
513
+ ctx.restore();
514
+ ctx.closePath();
515
+ }
516
+
517
+ /**
518
+ * get normalized options for plot label
519
+ * @param {object} chartRect chartRect
520
+ * @param {object} labelOpt plotLine Options
521
+ *
522
+ * @returns {object}
523
+ */
524
+ getNormalizedLabelOptions(chartRect, labelOpt) {
525
+ const mergedLabelOpt = defaultsDeep({}, labelOpt, PLOT_LINE_LABEL_OPTION);
526
+
527
+ const ctx = this.ctx;
528
+ const { maxWidth } = mergedLabelOpt;
529
+ const fontSize = mergedLabelOpt.fontSize > 20 ? 20 : mergedLabelOpt.fontSize;
530
+ let label = mergedLabelOpt.text;
531
+ let labelWidth = maxWidth ?? ctx.measureText(label).width;
532
+
533
+ const plotLabelAreaWidth = this.type === 'y'
534
+ ? chartRect.width - chartRect.chartWidth
535
+ : maxWidth ?? chartRect.width;
536
+
537
+ if (plotLabelAreaWidth < ctx.measureText(label).width && mergedLabelOpt.textOverflow === 'ellipsis') {
538
+ label = Util.truncateLabelWithEllipsis(mergedLabelOpt.text, plotLabelAreaWidth, ctx);
539
+ labelWidth = ctx.measureText(label).width;
540
+ }
541
+
542
+ return {
543
+ label,
544
+ fontSize,
545
+ labelWidth,
546
+ labelBoxPadding: fontSize / 4,
547
+ labelHalfWidth: labelWidth / 2,
548
+ labelHalfHeight: fontSize / 2,
549
+ ...mergedLabelOpt,
550
+ };
551
+ }
552
+
553
+ /**
554
+ * Calculate position of plot band's label
555
+ * @param {object} fromPos from data position
556
+ * @param {object} toPos to data position
557
+ * @param {object} labelOpt label options
558
+ * @param {object} maxX max x position
559
+ * @param {object} minY min y position
560
+ *
561
+ * @returns {object}
562
+ */
563
+ getPlotBandLabelPosition(fromPos, toPos, labelOpt, maxX, minY) {
564
+ const {
565
+ fontSize,
566
+ labelWidth,
567
+ labelHalfWidth,
568
+ labelHalfHeight,
569
+ labelBoxPadding,
570
+ textAlign,
571
+ verticalAlign,
572
+ } = labelOpt;
573
+
574
+ if (fontSize <= 0) {
575
+ return { textX: 0, textY: 0 };
576
+ }
577
+
578
+ let textX;
579
+ let textY;
580
+
581
+ if (this.type === 'x') {
582
+ textY = minY - labelBoxPadding - fontSize;
583
+
584
+ switch (textAlign) {
585
+ case 'left':
586
+ textX = fromPos + labelHalfWidth + labelBoxPadding;
587
+ break;
588
+
589
+ case 'right':
590
+ textX = toPos - labelHalfWidth - labelBoxPadding;
591
+ break;
592
+
593
+ case 'center':
594
+ default:
595
+ textX = ((toPos - fromPos) / 2) + fromPos;
596
+ break;
597
+ }
598
+ } else {
599
+ textX = maxX + labelWidth + labelBoxPadding;
600
+
601
+ switch (verticalAlign) {
602
+ case 'top':
603
+ textY = toPos + labelHalfHeight + labelBoxPadding;
604
+ break;
605
+
606
+ case 'bottom':
607
+ textY = fromPos - labelHalfHeight - labelBoxPadding;
608
+ break;
609
+
610
+ case 'middle':
611
+ default:
612
+ textY = ((fromPos - toPos) / 2) + toPos;
613
+ break;
285
614
  }
615
+ }
286
616
 
617
+ return { textX, textY };
618
+ }
619
+
620
+ /**
621
+ * Calculate position of plot line's label
622
+ * @param {object} dataPos data position
623
+ * @param {object} labelOpt label options
624
+ * @param {object} maxX max x position
625
+ * @param {object} minY min y position
626
+ *
627
+ * @returns {undefined}
628
+ */
629
+ getPlotLineLabelPosition(dataPos, labelOpt, maxX, minY) {
630
+ const {
631
+ fontSize,
632
+ labelWidth,
633
+ labelHalfWidth,
634
+ labelHalfHeight,
635
+ labelBoxPadding,
636
+ } = labelOpt;
637
+
638
+ if (fontSize <= 0) {
639
+ return { textX: 0, textY: 0 };
640
+ }
641
+
642
+ let textX;
643
+ let textY;
644
+
645
+ if (this.type === 'x') {
646
+ textY = minY - labelBoxPadding - fontSize;
647
+
648
+ switch (labelOpt.textAlign) {
649
+ case 'left':
650
+ textX = dataPos - labelHalfWidth - labelBoxPadding;
651
+ break;
652
+
653
+ case 'right':
654
+ textX = dataPos + labelHalfWidth + labelBoxPadding;
655
+ break;
656
+
657
+ case 'center':
658
+ default:
659
+ textX = dataPos;
660
+ break;
661
+ }
662
+ } else {
663
+ textX = maxX + labelWidth + labelBoxPadding;
664
+
665
+ switch (labelOpt.verticalAlign) {
666
+ case 'top':
667
+ textY = dataPos - labelHalfHeight - labelBoxPadding;
668
+ break;
669
+
670
+ case 'bottom':
671
+ textY = dataPos + labelHalfHeight + labelBoxPadding;
672
+ break;
673
+
674
+ case 'middle':
675
+ default:
676
+ textY = dataPos;
677
+ break;
678
+ }
679
+ }
680
+
681
+ return { textX, textY };
682
+ }
683
+
684
+ /**
685
+ * Calculate Values for drawing label
686
+ * @param {object} labelOptions plot line Label Options
687
+ * @param {object} positions x, y Position
688
+ *
689
+ * @returns {undefined}
690
+ */
691
+ drawPlotLabel(labelOptions, positions) {
692
+ if (!positions) {
693
+ return;
694
+ }
695
+
696
+ const { textX, textY } = positions;
697
+ const {
698
+ label,
699
+ fontSize,
700
+ fontColor,
701
+ fillColor,
702
+ lineColor,
703
+ lineWidth,
704
+ labelBoxPadding,
705
+ labelWidth,
706
+ labelHalfWidth,
707
+ labelHalfHeight,
708
+ } = labelOptions;
709
+
710
+ if (fontSize <= 0) {
711
+ return;
712
+ }
713
+
714
+ const ctx = this.ctx;
715
+ ctx.save();
716
+ ctx.beginPath();
717
+ ctx.font = Util.getLabelStyle(labelOptions);
718
+
719
+ let top = 0;
720
+ let bottom = 0;
721
+ let left = 0;
722
+ let right = 0;
723
+
724
+ if (this.type === 'x') {
725
+ top = textY - labelBoxPadding;
726
+ bottom = textY + fontSize;
727
+ left = textX - labelHalfWidth - labelBoxPadding;
728
+ right = textX + labelHalfWidth + labelBoxPadding;
729
+ } else {
730
+ top = textY - labelHalfHeight - labelBoxPadding;
731
+ bottom = textY + labelHalfHeight + labelBoxPadding;
732
+ left = textX - labelWidth;
733
+ right = textX + labelBoxPadding;
734
+ }
735
+
736
+ ctx.fillStyle = fillColor;
737
+ ctx.strokeStyle = lineColor;
738
+ ctx.lineWidth = lineWidth;
739
+ ctx.moveTo(left, bottom);
740
+ ctx.lineTo(left, top);
741
+ ctx.lineTo(right, top);
742
+ ctx.lineTo(right, bottom);
743
+ ctx.lineTo(left, bottom);
744
+ ctx.fill();
745
+
746
+ if (lineWidth > 0) {
287
747
  ctx.stroke();
288
- ctx.closePath();
289
748
  }
749
+
750
+ ctx.fillStyle = fontColor;
751
+
752
+ ctx.fillText(label, textX, textY);
753
+ ctx.closePath();
290
754
  }
291
755
  }
292
756
 
@@ -9,6 +9,14 @@ class LinearScale extends Scale {
9
9
  * @returns {string} formatted label
10
10
  */
11
11
  getLabelFormat(value) {
12
+ if (this.formatter) {
13
+ const formattedLabel = this.formatter(value);
14
+
15
+ if (typeof formattedLabel === 'string') {
16
+ return formattedLabel;
17
+ }
18
+ }
19
+
12
20
  return Util.labelSignFormat(value, this.decimalPoint);
13
21
  }
14
22
 
@@ -101,6 +101,14 @@ class LogarithmicScale extends Scale {
101
101
  * @returns {string} formatted label
102
102
  */
103
103
  getLabelFormat(value) {
104
+ if (this.formatter) {
105
+ const formattedLabel = this.formatter(value);
106
+
107
+ if (typeof formattedLabel === 'string') {
108
+ return formattedLabel;
109
+ }
110
+ }
111
+
104
112
  return Util.labelSignFormat(value, this.decimalPoint);
105
113
  }
106
114