]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
fix: calc visible points on update (#10667)
authorDan Onoshko <danon0404@gmail.com>
Sat, 24 Sep 2022 21:01:47 +0000 (04:01 +0700)
committerGitHub <noreply@github.com>
Sat, 24 Sep 2022 21:01:47 +0000 (17:01 -0400)
src/controllers/controller.line.js
src/helpers/helpers.collection.js
test/specs/controller.line.tests.js
test/specs/helpers.collection.tests.js

index de391c3a70cb5c3bec51e79e8ef5ef5e10dc0447..18f0aa847a6187ff6fdb93b375dfd71159a1b0fb 100644 (file)
@@ -82,12 +82,20 @@ export default class LineController extends DatasetController {
     const {spanGaps, segment} = this.options;
     const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
     const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
+    const end = start + count;
+    const pointsCount = points.length;
     let prevParsed = start > 0 && this.getParsed(start - 1);
 
-    for (let i = start; i < start + count; ++i) {
+    for (let i = 0; i < pointsCount; ++i) {
       const point = points[i];
-      const parsed = this.getParsed(i);
       const properties = directUpdate ? point : {};
+
+      if (i < start || i >= end) {
+        properties.skip = true;
+        continue;
+      }
+
+      const parsed = this.getParsed(i);
       const nullData = isNullOrUndef(parsed[vAxis]);
       const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
       const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
index 5b2369808a04196c3691b24a73b47b097b35a0fe..8e77b06aa81bd9fc877cf2956cb107259f7f1bff 100644 (file)
@@ -35,7 +35,10 @@ export function _lookup(table, value, cmp) {
  */
 export const _lookupByKey = (table, key, value, last) =>
   _lookup(table, value, last
-    ? index => table[index][key] <= value
+    ? index => {
+      const ti = table[index][key];
+      return ti < value || ti === value && table[index + 1][key] === value;
+    }
     : index => table[index][key] < value);
 
 /**
index 2a758f649c8068f26fcd4291ac70463171a33d87..368627d68a0cf4c7406203573c123829052227e4 100644 (file)
@@ -1051,6 +1051,9 @@ describe('Chart.controllers.line', function() {
       {x: 50, y: 9},
       {x: 50, y: 9},
       {x: 50, y: 9},
+      {x: 51, y: 9},
+      {x: 52, y: 9},
+      {x: 52, y: 9},
     ];
     chart.update();
 
@@ -1062,6 +1065,10 @@ describe('Chart.controllers.line', function() {
     };
 
     chart._handleEvent(event, false, true);
+
+    const visiblePoints = chart.getSortedVisibleDatasetMetas()[0].data.filter(_ => !_.skip);
+
+    expect(visiblePoints.length).toBe(6);
   }, 500);
 
   it('should not override tooltip title and label callbacks', async() => {
index f6a1cbae5eb738c03d5150e46313ea73b9c6ff2f..432bfb54297f6f03555a94767495e54c16d995a7 100644 (file)
@@ -19,6 +19,16 @@ describe('helpers.collection', function() {
     expect(_lookupByKey(data, 'x', 9)).toEqual({lo: 2, hi: 3});
   });
 
+  it('Should do binary search by key with last', () => {
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 6}, {x: 9}], 'x', 25, true)).toEqual({lo: 2, hi: 3});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 9}, {x: 9}], 'x', 25, true)).toEqual({lo: 2, hi: 3});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 9}, {x: 9}, {x: 22}], 'x', 25, true)).toEqual({lo: 3, hi: 4});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 25}, {x: 28}], 'x', 25, true)).toEqual({lo: 1, hi: 2});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 25}, {x: 25}], 'x', 25, true)).toEqual({lo: 2, hi: 3});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 25}, {x: 25}, {x: 28}], 'x', 25, true)).toEqual({lo: 2, hi: 3});
+    expect(_lookupByKey([{x: 0}, {x: 2}, {x: 25}, {x: 25}, {x: 25}, {x: 28}, {x: 29}], 'x', 25, true)).toEqual({lo: 3, hi: 4});
+  });
+
   it('Should do reverse binary search by key', function() {
     const data = [{x: 10}, {x: 7}, {x: 3}, {x: 0}];
     expect(_rlookupByKey(data, 'x', 0)).toEqual({lo: 2, hi: 3});