hoodcms 5.0.15 → 5.0.16

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/src/js/admin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * hoodcms v5.0.15
2
+ * hoodcms v5.0.16
3
3
  * A fully customisable content management system built in ASP.NET Core 5 & Bootstrap 5.
4
4
  * Written by George Whysall, 2022
5
5
  * Released under the GPL-3.0 License.
@@ -473,7 +473,7 @@
473
473
  * For LGPL see License.txt in the project root for license information.
474
474
  * For commercial licenses see https://www.tiny.cloud/
475
475
  *
476
- * Version: 5.10.2 (2021-11-17)
476
+ * Version: 5.10.3 (2022-02-09)
477
477
  */
478
478
 
479
479
  (function (module) {
@@ -16762,8 +16762,11 @@
16762
16762
  var children = from(node.childNodes);
16763
16763
  if (contentEditable && !hasContentEditableState) {
16764
16764
  var removed = removeNodeFormat(node);
16765
+ var currentNodeMatches = removed || exists(formatList, function (f) {
16766
+ return matchName$1(dom, node, f);
16767
+ });
16765
16768
  var parentNode = node.parentNode;
16766
- if (!removed && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
16769
+ if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
16767
16770
  removeNodeFormat(parentNode);
16768
16771
  }
16769
16772
  }
@@ -29471,8 +29474,8 @@
29471
29474
  suffix: null,
29472
29475
  $: DomQuery,
29473
29476
  majorVersion: '5',
29474
- minorVersion: '10.2',
29475
- releaseDate: '2021-11-17',
29477
+ minorVersion: '10.3',
29478
+ releaseDate: '2022-02-09',
29476
29479
  editors: legacyEditors,
29477
29480
  i18n: I18n,
29478
29481
  activeEditor: null,
@@ -30978,6 +30981,72 @@
30978
30981
  }.bind(this));
30979
30982
  };
30980
30983
  return MediaService;
30984
+ }());
30985
+ var MediaModal = /** @class */ (function () {
30986
+ function MediaModal() {
30987
+ $('body').on('click', '[data-hood-media=attach],[data-hood-media=select],[data-hood-media=gallery]', this.load.bind(this));
30988
+ $('body').on('click', '[data-hood-media=clear]', this.clear.bind(this));
30989
+ $('[data-hood-media=gallery]').each(this.initGallery.bind(this));
30990
+ }
30991
+ MediaModal.prototype.initGallery = function (index, element) {
30992
+ // setup the gallery list also, just a simple list jobby, and attach it to the
30993
+ var el = document.getElementById(element.dataset.hoodMediaTarget);
30994
+ if (el) {
30995
+ new DataList(el, {
30996
+ onComplete: function (data, sender) {
30997
+ Alerts.log('Finished loading gallery media list.', 'info');
30998
+ }.bind(this)
30999
+ });
31000
+ }
31001
+ };
31002
+ MediaModal.prototype.load = function (e) {
31003
+ e.preventDefault();
31004
+ e.stopPropagation();
31005
+ this.element = e.currentTarget;
31006
+ if (this.modal && this.modal.isOpen) {
31007
+ return;
31008
+ }
31009
+ this.modal = new ModalController({
31010
+ onComplete: function (sender) {
31011
+ this.list = document.getElementById('media-list');
31012
+ this.service = new MediaService(this.list, {
31013
+ action: this.element.dataset.hoodMedia,
31014
+ url: this.element.dataset.hoodMediaUrl,
31015
+ refresh: this.element.dataset.hoodMediaRefresh,
31016
+ target: this.element.dataset.hoodMediaTarget,
31017
+ size: this.element.dataset.hoodMediaSize,
31018
+ beforeAction: function (sender, mediaObject) {
31019
+ }.bind(this),
31020
+ onAction: function (sender, mediaObject) {
31021
+ this.modal.close();
31022
+ }.bind(this),
31023
+ onListLoad: function (sender) {
31024
+ },
31025
+ onListRender: function (data) {
31026
+ return data;
31027
+ },
31028
+ onListComplete: function (data) {
31029
+ },
31030
+ onError: function (jqXHR, textStatus, errorThrown) {
31031
+ },
31032
+ });
31033
+ }.bind(this)
31034
+ });
31035
+ this.modal.show($(e.currentTarget).data('hood-media-list'), e.currentTarget);
31036
+ };
31037
+ MediaModal.prototype.clear = function (e) {
31038
+ e.preventDefault();
31039
+ e.stopPropagation();
31040
+ Alerts.confirm({}, function (result) {
31041
+ if (result.isConfirmed) {
31042
+ Inline.post(e.currentTarget.href, e.currentTarget, function (response) {
31043
+ Response.process(response, 5000);
31044
+ MediaService.refresh(response.media, e.currentTarget.dataset.hoodMediaRefresh);
31045
+ }.bind(this));
31046
+ }
31047
+ }.bind(this));
31048
+ };
31049
+ return MediaModal;
30981
31050
  }());
30982
31051
 
30983
31052
  var Editors = /** @class */ (function () {
@@ -31714,9 +31783,9 @@
31714
31783
  };
31715
31784
 
31716
31785
  /*!
31717
- * Chart.js v3.6.0
31786
+ * Chart.js v3.7.1
31718
31787
  * https://www.chartjs.org
31719
- * (c) 2021 Chart.js Contributors
31788
+ * (c) 2022 Chart.js Contributors
31720
31789
  * Released under the MIT License
31721
31790
  */
31722
31791
  const requestAnimFrame = (function() {
@@ -31934,6 +32003,9 @@
31934
32003
  }
31935
32004
  return true;
31936
32005
  };
32006
+ function _isClickEvent(e) {
32007
+ return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
32008
+ }
31937
32009
 
31938
32010
  const PI = Math.PI;
31939
32011
  const TAU = 2 * PI;
@@ -32046,6 +32118,9 @@
32046
32118
  function _int16Range(value) {
32047
32119
  return _limitValue(value, -32768, 32767);
32048
32120
  }
32121
+ function _isBetween(value, start, end, epsilon = 1e-6) {
32122
+ return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
32123
+ }
32049
32124
 
32050
32125
  const atEdge = (t) => t === 0 || t === 1;
32051
32126
  const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
@@ -32755,6 +32830,7 @@
32755
32830
  this.scale = undefined;
32756
32831
  this.scales = {};
32757
32832
  this.showLine = true;
32833
+ this.drawActiveElementsOnTop = true;
32758
32834
  this.describe(_descriptors);
32759
32835
  }
32760
32836
  set(scope, values) {
@@ -33105,7 +33181,7 @@
33105
33181
  }
33106
33182
  return size * value;
33107
33183
  }
33108
- const numberOrZero$1 = v => +v || 0;
33184
+ const numberOrZero = v => +v || 0;
33109
33185
  function _readValueToProps(value, props) {
33110
33186
  const ret = {};
33111
33187
  const objProps = isObject(props);
@@ -33116,7 +33192,7 @@
33116
33192
  : prop => value[prop]
33117
33193
  : () => value;
33118
33194
  for (const prop of keys) {
33119
- ret[prop] = numberOrZero$1(read(prop));
33195
+ ret[prop] = numberOrZero(read(prop));
33120
33196
  }
33121
33197
  return ret;
33122
33198
  }
@@ -33323,8 +33399,7 @@
33323
33399
  },
33324
33400
  set(target, prop, value) {
33325
33401
  const storage = target._storage || (target._storage = getTarget());
33326
- storage[prop] = value;
33327
- delete target[prop];
33402
+ target[prop] = storage[prop] = value;
33328
33403
  delete target._keys;
33329
33404
  return true;
33330
33405
  }
@@ -33383,7 +33458,8 @@
33383
33458
  };
33384
33459
  }
33385
33460
  const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name;
33386
- const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters';
33461
+ const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' &&
33462
+ (Object.getPrototypeOf(value) === null || value.constructor === Object);
33387
33463
  function _cached(target, prop, resolve) {
33388
33464
  if (Object.prototype.hasOwnProperty.call(target, prop)) {
33389
33465
  return target[prop];
@@ -33414,7 +33490,7 @@
33414
33490
  _stack.add(prop);
33415
33491
  value = value(_context, _subProxy || receiver);
33416
33492
  _stack.delete(prop);
33417
- if (isObject(value)) {
33493
+ if (needsSubResolver(prop, value)) {
33418
33494
  value = createSubResolver(_proxy._scopes, _proxy, prop, value);
33419
33495
  }
33420
33496
  return value;
@@ -33439,12 +33515,12 @@
33439
33515
  }
33440
33516
  const getScope = (key, parent) => key === true ? parent
33441
33517
  : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
33442
- function addScopes(set, parentScopes, key, parentFallback) {
33518
+ function addScopes(set, parentScopes, key, parentFallback, value) {
33443
33519
  for (const parent of parentScopes) {
33444
33520
  const scope = getScope(key, parent);
33445
33521
  if (scope) {
33446
33522
  set.add(scope);
33447
- const fallback = resolveFallback(scope._fallback, key, scope);
33523
+ const fallback = resolveFallback(scope._fallback, key, value);
33448
33524
  if (defined(fallback) && fallback !== key && fallback !== parentFallback) {
33449
33525
  return fallback;
33450
33526
  }
@@ -33460,12 +33536,12 @@
33460
33536
  const allScopes = [...parentScopes, ...rootScopes];
33461
33537
  const set = new Set();
33462
33538
  set.add(value);
33463
- let key = addScopesFromKey(set, allScopes, prop, fallback || prop);
33539
+ let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
33464
33540
  if (key === null) {
33465
33541
  return false;
33466
33542
  }
33467
33543
  if (defined(fallback) && fallback !== prop) {
33468
- key = addScopesFromKey(set, allScopes, fallback, key);
33544
+ key = addScopesFromKey(set, allScopes, fallback, key, value);
33469
33545
  if (key === null) {
33470
33546
  return false;
33471
33547
  }
@@ -33473,9 +33549,9 @@
33473
33549
  return _createResolver(Array.from(set), [''], rootScopes, fallback,
33474
33550
  () => subGetTarget(resolver, prop, value));
33475
33551
  }
33476
- function addScopesFromKey(set, allScopes, key, fallback) {
33552
+ function addScopesFromKey(set, allScopes, key, fallback, item) {
33477
33553
  while (key) {
33478
- key = addScopes(set, allScopes, key, fallback);
33554
+ key = addScopes(set, allScopes, key, fallback, item);
33479
33555
  }
33480
33556
  return key;
33481
33557
  }
@@ -33966,7 +34042,7 @@
33966
34042
  };
33967
34043
  }
33968
34044
  return {
33969
- between: (n, s, e) => n >= Math.min(s, e) && n <= Math.max(e, s),
34045
+ between: _isBetween,
33970
34046
  compare: (a, b) => a - b,
33971
34047
  normalize: x => x
33972
34048
  };
@@ -34194,9 +34270,9 @@
34194
34270
  }
34195
34271
 
34196
34272
  /*!
34197
- * Chart.js v3.6.0
34273
+ * Chart.js v3.7.1
34198
34274
  * https://www.chartjs.org
34199
- * (c) 2021 Chart.js Contributors
34275
+ * (c) 2022 Chart.js Contributors
34200
34276
  * Released under the MIT License
34201
34277
  */
34202
34278
 
@@ -34919,6 +34995,7 @@
34919
34995
  const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
34920
34996
  this.options = config.createResolver(scopes, this.getContext());
34921
34997
  this._parsing = this.options.parsing;
34998
+ this._cachedDataOpts = {};
34922
34999
  }
34923
35000
  parse(start, count) {
34924
35001
  const {_cachedMeta: meta, _data: data} = this;
@@ -35090,8 +35167,6 @@
35090
35167
  }
35091
35168
  _update(mode) {
35092
35169
  const meta = this._cachedMeta;
35093
- this.configure();
35094
- this._cachedDataOpts = {};
35095
35170
  this.update(mode || 'default');
35096
35171
  meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
35097
35172
  }
@@ -35105,6 +35180,7 @@
35105
35180
  const active = [];
35106
35181
  const start = this._drawStart || 0;
35107
35182
  const count = this._drawCount || (elements.length - start);
35183
+ const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
35108
35184
  let i;
35109
35185
  if (meta.dataset) {
35110
35186
  meta.dataset.draw(ctx, area, start, count);
@@ -35114,7 +35190,7 @@
35114
35190
  if (element.hidden) {
35115
35191
  continue;
35116
35192
  }
35117
- if (element.active) {
35193
+ if (element.active && drawActiveElementsOnTop) {
35118
35194
  active.push(element);
35119
35195
  } else {
35120
35196
  element.draw(ctx, area);
@@ -35305,6 +35381,7 @@
35305
35381
  const [method, arg1, arg2] = args;
35306
35382
  this[method](arg1, arg2);
35307
35383
  }
35384
+ this.chart._dataChanges.push([this.index, ...args]);
35308
35385
  }
35309
35386
  _onDataPush() {
35310
35387
  const count = arguments.length;
@@ -35317,8 +35394,13 @@
35317
35394
  this._sync(['_removeElements', 0, 1]);
35318
35395
  }
35319
35396
  _onDataSplice(start, count) {
35320
- this._sync(['_removeElements', start, count]);
35321
- this._sync(['_insertElements', start, arguments.length - 2]);
35397
+ if (count) {
35398
+ this._sync(['_removeElements', start, count]);
35399
+ }
35400
+ const newCount = arguments.length - 2;
35401
+ if (newCount) {
35402
+ this._sync(['_insertElements', start, newCount]);
35403
+ }
35322
35404
  }
35323
35405
  _onDataUnshift() {
35324
35406
  this._sync(['_insertElements', 0, arguments.length]);
@@ -36098,9 +36180,6 @@
36098
36180
  meta = chart.getDatasetMeta(i);
36099
36181
  arcs = meta.data;
36100
36182
  controller = meta.controller;
36101
- if (controller !== this) {
36102
- controller.configure();
36103
- }
36104
36183
  break;
36105
36184
  }
36106
36185
  }
@@ -36705,7 +36784,7 @@
36705
36784
  function binarySearch(metaset, axis, value, intersect) {
36706
36785
  const {controller, data, _sorted} = metaset;
36707
36786
  const iScale = controller._cachedMeta.iScale;
36708
- if (iScale && axis === iScale.axis && _sorted && data.length) {
36787
+ if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
36709
36788
  const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;
36710
36789
  if (!intersect) {
36711
36790
  return lookupMethod(data, axis, value);
@@ -36757,19 +36836,30 @@
36757
36836
  optimizedEvaluateItems(chart, axis, position, evaluationFunc, true);
36758
36837
  return items;
36759
36838
  }
36760
- function getNearestItems(chart, position, axis, intersect, useFinalPosition) {
36761
- const distanceMetric = getDistanceMetricForAxis(axis);
36762
- let minDistance = Number.POSITIVE_INFINITY;
36839
+ function getNearestRadialItems(chart, position, axis, useFinalPosition) {
36763
36840
  let items = [];
36764
- if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {
36765
- return items;
36841
+ function evaluationFunc(element, datasetIndex, index) {
36842
+ const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition);
36843
+ const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y});
36844
+ if (_angleBetween(angle, startAngle, endAngle)) {
36845
+ items.push({element, datasetIndex, index});
36846
+ }
36766
36847
  }
36767
- const evaluationFunc = function(element, datasetIndex, index) {
36768
- if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) {
36848
+ optimizedEvaluateItems(chart, axis, position, evaluationFunc);
36849
+ return items;
36850
+ }
36851
+ function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) {
36852
+ let items = [];
36853
+ const distanceMetric = getDistanceMetricForAxis(axis);
36854
+ let minDistance = Number.POSITIVE_INFINITY;
36855
+ function evaluationFunc(element, datasetIndex, index) {
36856
+ const inRange = element.inRange(position.x, position.y, useFinalPosition);
36857
+ if (intersect && !inRange) {
36769
36858
  return;
36770
36859
  }
36771
36860
  const center = element.getCenterPoint(useFinalPosition);
36772
- if (!_isPointInArea(center, chart.chartArea, chart._minPadding) && !element.inRange(position.x, position.y, useFinalPosition)) {
36861
+ const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding);
36862
+ if (!pointInArea && !inRange) {
36773
36863
  return;
36774
36864
  }
36775
36865
  const distance = distanceMetric(position, center);
@@ -36779,10 +36869,18 @@
36779
36869
  } else if (distance === minDistance) {
36780
36870
  items.push({element, datasetIndex, index});
36781
36871
  }
36782
- };
36872
+ }
36783
36873
  optimizedEvaluateItems(chart, axis, position, evaluationFunc);
36784
36874
  return items;
36785
36875
  }
36876
+ function getNearestItems(chart, position, axis, intersect, useFinalPosition) {
36877
+ if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {
36878
+ return [];
36879
+ }
36880
+ return axis === 'r' && !intersect
36881
+ ? getNearestRadialItems(chart, position, axis, useFinalPosition)
36882
+ : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition);
36883
+ }
36786
36884
  function getAxisItems(chart, e, options, useFinalPosition) {
36787
36885
  const position = getRelativePosition(e, chart);
36788
36886
  const items = [];
@@ -36850,12 +36948,10 @@
36850
36948
  return getNearestItems(chart, position, axis, options.intersect, useFinalPosition);
36851
36949
  },
36852
36950
  x(chart, e, options, useFinalPosition) {
36853
- options.axis = 'x';
36854
- return getAxisItems(chart, e, options, useFinalPosition);
36951
+ return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition);
36855
36952
  },
36856
36953
  y(chart, e, options, useFinalPosition) {
36857
- options.axis = 'y';
36858
- return getAxisItems(chart, e, options, useFinalPosition);
36954
+ return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition);
36859
36955
  }
36860
36956
  }
36861
36957
  };
@@ -37166,7 +37262,7 @@
37166
37262
  each(boxes.chartArea, (layout) => {
37167
37263
  const box = layout.box;
37168
37264
  Object.assign(box, chart.chartArea);
37169
- box.update(chartArea.w, chartArea.h);
37265
+ box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0});
37170
37266
  });
37171
37267
  }
37172
37268
  };
@@ -37271,15 +37367,23 @@
37271
37367
  y: y !== undefined ? y : null,
37272
37368
  };
37273
37369
  }
37370
+ function nodeListContains(nodeList, canvas) {
37371
+ for (const node of nodeList) {
37372
+ if (node === canvas || node.contains(canvas)) {
37373
+ return true;
37374
+ }
37375
+ }
37376
+ }
37274
37377
  function createAttachObserver(chart, type, listener) {
37275
37378
  const canvas = chart.canvas;
37276
37379
  const observer = new MutationObserver(entries => {
37380
+ let trigger = false;
37277
37381
  for (const entry of entries) {
37278
- for (const node of entry.addedNodes) {
37279
- if (node === canvas || node.contains(canvas)) {
37280
- return listener();
37281
- }
37282
- }
37382
+ trigger = trigger || nodeListContains(entry.addedNodes, canvas);
37383
+ trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
37384
+ }
37385
+ if (trigger) {
37386
+ listener();
37283
37387
  }
37284
37388
  });
37285
37389
  observer.observe(document, {childList: true, subtree: true});
@@ -37288,12 +37392,13 @@
37288
37392
  function createDetachObserver(chart, type, listener) {
37289
37393
  const canvas = chart.canvas;
37290
37394
  const observer = new MutationObserver(entries => {
37395
+ let trigger = false;
37291
37396
  for (const entry of entries) {
37292
- for (const node of entry.removedNodes) {
37293
- if (node === canvas || node.contains(canvas)) {
37294
- return listener();
37295
- }
37296
- }
37397
+ trigger = trigger || nodeListContains(entry.removedNodes, canvas);
37398
+ trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
37399
+ }
37400
+ if (trigger) {
37401
+ listener();
37297
37402
  }
37298
37403
  });
37299
37404
  observer.observe(document, {childList: true, subtree: true});
@@ -39059,7 +39164,7 @@
39059
39164
  }
39060
39165
  const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
39061
39166
  const result = this._notify(descriptors, chart, hook, args);
39062
- if (hook === 'destroy') {
39167
+ if (hook === 'afterDestroy') {
39063
39168
  this._notify(descriptors, chart, 'stop');
39064
39169
  this._notify(this._init, chart, 'uninstall');
39065
39170
  }
@@ -39435,7 +39540,7 @@
39435
39540
  return false;
39436
39541
  }
39437
39542
 
39438
- var version = "3.6.0";
39543
+ var version = "3.7.1";
39439
39544
 
39440
39545
  const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea'];
39441
39546
  function positionIsHorizontal(position, axis) {
@@ -39475,6 +39580,28 @@
39475
39580
  const canvas = getCanvas(key);
39476
39581
  return Object.values(instances).filter((c) => c.canvas === canvas).pop();
39477
39582
  };
39583
+ function moveNumericKeys(obj, start, move) {
39584
+ const keys = Object.keys(obj);
39585
+ for (const key of keys) {
39586
+ const intKey = +key;
39587
+ if (intKey >= start) {
39588
+ const value = obj[key];
39589
+ delete obj[key];
39590
+ if (move > 0 || intKey > start) {
39591
+ obj[intKey + move] = value;
39592
+ }
39593
+ }
39594
+ }
39595
+ }
39596
+ function determineLastEvent(e, lastEvent, inChartArea, isClick) {
39597
+ if (!inChartArea || e.type === 'mouseout') {
39598
+ return null;
39599
+ }
39600
+ if (isClick) {
39601
+ return lastEvent;
39602
+ }
39603
+ return e;
39604
+ }
39478
39605
  class Chart {
39479
39606
  constructor(item, userConfig) {
39480
39607
  const config = this.config = new Config(userConfig);
@@ -39519,6 +39646,7 @@
39519
39646
  this._animationsDisabled = undefined;
39520
39647
  this.$context = undefined;
39521
39648
  this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0);
39649
+ this._dataChanges = [];
39522
39650
  instances[this.id] = this;
39523
39651
  if (!context || !canvas) {
39524
39652
  console.error("Failed to create chart: can't acquire context from the given item");
@@ -39738,18 +39866,10 @@
39738
39866
  const config = this.config;
39739
39867
  config.update();
39740
39868
  const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
39741
- each(this.scales, (scale) => {
39742
- layouts.removeBox(this, scale);
39743
- });
39744
39869
  const animsDisabled = this._animationsDisabled = !options.animation;
39745
- this.ensureScalesHaveIDs();
39746
- this.buildOrUpdateScales();
39747
- const existingEvents = new Set(Object.keys(this._listeners));
39748
- const newEvents = new Set(options.events);
39749
- if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
39750
- this.unbindEvents();
39751
- this.bindEvents();
39752
- }
39870
+ this._updateScales();
39871
+ this._checkEventBindings();
39872
+ this._updateHiddenIndices();
39753
39873
  this._plugins.invalidate();
39754
39874
  if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) {
39755
39875
  return;
@@ -39773,11 +39893,60 @@
39773
39893
  this._updateDatasets(mode);
39774
39894
  this.notifyPlugins('afterUpdate', {mode});
39775
39895
  this._layers.sort(compare2Level('z', '_idx'));
39776
- if (this._lastEvent) {
39777
- this._eventHandler(this._lastEvent, true);
39896
+ const {_active, _lastEvent} = this;
39897
+ if (_lastEvent) {
39898
+ this._eventHandler(_lastEvent, true);
39899
+ } else if (_active.length) {
39900
+ this._updateHoverStyles(_active, _active, true);
39778
39901
  }
39779
39902
  this.render();
39780
39903
  }
39904
+ _updateScales() {
39905
+ each(this.scales, (scale) => {
39906
+ layouts.removeBox(this, scale);
39907
+ });
39908
+ this.ensureScalesHaveIDs();
39909
+ this.buildOrUpdateScales();
39910
+ }
39911
+ _checkEventBindings() {
39912
+ const options = this.options;
39913
+ const existingEvents = new Set(Object.keys(this._listeners));
39914
+ const newEvents = new Set(options.events);
39915
+ if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
39916
+ this.unbindEvents();
39917
+ this.bindEvents();
39918
+ }
39919
+ }
39920
+ _updateHiddenIndices() {
39921
+ const {_hiddenIndices} = this;
39922
+ const changes = this._getUniformDataChanges() || [];
39923
+ for (const {method, start, count} of changes) {
39924
+ const move = method === '_removeElements' ? -count : count;
39925
+ moveNumericKeys(_hiddenIndices, start, move);
39926
+ }
39927
+ }
39928
+ _getUniformDataChanges() {
39929
+ const _dataChanges = this._dataChanges;
39930
+ if (!_dataChanges || !_dataChanges.length) {
39931
+ return;
39932
+ }
39933
+ this._dataChanges = [];
39934
+ const datasetCount = this.data.datasets.length;
39935
+ const makeSet = (idx) => new Set(
39936
+ _dataChanges
39937
+ .filter(c => c[0] === idx)
39938
+ .map((c, i) => i + ',' + c.splice(1).join(','))
39939
+ );
39940
+ const changeSet = makeSet(0);
39941
+ for (let i = 1; i < datasetCount; i++) {
39942
+ if (!setsEqual(changeSet, makeSet(i))) {
39943
+ return;
39944
+ }
39945
+ }
39946
+ return Array.from(changeSet)
39947
+ .map(c => c.split(','))
39948
+ .map(a => ({method: a[1], start: +a[2], count: +a[3]}));
39949
+ }
39781
39950
  _updateLayout(minPadding) {
39782
39951
  if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) {
39783
39952
  return;
@@ -39804,6 +39973,9 @@
39804
39973
  if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) {
39805
39974
  return;
39806
39975
  }
39976
+ for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
39977
+ this.getDatasetMeta(i).controller.configure();
39978
+ }
39807
39979
  for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
39808
39980
  this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode);
39809
39981
  }
@@ -39998,6 +40170,7 @@
39998
40170
  }
39999
40171
  }
40000
40172
  destroy() {
40173
+ this.notifyPlugins('beforeDestroy');
40001
40174
  const {canvas, ctx} = this;
40002
40175
  this._stop();
40003
40176
  this.config.clearCache();
@@ -40010,6 +40183,7 @@
40010
40183
  }
40011
40184
  this.notifyPlugins('destroy');
40012
40185
  delete instances[this.id];
40186
+ this.notifyPlugins('afterDestroy');
40013
40187
  }
40014
40188
  toBase64Image(...args) {
40015
40189
  return this.canvas.toDataURL(...args);
@@ -40122,6 +40296,7 @@
40122
40296
  const changed = !_elementsEqual(active, lastActive);
40123
40297
  if (changed) {
40124
40298
  this._active = active;
40299
+ this._lastEvent = null;
40125
40300
  this._updateHoverStyles(active, lastActive);
40126
40301
  }
40127
40302
  }
@@ -40141,12 +40316,17 @@
40141
40316
  }
40142
40317
  }
40143
40318
  _eventHandler(e, replay) {
40144
- const args = {event: e, replay, cancelable: true};
40319
+ const args = {
40320
+ event: e,
40321
+ replay,
40322
+ cancelable: true,
40323
+ inChartArea: _isPointInArea(e, this.chartArea, this._minPadding)
40324
+ };
40145
40325
  const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type);
40146
40326
  if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
40147
40327
  return;
40148
40328
  }
40149
- const changed = this._handleEvent(e, replay);
40329
+ const changed = this._handleEvent(e, replay, args.inChartArea);
40150
40330
  args.cancelable = false;
40151
40331
  this.notifyPlugins('afterEvent', args, eventFilter);
40152
40332
  if (changed || args.changed) {
@@ -40154,25 +40334,20 @@
40154
40334
  }
40155
40335
  return this;
40156
40336
  }
40157
- _handleEvent(e, replay) {
40337
+ _handleEvent(e, replay, inChartArea) {
40158
40338
  const {_active: lastActive = [], options} = this;
40159
- const hoverOptions = options.hover;
40160
40339
  const useFinalPosition = replay;
40161
- let active = [];
40162
- let changed = false;
40163
- let lastEvent = null;
40164
- if (e.type !== 'mouseout') {
40165
- active = this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
40166
- lastEvent = e.type === 'click' ? this._lastEvent : e;
40167
- }
40168
- this._lastEvent = null;
40169
- if (_isPointInArea(e, this.chartArea, this._minPadding)) {
40340
+ const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
40341
+ const isClick = _isClickEvent(e);
40342
+ const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
40343
+ if (inChartArea) {
40344
+ this._lastEvent = null;
40170
40345
  callback(options.onHover, [e, active, this], this);
40171
- if (e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu') {
40346
+ if (isClick) {
40172
40347
  callback(options.onClick, [e, active, this], this);
40173
40348
  }
40174
40349
  }
40175
- changed = !_elementsEqual(active, lastActive);
40350
+ const changed = !_elementsEqual(active, lastActive);
40176
40351
  if (changed || replay) {
40177
40352
  this._active = active;
40178
40353
  this._updateHoverStyles(active, lastActive, replay);
@@ -40180,6 +40355,16 @@
40180
40355
  this._lastEvent = lastEvent;
40181
40356
  return changed;
40182
40357
  }
40358
+ _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
40359
+ if (e.type === 'mouseout') {
40360
+ return [];
40361
+ }
40362
+ if (!inChartArea) {
40363
+ return lastActive;
40364
+ }
40365
+ const hoverOptions = this.options.hover;
40366
+ return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
40367
+ }
40183
40368
  }
40184
40369
  const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate());
40185
40370
  const enumerable = true;
@@ -40353,16 +40538,17 @@
40353
40538
  }
40354
40539
  function drawBorder(ctx, element, offset, spacing, endAngle) {
40355
40540
  const {options} = element;
40541
+ const {borderWidth, borderJoinStyle} = options;
40356
40542
  const inner = options.borderAlign === 'inner';
40357
- if (!options.borderWidth) {
40543
+ if (!borderWidth) {
40358
40544
  return;
40359
40545
  }
40360
40546
  if (inner) {
40361
- ctx.lineWidth = options.borderWidth * 2;
40362
- ctx.lineJoin = 'round';
40547
+ ctx.lineWidth = borderWidth * 2;
40548
+ ctx.lineJoin = borderJoinStyle || 'round';
40363
40549
  } else {
40364
- ctx.lineWidth = options.borderWidth;
40365
- ctx.lineJoin = 'bevel';
40550
+ ctx.lineWidth = borderWidth;
40551
+ ctx.lineJoin = borderJoinStyle || 'bevel';
40366
40552
  }
40367
40553
  if (element.fullCircles) {
40368
40554
  drawFullCircleBorders(ctx, element, inner);
@@ -40399,8 +40585,9 @@
40399
40585
  'circumference'
40400
40586
  ], useFinalPosition);
40401
40587
  const rAdjust = this.options.spacing / 2;
40402
- const betweenAngles = circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
40403
- const withinRadius = (distance >= innerRadius + rAdjust && distance <= outerRadius + rAdjust);
40588
+ const _circumference = valueOrDefault(circumference, endAngle - startAngle);
40589
+ const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
40590
+ const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);
40404
40591
  return (betweenAngles && withinRadius);
40405
40592
  }
40406
40593
  getCenterPoint(useFinalPosition) {
@@ -40454,6 +40641,7 @@
40454
40641
  ArcElement.defaults = {
40455
40642
  borderAlign: 'center',
40456
40643
  borderColor: '#fff',
40644
+ borderJoinStyle: undefined,
40457
40645
  borderRadius: 0,
40458
40646
  borderWidth: 2,
40459
40647
  offset: 0,
@@ -40888,8 +41076,8 @@
40888
41076
  const skipBoth = skipX && skipY;
40889
41077
  const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
40890
41078
  return bounds
40891
- && (skipX || x >= bounds.left && x <= bounds.right)
40892
- && (skipY || y >= bounds.top && y <= bounds.bottom);
41079
+ && (skipX || _isBetween(x, bounds.left, bounds.right))
41080
+ && (skipY || _isBetween(y, bounds.top, bounds.bottom));
40893
41081
  }
40894
41082
  function hasRadius(radius) {
40895
41083
  return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
@@ -41061,7 +41249,7 @@
41061
41249
  };
41062
41250
  }
41063
41251
  function getTooltipSize(tooltip, options) {
41064
- const ctx = tooltip._chart.ctx;
41252
+ const ctx = tooltip.chart.ctx;
41065
41253
  const {body, footer, title} = tooltip;
41066
41254
  const {boxWidth, boxHeight} = options;
41067
41255
  const bodyFont = toFont(options.bodyFont);
@@ -41149,9 +41337,9 @@
41149
41337
  return xAlign;
41150
41338
  }
41151
41339
  function determineAlignment(chart, options, size) {
41152
- const yAlign = options.yAlign || determineYAlign(chart, size);
41340
+ const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
41153
41341
  return {
41154
- xAlign: options.xAlign || determineXAlign(chart, options, size, yAlign),
41342
+ xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
41155
41343
  yAlign
41156
41344
  };
41157
41345
  }
@@ -41189,9 +41377,9 @@
41189
41377
  x -= paddingAndSize;
41190
41378
  }
41191
41379
  } else if (xAlign === 'left') {
41192
- x -= Math.max(topLeft, bottomLeft) + caretPadding;
41380
+ x -= Math.max(topLeft, bottomLeft) + caretSize;
41193
41381
  } else if (xAlign === 'right') {
41194
- x += Math.max(topRight, bottomRight) + caretPadding;
41382
+ x += Math.max(topRight, bottomRight) + caretSize;
41195
41383
  }
41196
41384
  return {
41197
41385
  x: _limitValue(x, 0, chart.width - size.width),
@@ -41225,13 +41413,14 @@
41225
41413
  super();
41226
41414
  this.opacity = 0;
41227
41415
  this._active = [];
41228
- this._chart = config._chart;
41229
41416
  this._eventPosition = undefined;
41230
41417
  this._size = undefined;
41231
41418
  this._cachedAnimations = undefined;
41232
41419
  this._tooltipItems = [];
41233
41420
  this.$animations = undefined;
41234
41421
  this.$context = undefined;
41422
+ this.chart = config.chart || config._chart;
41423
+ this._chart = this.chart;
41235
41424
  this.options = config.options;
41236
41425
  this.dataPoints = undefined;
41237
41426
  this.title = undefined;
@@ -41261,10 +41450,10 @@
41261
41450
  if (cached) {
41262
41451
  return cached;
41263
41452
  }
41264
- const chart = this._chart;
41453
+ const chart = this.chart;
41265
41454
  const options = this.options.setContext(this.getContext());
41266
41455
  const opts = options.enabled && chart.options.animation && options.animations;
41267
- const animations = new Animations(this._chart, opts);
41456
+ const animations = new Animations(this.chart, opts);
41268
41457
  if (opts._cacheable) {
41269
41458
  this._cachedAnimations = Object.freeze(animations);
41270
41459
  }
@@ -41272,7 +41461,7 @@
41272
41461
  }
41273
41462
  getContext() {
41274
41463
  return this.$context ||
41275
- (this.$context = createTooltipContext(this._chart.getContext(), this, this._tooltipItems));
41464
+ (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
41276
41465
  }
41277
41466
  getTitle(context, options) {
41278
41467
  const {callbacks} = options;
@@ -41321,14 +41510,14 @@
41321
41510
  }
41322
41511
  _createItems(options) {
41323
41512
  const active = this._active;
41324
- const data = this._chart.data;
41513
+ const data = this.chart.data;
41325
41514
  const labelColors = [];
41326
41515
  const labelPointStyles = [];
41327
41516
  const labelTextColors = [];
41328
41517
  let tooltipItems = [];
41329
41518
  let i, len;
41330
41519
  for (i = 0, len = active.length; i < len; ++i) {
41331
- tooltipItems.push(createTooltipItem(this._chart, active[i]));
41520
+ tooltipItems.push(createTooltipItem(this.chart, active[i]));
41332
41521
  }
41333
41522
  if (options.filter) {
41334
41523
  tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));
@@ -41369,8 +41558,8 @@
41369
41558
  this.footer = this.getFooter(tooltipItems, options);
41370
41559
  const size = this._size = getTooltipSize(this, options);
41371
41560
  const positionAndSize = Object.assign({}, position, size);
41372
- const alignment = determineAlignment(this._chart, options, positionAndSize);
41373
- const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this._chart);
41561
+ const alignment = determineAlignment(this.chart, options, positionAndSize);
41562
+ const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
41374
41563
  this.xAlign = alignment.xAlign;
41375
41564
  this.yAlign = alignment.yAlign;
41376
41565
  properties = {
@@ -41389,7 +41578,7 @@
41389
41578
  this._resolveAnimations().update(this, properties);
41390
41579
  }
41391
41580
  if (changed && options.external) {
41392
- options.external.call(this, {chart: this._chart, tooltip: this, replay});
41581
+ options.external.call(this, {chart: this.chart, tooltip: this, replay});
41393
41582
  }
41394
41583
  }
41395
41584
  drawCaret(tooltipPoint, ctx, size, options) {
@@ -41627,7 +41816,7 @@
41627
41816
  }
41628
41817
  }
41629
41818
  _updateAnimationTarget(options) {
41630
- const chart = this._chart;
41819
+ const chart = this.chart;
41631
41820
  const anims = this.$animations;
41632
41821
  const animX = anims && anims.x;
41633
41822
  const animY = anims && anims.y;
@@ -41688,7 +41877,7 @@
41688
41877
  setActiveElements(activeElements, eventPosition) {
41689
41878
  const lastActive = this._active;
41690
41879
  const active = activeElements.map(({datasetIndex, index}) => {
41691
- const meta = this._chart.getDatasetMeta(datasetIndex);
41880
+ const meta = this.chart.getDatasetMeta(datasetIndex);
41692
41881
  if (!meta) {
41693
41882
  throw new Error('Cannot find a dataset at index ' + datasetIndex);
41694
41883
  }
@@ -41703,22 +41892,20 @@
41703
41892
  if (changed || positionChanged) {
41704
41893
  this._active = active;
41705
41894
  this._eventPosition = eventPosition;
41895
+ this._ignoreReplayEvents = true;
41706
41896
  this.update(true);
41707
41897
  }
41708
41898
  }
41709
- handleEvent(e, replay) {
41899
+ handleEvent(e, replay, inChartArea = true) {
41900
+ if (replay && this._ignoreReplayEvents) {
41901
+ return false;
41902
+ }
41903
+ this._ignoreReplayEvents = false;
41710
41904
  const options = this.options;
41711
41905
  const lastActive = this._active || [];
41712
- let changed = false;
41713
- let active = [];
41714
- if (e.type !== 'mouseout') {
41715
- active = this._chart.getElementsAtEventForMode(e, options.mode, options, replay);
41716
- if (options.reverse) {
41717
- active.reverse();
41718
- }
41719
- }
41906
+ const active = this._getActiveElements(e, lastActive, replay, inChartArea);
41720
41907
  const positionChanged = this._positionChanged(active, e);
41721
- changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
41908
+ const changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
41722
41909
  if (changed) {
41723
41910
  this._active = active;
41724
41911
  if (options.enabled || options.external) {
@@ -41731,6 +41918,20 @@
41731
41918
  }
41732
41919
  return changed;
41733
41920
  }
41921
+ _getActiveElements(e, lastActive, replay, inChartArea) {
41922
+ const options = this.options;
41923
+ if (e.type === 'mouseout') {
41924
+ return [];
41925
+ }
41926
+ if (!inChartArea) {
41927
+ return lastActive;
41928
+ }
41929
+ const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
41930
+ if (options.reverse) {
41931
+ active.reverse();
41932
+ }
41933
+ return active;
41934
+ }
41734
41935
  _positionChanged(active, e) {
41735
41936
  const {caretX, caretY, options} = this;
41736
41937
  const position = positioners[options.position].call(this, active, e);
@@ -41739,13 +41940,19 @@
41739
41940
  }
41740
41941
  Tooltip.positioners = positioners;
41741
41942
 
41742
- const addIfString = (labels, raw, index) => typeof raw === 'string'
41743
- ? labels.push(raw) - 1
41744
- : isNaN(raw) ? null : index;
41745
- function findOrAddLabel(labels, raw, index) {
41943
+ const addIfString = (labels, raw, index, addedLabels) => {
41944
+ if (typeof raw === 'string') {
41945
+ index = labels.push(raw) - 1;
41946
+ addedLabels.unshift({index, label: raw});
41947
+ } else if (isNaN(raw)) {
41948
+ index = null;
41949
+ }
41950
+ return index;
41951
+ };
41952
+ function findOrAddLabel(labels, raw, index, addedLabels) {
41746
41953
  const first = labels.indexOf(raw);
41747
41954
  if (first === -1) {
41748
- return addIfString(labels, raw, index);
41955
+ return addIfString(labels, raw, index, addedLabels);
41749
41956
  }
41750
41957
  const last = labels.lastIndexOf(raw);
41751
41958
  return first !== last ? index : first;
@@ -41756,6 +41963,20 @@
41756
41963
  super(cfg);
41757
41964
  this._startValue = undefined;
41758
41965
  this._valueRange = 0;
41966
+ this._addedLabels = [];
41967
+ }
41968
+ init(scaleOptions) {
41969
+ const added = this._addedLabels;
41970
+ if (added.length) {
41971
+ const labels = this.getLabels();
41972
+ for (const {index, label} of added) {
41973
+ if (labels[index] === label) {
41974
+ labels.splice(index, 1);
41975
+ }
41976
+ }
41977
+ this._addedLabels = [];
41978
+ }
41979
+ super.init(scaleOptions);
41759
41980
  }
41760
41981
  parse(raw, index) {
41761
41982
  if (isNullOrUndef(raw)) {
@@ -41763,7 +41984,7 @@
41763
41984
  }
41764
41985
  const labels = this.getLabels();
41765
41986
  index = isFinite(index) && labels[index] === raw ? index
41766
- : findOrAddLabel(labels, raw, valueOrDefault(index, raw));
41987
+ : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels);
41767
41988
  return validIndex(index, labels.length - 1);
41768
41989
  }
41769
41990
  determineDataLimits() {
@@ -42040,7 +42261,7 @@
42040
42261
  this._valueRange = end - start;
42041
42262
  }
42042
42263
  getLabelForValue(value) {
42043
- return formatNumber(value, this.chart.options.locale);
42264
+ return formatNumber(value, this.chart.options.locale, this.options.ticks.format);
42044
42265
  }
42045
42266
  }
42046
42267
 
@@ -42173,7 +42394,9 @@
42173
42394
  return ticks;
42174
42395
  }
42175
42396
  getLabelForValue(value) {
42176
- return value === undefined ? '0' : formatNumber(value, this.chart.options.locale);
42397
+ return value === undefined
42398
+ ? '0'
42399
+ : formatNumber(value, this.chart.options.locale, this.options.ticks.format);
42177
42400
  }
42178
42401
  configure() {
42179
42402
  const start = this.min;
@@ -42240,57 +42463,69 @@
42240
42463
  };
42241
42464
  }
42242
42465
  function fitWithPointLabels(scale) {
42243
- const furthestLimits = {
42244
- l: 0,
42245
- r: scale.width,
42246
- t: 0,
42247
- b: scale.height - scale.paddingTop
42466
+ const orig = {
42467
+ l: scale.left + scale._padding.left,
42468
+ r: scale.right - scale._padding.right,
42469
+ t: scale.top + scale._padding.top,
42470
+ b: scale.bottom - scale._padding.bottom
42248
42471
  };
42249
- const furthestAngles = {};
42472
+ const limits = Object.assign({}, orig);
42250
42473
  const labelSizes = [];
42251
42474
  const padding = [];
42252
- const valueCount = scale.getLabels().length;
42475
+ const valueCount = scale._pointLabels.length;
42476
+ const pointLabelOpts = scale.options.pointLabels;
42477
+ const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0;
42253
42478
  for (let i = 0; i < valueCount; i++) {
42254
- const opts = scale.options.pointLabels.setContext(scale.getPointLabelContext(i));
42479
+ const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
42255
42480
  padding[i] = opts.padding;
42256
- const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i]);
42481
+ const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
42257
42482
  const plFont = toFont(opts.font);
42258
42483
  const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
42259
42484
  labelSizes[i] = textSize;
42260
- const angleRadians = scale.getIndexAngle(i);
42261
- const angle = toDegrees(angleRadians);
42485
+ const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle);
42486
+ const angle = Math.round(toDegrees(angleRadians));
42262
42487
  const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
42263
42488
  const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
42264
- if (hLimits.start < furthestLimits.l) {
42265
- furthestLimits.l = hLimits.start;
42266
- furthestAngles.l = angleRadians;
42267
- }
42268
- if (hLimits.end > furthestLimits.r) {
42269
- furthestLimits.r = hLimits.end;
42270
- furthestAngles.r = angleRadians;
42271
- }
42272
- if (vLimits.start < furthestLimits.t) {
42273
- furthestLimits.t = vLimits.start;
42274
- furthestAngles.t = angleRadians;
42275
- }
42276
- if (vLimits.end > furthestLimits.b) {
42277
- furthestLimits.b = vLimits.end;
42278
- furthestAngles.b = angleRadians;
42279
- }
42489
+ updateLimits(limits, orig, angleRadians, hLimits, vLimits);
42280
42490
  }
42281
- scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles);
42491
+ scale.setCenterPoint(
42492
+ orig.l - limits.l,
42493
+ limits.r - orig.r,
42494
+ orig.t - limits.t,
42495
+ limits.b - orig.b
42496
+ );
42282
42497
  scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
42283
42498
  }
42499
+ function updateLimits(limits, orig, angle, hLimits, vLimits) {
42500
+ const sin = Math.abs(Math.sin(angle));
42501
+ const cos = Math.abs(Math.cos(angle));
42502
+ let x = 0;
42503
+ let y = 0;
42504
+ if (hLimits.start < orig.l) {
42505
+ x = (orig.l - hLimits.start) / sin;
42506
+ limits.l = Math.min(limits.l, orig.l - x);
42507
+ } else if (hLimits.end > orig.r) {
42508
+ x = (hLimits.end - orig.r) / sin;
42509
+ limits.r = Math.max(limits.r, orig.r + x);
42510
+ }
42511
+ if (vLimits.start < orig.t) {
42512
+ y = (orig.t - vLimits.start) / cos;
42513
+ limits.t = Math.min(limits.t, orig.t - y);
42514
+ } else if (vLimits.end > orig.b) {
42515
+ y = (vLimits.end - orig.b) / cos;
42516
+ limits.b = Math.max(limits.b, orig.b + y);
42517
+ }
42518
+ }
42284
42519
  function buildPointLabelItems(scale, labelSizes, padding) {
42285
42520
  const items = [];
42286
- const valueCount = scale.getLabels().length;
42521
+ const valueCount = scale._pointLabels.length;
42287
42522
  const opts = scale.options;
42288
- const tickBackdropHeight = getTickBackdropHeight(opts);
42289
- const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
42523
+ const extra = getTickBackdropHeight(opts) / 2;
42524
+ const outerDistance = scale.drawingArea;
42525
+ const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0;
42290
42526
  for (let i = 0; i < valueCount; i++) {
42291
- const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
42292
- const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i]);
42293
- const angle = toDegrees(scale.getIndexAngle(i));
42527
+ const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle);
42528
+ const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI)));
42294
42529
  const size = labelSizes[i];
42295
42530
  const y = yForAngle(pointLabelPosition.y, size.h, angle);
42296
42531
  const textAlign = getTextAlignForAngle(angle);
@@ -42388,9 +42623,6 @@
42388
42623
  ctx.stroke();
42389
42624
  ctx.restore();
42390
42625
  }
42391
- function numberOrZero(param) {
42392
- return isNumber(param) ? param : 0;
42393
- }
42394
42626
  function createPointLabelContext(parent, index, label) {
42395
42627
  return createContext(parent, {
42396
42628
  label,
@@ -42408,12 +42640,12 @@
42408
42640
  this._pointLabelItems = [];
42409
42641
  }
42410
42642
  setDimensions() {
42411
- this.width = this.maxWidth;
42412
- this.height = this.maxHeight;
42413
- this.paddingTop = getTickBackdropHeight(this.options) / 2;
42414
- this.xCenter = Math.floor(this.width / 2);
42415
- this.yCenter = Math.floor((this.height - this.paddingTop) / 2);
42416
- this.drawingArea = Math.min(this.height - this.paddingTop, this.width) / 2;
42643
+ const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2);
42644
+ const w = this.width = this.maxWidth - padding.width;
42645
+ const h = this.height = this.maxHeight - padding.height;
42646
+ this.xCenter = Math.floor(this.left + w / 2 + padding.left);
42647
+ this.yCenter = Math.floor(this.top + h / 2 + padding.top);
42648
+ this.drawingArea = Math.floor(Math.min(w, h) / 2);
42417
42649
  }
42418
42650
  determineDataLimits() {
42419
42651
  const {min, max} = this.getMinMax(false);
@@ -42426,10 +42658,12 @@
42426
42658
  }
42427
42659
  generateTickLabels(ticks) {
42428
42660
  LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
42429
- this._pointLabels = this.getLabels().map((value, index) => {
42430
- const label = callback(this.options.pointLabels.callback, [value, index], this);
42431
- return label || label === 0 ? label : '';
42432
- });
42661
+ this._pointLabels = this.getLabels()
42662
+ .map((value, index) => {
42663
+ const label = callback(this.options.pointLabels.callback, [value, index], this);
42664
+ return label || label === 0 ? label : '';
42665
+ })
42666
+ .filter((v, i) => this.chart.getDataVisibility(i));
42433
42667
  }
42434
42668
  fit() {
42435
42669
  const opts = this.options;
@@ -42439,30 +42673,13 @@
42439
42673
  this.setCenterPoint(0, 0, 0, 0);
42440
42674
  }
42441
42675
  }
42442
- _setReductions(largestPossibleRadius, furthestLimits, furthestAngles) {
42443
- let radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
42444
- let radiusReductionRight = Math.max(furthestLimits.r - this.width, 0) / Math.sin(furthestAngles.r);
42445
- let radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
42446
- let radiusReductionBottom = -Math.max(furthestLimits.b - (this.height - this.paddingTop), 0) / Math.cos(furthestAngles.b);
42447
- radiusReductionLeft = numberOrZero(radiusReductionLeft);
42448
- radiusReductionRight = numberOrZero(radiusReductionRight);
42449
- radiusReductionTop = numberOrZero(radiusReductionTop);
42450
- radiusReductionBottom = numberOrZero(radiusReductionBottom);
42451
- this.drawingArea = Math.max(largestPossibleRadius / 2, Math.min(
42452
- Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
42453
- Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2)));
42454
- this.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
42455
- }
42456
42676
  setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
42457
- const maxRight = this.width - rightMovement - this.drawingArea;
42458
- const maxLeft = leftMovement + this.drawingArea;
42459
- const maxTop = topMovement + this.drawingArea;
42460
- const maxBottom = (this.height - this.paddingTop) - bottomMovement - this.drawingArea;
42461
- this.xCenter = Math.floor(((maxLeft + maxRight) / 2) + this.left);
42462
- this.yCenter = Math.floor(((maxTop + maxBottom) / 2) + this.top + this.paddingTop);
42677
+ this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
42678
+ this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
42679
+ this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
42463
42680
  }
42464
42681
  getIndexAngle(index) {
42465
- const angleMultiplier = TAU / this.getLabels().length;
42682
+ const angleMultiplier = TAU / (this._pointLabels.length || 1);
42466
42683
  const startAngle = this.options.startAngle || 0;
42467
42684
  return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));
42468
42685
  }
@@ -42490,8 +42707,8 @@
42490
42707
  return createPointLabelContext(this.getContext(), index, pointLabel);
42491
42708
  }
42492
42709
  }
42493
- getPointPosition(index, distanceFromCenter) {
42494
- const angle = this.getIndexAngle(index) - HALF_PI;
42710
+ getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
42711
+ const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;
42495
42712
  return {
42496
42713
  x: Math.cos(angle) * distanceFromCenter + this.xCenter,
42497
42714
  y: Math.sin(angle) * distanceFromCenter + this.yCenter,
@@ -42519,7 +42736,7 @@
42519
42736
  const ctx = this.ctx;
42520
42737
  ctx.save();
42521
42738
  ctx.beginPath();
42522
- pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this.getLabels().length);
42739
+ pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
42523
42740
  ctx.closePath();
42524
42741
  ctx.fillStyle = backgroundColor;
42525
42742
  ctx.fill();
@@ -42530,7 +42747,7 @@
42530
42747
  const ctx = this.ctx;
42531
42748
  const opts = this.options;
42532
42749
  const {angleLines, grid} = opts;
42533
- const labelCount = this.getLabels().length;
42750
+ const labelCount = this._pointLabels.length;
42534
42751
  let i, offset, position;
42535
42752
  if (opts.pointLabels.display) {
42536
42753
  drawPointLabels(this, labelCount);
@@ -42546,7 +42763,7 @@
42546
42763
  }
42547
42764
  if (angleLines.display) {
42548
42765
  ctx.save();
42549
- for (i = this.getLabels().length - 1; i >= 0; i--) {
42766
+ for (i = labelCount - 1; i >= 0; i--) {
42550
42767
  const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
42551
42768
  const {color, lineWidth} = optsAtIndex;
42552
42769
  if (!lineWidth || !color) {
@@ -42637,7 +42854,8 @@
42637
42854
  callback(label) {
42638
42855
  return label;
42639
42856
  },
42640
- padding: 5
42857
+ padding: 5,
42858
+ centerPointLabels: false
42641
42859
  }
42642
42860
  };
42643
42861
  RadialLinearScale.defaultRoutes = {
@@ -43998,6 +44216,7 @@
43998
44216
  var _this = _super.call(this) || this;
43999
44217
  _this.editors = new Editors();
44000
44218
  _this.colorPickers = new ColorPickers();
44219
+ _this.mediaModal = new MediaModal();
44001
44220
  // Hook up default handlers.
44002
44221
  _this.handlers.initDefaultHandlers();
44003
44222
  // Admin Controllers