@sports-alliance/sports-lib
Version:
A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc
199 lines (198 loc) • 6.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.standardDeviation = exports.medianFilter = exports.meanWindowSmoothing = exports.mean = void 0;
exports.isNumberOrString = isNumberOrString;
exports.isNumber = isNumber;
exports.convertSpeedToPace = convertSpeedToPace;
exports.convertSpeedToSwimPace = convertSpeedToSwimPace;
exports.convertSwimPaceToSpeed = convertSwimPaceToSpeed;
exports.convertSpeedToSpeedInKilometersPerHour = convertSpeedToSpeedInKilometersPerHour;
exports.convertSpeedToSpeedInMilesPerHour = convertSpeedToSpeedInMilesPerHour;
exports.convertSpeedToSpeedInFeetPerSecond = convertSpeedToSpeedInFeetPerSecond;
exports.convertSpeedToSpeedInMetersPerMinute = convertSpeedToSpeedInMetersPerMinute;
exports.convertSpeedToSpeedInFeetPerMinute = convertSpeedToSpeedInFeetPerMinute;
exports.convertSpeedToSpeedInFeetPerHour = convertSpeedToSpeedInFeetPerHour;
exports.convertSpeedToSpeedInMetersPerHour = convertSpeedToSpeedInMetersPerHour;
exports.convertSpeedToSpeedInKnots = convertSpeedToSpeedInKnots;
exports.convertPaceToPaceInMinutesPerMile = convertPaceToPaceInMinutesPerMile;
exports.convertMetersToMiles = convertMetersToMiles;
exports.convertMetersToFeet = convertMetersToFeet;
exports.convertSwimPaceToSwimPacePer100Yard = convertSwimPaceToSwimPacePer100Yard;
exports.getSize = getSize;
exports.getSizeFormated = getSizeFormated;
exports.fillMissingValuesLinear = fillMissingValuesLinear;
function isNumberOrString(property) {
return typeof property === 'number' || typeof property === 'string';
}
function isNumber(property) {
return typeof property === 'number' && !isNaN(property);
}
/**
* Converts speed from m/s to pace as of seconds per km
* @param {number} number
* @return {number}
*/
function convertSpeedToPace(number) {
return number === 0 ? Infinity : 1000 / number;
}
/**
* Converts m/s to seconds per 100m
* @param number
*/
function convertSpeedToSwimPace(number) {
return number === 0 ? Infinity : 100 / number;
}
/**
* Converts swim pace from seconds per 100m to m/s
* @param number
*/
function convertSwimPaceToSpeed(number) {
return number === 0 ? Infinity : 100 / number;
}
function convertSpeedToSpeedInKilometersPerHour(number) {
return number * 3.6;
}
function convertSpeedToSpeedInMilesPerHour(number) {
return number * 2.237;
}
function convertSpeedToSpeedInFeetPerSecond(number) {
return number * 3.28084;
}
function convertSpeedToSpeedInMetersPerMinute(number) {
return number * 60;
}
function convertSpeedToSpeedInFeetPerMinute(number) {
return number * 196.85;
}
function convertSpeedToSpeedInFeetPerHour(number) {
return number * 11811.024;
}
function convertSpeedToSpeedInMetersPerHour(number) {
return number * 3600;
}
function convertSpeedToSpeedInKnots(number) {
return number * 1.943844;
}
function convertPaceToPaceInMinutesPerMile(number) {
return number * 1.60934;
}
function convertMetersToMiles(number) {
return number === 0 ? 0 : number / 1609;
}
function convertMetersToFeet(number) {
return number * 3.28084;
}
/**
* Converts swim pace from seconds per 100m to seconds per 100yd.
* @param number
*/
function convertSwimPaceToSwimPacePer100Yard(number) {
return number * 0.9144;
}
function getSize(obj) {
return getSizeWithOptionalFormat(obj, false);
}
function getSizeFormated(obj) {
return getSizeWithOptionalFormat(obj, true);
}
function getSizeWithOptionalFormat(obj, format = true) {
let size;
try {
size = new Blob([obj]).size;
}
catch (_a) {
size = Buffer.from(obj).length;
}
function formatByteSize(bytes) {
if (bytes < 1024) {
return bytes + ' bytes';
}
else if (bytes < 1048576) {
return (bytes / 1024).toFixed(4) + ' KiB';
}
else if (bytes < 1073741824) {
return (bytes / 1048576).toFixed(4) + ' MiB';
}
else {
return (bytes / 1073741824).toFixed(4) + ' GiB';
}
}
return format ? formatByteSize(size) : size;
}
/**
* from https://stackoverflow.com/questions/48340403/fill-missing-numeric-values-in-an-array
* Very badly written
* @param array
*/
function fillMissingValuesLinear(array) {
let i = 0, j, delta;
while (i < array.length) {
if (array[i] !== null) {
i++;
continue;
}
j = i;
while (array[++j] === null) { }
// @ts-ignore
delta = (array[j] - array[i - 1]) / (j - i + 1);
do {
// @ts-ignore
array[i] = delta + array[i - 1];
i++;
} while (i < j);
}
return array;
}
const mean = (array) => {
return array.reduce((a, b) => a + b, 0) / array.length;
};
exports.mean = mean;
const meanWindowSmoothing = (array, windowSize = 7, roundDecimals = 3) => {
const roundDecimalsFactor = Math.pow(10, roundDecimals);
return array.map((value, index) => {
const window = array.slice(index, index + windowSize); // Get window
return Math.round((0, exports.mean)(window) * roundDecimalsFactor) / roundDecimalsFactor; // Round and return
});
};
exports.meanWindowSmoothing = meanWindowSmoothing;
const median = (inputArray) => {
const s = inputArray.slice().sort((a, b) => {
return a - b;
});
return s[Math.floor((s.length - 1) / 2)];
};
/**
* Remove spikes into a vector (http://fourier.eng.hmc.edu/e161/lectures/smooth_sharpen/node2.html)
* @param array to be filtered
* @param window Window size (should be odd number)
*/
const medianFilter = (array, window = 11) => {
if (window % 2 === 0) {
throw new Error('Window size should be an odd number');
}
if (array.length < window) {
return array;
}
const f = [];
const w = [];
let i;
w.push(array[0]);
for (i = 0; i < array.length; i++) {
const midWindowIndex = Math.floor(window / 2);
if (array.length - 1 >= i + midWindowIndex) {
w.push(array[i + midWindowIndex]);
}
f.push(median(w));
if (i >= midWindowIndex) {
w.shift();
}
}
return f;
};
exports.medianFilter = medianFilter;
const standardDeviation = (stream) => {
const avg = (0, exports.mean)(stream);
const variance = (0, exports.mean)(stream.map(value => Math.pow(value, 2))) - Math.pow(avg, 2);
return variance > 0 ? Math.sqrt(variance) : 0;
};
exports.standardDeviation = standardDeviation;