]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Allow the events option to be changed at runtime (#8928)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sat, 17 Apr 2021 18:08:36 +0000 (14:08 -0400)
committerGitHub <noreply@github.com>
Sat, 17 Apr 2021 18:08:36 +0000 (14:08 -0400)
src/core/core.controller.js
src/helpers/helpers.core.js
test/specs/core.controller.tests.js
test/specs/helpers.core.tests.js
types/helpers/helpers.core.d.ts

index 856ec56a3dc0ebd31bfc625ae4facc1398343358..e1ce13e300e6d0f85d3d6e52663994680ed61d07 100644 (file)
@@ -7,7 +7,7 @@ import PluginService from './core.plugins';
 import registry from './core.registry';
 import Config, {determineAxis, getIndexAxis} from './core.config';
 import {retinaScale} from '../helpers/helpers.dom';
-import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef} from '../helpers/helpers.core';
+import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual} from '../helpers/helpers.core';
 import {clearCanvas, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas';
 // @ts-ignore
 import {version} from '../../package.json';
@@ -480,6 +480,15 @@ class Chart {
     me.ensureScalesHaveIDs();
     me.buildOrUpdateScales();
 
+    const existingEvents = new Set(Object.keys(me._listeners));
+    const newEvents = new Set(me.options.events);
+
+    if (!setsEqual(existingEvents, newEvents)) {
+      // The events array has changed. Rebind it
+      me.unbindEvents();
+      me.bindEvents();
+    }
+
     // plugins options references might have change, let's invalidate the cache
     // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
     me._plugins.invalidate();
@@ -953,7 +962,7 @@ class Chart {
       return;
     }
 
-    delete me._listeners;
+    me._listeners = {};
     each(listeners, (listener, type) => {
       me.platform.removeEventListener(me, type, listener);
     });
index 0b5ecf8f8be54fc02c416856fa745d47b2e13e26..0a5fcea1e6f6e6fd481c9efd1704baf39ba726a1 100644 (file)
@@ -325,3 +325,18 @@ export function _capitalize(str) {
 export const defined = (value) => typeof value !== 'undefined';
 
 export const isFunction = (value) => typeof value === 'function';
+
+// Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384
+export const setsEqual = (a, b) => {
+  if (a.size !== b.size) {
+    return false;
+  }
+
+  for (const item of a) {
+    if (!b.has(item)) {
+      return false;
+    }
+  }
+
+  return true;
+};
index aa492ba837d310f5e6c82a8ad939644705e34d8e..5877ad7a8f7a482c55be56e9b60080afc413750d 100644 (file)
@@ -291,6 +291,33 @@ describe('Chart', function() {
       expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point}]);
     });
 
+    it('should handle changing the events at runtime', async function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          events: ['click']
+        }
+      });
+
+      var point1 = chart.getDatasetMeta(0).data[1];
+      var point2 = chart.getDatasetMeta(0).data[2];
+
+      await jasmine.triggerMouseEvent(chart, 'click', point1);
+      expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point1}]);
+
+      chart.options.events = ['mousemove'];
+      chart.update();
+
+      await jasmine.triggerMouseEvent(chart, 'mousemove', point2);
+      expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 2, element: point2}]);
+    });
+
     it('should activate element on hover when minPadding pixels outside chart area', async function() {
       var chart = acquireChart({
         type: 'line',
index fb4e34f53bf402f35f6ea904496a6b3ad34ff7f6..e3d1400b17e8bb6e81ba3832804c346dfe6d26a0 100644 (file)
@@ -457,4 +457,15 @@ describe('Chart.helpers.core', function() {
       expect(() => helpers.resolveObjectKey({}, 1)).toThrow();
     });
   });
+
+  describe('setsEqual', function() {
+    it('should handle set comparison', function() {
+      var a = new Set([1]);
+      var b = new Set(['1']);
+      var c = new Set([1]);
+
+      expect(helpers.setsEqual(a, b)).toBeFalse();
+      expect(helpers.setsEqual(a, c)).toBeTrue();
+    });
+  });
 });
index 48beb6b42c9aa8fa983ccecf4255f0b4f3472c8e..f092809060a074de438a3e86684f4dfa00d4ace8 100644 (file)
@@ -136,3 +136,5 @@ export function mergeIf<T, S1, S2, S3, S4>(target: T, source: [S1, S2, S3, S4]):
 export function mergeIf<T>(target: T, source: AnyObject[]): AnyObject;
 
 export function resolveObjectKey(obj: AnyObject, key: string): AnyObject;
+
+export function setsEqual(a: Set<unknown>, b: Set<unknown>): boolean;