chartjs-chart-treemap 2.1.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,13 @@
1
1
  /*!
2
- * chartjs-chart-treemap v2.1.2
2
+ * chartjs-chart-treemap v2.2.0
3
3
  * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2022 Jukka Kurkela
5
5
  * Released under the MIT license
6
6
  */
7
7
  import { Element, Chart, registry, DatasetController } from 'chart.js';
8
- import { isObject, addRoundedRectPath, toFont, isArray, toTRBL, toTRBLCorners, valueOrDefault, defined, clipArea, unclipArea } from 'chart.js/helpers';
8
+ import { isObject, addRoundedRectPath, defined, toFont, isArray, toTRBL, toTRBLCorners, valueOrDefault, clipArea, unclipArea } from 'chart.js/helpers';
9
9
 
10
- const getValue = (item) => isObject(item) ? item.v : item;
11
-
12
- const maxValue = (data) => data.reduce(function(m, v) {
13
- return (m > getValue(v) ? m : getValue(v));
14
- }, 0);
15
-
16
- const minValue = (data, mx) => data.reduce(function(m, v) {
17
- return (m < getValue(v) ? m : getValue(v));
18
- }, mx);
10
+ const isOlderPart = (act, req) => req > act || (act.length > req.length && act.slice(0, req.length) === req);
19
11
 
20
12
  const getGroupKey = (lvl) => '' + lvl;
21
13
 
@@ -185,23 +177,30 @@ function sum(values, key) {
185
177
  return s;
186
178
  }
187
179
 
188
- function requireVersion(min, ver) {
180
+ /**
181
+ * @param {string} pkg
182
+ * @param {string} min
183
+ * @param {string} ver
184
+ * @param {boolean} [strict=true]
185
+ * @returns {boolean}
186
+ */
187
+ function requireVersion(pkg, min, ver, strict = true) {
189
188
  const parts = ver.split('.');
190
- if (!min.split('.').reduce((a, c, i) => a && c <= parts[i], true)) {
191
- throw new Error(`Chart.js v${ver} is not supported. v${min} or newer is required.`);
189
+ let i = 0;
190
+ for (const req of min.split('.')) {
191
+ const act = parts[i++];
192
+ if (parseInt(req, 10) < parseInt(act, 10)) {
193
+ break;
194
+ }
195
+ if (isOlderPart(act, req)) {
196
+ if (strict) {
197
+ throw new Error(`${pkg} v${ver} is not supported. v${min} or newer is required.`);
198
+ } else {
199
+ return false;
200
+ }
201
+ }
192
202
  }
193
- }
194
-
195
- const rasterize = (v, dpr) => Math.round(v * dpr) / dpr;
196
-
197
- function rasterizeRect(rect, dpr) {
198
- return {
199
- ...rect,
200
- x: rasterize(rect.x, dpr),
201
- y: rasterize(rect.y, dpr),
202
- w: rasterize(rect.w, dpr),
203
- h: rasterize(rect.h, dpr),
204
- };
203
+ return true;
205
204
  }
206
205
 
207
206
  const widthCache = new Map();
@@ -245,20 +244,20 @@ function parseBorderRadius(value, maxW, maxH) {
245
244
  };
246
245
  }
247
246
 
248
- function boundingRects(rect, dpr) {
247
+ function boundingRects(rect) {
249
248
  const bounds = getBounds(rect);
250
249
  const width = bounds.right - bounds.left;
251
250
  const height = bounds.bottom - bounds.top;
252
251
  const border = parseBorderWidth(rect.options.borderWidth, width / 2, height / 2);
253
252
  const radius = parseBorderRadius(rect.options.borderRadius, width / 2, height / 2);
254
- const outer = rasterizeRect({
253
+ const outer = {
255
254
  x: bounds.left,
256
255
  y: bounds.top,
257
256
  w: width,
258
257
  h: height,
259
258
  active: rect.active,
260
259
  radius
261
- }, dpr);
260
+ };
262
261
 
263
262
  return {
264
263
  outer,
@@ -318,7 +317,7 @@ function drawText(ctx, rect, options, item, levels) {
318
317
  ctx.beginPath();
319
318
  ctx.rect(rect.x, rect.y, rect.w, rect.h);
320
319
  ctx.clip();
321
- const isLeaf = (!('l' in item) || item.l === levels);
320
+ const isLeaf = item && (!defined(item.l) || item.l === levels);
322
321
  if (isLeaf && labels.display) {
323
322
  drawLabel(ctx, rect, options);
324
323
  } else if (!isLeaf && shouldDrawCaption(rect, captions)) {
@@ -472,12 +471,12 @@ class TreemapElement extends Element {
472
471
  }
473
472
  }
474
473
 
475
- draw(ctx, data, levels = 0, dpr) {
474
+ draw(ctx, data, levels = 0) {
476
475
  if (!data) {
477
476
  return;
478
477
  }
479
478
  const options = this.options;
480
- const {inner, outer} = boundingRects(this, dpr);
479
+ const {inner, outer} = boundingRects(this);
481
480
 
482
481
  const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;
483
482
 
@@ -591,11 +590,11 @@ TreemapElement.defaultRoutes = {
591
590
  borderColor: 'borderColor'
592
591
  };
593
592
 
594
- function getDims(itm, w2, s2, key, dpr, maxd2) {
593
+ function getDims(itm, w2, s2, key) {
595
594
  const a = itm._normalized;
596
595
  const ar = w2 * a / s2;
597
- const d1 = rasterize(Math.sqrt(a * ar), dpr);
598
- const d2 = Math.min(rasterize(a / d1, dpr), maxd2);
596
+ const d1 = Math.sqrt(a * ar);
597
+ const d2 = a / d1;
599
598
  const w = key === '_ix' ? d1 : d2;
600
599
  const h = key === '_ix' ? d2 : d1;
601
600
 
@@ -604,8 +603,8 @@ function getDims(itm, w2, s2, key, dpr, maxd2) {
604
603
 
605
604
  const getX = (rect, w) => rect.rtl ? rect.x + rect.iw - w : rect.x + rect._ix;
606
605
 
607
- function buildRow(rect, itm, dims, sum, dpr) {
608
- const r = rasterizeRect({
606
+ function buildRow(rect, itm, dims, sum) {
607
+ const r = {
609
608
  x: getX(rect, dims.w),
610
609
  y: rect.y + rect._iy,
611
610
  w: dims.w,
@@ -614,7 +613,7 @@ function buildRow(rect, itm, dims, sum, dpr) {
614
613
  v: itm.value,
615
614
  s: sum,
616
615
  _data: itm._data
617
- }, dpr);
616
+ };
618
617
  if (itm.group) {
619
618
  r.g = itm.group;
620
619
  r.l = itm.level;
@@ -624,8 +623,7 @@ function buildRow(rect, itm, dims, sum, dpr) {
624
623
  }
625
624
 
626
625
  class Rect {
627
- constructor(r, dpr) {
628
- this.dpr = dpr;
626
+ constructor(r) {
629
627
  r = r || {w: 1, h: 1};
630
628
  this.rtl = !!r.rtl;
631
629
  this.x = r.x || r.left || 0;
@@ -654,61 +652,33 @@ class Rect {
654
652
  }
655
653
 
656
654
  get side() {
657
- return rasterize(this.dir === 'x' ? this.iw : this.ih, this.dpr);
655
+ return this.dir === 'x' ? this.iw : this.ih;
658
656
  }
659
657
 
660
658
  map(arr) {
661
- const {dir, side, dpr} = this;
662
- const {key, d2prop, id2prop, d2key} = getPropNames(dir);
659
+ const {dir, side} = this;
660
+ const key = dir === 'x' ? '_ix' : '_iy';
663
661
  const sum = arr.nsum;
664
662
  const row = arr.get();
665
663
  const w2 = side * side;
666
- const availd2 = rasterize(this[id2prop], dpr);
667
664
  const s2 = sum * sum;
668
665
  const ret = [];
669
666
  let maxd2 = 0;
670
667
  let totd1 = 0;
671
668
  for (const itm of row) {
672
- const dims = getDims(itm, w2, s2, key, dpr, availd2);
669
+ const dims = getDims(itm, w2, s2, key);
673
670
  totd1 += dims.d1;
674
- maxd2 = Math.min(Math.max(maxd2, dims.d2), availd2);
675
- ret.push(buildRow(this, itm, dims, arr.sum, dpr));
671
+ maxd2 = Math.max(maxd2, dims.d2);
672
+ ret.push(buildRow(this, itm, dims, arr.sum));
676
673
  this[key] += dims.d1;
677
674
  }
678
- // make sure all rects are same size in d2 direction
679
- for (const r of ret) {
680
- const d2 = r[d2prop];
681
- if (d2 !== maxd2) {
682
- if (this.rtl && dir === 'y') {
683
- // for RTL, x-coordinate needs to be adjusted too
684
- r.x -= maxd2 - d2;
685
- }
686
- r[d2prop] = maxd2;
687
- }
688
- }
689
- this[d2key] += maxd2;
675
+
676
+ this[dir === 'x' ? '_iy' : '_ix'] += maxd2;
690
677
  this[key] -= totd1;
691
678
  return ret;
692
679
  }
693
680
  }
694
681
 
695
- function getPropNames(dir) {
696
- if (dir === 'x') {
697
- return {
698
- key: '_ix',
699
- d2prop: 'h',
700
- id2prop: 'ih',
701
- d2key: '_iy'
702
- };
703
- }
704
- return {
705
- key: '_iy',
706
- d2prop: 'w',
707
- id2prop: 'iw',
708
- d2key: '_ix'
709
- };
710
- }
711
-
712
682
  const min = Math.min;
713
683
  const max = Math.max;
714
684
 
@@ -807,15 +777,14 @@ function compareAspectRatio(oldStat, newStat, args) {
807
777
  * @param {number[]|object[]} values
808
778
  * @param {object} rectangle
809
779
  * @param {string} [key]
810
- * @param {number} [dpr=1]
811
- * @param {*} [grp]
812
- * @param {*} [lvl]
813
- * @param {*} [gsum]
780
+ * @param {string} [grp]
781
+ * @param {number} [lvl]
782
+ * @param {number} [gsum]
814
783
  */
815
- function squarify(values, rectangle, key, dpr = 1, grp, lvl, gsum) {
784
+ function squarify(values, rectangle, key, grp, lvl, gsum) {
816
785
  values = values || [];
817
786
  const rows = [];
818
- const rect = new Rect(rectangle, dpr);
787
+ const rect = new Rect(rectangle);
819
788
  const row = new StatArray('value', rect.area / sum(values, key));
820
789
  let length = rect.side;
821
790
  const n = values.length;
@@ -852,35 +821,58 @@ function squarify(values, rectangle, key, dpr = 1, grp, lvl, gsum) {
852
821
  return flatten(rows);
853
822
  }
854
823
 
855
- var version = "2.1.2";
824
+ var version = "2.2.0";
825
+
826
+ function scaleRect(sq, xScale, yScale, sp) {
827
+ const sp2 = sp * 2;
828
+ const x = xScale.getPixelForValue(sq.x);
829
+ const y = yScale.getPixelForValue(sq.y);
830
+ const w = xScale.getPixelForValue(sq.x + sq.w) - x;
831
+ const h = yScale.getPixelForValue(sq.y + sq.h) - y;
832
+ return {
833
+ x: x + sp,
834
+ y: y + sp,
835
+ width: w - sp2,
836
+ height: h - sp2,
837
+ hidden: sp2 > w || sp2 > h,
838
+ };
839
+ }
856
840
 
857
841
  function rectNotEqual(r1, r2) {
858
842
  return !r1 || !r2
859
843
  || r1.x !== r2.x
860
844
  || r1.y !== r2.y
861
845
  || r1.w !== r2.w
862
- || r1.h !== r2.h;
846
+ || r1.h !== r2.h
847
+ || r1.rtl !== r2.rtl;
863
848
  }
864
849
 
865
- function arrayNotEqual(a1, a2) {
850
+ function arrayNotEqual(a, b) {
866
851
  let i, n;
867
852
 
868
- if (a1.lenght !== a2.length) {
853
+ if (!a || !b) {
869
854
  return true;
870
855
  }
871
856
 
872
- for (i = 0, n = a1.length; i < n; ++i) {
873
- if (a1[i] !== a2[i]) {
857
+ if (a === b) {
858
+ return false;
859
+ }
860
+
861
+ if (a.length !== b.length) {
862
+ return true;
863
+ }
864
+
865
+ for (i = 0, n = a.length; i < n; ++i) {
866
+ if (a[i] !== b[i]) {
874
867
  return true;
875
868
  }
876
869
  }
877
870
  return false;
878
871
  }
879
872
 
880
- function buildData(dataset, mainRect, dpr) {
873
+ function buildData(tree, dataset, mainRect) {
881
874
  const key = dataset.key || '';
882
875
  const treeLeafKey = dataset.treeLeafKey || '_leaf';
883
- let tree = dataset.tree || [];
884
876
  if (isObject(tree)) {
885
877
  tree = normalizeTreeToArray(key, treeLeafKey, tree);
886
878
  }
@@ -895,7 +887,7 @@ function buildData(dataset, mainRect, dpr) {
895
887
  const g = getGroupKey(groups[gidx]);
896
888
  const pg = (gidx > 0) && getGroupKey(groups[gidx - 1]);
897
889
  const gdata = group(tree, g, key, treeLeafKey, pg, parent, groups.filter((item, index) => index <= gidx));
898
- const gsq = squarify(gdata, rect, key, dpr, g, gidx, gs);
890
+ const gsq = squarify(gdata, rect, key, g, gidx, gs);
899
891
  const ret = gsq.slice();
900
892
  if (gidx < glen - 1) {
901
893
  gsq.forEach((sq) => {
@@ -911,44 +903,25 @@ function buildData(dataset, mainRect, dpr) {
911
903
  subRect.y += font.lineHeight + padding * 2;
912
904
  subRect.h -= font.lineHeight + padding * 2;
913
905
  }
914
- ret.push(...recur(gidx + 1, rasterizeRect(subRect, dpr), sq.g, sq.s));
906
+ ret.push(...recur(gidx + 1, subRect, sq.g, sq.s));
915
907
  });
916
908
  }
917
909
  return ret;
918
910
  }
919
911
 
920
- if (!tree.length && dataset.data.length) {
921
- tree = dataset.tree = dataset.data;
922
- }
923
-
924
912
  return glen
925
913
  ? recur(0, mainRect)
926
- : squarify(tree, mainRect, key, dpr);
927
- }
928
-
929
- function getMinMax(data, useTree) {
930
- const vMax = useTree ? 1 : maxValue(data);
931
- const vMin = useTree ? 0 : minValue(data, vMax);
932
- return {vMin, vMax};
933
- }
934
-
935
- function getArea({xScale, yScale}, data, rtl, useTree) {
936
- const {vMin, vMax} = getMinMax(data, useTree);
937
- const xMin = xScale.getPixelForValue(0);
938
- const xMax = xScale.getPixelForValue(1);
939
- const yMin = yScale.getPixelForValue(vMin);
940
- const yMax = yScale.getPixelForValue(vMax);
941
- return {x: xMin, y: yMax, w: xMax - xMin, h: yMin - yMax, rtl};
914
+ : squarify(tree, mainRect, key);
942
915
  }
943
916
 
944
917
  class TreemapController extends DatasetController {
945
918
  constructor(chart, datasetIndex) {
946
919
  super(chart, datasetIndex);
947
920
 
948
- this._rect = undefined;
949
- this._key = undefined;
950
921
  this._groups = undefined;
951
- this._useTree = undefined;
922
+ this._key = undefined;
923
+ this._rect = undefined;
924
+ this._rectChanged = true;
952
925
  }
953
926
 
954
927
  initialize() {
@@ -956,86 +929,93 @@ class TreemapController extends DatasetController {
956
929
  super.initialize();
957
930
  }
958
931
 
959
- /**
960
- * @todo: Remove with https://github.com/kurkle/chartjs-chart-treemap/issues/137
961
- */
962
- updateRangeFromParsed(range, scale) {
963
- if (range.updated) {
932
+ getMinMax(scale) {
933
+ return {
934
+ min: 0,
935
+ max: scale.axis === 'x' ? scale.right - scale.left : scale.bottom - scale.top
936
+ };
937
+ }
938
+
939
+ configure() {
940
+ super.configure();
941
+ const {xScale, yScale} = this.getMeta();
942
+ if (!xScale || !yScale) {
943
+ // configure is called once before `linkScales`, and at that call we don't have any scales linked yet
964
944
  return;
965
945
  }
966
- range.updated = true;
967
- if (scale.axis === 'x') {
968
- range.min = 0;
969
- range.max = 1;
970
- return;
946
+
947
+ const w = xScale.right - xScale.left;
948
+ const h = yScale.bottom - yScale.top;
949
+ const rect = {x: 0, y: 0, w, h, rtl: !!this.options.rtl};
950
+
951
+ if (rectNotEqual(this._rect, rect)) {
952
+ this._rect = rect;
953
+ this._rectChanged = true;
954
+ }
955
+
956
+ if (this._rectChanged) {
957
+ xScale.max = w;
958
+ xScale.configure();
959
+ yScale.max = h;
960
+ yScale.configure();
971
961
  }
972
- const dataset = this.getDataset();
973
- const {vMin, vMax} = getMinMax(dataset.data, this._useTree);
974
- range.min = vMin;
975
- range.max = vMax;
976
962
  }
977
963
 
978
964
  update(mode) {
979
- const meta = this.getMeta();
980
965
  const dataset = this.getDataset();
981
- const dpr = this.chart.currentDevicePixelRatio;
982
-
983
- if (!defined(this._useTree)) {
984
- this._useTree = !!dataset.tree;
985
- }
966
+ const {data} = this.getMeta();
986
967
  const groups = dataset.groups || (dataset.groups = []);
987
- const key = dataset.key || '';
988
- const rtl = !!dataset.rtl;
968
+ const key = dataset.key;
969
+ const tree = dataset.tree = dataset.tree || dataset.data || [];
989
970
 
990
- const mainRect = rasterizeRect(getArea(meta, dataset.data, rtl, this._useTree), dpr);
971
+ if (mode === 'reset') {
972
+ // reset is called before 2nd configure and is only called if animations are enabled. So wen need an extra configure call here.
973
+ this.configure();
974
+ }
991
975
 
992
- if (mode === 'reset' || rectNotEqual(this._rect, mainRect) || this._key !== key || arrayNotEqual(this._groups, groups)) {
993
- this._rect = mainRect;
976
+ if (this._rectChanged || this._key !== key || arrayNotEqual(this._groups, groups) || this._prevTree !== tree) {
994
977
  this._groups = groups.slice();
995
978
  this._key = key;
979
+ this._prevTree = tree;
980
+ this._rectChanged = false;
996
981
 
997
- dataset.data = buildData(dataset, mainRect, dpr);
982
+ dataset.data = buildData(tree, dataset, this._rect);
998
983
  // @ts-ignore using private stuff
999
984
  this._dataCheck();
1000
985
  // @ts-ignore using private stuff
1001
986
  this._resyncElements();
1002
987
  }
1003
988
 
1004
- this.updateElements(meta.data, 0, meta.data.length, mode);
989
+ this.updateElements(data, 0, data.length, mode);
1005
990
  }
1006
991
 
1007
992
  updateElements(rects, start, count, mode) {
1008
- const me = this;
1009
993
  const reset = mode === 'reset';
1010
- const dataset = me.getDataset();
1011
- const firstOpts = me._rect.options = me.resolveDataElementOptions(start, mode);
1012
- const sharedOptions = me.getSharedOptions(firstOpts);
1013
- const includeOptions = me.includeOptions(mode, sharedOptions);
994
+ const dataset = this.getDataset();
995
+ const firstOpts = this._rect.options = this.resolveDataElementOptions(start, mode);
996
+ const sharedOptions = this.getSharedOptions(firstOpts);
997
+ const includeOptions = this.includeOptions(mode, sharedOptions);
998
+ const {xScale, yScale} = this.getMeta(this.index);
1014
999
 
1015
1000
  for (let i = start; i < start + count; i++) {
1016
- const sq = dataset.data[i];
1017
- const options = sharedOptions || me.resolveDataElementOptions(i, mode);
1018
- const sp = options.spacing;
1019
- const sp2 = sp * 2;
1020
- const properties = {
1021
- x: sq.x + sp,
1022
- y: sq.y + sp,
1023
- width: reset ? 0 : sq.w - sp2,
1024
- height: reset ? 0 : sq.h - sp2,
1025
- hidden: sp2 > sq.w || sp2 > sq.h,
1026
- };
1001
+ const options = sharedOptions || this.resolveDataElementOptions(i, mode);
1002
+ const properties = scaleRect(dataset.data[i], xScale, yScale, options.spacing);
1003
+ if (reset) {
1004
+ properties.width = 0;
1005
+ properties.height = 0;
1006
+ }
1027
1007
 
1028
1008
  if (includeOptions) {
1029
1009
  properties.options = options;
1030
1010
  }
1031
- me.updateElement(rects[i], i, properties, mode);
1011
+ this.updateElement(rects[i], i, properties, mode);
1032
1012
  }
1033
1013
 
1034
- me.updateSharedOptions(sharedOptions, mode, firstOpts);
1014
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
1035
1015
  }
1036
1016
 
1037
1017
  draw() {
1038
- const {ctx, chartArea, currentDevicePixelRatio: dpr} = this.chart;
1018
+ const {ctx, chartArea} = this.chart;
1039
1019
  const metadata = this.getMeta().data || [];
1040
1020
  const dataset = this.getDataset();
1041
1021
  const levels = (dataset.groups || []).length - 1;
@@ -1045,7 +1025,7 @@ class TreemapController extends DatasetController {
1045
1025
  for (let i = 0, ilen = metadata.length; i < ilen; ++i) {
1046
1026
  const rect = metadata[i];
1047
1027
  if (!rect.hidden) {
1048
- rect.draw(ctx, data[i], levels, dpr);
1028
+ rect.draw(ctx, data[i], levels);
1049
1029
  }
1050
1030
  }
1051
1031
  unclipArea(ctx);
@@ -1106,17 +1086,22 @@ TreemapController.overrides = {
1106
1086
  scales: {
1107
1087
  x: {
1108
1088
  type: 'linear',
1089
+ alignToPixels: true,
1090
+ bounds: 'data',
1109
1091
  display: false
1110
1092
  },
1111
1093
  y: {
1112
1094
  type: 'linear',
1113
- display: false
1095
+ alignToPixels: true,
1096
+ bounds: 'data',
1097
+ display: false,
1098
+ reverse: true
1114
1099
  }
1115
1100
  },
1116
1101
  };
1117
1102
 
1118
1103
  TreemapController.beforeRegister = function() {
1119
- requireVersion('3.8', Chart.version);
1104
+ requireVersion('chart.js', '3.8', Chart.version);
1120
1105
  };
1121
1106
 
1122
1107
  TreemapController.afterRegister = function() {
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * chartjs-chart-treemap v2.1.2
2
+ * chartjs-chart-treemap v2.2.0
3
3
  * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2022 Jukka Kurkela
5
5
  * Released under the MIT license
@@ -10,15 +10,7 @@ typeof define === 'function' && define.amd ? define(['exports', 'chart.js', 'cha
10
10
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["chartjs-chart-treemap"] = {}, global.Chart, global.Chart.helpers));
11
11
  })(this, (function (exports, chart_js, helpers) { 'use strict';
12
12
 
13
- const getValue = (item) => helpers.isObject(item) ? item.v : item;
14
-
15
- const maxValue = (data) => data.reduce(function(m, v) {
16
- return (m > getValue(v) ? m : getValue(v));
17
- }, 0);
18
-
19
- const minValue = (data, mx) => data.reduce(function(m, v) {
20
- return (m < getValue(v) ? m : getValue(v));
21
- }, mx);
13
+ const isOlderPart = (act, req) => req > act || (act.length > req.length && act.slice(0, req.length) === req);
22
14
 
23
15
  const getGroupKey = (lvl) => '' + lvl;
24
16
 
@@ -188,23 +180,30 @@ function sum(values, key) {
188
180
  return s;
189
181
  }
190
182
 
191
- function requireVersion(min, ver) {
183
+ /**
184
+ * @param {string} pkg
185
+ * @param {string} min
186
+ * @param {string} ver
187
+ * @param {boolean} [strict=true]
188
+ * @returns {boolean}
189
+ */
190
+ function requireVersion(pkg, min, ver, strict = true) {
192
191
  const parts = ver.split('.');
193
- if (!min.split('.').reduce((a, c, i) => a && c <= parts[i], true)) {
194
- throw new Error(`Chart.js v${ver} is not supported. v${min} or newer is required.`);
192
+ let i = 0;
193
+ for (const req of min.split('.')) {
194
+ const act = parts[i++];
195
+ if (parseInt(req, 10) < parseInt(act, 10)) {
196
+ break;
197
+ }
198
+ if (isOlderPart(act, req)) {
199
+ if (strict) {
200
+ throw new Error(`${pkg} v${ver} is not supported. v${min} or newer is required.`);
201
+ } else {
202
+ return false;
203
+ }
204
+ }
195
205
  }
196
- }
197
-
198
- const rasterize = (v, dpr) => Math.round(v * dpr) / dpr;
199
-
200
- function rasterizeRect(rect, dpr) {
201
- return {
202
- ...rect,
203
- x: rasterize(rect.x, dpr),
204
- y: rasterize(rect.y, dpr),
205
- w: rasterize(rect.w, dpr),
206
- h: rasterize(rect.h, dpr),
207
- };
206
+ return true;
208
207
  }
209
208
 
210
209
  const widthCache = new Map();
@@ -248,20 +247,20 @@ function parseBorderRadius(value, maxW, maxH) {
248
247
  };
249
248
  }
250
249
 
251
- function boundingRects(rect, dpr) {
250
+ function boundingRects(rect) {
252
251
  const bounds = getBounds(rect);
253
252
  const width = bounds.right - bounds.left;
254
253
  const height = bounds.bottom - bounds.top;
255
254
  const border = parseBorderWidth(rect.options.borderWidth, width / 2, height / 2);
256
255
  const radius = parseBorderRadius(rect.options.borderRadius, width / 2, height / 2);
257
- const outer = rasterizeRect({
256
+ const outer = {
258
257
  x: bounds.left,
259
258
  y: bounds.top,
260
259
  w: width,
261
260
  h: height,
262
261
  active: rect.active,
263
262
  radius
264
- }, dpr);
263
+ };
265
264
 
266
265
  return {
267
266
  outer,
@@ -321,7 +320,7 @@ function drawText(ctx, rect, options, item, levels) {
321
320
  ctx.beginPath();
322
321
  ctx.rect(rect.x, rect.y, rect.w, rect.h);
323
322
  ctx.clip();
324
- const isLeaf = (!('l' in item) || item.l === levels);
323
+ const isLeaf = item && (!helpers.defined(item.l) || item.l === levels);
325
324
  if (isLeaf && labels.display) {
326
325
  drawLabel(ctx, rect, options);
327
326
  } else if (!isLeaf && shouldDrawCaption(rect, captions)) {
@@ -475,12 +474,12 @@ class TreemapElement extends chart_js.Element {
475
474
  }
476
475
  }
477
476
 
478
- draw(ctx, data, levels = 0, dpr) {
477
+ draw(ctx, data, levels = 0) {
479
478
  if (!data) {
480
479
  return;
481
480
  }
482
481
  const options = this.options;
483
- const {inner, outer} = boundingRects(this, dpr);
482
+ const {inner, outer} = boundingRects(this);
484
483
 
485
484
  const addRectPath = hasRadius(outer.radius) ? helpers.addRoundedRectPath : addNormalRectPath;
486
485
 
@@ -594,11 +593,11 @@ TreemapElement.defaultRoutes = {
594
593
  borderColor: 'borderColor'
595
594
  };
596
595
 
597
- function getDims(itm, w2, s2, key, dpr, maxd2) {
596
+ function getDims(itm, w2, s2, key) {
598
597
  const a = itm._normalized;
599
598
  const ar = w2 * a / s2;
600
- const d1 = rasterize(Math.sqrt(a * ar), dpr);
601
- const d2 = Math.min(rasterize(a / d1, dpr), maxd2);
599
+ const d1 = Math.sqrt(a * ar);
600
+ const d2 = a / d1;
602
601
  const w = key === '_ix' ? d1 : d2;
603
602
  const h = key === '_ix' ? d2 : d1;
604
603
 
@@ -607,8 +606,8 @@ function getDims(itm, w2, s2, key, dpr, maxd2) {
607
606
 
608
607
  const getX = (rect, w) => rect.rtl ? rect.x + rect.iw - w : rect.x + rect._ix;
609
608
 
610
- function buildRow(rect, itm, dims, sum, dpr) {
611
- const r = rasterizeRect({
609
+ function buildRow(rect, itm, dims, sum) {
610
+ const r = {
612
611
  x: getX(rect, dims.w),
613
612
  y: rect.y + rect._iy,
614
613
  w: dims.w,
@@ -617,7 +616,7 @@ function buildRow(rect, itm, dims, sum, dpr) {
617
616
  v: itm.value,
618
617
  s: sum,
619
618
  _data: itm._data
620
- }, dpr);
619
+ };
621
620
  if (itm.group) {
622
621
  r.g = itm.group;
623
622
  r.l = itm.level;
@@ -627,8 +626,7 @@ function buildRow(rect, itm, dims, sum, dpr) {
627
626
  }
628
627
 
629
628
  class Rect {
630
- constructor(r, dpr) {
631
- this.dpr = dpr;
629
+ constructor(r) {
632
630
  r = r || {w: 1, h: 1};
633
631
  this.rtl = !!r.rtl;
634
632
  this.x = r.x || r.left || 0;
@@ -657,61 +655,33 @@ class Rect {
657
655
  }
658
656
 
659
657
  get side() {
660
- return rasterize(this.dir === 'x' ? this.iw : this.ih, this.dpr);
658
+ return this.dir === 'x' ? this.iw : this.ih;
661
659
  }
662
660
 
663
661
  map(arr) {
664
- const {dir, side, dpr} = this;
665
- const {key, d2prop, id2prop, d2key} = getPropNames(dir);
662
+ const {dir, side} = this;
663
+ const key = dir === 'x' ? '_ix' : '_iy';
666
664
  const sum = arr.nsum;
667
665
  const row = arr.get();
668
666
  const w2 = side * side;
669
- const availd2 = rasterize(this[id2prop], dpr);
670
667
  const s2 = sum * sum;
671
668
  const ret = [];
672
669
  let maxd2 = 0;
673
670
  let totd1 = 0;
674
671
  for (const itm of row) {
675
- const dims = getDims(itm, w2, s2, key, dpr, availd2);
672
+ const dims = getDims(itm, w2, s2, key);
676
673
  totd1 += dims.d1;
677
- maxd2 = Math.min(Math.max(maxd2, dims.d2), availd2);
678
- ret.push(buildRow(this, itm, dims, arr.sum, dpr));
674
+ maxd2 = Math.max(maxd2, dims.d2);
675
+ ret.push(buildRow(this, itm, dims, arr.sum));
679
676
  this[key] += dims.d1;
680
677
  }
681
- // make sure all rects are same size in d2 direction
682
- for (const r of ret) {
683
- const d2 = r[d2prop];
684
- if (d2 !== maxd2) {
685
- if (this.rtl && dir === 'y') {
686
- // for RTL, x-coordinate needs to be adjusted too
687
- r.x -= maxd2 - d2;
688
- }
689
- r[d2prop] = maxd2;
690
- }
691
- }
692
- this[d2key] += maxd2;
678
+
679
+ this[dir === 'x' ? '_iy' : '_ix'] += maxd2;
693
680
  this[key] -= totd1;
694
681
  return ret;
695
682
  }
696
683
  }
697
684
 
698
- function getPropNames(dir) {
699
- if (dir === 'x') {
700
- return {
701
- key: '_ix',
702
- d2prop: 'h',
703
- id2prop: 'ih',
704
- d2key: '_iy'
705
- };
706
- }
707
- return {
708
- key: '_iy',
709
- d2prop: 'w',
710
- id2prop: 'iw',
711
- d2key: '_ix'
712
- };
713
- }
714
-
715
685
  const min = Math.min;
716
686
  const max = Math.max;
717
687
 
@@ -810,15 +780,14 @@ function compareAspectRatio(oldStat, newStat, args) {
810
780
  * @param {number[]|object[]} values
811
781
  * @param {object} rectangle
812
782
  * @param {string} [key]
813
- * @param {number} [dpr=1]
814
- * @param {*} [grp]
815
- * @param {*} [lvl]
816
- * @param {*} [gsum]
783
+ * @param {string} [grp]
784
+ * @param {number} [lvl]
785
+ * @param {number} [gsum]
817
786
  */
818
- function squarify(values, rectangle, key, dpr = 1, grp, lvl, gsum) {
787
+ function squarify(values, rectangle, key, grp, lvl, gsum) {
819
788
  values = values || [];
820
789
  const rows = [];
821
- const rect = new Rect(rectangle, dpr);
790
+ const rect = new Rect(rectangle);
822
791
  const row = new StatArray('value', rect.area / sum(values, key));
823
792
  let length = rect.side;
824
793
  const n = values.length;
@@ -855,35 +824,58 @@ function squarify(values, rectangle, key, dpr = 1, grp, lvl, gsum) {
855
824
  return flatten(rows);
856
825
  }
857
826
 
858
- var version = "2.1.2";
827
+ var version = "2.2.0";
828
+
829
+ function scaleRect(sq, xScale, yScale, sp) {
830
+ const sp2 = sp * 2;
831
+ const x = xScale.getPixelForValue(sq.x);
832
+ const y = yScale.getPixelForValue(sq.y);
833
+ const w = xScale.getPixelForValue(sq.x + sq.w) - x;
834
+ const h = yScale.getPixelForValue(sq.y + sq.h) - y;
835
+ return {
836
+ x: x + sp,
837
+ y: y + sp,
838
+ width: w - sp2,
839
+ height: h - sp2,
840
+ hidden: sp2 > w || sp2 > h,
841
+ };
842
+ }
859
843
 
860
844
  function rectNotEqual(r1, r2) {
861
845
  return !r1 || !r2
862
846
  || r1.x !== r2.x
863
847
  || r1.y !== r2.y
864
848
  || r1.w !== r2.w
865
- || r1.h !== r2.h;
849
+ || r1.h !== r2.h
850
+ || r1.rtl !== r2.rtl;
866
851
  }
867
852
 
868
- function arrayNotEqual(a1, a2) {
853
+ function arrayNotEqual(a, b) {
869
854
  let i, n;
870
855
 
871
- if (a1.lenght !== a2.length) {
856
+ if (!a || !b) {
857
+ return true;
858
+ }
859
+
860
+ if (a === b) {
861
+ return false;
862
+ }
863
+
864
+ if (a.length !== b.length) {
872
865
  return true;
873
866
  }
874
867
 
875
- for (i = 0, n = a1.length; i < n; ++i) {
876
- if (a1[i] !== a2[i]) {
868
+ for (i = 0, n = a.length; i < n; ++i) {
869
+ if (a[i] !== b[i]) {
877
870
  return true;
878
871
  }
879
872
  }
880
873
  return false;
881
874
  }
882
875
 
883
- function buildData(dataset, mainRect, dpr) {
876
+ function buildData(tree, dataset, mainRect) {
884
877
  const key = dataset.key || '';
885
878
  const treeLeafKey = dataset.treeLeafKey || '_leaf';
886
- let tree = dataset.tree || [];
887
879
  if (helpers.isObject(tree)) {
888
880
  tree = normalizeTreeToArray(key, treeLeafKey, tree);
889
881
  }
@@ -898,7 +890,7 @@ function buildData(dataset, mainRect, dpr) {
898
890
  const g = getGroupKey(groups[gidx]);
899
891
  const pg = (gidx > 0) && getGroupKey(groups[gidx - 1]);
900
892
  const gdata = group(tree, g, key, treeLeafKey, pg, parent, groups.filter((item, index) => index <= gidx));
901
- const gsq = squarify(gdata, rect, key, dpr, g, gidx, gs);
893
+ const gsq = squarify(gdata, rect, key, g, gidx, gs);
902
894
  const ret = gsq.slice();
903
895
  if (gidx < glen - 1) {
904
896
  gsq.forEach((sq) => {
@@ -914,44 +906,25 @@ function buildData(dataset, mainRect, dpr) {
914
906
  subRect.y += font.lineHeight + padding * 2;
915
907
  subRect.h -= font.lineHeight + padding * 2;
916
908
  }
917
- ret.push(...recur(gidx + 1, rasterizeRect(subRect, dpr), sq.g, sq.s));
909
+ ret.push(...recur(gidx + 1, subRect, sq.g, sq.s));
918
910
  });
919
911
  }
920
912
  return ret;
921
913
  }
922
914
 
923
- if (!tree.length && dataset.data.length) {
924
- tree = dataset.tree = dataset.data;
925
- }
926
-
927
915
  return glen
928
916
  ? recur(0, mainRect)
929
- : squarify(tree, mainRect, key, dpr);
930
- }
931
-
932
- function getMinMax(data, useTree) {
933
- const vMax = useTree ? 1 : maxValue(data);
934
- const vMin = useTree ? 0 : minValue(data, vMax);
935
- return {vMin, vMax};
936
- }
937
-
938
- function getArea({xScale, yScale}, data, rtl, useTree) {
939
- const {vMin, vMax} = getMinMax(data, useTree);
940
- const xMin = xScale.getPixelForValue(0);
941
- const xMax = xScale.getPixelForValue(1);
942
- const yMin = yScale.getPixelForValue(vMin);
943
- const yMax = yScale.getPixelForValue(vMax);
944
- return {x: xMin, y: yMax, w: xMax - xMin, h: yMin - yMax, rtl};
917
+ : squarify(tree, mainRect, key);
945
918
  }
946
919
 
947
920
  class TreemapController extends chart_js.DatasetController {
948
921
  constructor(chart, datasetIndex) {
949
922
  super(chart, datasetIndex);
950
923
 
951
- this._rect = undefined;
952
- this._key = undefined;
953
924
  this._groups = undefined;
954
- this._useTree = undefined;
925
+ this._key = undefined;
926
+ this._rect = undefined;
927
+ this._rectChanged = true;
955
928
  }
956
929
 
957
930
  initialize() {
@@ -959,86 +932,93 @@ class TreemapController extends chart_js.DatasetController {
959
932
  super.initialize();
960
933
  }
961
934
 
962
- /**
963
- * @todo: Remove with https://github.com/kurkle/chartjs-chart-treemap/issues/137
964
- */
965
- updateRangeFromParsed(range, scale) {
966
- if (range.updated) {
935
+ getMinMax(scale) {
936
+ return {
937
+ min: 0,
938
+ max: scale.axis === 'x' ? scale.right - scale.left : scale.bottom - scale.top
939
+ };
940
+ }
941
+
942
+ configure() {
943
+ super.configure();
944
+ const {xScale, yScale} = this.getMeta();
945
+ if (!xScale || !yScale) {
946
+ // configure is called once before `linkScales`, and at that call we don't have any scales linked yet
967
947
  return;
968
948
  }
969
- range.updated = true;
970
- if (scale.axis === 'x') {
971
- range.min = 0;
972
- range.max = 1;
973
- return;
949
+
950
+ const w = xScale.right - xScale.left;
951
+ const h = yScale.bottom - yScale.top;
952
+ const rect = {x: 0, y: 0, w, h, rtl: !!this.options.rtl};
953
+
954
+ if (rectNotEqual(this._rect, rect)) {
955
+ this._rect = rect;
956
+ this._rectChanged = true;
957
+ }
958
+
959
+ if (this._rectChanged) {
960
+ xScale.max = w;
961
+ xScale.configure();
962
+ yScale.max = h;
963
+ yScale.configure();
974
964
  }
975
- const dataset = this.getDataset();
976
- const {vMin, vMax} = getMinMax(dataset.data, this._useTree);
977
- range.min = vMin;
978
- range.max = vMax;
979
965
  }
980
966
 
981
967
  update(mode) {
982
- const meta = this.getMeta();
983
968
  const dataset = this.getDataset();
984
- const dpr = this.chart.currentDevicePixelRatio;
985
-
986
- if (!helpers.defined(this._useTree)) {
987
- this._useTree = !!dataset.tree;
988
- }
969
+ const {data} = this.getMeta();
989
970
  const groups = dataset.groups || (dataset.groups = []);
990
- const key = dataset.key || '';
991
- const rtl = !!dataset.rtl;
971
+ const key = dataset.key;
972
+ const tree = dataset.tree = dataset.tree || dataset.data || [];
992
973
 
993
- const mainRect = rasterizeRect(getArea(meta, dataset.data, rtl, this._useTree), dpr);
974
+ if (mode === 'reset') {
975
+ // reset is called before 2nd configure and is only called if animations are enabled. So wen need an extra configure call here.
976
+ this.configure();
977
+ }
994
978
 
995
- if (mode === 'reset' || rectNotEqual(this._rect, mainRect) || this._key !== key || arrayNotEqual(this._groups, groups)) {
996
- this._rect = mainRect;
979
+ if (this._rectChanged || this._key !== key || arrayNotEqual(this._groups, groups) || this._prevTree !== tree) {
997
980
  this._groups = groups.slice();
998
981
  this._key = key;
982
+ this._prevTree = tree;
983
+ this._rectChanged = false;
999
984
 
1000
- dataset.data = buildData(dataset, mainRect, dpr);
985
+ dataset.data = buildData(tree, dataset, this._rect);
1001
986
  // @ts-ignore using private stuff
1002
987
  this._dataCheck();
1003
988
  // @ts-ignore using private stuff
1004
989
  this._resyncElements();
1005
990
  }
1006
991
 
1007
- this.updateElements(meta.data, 0, meta.data.length, mode);
992
+ this.updateElements(data, 0, data.length, mode);
1008
993
  }
1009
994
 
1010
995
  updateElements(rects, start, count, mode) {
1011
- const me = this;
1012
996
  const reset = mode === 'reset';
1013
- const dataset = me.getDataset();
1014
- const firstOpts = me._rect.options = me.resolveDataElementOptions(start, mode);
1015
- const sharedOptions = me.getSharedOptions(firstOpts);
1016
- const includeOptions = me.includeOptions(mode, sharedOptions);
997
+ const dataset = this.getDataset();
998
+ const firstOpts = this._rect.options = this.resolveDataElementOptions(start, mode);
999
+ const sharedOptions = this.getSharedOptions(firstOpts);
1000
+ const includeOptions = this.includeOptions(mode, sharedOptions);
1001
+ const {xScale, yScale} = this.getMeta(this.index);
1017
1002
 
1018
1003
  for (let i = start; i < start + count; i++) {
1019
- const sq = dataset.data[i];
1020
- const options = sharedOptions || me.resolveDataElementOptions(i, mode);
1021
- const sp = options.spacing;
1022
- const sp2 = sp * 2;
1023
- const properties = {
1024
- x: sq.x + sp,
1025
- y: sq.y + sp,
1026
- width: reset ? 0 : sq.w - sp2,
1027
- height: reset ? 0 : sq.h - sp2,
1028
- hidden: sp2 > sq.w || sp2 > sq.h,
1029
- };
1004
+ const options = sharedOptions || this.resolveDataElementOptions(i, mode);
1005
+ const properties = scaleRect(dataset.data[i], xScale, yScale, options.spacing);
1006
+ if (reset) {
1007
+ properties.width = 0;
1008
+ properties.height = 0;
1009
+ }
1030
1010
 
1031
1011
  if (includeOptions) {
1032
1012
  properties.options = options;
1033
1013
  }
1034
- me.updateElement(rects[i], i, properties, mode);
1014
+ this.updateElement(rects[i], i, properties, mode);
1035
1015
  }
1036
1016
 
1037
- me.updateSharedOptions(sharedOptions, mode, firstOpts);
1017
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
1038
1018
  }
1039
1019
 
1040
1020
  draw() {
1041
- const {ctx, chartArea, currentDevicePixelRatio: dpr} = this.chart;
1021
+ const {ctx, chartArea} = this.chart;
1042
1022
  const metadata = this.getMeta().data || [];
1043
1023
  const dataset = this.getDataset();
1044
1024
  const levels = (dataset.groups || []).length - 1;
@@ -1048,7 +1028,7 @@ class TreemapController extends chart_js.DatasetController {
1048
1028
  for (let i = 0, ilen = metadata.length; i < ilen; ++i) {
1049
1029
  const rect = metadata[i];
1050
1030
  if (!rect.hidden) {
1051
- rect.draw(ctx, data[i], levels, dpr);
1031
+ rect.draw(ctx, data[i], levels);
1052
1032
  }
1053
1033
  }
1054
1034
  helpers.unclipArea(ctx);
@@ -1109,17 +1089,22 @@ TreemapController.overrides = {
1109
1089
  scales: {
1110
1090
  x: {
1111
1091
  type: 'linear',
1092
+ alignToPixels: true,
1093
+ bounds: 'data',
1112
1094
  display: false
1113
1095
  },
1114
1096
  y: {
1115
1097
  type: 'linear',
1116
- display: false
1098
+ alignToPixels: true,
1099
+ bounds: 'data',
1100
+ display: false,
1101
+ reverse: true
1117
1102
  }
1118
1103
  },
1119
1104
  };
1120
1105
 
1121
1106
  TreemapController.beforeRegister = function() {
1122
- requireVersion('3.8', chart_js.Chart.version);
1107
+ requireVersion('chart.js', '3.8', chart_js.Chart.version);
1123
1108
  };
1124
1109
 
1125
1110
  TreemapController.afterRegister = function() {
@@ -1153,13 +1138,9 @@ exports.flatten = flatten;
1153
1138
  exports.getGroupKey = getGroupKey;
1154
1139
  exports.group = group;
1155
1140
  exports.index = index;
1156
- exports.maxValue = maxValue;
1157
- exports.minValue = minValue;
1158
1141
  exports.normalizeTreeToArray = normalizeTreeToArray;
1159
1142
  exports.requireVersion = requireVersion;
1160
1143
  exports.sort = sort;
1161
1144
  exports.sum = sum;
1162
1145
 
1163
- Object.defineProperty(exports, '__esModule', { value: true });
1164
-
1165
1146
  }));
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * chartjs-chart-treemap v2.1.2
2
+ * chartjs-chart-treemap v2.2.0
3
3
  * https://chartjs-chart-treemap.pages.dev/
4
4
  * (c) 2022 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";const i=t=>n.isObject(t)?t.v:t,r=t=>t.reduce((function(t,e){return t>i(e)?t:i(e)}),0),o=(t,e)=>t.reduce((function(t,e){return t<i(e)?t:i(e)}),e),s=t=>""+t;function a(t,e,i,r=[],o=0,l=[]){const h=o-1;if(t in i&&o>0){const n=r.reduce((function(t,e,n){return n!==h&&(t[s(n)]=e),t}),{});n[e]=r[h],n[t]=i[t],l.push(n)}else for(const s of Object.keys(i)){const h=i[s];n.isObject(h)&&(r.push(s),a(t,e,h,r,o+1,l))}return r.splice(h,1),l}function l(t,e,n){const i=a(t,e,n);if(!i.length)return i;const r=i.reduce((function(t,e){const n=Object.keys(e).length-2;return t>n?t:n}));return i.forEach((function(t){for(let e=0;e<r;e++){const n=s(e);t[n]||(t[n]="")}})),i}function h(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 u(t,e,n){if(!t.length)return;const i=[];for(const r of t){const t=e[r];if(""===t){i.push(n);break}i.push(t)}return i.length?i.join("."):n}function c(t,e,n,i,r,o,s=[]){const a=Object.create(null),l=Object.create(null),h=[];let c,d,p;for(d=0,p=t.length;d<p;++d){const h=t[d];r&&h[r]!==o||(c=h[e]||h[i]||"",c in a||(a[c]={value:0},l[c]=[]),a[c].value+=+h[n],a[c].label=h[e]||"",a[c].path=u(s,h,c),l[c].push(h))}return Object.keys(a).forEach((t=>{const i={children:l[t]};i[n]=+a[t].value,i[e]=a[t].label,i.label=t,i.path=a[t].path,r&&(i[r]=o),h.push(i)})),h}function d(t,e){let i,r=t.length;if(!r)return e;const o=n.isObject(t[0]);for(e=o?e:"v",i=0,r=t.length;i<r;++i)o?t[i]._idx=i:t[i]={v:t[i],_idx:i};return e}function p(t,e){e?t.sort(((t,n)=>+n[e]-+t[e])):t.sort(((t,e)=>+e-+t))}function f(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 g(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.`)}const m=(t,e)=>Math.round(t*e)/e;function x(t,e){return{...t,x:m(t.x,e),y:m(t.y,e),w:m(t.w,e),h:m(t.h,e)}}const y=new Map;function b(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 v(t,e,n){return Math.max(Math.min(t,n),e)}function w(t,e,i){const r=n.toTRBL(t);return{t:v(r.top,0,i),r:v(r.right,0,e),b:v(r.bottom,0,i),l:v(r.left,0,e)}}function _(t,e){const i=b(t),r=i.right-i.left,o=i.bottom-i.top,s=w(t.options.borderWidth,r/2,o/2),a=function(t,e,i){const r=n.toTRBLCorners(t),o=Math.min(e,i);return{topLeft:v(r.topLeft,0,o),topRight:v(r.topRight,0,o),bottomLeft:v(r.bottomLeft,0,o),bottomRight:v(r.bottomRight,0,o)}}(t.options.borderRadius,r/2,o/2),l=x({x:i.left,y:i.top,w:r,h:o,active:t.active,radius:a},e);return{outer:l,inner:{x:l.x+s.l,y:l.y+s.t,w:l.w-s.l-s.r,h:l.h-s.t-s.b,active:t.active,radius:{topLeft:Math.max(0,a.topLeft-Math.max(s.t,s.l)),topRight:Math.max(0,a.topRight-Math.max(s.t,s.r)),bottomLeft:Math.max(0,a.bottomLeft-Math.max(s.b,s.l)),bottomRight:Math.max(0,a.bottomRight-Math.max(s.b,s.r))}}}}function M(t,e,n,i){const r=null===e,o=null===n,s=!(!t||r&&o)&&b(t,i);return s&&(r||e>=s.left&&e<=s.right)&&(o||n>=s.top&&n<=s.bottom)}function k(t,e){t.rect(e.x,e.y,e.w,e.h)}function R(t,e){if(!e||!1===e.display)return!1;const{w:i,h:r}=t,o=n.toFont(e.font).lineHeight,s=v(2*n.valueOrDefault(e.padding,3),0,Math.min(i,r));return i-s>o&&r-s>o}function O(t,e,i,r,o){const{captions:s,labels:a}=i;t.save(),t.beginPath(),t.rect(e.x,e.y,e.w,e.h),t.clip();const l=!("l"in r)||r.l===o;l&&a.display?function(t,e,i){const r=i.labels,o=r.formatter;if(!o)return;const s=n.isArray(o)?o:[o],{font:a,hoverFont:l}=r,h=(e.active?l:a)||a,u=n.isArray(h)?h.map((t=>n.toFont(t))):[n.toFont(h)],c=function(t,e,n){const i=n.reduce((function(t,e){return t+=e.string}),""),r=e.join()+i+(t._measureText?"-spriting":"");if(!y.has(r)){t.save();const i=e.length;let o=0,s=0;for(let r=0;r<i;r++){const i=n[Math.min(r,n.length-1)];t.font=i.string;const a=e[r];o=Math.max(o,t.measureText(a).width),s+=i.lineHeight}t.restore(),y.set(r,{width:o,height:s})}return y.get(r)}(t,s,u);if(!function(t,e,n,i){const{overflow:r,padding:o}=n,{width:s,height:a}=i;if("hidden"===r)return!(s+2*o>e.w||a+2*o>e.h);return!0}(0,e,r,c))return;const{color:d,hoverColor:p,align:f}=r,g=(e.active?p:d)||d,m=n.isArray(g)?g:[g],x=function(t,e,n){const{align:i,position:r,padding:o}=e;let s,a;s=C(t,i,o),a="top"===r?t.y+o:"bottom"===r?t.y+t.h-o-n.height:t.y+(t.h-n.height)/2+o;return{x:s,y:a}}(e,r,c);t.textAlign=f,t.textBaseline="middle";let b=0;s.forEach((function(e,n){const i=m[Math.min(n,m.length-1)],r=u[Math.min(n,u.length-1)],o=r.lineHeight;t.font=r.string,t.fillStyle=i,t.fillText(e,x.x,x.y+o/2+b),b+=o}))}(t,e,i):!l&&R(e,s)&&function(t,e,i,r){const{captions:o,spacing:s,rtl:a}=i,{color:l,hoverColor:h,font:u,hoverFont:c,padding:d,align:p,formatter:f}=o,g=(e.active?h:l)||l,m=p||(a?"right":"left"),x=(e.active?c:u)||u,y=n.toFont(x),b=y.lineHeight/2,v=C(e,m,d);t.fillStyle=g,t.font=y.string,t.textAlign=m,t.textBaseline="middle",t.fillText(f||r.g,v,e.y+d+s+b)}(t,e,i,r),t.restore()}function C(t,e,n){return"left"===e?t.x+n:"right"===e?t.x+t.w-n:t.x+t.w/2}class j 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,e,i=0,r){if(!e)return;const o=this.options,{inner:s,outer:a}=_(this,r),l=(h=a.radius).topLeft||h.topRight||h.bottomLeft||h.bottomRight?n.addRoundedRectPath:k;var h;t.save(),a.w===s.w&&a.h===s.h||(t.beginPath(),l(t,a),t.clip(),l(t,s),t.fillStyle=o.borderColor,t.fill("evenodd")),t.beginPath(),l(t,s),t.fillStyle=o.backgroundColor,t.fill(),function(t,e,n,i){const r=n.dividers;if(!r.display||!i._data.children.length)return;const{x:o,y:s,w:a,h:l}=e,{lineColor:h,lineCapStyle:u,lineDash:c,lineDashOffset:d,lineWidth:p}=r;if(t.save(),t.strokeStyle=h,t.lineCap=u,t.setLineDash(c),t.lineDashOffset=d,t.lineWidth=p,t.beginPath(),a>l){const e=a/2;t.moveTo(o+e,s),t.lineTo(o+e,s+l)}else{const e=l/2;t.moveTo(o,s+e),t.lineTo(o+a,s+e)}t.stroke(),t.restore()}(t,s,o,e),O(t,s,o,e,i),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}}function T(t,e,n,i,r,o){const s=t._normalized,a=e*s/n,l=m(Math.sqrt(s*a),r),h=Math.min(m(s/l,r),o);return{d1:l,d2:h,w:"_ix"===i?l:h,h:"_ix"===i?h:l}}j.id="treemap",j.defaults={label:void 0,borderRadius:0,borderWidth:0,captions:{align:void 0,color:"black",display:!0,font:{},formatter:t=>t.raw.g||t.raw._data.label||"",padding:3},dividers:{display:!1,lineCapStyle:"butt",lineColor:"black",lineDash:[],lineDashOffset:0,lineWidth:1},labels:{align:"center",color:"black",display:!1,font:{},formatter:t=>t.raw.g?[t.raw.g,t.raw.v+""]:t.raw._data.label?[t.raw._data.label,t.raw.v+""]:t.raw.v+"",overflow:"cut",position:"middle",padding:3},rtl:!1,spacing:.5},j.descriptors={labels:{_fallback:!0},captions:{_fallback:!0},_scriptable:!0,_indexable:!1},j.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};const P=(t,e)=>t.rtl?t.x+t.iw-e:t.x+t._ix;function D(t,e,n,i,r){const o=x({x:P(t,n.w),y:t.y+t._iy,w:n.w,h:n.h,a:e._normalized,v:e.value,s:i,_data:e._data},r);return e.group&&(o.g=e.group,o.l=e.level,o.gs=e.groupSum),o}class L{constructor(t,e){this.dpr=e,t=t||{w:1,h:1},this.rtl=!!t.rtl,this.x=t.x||t.left||0,this.y=t.y||t.top||0,this._ix=0,this._iy=0,this.w=t.w||t.width||t.right-t.left,this.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 m("x"===this.dir?this.iw:this.ih,this.dpr)}map(t){const{dir:e,side:n,dpr:i}=this,{key:r,d2prop:o,id2prop:s,d2key:a}=function(t){if("x"===t)return{key:"_ix",d2prop:"h",id2prop:"ih",d2key:"_iy"};return{key:"_iy",d2prop:"w",id2prop:"iw",d2key:"_ix"}}(e),l=t.nsum,h=t.get(),u=n*n,c=m(this[s],i),d=l*l,p=[];let f=0,g=0;for(const e of h){const n=T(e,u,d,r,i,c);g+=n.d1,f=Math.min(Math.max(f,n.d2),c),p.push(D(this,e,n,t.sum,i)),this[r]+=n.d1}for(const t of p){const n=t[o];n!==f&&(this.rtl&&"y"===e&&(t.x-=f-n),t[o]=f)}return this[a]+=f,this[r]-=g,p}}const S=Math.min,E=Math.max;function F(t,e){const n=+e[t.key],i=n*t.ratio;return e._normalized=i,{min:S(t.min,n),max:E(t.max,n),sum:t.sum+n,nmin:S(t.nmin,i),nmax:E(t.nmax,i),nsum:t.nsum+i}}function A(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){A(this,t,F(this,t))}pushIf(t,e,...n){const i=F(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;A(this,t,i)}get(){return this._arr}}function z(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 H(t,e,n,i=1,r,o,s){t=t||[];const a=[],l=new L(e,i),u=new V("value",l.area/f(t,n));let c=l.side;const g=t.length;let m,x;if(!g)return a;const y=t.slice();n=d(y,n),p(y,n);const b=t=>r&&y[t][r];for(m=0;m<g;++m)x={value:(v=m,n?+y[v][n]:+y[v]),groupSum:s,_data:t[y[m]._idx],level:void 0,group:void 0},r&&(x.level=o,x.group=b(m)),x=u.pushIf(x,z,c),x&&(a.push(l.map(u)),c=l.side,u.reset(),u.push(x));var v;return u.length&&a.push(l.map(u)),h(a)}function W(t,e){const n=e?1:r(t);return{vMin:e?0:o(t,n),vMax:n}}class q extends e.DatasetController{constructor(t,e){super(t,e),this._rect=void 0,this._key=void 0,this._groups=void 0,this._useTree=void 0}initialize(){this.enableOptionSharing=!0,super.initialize()}updateRangeFromParsed(t,e){if(t.updated)return;if(t.updated=!0,"x"===e.axis)return t.min=0,void(t.max=1);const n=this.getDataset(),{vMin:i,vMax:r}=W(n.data,this._useTree);t.min=i,t.max=r}update(t){const e=this.getMeta(),i=this.getDataset(),r=this.chart.currentDevicePixelRatio;n.defined(this._useTree)||(this._useTree=!!i.tree);const o=i.groups||(i.groups=[]),a=i.key||"",h=!!i.rtl,u=x(function({xScale:t,yScale:e},n,i,r){const{vMin:o,vMax:s}=W(n,r),a=t.getPixelForValue(0),l=t.getPixelForValue(1),h=e.getPixelForValue(o),u=e.getPixelForValue(s);return{x:a,y:u,w:l-a,h:h-u,rtl:i}}(e,i.data,h,this._useTree),r);var d,p;"reset"!==t&&(d=this._rect,p=u,d&&p&&d.x===p.x&&d.y===p.y&&d.w===p.w&&d.h===p.h)&&this._key===a&&!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}(this._groups,o)||(this._rect=u,this._groups=o.slice(),this._key=a,i.data=function(t,e,i){const r=t.key||"",o=t.treeLeafKey||"_leaf";let a=t.tree||[];n.isObject(a)&&(a=l(r,o,a));const h=t.groups||[],u=h.length,d=n.valueOrDefault(t.spacing,0),p=t.captions||{},f=n.toFont(p.font),g=n.valueOrDefault(p.padding,3);return!a.length&&t.data.length&&(a=t.tree=t.data),u?function e(n,l,m,y){const b=s(h[n]),v=n>0&&s(h[n-1]),_=c(a,b,r,o,v,m,h.filter(((t,e)=>e<=n))),M=H(_,l,r,i,b,n,y),k=M.slice();return n<u-1&&M.forEach((r=>{const o=w(t.borderWidth,r.w/2,r.h/2),s={...l,x:r.x+d+o.l,y:r.y+d+o.t,w:r.w-2*d-o.l-o.r,h:r.h-2*d-o.t-o.b};R(s,p)&&(s.y+=f.lineHeight+2*g,s.h-=f.lineHeight+2*g),k.push(...e(n+1,x(s,i),r.g,r.s))})),k}(0,e):H(a,e,r,i)}(i,u,r),this._dataCheck(),this._resyncElements()),this.updateElements(e.data,0,e.data.length,t)}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=n.spacing,c=2*u,d={x:e.x+u,y:e.y+u,width:o?0:e.w-c,height:o?0:e.h-c,hidden:c>e.w||c>e.h};h&&(d.options=n),r.updateElement(t[a],a,d,i)}r.updateSharedOptions(l,i,a)}draw(){const{ctx:t,chartArea:e,currentDevicePixelRatio:i}=this.chart,r=this.getMeta().data||[],o=this.getDataset(),s=(o.groups||[]).length-1,a=o.data;n.clipArea(t,e);for(let e=0,n=r.length;e<n;++e){const n=r[e];n.hidden||n.draw(t,a[e],s,i)}n.unclipArea(t)}}q.id="treemap",q.version="2.1.2",q.defaults={dataElementType:"treemap",animations:{numbers:{type:"number",properties:["x","y","width","height"]}}},q.descriptors={_scriptable:!0,_indexable:!1},q.overrides={interaction:{mode:"point",includeInvisible:!0,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||n._data.label||e.label;return(i?i+": ":"")+n.v}}}},scales:{x:{type:"linear",display:!1},y:{type:"linear",display:!1}}},q.beforeRegister=function(){g("3.8",e.Chart.version)},q.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()}:console.warn("Unable to register the treemap positioner because tooltip plugin is not registered")},q.afterUnregister=function(){const t=e.registry.plugins.get("tooltip");t&&delete t.positioners.treemap},e.Chart.register(q,j),t.flatten=h,t.getGroupKey=s,t.group=c,t.index=d,t.maxValue=r,t.minValue=o,t.normalizeTreeToArray=l,t.requireVersion=g,t.sort=p,t.sum=f,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";const i=(t,e)=>e>t||t.length>e.length&&t.slice(0,e.length)===e,r=t=>""+t;function o(t,e,i,s=[],a=0,h=[]){const l=a-1;if(t in i&&a>0){const n=s.reduce((function(t,e,n){return n!==l&&(t[r(n)]=e),t}),{});n[e]=s[l],n[t]=i[t],h.push(n)}else for(const r of Object.keys(i)){const l=i[r];n.isObject(l)&&(s.push(r),o(t,e,l,s,a+1,h))}return s.splice(l,1),h}function s(t,e,n){const i=o(t,e,n);if(!i.length)return i;const s=i.reduce((function(t,e){const n=Object.keys(e).length-2;return t>n?t:n}));return i.forEach((function(t){for(let e=0;e<s;e++){const n=r(e);t[n]||(t[n]="")}})),i}function a(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 h(t,e,n){if(!t.length)return;const i=[];for(const r of t){const t=e[r];if(""===t){i.push(n);break}i.push(t)}return i.length?i.join("."):n}function l(t,e,n,i,r,o,s=[]){const a=Object.create(null),l=Object.create(null),u=[];let c,g,d;for(g=0,d=t.length;g<d;++g){const u=t[g];r&&u[r]!==o||(c=u[e]||u[i]||"",c in a||(a[c]={value:0},l[c]=[]),a[c].value+=+u[n],a[c].label=u[e]||"",a[c].path=h(s,u,c),l[c].push(u))}return Object.keys(a).forEach((t=>{const i={children:l[t]};i[n]=+a[t].value,i[e]=a[t].label,i.label=t,i.path=a[t].path,r&&(i[r]=o),u.push(i)})),u}function u(t,e){let i,r=t.length;if(!r)return e;const o=n.isObject(t[0]);for(e=o?e:"v",i=0,r=t.length;i<r;++i)o?t[i]._idx=i:t[i]={v:t[i],_idx:i};return e}function c(t,e){e?t.sort(((t,n)=>+n[e]-+t[e])):t.sort(((t,e)=>+e-+t))}function g(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 d(t,e,n,r=!0){const o=n.split(".");let s=0;for(const a of e.split(".")){const h=o[s++];if(parseInt(a,10)<parseInt(h,10))break;if(i(h,a)){if(r)throw new Error(`${t} v${n} is not supported. v${e} or newer is required.`);return!1}}return!0}const f=new Map;function p(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 m(t,e,n){return Math.max(Math.min(t,n),e)}function x(t,e,i){const r=n.toTRBL(t);return{t:m(r.top,0,i),r:m(r.right,0,e),b:m(r.bottom,0,i),l:m(r.left,0,e)}}function b(t){const e=p(t),i=e.right-e.left,r=e.bottom-e.top,o=x(t.options.borderWidth,i/2,r/2),s=function(t,e,i){const r=n.toTRBLCorners(t),o=Math.min(e,i);return{topLeft:m(r.topLeft,0,o),topRight:m(r.topRight,0,o),bottomLeft:m(r.bottomLeft,0,o),bottomRight:m(r.bottomRight,0,o)}}(t.options.borderRadius,i/2,r/2),a={x:e.left,y:e.top,w:i,h:r,active:t.active,radius:s};return{outer:a,inner:{x:a.x+o.l,y:a.y+o.t,w:a.w-o.l-o.r,h:a.h-o.t-o.b,active:t.active,radius:{topLeft:Math.max(0,s.topLeft-Math.max(o.t,o.l)),topRight:Math.max(0,s.topRight-Math.max(o.t,o.r)),bottomLeft:Math.max(0,s.bottomLeft-Math.max(o.b,o.l)),bottomRight:Math.max(0,s.bottomRight-Math.max(o.b,o.r))}}}}function y(t,e,n,i){const r=null===e,o=null===n,s=!(!t||r&&o)&&p(t,i);return s&&(r||e>=s.left&&e<=s.right)&&(o||n>=s.top&&n<=s.bottom)}function v(t,e){t.rect(e.x,e.y,e.w,e.h)}function w(t,e){if(!e||!1===e.display)return!1;const{w:i,h:r}=t,o=n.toFont(e.font).lineHeight,s=m(2*n.valueOrDefault(e.padding,3),0,Math.min(i,r));return i-s>o&&r-s>o}function _(t,e,i,r,o){const{captions:s,labels:a}=i;t.save(),t.beginPath(),t.rect(e.x,e.y,e.w,e.h),t.clip();const h=r&&(!n.defined(r.l)||r.l===o);h&&a.display?function(t,e,i){const r=i.labels,o=r.formatter;if(!o)return;const s=n.isArray(o)?o:[o],{font:a,hoverFont:h}=r,l=(e.active?h:a)||a,u=n.isArray(l)?l.map((t=>n.toFont(t))):[n.toFont(l)],c=function(t,e,n){const i=n.reduce((function(t,e){return t+=e.string}),""),r=e.join()+i+(t._measureText?"-spriting":"");if(!f.has(r)){t.save();const i=e.length;let o=0,s=0;for(let r=0;r<i;r++){const i=n[Math.min(r,n.length-1)];t.font=i.string;const a=e[r];o=Math.max(o,t.measureText(a).width),s+=i.lineHeight}t.restore(),f.set(r,{width:o,height:s})}return f.get(r)}(t,s,u);if(!function(t,e,n,i){const{overflow:r,padding:o}=n,{width:s,height:a}=i;if("hidden"===r)return!(s+2*o>e.w||a+2*o>e.h);return!0}(0,e,r,c))return;const{color:g,hoverColor:d,align:p}=r,m=(e.active?d:g)||g,x=n.isArray(m)?m:[m],b=function(t,e,n){const{align:i,position:r,padding:o}=e;let s,a;s=M(t,i,o),a="top"===r?t.y+o:"bottom"===r?t.y+t.h-o-n.height:t.y+(t.h-n.height)/2+o;return{x:s,y:a}}(e,r,c);t.textAlign=p,t.textBaseline="middle";let y=0;s.forEach((function(e,n){const i=x[Math.min(n,x.length-1)],r=u[Math.min(n,u.length-1)],o=r.lineHeight;t.font=r.string,t.fillStyle=i,t.fillText(e,b.x,b.y+o/2+y),y+=o}))}(t,e,i):!h&&w(e,s)&&function(t,e,i,r){const{captions:o,spacing:s,rtl:a}=i,{color:h,hoverColor:l,font:u,hoverFont:c,padding:g,align:d,formatter:f}=o,p=(e.active?l:h)||h,m=d||(a?"right":"left"),x=(e.active?c:u)||u,b=n.toFont(x),y=b.lineHeight/2,v=M(e,m,g);t.fillStyle=p,t.font=b.string,t.textAlign=m,t.textBaseline="middle",t.fillText(f||r.g,v,e.y+g+s+y)}(t,e,i,r),t.restore()}function M(t,e,n){return"left"===e?t.x+n:"right"===e?t.x+t.w-n:t.x+t.w/2}class C 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,e,i=0){if(!e)return;const r=this.options,{inner:o,outer:s}=b(this),a=(h=s.radius).topLeft||h.topRight||h.bottomLeft||h.bottomRight?n.addRoundedRectPath:v;var h;t.save(),s.w===o.w&&s.h===o.h||(t.beginPath(),a(t,s),t.clip(),a(t,o),t.fillStyle=r.borderColor,t.fill("evenodd")),t.beginPath(),a(t,o),t.fillStyle=r.backgroundColor,t.fill(),function(t,e,n,i){const r=n.dividers;if(!r.display||!i._data.children.length)return;const{x:o,y:s,w:a,h:h}=e,{lineColor:l,lineCapStyle:u,lineDash:c,lineDashOffset:g,lineWidth:d}=r;if(t.save(),t.strokeStyle=l,t.lineCap=u,t.setLineDash(c),t.lineDashOffset=g,t.lineWidth=d,t.beginPath(),a>h){const e=a/2;t.moveTo(o+e,s),t.lineTo(o+e,s+h)}else{const e=h/2;t.moveTo(o,s+e),t.lineTo(o+a,s+e)}t.stroke(),t.restore()}(t,o,r,e),_(t,o,r,e,i),t.restore()}inRange(t,e,n){return y(this,t,e,n)}inXRange(t,e){return y(this,t,null,e)}inYRange(t,e){return y(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}}function k(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}}C.id="treemap",C.defaults={label:void 0,borderRadius:0,borderWidth:0,captions:{align:void 0,color:"black",display:!0,font:{},formatter:t=>t.raw.g||t.raw._data.label||"",padding:3},dividers:{display:!1,lineCapStyle:"butt",lineColor:"black",lineDash:[],lineDashOffset:0,lineWidth:1},labels:{align:"center",color:"black",display:!1,font:{},formatter:t=>t.raw.g?[t.raw.g,t.raw.v+""]:t.raw._data.label?[t.raw._data.label,t.raw.v+""]:t.raw.v+"",overflow:"cut",position:"middle",padding:3},rtl:!1,spacing:.5},C.descriptors={labels:{_fallback:!0},captions:{_fallback:!0},_scriptable:!0,_indexable:!1},C.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};const R=(t,e)=>t.rtl?t.x+t.iw-e:t.x+t._ix;function O(t,e,n,i){const r={x:R(t,n.w),y:t.y+t._iy,w:n.w,h:n.h,a:e._normalized,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 j{constructor(t){t=t||{w:1,h:1},this.rtl=!!t.rtl,this.x=t.x||t.left||0,this.y=t.y||t.top||0,this._ix=0,this._iy=0,this.w=t.w||t.width||t.right-t.left,this.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{dir:e,side:n}=this,i="x"===e?"_ix":"_iy",r=t.nsum,o=t.get(),s=n*n,a=r*r,h=[];let l=0,u=0;for(const e of o){const n=k(e,s,a,i);u+=n.d1,l=Math.max(l,n.d2),h.push(O(this,e,n,t.sum)),this[i]+=n.d1}return this["x"===e?"_iy":"_ix"]+=l,this[i]-=u,h}}const T=Math.min,P=Math.max;function S(t,e){const n=+e[t.key],i=n*t.ratio;return e._normalized=i,{min:T(t.min,n),max:P(t.max,n),sum:t.sum+n,nmin:T(t.nmin,i),nmax:P(t.nmax,i),nsum:t.nsum+i}}function D(t,e,n){t._arr.push(e),function(t,e){Object.assign(t,e)}(t,n)}class L{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){D(this,t,S(this,t))}pushIf(t,e,...n){const i=S(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;D(this,t,i)}get(){return this._arr}}function E(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 A(t,e,n,i,r,o){t=t||[];const s=[],h=new j(e),l=new L("value",h.area/g(t,n));let d=h.side;const f=t.length;let p,m;if(!f)return s;const x=t.slice();n=u(x,n),c(x,n);const b=t=>i&&x[t][i];for(p=0;p<f;++p)m={value:(y=p,n?+x[y][n]:+x[y]),groupSum:o,_data:t[x[p]._idx],level:void 0,group:void 0},i&&(m.level=r,m.group=b(p)),m=l.pushIf(m,E,d),m&&(s.push(h.map(l)),d=h.side,l.reset(),l.push(m));var y;return l.length&&s.push(h.map(l)),a(s)}function F(t,e,n,i){const r=2*i,o=e.getPixelForValue(t.x),s=n.getPixelForValue(t.y),a=e.getPixelForValue(t.x+t.w)-o,h=n.getPixelForValue(t.y+t.h)-s;return{x:o+i,y:s+i,width:a-r,height:h-r,hidden:r>a||r>h}}class z extends e.DatasetController{constructor(t,e){super(t,e),this._groups=void 0,this._key=void 0,this._rect=void 0,this._rectChanged=!0}initialize(){this.enableOptionSharing=!0,super.initialize()}getMinMax(t){return{min:0,max:"x"===t.axis?t.right-t.left:t.bottom-t.top}}configure(){super.configure();const{xScale:t,yScale:e}=this.getMeta();if(!t||!e)return;const n=t.right-t.left,i=e.bottom-e.top,r={x:0,y:0,w:n,h:i,rtl:!!this.options.rtl};var o,s;o=this._rect,s=r,o&&s&&o.x===s.x&&o.y===s.y&&o.w===s.w&&o.h===s.h&&o.rtl===s.rtl||(this._rect=r,this._rectChanged=!0),this._rectChanged&&(t.max=n,t.configure(),e.max=i,e.configure())}update(t){const e=this.getDataset(),{data:i}=this.getMeta(),o=e.groups||(e.groups=[]),a=e.key,h=e.tree=e.tree||e.data||[];"reset"===t&&this.configure(),(this._rectChanged||this._key!==a||function(t,e){let n,i;if(!t||!e)return!0;if(t===e)return!1;if(t.length!==e.length)return!0;for(n=0,i=t.length;n<i;++n)if(t[n]!==e[n])return!0;return!1}(this._groups,o)||this._prevTree!==h)&&(this._groups=o.slice(),this._key=a,this._prevTree=h,this._rectChanged=!1,e.data=function(t,e,i){const o=e.key||"",a=e.treeLeafKey||"_leaf";n.isObject(t)&&(t=s(o,a,t));const h=e.groups||[],u=h.length,c=n.valueOrDefault(e.spacing,0),g=e.captions||{},d=n.toFont(g.font),f=n.valueOrDefault(g.padding,3);return u?function n(i,s,p,m){const b=r(h[i]),y=i>0&&r(h[i-1]),v=l(t,b,o,a,y,p,h.filter(((t,e)=>e<=i))),_=A(v,s,o,b,i,m),M=_.slice();return i<u-1&&_.forEach((t=>{const r=x(e.borderWidth,t.w/2,t.h/2),o={...s,x:t.x+c+r.l,y:t.y+c+r.t,w:t.w-2*c-r.l-r.r,h:t.h-2*c-r.t-r.b};w(o,g)&&(o.y+=d.lineHeight+2*f,o.h-=d.lineHeight+2*f),M.push(...n(i+1,o,t.g,t.s))})),M}(0,i):A(t,i,o)}(h,e,this._rect),this._dataCheck(),this._resyncElements()),this.updateElements(i,0,i.length,t)}updateElements(t,e,n,i){const r="reset"===i,o=this.getDataset(),s=this._rect.options=this.resolveDataElementOptions(e,i),a=this.getSharedOptions(s),h=this.includeOptions(i,a),{xScale:l,yScale:u}=this.getMeta(this.index);for(let s=e;s<e+n;s++){const e=a||this.resolveDataElementOptions(s,i),n=F(o.data[s],l,u,e.spacing);r&&(n.width=0,n.height=0),h&&(n.options=e),this.updateElement(t[s],s,n,i)}this.updateSharedOptions(a,i,s)}draw(){const{ctx:t,chartArea:e}=this.chart,i=this.getMeta().data||[],r=this.getDataset(),o=(r.groups||[]).length-1,s=r.data;n.clipArea(t,e);for(let e=0,n=i.length;e<n;++e){const n=i[e];n.hidden||n.draw(t,s[e],o)}n.unclipArea(t)}}z.id="treemap",z.version="2.2.0",z.defaults={dataElementType:"treemap",animations:{numbers:{type:"number",properties:["x","y","width","height"]}}},z.descriptors={_scriptable:!0,_indexable:!1},z.overrides={interaction:{mode:"point",includeInvisible:!0,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||n._data.label||e.label;return(i?i+": ":"")+n.v}}}},scales:{x:{type:"linear",alignToPixels:!0,bounds:"data",display:!1},y:{type:"linear",alignToPixels:!0,bounds:"data",display:!1,reverse:!0}}},z.beforeRegister=function(){d("chart.js","3.8",e.Chart.version)},z.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()}:console.warn("Unable to register the treemap positioner because tooltip plugin is not registered")},z.afterUnregister=function(){const t=e.registry.plugins.get("tooltip");t&&delete t.positioners.treemap},e.Chart.register(z,C),t.flatten=a,t.getGroupKey=r,t.group=l,t.index=u,t.normalizeTreeToArray=s,t.requireVersion=d,t.sort=c,t.sum=g}));
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "chartjs-chart-treemap",
3
3
  "homepage": "https://chartjs-chart-treemap.pages.dev/",
4
- "version": "2.1.2",
4
+ "version": "2.2.0",
5
5
  "description": "Chart.js module for creating treemap charts",
6
- "main": "dist/chartjs-chart-treemap.js",
7
- "module": "dist/chartjs-chart-treemap.esm.js",
6
+ "type": "module",
7
+ "main": "dist/chartjs-chart-treemap.esm.js",
8
8
  "types": "types/index.esm.d.ts",
9
+ "jsdelivr": "dist/chartjs-chart-treemap.min.js",
10
+ "unpkg": "dist/chartjs-chart-treemap.min.js",
11
+ "exports": {
12
+ "types": "./types/index.esm.d.ts",
13
+ "import": "./dist/chartjs-chart-treemap.esm.js",
14
+ "require": "./dist/chartjs-chart-treemap.min.js"
15
+ },
9
16
  "scripts": {
10
17
  "autobuild": "rollup -c -w",
11
18
  "build": "rollup -c",
12
- "dev": "karma start --no-signle-run --auto-watch --browsers chrome",
13
- "dev:ff": "karma start --no-signle-run --auto-watch --browsers firefox",
19
+ "dev": "karma start ./karma.conf.cjs --no-signle-run --auto-watch --browsers chrome",
20
+ "dev:ff": "karma start ./karma.conf.cjs --no-signle-run --auto-watch --browsers firefox",
14
21
  "docs": "npm run build && vuepress build docs --no-cache",
15
22
  "docs:dev": "concurrently \"npm:autobuild\" \"vuepress dev docs --no-cache\"",
16
23
  "lint": "concurrently -r \"npm:lint-*\"",
@@ -20,7 +27,7 @@
20
27
  "test": "cross-env NODE_ENV=test concurrently \"npm:test-*\"",
21
28
  "test-lint": "npm run lint",
22
29
  "test-types": "tsc -p types/tests/",
23
- "test-karma": "karma start --auto-watch --single-run"
30
+ "test-karma": "karma start ./karma.conf.cjs --auto-watch --single-run"
24
31
  },
25
32
  "repository": {
26
33
  "type": "git",
@@ -32,7 +39,8 @@
32
39
  "treemap"
33
40
  ],
34
41
  "files": [
35
- "dist/*.js",
42
+ "dist/*",
43
+ "!dist/docs/**",
36
44
  "types/index.esm.d.ts"
37
45
  ],
38
46
  "author": "Jukka Kurkela",
@@ -41,19 +49,18 @@
41
49
  "url": "https://github.com/kurkle/chartjs-chart-treemap/issues"
42
50
  },
43
51
  "devDependencies": {
44
- "@rollup/plugin-commonjs": "^23.0.0",
45
- "@rollup/plugin-json": "^5.0.0",
46
- "@rollup/plugin-node-resolve": "^15.0.0",
52
+ "@rollup/plugin-commonjs": "^23.0.2",
53
+ "@rollup/plugin-json": "^5.0.1",
54
+ "@rollup/plugin-node-resolve": "^15.0.1",
55
+ "@rollup/plugin-terser": "^0.1.0",
47
56
  "@typescript-eslint/eslint-plugin": "^5.4.0",
48
57
  "@typescript-eslint/parser": "^5.4.0",
49
- "chart.js": "^3.8.0",
50
- "chartjs-adapter-date-fns": "^2.0.0",
51
- "chartjs-plugin-datalabels": "^2.0.0",
52
- "chartjs-plugin-zoom": "^1.2.0",
58
+ "chart.js": "^4.0.1",
59
+ "chartjs-plugin-datalabels": "^2.2.0",
60
+ "chartjs-plugin-zoom": "^2.0.0",
53
61
  "chartjs-test-utils": "^0.5.0",
54
62
  "concurrently": "^7.4.0",
55
63
  "cross-env": "^7.0.3",
56
- "date-fns": "^2.20.2",
57
64
  "eslint": "^8.3.0",
58
65
  "eslint-config-chartjs": "^0.3.0",
59
66
  "eslint-plugin-es": "^4.1.0",
@@ -67,21 +74,20 @@
67
74
  "karma-jasmine": "^5.1.0",
68
75
  "karma-jasmine-html-reporter": "^2.0.0",
69
76
  "karma-rollup-preprocessor": "7.0.7",
70
- "karma-spec-reporter": "^0.0.34",
77
+ "karma-spec-reporter": "^0.0.35",
71
78
  "karma-summary-reporter": "^3.0.0",
72
79
  "ng-hammerjs": "^2.0.8",
73
80
  "pixelmatch": "^5.2.1",
74
- "rollup": "^2.79.1",
81
+ "rollup": "^3.3.0",
75
82
  "rollup-plugin-analyzer": "^4.0.0",
76
- "rollup-plugin-istanbul": "^3.0.0",
77
- "rollup-plugin-terser": "^7.0.2",
78
- "typescript": "^4.3.5",
79
- "vuepress": "^1.8.2",
83
+ "rollup-plugin-istanbul": "^4.0.0",
84
+ "typescript": "^4.7.4",
85
+ "vuepress": "^1.9.7",
80
86
  "vuepress-plugin-flexsearch": "^0.3.0",
81
87
  "vuepress-plugin-redirect": "^1.2.5",
82
88
  "vuepress-theme-chartjs": "^0.2.0"
83
89
  },
84
90
  "peerDependencies": {
85
- "chart.js": "^3.0.0"
91
+ "chart.js": ">=3.0.0"
86
92
  }
87
93
  }
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  Chart,
3
3
  ChartComponent,
4
+ CoreChartOptions,
4
5
  DatasetController,
5
6
  Element, VisualElement,
6
7
  ScriptableContext, Color, Scriptable, FontSpec
7
8
  } from 'chart.js';
8
- import { AnyObject } from 'chart.js/types/basic';
9
+
10
+ type AnyObject = Record<string, unknown>;
9
11
 
10
12
  type TreemapScriptableContext = ScriptableContext<'treemap'> & {
11
13
  raw: TreemapDataPoint