chartjs-chart-treemap 1.0.0-beta.4 → 1.0.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 Jukka Kurkela
3
+ Copyright (c) 2019-2021 Jukka Kurkela
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,74 +1,13 @@
1
1
  # chartjs-chart-treemap
2
2
 
3
- [Chart.js](https://www.chartjs.org/) **v3.0.0-beta.10** module for creating treemap charts. Implementation for Chart.js v2 is in [2.x branch](https://github.com/kurkle/chartjs-chart-treemap/tree/2.x)
3
+ [Chart.js](https://www.chartjs.org/) **v3.6.0** module for creating treemap charts. Implementation for Chart.js v2 is in [2.x branch](https://github.com/kurkle/chartjs-chart-treemap/tree/2.x)
4
4
 
5
- [![npm](https://img.shields.io/npm/v/chartjs-chart-treemap.svg)](https://www.npmjs.com/package/chartjs-chart-matrix)
5
+ [![npm](https://img.shields.io/npm/v/chartjs-chart-treemap.svg)](https://www.npmjs.com/package/chartjs-chart-treemap)
6
6
  [![release](https://img.shields.io/github/release/kurkle/chartjs-chart-treemap.svg?style=flat-square)](https://github.com/kurkle/chartjs-chart-treemap/releases/latest)
7
7
  ![npm bundle size](https://img.shields.io/bundlephobia/min/chartjs-chart-treemap.svg)
8
+ [![documentation](https://img.shields.io/static/v1?message=Documentation&color=informational)](https://chartjs-chart-treemap.pages.dev)
8
9
  ![GitHub](https://img.shields.io/github/license/kurkle/chartjs-chart-treemap.svg)
9
-
10
- ## Documentation
11
-
12
- To create a treemap chart, include chartjs-chart-treemap.js after chart.js and then create the chart by setting the `type` attribute to `'treemap'`
13
-
14
- ```js
15
- new Chart(ctx, {
16
- type: 'treemap',
17
- tree: dataObject,
18
- key: 'value',
19
- groups: ['main', 'sub']
20
- });
21
- ```
22
-
23
- ## Configuration
24
-
25
- Tree data should be provided in `tree` property of dataset. `data` is then automatically build. `key` defines the key name in data objects to use for value. `groups` array can be provided to display multiple levels of hierarchy.
26
- Data is summarized to groups internally.
27
-
28
- ```js
29
- new Chart(ctx, {
30
- type: 'treemap',
31
- data: {
32
- datasets: [{
33
- label: 'Basic treemap',
34
- tree: [6,6,5,4,3,2,2,1],
35
- font: {
36
- color: '#000',
37
- family: 'serif',
38
- size: 12,
39
- style: 'normal',
40
- },
41
- backgroundColor: function(ctx) {
42
- var value = ctx.dataset.data[ctx.dataIndex];
43
- var alpha = (value + 3) / 10;
44
- return Color('blue').alpha(alpha).rgbString();
45
- },
46
- rtl: false // control in which direction the squares are positioned
47
- }]
48
- },
49
- });
50
- ```
51
-
52
- ### Note about chartjs-plugin-datalabels
53
-
54
- Treemap is not using any scales currently and thats why [chartjs-plugin-datalabels](https://chartjs-plugin-datalabels.netlify.app/) plugin does not work with it.
55
- When other charts are using datalables on the same page, you'll need to disable the plugin for treemap charts:
56
-
57
- ```js
58
- new Chart(ctx, {
59
- type: 'treemap',
60
- data: (...),
61
- options: {
62
- plugins: {
63
- datalabels: false
64
- }
65
- }
66
- });
67
- ```
68
-
69
- ## Example
70
-
71
- [Live examples @codepen.io](https://codepen.io/kurkle/full/oNjXJwe)
10
+ [![Coverage Status](https://coveralls.io/repos/github/kurkle/chartjs-chart-treemap/badge.svg)](https://coveralls.io/github/kurkle/chartjs-chart-treemap)
72
11
 
73
12
  ![TreeMap Example Image](treemap.png)
74
13
 
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * chartjs-chart-treemap v1.0.0-beta.4
3
- * https://github.com/kurkle/chartjs-chart-treemap#readme
2
+ * chartjs-chart-treemap v1.0.3
3
+ * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2021 Jukka Kurkela
5
5
  * Released under the MIT license
6
6
  */
7
- import { DatasetController, Element } from 'chart.js';
8
- import { toFont, valueOrDefault } from 'chart.js/helpers';
7
+ import { Chart, registry, DatasetController, Element } from 'chart.js';
8
+ import { toFont, valueOrDefault, isArray } from 'chart.js/helpers';
9
9
 
10
10
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
11
11
  function flatten(input) {
@@ -108,7 +108,15 @@ function sum(values, key) {
108
108
  return s;
109
109
  }
110
110
 
111
+ function requireVersion(min, ver) {
112
+ const parts = ver.split('.');
113
+ if (!min.split('.').reduce((a, c, i) => a && c <= parts[i], true)) {
114
+ throw new Error(`Chart.js v${ver} is not supported. v${min} or newer is required.`);
115
+ }
116
+ }
117
+
111
118
  function round(v, n) {
119
+ // @ts-ignore
112
120
  return (+(Math.round(v + 'e+' + n) + 'e-' + n)) || 0;
113
121
  }
114
122
 
@@ -326,7 +334,7 @@ function squarify(values, rectangle, key, grp, lvl, gsum) {
326
334
  const gval = (idx) => grp && tmp[idx][grp];
327
335
 
328
336
  for (i = 0; i < n; ++i) {
329
- o = {value: val(i), groupSum: gsum, _data: values[tmp[i]._idx]};
337
+ o = {value: val(i), groupSum: gsum, _data: values[tmp[i]._idx], level: undefined, group: undefined};
330
338
  if (grp) {
331
339
  o.level = lvl;
332
340
  o.group = gval(i);
@@ -345,6 +353,8 @@ function squarify(values, rectangle, key, grp, lvl, gsum) {
345
353
  return flatten(rows);
346
354
  }
347
355
 
356
+ var version = "1.0.3";
357
+
348
358
  function rectNotEqual(r1, r2) {
349
359
  return !r1 || !r2
350
360
  || r1.x !== r2.x
@@ -380,35 +390,47 @@ function shouldDrawCaption(rect, font) {
380
390
 
381
391
  function drawCaption(ctx, rect, item, opts, levels) {
382
392
  ctx.save();
383
- ctx.fillStyle = opts.color;
384
- ctx.font = opts.font.string;
385
393
  ctx.beginPath();
386
394
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
387
395
  ctx.clip();
388
396
  if (!('l' in item) || item.l === levels) {
389
- ctx.textAlign = 'center';
390
- ctx.textBaseline = 'middle';
391
397
  drawLabels(ctx, item, rect);
392
- } else if (opts.groupLabels) {
393
- ctx.textAlign = opts.rtl ? 'end' : 'start';
394
- ctx.textBaseline = 'top';
395
- const x = opts.rtl ? rect.x + rect.width - opts.borderWidth - 3 : rect.x + opts.borderWidth + 3;
396
- ctx.fillText(item.g, x, rect.y + opts.borderWidth + 3);
398
+ } else if (opts.captions && opts.captions.display) {
399
+ drawCaptionLabel(ctx, item, rect);
397
400
  }
398
401
  ctx.restore();
399
402
  }
400
403
 
404
+ function drawCaptionLabel(ctx, item, rect) {
405
+ const opts = rect.options;
406
+ const captionsOpts = opts.captions || {};
407
+ const borderWidth = opts.borderWidth || 0;
408
+ const spacing = valueOrDefault(opts.spacing, 0) + borderWidth;
409
+ const color = (rect.active ? captionsOpts.hoverColor : captionsOpts.color) || captionsOpts.color;
410
+ const padding = captionsOpts.padding;
411
+ const align = captionsOpts.align || (opts.rtl ? 'right' : 'left');
412
+ const optFont = (rect.active ? captionsOpts.hoverFont : captionsOpts.font) || captionsOpts.font;
413
+ const font = toFont(optFont);
414
+ const x = calculateX(rect, align, padding, borderWidth);
415
+ ctx.fillStyle = color;
416
+ ctx.font = font.string;
417
+ ctx.textAlign = align;
418
+ ctx.textBaseline = 'middle';
419
+ ctx.fillText(captionsOpts.formatter || item.g, x, rect.y + padding + spacing + (font.lineHeight / 2));
420
+ }
421
+
401
422
  function drawDivider(ctx, rect) {
402
423
  const opts = rect.options;
424
+ const dividersOpts = opts.dividers || {};
403
425
  const w = rect.width || rect.w;
404
426
  const h = rect.height || rect.h;
405
427
 
406
428
  ctx.save();
407
- ctx.strokeStyle = opts.dividerColor || 'black';
408
- ctx.lineCap = opts.dividerCapStyle;
409
- ctx.setLineDash(opts.dividerDash || []);
410
- ctx.lineDashOffset = opts.dividerDashOffset;
411
- ctx.lineWidth = opts.dividerWidth;
429
+ ctx.strokeStyle = dividersOpts.lineColor || 'black';
430
+ ctx.lineCap = dividersOpts.lineCapStyle;
431
+ ctx.setLineDash(dividersOpts.lineDash || []);
432
+ ctx.lineDashOffset = dividersOpts.lineDashOffset;
433
+ ctx.lineWidth = dividersOpts.lineWidth;
412
434
  ctx.beginPath();
413
435
  if (w > h) {
414
436
  const w2 = w / 2;
@@ -423,12 +445,15 @@ function drawDivider(ctx, rect) {
423
445
  ctx.restore();
424
446
  }
425
447
 
426
- function buildData(dataset, mainRect, font) {
448
+ function buildData(dataset, mainRect, captions) {
427
449
  const key = dataset.key || '';
428
450
  let tree = dataset.tree || [];
429
451
  const groups = dataset.groups || [];
430
452
  const glen = groups.length;
431
- const sp = (dataset.spacing || 0) + (dataset.borderWidth || 0);
453
+ const sp = valueOrDefault(dataset.spacing, 0) + valueOrDefault(dataset.borderWidth, 0);
454
+ const captionsFont = captions.font || {};
455
+ const font = toFont(captionsFont);
456
+ const padding = valueOrDefault(captions.padding, 3);
432
457
 
433
458
  function recur(gidx, rect, parent, gs) {
434
459
  const g = groups[gidx];
@@ -440,10 +465,9 @@ function buildData(dataset, mainRect, font) {
440
465
  if (gidx < glen - 1) {
441
466
  gsq.forEach((sq) => {
442
467
  subRect = {x: sq.x + sp, y: sq.y + sp, w: sq.w - 2 * sp, h: sq.h - 2 * sp};
443
-
444
- if (valueOrDefault(dataset.groupLabels, true) && shouldDrawCaption(sq, font)) {
445
- subRect.y += font.lineHeight;
446
- subRect.h -= font.lineHeight;
468
+ if (valueOrDefault(captions.display, true) && shouldDrawCaption(sq, font)) {
469
+ subRect.y += font.lineHeight + padding * 2;
470
+ subRect.h -= font.lineHeight + padding * 2;
447
471
  }
448
472
  ret.push(...recur(gidx + 1, subRect, sq.g, sq.s));
449
473
  });
@@ -462,13 +486,60 @@ function buildData(dataset, mainRect, font) {
462
486
 
463
487
  function drawLabels(ctx, item, rect) {
464
488
  const opts = rect.options;
465
- const lh = opts.font.lineHeight;
466
- const labels = (opts.label || item.g + '\n' + item.v).split('\n');
467
- const y = rect.y + rect.height / 2 - labels.length * lh / 4;
468
- labels.forEach((l, i) => ctx.fillText(l, rect.x + rect.width / 2, y + i * lh));
489
+ const labelsOpts = opts.labels;
490
+ if (!labelsOpts || !labelsOpts.display) {
491
+ return;
492
+ }
493
+ const optColor = (rect.active ? labelsOpts.hoverColor : labelsOpts.color) || labelsOpts.color;
494
+ const optFont = (rect.active ? labelsOpts.hoverFont : labelsOpts.font) || labelsOpts.font;
495
+ const font = toFont(optFont);
496
+ const lh = font.lineHeight;
497
+ const label = labelsOpts.formatter;
498
+ if (label) {
499
+ const labels = isArray(label) ? label : [label];
500
+ const xyPoint = calculateXYLabel(opts, rect, labels, lh);
501
+ ctx.font = font.string;
502
+ ctx.textAlign = labelsOpts.align;
503
+ ctx.textBaseline = labelsOpts.position;
504
+ ctx.fillStyle = optColor;
505
+ labels.forEach((l, i) => ctx.fillText(l, xyPoint.x, xyPoint.y + i * lh));
506
+ }
507
+ }
508
+
509
+ function calculateXYLabel(options, rect, labels, lineHeight) {
510
+ const labelsOpts = options.labels;
511
+ const borderWidth = options.borderWidth || 0;
512
+ const {align, position, padding} = labelsOpts;
513
+ let x, y;
514
+ x = calculateX(rect, align, padding, borderWidth);
515
+ if (position === 'top') {
516
+ y = rect.y + padding + borderWidth;
517
+ } else if (position === 'bottom') {
518
+ y = rect.y + rect.height - padding - borderWidth - (labels.length - 1) * lineHeight;
519
+ } else {
520
+ y = rect.y + rect.height / 2 - labels.length * lineHeight / 4;
521
+ }
522
+ return {x, y};
523
+ }
524
+
525
+ function calculateX(rect, align, padding, borderWidth) {
526
+ if (align === 'left') {
527
+ return rect.x + padding + borderWidth;
528
+ } else if (align === 'right') {
529
+ return rect.x + rect.width - padding - borderWidth;
530
+ }
531
+ return rect.x + rect.width / 2;
469
532
  }
470
533
 
471
534
  class TreemapController extends DatasetController {
535
+ constructor(chart, datasetIndex) {
536
+ super(chart, datasetIndex);
537
+
538
+ this._rect = undefined;
539
+ this._key = undefined;
540
+ this._groups = undefined;
541
+ }
542
+
472
543
  initialize() {
473
544
  this.enableOptionSharing = true;
474
545
  super.initialize();
@@ -479,7 +550,7 @@ class TreemapController extends DatasetController {
479
550
  const meta = me.getMeta();
480
551
  const dataset = me.getDataset();
481
552
  const groups = dataset.groups || (dataset.groups = []);
482
- const font = toFont(dataset.font, me.chart.options.font);
553
+ const captions = dataset.captions ? dataset.captions : {};
483
554
  const area = me.chart.chartArea;
484
555
  const key = dataset.key || '';
485
556
  const rtl = !!dataset.rtl;
@@ -490,8 +561,11 @@ class TreemapController extends DatasetController {
490
561
  me._rect = mainRect;
491
562
  me._groups = groups.slice();
492
563
  me._key = key;
493
- dataset.data = buildData(dataset, mainRect, font);
564
+
565
+ dataset.data = buildData(dataset, mainRect, captions);
566
+ // @ts-ignore using private stuff
494
567
  me._dataCheck();
568
+ // @ts-ignore using private stuff
495
569
  me._resyncElements();
496
570
  }
497
571
 
@@ -501,7 +575,7 @@ class TreemapController extends DatasetController {
501
575
  resolveDataElementOptions(index, mode) {
502
576
  const options = super.resolveDataElementOptions(index, mode);
503
577
  const result = Object.isFrozen(options) ? Object.assign({}, options) : options;
504
- result.font = toFont(options.font, this.chart.options.font);
578
+ result.font = toFont(options.captions.font);
505
579
  return result;
506
580
  }
507
581
 
@@ -540,13 +614,11 @@ class TreemapController extends DatasetController {
540
614
  for (let i = 0, ilen = metadata.length; i < ilen; ++i) {
541
615
  const rect = metadata[i];
542
616
  const item = data[i];
543
- if (rect.options.groupDividers && item._data.children.length > 1) {
617
+ const dividersOpts = rect.options.dividers || {};
618
+ if (dividersOpts.display && item._data.children.length > 1) {
544
619
  drawDivider(ctx, rect);
545
620
  }
546
621
  }
547
- if (this.getDataset().groupDividers) {
548
- drawDivider(ctx, this._rect);
549
- }
550
622
  }
551
623
 
552
624
  _drawRects(ctx, data, metadata, levels) {
@@ -556,7 +628,7 @@ class TreemapController extends DatasetController {
556
628
  if (!rect.hidden) {
557
629
  rect.draw(ctx);
558
630
  const opts = rect.options;
559
- if (shouldDrawCaption(rect, opts.font) && item.g) {
631
+ if (shouldDrawCaption(rect, opts.captions.font)) {
560
632
  drawCaption(ctx, rect, item, opts, levels);
561
633
  }
562
634
  }
@@ -578,16 +650,25 @@ class TreemapController extends DatasetController {
578
650
 
579
651
  TreemapController.id = 'treemap';
580
652
 
653
+ TreemapController.version = version;
654
+
581
655
  TreemapController.defaults = {
582
656
  dataElementType: 'treemap',
583
657
 
584
- groupLabels: true,
585
658
  borderWidth: 0,
586
659
  spacing: 0.5,
587
- groupDividers: false,
588
- dividerWidth: 1
660
+ dividers: {
661
+ display: false,
662
+ lineWidth: 1,
663
+ }
664
+
665
+ };
589
666
 
667
+ TreemapController.descriptors = {
668
+ _scriptable: true,
669
+ _indexable: false
590
670
  };
671
+
591
672
  TreemapController.overrides = {
592
673
  interaction: {
593
674
  mode: 'point',
@@ -629,6 +710,33 @@ TreemapController.overrides = {
629
710
  },
630
711
  };
631
712
 
713
+ TreemapController.beforeRegister = function() {
714
+ requireVersion('3.6', Chart.version);
715
+ };
716
+
717
+ TreemapController.afterRegister = function() {
718
+ const tooltipPlugin = registry.plugins.get('tooltip');
719
+ if (tooltipPlugin) {
720
+ tooltipPlugin.positioners.treemap = function(active) {
721
+ if (!active.length) {
722
+ return false;
723
+ }
724
+
725
+ const item = active[active.length - 1];
726
+ const el = item.element;
727
+
728
+ return el.tooltipPosition();
729
+ };
730
+ }
731
+ };
732
+
733
+ TreemapController.afterUnregister = function() {
734
+ const tooltipPlugin = registry.plugins.get('tooltip');
735
+ if (tooltipPlugin) {
736
+ delete tooltipPlugin.positioners.treemap;
737
+ }
738
+ };
739
+
632
740
  /**
633
741
  * Helper function to get the bounds of the rect
634
742
  * @param {TreemapElement} rect the rect
@@ -730,7 +838,6 @@ class TreemapElement extends Element {
730
838
  ctx.fillStyle = options.backgroundColor;
731
839
  ctx.fillRect(inner.x, inner.y, inner.w, inner.h);
732
840
  }
733
-
734
841
  ctx.restore();
735
842
  }
736
843
 
@@ -766,20 +873,40 @@ class TreemapElement extends Element {
766
873
  TreemapElement.id = 'treemap';
767
874
 
768
875
  TreemapElement.defaults = {
769
- borderSkipped: undefined,
770
876
  borderWidth: undefined,
771
- color: undefined,
772
- dividerCapStyle: 'butt',
773
- dividerColor: 'black',
774
- dividerDash: undefined,
775
- dividerDashOffset: 0,
776
- dividerWidth: 0,
777
- font: {},
778
- groupDividers: false,
779
- groupLabels: undefined,
780
877
  spacing: undefined,
781
878
  label: undefined,
782
- rtl: undefined
879
+ rtl: undefined,
880
+ dividers: {
881
+ display: false,
882
+ lineCapStyle: 'butt',
883
+ lineColor: 'black',
884
+ lineDash: undefined,
885
+ lineDashOffset: 0,
886
+ lineWidth: 0,
887
+ },
888
+ captions: {
889
+ align: undefined,
890
+ color: undefined,
891
+ display: true,
892
+ formatter: (ctx) => ctx.raw.g || '',
893
+ font: {},
894
+ padding: 3
895
+ },
896
+ labels: {
897
+ align: 'center',
898
+ color: undefined,
899
+ display: false,
900
+ formatter: (ctx) => ctx.raw.g ? [ctx.raw.g, ctx.raw.v] : ctx.raw.v,
901
+ font: {},
902
+ position: 'middle',
903
+ padding: 3
904
+ }
905
+ };
906
+
907
+ TreemapElement.descriptors = {
908
+ _scriptable: true,
909
+ _indexable: false
783
910
  };
784
911
 
785
912
  TreemapElement.defaultRoutes = {
@@ -787,4 +914,4 @@ TreemapElement.defaultRoutes = {
787
914
  borderColor: 'borderColor'
788
915
  };
789
916
 
790
- export { Rect, TreemapElement as Rectangle, StatArray, TreemapController, flatten, group, index, isObject, sort, squarify, sum };
917
+ export { TreemapController, TreemapElement };
@@ -1,14 +1,14 @@
1
1
  /*!
2
- * chartjs-chart-treemap v1.0.0-beta.4
3
- * https://github.com/kurkle/chartjs-chart-treemap#readme
2
+ * chartjs-chart-treemap v1.0.3
3
+ * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2021 Jukka Kurkela
5
5
  * Released under the MIT license
6
6
  */
7
7
  (function (global, factory) {
8
8
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('chart.js'), require('chart.js/helpers')) :
9
9
  typeof define === 'function' && define.amd ? define(['exports', 'chart.js', 'chart.js/helpers'], factory) :
10
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['chartjs-chart-treemap'] = {}, global.Chart, global.Chart.helpers));
11
- }(this, (function (exports, chart_js, helpers) { 'use strict';
10
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["chartjs-chart-treemap"] = {}, global.Chart, global.Chart.helpers));
11
+ })(this, (function (exports, chart_js, helpers) { 'use strict';
12
12
 
13
13
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
14
14
  function flatten(input) {
@@ -111,7 +111,15 @@ function sum(values, key) {
111
111
  return s;
112
112
  }
113
113
 
114
+ function requireVersion(min, ver) {
115
+ const parts = ver.split('.');
116
+ if (!min.split('.').reduce((a, c, i) => a && c <= parts[i], true)) {
117
+ throw new Error(`Chart.js v${ver} is not supported. v${min} or newer is required.`);
118
+ }
119
+ }
120
+
114
121
  function round(v, n) {
122
+ // @ts-ignore
115
123
  return (+(Math.round(v + 'e+' + n) + 'e-' + n)) || 0;
116
124
  }
117
125
 
@@ -329,7 +337,7 @@ function squarify(values, rectangle, key, grp, lvl, gsum) {
329
337
  const gval = (idx) => grp && tmp[idx][grp];
330
338
 
331
339
  for (i = 0; i < n; ++i) {
332
- o = {value: val(i), groupSum: gsum, _data: values[tmp[i]._idx]};
340
+ o = {value: val(i), groupSum: gsum, _data: values[tmp[i]._idx], level: undefined, group: undefined};
333
341
  if (grp) {
334
342
  o.level = lvl;
335
343
  o.group = gval(i);
@@ -348,6 +356,8 @@ function squarify(values, rectangle, key, grp, lvl, gsum) {
348
356
  return flatten(rows);
349
357
  }
350
358
 
359
+ var version = "1.0.3";
360
+
351
361
  function rectNotEqual(r1, r2) {
352
362
  return !r1 || !r2
353
363
  || r1.x !== r2.x
@@ -383,35 +393,47 @@ function shouldDrawCaption(rect, font) {
383
393
 
384
394
  function drawCaption(ctx, rect, item, opts, levels) {
385
395
  ctx.save();
386
- ctx.fillStyle = opts.color;
387
- ctx.font = opts.font.string;
388
396
  ctx.beginPath();
389
397
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
390
398
  ctx.clip();
391
399
  if (!('l' in item) || item.l === levels) {
392
- ctx.textAlign = 'center';
393
- ctx.textBaseline = 'middle';
394
400
  drawLabels(ctx, item, rect);
395
- } else if (opts.groupLabels) {
396
- ctx.textAlign = opts.rtl ? 'end' : 'start';
397
- ctx.textBaseline = 'top';
398
- const x = opts.rtl ? rect.x + rect.width - opts.borderWidth - 3 : rect.x + opts.borderWidth + 3;
399
- ctx.fillText(item.g, x, rect.y + opts.borderWidth + 3);
401
+ } else if (opts.captions && opts.captions.display) {
402
+ drawCaptionLabel(ctx, item, rect);
400
403
  }
401
404
  ctx.restore();
402
405
  }
403
406
 
407
+ function drawCaptionLabel(ctx, item, rect) {
408
+ const opts = rect.options;
409
+ const captionsOpts = opts.captions || {};
410
+ const borderWidth = opts.borderWidth || 0;
411
+ const spacing = helpers.valueOrDefault(opts.spacing, 0) + borderWidth;
412
+ const color = (rect.active ? captionsOpts.hoverColor : captionsOpts.color) || captionsOpts.color;
413
+ const padding = captionsOpts.padding;
414
+ const align = captionsOpts.align || (opts.rtl ? 'right' : 'left');
415
+ const optFont = (rect.active ? captionsOpts.hoverFont : captionsOpts.font) || captionsOpts.font;
416
+ const font = helpers.toFont(optFont);
417
+ const x = calculateX(rect, align, padding, borderWidth);
418
+ ctx.fillStyle = color;
419
+ ctx.font = font.string;
420
+ ctx.textAlign = align;
421
+ ctx.textBaseline = 'middle';
422
+ ctx.fillText(captionsOpts.formatter || item.g, x, rect.y + padding + spacing + (font.lineHeight / 2));
423
+ }
424
+
404
425
  function drawDivider(ctx, rect) {
405
426
  const opts = rect.options;
427
+ const dividersOpts = opts.dividers || {};
406
428
  const w = rect.width || rect.w;
407
429
  const h = rect.height || rect.h;
408
430
 
409
431
  ctx.save();
410
- ctx.strokeStyle = opts.dividerColor || 'black';
411
- ctx.lineCap = opts.dividerCapStyle;
412
- ctx.setLineDash(opts.dividerDash || []);
413
- ctx.lineDashOffset = opts.dividerDashOffset;
414
- ctx.lineWidth = opts.dividerWidth;
432
+ ctx.strokeStyle = dividersOpts.lineColor || 'black';
433
+ ctx.lineCap = dividersOpts.lineCapStyle;
434
+ ctx.setLineDash(dividersOpts.lineDash || []);
435
+ ctx.lineDashOffset = dividersOpts.lineDashOffset;
436
+ ctx.lineWidth = dividersOpts.lineWidth;
415
437
  ctx.beginPath();
416
438
  if (w > h) {
417
439
  const w2 = w / 2;
@@ -426,12 +448,15 @@ function drawDivider(ctx, rect) {
426
448
  ctx.restore();
427
449
  }
428
450
 
429
- function buildData(dataset, mainRect, font) {
451
+ function buildData(dataset, mainRect, captions) {
430
452
  const key = dataset.key || '';
431
453
  let tree = dataset.tree || [];
432
454
  const groups = dataset.groups || [];
433
455
  const glen = groups.length;
434
- const sp = (dataset.spacing || 0) + (dataset.borderWidth || 0);
456
+ const sp = helpers.valueOrDefault(dataset.spacing, 0) + helpers.valueOrDefault(dataset.borderWidth, 0);
457
+ const captionsFont = captions.font || {};
458
+ const font = helpers.toFont(captionsFont);
459
+ const padding = helpers.valueOrDefault(captions.padding, 3);
435
460
 
436
461
  function recur(gidx, rect, parent, gs) {
437
462
  const g = groups[gidx];
@@ -443,10 +468,9 @@ function buildData(dataset, mainRect, font) {
443
468
  if (gidx < glen - 1) {
444
469
  gsq.forEach((sq) => {
445
470
  subRect = {x: sq.x + sp, y: sq.y + sp, w: sq.w - 2 * sp, h: sq.h - 2 * sp};
446
-
447
- if (helpers.valueOrDefault(dataset.groupLabels, true) && shouldDrawCaption(sq, font)) {
448
- subRect.y += font.lineHeight;
449
- subRect.h -= font.lineHeight;
471
+ if (helpers.valueOrDefault(captions.display, true) && shouldDrawCaption(sq, font)) {
472
+ subRect.y += font.lineHeight + padding * 2;
473
+ subRect.h -= font.lineHeight + padding * 2;
450
474
  }
451
475
  ret.push(...recur(gidx + 1, subRect, sq.g, sq.s));
452
476
  });
@@ -465,13 +489,60 @@ function buildData(dataset, mainRect, font) {
465
489
 
466
490
  function drawLabels(ctx, item, rect) {
467
491
  const opts = rect.options;
468
- const lh = opts.font.lineHeight;
469
- const labels = (opts.label || item.g + '\n' + item.v).split('\n');
470
- const y = rect.y + rect.height / 2 - labels.length * lh / 4;
471
- labels.forEach((l, i) => ctx.fillText(l, rect.x + rect.width / 2, y + i * lh));
492
+ const labelsOpts = opts.labels;
493
+ if (!labelsOpts || !labelsOpts.display) {
494
+ return;
495
+ }
496
+ const optColor = (rect.active ? labelsOpts.hoverColor : labelsOpts.color) || labelsOpts.color;
497
+ const optFont = (rect.active ? labelsOpts.hoverFont : labelsOpts.font) || labelsOpts.font;
498
+ const font = helpers.toFont(optFont);
499
+ const lh = font.lineHeight;
500
+ const label = labelsOpts.formatter;
501
+ if (label) {
502
+ const labels = helpers.isArray(label) ? label : [label];
503
+ const xyPoint = calculateXYLabel(opts, rect, labels, lh);
504
+ ctx.font = font.string;
505
+ ctx.textAlign = labelsOpts.align;
506
+ ctx.textBaseline = labelsOpts.position;
507
+ ctx.fillStyle = optColor;
508
+ labels.forEach((l, i) => ctx.fillText(l, xyPoint.x, xyPoint.y + i * lh));
509
+ }
510
+ }
511
+
512
+ function calculateXYLabel(options, rect, labels, lineHeight) {
513
+ const labelsOpts = options.labels;
514
+ const borderWidth = options.borderWidth || 0;
515
+ const {align, position, padding} = labelsOpts;
516
+ let x, y;
517
+ x = calculateX(rect, align, padding, borderWidth);
518
+ if (position === 'top') {
519
+ y = rect.y + padding + borderWidth;
520
+ } else if (position === 'bottom') {
521
+ y = rect.y + rect.height - padding - borderWidth - (labels.length - 1) * lineHeight;
522
+ } else {
523
+ y = rect.y + rect.height / 2 - labels.length * lineHeight / 4;
524
+ }
525
+ return {x, y};
526
+ }
527
+
528
+ function calculateX(rect, align, padding, borderWidth) {
529
+ if (align === 'left') {
530
+ return rect.x + padding + borderWidth;
531
+ } else if (align === 'right') {
532
+ return rect.x + rect.width - padding - borderWidth;
533
+ }
534
+ return rect.x + rect.width / 2;
472
535
  }
473
536
 
474
537
  class TreemapController extends chart_js.DatasetController {
538
+ constructor(chart, datasetIndex) {
539
+ super(chart, datasetIndex);
540
+
541
+ this._rect = undefined;
542
+ this._key = undefined;
543
+ this._groups = undefined;
544
+ }
545
+
475
546
  initialize() {
476
547
  this.enableOptionSharing = true;
477
548
  super.initialize();
@@ -482,7 +553,7 @@ class TreemapController extends chart_js.DatasetController {
482
553
  const meta = me.getMeta();
483
554
  const dataset = me.getDataset();
484
555
  const groups = dataset.groups || (dataset.groups = []);
485
- const font = helpers.toFont(dataset.font, me.chart.options.font);
556
+ const captions = dataset.captions ? dataset.captions : {};
486
557
  const area = me.chart.chartArea;
487
558
  const key = dataset.key || '';
488
559
  const rtl = !!dataset.rtl;
@@ -493,8 +564,11 @@ class TreemapController extends chart_js.DatasetController {
493
564
  me._rect = mainRect;
494
565
  me._groups = groups.slice();
495
566
  me._key = key;
496
- dataset.data = buildData(dataset, mainRect, font);
567
+
568
+ dataset.data = buildData(dataset, mainRect, captions);
569
+ // @ts-ignore using private stuff
497
570
  me._dataCheck();
571
+ // @ts-ignore using private stuff
498
572
  me._resyncElements();
499
573
  }
500
574
 
@@ -504,7 +578,7 @@ class TreemapController extends chart_js.DatasetController {
504
578
  resolveDataElementOptions(index, mode) {
505
579
  const options = super.resolveDataElementOptions(index, mode);
506
580
  const result = Object.isFrozen(options) ? Object.assign({}, options) : options;
507
- result.font = helpers.toFont(options.font, this.chart.options.font);
581
+ result.font = helpers.toFont(options.captions.font);
508
582
  return result;
509
583
  }
510
584
 
@@ -543,13 +617,11 @@ class TreemapController extends chart_js.DatasetController {
543
617
  for (let i = 0, ilen = metadata.length; i < ilen; ++i) {
544
618
  const rect = metadata[i];
545
619
  const item = data[i];
546
- if (rect.options.groupDividers && item._data.children.length > 1) {
620
+ const dividersOpts = rect.options.dividers || {};
621
+ if (dividersOpts.display && item._data.children.length > 1) {
547
622
  drawDivider(ctx, rect);
548
623
  }
549
624
  }
550
- if (this.getDataset().groupDividers) {
551
- drawDivider(ctx, this._rect);
552
- }
553
625
  }
554
626
 
555
627
  _drawRects(ctx, data, metadata, levels) {
@@ -559,7 +631,7 @@ class TreemapController extends chart_js.DatasetController {
559
631
  if (!rect.hidden) {
560
632
  rect.draw(ctx);
561
633
  const opts = rect.options;
562
- if (shouldDrawCaption(rect, opts.font) && item.g) {
634
+ if (shouldDrawCaption(rect, opts.captions.font)) {
563
635
  drawCaption(ctx, rect, item, opts, levels);
564
636
  }
565
637
  }
@@ -581,16 +653,25 @@ class TreemapController extends chart_js.DatasetController {
581
653
 
582
654
  TreemapController.id = 'treemap';
583
655
 
656
+ TreemapController.version = version;
657
+
584
658
  TreemapController.defaults = {
585
659
  dataElementType: 'treemap',
586
660
 
587
- groupLabels: true,
588
661
  borderWidth: 0,
589
662
  spacing: 0.5,
590
- groupDividers: false,
591
- dividerWidth: 1
663
+ dividers: {
664
+ display: false,
665
+ lineWidth: 1,
666
+ }
667
+
668
+ };
592
669
 
670
+ TreemapController.descriptors = {
671
+ _scriptable: true,
672
+ _indexable: false
593
673
  };
674
+
594
675
  TreemapController.overrides = {
595
676
  interaction: {
596
677
  mode: 'point',
@@ -632,6 +713,33 @@ TreemapController.overrides = {
632
713
  },
633
714
  };
634
715
 
716
+ TreemapController.beforeRegister = function() {
717
+ requireVersion('3.6', chart_js.Chart.version);
718
+ };
719
+
720
+ TreemapController.afterRegister = function() {
721
+ const tooltipPlugin = chart_js.registry.plugins.get('tooltip');
722
+ if (tooltipPlugin) {
723
+ tooltipPlugin.positioners.treemap = function(active) {
724
+ if (!active.length) {
725
+ return false;
726
+ }
727
+
728
+ const item = active[active.length - 1];
729
+ const el = item.element;
730
+
731
+ return el.tooltipPosition();
732
+ };
733
+ }
734
+ };
735
+
736
+ TreemapController.afterUnregister = function() {
737
+ const tooltipPlugin = chart_js.registry.plugins.get('tooltip');
738
+ if (tooltipPlugin) {
739
+ delete tooltipPlugin.positioners.treemap;
740
+ }
741
+ };
742
+
635
743
  /**
636
744
  * Helper function to get the bounds of the rect
637
745
  * @param {TreemapElement} rect the rect
@@ -733,7 +841,6 @@ class TreemapElement extends chart_js.Element {
733
841
  ctx.fillStyle = options.backgroundColor;
734
842
  ctx.fillRect(inner.x, inner.y, inner.w, inner.h);
735
843
  }
736
-
737
844
  ctx.restore();
738
845
  }
739
846
 
@@ -769,20 +876,40 @@ class TreemapElement extends chart_js.Element {
769
876
  TreemapElement.id = 'treemap';
770
877
 
771
878
  TreemapElement.defaults = {
772
- borderSkipped: undefined,
773
879
  borderWidth: undefined,
774
- color: undefined,
775
- dividerCapStyle: 'butt',
776
- dividerColor: 'black',
777
- dividerDash: undefined,
778
- dividerDashOffset: 0,
779
- dividerWidth: 0,
780
- font: {},
781
- groupDividers: false,
782
- groupLabels: undefined,
783
880
  spacing: undefined,
784
881
  label: undefined,
785
- rtl: undefined
882
+ rtl: undefined,
883
+ dividers: {
884
+ display: false,
885
+ lineCapStyle: 'butt',
886
+ lineColor: 'black',
887
+ lineDash: undefined,
888
+ lineDashOffset: 0,
889
+ lineWidth: 0,
890
+ },
891
+ captions: {
892
+ align: undefined,
893
+ color: undefined,
894
+ display: true,
895
+ formatter: (ctx) => ctx.raw.g || '',
896
+ font: {},
897
+ padding: 3
898
+ },
899
+ labels: {
900
+ align: 'center',
901
+ color: undefined,
902
+ display: false,
903
+ formatter: (ctx) => ctx.raw.g ? [ctx.raw.g, ctx.raw.v] : ctx.raw.v,
904
+ font: {},
905
+ position: 'middle',
906
+ padding: 3
907
+ }
908
+ };
909
+
910
+ TreemapElement.descriptors = {
911
+ _scriptable: true,
912
+ _indexable: false
786
913
  };
787
914
 
788
915
  TreemapElement.defaultRoutes = {
@@ -792,25 +919,14 @@ TreemapElement.defaultRoutes = {
792
919
 
793
920
  chart_js.Chart.register(TreemapController, TreemapElement);
794
921
 
795
- const tooltipPlugin = chart_js.Chart.registry.plugins.get('tooltip');
796
- tooltipPlugin.positioners.treemap = function(active) {
797
- if (!active.length) {
798
- return false;
799
- }
800
-
801
- const item = active[active.length - 1];
802
- const el = item.element;
803
-
804
- return el.tooltipPosition();
805
- };
806
-
807
922
  exports.flatten = flatten;
808
923
  exports.group = group;
809
924
  exports.index = index;
810
925
  exports.isObject = isObject;
926
+ exports.requireVersion = requireVersion;
811
927
  exports.sort = sort;
812
928
  exports.sum = sum;
813
929
 
814
930
  Object.defineProperty(exports, '__esModule', { value: true });
815
931
 
816
- })));
932
+ }));
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * chartjs-chart-treemap v1.0.0-beta.4
3
- * https://github.com/kurkle/chartjs-chart-treemap#readme
2
+ * chartjs-chart-treemap v1.0.3
3
+ * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2021 Jukka Kurkela
5
5
  * Released under the MIT license
6
6
  */
7
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-chart-treemap"]={},t.Chart,t.Chart.helpers)}(this,(function(t,e,n){"use strict";function i(t){const e=[...t],n=[];for(;e.length;){const t=e.pop();Array.isArray(t)?e.push(...t):n.push(t)}return n.reverse()}function r(t,e,n,i,r){const o=Object.create(null),s=Object.create(null),a=[];let h,l,u,d;for(l=0,u=t.length;l<u;++l)d=t[l],i&&d[i]!==r||(h=d[e]||"",h in o||(o[h]=0,s[h]=[]),o[h]+=+d[n],s[h].push(d));return Object.keys(o).forEach((t=>{d={children:s[t]},d[n]=+o[t],d[e]=t,i&&(d[i]=r),a.push(d)})),a}function o(t){const e=typeof t;return"function"===e||"object"===e&&!!t}function s(t,e){let n,i=t.length;if(!i)return e;const r=o(t[0]);for(e=r?e:"v",n=0,i=t.length;n<i;++n)r?t[n]._idx=n:t[n]={v:t[n],_idx:n};return e}function a(t,e){e?t.sort(((t,n)=>+n[e]-+t[e])):t.sort(((t,e)=>+e-+t))}function h(t,e){let n,i,r;for(n=0,i=0,r=t.length;i<r;++i)n+=e?+t[i][e]:+t[i];return n}function l(t,e){return+(Math.round(t+"e+"+e)+"e-"+e)||0}function u(t,e,n,i){const r=t._normalized,o=e*r/n,s=Math.sqrt(r*o),a=r/s;return{d1:s,d2:a,w:"_ix"===i?s:a,h:"_ix"===i?a:s}}const d=(t,e)=>l(t.rtl?t.x+t.w-t._ix-e:t.x+t._ix,4);function c(t,e,n,i){const r={x:d(t,n.w),y:l(t.y+t._iy,4),w:l(n.w,4),h:l(n.h,4),a:l(e._normalized,4),v:e.value,s:i,_data:e._data};return e.group&&(r.g=e.group,r.l=e.level,r.gs=e.groupSum),r}class g{constructor(t){const e=this;t=t||{w:1,h:1},e.rtl=!!t.rtl,e.x=t.x||t.left||0,e.y=t.y||t.top||0,e._ix=0,e._iy=0,e.w=t.w||t.width||t.right-t.left,e.h=t.h||t.height||t.bottom-t.top}get area(){return this.w*this.h}get iw(){return this.w-this._ix}get ih(){return this.h-this._iy}get dir(){const t=this.ih;return t<=this.iw&&t>0?"y":"x"}get side(){return"x"===this.dir?this.iw:this.ih}map(t){const e=this,n=[],i=t.nsum,r=t.get(),o=e.dir,s=e.side,a=s*s,h="x"===o?"_ix":"_iy",l=i*i;let d=0,g=0;for(const i of r){const r=u(i,a,l,h);g+=r.d1,d=Math.max(d,r.d2),n.push(c(e,i,r,t.sum)),e[h]+=r.d1}return e["y"===o?"_ix":"_iy"]+=d,e[h]-=g,n}}const p=Math.min,f=Math.max;function m(t,e){const n=+e[t.key],i=n*t.ratio;return e._normalized=i,{min:p(t.min,n),max:f(t.max,n),sum:t.sum+n,nmin:p(t.nmin,i),nmax:f(t.nmax,i),nsum:t.nsum+i}}function x(t,e,n){t._arr.push(e),function(t,e){Object.assign(t,e)}(t,n)}class y{constructor(t,e){const n=this;n.key=t,n.ratio=e,n.reset()}get length(){return this._arr.length}reset(){const t=this;t._arr=[],t._hist=[],t.sum=0,t.nsum=0,t.min=1/0,t.max=-1/0,t.nmin=1/0,t.nmax=-1/0}push(t){x(this,t,m(this,t))}pushIf(t,e,...n){const i=m(this,t);if(!e((r=this,{min:r.min,max:r.max,sum:r.sum,nmin:r.nmin,nmax:r.nmax,nsum:r.nsum}),i,n))return t;var r;x(this,t,i)}get(){return this._arr}}function v(t,e,n){if(0===t.sum)return!0;const[i]=n,r=t.nsum*t.nsum,o=e.nsum*e.nsum,s=i*i,a=Math.max(s*t.nmax/r,r/(s*t.nmin));return Math.max(s*e.nmax/o,o/(s*e.nmin))<=a}function b(t,e,n,r,o,l){t=t||[];const u=[],d=new g(e),c=new y("value",d.area/h(t,n));let p=d.side;const f=t.length;let m,x;if(!f)return u;const b=t.slice();n=s(b,n),a(b,n);const w=t=>r&&b[t][r];for(m=0;m<f;++m)x={value:(_=m,n?+b[_][n]:+b[_]),groupSum:l,_data:t[b[m]._idx]},r&&(x.level=o,x.group=w(m)),x=c.pushIf(x,v,p),x&&(u.push(d.map(c)),p=d.side,c.reset(),c.push(x));var _;return c.length&&u.push(d.map(c)),i(u)}function w(t,e){if(!e)return!1;const n=t.width||t.w,i=t.height||t.h,r=2*e.lineHeight;return n>r&&i>r}function _(t,e,n,i,r){if(t.save(),t.fillStyle=i.color,t.font=i.font.string,t.beginPath(),t.rect(e.x,e.y,e.width,e.height),t.clip(),"l"in n&&n.l!==r){if(i.groupLabels){t.textAlign=i.rtl?"end":"start",t.textBaseline="top";const r=i.rtl?e.x+e.width-i.borderWidth-3:e.x+i.borderWidth+3;t.fillText(n.g,r,e.y+i.borderWidth+3)}}else t.textAlign="center",t.textBaseline="middle",function(t,e,n){const i=n.options,r=i.font.lineHeight,o=(i.label||e.g+"\n"+e.v).split("\n"),s=n.y+n.height/2-o.length*r/4;o.forEach(((e,i)=>t.fillText(e,n.x+n.width/2,s+i*r)))}(t,n,e);t.restore()}function D(t,e){const n=e.options,i=e.width||e.w,r=e.height||e.h;if(t.save(),t.strokeStyle=n.dividerColor||"black",t.lineCap=n.dividerCapStyle,t.setLineDash(n.dividerDash||[]),t.lineDashOffset=n.dividerDashOffset,t.lineWidth=n.dividerWidth,t.beginPath(),i>r){const n=i/2;t.moveTo(e.x+n,e.y),t.lineTo(e.x+n,e.y+r)}else{const n=r/2;t.moveTo(e.x,e.y+n),t.lineTo(e.x+i,e.y+n)}t.stroke(),t.restore()}class O extends e.DatasetController{initialize(){this.enableOptionSharing=!0,super.initialize()}update(t){const e=this,i=e.getMeta(),o=e.getDataset(),s=o.groups||(o.groups=[]),a=n.toFont(o.font,e.chart.options.font),h=e.chart.chartArea,l=o.key||"",u=!!o.rtl,d={x:h.left,y:h.top,w:h.right-h.left,h:h.bottom-h.top,rtl:u};var c,g;"reset"!==t&&(c=e._rect,g=d,c&&g&&c.x===g.x&&c.y===g.y&&c.w===g.w&&c.h===g.h)&&e._key===l&&!function(t,e){let n,i;if(t.lenght!==e.length)return!0;for(n=0,i=t.length;n<i;++n)if(t[n]!==e[n])return!0;return!1}(e._groups,s)||(e._rect=d,e._groups=s.slice(),e._key=l,o.data=function(t,e,i){const o=t.key||"";let s=t.tree||[];const a=t.groups||[],h=a.length,l=(t.spacing||0)+(t.borderWidth||0);return!s.length&&t.data.length&&(s=t.tree=t.data),h?function e(u,d,c,g){const p=a[u],f=u>0&&a[u-1],m=b(r(s,p,o,f,c),d,o,p,u,g),x=m.slice();let y;return u<h-1&&m.forEach((r=>{y={x:r.x+l,y:r.y+l,w:r.w-2*l,h:r.h-2*l},n.valueOrDefault(t.groupLabels,!0)&&w(r,i)&&(y.y+=i.lineHeight,y.h-=i.lineHeight),x.push(...e(u+1,y,r.g,r.s))})),x}(0,e):b(s,e,o)}(o,d,a),e._dataCheck(),e._resyncElements()),e.updateElements(i.data,0,i.data.length,t)}resolveDataElementOptions(t,e){const i=super.resolveDataElementOptions(t,e),r=Object.isFrozen(i)?Object.assign({},i):i;return r.font=n.toFont(i.font,this.chart.options.font),r}updateElements(t,e,n,i){const r=this,o="reset"===i,s=r.getDataset(),a=r._rect.options=r.resolveDataElementOptions(e,i),h=r.getSharedOptions(a),l=r.includeOptions(i,h);for(let a=e;a<e+n;a++){const e=s.data[a],n=h||r.resolveDataElementOptions(a,i),u=o?0:e.h-2*n.spacing,d=o?0:e.w-2*n.spacing,c={x:e.x+n.spacing,y:e.y+n.spacing,width:d,height:u};l&&(c.options=n),r.updateElement(t[a],a,c,i)}r.updateSharedOptions(h,i,a)}_drawDividers(t,e,n){for(let i=0,r=n.length;i<r;++i){const r=n[i],o=e[i];r.options.groupDividers&&o._data.children.length>1&&D(t,r)}this.getDataset().groupDividers&&D(t,this._rect)}_drawRects(t,e,n,i){for(let r=0,o=n.length;r<o;++r){const o=n[r],s=e[r];if(!o.hidden){o.draw(t);const e=o.options;w(o,e.font)&&s.g&&_(t,o,s,e,i)}}}draw(){const t=this,e=t.chart.ctx,n=t.getMeta().data||[],i=t.getDataset(),r=(i.groups||[]).length-1,o=i.data||[];t._drawRects(e,o,n,r),t._drawDividers(e,o,n)}}function C(t,e){const{x:n,y:i,width:r,height:o}=t.getProps(["x","y","width","height"],e);return{left:n,top:i,right:n+r,bottom:i+o}}function k(t,e,n){return Math.max(Math.min(t,n),e)}function j(t){const e=C(t),n=e.right-e.left,i=e.bottom-e.top,r=function(t,e,n){let i,r,s,a;return o(t)?(i=+t.top||0,r=+t.right||0,s=+t.bottom||0,a=+t.left||0):i=r=s=a=+t||0,{t:k(i,0,n),r:k(r,0,e),b:k(s,0,n),l:k(a,0,e)}}(t.options.borderWidth,n/2,i/2);return{outer:{x:e.left,y:e.top,w:n,h:i},inner:{x:e.left+r.l,y:e.top+r.t,w:n-r.l-r.r,h:i-r.t-r.b}}}function E(t,e,n,i){const r=null===e,o=null===n,s=!(!t||r&&o)&&C(t,i);return s&&(r||e>=s.left&&e<=s.right)&&(o||n>=s.top&&n<=s.bottom)}O.id="treemap",O.defaults={dataElementType:"treemap",groupLabels:!0,borderWidth:0,spacing:.5,groupDividers:!1,dividerWidth:1},O.overrides={interaction:{mode:"point",intersect:!0},hover:{},plugins:{tooltip:{position:"treemap",intersect:!0,callbacks:{title(t){if(t.length){return t[0].dataset.key||""}return""},label(t){const e=t.dataset,n=e.data[t.dataIndex],i=n.g||e.label;return(i?i+": ":"")+n.v}}}},scales:{x:{type:"linear",display:!1},y:{type:"linear",display:!1}}};class S extends e.Element{constructor(t){super(),this.options=void 0,this.width=void 0,this.height=void 0,t&&Object.assign(this,t)}draw(t){const e=this.options,{inner:n,outer:i}=j(this);t.save(),i.w!==n.w||i.h!==n.h?(t.beginPath(),t.rect(i.x,i.y,i.w,i.h),t.clip(),t.rect(n.x,n.y,n.w,n.h),t.fillStyle=e.backgroundColor,t.fill(),t.fillStyle=e.borderColor,t.fill("evenodd")):(t.fillStyle=e.backgroundColor,t.fillRect(n.x,n.y,n.w,n.h)),t.restore()}inRange(t,e,n){return E(this,t,e,n)}inXRange(t,e){return E(this,t,null,e)}inYRange(t,e){return E(this,null,t,e)}getCenterPoint(t){const{x:e,y:n,width:i,height:r}=this.getProps(["x","y","width","height"],t);return{x:e+i/2,y:n+r/2}}tooltipPosition(){return this.getCenterPoint()}getRange(t){return"x"===t?this.width/2:this.height/2}}S.id="treemap",S.defaults={borderSkipped:void 0,borderWidth:void 0,color:void 0,dividerCapStyle:"butt",dividerColor:"black",dividerDash:void 0,dividerDashOffset:0,dividerWidth:0,font:{},groupDividers:!1,groupLabels:void 0,spacing:void 0,label:void 0,rtl:void 0},S.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"},e.Chart.register(O,S);e.Chart.registry.plugins.get("tooltip").positioners.treemap=function(t){if(!t.length)return!1;return t[t.length-1].element.tooltipPosition()},t.flatten=i,t.group=r,t.index=s,t.isObject=o,t.sort=a,t.sum=h,Object.defineProperty(t,"__esModule",{value:!0})}));
7
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-chart-treemap"]={},t.Chart,t.Chart.helpers)}(this,(function(t,e,n){"use strict";function i(t){const e=[...t],n=[];for(;e.length;){const t=e.pop();Array.isArray(t)?e.push(...t):n.push(t)}return n.reverse()}function r(t,e,n,i,r){const o=Object.create(null),s=Object.create(null),a=[];let l,h,u,c;for(h=0,u=t.length;h<u;++h)c=t[h],i&&c[i]!==r||(l=c[e]||"",l in o||(o[l]=0,s[l]=[]),o[l]+=+c[n],s[l].push(c));return Object.keys(o).forEach((t=>{c={children:s[t]},c[n]=+o[t],c[e]=t,i&&(c[i]=r),a.push(c)})),a}function o(t){const e=typeof t;return"function"===e||"object"===e&&!!t}function s(t,e){let n,i=t.length;if(!i)return e;const r=o(t[0]);for(e=r?e:"v",n=0,i=t.length;n<i;++n)r?t[n]._idx=n:t[n]={v:t[n],_idx:n};return e}function a(t,e){e?t.sort(((t,n)=>+n[e]-+t[e])):t.sort(((t,e)=>+e-+t))}function l(t,e){let n,i,r;for(n=0,i=0,r=t.length;i<r;++i)n+=e?+t[i][e]:+t[i];return n}function h(t,e){const n=e.split(".");if(!t.split(".").reduce(((t,e,i)=>t&&e<=n[i]),!0))throw new Error(`Chart.js v${e} is not supported. v${t} or newer is required.`)}function u(t,e){return+(Math.round(t+"e+"+e)+"e-"+e)||0}function c(t,e,n,i){const r=t._normalized,o=e*r/n,s=Math.sqrt(r*o),a=r/s;return{d1:s,d2:a,w:"_ix"===i?s:a,h:"_ix"===i?a:s}}const d=(t,e)=>u(t.rtl?t.x+t.w-t._ix-e:t.x+t._ix,4);function p(t,e,n,i){const r={x:d(t,n.w),y:u(t.y+t._iy,4),w:u(n.w,4),h:u(n.h,4),a:u(e._normalized,4),v:e.value,s:i,_data:e._data};return e.group&&(r.g=e.group,r.l=e.level,r.gs=e.groupSum),r}class g{constructor(t){const e=this;t=t||{w:1,h:1},e.rtl=!!t.rtl,e.x=t.x||t.left||0,e.y=t.y||t.top||0,e._ix=0,e._iy=0,e.w=t.w||t.width||t.right-t.left,e.h=t.h||t.height||t.bottom-t.top}get area(){return this.w*this.h}get iw(){return this.w-this._ix}get ih(){return this.h-this._iy}get dir(){const t=this.ih;return t<=this.iw&&t>0?"y":"x"}get side(){return"x"===this.dir?this.iw:this.ih}map(t){const e=this,n=[],i=t.nsum,r=t.get(),o=e.dir,s=e.side,a=s*s,l="x"===o?"_ix":"_iy",h=i*i;let u=0,d=0;for(const i of r){const r=c(i,a,h,l);d+=r.d1,u=Math.max(u,r.d2),n.push(p(e,i,r,t.sum)),e[l]+=r.d1}return e["y"===o?"_ix":"_iy"]+=u,e[l]-=d,n}}const f=Math.min,m=Math.max;function y(t,e){const n=+e[t.key],i=n*t.ratio;return e._normalized=i,{min:f(t.min,n),max:m(t.max,n),sum:t.sum+n,nmin:f(t.nmin,i),nmax:m(t.nmax,i),nsum:t.nsum+i}}function x(t,e,n){t._arr.push(e),function(t,e){Object.assign(t,e)}(t,n)}class v{constructor(t,e){const n=this;n.key=t,n.ratio=e,n.reset()}get length(){return this._arr.length}reset(){const t=this;t._arr=[],t._hist=[],t.sum=0,t.nsum=0,t.min=1/0,t.max=-1/0,t.nmin=1/0,t.nmax=-1/0}push(t){x(this,t,y(this,t))}pushIf(t,e,...n){const i=y(this,t);if(!e((r=this,{min:r.min,max:r.max,sum:r.sum,nmin:r.nmin,nmax:r.nmax,nsum:r.nsum}),i,n))return t;var r;x(this,t,i)}get(){return this._arr}}function w(t,e,n){if(0===t.sum)return!0;const[i]=n,r=t.nsum*t.nsum,o=e.nsum*e.nsum,s=i*i,a=Math.max(s*t.nmax/r,r/(s*t.nmin));return Math.max(s*e.nmax/o,o/(s*e.nmin))<=a}function b(t,e,n,r,o,h){t=t||[];const u=[],c=new g(e),d=new v("value",c.area/l(t,n));let p=c.side;const f=t.length;let m,y;if(!f)return u;const x=t.slice();n=s(x,n),a(x,n);const b=t=>r&&x[t][r];for(m=0;m<f;++m)y={value:(_=m,n?+x[_][n]:+x[_]),groupSum:h,_data:t[x[m]._idx],level:void 0,group:void 0},r&&(y.level=o,y.group=b(m)),y=d.pushIf(y,w,p),y&&(u.push(c.map(d)),p=c.side,d.reset(),d.push(y));var _;return d.length&&u.push(c.map(d)),i(u)}function _(t,e){if(!e)return!1;const n=t.width||t.w,i=t.height||t.h,r=2*e.lineHeight;return n>r&&i>r}function O(t,e,i,r,o){t.save(),t.beginPath(),t.rect(e.x,e.y,e.width,e.height),t.clip(),"l"in i&&i.l!==o?r.captions&&r.captions.display&&function(t,e,i){const r=i.options,o=r.captions||{},s=r.borderWidth||0,a=n.valueOrDefault(r.spacing,0)+s,l=(i.active?o.hoverColor:o.color)||o.color,h=o.padding,u=o.align||(r.rtl?"right":"left"),c=(i.active?o.hoverFont:o.font)||o.font,d=n.toFont(c),p=D(i,u,h,s);t.fillStyle=l,t.font=d.string,t.textAlign=u,t.textBaseline="middle",t.fillText(o.formatter||e.g,p,i.y+h+a+d.lineHeight/2)}(t,i,e):function(t,e,i){const r=i.options,o=r.labels;if(!o||!o.display)return;const s=(i.active?o.hoverColor:o.color)||o.color,a=(i.active?o.hoverFont:o.font)||o.font,l=n.toFont(a),h=l.lineHeight,u=o.formatter;if(u){const e=n.isArray(u)?u:[u],a=function(t,e,n,i){const r=t.labels,o=t.borderWidth||0,{align:s,position:a,padding:l}=r;let h,u;h=D(e,s,l,o),u="top"===a?e.y+l+o:"bottom"===a?e.y+e.height-l-o-(n.length-1)*i:e.y+e.height/2-n.length*i/4;return{x:h,y:u}}(r,i,e,h);t.font=l.string,t.textAlign=o.align,t.textBaseline=o.position,t.fillStyle=s,e.forEach(((e,n)=>t.fillText(e,a.x,a.y+n*h)))}}(t,0,e),t.restore()}function C(t,e){const n=e.options.dividers||{},i=e.width||e.w,r=e.height||e.h;if(t.save(),t.strokeStyle=n.lineColor||"black",t.lineCap=n.lineCapStyle,t.setLineDash(n.lineDash||[]),t.lineDashOffset=n.lineDashOffset,t.lineWidth=n.lineWidth,t.beginPath(),i>r){const n=i/2;t.moveTo(e.x+n,e.y),t.lineTo(e.x+n,e.y+r)}else{const n=r/2;t.moveTo(e.x,e.y+n),t.lineTo(e.x+i,e.y+n)}t.stroke(),t.restore()}function D(t,e,n,i){return"left"===e?t.x+n+i:"right"===e?t.x+t.width-n-i:t.x+t.width/2}class k extends e.DatasetController{constructor(t,e){super(t,e),this._rect=void 0,this._key=void 0,this._groups=void 0}initialize(){this.enableOptionSharing=!0,super.initialize()}update(t){const e=this,i=e.getMeta(),o=e.getDataset(),s=o.groups||(o.groups=[]),a=o.captions?o.captions:{},l=e.chart.chartArea,h=o.key||"",u=!!o.rtl,c={x:l.left,y:l.top,w:l.right-l.left,h:l.bottom-l.top,rtl:u};var d,p;"reset"!==t&&(d=e._rect,p=c,d&&p&&d.x===p.x&&d.y===p.y&&d.w===p.w&&d.h===p.h)&&e._key===h&&!function(t,e){let n,i;if(t.lenght!==e.length)return!0;for(n=0,i=t.length;n<i;++n)if(t[n]!==e[n])return!0;return!1}(e._groups,s)||(e._rect=c,e._groups=s.slice(),e._key=h,o.data=function(t,e,i){const o=t.key||"";let s=t.tree||[];const a=t.groups||[],l=a.length,h=n.valueOrDefault(t.spacing,0)+n.valueOrDefault(t.borderWidth,0),u=i.font||{},c=n.toFont(u),d=n.valueOrDefault(i.padding,3);return!s.length&&t.data.length&&(s=t.tree=t.data),l?function t(e,u,p,g){const f=a[e],m=e>0&&a[e-1],y=b(r(s,f,o,m,p),u,o,f,e,g),x=y.slice();let v;return e<l-1&&y.forEach((r=>{v={x:r.x+h,y:r.y+h,w:r.w-2*h,h:r.h-2*h},n.valueOrDefault(i.display,!0)&&_(r,c)&&(v.y+=c.lineHeight+2*d,v.h-=c.lineHeight+2*d),x.push(...t(e+1,v,r.g,r.s))})),x}(0,e):b(s,e,o)}(o,c,a),e._dataCheck(),e._resyncElements()),e.updateElements(i.data,0,i.data.length,t)}resolveDataElementOptions(t,e){const i=super.resolveDataElementOptions(t,e),r=Object.isFrozen(i)?Object.assign({},i):i;return r.font=n.toFont(i.captions.font),r}updateElements(t,e,n,i){const r=this,o="reset"===i,s=r.getDataset(),a=r._rect.options=r.resolveDataElementOptions(e,i),l=r.getSharedOptions(a),h=r.includeOptions(i,l);for(let a=e;a<e+n;a++){const e=s.data[a],n=l||r.resolveDataElementOptions(a,i),u=o?0:e.h-2*n.spacing,c=o?0:e.w-2*n.spacing,d={x:e.x+n.spacing,y:e.y+n.spacing,width:c,height:u};h&&(d.options=n),r.updateElement(t[a],a,d,i)}r.updateSharedOptions(l,i,a)}_drawDividers(t,e,n){for(let i=0,r=n.length;i<r;++i){const r=n[i],o=e[i];(r.options.dividers||{}).display&&o._data.children.length>1&&C(t,r)}}_drawRects(t,e,n,i){for(let r=0,o=n.length;r<o;++r){const o=n[r],s=e[r];if(!o.hidden){o.draw(t);const e=o.options;_(o,e.captions.font)&&O(t,o,s,e,i)}}}draw(){const t=this,e=t.chart.ctx,n=t.getMeta().data||[],i=t.getDataset(),r=(i.groups||[]).length-1,o=i.data||[];t._drawRects(e,o,n,r),t._drawDividers(e,o,n)}}function j(t,e){const{x:n,y:i,width:r,height:o}=t.getProps(["x","y","width","height"],e);return{left:n,top:i,right:n+r,bottom:i+o}}function E(t,e,n){return Math.max(Math.min(t,n),e)}function S(t){const e=j(t),n=e.right-e.left,i=e.bottom-e.top,r=function(t,e,n){let i,r,s,a;return o(t)?(i=+t.top||0,r=+t.right||0,s=+t.bottom||0,a=+t.left||0):i=r=s=a=+t||0,{t:E(i,0,n),r:E(r,0,e),b:E(s,0,n),l:E(a,0,e)}}(t.options.borderWidth,n/2,i/2);return{outer:{x:e.left,y:e.top,w:n,h:i},inner:{x:e.left+r.l,y:e.top+r.t,w:n-r.l-r.r,h:i-r.t-r.b}}}function M(t,e,n,i){const r=null===e,o=null===n,s=!(!t||r&&o)&&j(t,i);return s&&(r||e>=s.left&&e<=s.right)&&(o||n>=s.top&&n<=s.bottom)}k.id="treemap",k.version="1.0.3",k.defaults={dataElementType:"treemap",borderWidth:0,spacing:.5,dividers:{display:!1,lineWidth:1}},k.descriptors={_scriptable:!0,_indexable:!1},k.overrides={interaction:{mode:"point",intersect:!0},hover:{},plugins:{tooltip:{position:"treemap",intersect:!0,callbacks:{title(t){if(t.length){return t[0].dataset.key||""}return""},label(t){const e=t.dataset,n=e.data[t.dataIndex],i=n.g||e.label;return(i?i+": ":"")+n.v}}}},scales:{x:{type:"linear",display:!1},y:{type:"linear",display:!1}}},k.beforeRegister=function(){h("3.6",e.Chart.version)},k.afterRegister=function(){const t=e.registry.plugins.get("tooltip");t&&(t.positioners.treemap=function(t){if(!t.length)return!1;return t[t.length-1].element.tooltipPosition()})},k.afterUnregister=function(){const t=e.registry.plugins.get("tooltip");t&&delete t.positioners.treemap};class P extends e.Element{constructor(t){super(),this.options=void 0,this.width=void 0,this.height=void 0,t&&Object.assign(this,t)}draw(t){const e=this.options,{inner:n,outer:i}=S(this);t.save(),i.w!==n.w||i.h!==n.h?(t.beginPath(),t.rect(i.x,i.y,i.w,i.h),t.clip(),t.rect(n.x,n.y,n.w,n.h),t.fillStyle=e.backgroundColor,t.fill(),t.fillStyle=e.borderColor,t.fill("evenodd")):(t.fillStyle=e.backgroundColor,t.fillRect(n.x,n.y,n.w,n.h)),t.restore()}inRange(t,e,n){return M(this,t,e,n)}inXRange(t,e){return M(this,t,null,e)}inYRange(t,e){return M(this,null,t,e)}getCenterPoint(t){const{x:e,y:n,width:i,height:r}=this.getProps(["x","y","width","height"],t);return{x:e+i/2,y:n+r/2}}tooltipPosition(){return this.getCenterPoint()}getRange(t){return"x"===t?this.width/2:this.height/2}}P.id="treemap",P.defaults={borderWidth:void 0,spacing:void 0,label:void 0,rtl:void 0,dividers:{display:!1,lineCapStyle:"butt",lineColor:"black",lineDash:void 0,lineDashOffset:0,lineWidth:0},captions:{align:void 0,color:void 0,display:!0,formatter:t=>t.raw.g||"",font:{},padding:3},labels:{align:"center",color:void 0,display:!1,formatter:t=>t.raw.g?[t.raw.g,t.raw.v]:t.raw.v,font:{},position:"middle",padding:3}},P.descriptors={_scriptable:!0,_indexable:!1},P.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"},e.Chart.register(k,P),t.flatten=i,t.group=r,t.index=s,t.isObject=o,t.requireVersion=h,t.sort=a,t.sum=l,Object.defineProperty(t,"__esModule",{value:!0})}));
package/package.json CHANGED
@@ -1,15 +1,21 @@
1
1
  {
2
2
  "name": "chartjs-chart-treemap",
3
- "version": "1.0.0-beta.4",
3
+ "homepage": "https://chartjs-chart-treemap.pages.dev/",
4
+ "version": "1.0.3",
4
5
  "description": "Chart.js module for creating treemap charts",
5
6
  "main": "dist/chartjs-chart-treemap.js",
6
7
  "module": "dist/chartjs-chart-treemap.esm.js",
8
+ "types": "types/index.esm.d.ts",
7
9
  "scripts": {
8
10
  "autobuild": "rollup -c -w",
9
11
  "build": "rollup -c",
10
12
  "dev": "karma start --no-signle-run --auto-watch --browsers chrome",
11
- "lint": "eslint --ignore-path .gitignore .",
12
- "lint-fix": "eslint --ignore-path .gitignore --fix .",
13
+ "docs": "npm run build && vuepress build docs --no-cache",
14
+ "docs:dev": "npm run build && vuepress dev docs --no-cache",
15
+ "lint": "concurrently -r \"npm:lint-*\"",
16
+ "lint-js": "eslint \"src/**/*.js\" \"test/**/*.js\" \"docs/**/*.js\"",
17
+ "lint-md": "eslint \"**/*.md\"",
18
+ "lint-types": "eslint \"types/**/*.ts\" && tsc -p types/tests/",
13
19
  "test": "cross-env NODE_ENV=test concurrently \"npm:test-*\"",
14
20
  "test-lint": "npm run lint",
15
21
  "test-karma": "karma start --auto-watch --single-run"
@@ -24,29 +30,33 @@
24
30
  "treemap"
25
31
  ],
26
32
  "files": [
27
- "dist/*.js"
33
+ "dist/*.js",
34
+ "types/index.esm.d.ts"
28
35
  ],
29
36
  "author": "Jukka Kurkela",
30
37
  "license": "MIT",
31
38
  "bugs": {
32
39
  "url": "https://github.com/kurkle/chartjs-chart-treemap/issues"
33
40
  },
34
- "homepage": "https://github.com/kurkle/chartjs-chart-treemap#readme",
35
41
  "devDependencies": {
36
- "@rollup/plugin-commonjs": "^17.1.0",
37
- "@rollup/plugin-node-resolve": "^11.2.0",
38
- "chart.js": "^3.0.0-rc.2",
39
- "chartjs-adapter-date-fns": "^1.1.0-beta.1",
40
- "chartjs-test-utils": "^0.2.2",
41
- "concurrently": "^6.0.0",
42
+ "@rollup/plugin-commonjs": "^19.0.0",
43
+ "@rollup/plugin-json": "^4.1.0",
44
+ "@rollup/plugin-node-resolve": "^13.0.0",
45
+ "@typescript-eslint/eslint-plugin": "^4.22.0",
46
+ "@typescript-eslint/parser": "^4.22.0",
47
+ "chart.js": "^3.6.0",
48
+ "chartjs-adapter-date-fns": "^2.0.0",
49
+ "chartjs-test-utils": "^0.3.0",
50
+ "concurrently": "^6.0.1",
42
51
  "cross-env": "^7.0.3",
43
- "date-fns": "^2.19.0",
44
- "eslint": "^7.22.0",
52
+ "date-fns": "^2.20.2",
53
+ "eslint": "^7.24.0",
45
54
  "eslint-config-chartjs": "^0.3.0",
46
55
  "eslint-plugin-es": "^4.1.0",
47
56
  "eslint-plugin-html": "^6.1.2",
57
+ "eslint-plugin-markdown": "^2.0.1",
48
58
  "jasmine-core": "^3.7.1",
49
- "karma": "^6.2.0",
59
+ "karma": "^6.3.2",
50
60
  "karma-chrome-launcher": "^3.1.0",
51
61
  "karma-coverage": "^2.0.3",
52
62
  "karma-firefox-launcher": "^2.1.0",
@@ -56,12 +66,17 @@
56
66
  "karma-spec-reporter": "0.0.32",
57
67
  "karma-summary-reporter": "^2.0.2",
58
68
  "pixelmatch": "^5.2.1",
59
- "rollup": "^2.42.1",
69
+ "rollup": "^2.45.1",
70
+ "rollup-plugin-analyzer": "^4.0.0",
60
71
  "rollup-plugin-istanbul": "^3.0.0",
61
- "rollup-plugin-terser": "^7.0.2"
72
+ "rollup-plugin-terser": "^7.0.2",
73
+ "typescript": "^4.3.5",
74
+ "vuepress": "^1.8.2",
75
+ "vuepress-plugin-flexsearch": "^0.2.0",
76
+ "vuepress-plugin-redirect": "^1.2.5",
77
+ "vuepress-theme-chartjs": "^0.2.0"
62
78
  },
63
79
  "peerDependencies": {
64
- "chart.js": "^3.0.0-beta.10"
65
- },
66
- "dependencies": {}
80
+ "chart.js": "^3.0.0"
81
+ }
67
82
  }
@@ -0,0 +1,143 @@
1
+ import {
2
+ Chart,
3
+ ChartComponent,
4
+ DatasetController,
5
+ Element,
6
+ ScriptableContext, Color, Scriptable, FontSpec
7
+ } from 'chart.js';
8
+
9
+ type TreemapScriptableContext = ScriptableContext<'treemap'> & {
10
+ raw: TreemapDataPoint
11
+ }
12
+
13
+ type TreemapControllerDatasetCaptionsOptions = {
14
+ align?: Scriptable<LabelAlign, TreemapScriptableContext>,
15
+ color?: Scriptable<Color, TreemapScriptableContext>,
16
+ display?: boolean;
17
+ formatter?: Scriptable<string, TreemapScriptableContext>,
18
+ font?: FontSpec,
19
+ hoverColor?: Scriptable<Color, TreemapScriptableContext>,
20
+ hoverFont?: FontSpec,
21
+ padding?: number,
22
+ }
23
+
24
+ type TreemapControllerDatasetLabelsOptions = {
25
+ align?: Scriptable<LabelAlign, TreemapScriptableContext>,
26
+ color?: Scriptable<Color, TreemapScriptableContext>,
27
+ display?: boolean;
28
+ formatter?: Scriptable<string | Array<string>, TreemapScriptableContext>,
29
+ font?: FontSpec,
30
+ hoverColor?: Scriptable<Color, TreemapScriptableContext>,
31
+ hoverFont?: FontSpec,
32
+ padding?: number,
33
+ position?: Scriptable<LabelPosition, TreemapScriptableContext>
34
+ }
35
+
36
+ export type LabelPosition = 'top' | 'middle' | 'bottom';
37
+
38
+ export type LabelAlign = 'left' | 'center' | 'right';
39
+
40
+ type TreemapControllerDatasetDividersOptions = {
41
+ display?: boolean,
42
+ lineCapStyle?: string,
43
+ lineColor?: string,
44
+ lineDash?: number[],
45
+ lineDashOffset?: number,
46
+ lineWidth?: number,
47
+ }
48
+
49
+ export interface TreemapControllerDatasetOptions<DType> {
50
+ spacing?: number,
51
+ rtl?: boolean,
52
+
53
+ backgroundColor?: Scriptable<Color, TreemapScriptableContext>;
54
+ borderColor?: Scriptable<Color, TreemapScriptableContext>;
55
+ borderWidth?: number;
56
+
57
+ hoverBackgroundColor?: Scriptable<Color, TreemapScriptableContext>;
58
+ hoverBorderColor?: Scriptable<Color, TreemapScriptableContext>;
59
+ hoverBorderWidth?: number;
60
+
61
+ captions?: TreemapControllerDatasetCaptionsOptions;
62
+ dividers?: TreemapControllerDatasetDividersOptions;
63
+ labels?: TreemapControllerDatasetLabelsOptions;
64
+ label?: string;
65
+
66
+ data: TreemapDataPoint[]; // This will be auto-generated from `tree`
67
+ groups?: Array<keyof DType>;
68
+ tree: number[] | DType[];
69
+ key?: keyof DType;
70
+ }
71
+
72
+ export interface TreemapDataPoint {
73
+ x: number,
74
+ y: number,
75
+ w: number,
76
+ h: number,
77
+ /**
78
+ * Value
79
+ */
80
+ v: number,
81
+ /**
82
+ * Sum
83
+ */
84
+ s: number,
85
+ /**
86
+ * Depth, only available if grouping
87
+ */
88
+ l?: number,
89
+ /**
90
+ * Group name, only available if grouping
91
+ */
92
+ g?: string,
93
+ /**
94
+ * Group Sum, only available if grouping
95
+ */
96
+ gs?: number,
97
+ }
98
+
99
+ /*
100
+ export interface TreemapInteractionOptions {
101
+ position: Scriptable<"treemap", ScriptableTooltipContext<"treemap">>
102
+ }*/
103
+
104
+ declare module 'chart.js' {
105
+ export interface ChartTypeRegistry {
106
+ treemap: {
107
+ chartOptions: CoreChartOptions<'treemap'>;
108
+ datasetOptions: TreemapControllerDatasetOptions<Record<string, unknown>>;
109
+ defaultDataPoint: TreemapDataPoint;
110
+ metaExtensions: {};
111
+ parsedDataType: unknown,
112
+ scales: never;
113
+ }
114
+ }
115
+
116
+ // interface TooltipOptions<TType extends ChartType> extends CoreInteractionOptions, TreemapInteractionOptions {
117
+ // }
118
+ }
119
+
120
+ type TreemapOptions = {
121
+ backgroundColor: Color;
122
+ borderColor: Color;
123
+ borderWidth: number | { top?: number, right?: number, bottom?: number, left?: number }
124
+ }
125
+
126
+ type TreemapConfig = {
127
+ x: number;
128
+ y: number;
129
+ width: number;
130
+ height: number;
131
+ }
132
+
133
+ export type TreemapController = DatasetController;
134
+ export const TreemapController: ChartComponent & {
135
+ prototype: TreemapController;
136
+ new(chart: Chart, datasetIndex: number): TreemapController
137
+ };
138
+
139
+ export type TreemapElement = Element<TreemapConfig, TreemapOptions>;
140
+ export const TreemapElement: ChartComponent & {
141
+ prototype: TreemapElement;
142
+ new(cfg: TreemapConfig): TreemapElement
143
+ };