UNPKG

downsample-lttb-ts

Version:

Minimal weight downsample N array of numbers to K array of numbers squashed up.

69 lines (68 loc) 2.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.downsample = exports.singularDownSample = void 0; const floor = Math.floor; const abs = Math.abs; const singularDownSample = ({ series, threshold, }) => { const seriesToPoints = series.map((value, idx) => [idx, value]); return (0, exports.downsample)({ series: seriesToPoints, threshold, }).map((point) => point[1]); }; exports.singularDownSample = singularDownSample; const downsample = ({ series, threshold }) => { const seriesLength = series.length; if (threshold >= seriesLength || threshold <= 0) { return series; } const sampled = []; let sampledIndex = 0; const bucketSize = (seriesLength - 2) / (threshold - 2); let initialPointInTriangle = 0; let maxAreaPoint; let maxArea; let area; let nextPointInTriangle; sampled[sampledIndex++] = series[initialPointInTriangle]; // Always add the first point for (let i = 0; i < threshold - 2; i++) { // Calculate point average for next bucket (containing c) let averageX = 0; let averageY = 0; let avgRangeStart = floor((i + 1) * bucketSize) + 1; let avgRangeEnd = floor((i + 2) * bucketSize) + 1; avgRangeEnd = avgRangeEnd < seriesLength ? avgRangeEnd : seriesLength; const avgRangeLength = avgRangeEnd - avgRangeStart; for (; avgRangeStart < avgRangeEnd; avgRangeStart++) { averageX += series[avgRangeStart][0] * 1; // * 1 enforces Number (value may be Date) averageY += series[avgRangeStart][1] * 1; } averageX /= avgRangeLength; averageY /= avgRangeLength; // Get range for bucket let rangeOffs = floor((i + 0) * bucketSize) + 1; const rangeTo = floor((i + 1) * bucketSize) + 1; // Point of triangle const pointTriangleX = series[initialPointInTriangle][0] * 1; const pointTriangleY = series[initialPointInTriangle][1] * 1; maxArea = area = -1; for (; rangeOffs < rangeTo; rangeOffs++) { // Calculate triangle area over three buckets area = abs((pointTriangleX - averageX) * (series[rangeOffs][1] - pointTriangleY) - (pointTriangleX - series[rangeOffs][0]) * (averageY - pointTriangleY)) * 0.5; if (area > maxArea) { maxArea = area; maxAreaPoint = series[rangeOffs]; nextPointInTriangle = rangeOffs; } } sampled[sampledIndex++] = maxAreaPoint; // Pick this point from the bucket initialPointInTriangle = nextPointInTriangle; // This a is the next a (chosen b) } sampled[sampledIndex++] = series[seriesLength - 1]; // Always add last return sampled; }; exports.downsample = downsample;