From e29ba78cd1040732f896d650d8cc9b333f844161 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 17 Apr 2021 14:08:36 -0400 Subject: [PATCH] Allow the events option to be changed at runtime (#8928) --- src/core/core.controller.js | 13 +++++++++++-- src/helpers/helpers.core.js | 15 +++++++++++++++ test/specs/core.controller.tests.js | 27 +++++++++++++++++++++++++++ test/specs/helpers.core.tests.js | 11 +++++++++++ types/helpers/helpers.core.d.ts | 2 ++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 856ec56a3dc..e1ce13e300e 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -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); }); diff --git a/src/helpers/helpers.core.js b/src/helpers/helpers.core.js index 0b5ecf8f8be..0a5fcea1e6f 100644 --- a/src/helpers/helpers.core.js +++ b/src/helpers/helpers.core.js @@ -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; +}; diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index aa492ba837d..5877ad7a8f7 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -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', diff --git a/test/specs/helpers.core.tests.js b/test/specs/helpers.core.tests.js index fb4e34f53bf..e3d1400b17e 100644 --- a/test/specs/helpers.core.tests.js +++ b/test/specs/helpers.core.tests.js @@ -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(); + }); + }); }); diff --git a/types/helpers/helpers.core.d.ts b/types/helpers/helpers.core.d.ts index 48beb6b42c9..f092809060a 100644 --- a/types/helpers/helpers.core.d.ts +++ b/types/helpers/helpers.core.d.ts @@ -136,3 +136,5 @@ export function mergeIf(target: T, source: [S1, S2, S3, S4]): export function mergeIf(target: T, source: AnyObject[]): AnyObject; export function resolveObjectKey(obj: AnyObject, key: string): AnyObject; + +export function setsEqual(a: Set, b: Set): boolean;