Skip to content

Commit

Permalink
Decimation plugin fixes (#8467)
Browse files Browse the repository at this point in the history
* fix: Decimation plugin no longer changes the data order
fix: Decimation plugin no longer duplicates data points

* Use nullOrUndef helper instead of direct check

* Compute averageX value when decimating data using minMax decimation

* Place last point of interval at real X

This reduces the fuzziness on screens with devicePixelRatio > 1
  • Loading branch information
etimberg authored Feb 20, 2021
1 parent 57c8027 commit 709dc3e
Showing 1 changed file with 37 additions and 7 deletions.
44 changes: 37 additions & 7 deletions src/plugins/plugin.decimation.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {isNullOrUndef, resolve} from '../helpers';

function minMaxDecimation(data, availableWidth) {
let i, point, x, y, prevX, minIndex, maxIndex, minY, maxY;
let avgX = 0;
let countX = 0;
let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
const decimated = [];

const xMin = data[0].x;
Expand All @@ -23,19 +25,48 @@ function minMaxDecimation(data, availableWidth) {
maxY = y;
maxIndex = i;
}
// For first point in group, countX is `0`, so average will be `x` / 1.
// Use point.x here because we're computing the average data `x` value
avgX = (countX * avgX + point.x) / ++countX;
} else {
// Push up to 4 points, 3 for the last interval and the first point for this interval
if (minIndex && maxIndex) {
decimated.push(data[minIndex], data[maxIndex]);
const lastIndex = i - 1;

if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) {
// The interval is defined by 4 points: start, min, max, end.
// The starting point is already considered at this point, so we need to determine which
// of the other points to add. We need to sort these points to ensure the decimated data
// is still sorted and then ensure there are no duplicates.
const intermediateIndex1 = Math.min(minIndex, maxIndex);
const intermediateIndex2 = Math.max(minIndex, maxIndex);

if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
decimated.push({
...data[intermediateIndex1],
x: avgX,
});
}
if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
decimated.push({
...data[intermediateIndex2],
x: avgX
});
}
}
if (i > 0) {

// lastIndex === startIndex will occur when a range has only 1 point which could
// happen with very uneven data
if (i > 0 && lastIndex !== startIndex) {
// Last point in the previous interval
decimated.push(data[i - 1]);
decimated.push(data[lastIndex]);
}

// Start of the new interval
decimated.push(point);
prevX = truncX;
countX = 0;
minY = maxY = y;
minIndex = maxIndex = i;
minIndex = maxIndex = startIndex = i;
}
}

Expand Down Expand Up @@ -93,7 +124,6 @@ export default {
// First time we are seeing this dataset
// We override the 'data' property with a setter that stores the
// raw data in _data, but reads the decimated data from _decimated
// TODO: Undo this on chart destruction
dataset._data = data;
delete dataset.data;
Object.defineProperty(dataset, 'data', {
Expand Down

0 comments on commit 709dc3e

Please sign in to comment.