mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 12:19:08 +02:00
parent
def8d25d4b
commit
5c9e1d578c
@ -12,13 +12,19 @@ Namespace: `options.plugins.decimation`, the global options for the plugin are d
|
||||
| ---- | ---- | ------- | -----------
|
||||
| `enabled` | `boolean` | `true` | Is decimation enabled?
|
||||
| `algorithm` | `string` | `'min-max'` | Decimation algorithm to use. See the [more...](#decimation-algorithms)
|
||||
| `samples` | `number` | | If the `'lttb'` algorithm is used, this is the number of samples in the output dataset. Defaults to the canvas width to pick 1 sample per pixel.
|
||||
|
||||
## Decimation Algorithms
|
||||
|
||||
Decimation algorithm to use for data. Options are:
|
||||
|
||||
* `'lttb'`
|
||||
* `'min-max'`
|
||||
|
||||
### Largest Triangle Three Bucket (LTTB) Decimation
|
||||
|
||||
[LTTB](https://github.com/sveinn-steinarsson/flot-downsample) decimation reduces the number of data points significantly. This is most useful for showing trends in data using only a few data points.
|
||||
|
||||
### Min/Max Decimation
|
||||
|
||||
[Min/max](https://digital.ni.com/public.nsf/allkb/F694FFEEA0ACF282862576020075F784) decimation will preserve peaks in your data but could require up to 4 points for each pixel. This type of decimation would work well for a very noisy signal where you need to see data peaks.
|
||||
|
@ -1,5 +1,73 @@
|
||||
import {isNullOrUndef, resolve} from '../helpers';
|
||||
|
||||
function lttbDecimation(data, availableWidth, options) {
|
||||
/**
|
||||
* Implementation of the Largest Triangle Three Buckets algorithm.
|
||||
*
|
||||
* This implementation is based on the original implementation by Sveinn Steinarsson
|
||||
* in https://github.com/sveinn-steinarsson/flot-downsample/blob/master/jquery.flot.downsample.js
|
||||
*
|
||||
* The original implementation is MIT licensed.
|
||||
*/
|
||||
const samples = options.samples || availableWidth;
|
||||
const decimated = [];
|
||||
|
||||
const bucketWidth = (data.length - 2) / (samples - 2);
|
||||
let sampledIndex = 0;
|
||||
let a = 0;
|
||||
let i, maxAreaPoint, maxArea, area, nextA;
|
||||
decimated[sampledIndex++] = data[a];
|
||||
|
||||
for (i = 0; i < samples - 2; i++) {
|
||||
let avgX = 0;
|
||||
let avgY = 0;
|
||||
let j;
|
||||
const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1;
|
||||
const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, data.length);
|
||||
const avgRangeLength = avgRangeEnd - avgRangeStart;
|
||||
|
||||
for (j = avgRangeStart; j < avgRangeEnd; j++) {
|
||||
avgX = data[j].x;
|
||||
avgY = data[j].y;
|
||||
}
|
||||
|
||||
avgX /= avgRangeLength;
|
||||
avgY /= avgRangeLength;
|
||||
|
||||
const rangeOffs = Math.floor(i * bucketWidth) + 1;
|
||||
const rangeTo = Math.floor((i + 1) * bucketWidth) + 1;
|
||||
const {x: pointAx, y: pointAy} = data[a];
|
||||
|
||||
// Note that this is changed from the original algorithm which initializes these
|
||||
// values to 1. The reason for this change is that if the area is small, nextA
|
||||
// would never be set and thus a crash would occur in the next loop as `a` would become
|
||||
// `undefined`. Since the area is always positive, but could be 0 in the case of a flat trace,
|
||||
// initializing with a negative number is the correct solution.
|
||||
maxArea = area = -1;
|
||||
|
||||
for (j = rangeOffs; j < rangeTo; j++) {
|
||||
area = 0.5 * Math.abs(
|
||||
(pointAx - avgX) * (data[j].y - pointAy) -
|
||||
(pointAx - data[j].x) * (avgY - pointAy)
|
||||
);
|
||||
|
||||
if (area > maxArea) {
|
||||
maxArea = area;
|
||||
maxAreaPoint = data[j];
|
||||
nextA = j;
|
||||
}
|
||||
}
|
||||
|
||||
decimated[sampledIndex++] = maxAreaPoint;
|
||||
a = nextA;
|
||||
}
|
||||
|
||||
// Include the last point
|
||||
decimated[sampledIndex++] = data[data.length - 1];
|
||||
|
||||
return decimated;
|
||||
}
|
||||
|
||||
function minMaxDecimation(data, availableWidth) {
|
||||
let avgX = 0;
|
||||
let countX = 0;
|
||||
@ -141,6 +209,9 @@ export default {
|
||||
// Point the chart to the decimated data
|
||||
let decimated;
|
||||
switch (options.algorithm) {
|
||||
case 'lttb':
|
||||
decimated = lttbDecimation(data, availableWidth, options);
|
||||
break;
|
||||
case 'min-max':
|
||||
decimated = minMaxDecimation(data, availableWidth);
|
||||
break;
|
||||
|
16
types/index.esm.d.ts
vendored
16
types/index.esm.d.ts
vendored
@ -1920,14 +1920,24 @@ export class BasicPlatform extends BasePlatform {}
|
||||
export class DomPlatform extends BasePlatform {}
|
||||
|
||||
export declare enum DecimationAlgorithm {
|
||||
lttb = 'lttb',
|
||||
minmax = 'min-max',
|
||||
}
|
||||
|
||||
export interface DecimationOptions {
|
||||
interface BaseDecimationOptions {
|
||||
enabled: boolean;
|
||||
algorithm: DecimationAlgorithm;
|
||||
}
|
||||
|
||||
interface LttbDecimationOptions extends BaseDecimationOptions {
|
||||
algorithm: DecimationAlgorithm.lttb;
|
||||
samples?: number;
|
||||
}
|
||||
|
||||
interface MinMaxDecimationOptions extends BaseDecimationOptions {
|
||||
algorithm: DecimationAlgorithm.minmax;
|
||||
}
|
||||
|
||||
export type DecimationOptions = LttbDecimationOptions | MinMaxDecimationOptions;
|
||||
|
||||
export const Filler: Plugin;
|
||||
export interface FillerOptions {
|
||||
propagate: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user