]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Fix setActiveElements behavior after a mouse event (#9992)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Thu, 16 Dec 2021 22:34:53 +0000 (00:34 +0200)
committerGitHub <noreply@github.com>
Thu, 16 Dec 2021 22:34:53 +0000 (00:34 +0200)
* Fix setActiveElements behavior after a mouse event

* Better variable name

src/core/core.controller.js
src/plugins/plugin.tooltip.js
test/specs/core.controller.tests.js
test/specs/plugin.tooltip.tests.js

index 7b4df4137bf6eb8536c0d862ef876fbb40b0db22..6b0bd2f71da0567bbe846a4f2f285897f8a49241 100644 (file)
@@ -504,9 +504,12 @@ class Chart {
 
     this._layers.sort(compare2Level('z', '_idx'));
 
-    // Replay last event from before update
-    if (this._lastEvent) {
-      this._eventHandler(this._lastEvent, true);
+    // Replay last event from before update, or set hover styles on active elements
+    const {_active, _lastEvent} = this;
+    if (_lastEvent) {
+      this._eventHandler(_lastEvent, true);
+    } else if (_active.length) {
+      this._updateHoverStyles(_active, _active, true);
     }
 
     this.render();
@@ -1086,6 +1089,8 @@ class Chart {
 
     if (changed) {
       this._active = active;
+      // Make sure we don't use the previous mouse event to override the active elements in update.
+      this._lastEvent = null;
       this._updateHoverStyles(active, lastActive);
     }
   }
index 751569a8b7c88aa5678f0044896ad91093d76b75..76db6bef5fa01eafa390c2fc3eb52f2ce4fb6c37 100644 (file)
@@ -1004,6 +1004,7 @@ export class Tooltip extends Element {
     if (changed || positionChanged) {
       this._active = active;
       this._eventPosition = eventPosition;
+      this._ignoreReplayEvents = true;
       this.update(true);
     }
   }
@@ -1016,6 +1017,11 @@ export class Tooltip extends Element {
         * @returns {boolean} true if the tooltip changed
         */
   handleEvent(e, replay, inChartArea = true) {
+    if (replay && this._ignoreReplayEvents) {
+      return false;
+    }
+    this._ignoreReplayEvents = false;
+
     const options = this.options;
     const lastActive = this._active || [];
     const active = this._getActiveElements(e, lastActive, replay, inChartArea);
index b0197b152abe7324c7e2f34781eea45ca842e173..6c4af91b7c829e4eef1b8bdcadf0ca8b9f2c9c1c 100644 (file)
@@ -2287,6 +2287,42 @@ describe('Chart', function() {
     });
   });
 
+  it('should not replace the user set active elements by event replay', async function() {
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        labels: [1, 2, 3],
+        datasets: [{
+          data: [1, 2, 3],
+          borderColor: 'red',
+          hoverBorderColor: 'blue',
+        }]
+      }
+    });
+
+    const meta = chart.getDatasetMeta(0);
+    const point0 = meta.data[0];
+    const point1 = meta.data[1];
+
+    let props = meta.data[0].getProps(['borderColor']);
+    expect(props.options.borderColor).toEqual('red');
+
+    await jasmine.triggerMouseEvent(chart, 'mousemove', {x: point0.x, y: point0.y});
+    expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 0, element: point0}]);
+    expect(point0.options.borderColor).toEqual('blue');
+    expect(point1.options.borderColor).toEqual('red');
+
+    chart.setActiveElements([{datasetIndex: 0, index: 1}]);
+    expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point1}]);
+    expect(point0.options.borderColor).toEqual('red');
+    expect(point1.options.borderColor).toEqual('blue');
+
+    chart.update();
+    expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point1}]);
+    expect(point0.options.borderColor).toEqual('red');
+    expect(point1.options.borderColor).toEqual('blue');
+  });
+
   describe('platform', function() {
     it('should use the platform constructor provided in config', function() {
       const chart = acquireChart({
index dedd7db88db288f897d95f6193ce1241b5dac886..8644b34c794178b5df39be81b2ffa8eef4b4f170 100644 (file)
@@ -1556,6 +1556,42 @@ describe('Plugin.Tooltip', function() {
       expect(chart.tooltip.getActiveElements()[0].element).toBe(meta.data[0]);
     });
 
+    it('should not replace the user set active elements by event replay', async function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+        options: {
+          events: ['pointerdown', 'pointerup']
+        }
+      });
+
+      const meta = chart.getDatasetMeta(0);
+      const point0 = meta.data[0];
+      const point1 = meta.data[1];
+
+      await jasmine.triggerMouseEvent(chart, 'pointerdown', {x: point0.x, y: point0.y});
+      expect(chart.tooltip.opacity).toBe(1);
+      expect(chart.tooltip.getActiveElements()).toEqual([{datasetIndex: 0, index: 0, element: point0}]);
+
+      chart.tooltip.setActiveElements([{datasetIndex: 0, index: 1}]);
+      chart.update();
+      expect(chart.tooltip.opacity).toBe(1);
+      expect(chart.tooltip.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point1}]);
+
+      chart.tooltip.setActiveElements([]);
+      chart.update();
+      expect(chart.tooltip.opacity).toBe(0);
+      expect(chart.tooltip.getActiveElements().length).toBe(0);
+    });
+
     it('should not change the active elements on events outside chartArea, except for mouseout', async function() {
       var chart = acquireChart({
         type: 'line',