forked from janjakubnanista/downsample
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.ts
More file actions
80 lines (61 loc) · 2.46 KB
/
utils.ts
File metadata and controls
80 lines (61 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { DataPoint, NormalizedDataPoint, TupleDataPoint, X, XYDataPoint } from './types';
const isTupleDataPoint = (dataPoint: DataPoint): dataPoint is TupleDataPoint => {
return Array.isArray(dataPoint);
};
const isXYDataPoint = (dataPoint: DataPoint): dataPoint is XYDataPoint => {
return !!dataPoint && 'x' in dataPoint && 'y' in dataPoint;
};
const normalizeX = (x: X): number => (x instanceof Date ? x.getTime() : x);
export function normalizeDataPoint(dataPoint: DataPoint): NormalizedDataPoint | undefined {
if (!dataPoint) return undefined;
if (isXYDataPoint(dataPoint)) {
return [normalizeX(dataPoint.x), dataPoint.y];
}
if (isTupleDataPoint(dataPoint)) {
return [normalizeX(dataPoint[0]), dataPoint[1]];
}
throw new Error(`Invalid data point format supplied: ${JSON.stringify(dataPoint)}`);
}
export function normalizeDataPoints(dataPoints: DataPoint[]): NormalizedDataPoint[] {
return dataPoints.map(normalizeDataPoint).filter(Boolean) as NormalizedDataPoint[];
}
export function calculateTriangleArea(
pointA: NormalizedDataPoint,
pointB: NormalizedDataPoint,
pointC: NormalizedDataPoint,
): number {
return (
Math.abs((pointA[0] - pointC[0]) * (pointB[1] - pointA[1]) - (pointA[0] - pointB[0]) * (pointC[1] - pointA[1])) / 2
);
}
export function calculateAverageDataPoint(...points: NormalizedDataPoint[]): NormalizedDataPoint | undefined {
const { length } = points;
if (!length) return undefined;
let averageX = 0;
let averageY = 0;
for (let i = 0; i < length; i++) {
averageX += points[i][0];
averageY += points[i][1];
}
return [averageX / length, averageY / length];
}
export function splitIntoBuckets<T>(data: T[], desiredLength: number): T[][] {
if (data.length === 2) {
return [[data[0]], [data[1]]];
}
const first: T = data[0];
const center: T[] = data.slice(1, data.length - 1);
const last: T = data[data.length - 1];
// First and last bucket are formed by the first and the last data points
// so we only have N - 2 buckets left to fill
const bucketSize: number = center.length / (desiredLength - 2);
const splitData: T[][] = [[first]];
for (let i = 0; i < desiredLength - 2; i++) {
const bucketStartIndex: number = Math.floor(i * bucketSize);
const bucketEndIndex: number = Math.floor((i + 1) * bucketSize);
const dataPointsInBucket: T[] = center.slice(bucketStartIndex, bucketEndIndex);
splitData.push(dataPointsInBucket);
}
splitData.push([last]);
return splitData;
}