@sports-alliance/sports-lib 7.1.2 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/README.md +16 -0
- package/inspect_jump_raw.js +24 -0
- package/lib/cjs/data/data-ground-contact-time-balance-left.d.ts +4 -0
- package/lib/cjs/data/data-ground-contact-time-balance-left.js +8 -0
- package/lib/cjs/data/data-ground-contact-time-balance-right.d.ts +4 -0
- package/lib/cjs/data/data-ground-contact-time-balance-right.js +8 -0
- package/lib/cjs/data/data-ground-contact-time-balance.d.ts +3 -0
- package/lib/cjs/data/data-ground-contact-time-balance.js +7 -0
- package/lib/cjs/data/data-stance-time-balance-left.d.ts +1 -0
- package/lib/cjs/data/data-stance-time-balance-left.js +1 -0
- package/lib/cjs/data/data-stance-time-balance-right.d.ts +1 -0
- package/lib/cjs/data/data-stance-time-balance-right.js +1 -0
- package/lib/cjs/data/data-stance-time-balance.d.ts +1 -0
- package/lib/cjs/data/data-stance-time-balance.js +1 -0
- package/lib/cjs/data/data.depth-max.d.ts +5 -0
- package/lib/cjs/data/data.depth-max.js +9 -0
- package/lib/cjs/data/data.depth.d.ts +5 -0
- package/lib/cjs/data/data.depth.js +9 -0
- package/lib/cjs/data/data.fitness-age.d.ts +5 -0
- package/lib/cjs/data/data.fitness-age.js +9 -0
- package/lib/cjs/data/data.ground-contact-time-avg.d.ts +5 -0
- package/lib/cjs/data/data.ground-contact-time-avg.js +9 -0
- package/lib/cjs/data/data.ground-contact-time-max.d.ts +5 -0
- package/lib/cjs/data/data.ground-contact-time-max.js +9 -0
- package/lib/cjs/data/data.ground-contact-time-min.d.ts +5 -0
- package/lib/cjs/data/data.ground-contact-time-min.js +9 -0
- package/lib/cjs/data/data.ground-contact-time.d.ts +5 -0
- package/lib/cjs/data/data.ground-contact-time.js +9 -0
- package/lib/cjs/data/data.jump-event.d.ts +6 -1
- package/lib/cjs/data/data.jump-stats.d.ts +91 -0
- package/lib/cjs/data/data.jump-stats.js +112 -0
- package/lib/cjs/data/data.max-hr-setting.d.ts +5 -0
- package/lib/cjs/data/data.max-hr-setting.js +9 -0
- package/lib/cjs/data/data.stance-time.d.ts +1 -0
- package/lib/cjs/data/data.stance-time.js +1 -0
- package/lib/cjs/data/data.store.js +58 -1
- package/lib/cjs/data/data.vertical-oscillation-avg.d.ts +5 -0
- package/lib/cjs/data/data.vertical-oscillation-avg.js +9 -0
- package/lib/cjs/data/data.vertical-oscillation-max.d.ts +5 -0
- package/lib/cjs/data/data.vertical-oscillation-max.js +9 -0
- package/lib/cjs/data/data.vertical-oscillation-min.d.ts +5 -0
- package/lib/cjs/data/data.vertical-oscillation-min.js +9 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.js +112 -9
- package/lib/cjs/events/adapters/importers/fit/importer.fit.mapper.js +23 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.mtb.spec.js +34 -6
- package/lib/cjs/events/adapters/importers/suunto/importer.suunto.integration.spec.js +87 -3
- package/lib/cjs/events/adapters/importers/suunto/importer.suunto.json.js +86 -6
- package/lib/cjs/events/utilities/activity.utilities.js +38 -2
- package/lib/esm/data/data-ground-contact-time-balance-left.d.ts +4 -0
- package/lib/esm/data/data-ground-contact-time-balance-right.d.ts +4 -0
- package/lib/esm/data/data-ground-contact-time-balance.d.ts +3 -0
- package/lib/esm/data/data-stance-time-balance-left.d.ts +1 -0
- package/lib/esm/data/data-stance-time-balance-right.d.ts +1 -0
- package/lib/esm/data/data-stance-time-balance.d.ts +1 -0
- package/lib/esm/data/data.depth-max.d.ts +5 -0
- package/lib/esm/data/data.depth.d.ts +5 -0
- package/lib/esm/data/data.fitness-age.d.ts +5 -0
- package/lib/esm/data/data.ground-contact-time-avg.d.ts +5 -0
- package/lib/esm/data/data.ground-contact-time-max.d.ts +5 -0
- package/lib/esm/data/data.ground-contact-time-min.d.ts +5 -0
- package/lib/esm/data/data.ground-contact-time.d.ts +5 -0
- package/lib/esm/data/data.jump-event.d.ts +6 -1
- package/lib/esm/data/data.jump-stats.d.ts +91 -0
- package/lib/esm/data/data.max-hr-setting.d.ts +5 -0
- package/lib/esm/data/data.stance-time.d.ts +1 -0
- package/lib/esm/data/data.vertical-oscillation-avg.d.ts +5 -0
- package/lib/esm/data/data.vertical-oscillation-max.d.ts +5 -0
- package/lib/esm/data/data.vertical-oscillation-min.d.ts +5 -0
- package/lib/esm/index.js +555 -12
- package/package.json +2 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataVerticalOscillationMin = void 0;
|
|
4
|
+
const data_number_1 = require("./data.number");
|
|
5
|
+
class DataVerticalOscillationMin extends data_number_1.DataNumber {
|
|
6
|
+
}
|
|
7
|
+
exports.DataVerticalOscillationMin = DataVerticalOscillationMin;
|
|
8
|
+
DataVerticalOscillationMin.type = 'Minimum Vertical Oscillation';
|
|
9
|
+
DataVerticalOscillationMin.unit = 'mm';
|
|
@@ -129,6 +129,7 @@ const data_cycling_standing_time_1 = require("../../../../data/data.cycling-stan
|
|
|
129
129
|
const data_cycling_seated_time_1 = require("../../../../data/data.cycling-seated-time");
|
|
130
130
|
const data_cycling_position_1 = require("../../../../data/data.cycling-position");
|
|
131
131
|
const data_rider_position_change_event_1 = require("../../../../data/data.rider-position-change-event");
|
|
132
|
+
const data_ground_contact_time_avg_1 = require("../../../../data/data.ground-contact-time-avg");
|
|
132
133
|
const data_stance_time_1 = require("../../../../data/data.stance-time");
|
|
133
134
|
const data_vertical_oscillation_1 = require("../../../../data/data.vertical-oscillation");
|
|
134
135
|
const data_vertical_ratio_1 = require("../../../../data/data.vertical-ratio");
|
|
@@ -166,6 +167,7 @@ const data_age_1 = require("../../../../data/data.age");
|
|
|
166
167
|
const data_gender_1 = require("../../../../data/data.gender");
|
|
167
168
|
const data_avg_grit_1 = require("../../../../data/data.avg-grit");
|
|
168
169
|
const data_jump_event_1 = require("../../../../data/data.jump-event");
|
|
170
|
+
const data_jump_stats_1 = require("../../../../data/data.jump-stats");
|
|
169
171
|
// Threshold to detect that session.timestamp are not trustable (when exceeding 15% of session.total_elapsed_time)
|
|
170
172
|
const INVALID_DATES_ELAPSED_TIME_RATIO_THRESHOLD = 1.15;
|
|
171
173
|
class EventImporterFIT {
|
|
@@ -183,7 +185,7 @@ class EventImporterFIT {
|
|
|
183
185
|
mode: 'both'
|
|
184
186
|
});
|
|
185
187
|
fitFileParser.parse(arrayBuffer, (error, fitDataObject) => {
|
|
186
|
-
var _a;
|
|
188
|
+
var _a, _b;
|
|
187
189
|
if (error) {
|
|
188
190
|
// For now, assume any error from parser on this file means it's broken/empty in a way we treat as EmptyEventLibError
|
|
189
191
|
// to satisfy existing tests. Or ideally we wrap in a generic EventLibError.
|
|
@@ -216,6 +218,17 @@ class EventImporterFIT {
|
|
|
216
218
|
});
|
|
217
219
|
});
|
|
218
220
|
}
|
|
221
|
+
// Check for jumps data at the top level
|
|
222
|
+
if (fitDataObject.jumps && fitDataObject.jumps.length > 0) {
|
|
223
|
+
(_b = fitDataObject.sessions) === null || _b === void 0 ? void 0 : _b.forEach((session) => {
|
|
224
|
+
const sessionStartTime = new Date(session.start_time).getTime();
|
|
225
|
+
const sessionEndTime = sessionStartTime + (session.total_elapsed_time || 0) * 1000;
|
|
226
|
+
session.jumps = fitDataObject.jumps.filter((jump) => {
|
|
227
|
+
const jumpTime = new Date(jump.timestamp).getTime();
|
|
228
|
+
return jumpTime >= sessionStartTime && jumpTime < sessionEndTime;
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
219
232
|
// Iterate over the sessions and create their activities
|
|
220
233
|
const activities = fitDataObject.sessions.map((sessionObject) => {
|
|
221
234
|
// Get the activity from the sessionObject
|
|
@@ -350,7 +363,12 @@ class EventImporterFIT {
|
|
|
350
363
|
activity.addEvent(new data_jump_event_1.DataJumpEvent(activity.getDateIndex(jump.timestamp), {
|
|
351
364
|
distance: jump.distance,
|
|
352
365
|
height: jump.height,
|
|
353
|
-
score: jump.score
|
|
366
|
+
score: jump.score,
|
|
367
|
+
hang_time: jump.hang_time,
|
|
368
|
+
position_lat: jump.position_lat,
|
|
369
|
+
position_long: jump.position_long,
|
|
370
|
+
speed: jump.speed,
|
|
371
|
+
rotations: jump.rotations
|
|
354
372
|
}));
|
|
355
373
|
});
|
|
356
374
|
}
|
|
@@ -625,13 +643,6 @@ class EventImporterFIT {
|
|
|
625
643
|
const activity = new activity_1.Activity(startDate, endDate, this.getActivityTypeFromSessionObject(sessionObject), this.getCreatorFromFitDataObject(fitDataObject), options);
|
|
626
644
|
// Set the activity stats
|
|
627
645
|
this.getStatsFromObject(sessionObject, activity, false).forEach(stat => activity.addStat(stat));
|
|
628
|
-
// Check for VO2 Max in jumps
|
|
629
|
-
if (fitDataObject.jumps && fitDataObject.jumps.length) {
|
|
630
|
-
const jumpWithMets = fitDataObject.jumps.find((j) => j.enhanced_mets);
|
|
631
|
-
if (jumpWithMets) {
|
|
632
|
-
activity.addStat(new data_vo2_max_1.DataVO2Max(jumpWithMets.enhanced_mets * 3.5));
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
646
|
// Check for User Profile
|
|
636
647
|
if (fitDataObject.user_profile) {
|
|
637
648
|
const userProfile = fitDataObject.user_profile;
|
|
@@ -1008,7 +1019,11 @@ class EventImporterFIT {
|
|
|
1008
1019
|
stats.push(new data_cycling_seated_time_1.DataCyclingSeatedTime(seatedTime));
|
|
1009
1020
|
}
|
|
1010
1021
|
// Running dynamics
|
|
1022
|
+
// Stance Time
|
|
1011
1023
|
if (Number.isFinite(object.avg_stance_time)) {
|
|
1024
|
+
stats.push(new data_ground_contact_time_avg_1.DataGroundContactTimeAvg(object.avg_stance_time));
|
|
1025
|
+
// Keep DataStanceTime for backward compatibility (if needed, though logically it's an Avg)
|
|
1026
|
+
// The original code mapped avg_stance_time to DataStanceTime, which was arguably incorrect naming or type usage
|
|
1012
1027
|
stats.push(new data_stance_time_1.DataStanceTime(object.avg_stance_time));
|
|
1013
1028
|
}
|
|
1014
1029
|
if (Number.isFinite(object.avg_vertical_oscillation)) {
|
|
@@ -1080,6 +1095,94 @@ class EventImporterFIT {
|
|
|
1080
1095
|
if ((0, helpers_1.isNumberOrString)(object.avg_vam)) {
|
|
1081
1096
|
stats.push(new data_avg_vam_1.DataAvgVAM(object.avg_vam));
|
|
1082
1097
|
}
|
|
1098
|
+
// Jump Statistics
|
|
1099
|
+
if (object.jumps && object.jumps.length > 0) {
|
|
1100
|
+
const jumps = object.jumps;
|
|
1101
|
+
let count = 0;
|
|
1102
|
+
let hangTimeSum = 0, hangTimeMin = Number.MAX_VALUE, hangTimeMax = -Number.MAX_VALUE;
|
|
1103
|
+
let distanceSum = 0, distanceMin = Number.MAX_VALUE, distanceMax = -Number.MAX_VALUE;
|
|
1104
|
+
let speedSum = 0, speedMin = Number.MAX_VALUE, speedMax = -Number.MAX_VALUE;
|
|
1105
|
+
let rotationsSum = 0, rotationsMin = Number.MAX_VALUE, rotationsMax = -Number.MAX_VALUE;
|
|
1106
|
+
let scoreSum = 0, scoreMin = Number.MAX_VALUE, scoreMax = -Number.MAX_VALUE;
|
|
1107
|
+
let heightSum = 0, heightMin = Number.MAX_VALUE, heightMax = -Number.MAX_VALUE;
|
|
1108
|
+
jumps.forEach((j) => {
|
|
1109
|
+
count++;
|
|
1110
|
+
// Hangtime
|
|
1111
|
+
if (Number.isFinite(j.hang_time)) {
|
|
1112
|
+
hangTimeSum += j.hang_time;
|
|
1113
|
+
hangTimeMin = Math.min(hangTimeMin, j.hang_time);
|
|
1114
|
+
hangTimeMax = Math.max(hangTimeMax, j.hang_time);
|
|
1115
|
+
}
|
|
1116
|
+
// Distance
|
|
1117
|
+
if (Number.isFinite(j.distance)) {
|
|
1118
|
+
distanceSum += j.distance;
|
|
1119
|
+
distanceMin = Math.min(distanceMin, j.distance);
|
|
1120
|
+
distanceMax = Math.max(distanceMax, j.distance);
|
|
1121
|
+
}
|
|
1122
|
+
// Speed
|
|
1123
|
+
if (Number.isFinite(j.speed)) {
|
|
1124
|
+
speedSum += j.speed;
|
|
1125
|
+
speedMin = Math.min(speedMin, j.speed);
|
|
1126
|
+
speedMax = Math.max(speedMax, j.speed);
|
|
1127
|
+
}
|
|
1128
|
+
// Rotations
|
|
1129
|
+
if (Number.isFinite(j.rotations)) {
|
|
1130
|
+
rotationsSum += j.rotations;
|
|
1131
|
+
rotationsMin = Math.min(rotationsMin, j.rotations);
|
|
1132
|
+
rotationsMax = Math.max(rotationsMax, j.rotations);
|
|
1133
|
+
}
|
|
1134
|
+
// Score
|
|
1135
|
+
if (Number.isFinite(j.score)) {
|
|
1136
|
+
scoreSum += j.score;
|
|
1137
|
+
scoreMin = Math.min(scoreMin, j.score);
|
|
1138
|
+
scoreMax = Math.max(scoreMax, j.score);
|
|
1139
|
+
}
|
|
1140
|
+
// Height
|
|
1141
|
+
if (Number.isFinite(j.height)) {
|
|
1142
|
+
heightSum += j.height;
|
|
1143
|
+
heightMin = Math.min(heightMin, j.height);
|
|
1144
|
+
heightMax = Math.max(heightMax, j.height);
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
if (count > 0) {
|
|
1148
|
+
if (hangTimeMin !== Number.MAX_VALUE)
|
|
1149
|
+
stats.push(new data_jump_stats_1.DataJumpHangTimeMin(hangTimeMin));
|
|
1150
|
+
if (hangTimeMax !== -Number.MAX_VALUE)
|
|
1151
|
+
stats.push(new data_jump_stats_1.DataJumpHangTimeMax(hangTimeMax));
|
|
1152
|
+
if (hangTimeSum > 0)
|
|
1153
|
+
stats.push(new data_jump_stats_1.DataJumpHangTimeAvg(hangTimeSum / count)); // Assuming count is correct divisor for existing values
|
|
1154
|
+
if (distanceMin !== Number.MAX_VALUE)
|
|
1155
|
+
stats.push(new data_jump_stats_1.DataJumpDistanceMin(distanceMin));
|
|
1156
|
+
if (distanceMax !== -Number.MAX_VALUE)
|
|
1157
|
+
stats.push(new data_jump_stats_1.DataJumpDistanceMax(distanceMax));
|
|
1158
|
+
if (distanceSum > 0)
|
|
1159
|
+
stats.push(new data_jump_stats_1.DataJumpDistanceAvg(distanceSum / count));
|
|
1160
|
+
if (speedMin !== Number.MAX_VALUE)
|
|
1161
|
+
stats.push(new data_jump_stats_1.DataJumpSpeedMin(speedMin));
|
|
1162
|
+
if (speedMax !== -Number.MAX_VALUE)
|
|
1163
|
+
stats.push(new data_jump_stats_1.DataJumpSpeedMax(speedMax));
|
|
1164
|
+
if (speedSum > 0)
|
|
1165
|
+
stats.push(new data_jump_stats_1.DataJumpSpeedAvg(speedSum / count));
|
|
1166
|
+
if (rotationsMin !== Number.MAX_VALUE)
|
|
1167
|
+
stats.push(new data_jump_stats_1.DataJumpRotationsMin(rotationsMin));
|
|
1168
|
+
if (rotationsMax !== -Number.MAX_VALUE)
|
|
1169
|
+
stats.push(new data_jump_stats_1.DataJumpRotationsMax(rotationsMax));
|
|
1170
|
+
if (rotationsSum > 0)
|
|
1171
|
+
stats.push(new data_jump_stats_1.DataJumpRotationsAvg(rotationsSum / count));
|
|
1172
|
+
if (scoreMin !== Number.MAX_VALUE)
|
|
1173
|
+
stats.push(new data_jump_stats_1.DataJumpScoreMin(scoreMin));
|
|
1174
|
+
if (scoreMax !== -Number.MAX_VALUE)
|
|
1175
|
+
stats.push(new data_jump_stats_1.DataJumpScoreMax(scoreMax));
|
|
1176
|
+
if (scoreSum > 0)
|
|
1177
|
+
stats.push(new data_jump_stats_1.DataJumpScoreAvg(scoreSum / count));
|
|
1178
|
+
if (heightMin !== Number.MAX_VALUE)
|
|
1179
|
+
stats.push(new data_jump_stats_1.DataJumpHeightMin(heightMin));
|
|
1180
|
+
if (heightMax !== -Number.MAX_VALUE)
|
|
1181
|
+
stats.push(new data_jump_stats_1.DataJumpHeightMax(heightMax));
|
|
1182
|
+
if (heightSum > 0)
|
|
1183
|
+
stats.push(new data_jump_stats_1.DataJumpHeightAvg(heightSum / count));
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1083
1186
|
return stats;
|
|
1084
1187
|
}
|
|
1085
1188
|
static getCreatorFromFitDataObject(fitDataObject) {
|
|
@@ -21,6 +21,9 @@ const data_stryd_distance_1 = require("../../../../data/data.stryd-distance");
|
|
|
21
21
|
const data_stryd_speed_1 = require("../../../../data/data.stryd-speed");
|
|
22
22
|
const data_right_balance_1 = require("../../../../data/data.right-balance");
|
|
23
23
|
const data_left_balance_1 = require("../../../../data/data.left-balance");
|
|
24
|
+
const data_ground_contact_time_1 = require("../../../../data/data.ground-contact-time");
|
|
25
|
+
const data_ground_contact_time_balance_left_1 = require("../../../../data/data-ground-contact-time-balance-left");
|
|
26
|
+
const data_ground_contact_time_balance_right_1 = require("../../../../data/data-ground-contact-time-balance-right");
|
|
24
27
|
const data_stance_time_1 = require("../../../../data/data.stance-time");
|
|
25
28
|
const data_stance_time_balance_left_1 = require("../../../../data/data-stance-time-balance-left");
|
|
26
29
|
const data_step_length_1 = require("../../../../data/data.step-length");
|
|
@@ -213,12 +216,32 @@ exports.FITSampleMapper = [
|
|
|
213
216
|
: 100 - sample.left_right_balance.value;
|
|
214
217
|
}
|
|
215
218
|
},
|
|
219
|
+
{
|
|
220
|
+
dataType: data_ground_contact_time_1.DataGroundContactTime.type,
|
|
221
|
+
getSampleValue: (sample) => {
|
|
222
|
+
return sample.stance_time;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
// Keep DataStanceTime for backward compatibility
|
|
216
226
|
{
|
|
217
227
|
dataType: data_stance_time_1.DataStanceTime.type,
|
|
218
228
|
getSampleValue: (sample) => {
|
|
219
229
|
return sample.stance_time;
|
|
220
230
|
}
|
|
221
231
|
},
|
|
232
|
+
{
|
|
233
|
+
dataType: data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type,
|
|
234
|
+
getSampleValue: (sample) => {
|
|
235
|
+
return sample.stance_time_balance; // The field sample refers to the balance on left leg
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
dataType: data_ground_contact_time_balance_right_1.DataGroundContactTimeBalanceRight.type,
|
|
240
|
+
getSampleValue: (sample) => {
|
|
241
|
+
return (0, helpers_1.isNumber)(sample.stance_time_balance) ? 100 - sample.stance_time_balance : null;
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
// Keep DataStanceTimeBalanceLeft for backward compatibility
|
|
222
245
|
{
|
|
223
246
|
dataType: data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type,
|
|
224
247
|
getSampleValue: (sample) => {
|
|
@@ -47,7 +47,6 @@ const path = __importStar(require("path"));
|
|
|
47
47
|
const importer_fit_1 = require("./importer.fit");
|
|
48
48
|
const data_aerobic_training_effect_1 = require("../../../../data/data-aerobic-training-effect");
|
|
49
49
|
const data_anaerobic_training_effect_1 = require("../../../../data/data-anaerobic-training-effect");
|
|
50
|
-
const data_vo2_max_1 = require("../../../../data/data.vo2-max");
|
|
51
50
|
const data_recovery_time_1 = require("../../../../data/data.recovery-time");
|
|
52
51
|
const data_avg_respiration_rate_1 = require("../../../../data/data.avg-respiration-rate");
|
|
53
52
|
const data_heart_rate_zone_five_duration_1 = require("../../../../data/data.heart-rate-zone-five-duration");
|
|
@@ -146,10 +145,6 @@ describe('EventImporterFIT MTB Jumps', () => {
|
|
|
146
145
|
const anaerobic = activity.getStat(data_anaerobic_training_effect_1.DataAnaerobicTrainingEffect.type);
|
|
147
146
|
expect(anaerobic).toBeDefined();
|
|
148
147
|
expect(anaerobic.getValue()).toBe(2);
|
|
149
|
-
// VO2 Max
|
|
150
|
-
const vo2Max = activity.getStat(data_vo2_max_1.DataVO2Max.type);
|
|
151
|
-
expect(vo2Max).toBeDefined();
|
|
152
|
-
expect(vo2Max.getValue()).toBeCloseTo(57.0633, 4);
|
|
153
148
|
expect(activity.getStat(data_temperature_max_1.DataTemperatureMax.type).getValue()).toBe(19);
|
|
154
149
|
expect(activity.getStat(data_temperature_min_1.DataTemperatureMin.type).getValue()).toBe(7);
|
|
155
150
|
// Positions
|
|
@@ -200,13 +195,46 @@ describe('EventImporterFIT MTB Jumps', () => {
|
|
|
200
195
|
// Check Jumps
|
|
201
196
|
const jumpEvents = activity.getAllEvents().filter((e) => e.getType() === data_jump_event_1.DataJumpEvent.type);
|
|
202
197
|
expect(jumpEvents.length).toBeGreaterThan(0);
|
|
198
|
+
expect(jumpEvents.length).toBe(11);
|
|
203
199
|
const jump = jumpEvents[0];
|
|
204
200
|
expect(jump.jumpData).toBeDefined();
|
|
205
201
|
expect((0, helpers_1.isNumber)(jump.jumpData.distance)).toBeTruthy();
|
|
206
|
-
expect((0, helpers_1.isNumber)(jump.jumpData.height)).toBeTruthy();
|
|
207
202
|
expect((0, helpers_1.isNumber)(jump.jumpData.score)).toBeTruthy();
|
|
203
|
+
// Verify new jump fields with expected values
|
|
204
|
+
expect(jump.jumpData.distance).toBeCloseTo(2.069, 2);
|
|
205
|
+
expect(jump.jumpData.hang_time).toBeCloseTo(0.36, 2);
|
|
206
|
+
expect(jump.jumpData.score).toBeCloseTo(62.44, 1);
|
|
207
|
+
expect(jump.jumpData.position_lat).toBeCloseTo(39.6679, 3);
|
|
208
|
+
expect(jump.jumpData.position_long).toBeCloseTo(20.8382, 3);
|
|
209
|
+
expect(jump.jumpData.speed).toBeCloseTo(5.748, 2);
|
|
208
210
|
console.log(`Found ${jumpEvents.length} jumps.`);
|
|
209
211
|
console.log('First jump:', jump.jumpData);
|
|
212
|
+
// Verify Jump Statistics (Min, Max, Avg)
|
|
213
|
+
const { DataJumpDistanceAvg, DataJumpDistanceMax, DataJumpDistanceMin, DataJumpHangTimeAvg, DataJumpHangTimeMax, DataJumpHangTimeMin, DataJumpHeightAvg, DataJumpHeightMax, DataJumpHeightMin, DataJumpRotationsAvg, DataJumpRotationsMax, DataJumpRotationsMin, DataJumpScoreAvg, DataJumpScoreMax, DataJumpScoreMin, DataJumpSpeedAvg, DataJumpSpeedMax, DataJumpSpeedMin } = yield Promise.resolve().then(() => __importStar(require('../../../../data/data.jump-stats')));
|
|
214
|
+
// Hangtime
|
|
215
|
+
expect(activity.getStat(DataJumpHangTimeMin.type).getValue()).toBeCloseTo(0.36, 2);
|
|
216
|
+
expect(activity.getStat(DataJumpHangTimeMax.type).getValue()).toBeCloseTo(0.696, 3);
|
|
217
|
+
expect(activity.getStat(DataJumpHangTimeAvg.type).getValue()).toBeCloseTo(0.45, 2);
|
|
218
|
+
// Distance
|
|
219
|
+
expect(activity.getStat(DataJumpDistanceMin.type).getValue()).toBeCloseTo(1.40, 2);
|
|
220
|
+
expect(activity.getStat(DataJumpDistanceMax.type).getValue()).toBeCloseTo(4.68, 2);
|
|
221
|
+
expect(activity.getStat(DataJumpDistanceAvg.type).getValue()).toBeCloseTo(3.02, 2);
|
|
222
|
+
// Speed
|
|
223
|
+
expect(activity.getStat(DataJumpSpeedMin.type).getValue()).toBeCloseTo(3.88, 2);
|
|
224
|
+
expect(activity.getStat(DataJumpSpeedMax.type).getValue()).toBeCloseTo(8.995, 3);
|
|
225
|
+
expect(activity.getStat(DataJumpSpeedAvg.type).getValue()).toBeCloseTo(6.55, 2);
|
|
226
|
+
// Score
|
|
227
|
+
expect(activity.getStat(DataJumpScoreMin.type).getValue()).toBeCloseTo(53.9, 1);
|
|
228
|
+
expect(activity.getStat(DataJumpScoreMax.type).getValue()).toBeCloseTo(122.6, 1);
|
|
229
|
+
expect(activity.getStat(DataJumpScoreAvg.type).getValue()).toBeCloseTo(81.8, 1);
|
|
230
|
+
// Rotations (Should be undefined for this file)
|
|
231
|
+
expect(activity.getStat(DataJumpRotationsMin.type)).toBeUndefined();
|
|
232
|
+
expect(activity.getStat(DataJumpRotationsMax.type)).toBeUndefined();
|
|
233
|
+
expect(activity.getStat(DataJumpRotationsAvg.type)).toBeUndefined();
|
|
234
|
+
// Height (Should be undefined for this file)
|
|
235
|
+
expect(activity.getStat(DataJumpHeightMin.type)).toBeUndefined();
|
|
236
|
+
expect(activity.getStat(DataJumpHeightMax.type)).toBeUndefined();
|
|
237
|
+
expect(activity.getStat(DataJumpHeightAvg.type)).toBeUndefined();
|
|
210
238
|
// We can check if we can find a sample with Grit.
|
|
211
239
|
// In sports-lib, samples are often accessed via activity.getStream(type) or similar, BUT
|
|
212
240
|
// importer creates `DataPoint`s? Or `DataSample`s?
|
|
@@ -45,6 +45,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
const fs = __importStar(require("fs"));
|
|
46
46
|
const path = __importStar(require("path"));
|
|
47
47
|
const importer_suunto_json_1 = require("./importer.suunto.json");
|
|
48
|
+
const data_ground_contact_time_1 = require("../../../../data/data.ground-contact-time");
|
|
49
|
+
const data_ground_contact_time_avg_1 = require("../../../../data/data.ground-contact-time-avg");
|
|
50
|
+
const data_ground_contact_time_max_1 = require("../../../../data/data.ground-contact-time-max");
|
|
51
|
+
const data_ground_contact_time_min_1 = require("../../../../data/data.ground-contact-time-min");
|
|
52
|
+
const data_vertical_oscillation_1 = require("../../../../data/data.vertical-oscillation");
|
|
53
|
+
const data_vertical_oscillation_avg_1 = require("../../../../data/data.vertical-oscillation-avg");
|
|
54
|
+
const data_vertical_oscillation_max_1 = require("../../../../data/data.vertical-oscillation-max");
|
|
55
|
+
const data_vertical_oscillation_min_1 = require("../../../../data/data.vertical-oscillation-min");
|
|
56
|
+
const data_fitness_age_1 = require("../../../../data/data.fitness-age");
|
|
57
|
+
const data_max_hr_setting_1 = require("../../../../data/data.max-hr-setting");
|
|
48
58
|
describe('EventImporterSuuntoJSON Integration', () => {
|
|
49
59
|
// Go up 5 levels from src/events/adapters/importers/suunto -> sports-lib root
|
|
50
60
|
const samplesDir = path.resolve(__dirname, '../../../../../samples/suunto');
|
|
@@ -58,7 +68,6 @@ describe('EventImporterSuuntoJSON Integration', () => {
|
|
|
58
68
|
console.warn('No .json files found in samples directory.');
|
|
59
69
|
return;
|
|
60
70
|
}
|
|
61
|
-
console.log(`Found ${files.length} .json files to test:`, files);
|
|
62
71
|
for (const file of files) {
|
|
63
72
|
const filePath = path.join(samplesDir, file);
|
|
64
73
|
const fileString = fs.readFileSync(filePath, 'utf-8');
|
|
@@ -67,7 +76,6 @@ describe('EventImporterSuuntoJSON Integration', () => {
|
|
|
67
76
|
const event = yield importer_suunto_json_1.EventImporterSuuntoJSON.getFromJSONString(fileString);
|
|
68
77
|
expect(event).toBeDefined();
|
|
69
78
|
expect(event.getActivities().length).toBeGreaterThan(0);
|
|
70
|
-
console.log(`✅ Successfully parsed ${file}`);
|
|
71
79
|
}
|
|
72
80
|
catch (error) {
|
|
73
81
|
console.error(`❌ Failed to parse ${file}:`, error);
|
|
@@ -75,5 +83,81 @@ describe('EventImporterSuuntoJSON Integration', () => {
|
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
}));
|
|
78
|
-
|
|
86
|
+
describe('running-with-extra-data.json', () => {
|
|
87
|
+
let event;
|
|
88
|
+
let activity;
|
|
89
|
+
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
|
+
const filePath = path.join(samplesDir, 'running-with-extra-data.json');
|
|
91
|
+
if (!fs.existsSync(filePath)) {
|
|
92
|
+
console.warn('running-with-extra-data.json not found. Skipping detailed tests.');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const fileString = fs.readFileSync(filePath, 'utf-8');
|
|
96
|
+
event = yield importer_suunto_json_1.EventImporterSuuntoJSON.getFromJSONString(fileString);
|
|
97
|
+
// DEBUG: print one sample's date from the source file just blindly
|
|
98
|
+
// (we can't easily access json here again without parsing, but we can infer from activity)
|
|
99
|
+
// Find the main running activity (longest duration)
|
|
100
|
+
activity = event.getActivities().reduce((prev, current) => (prev.getDuration().getValue() > current.getDuration().getValue()) ? prev : current);
|
|
101
|
+
}));
|
|
102
|
+
it('should parse Ground Contact Time stream', () => {
|
|
103
|
+
if (!activity)
|
|
104
|
+
return;
|
|
105
|
+
// Depending on the file structure, GCT might be in the first or second activity.
|
|
106
|
+
// We selected the longest one.
|
|
107
|
+
const hasStream = activity.hasStreamData(data_ground_contact_time_1.DataGroundContactTime.type);
|
|
108
|
+
expect(hasStream).toBe(true);
|
|
109
|
+
if (hasStream) {
|
|
110
|
+
const stream = activity.getStreamData(data_ground_contact_time_1.DataGroundContactTime.type);
|
|
111
|
+
expect(stream.length).toBeGreaterThan(0);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
it('should parse Ground Contact Time stats (avg, max, min)', () => {
|
|
115
|
+
if (!activity)
|
|
116
|
+
return;
|
|
117
|
+
const avgStat = activity.getStat(data_ground_contact_time_avg_1.DataGroundContactTimeAvg.type);
|
|
118
|
+
const maxStat = activity.getStat(data_ground_contact_time_max_1.DataGroundContactTimeMax.type);
|
|
119
|
+
const minStat = activity.getStat(data_ground_contact_time_min_1.DataGroundContactTimeMin.type);
|
|
120
|
+
expect(avgStat).toBeDefined();
|
|
121
|
+
expect(avgStat === null || avgStat === void 0 ? void 0 : avgStat.getValue()).toBeCloseTo(255.969, 3);
|
|
122
|
+
expect(maxStat).toBeDefined();
|
|
123
|
+
expect(maxStat === null || maxStat === void 0 ? void 0 : maxStat.getValue()).toBe(339);
|
|
124
|
+
expect(minStat).toBeDefined();
|
|
125
|
+
expect(minStat === null || minStat === void 0 ? void 0 : minStat.getValue()).toBe(219);
|
|
126
|
+
});
|
|
127
|
+
it('should parse Vertical Oscillation stream', () => {
|
|
128
|
+
if (!activity)
|
|
129
|
+
return;
|
|
130
|
+
const hasStream = activity.hasStreamData(data_vertical_oscillation_1.DataVerticalOscillation.type);
|
|
131
|
+
expect(hasStream).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
it('should parse Vertical Oscillation stats (avg, max, min)', () => {
|
|
134
|
+
if (!activity)
|
|
135
|
+
return;
|
|
136
|
+
const avgStat = activity.getStat(data_vertical_oscillation_avg_1.DataVerticalOscillationAvg.type);
|
|
137
|
+
const maxStat = activity.getStat(data_vertical_oscillation_max_1.DataVerticalOscillationMax.type);
|
|
138
|
+
const minStat = activity.getStat(data_vertical_oscillation_min_1.DataVerticalOscillationMin.type);
|
|
139
|
+
expect(avgStat).toBeDefined();
|
|
140
|
+
expect(avgStat === null || avgStat === void 0 ? void 0 : avgStat.getValue()).toBeCloseTo(74.359, 3);
|
|
141
|
+
expect(maxStat).toBeDefined();
|
|
142
|
+
expect(maxStat === null || maxStat === void 0 ? void 0 : maxStat.getValue()).toBe(87);
|
|
143
|
+
expect(minStat).toBeDefined();
|
|
144
|
+
expect(minStat === null || minStat === void 0 ? void 0 : minStat.getValue()).toBe(42);
|
|
145
|
+
});
|
|
146
|
+
it('should parse Fitness Age from header (Event or Activity)', () => {
|
|
147
|
+
let stat = event.getStat(data_fitness_age_1.DataFitnessAge.type);
|
|
148
|
+
if (!stat && activity) {
|
|
149
|
+
stat = activity.getStat(data_fitness_age_1.DataFitnessAge.type);
|
|
150
|
+
}
|
|
151
|
+
expect(stat).toBeDefined();
|
|
152
|
+
expect(stat === null || stat === void 0 ? void 0 : stat.getValue()).toBe(25);
|
|
153
|
+
});
|
|
154
|
+
it('should parse Personal MaxHR from header (Event or Activity)', () => {
|
|
155
|
+
let stat = event.getStat(data_max_hr_setting_1.DataMaxHRSetting.type);
|
|
156
|
+
if (!stat && activity) {
|
|
157
|
+
stat = activity.getStat(data_max_hr_setting_1.DataMaxHRSetting.type);
|
|
158
|
+
}
|
|
159
|
+
expect(stat).toBeDefined();
|
|
160
|
+
expect(stat === null || stat === void 0 ? void 0 : stat.getValue()).toBe(171);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
79
163
|
});
|
|
@@ -100,6 +100,18 @@ const data_speed_zone_two_duration_1 = require("../../../../data/data.speed-zone
|
|
|
100
100
|
const data_speed_zone_three_duration_1 = require("../../../../data/data.speed-zone-three-duration");
|
|
101
101
|
const data_speed_zone_four_duration_1 = require("../../../../data/data.speed-zone-four-duration");
|
|
102
102
|
const data_speed_zone_five_duration_1 = require("../../../../data/data.speed-zone-five-duration");
|
|
103
|
+
const data_ground_contact_time_1 = require("../../../../data/data.ground-contact-time");
|
|
104
|
+
const data_ground_contact_time_avg_1 = require("../../../../data/data.ground-contact-time-avg");
|
|
105
|
+
const data_ground_contact_time_max_1 = require("../../../../data/data.ground-contact-time-max");
|
|
106
|
+
const data_ground_contact_time_min_1 = require("../../../../data/data.ground-contact-time-min");
|
|
107
|
+
const data_vertical_oscillation_1 = require("../../../../data/data.vertical-oscillation");
|
|
108
|
+
const data_vertical_oscillation_avg_1 = require("../../../../data/data.vertical-oscillation-avg");
|
|
109
|
+
const data_vertical_oscillation_max_1 = require("../../../../data/data.vertical-oscillation-max");
|
|
110
|
+
const data_vertical_oscillation_min_1 = require("../../../../data/data.vertical-oscillation-min");
|
|
111
|
+
const data_fitness_age_1 = require("../../../../data/data.fitness-age");
|
|
112
|
+
const data_max_hr_setting_1 = require("../../../../data/data.max-hr-setting");
|
|
113
|
+
const data_depth_1 = require("../../../../data/data.depth");
|
|
114
|
+
const data_depth_max_1 = require("../../../../data/data.depth-max");
|
|
103
115
|
const file_type_enum_1 = require("../../file-type.enum");
|
|
104
116
|
const activity_parsing_options_1 = require("../../../../activities/activity-parsing-options");
|
|
105
117
|
class EventImporterSuuntoJSON {
|
|
@@ -152,8 +164,11 @@ class EventImporterSuuntoJSON {
|
|
|
152
164
|
: [];
|
|
153
165
|
// Create the activities
|
|
154
166
|
const activities = activityStartEventSamples.map((activityStartEventSample, index) => {
|
|
167
|
+
// If no stop event, use the last sample time as end date
|
|
168
|
+
const lastSampleTime = eventJSONObject.DeviceLog.Samples[eventJSONObject.DeviceLog.Samples.length - 1].TimeISO8601;
|
|
169
|
+
const fallbackEndTime = stopEventSample ? stopEventSample.TimeISO8601 : lastSampleTime;
|
|
155
170
|
const activity = new activity_1.Activity(new Date(activityStartEventSample.TimeISO8601), activityStartEventSamples.length - 1 === index
|
|
156
|
-
? new Date(
|
|
171
|
+
? new Date(fallbackEndTime)
|
|
157
172
|
: new Date(activityStartEventSamples[index + 1].TimeISO8601), activity_types_1.ActivityTypes[(importer_suunto_activity_ids_1.ImporterSuuntoActivityIds[activityStartEventSample.Events[0].Activity.ActivityType])], creator, options);
|
|
158
173
|
// Set the end date to the stop event time if the activity is the last or the only one else set it on the next itery time
|
|
159
174
|
// Create the stats these are a 1:1 ref arrays
|
|
@@ -268,10 +283,6 @@ class EventImporterSuuntoJSON {
|
|
|
268
283
|
// @todo check if start and end date can derive from the json
|
|
269
284
|
const event = new event_1.Event('', activities[0].startDate, activities[activities.length - 1].endDate, file_type_enum_1.FileType.SUUNTO);
|
|
270
285
|
activities.forEach(activity => event.addActivity(activity));
|
|
271
|
-
// Populate the event stats from the Header Object // @todo maybe remove
|
|
272
|
-
this.getStats(eventJSONObject.DeviceLog.Header).forEach(stat => {
|
|
273
|
-
event.addStat(stat);
|
|
274
|
-
});
|
|
275
286
|
// Get the settings and add it to all activities as it's logical
|
|
276
287
|
if (eventJSONObject.DeviceLog.Header.Settings) {
|
|
277
288
|
this.getSettings(eventJSONObject.DeviceLog.Header.Settings).forEach(stat => {
|
|
@@ -285,9 +296,12 @@ class EventImporterSuuntoJSON {
|
|
|
285
296
|
stat instanceof data_pool_length_1.DataPoolLength);
|
|
286
297
|
stats.forEach(stat => activities[0].addStat(stat));
|
|
287
298
|
}
|
|
288
|
-
// @todo see how we can have those event stats persisted as the below generation wipes those off.
|
|
289
299
|
// Generate stats
|
|
290
300
|
event_utilities_1.EventUtilities.generateStatsForAll(event);
|
|
301
|
+
// Populate the event stats from the Header Object
|
|
302
|
+
this.getStats(eventJSONObject.DeviceLog.Header).forEach(stat => {
|
|
303
|
+
event.addStat(stat);
|
|
304
|
+
});
|
|
291
305
|
resolve(event);
|
|
292
306
|
});
|
|
293
307
|
}
|
|
@@ -355,8 +369,12 @@ class EventImporterSuuntoJSON {
|
|
|
355
369
|
return samples;
|
|
356
370
|
}
|
|
357
371
|
static setStreamsForActivity(activity, samples) {
|
|
372
|
+
// console.log(`Setting streams for activity with ${samples.length} samples`);
|
|
358
373
|
exports.SuuntoSampleMapper.forEach(sampleMapping => {
|
|
359
374
|
const subjectSamples = samples.filter(sample => (0, helpers_1.isNumberOrString)(sample[sampleMapping.sampleField]));
|
|
375
|
+
// if (sampleMapping.sampleField === 'GroundContactTime') {
|
|
376
|
+
// console.log(`GCT Samples found: ${subjectSamples.length}`);
|
|
377
|
+
// }
|
|
360
378
|
if (subjectSamples.length) {
|
|
361
379
|
activity.addStream(activity.createStream(sampleMapping.dataType));
|
|
362
380
|
subjectSamples.forEach(subjectSample => {
|
|
@@ -525,6 +543,53 @@ class EventImporterSuuntoJSON {
|
|
|
525
543
|
}
|
|
526
544
|
}
|
|
527
545
|
}
|
|
546
|
+
// Ground Contact Time (Running Dynamics)
|
|
547
|
+
if (object.hasOwnProperty('GroundContactTime')) {
|
|
548
|
+
if (Array.isArray(object.GroundContactTime)) {
|
|
549
|
+
if ((0, helpers_1.isNumber)(object.GroundContactTime[0].Avg)) {
|
|
550
|
+
stats.push(new data_ground_contact_time_avg_1.DataGroundContactTimeAvg(object.GroundContactTime[0].Avg * 1000)); // Convert s to ms
|
|
551
|
+
}
|
|
552
|
+
if ((0, helpers_1.isNumber)(object.GroundContactTime[0].Max)) {
|
|
553
|
+
stats.push(new data_ground_contact_time_max_1.DataGroundContactTimeMax(object.GroundContactTime[0].Max * 1000));
|
|
554
|
+
}
|
|
555
|
+
if ((0, helpers_1.isNumber)(object.GroundContactTime[0].Min)) {
|
|
556
|
+
stats.push(new data_ground_contact_time_min_1.DataGroundContactTimeMin(object.GroundContactTime[0].Min * 1000));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// Vertical Oscillation (Running Dynamics)
|
|
561
|
+
if (object.hasOwnProperty('VerticalOscillation')) {
|
|
562
|
+
if (Array.isArray(object.VerticalOscillation)) {
|
|
563
|
+
if ((0, helpers_1.isNumber)(object.VerticalOscillation[0].Avg)) {
|
|
564
|
+
stats.push(new data_vertical_oscillation_avg_1.DataVerticalOscillationAvg(object.VerticalOscillation[0].Avg * 1000)); // Convert m to mm
|
|
565
|
+
}
|
|
566
|
+
if ((0, helpers_1.isNumber)(object.VerticalOscillation[0].Max)) {
|
|
567
|
+
stats.push(new data_vertical_oscillation_max_1.DataVerticalOscillationMax(object.VerticalOscillation[0].Max * 1000));
|
|
568
|
+
}
|
|
569
|
+
if ((0, helpers_1.isNumber)(object.VerticalOscillation[0].Min)) {
|
|
570
|
+
stats.push(new data_vertical_oscillation_min_1.DataVerticalOscillationMin(object.VerticalOscillation[0].Min * 1000));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
// Fitness Age
|
|
575
|
+
if ((0, helpers_1.isNumber)(object.FitnessAge)) {
|
|
576
|
+
stats.push(new data_fitness_age_1.DataFitnessAge(object.FitnessAge));
|
|
577
|
+
}
|
|
578
|
+
// Personal MaxHR
|
|
579
|
+
if (object.Personal && (0, helpers_1.isNumber)(object.Personal.MaxHR)) {
|
|
580
|
+
stats.push(new data_max_hr_setting_1.DataMaxHRSetting(object.Personal.MaxHR * 60)); // Convert from Hz to bpm
|
|
581
|
+
}
|
|
582
|
+
// Depth (Diving)
|
|
583
|
+
if (object.hasOwnProperty('Depth')) {
|
|
584
|
+
if (Array.isArray(object.Depth)) {
|
|
585
|
+
if ((0, helpers_1.isNumber)(object.Depth[0].Max) && object.Depth[0].Max > 0) {
|
|
586
|
+
stats.push(new data_depth_max_1.DataDepthMax(object.Depth[0].Max));
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
else if ((0, helpers_1.isNumber)(object.Depth.Max) && object.Depth.Max > 0) {
|
|
590
|
+
stats.push(new data_depth_max_1.DataDepthMax(object.Depth.Max));
|
|
591
|
+
}
|
|
592
|
+
}
|
|
528
593
|
return stats;
|
|
529
594
|
}
|
|
530
595
|
}
|
|
@@ -717,5 +782,20 @@ exports.SuuntoSampleMapper = [
|
|
|
717
782
|
dataType: data_battery_voltage_1.DataBatteryVoltage.type,
|
|
718
783
|
sampleField: 'BatteryVoltage',
|
|
719
784
|
convertSampleValue: (value) => Number(value)
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
dataType: data_vertical_oscillation_1.DataVerticalOscillation.type,
|
|
788
|
+
sampleField: 'VerticalOscillation',
|
|
789
|
+
convertSampleValue: (value) => Number(value * 1000) // Convert m to mm
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
dataType: data_ground_contact_time_1.DataGroundContactTime.type,
|
|
793
|
+
sampleField: 'GroundContactTime',
|
|
794
|
+
convertSampleValue: (value) => Number(value * 1000) // Convert s to ms
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
dataType: data_depth_1.DataDepth.type,
|
|
798
|
+
sampleField: 'Depth',
|
|
799
|
+
convertSampleValue: (value) => Number(value)
|
|
720
800
|
}
|
|
721
801
|
];
|
|
@@ -82,6 +82,18 @@ const data_speed_zone_two_duration_1 = require("../../data/data.speed-zone-two-d
|
|
|
82
82
|
const data_speed_zone_three_duration_1 = require("../../data/data.speed-zone-three-duration");
|
|
83
83
|
const data_speed_zone_four_duration_1 = require("../../data/data.speed-zone-four-duration");
|
|
84
84
|
const data_speed_zone_five_duration_1 = require("../../data/data.speed-zone-five-duration");
|
|
85
|
+
const data_ground_contact_time_1 = require("../../data/data.ground-contact-time");
|
|
86
|
+
const data_ground_contact_time_avg_1 = require("../../data/data.ground-contact-time-avg");
|
|
87
|
+
const data_ground_contact_time_max_1 = require("../../data/data.ground-contact-time-max");
|
|
88
|
+
const data_ground_contact_time_min_1 = require("../../data/data.ground-contact-time-min");
|
|
89
|
+
const data_ground_contact_time_balance_left_1 = require("../../data/data-ground-contact-time-balance-left");
|
|
90
|
+
const data_ground_contact_time_balance_right_1 = require("../../data/data-ground-contact-time-balance-right");
|
|
91
|
+
const data_vertical_oscillation_1 = require("../../data/data.vertical-oscillation");
|
|
92
|
+
const data_vertical_oscillation_avg_1 = require("../../data/data.vertical-oscillation-avg");
|
|
93
|
+
const data_vertical_oscillation_max_1 = require("../../data/data.vertical-oscillation-max");
|
|
94
|
+
const data_vertical_oscillation_min_1 = require("../../data/data.vertical-oscillation-min");
|
|
95
|
+
const data_stance_time_balance_left_1 = require("../../data/data-stance-time-balance-left");
|
|
96
|
+
const data_stance_time_balance_right_1 = require("../../data/data-stance-time-balance-right");
|
|
85
97
|
const data_store_1 = require("../../data/data.store");
|
|
86
98
|
const data_start_position_1 = require("../../data/data.start-position");
|
|
87
99
|
const data_end_position_1 = require("../../data/data.end-position");
|
|
@@ -101,8 +113,6 @@ const data_altitude_smooth_1 = require("../../data/data.altitude-smooth");
|
|
|
101
113
|
const data_grade_smooth_1 = require("../../data/data.grade-smooth");
|
|
102
114
|
const data_swolf_25m_1 = require("../../data/data.swolf-25m");
|
|
103
115
|
const data_swolf_50m_1 = require("../../data/data.swolf-50m");
|
|
104
|
-
const data_stance_time_balance_left_1 = require("../../data/data-stance-time-balance-left");
|
|
105
|
-
const data_stance_time_balance_right_1 = require("../../data/data-stance-time-balance-right");
|
|
106
116
|
const low_pass_filter_1 = require("./grade-calculator/low-pass-filter");
|
|
107
117
|
const data_power_normalized_1 = require("../../data/data.power-normalized");
|
|
108
118
|
const data_power_work_1 = require("../../data/data.power-work");
|
|
@@ -1310,11 +1320,37 @@ class ActivityUtilities {
|
|
|
1310
1320
|
activity.addStat(new data_left_balance_1.DataLeftBalance(100 - avgRightBalance));
|
|
1311
1321
|
}
|
|
1312
1322
|
// Assign L/R balance stance time from streams if exists
|
|
1323
|
+
if (!activity.getStat(data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type) && activity.hasStreamData(data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type)) {
|
|
1324
|
+
const avgStanceTimeLeftBalance = this.round(this.getDataTypeAvg(activity, data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft.type), 2);
|
|
1325
|
+
activity.addStat(new data_ground_contact_time_balance_left_1.DataGroundContactTimeBalanceLeft(avgStanceTimeLeftBalance));
|
|
1326
|
+
activity.addStat(new data_ground_contact_time_balance_right_1.DataGroundContactTimeBalanceRight(100 - avgStanceTimeLeftBalance));
|
|
1327
|
+
}
|
|
1328
|
+
// Backward compatibility for Stance Time Balance
|
|
1313
1329
|
if (!activity.getStat(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type) && activity.hasStreamData(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type)) {
|
|
1314
1330
|
const avgStanceTimeLeftBalance = this.round(this.getDataTypeAvg(activity, data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type), 2);
|
|
1315
1331
|
activity.addStat(new data_stance_time_balance_left_1.DataStanceTimeBalanceLeft(avgStanceTimeLeftBalance));
|
|
1316
1332
|
activity.addStat(new data_stance_time_balance_right_1.DataStanceTimeBalanceRight(100 - avgStanceTimeLeftBalance));
|
|
1317
1333
|
}
|
|
1334
|
+
// Ground Contact Time
|
|
1335
|
+
if (!activity.getStat(data_ground_contact_time_max_1.DataGroundContactTimeMax.type) && activity.hasStreamData(data_ground_contact_time_1.DataGroundContactTime.type)) {
|
|
1336
|
+
activity.addStat(new data_ground_contact_time_max_1.DataGroundContactTimeMax(this.getDataTypeMax(activity, data_ground_contact_time_1.DataGroundContactTime.type)));
|
|
1337
|
+
}
|
|
1338
|
+
if (!activity.getStat(data_ground_contact_time_min_1.DataGroundContactTimeMin.type) && activity.hasStreamData(data_ground_contact_time_1.DataGroundContactTime.type)) {
|
|
1339
|
+
activity.addStat(new data_ground_contact_time_min_1.DataGroundContactTimeMin(this.getDataTypeMin(activity, data_ground_contact_time_1.DataGroundContactTime.type)));
|
|
1340
|
+
}
|
|
1341
|
+
if (!activity.getStat(data_ground_contact_time_avg_1.DataGroundContactTimeAvg.type) && activity.hasStreamData(data_ground_contact_time_1.DataGroundContactTime.type)) {
|
|
1342
|
+
activity.addStat(new data_ground_contact_time_avg_1.DataGroundContactTimeAvg(this.getDataTypeAvg(activity, data_ground_contact_time_1.DataGroundContactTime.type)));
|
|
1343
|
+
}
|
|
1344
|
+
// Vertical Oscillation
|
|
1345
|
+
if (!activity.getStat(data_vertical_oscillation_max_1.DataVerticalOscillationMax.type) && activity.hasStreamData(data_vertical_oscillation_1.DataVerticalOscillation.type)) {
|
|
1346
|
+
activity.addStat(new data_vertical_oscillation_max_1.DataVerticalOscillationMax(this.getDataTypeMax(activity, data_vertical_oscillation_1.DataVerticalOscillation.type)));
|
|
1347
|
+
}
|
|
1348
|
+
if (!activity.getStat(data_vertical_oscillation_min_1.DataVerticalOscillationMin.type) && activity.hasStreamData(data_vertical_oscillation_1.DataVerticalOscillation.type)) {
|
|
1349
|
+
activity.addStat(new data_vertical_oscillation_min_1.DataVerticalOscillationMin(this.getDataTypeMin(activity, data_vertical_oscillation_1.DataVerticalOscillation.type)));
|
|
1350
|
+
}
|
|
1351
|
+
if (!activity.getStat(data_vertical_oscillation_avg_1.DataVerticalOscillationAvg.type) && activity.hasStreamData(data_vertical_oscillation_1.DataVerticalOscillation.type)) {
|
|
1352
|
+
activity.addStat(new data_vertical_oscillation_avg_1.DataVerticalOscillationAvg(this.getDataTypeAvg(activity, data_vertical_oscillation_1.DataVerticalOscillation.type)));
|
|
1353
|
+
}
|
|
1318
1354
|
}
|
|
1319
1355
|
static generateMissingSpeedDerivedStatsForActivity(activity) {
|
|
1320
1356
|
// Pace
|