@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
383 lines (382 loc) • 16.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FITSampleMapper = void 0;
const data_latitude_degrees_1 = require("../../../../data/data.latitude-degrees");
const data_altitude_1 = require("../../../../data/data.altitude");
const data_heart_rate_1 = require("../../../../data/data.heart-rate");
const data_cadence_1 = require("../../../../data/data.cadence");
const data_temperature_1 = require("../../../../data/data.temperature");
const data_distance_1 = require("../../../../data/data.distance");
const data_speed_1 = require("../../../../data/data.speed");
const data_vertical_speed_1 = require("../../../../data/data.vertical-speed");
const data_power_1 = require("../../../../data/data.power");
const data_longitude_degrees_1 = require("../../../../data/data.longitude-degrees");
const data_form_power_1 = require("../../../../data/data.form-power");
const data_leg_stiffness_1 = require("../../../../data/data.leg-stiffness");
const data_vertical_oscillation_1 = require("../../../../data/data.vertical-oscillation");
const helpers_1 = require("../../../utilities/helpers");
const data_accumulated_power_1 = require("../../../../data/data.accumulated-power");
const data_stryd_altitude_1 = require("../../../../data/data.stryd-altitude");
const data_stryd_distance_1 = require("../../../../data/data.stryd-distance");
const data_stryd_speed_1 = require("../../../../data/data.stryd-speed");
const data_power_balance_left_1 = require("../../../../data/data.power-balance-left");
const data_power_balance_right_1 = require("../../../../data/data.power-balance-right");
const data_ground_contact_time_1 = require("../../../../data/data.ground-contact-time");
const data_ground_contact_time_balance_left_1 = require("../../../../data/data-ground-contact-time-balance-left");
const data_ground_contact_time_balance_right_1 = require("../../../../data/data-ground-contact-time-balance-right");
const data_stance_time_1 = require("../../../../data/data.stance-time");
const data_stance_time_balance_left_1 = require("../../../../data/data-stance-time-balance-left");
const data_step_length_1 = require("../../../../data/data.step-length");
const data_effort_pace_1 = require("../../../../data/data.effort-pace");
const data_vertical_ratio_1 = require("../../../../data/data.vertical-ratio");
const data_ground_time_1 = require("../../../../data/data.ground-time");
const data_air_power_1 = require("../../../../data/data.air-power");
const data_grit_1 = require("../../../../data/data.grit");
const data_flow_1 = require("../../../../data/data.flow");
const data_stamina_1 = require("../../../../data/data.stamina");
const data_running_dynamics_balance_1 = require("../../../../data/data.running-dynamics-balance");
const data_left_torque_effectiveness_1 = require("../../../../data/data.left-torque-effectiveness");
const data_right_torque_effectiveness_1 = require("../../../../data/data.right-torque-effectiveness");
const data_left_pedal_smoothness_1 = require("../../../../data/data.left-pedal-smoothness");
const data_right_pedal_smoothness_1 = require("../../../../data/data.right-pedal-smoothness");
const constants_1 = require("../../../../constants/constants");
const getPositiveBalanceValue = (sample, fieldName) => {
const value = sample[fieldName];
return (0, helpers_1.isNumber)(value) && value > 0 ? value : null;
};
const getPositiveBalanceComplementValue = (sample, fieldName) => {
const value = getPositiveBalanceValue(sample, fieldName);
return value === null ? null : 100 - value;
};
exports.FITSampleMapper = [
{
dataType: data_latitude_degrees_1.DataLatitudeDegrees.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.position_lat)
? Math.round(sample.position_lat * Math.pow(10, constants_1.GNSS_DEGREES_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
Math.pow(10, constants_1.GNSS_DEGREES_PRECISION_NUMBER_OF_DECIMAL_PLACES)
: sample.position_lat;
}
},
{
dataType: data_longitude_degrees_1.DataLongitudeDegrees.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.position_long)
? Math.round(sample.position_long * Math.pow(10, constants_1.GNSS_DEGREES_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
Math.pow(10, constants_1.GNSS_DEGREES_PRECISION_NUMBER_OF_DECIMAL_PLACES)
: sample.position_long;
}
},
{
dataType: data_distance_1.DataDistance.type,
getSampleValue: (sample) => {
// TODO(sports-lib): fix duplicate distance-family outputs at the source by reading FIT field units/metadata
// instead of blindly preferring `distance`/`Distance`. Some vendor exports can mix differently-scaled fields.
return (0, helpers_1.isNumber)(sample.distance) ? sample.distance : sample.Distance;
}
},
{
dataType: data_heart_rate_1.DataHeartRate.type,
getSampleValue: (sample) => {
return sample.heart_rate;
}
},
{
dataType: data_altitude_1.DataAltitude.type,
getSampleValue: (sample) => {
const altitude = (0, helpers_1.isNumber)(sample.enhanced_altitude)
? sample.enhanced_altitude
: (0, helpers_1.isNumber)(sample.EnhancedAltitude)
? sample.EnhancedAltitude
: (0, helpers_1.isNumber)(sample.altitude)
? sample.altitude
: (0, helpers_1.isNumber)(sample.Altitude)
? sample.Altitude
: null;
return (0, helpers_1.isNumber)(altitude)
? Math.round(altitude * Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
: altitude;
}
},
{
dataType: data_stryd_altitude_1.DataStrydAltitude.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.Elevation)
? Math.round(sample.Elevation * Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
: sample.Elevation;
}
},
{
dataType: data_stryd_distance_1.DataStrydDistance.type,
getSampleValue: (sample) => {
return sample.Distance;
}
},
{
dataType: data_stryd_speed_1.DataStrydSpeed.type,
getSampleValue: (sample) => {
return sample.Speed;
}
},
{
dataType: data_cadence_1.DataCadence.type,
getSampleValue: (sample) => {
let cadenceValue = sample.cadence;
if ((0, helpers_1.isNumber)(sample.fractional_cadence)) {
cadenceValue += sample.fractional_cadence;
}
return cadenceValue;
}
},
{
dataType: data_speed_1.DataSpeed.type,
getSampleValue: (sample) => {
// TODO(sports-lib): fix duplicate speed-family outputs at the source by normalizing vendor-specific speed keys
// (`enhanced_speed`, `speed`, `Speed`) with explicit unit handling. This should guarantee one canonical base stream.
if ((0, helpers_1.isNumber)(sample.enhanced_speed)) {
return sample.enhanced_speed;
}
if ((0, helpers_1.isNumber)(sample.EnhancedSpeed)) {
return sample.EnhancedSpeed;
}
if ((0, helpers_1.isNumber)(sample.speed)) {
return sample.speed;
}
if ((0, helpers_1.isNumber)(sample.Speed)) {
return sample.Speed;
}
return null;
}
},
{
dataType: data_vertical_speed_1.DataVerticalSpeed.type,
getSampleValue: (sample) => {
return sample.vertical_speed;
}
},
{
dataType: data_power_1.DataPower.type,
getSampleValue: (sample, sampleInfo) => {
// Ensure power stream compliance when in some cases power sample field could be missing even if others samples have it
// Just set watts to 0 when this happen
// Case example: ride file "7432332116.fit" from integration tests
const watts = (0, helpers_1.isNumber)(sample.power) ? sample.power : (0, helpers_1.isNumber)(sample.Power) ? sample.Power : sample.RP_Power;
return (sampleInfo === null || sampleInfo === void 0 ? void 0 : sampleInfo.hasPowerMeter) ? watts || 0 : null;
}
},
{
dataType: data_accumulated_power_1.DataAccumulatedPower.type,
getSampleValue: (sample) => {
return sample.accumulated_power;
}
},
{
dataType: data_temperature_1.DataTemperature.type,
getSampleValue: (sample) => {
return sample.temperature;
}
},
{
dataType: data_form_power_1.DataFormPower.type,
getSampleValue: (sample) => {
return sample['Form Power'];
}
},
{
dataType: data_air_power_1.DataAirPower.type,
getSampleValue: (sample) => {
return sample['Air Power'];
}
},
{
dataType: data_ground_time_1.DataGroundTime.type,
getSampleValue: (sample) => {
return sample['Ground Time'];
}
},
{
dataType: data_leg_stiffness_1.DataLegStiffness.type,
getSampleValue: (sample) => {
return sample['Leg Spring Stiffness'];
}
},
{
dataType: data_vertical_oscillation_1.DataVerticalOscillation.type,
getSampleValue: (sample) => {
return sample.vertical_oscillation;
}
},
{
dataType: data_power_balance_right_1.DataPowerBalanceRight.type,
getSampleValue: (sample) => {
if (!sample.left_right_balance) {
return null;
}
return sample.left_right_balance.right === true
? sample.left_right_balance.value
: 100 - sample.left_right_balance.value;
}
},
// @todo if conservation of data is needed this can be taken of and generated on the fly
{
dataType: data_power_balance_left_1.DataPowerBalanceLeft.type,
getSampleValue: (sample) => {
if (!sample.left_right_balance) {
return null;
}
return sample.left_right_balance.right === false
? sample.left_right_balance.value
: 100 - sample.left_right_balance.value;
}
},
{
dataType: data_ground_contact_time_1.DataGroundContactTime.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.stance_time)
? sample.stance_time
: (0, helpers_1.isNumber)(sample['Ground Time'])
? sample['Ground Time']
: null;
}
},
// Keep DataStanceTime for backward compatibility
{
dataType: data_stance_time_1.DataStanceTime.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.stance_time)
? sample.stance_time
: (0, helpers_1.isNumber)(sample['Ground Time'])
? sample['Ground Time']
: null;
}
},
{
dataType: data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type,
getSampleValue: (sample) => {
// The FIT stance_time_balance field refers to the balance on the left leg.
return getPositiveBalanceValue(sample, 'stance_time_balance');
}
},
{
dataType: data_ground_contact_time_balance_right_1.DataGroundContactTimeBalanceRight.type,
getSampleValue: (sample) => {
return getPositiveBalanceComplementValue(sample, 'stance_time_balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataVerticalOscillationBalanceLeft.type,
getSampleValue: (sample) => {
return getPositiveBalanceValue(sample, 'Vertical Oscillation Balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataVerticalOscillationBalanceRight.type,
getSampleValue: (sample) => {
return getPositiveBalanceComplementValue(sample, 'Vertical Oscillation Balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataLegSpringStiffnessBalanceLeft.type,
getSampleValue: (sample) => {
return getPositiveBalanceValue(sample, 'Leg Spring Stiffness Balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataLegSpringStiffnessBalanceRight.type,
getSampleValue: (sample) => {
return getPositiveBalanceComplementValue(sample, 'Leg Spring Stiffness Balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataImpactLoadingRateBalanceLeft.type,
getSampleValue: (sample) => {
return getPositiveBalanceValue(sample, 'Impact Loading Rate Balance');
}
},
{
dataType: data_running_dynamics_balance_1.DataImpactLoadingRateBalanceRight.type,
getSampleValue: (sample) => {
return getPositiveBalanceComplementValue(sample, 'Impact Loading Rate Balance');
}
},
// Keep DataStanceTimeBalanceLeft for backward compatibility
{
dataType: data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type,
getSampleValue: (sample) => {
// The FIT stance_time_balance field refers to the balance on the left leg.
return getPositiveBalanceValue(sample, 'stance_time_balance');
}
},
{
dataType: data_step_length_1.DataStepLength.type,
getSampleValue: (sample) => {
return sample.step_length / 1000;
}
},
{
dataType: data_effort_pace_1.DataEffortPace.type,
getSampleValue: (sample) => {
if (!(0, helpers_1.isNumber)(sample['Effort Pace']) || sample['Effort Pace'] <= 0) {
return null;
}
const effortPace = (0, helpers_1.convertSpeedToPace)(sample['Effort Pace']);
return Number.isFinite(effortPace) ? effortPace : null;
}
},
{
dataType: data_vertical_ratio_1.DataVerticalRatio.type,
getSampleValue: (sample) => {
return sample.vertical_ratio;
}
},
{
dataType: data_stamina_1.DataStamina.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.stamina) ? sample.stamina : null;
}
},
{
dataType: data_stamina_1.DataPotentialStamina.type,
getSampleValue: (sample) => {
return (0, helpers_1.isNumber)(sample.potential_stamina) ? sample.potential_stamina : null;
}
},
{
dataType: data_grit_1.DataGrit.type,
getSampleValue: (sample) => {
return sample.grit;
}
},
{
dataType: data_flow_1.DataFlow.type,
getSampleValue: (sample) => {
return sample.flow;
}
},
{
dataType: data_left_torque_effectiveness_1.DataLeftTorqueEffectiveness.type,
getSampleValue: (sample) => {
return sample.left_torque_effectiveness;
}
},
{
dataType: data_right_torque_effectiveness_1.DataRightTorqueEffectiveness.type,
getSampleValue: (sample) => {
return sample.right_torque_effectiveness;
}
},
{
dataType: data_left_pedal_smoothness_1.DataLeftPedalSmoothness.type,
getSampleValue: (sample) => {
return sample.left_pedal_smoothness;
}
},
{
dataType: data_right_pedal_smoothness_1.DataRightPedalSmoothness.type,
getSampleValue: (sample) => {
return sample.right_pedal_smoothness;
}
}
];