@sports-alliance/sports-lib 7.0.8 → 7.0.9

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.
Files changed (326) hide show
  1. package/lib/esm/index.js +12034 -152
  2. package/package.json +2 -2
  3. package/lib/esm/activities/activity-parsing-options.js +0 -19
  4. package/lib/esm/activities/activity.interface.js +0 -1
  5. package/lib/esm/activities/activity.js +0 -281
  6. package/lib/esm/activities/activity.json.interface.js +0 -1
  7. package/lib/esm/activities/activity.spec.js +0 -348
  8. package/lib/esm/activities/activity.types.js +0 -1046
  9. package/lib/esm/activities/activityt-types.spec.js +0 -16
  10. package/lib/esm/activities/devices/device.interface.js +0 -1
  11. package/lib/esm/activities/devices/device.js +0 -26
  12. package/lib/esm/activities/devices/device.json.interface.js +0 -1
  13. package/lib/esm/constants/constants.js +0 -8
  14. package/lib/esm/creators/creator.interface.js +0 -1
  15. package/lib/esm/creators/creator.js +0 -37
  16. package/lib/esm/creators/creator.json.interface.js +0 -1
  17. package/lib/esm/creators/creator.spec.js +0 -25
  18. package/lib/esm/data/data-active-lap.js +0 -4
  19. package/lib/esm/data/data-active-lengths.js +0 -4
  20. package/lib/esm/data/data-aerobic-training-effect.js +0 -8
  21. package/lib/esm/data/data-anaerobic-training-effect.js +0 -8
  22. package/lib/esm/data/data-stance-time-balance-left.js +0 -4
  23. package/lib/esm/data/data-stance-time-balance-right.js +0 -4
  24. package/lib/esm/data/data-stance-time-balance.js +0 -3
  25. package/lib/esm/data/data-store.spec.js +0 -78
  26. package/lib/esm/data/data-total-cycles.js +0 -4
  27. package/lib/esm/data/data.absolute-pressure.js +0 -5
  28. package/lib/esm/data/data.accumulated-power.js +0 -8
  29. package/lib/esm/data/data.activity-types.js +0 -7
  30. package/lib/esm/data/data.air-power-avg.js +0 -4
  31. package/lib/esm/data/data.air-power-max.js +0 -4
  32. package/lib/esm/data/data.air-power-min.js +0 -4
  33. package/lib/esm/data/data.air-power.js +0 -8
  34. package/lib/esm/data/data.alti-baro-profile.js +0 -4
  35. package/lib/esm/data/data.altitude-avg.js +0 -4
  36. package/lib/esm/data/data.altitude-gps.js +0 -5
  37. package/lib/esm/data/data.altitude-max.js +0 -4
  38. package/lib/esm/data/data.altitude-min.js +0 -4
  39. package/lib/esm/data/data.altitude-smooth.js +0 -4
  40. package/lib/esm/data/data.altitude.js +0 -8
  41. package/lib/esm/data/data.array.js +0 -13
  42. package/lib/esm/data/data.ascent-time.js +0 -4
  43. package/lib/esm/data/data.ascent.js +0 -4
  44. package/lib/esm/data/data.auto-lap-distance.js +0 -5
  45. package/lib/esm/data/data.auto-lap-duration.js +0 -4
  46. package/lib/esm/data/data.auto-lap-used.js +0 -7
  47. package/lib/esm/data/data.auto-pause-used.js +0 -7
  48. package/lib/esm/data/data.avg-stride-length.js +0 -4
  49. package/lib/esm/data/data.balance.js +0 -6
  50. package/lib/esm/data/data.bare.js +0 -4
  51. package/lib/esm/data/data.battery-charge.js +0 -8
  52. package/lib/esm/data/data.battery-consumption.js +0 -8
  53. package/lib/esm/data/data.battery-current.js +0 -8
  54. package/lib/esm/data/data.battery-life-estimation.js +0 -4
  55. package/lib/esm/data/data.battery-voltage.js +0 -8
  56. package/lib/esm/data/data.bike-pod-used.js +0 -7
  57. package/lib/esm/data/data.boolean.js +0 -9
  58. package/lib/esm/data/data.cadence-avg.js +0 -4
  59. package/lib/esm/data/data.cadence-max.js +0 -4
  60. package/lib/esm/data/data.cadence-min.js +0 -4
  61. package/lib/esm/data/data.cadence.js +0 -8
  62. package/lib/esm/data/data.cycling-dynamics.js +0 -3
  63. package/lib/esm/data/data.cycling-position.js +0 -37
  64. package/lib/esm/data/data.cycling-seated-time.js +0 -5
  65. package/lib/esm/data/data.cycling-standing-time.js +0 -5
  66. package/lib/esm/data/data.descent-time.js +0 -4
  67. package/lib/esm/data/data.descent.js +0 -4
  68. package/lib/esm/data/data.description.js +0 -4
  69. package/lib/esm/data/data.device-location.js +0 -4
  70. package/lib/esm/data/data.device-names.js +0 -7
  71. package/lib/esm/data/data.distance.js +0 -15
  72. package/lib/esm/data/data.duration.js +0 -56
  73. package/lib/esm/data/data.ehpe.js +0 -5
  74. package/lib/esm/data/data.enabled-navigation-systems.js +0 -4
  75. package/lib/esm/data/data.end-altitude.js +0 -4
  76. package/lib/esm/data/data.end-position.js +0 -4
  77. package/lib/esm/data/data.energy.js +0 -8
  78. package/lib/esm/data/data.epoc.js +0 -5
  79. package/lib/esm/data/data.event.js +0 -3
  80. package/lib/esm/data/data.evpe.js +0 -4
  81. package/lib/esm/data/data.feeling.js +0 -15
  82. package/lib/esm/data/data.foot-pod-used.js +0 -7
  83. package/lib/esm/data/data.form-power.js +0 -4
  84. package/lib/esm/data/data.fused-altitude.js +0 -7
  85. package/lib/esm/data/data.fused-location.js +0 -7
  86. package/lib/esm/data/data.gnss-distance.js +0 -4
  87. package/lib/esm/data/data.grade-adjusted-pace-avg.js +0 -15
  88. package/lib/esm/data/data.grade-adjusted-pace-max.js +0 -15
  89. package/lib/esm/data/data.grade-adjusted-pace-min.js +0 -15
  90. package/lib/esm/data/data.grade-adjusted-pace.js +0 -25
  91. package/lib/esm/data/data.grade-adjusted-speed-avg.js +0 -46
  92. package/lib/esm/data/data.grade-adjusted-speed-max.js +0 -46
  93. package/lib/esm/data/data.grade-adjusted-speed-min.js +0 -46
  94. package/lib/esm/data/data.grade-adjusted-speed.js +0 -78
  95. package/lib/esm/data/data.grade-smooth.js +0 -7
  96. package/lib/esm/data/data.grade.js +0 -7
  97. package/lib/esm/data/data.ground-time.js +0 -8
  98. package/lib/esm/data/data.heart-rate-avg.js +0 -4
  99. package/lib/esm/data/data.heart-rate-max.js +0 -4
  100. package/lib/esm/data/data.heart-rate-min.js +0 -4
  101. package/lib/esm/data/data.heart-rate-used.js +0 -7
  102. package/lib/esm/data/data.heart-rate-zone-five-duration.js +0 -4
  103. package/lib/esm/data/data.heart-rate-zone-four-duration.js +0 -4
  104. package/lib/esm/data/data.heart-rate-zone-one-duration.js +0 -4
  105. package/lib/esm/data/data.heart-rate-zone-three-duration.js +0 -4
  106. package/lib/esm/data/data.heart-rate-zone-two-duration.js +0 -4
  107. package/lib/esm/data/data.heart-rate.js +0 -8
  108. package/lib/esm/data/data.ibi.js +0 -8
  109. package/lib/esm/data/data.interface.js +0 -5
  110. package/lib/esm/data/data.js +0 -62
  111. package/lib/esm/data/data.json.interface.js +0 -1
  112. package/lib/esm/data/data.latitude-degrees.js +0 -5
  113. package/lib/esm/data/data.left-balance.js +0 -4
  114. package/lib/esm/data/data.leg-stiffness.js +0 -16
  115. package/lib/esm/data/data.longitude-degrees.js +0 -5
  116. package/lib/esm/data/data.moving-time.js +0 -4
  117. package/lib/esm/data/data.number-of-satellites.js +0 -7
  118. package/lib/esm/data/data.number-of.samples.js +0 -4
  119. package/lib/esm/data/data.number.js +0 -13
  120. package/lib/esm/data/data.pace-avg.js +0 -8
  121. package/lib/esm/data/data.pace-max.js +0 -8
  122. package/lib/esm/data/data.pace-min.js +0 -8
  123. package/lib/esm/data/data.pace.js +0 -46
  124. package/lib/esm/data/data.pause.js +0 -4
  125. package/lib/esm/data/data.peak-epoc.js +0 -7
  126. package/lib/esm/data/data.peak-training-effect.js +0 -4
  127. package/lib/esm/data/data.percent.js +0 -4
  128. package/lib/esm/data/data.pool-length.js +0 -5
  129. package/lib/esm/data/data.position.interface.js +0 -1
  130. package/lib/esm/data/data.position.js +0 -18
  131. package/lib/esm/data/data.power-avg.js +0 -4
  132. package/lib/esm/data/data.power-down.js +0 -4
  133. package/lib/esm/data/data.power-intensity-factor.js +0 -5
  134. package/lib/esm/data/data.power-left.js +0 -4
  135. package/lib/esm/data/data.power-max.js +0 -4
  136. package/lib/esm/data/data.power-min.js +0 -4
  137. package/lib/esm/data/data.power-normalized.js +0 -4
  138. package/lib/esm/data/data.power-pedal-smoothness-left.js +0 -4
  139. package/lib/esm/data/data.power-pedal-smoothness-right.js +0 -4
  140. package/lib/esm/data/data.power-pod-used.js +0 -7
  141. package/lib/esm/data/data.power-right.js +0 -4
  142. package/lib/esm/data/data.power-torque-effectiveness-left.js +0 -4
  143. package/lib/esm/data/data.power-torque-effectiveness-right.js +0 -4
  144. package/lib/esm/data/data.power-training-stress-score.js +0 -5
  145. package/lib/esm/data/data.power-up.js +0 -4
  146. package/lib/esm/data/data.power-work.js +0 -5
  147. package/lib/esm/data/data.power-zone-five-duration.js +0 -4
  148. package/lib/esm/data/data.power-zone-four-duration.js +0 -4
  149. package/lib/esm/data/data.power-zone-one-duration.js +0 -4
  150. package/lib/esm/data/data.power-zone-three-duration.js +0 -4
  151. package/lib/esm/data/data.power-zone-two-duration.js +0 -4
  152. package/lib/esm/data/data.power.js +0 -8
  153. package/lib/esm/data/data.recovery-time.js +0 -7
  154. package/lib/esm/data/data.rider-position-change-event.js +0 -8
  155. package/lib/esm/data/data.right-balance.js +0 -4
  156. package/lib/esm/data/data.rpe.js +0 -23
  157. package/lib/esm/data/data.satellite-5-best-snr.js +0 -4
  158. package/lib/esm/data/data.sea-level-pressure.js +0 -5
  159. package/lib/esm/data/data.spec.js +0 -25
  160. package/lib/esm/data/data.speed-avg.js +0 -46
  161. package/lib/esm/data/data.speed-max.js +0 -46
  162. package/lib/esm/data/data.speed-min.js +0 -46
  163. package/lib/esm/data/data.speed-zone-five-duration.js +0 -4
  164. package/lib/esm/data/data.speed-zone-four-duration.js +0 -4
  165. package/lib/esm/data/data.speed-zone-one-duration.js +0 -4
  166. package/lib/esm/data/data.speed-zone-three-duration.js +0 -4
  167. package/lib/esm/data/data.speed-zone-two-duration.js +0 -4
  168. package/lib/esm/data/data.speed.js +0 -88
  169. package/lib/esm/data/data.sport-profile-name.js +0 -4
  170. package/lib/esm/data/data.stance-time.js +0 -5
  171. package/lib/esm/data/data.start-altitude.js +0 -4
  172. package/lib/esm/data/data.start-event.js +0 -4
  173. package/lib/esm/data/data.start-position.js +0 -4
  174. package/lib/esm/data/data.step-length.js +0 -4
  175. package/lib/esm/data/data.steps-old.js +0 -4
  176. package/lib/esm/data/data.steps.js +0 -4
  177. package/lib/esm/data/data.stop-all-event.js +0 -4
  178. package/lib/esm/data/data.stop-event.js +0 -4
  179. package/lib/esm/data/data.store.export.spec.js +0 -66
  180. package/lib/esm/data/data.store.js +0 -1213
  181. package/lib/esm/data/data.string.js +0 -13
  182. package/lib/esm/data/data.stryd-altitude.js +0 -4
  183. package/lib/esm/data/data.stryd-distance.js +0 -4
  184. package/lib/esm/data/data.stryd-speed.js +0 -4
  185. package/lib/esm/data/data.swim-pace-avg.js +0 -8
  186. package/lib/esm/data/data.swim-pace-max.js +0 -8
  187. package/lib/esm/data/data.swim-pace-min.js +0 -8
  188. package/lib/esm/data/data.swim-pace.js +0 -19
  189. package/lib/esm/data/data.swolf-25m.js +0 -4
  190. package/lib/esm/data/data.swolf-50m.js +0 -4
  191. package/lib/esm/data/data.target-distance.js +0 -4
  192. package/lib/esm/data/data.target-heart-rate-zone.js +0 -4
  193. package/lib/esm/data/data.target-power-zone.js +0 -4
  194. package/lib/esm/data/data.target-speed-zone.js +0 -4
  195. package/lib/esm/data/data.target-time.js +0 -4
  196. package/lib/esm/data/data.temperature-avg.js +0 -4
  197. package/lib/esm/data/data.temperature-max.js +0 -4
  198. package/lib/esm/data/data.temperature-min.js +0 -4
  199. package/lib/esm/data/data.temperature.js +0 -8
  200. package/lib/esm/data/data.time.js +0 -6
  201. package/lib/esm/data/data.timer-time.js +0 -4
  202. package/lib/esm/data/data.vertical-oscillation.js +0 -5
  203. package/lib/esm/data/data.vertical-ratio.js +0 -5
  204. package/lib/esm/data/data.vertical-speed-avg.js +0 -53
  205. package/lib/esm/data/data.vertical-speed-max.js +0 -53
  206. package/lib/esm/data/data.vertical-speed-min.js +0 -53
  207. package/lib/esm/data/data.vertical-speed.js +0 -103
  208. package/lib/esm/data/data.vo2-max.js +0 -7
  209. package/lib/esm/data/ibi/data.ibi.filters.js +0 -52
  210. package/lib/esm/data/ibi/data.ibi.js +0 -98
  211. package/lib/esm/data/ibi/data.ibi.spec.js +0 -66
  212. package/lib/esm/duration/duration.class.abstract.js +0 -36
  213. package/lib/esm/duration/duration.class.interface.js +0 -1
  214. package/lib/esm/errors/duration-exceeded-event-lib.error.js +0 -9
  215. package/lib/esm/errors/empty-event-sports-libs.error.js +0 -9
  216. package/lib/esm/errors/event-lib.error.js +0 -8
  217. package/lib/esm/errors/lib.error.js +0 -6
  218. package/lib/esm/errors/parsing-event-lib.error.js +0 -9
  219. package/lib/esm/events/adapters/exporters/exporter.gpx.js +0 -75
  220. package/lib/esm/events/adapters/exporters/exporter.interface.js +0 -1
  221. package/lib/esm/events/adapters/exporters/exporter.json.js +0 -20
  222. package/lib/esm/events/adapters/file-type.enum.js +0 -7
  223. package/lib/esm/events/adapters/importers/fit/importer.fit.ant-plus.device.names.js +0 -25
  224. package/lib/esm/events/adapters/importers/fit/importer.fit.coros.device.names.js +0 -5
  225. package/lib/esm/events/adapters/importers/fit/importer.fit.development.device.names.js +0 -4
  226. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.device.names.js +0 -462
  227. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.data.js +0 -877
  228. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.js +0 -106
  229. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.spec.js +0 -32
  230. package/lib/esm/events/adapters/importers/fit/importer.fit.hammerhead.device.names.js +0 -4
  231. package/lib/esm/events/adapters/importers/fit/importer.fit.integration.spec.js +0 -44
  232. package/lib/esm/events/adapters/importers/fit/importer.fit.js +0 -978
  233. package/lib/esm/events/adapters/importers/fit/importer.fit.lezyne.device.names.js +0 -3
  234. package/lib/esm/events/adapters/importers/fit/importer.fit.magellan.device.names.js +0 -5
  235. package/lib/esm/events/adapters/importers/fit/importer.fit.mapper.js +0 -231
  236. package/lib/esm/events/adapters/importers/fit/importer.fit.saris.device.names.js +0 -3
  237. package/lib/esm/events/adapters/importers/fit/importer.fit.spec.js +0 -326
  238. package/lib/esm/events/adapters/importers/fit/importer.fit.srm.device.names.js +0 -7
  239. package/lib/esm/events/adapters/importers/fit/importer.fit.suunto.device.names.js +0 -16
  240. package/lib/esm/events/adapters/importers/fit/importer.fit.wahoo.device.names.js +0 -10
  241. package/lib/esm/events/adapters/importers/gpx/gx-parser.js +0 -36
  242. package/lib/esm/events/adapters/importers/gpx/importer.gpx.integration.spec.js +0 -44
  243. package/lib/esm/events/adapters/importers/gpx/importer.gpx.js +0 -102
  244. package/lib/esm/events/adapters/importers/gpx/importer.gpx.mapper.js +0 -142
  245. package/lib/esm/events/adapters/importers/gpx/importer.gpx.spec.js +0 -71
  246. package/lib/esm/events/adapters/importers/json/importer.json.js +0 -160
  247. package/lib/esm/events/adapters/importers/sample-info.interface.js +0 -1
  248. package/lib/esm/events/adapters/importers/suunto/importer.suunto.activity.ids.js +0 -85
  249. package/lib/esm/events/adapters/importers/suunto/importer.suunto.device.names.js +0 -26
  250. package/lib/esm/events/adapters/importers/suunto/importer.suunto.integration.spec.js +0 -44
  251. package/lib/esm/events/adapters/importers/suunto/importer.suunto.json.js +0 -717
  252. package/lib/esm/events/adapters/importers/suunto/importer.suunto.sml.js +0 -125
  253. package/lib/esm/events/adapters/importers/tcx/importer.tcx.integration.spec.js +0 -46
  254. package/lib/esm/events/adapters/importers/tcx/importer.tcx.js +0 -442
  255. package/lib/esm/events/adapters/importers/tcx/importer.tcx.mapper.js +0 -91
  256. package/lib/esm/events/adapters/importers/tcx/utils.tcx.js +0 -36
  257. package/lib/esm/events/event.interface.js +0 -1
  258. package/lib/esm/events/event.js +0 -123
  259. package/lib/esm/events/event.json.interface.js +0 -1
  260. package/lib/esm/events/event.spec.js +0 -51
  261. package/lib/esm/events/utilities/activity.utilities.js +0 -1841
  262. package/lib/esm/events/utilities/activity.utilities.spec.js +0 -373
  263. package/lib/esm/events/utilities/event.utilities.js +0 -57
  264. package/lib/esm/events/utilities/grade-calculator/grade-calculator.js +0 -121
  265. package/lib/esm/events/utilities/grade-calculator/grade-calculator.spec.js +0 -93
  266. package/lib/esm/events/utilities/grade-calculator/low-pass-filter.js +0 -86
  267. package/lib/esm/events/utilities/helpers.js +0 -162
  268. package/lib/esm/geodesy/adapters/adapter.interface.js +0 -1
  269. package/lib/esm/geodesy/adapters/geolib.adapter.js +0 -28
  270. package/lib/esm/id/id.abstract.class.js +0 -9
  271. package/lib/esm/id/id.class.interface.js +0 -1
  272. package/lib/esm/id/id.class.spec.js +0 -13
  273. package/lib/esm/intensity-zones/intensity-zones.interface.js +0 -1
  274. package/lib/esm/intensity-zones/intensity-zones.js +0 -29
  275. package/lib/esm/intensity-zones/intensity-zones.json.interface.js +0 -1
  276. package/lib/esm/intensity-zones/intensity-zones.spec.js +0 -30
  277. package/lib/esm/laps/lap.interface.js +0 -1
  278. package/lib/esm/laps/lap.js +0 -29
  279. package/lib/esm/laps/lap.json.interface.js +0 -1
  280. package/lib/esm/laps/lap.types.js +0 -52
  281. package/lib/esm/meta-data/event-meta-data.interface.js +0 -6
  282. package/lib/esm/meta-data/meta-data.js +0 -57
  283. package/lib/esm/meta-data/meta-data.json.interface.js +0 -1
  284. package/lib/esm/privacy/privacy.class.interface.js +0 -5
  285. package/lib/esm/serializable/serializable.class.interface.js +0 -1
  286. package/lib/esm/service-tokens/oauth1-service-token.interface.js +0 -1
  287. package/lib/esm/service-tokens/oauth2-service-token.interface.js +0 -1
  288. package/lib/esm/specs/activities-parsing.integration.spec.js +0 -1847
  289. package/lib/esm/specs/activity-duration-stream.integration.spec.js +0 -57
  290. package/lib/esm/specs/fixtures/streams/strava/rides/3171472783.json +0 -52534
  291. package/lib/esm/specs/fixtures/streams/strava/rides/3171487458.json +0 -78818
  292. package/lib/esm/specs/fixtures/streams/strava/rides/343080886.json +0 -105090
  293. package/lib/esm/specs/fixtures/streams/strava/rides/5910143591.json +0 -110711
  294. package/lib/esm/specs/fixtures/streams/strava/runs/2451375851.json +0 -74846
  295. package/lib/esm/specs/fixtures/streams/strava/runs/2709634581.json +0 -66817
  296. package/lib/esm/specs/fixtures/streams/strava/runs/3156040843.json +0 -17594
  297. package/lib/esm/specs/fixtures/streams/strava/runs/3182900697.json +0 -17322
  298. package/lib/esm/specs/fixtures/streams/strava/runs/3183465494.json +0 -20463
  299. package/lib/esm/specs/fixtures/streams/strava/runs/3183490558.json +0 -58202
  300. package/lib/esm/specs/spec-utils.js +0 -159
  301. package/lib/esm/specs/strava-streams-compliance.spec.js +0 -951
  302. package/lib/esm/stats/stats.class.abstract.js +0 -32
  303. package/lib/esm/stats/stats.class.interface.js +0 -1
  304. package/lib/esm/stats/stats.json.interface.js +0 -1
  305. package/lib/esm/streams/compressed.stream.interface.js +0 -12
  306. package/lib/esm/streams/ibi-stream.js +0 -43
  307. package/lib/esm/streams/low-pass.stream.filter.js +0 -9
  308. package/lib/esm/streams/stream.filter.interface.js +0 -1
  309. package/lib/esm/streams/stream.interface.js +0 -1
  310. package/lib/esm/streams/stream.js +0 -72
  311. package/lib/esm/streams/stream.spec.js +0 -168
  312. package/lib/esm/tiles/tile.settings.interface.js +0 -41
  313. package/lib/esm/users/settings/dashboard/user.dashboard.settings.interface.js +0 -13
  314. package/lib/esm/users/settings/user.app.settings.interface.js +0 -5
  315. package/lib/esm/users/settings/user.chart.settings.interface.js +0 -23
  316. package/lib/esm/users/settings/user.map.settings.interface.js +0 -22
  317. package/lib/esm/users/settings/user.my-tracks.settings.interface.js +0 -1
  318. package/lib/esm/users/settings/user.settings.interface.js +0 -1
  319. package/lib/esm/users/settings/user.stats-settings.interface.js +0 -1
  320. package/lib/esm/users/settings/user.summaries.settings.interface.js +0 -1
  321. package/lib/esm/users/settings/user.unit.settings.interface.js +0 -73
  322. package/lib/esm/users/user.account.privileges.interface.js +0 -1
  323. package/lib/esm/users/user.export-to-csv.settings.interface.js +0 -1
  324. package/lib/esm/users/user.interface.js +0 -1
  325. package/lib/esm/users/user.js +0 -38
  326. package/lib/esm/users/user.service.meta.interface.js +0 -1
@@ -1,1841 +0,0 @@
1
- import { DataHeartRate } from '../../data/data.heart-rate';
2
- import { DataCadence } from '../../data/data.cadence';
3
- import { DataSpeed } from '../../data/data.speed';
4
- import { DataVerticalSpeed } from '../../data/data.vertical-speed';
5
- import { DataTemperature } from '../../data/data.temperature';
6
- import { DataAltitude } from '../../data/data.altitude';
7
- import { DataPower } from '../../data/data.power';
8
- import { DataAltitudeMax } from '../../data/data.altitude-max';
9
- import { DataAltitudeMin } from '../../data/data.altitude-min';
10
- import { DataAltitudeAvg } from '../../data/data.altitude-avg';
11
- import { DataHeartRateMax } from '../../data/data.heart-rate-max';
12
- import { DataHeartRateMin } from '../../data/data.heart-rate-min';
13
- import { DataHeartRateAvg } from '../../data/data.heart-rate-avg';
14
- import { DataCadenceMax } from '../../data/data.cadence-max';
15
- import { DataCadenceMin } from '../../data/data.cadence-min';
16
- import { DataCadenceAvg } from '../../data/data.cadence-avg';
17
- import { DataSpeedMax, DataSpeedMaxFeetPerMinute, DataSpeedMaxFeetPerSecond, DataSpeedMaxKilometersPerHour, DataSpeedMaxKnots, DataSpeedMaxMetersPerMinute, DataSpeedMaxMilesPerHour } from '../../data/data.speed-max';
18
- import { DataSpeedMin, DataSpeedMinFeetPerMinute, DataSpeedMinFeetPerSecond, DataSpeedMinKilometersPerHour, DataSpeedMinKnots, DataSpeedMinMetersPerMinute, DataSpeedMinMilesPerHour } from '../../data/data.speed-min';
19
- import { DataSpeedAvg, DataSpeedAvgFeetPerMinute, DataSpeedAvgFeetPerSecond, DataSpeedAvgKilometersPerHour, DataSpeedAvgKnots, DataSpeedAvgMetersPerMinute, DataSpeedAvgMilesPerHour } from '../../data/data.speed-avg';
20
- import { DataVerticalSpeedMax, DataVerticalSpeedMaxFeetPerHour, DataVerticalSpeedMaxFeetPerMinute, DataVerticalSpeedMaxFeetPerSecond, DataVerticalSpeedMaxKilometerPerHour, DataVerticalSpeedMaxMetersPerHour, DataVerticalSpeedMaxMetersPerMinute, DataVerticalSpeedMaxMilesPerHour } from '../../data/data.vertical-speed-max';
21
- import { DataVerticalSpeedMin, DataVerticalSpeedMinFeetPerHour, DataVerticalSpeedMinFeetPerMinute, DataVerticalSpeedMinFeetPerSecond, DataVerticalSpeedMinKilometerPerHour, DataVerticalSpeedMinMetersPerHour, DataVerticalSpeedMinMetersPerMinute, DataVerticalSpeedMinMilesPerHour } from '../../data/data.vertical-speed-min';
22
- import { DataVerticalSpeedAvg, DataVerticalSpeedAvgFeetPerHour, DataVerticalSpeedAvgFeetPerMinute, DataVerticalSpeedAvgFeetPerSecond, DataVerticalSpeedAvgKilometerPerHour, DataVerticalSpeedAvgMetersPerHour, DataVerticalSpeedAvgMetersPerMinute, DataVerticalSpeedAvgMilesPerHour } from '../../data/data.vertical-speed-avg';
23
- import { DataPowerMax } from '../../data/data.power-max';
24
- import { DataPowerMin } from '../../data/data.power-min';
25
- import { DataPowerAvg } from '../../data/data.power-avg';
26
- import { DataTemperatureMax } from '../../data/data.temperature-max';
27
- import { DataTemperatureMin } from '../../data/data.temperature-min';
28
- import { DataTemperatureAvg } from '../../data/data.temperature-avg';
29
- import { DataDistance } from '../../data/data.distance';
30
- import { DataDuration } from '../../data/data.duration';
31
- import { DataPause } from '../../data/data.pause';
32
- import { DataAscent } from '../../data/data.ascent';
33
- import { DataDescent } from '../../data/data.descent';
34
- import { GeoLibAdapter } from '../../geodesy/adapters/geolib.adapter';
35
- import { DataPaceMax, DataPaceMaxMinutesPerMile } from '../../data/data.pace-max';
36
- import { DataPace } from '../../data/data.pace';
37
- import { DataPaceMin, DataPaceMinMinutesPerMile } from '../../data/data.pace-min';
38
- import { DataPaceAvg, DataPaceAvgMinutesPerMile } from '../../data/data.pace-avg';
39
- import { DataBatteryCharge } from '../../data/data.battery-charge';
40
- import { DataBatteryConsumption } from '../../data/data.battery-consumption';
41
- import { DataBatteryLifeEstimation } from '../../data/data.battery-life-estimation';
42
- import { DataLatitudeDegrees } from '../../data/data.latitude-degrees';
43
- import { Stream } from '../../streams/stream';
44
- import { convertPaceToPaceInMinutesPerMile, convertSpeedToPace, convertSpeedToSpeedInFeetPerHour, convertSpeedToSpeedInFeetPerMinute, convertSpeedToSpeedInFeetPerSecond, convertSpeedToSpeedInKilometersPerHour, convertSpeedToSpeedInKnots, convertSpeedToSpeedInMetersPerHour, convertSpeedToSpeedInMetersPerMinute, convertSpeedToSpeedInMilesPerHour, convertSpeedToSwimPace, convertSwimPaceToSwimPacePer100Yard, isNumber, isNumberOrString, medianFilter, standardDeviation } from './helpers';
45
- import { DataLongitudeDegrees } from '../../data/data.longitude-degrees';
46
- import { DataEnergy } from '../../data/data.energy';
47
- import { DataStartAltitude } from '../../data/data.start-altitude';
48
- import { DataEndAltitude } from '../../data/data.end-altitude';
49
- import { DataSwimPaceMax, DataSwimPaceMaxMinutesPer100Yard } from '../../data/data.swim-pace-max';
50
- import { DataSwimPace } from '../../data/data.swim-pace';
51
- import { DataSwimPaceMin, DataSwimPaceMinMinutesPer100Yard } from '../../data/data.swim-pace-min';
52
- import { DataSwimPaceAvg, DataSwimPaceAvgMinutesPer100Yard } from '../../data/data.swim-pace-avg';
53
- import { DataFeeling } from '../../data/data.feeling';
54
- import { DataPowerLeft } from '../../data/data.power-left';
55
- import { DataRightBalance } from '../../data/data.right-balance';
56
- import { DataLeftBalance } from '../../data/data.left-balance';
57
- import { DataPowerRight } from '../../data/data.power-right';
58
- import { DataAirPowerMin } from '../../data/data.air-power-min';
59
- import { DataAirPower } from '../../data/data.air-power';
60
- import { DataAirPowerMax } from '../../data/data.air-power-max';
61
- import { DataAirPowerAvg } from '../../data/data.air-power-avg';
62
- import { DataRPE } from '../../data/data.rpe';
63
- import { DataGNSSDistance } from '../../data/data.gnss-distance';
64
- import { DataHeartRateZoneOneDuration } from '../../data/data.heart-rate-zone-one-duration';
65
- import { DataHeartRateZoneTwoDuration } from '../../data/data.heart-rate-zone-two-duration';
66
- import { DataHeartRateZoneThreeDuration } from '../../data/data.heart-rate-zone-three-duration';
67
- import { DataHeartRateZoneFourDuration } from '../../data/data.heart-rate-zone-four-duration';
68
- import { DataHeartRateZoneFiveDuration } from '../../data/data.heart-rate-zone-five-duration';
69
- import { DataPowerZoneOneDuration } from '../../data/data.power-zone-one-duration';
70
- import { DataPowerZoneTwoDuration } from '../../data/data.power-zone-two-duration';
71
- import { DataPowerZoneThreeDuration } from '../../data/data.power-zone-three-duration';
72
- import { DataPowerZoneFourDuration } from '../../data/data.power-zone-four-duration';
73
- import { DataPowerZoneFiveDuration } from '../../data/data.power-zone-five-duration';
74
- import { DataSpeedZoneOneDuration } from '../../data/data.speed-zone-one-duration';
75
- import { DataSpeedZoneTwoDuration } from '../../data/data.speed-zone-two-duration';
76
- import { DataSpeedZoneThreeDuration } from '../../data/data.speed-zone-three-duration';
77
- import { DataSpeedZoneFourDuration } from '../../data/data.speed-zone-four-duration';
78
- import { DataSpeedZoneFiveDuration } from '../../data/data.speed-zone-five-duration';
79
- import { DynamicDataLoader } from '../../data/data.store';
80
- import { DataStartPosition } from '../../data/data.start-position';
81
- import { DataEndPosition } from '../../data/data.end-position';
82
- import { DataGradeAdjustedSpeedAvg, DataGradeAdjustedSpeedAvgFeetPerMinute, DataGradeAdjustedSpeedAvgFeetPerSecond, DataGradeAdjustedSpeedAvgKilometersPerHour, DataGradeAdjustedSpeedAvgKnots, DataGradeAdjustedSpeedAvgMetersPerMinute, DataGradeAdjustedSpeedAvgMilesPerHour } from '../../data/data.grade-adjusted-speed-avg';
83
- import { DataGradeAdjustedPaceAvg, DataGradeAdjustedPaceAvgMinutesPerMile } from '../../data/data.grade-adjusted-pace-avg';
84
- import { DataGradeAdjustedSpeed } from '../../data/data.grade-adjusted-speed';
85
- import { DataGradeAdjustedPace } from '../../data/data.grade-adjusted-pace';
86
- import { DataGradeAdjustedSpeedMax, DataGradeAdjustedSpeedMaxFeetPerMinute, DataGradeAdjustedSpeedMaxFeetPerSecond, DataGradeAdjustedSpeedMaxKilometersPerHour, DataGradeAdjustedSpeedMaxKnots, DataGradeAdjustedSpeedMaxMetersPerMinute, DataGradeAdjustedSpeedMaxMilesPerHour } from '../../data/data.grade-adjusted-speed-max';
87
- import { DataGradeAdjustedSpeedMin, DataGradeAdjustedSpeedMinFeetPerMinute, DataGradeAdjustedSpeedMinFeetPerSecond, DataGradeAdjustedSpeedMinKilometersPerHour, DataGradeAdjustedSpeedMinKnots, DataGradeAdjustedSpeedMinMetersPerMinute, DataGradeAdjustedSpeedMinMilesPerHour } from '../../data/data.grade-adjusted-speed-min';
88
- import { DataGradeAdjustedPaceMax, DataGradeAdjustedPaceMaxMinutesPerMile } from '../../data/data.grade-adjusted-pace-max';
89
- import { DataGradeAdjustedPaceMin, DataGradeAdjustedPaceMinMinutesPerMile } from '../../data/data.grade-adjusted-pace-min';
90
- import { DataGrade } from '../../data/data.grade';
91
- import { ActivityTypeGroups, ActivityTypes, ActivityTypesHelper, ActivityTypesMoving } from '../../activities/activity.types';
92
- import { DataMovingTime } from '../../data/data.moving-time';
93
- import { DataTimerTime } from '../../data/data.timer-time';
94
- import { DataAltitudeSmooth } from '../../data/data.altitude-smooth';
95
- import { DataGradeSmooth } from '../../data/data.grade-smooth';
96
- import { DataSWOLF25m } from '../../data/data.swolf-25m';
97
- import { DataSWOLF50m } from '../../data/data.swolf-50m';
98
- import { DataStanceTimeBalanceLeft } from '../../data/data-stance-time-balance-left';
99
- import { DataStanceTimeBalanceRight } from '../../data/data-stance-time-balance-right';
100
- import { LowPassFilter } from './grade-calculator/low-pass-filter';
101
- import { DataPowerNormalized } from '../../data/data.power-normalized';
102
- import { DataPowerWork } from '../../data/data.power-work';
103
- import { GradeCalculator } from './grade-calculator/grade-calculator';
104
- const KalmanFilter = require('kalmanjs');
105
- /* Configure filtering values */
106
- // Altitude stream
107
- const ALTITUDE_SPIKES_FILTER_WIN = 3;
108
- // Fix abnormal streams
109
- const SPEED_STREAM_STD_DEV_THRESHOLD_DEFAULT = 25 / 3.6; // Kph to mps
110
- const SPEED_STREAM_STD_DEV_THRESHOLD_MAP = new Map([
111
- [ActivityTypeGroups.Running, 15 / 3.6], // kph to m/s
112
- [ActivityTypeGroups.Cycling, 27 / 3.6], // kph to m/s
113
- [ActivityTypeGroups.Swimming, 5 / 3.6] // kph to m/s
114
- ]);
115
- export class ActivityUtilities {
116
- /**
117
- * Provide average from laps a given stat type
118
- */
119
- static getDataTypeAvgFromLaps(activity, statType, filterOver) {
120
- const data = activity
121
- .getLaps()
122
- .map(lap => { var _a; return (_a = lap.getStat(statType)) === null || _a === void 0 ? void 0 : _a.getValue(); })
123
- .filter(d => Number.isFinite(d) && (Number.isFinite(filterOver) ? d > filterOver : true));
124
- if (data.length > 0) {
125
- return this.getAverage(data);
126
- }
127
- return null;
128
- }
129
- /**
130
- * Provide average of a given stream type
131
- */
132
- static getDataTypeAvg(activity, streamType, startDate, endDate, filterOver) {
133
- const data = (activity
134
- .getSquashedStreamData(streamType, startDate, endDate)
135
- .filter(streamData => streamData !== Infinity &&
136
- streamData !== -Infinity &&
137
- (Number.isFinite(filterOver) ? streamData > filterOver : true)));
138
- return this.getAverage(data);
139
- }
140
- static round(value, decimals = 0) {
141
- const decimalsFactor = Math.pow(10, decimals);
142
- return Math.round(value * decimalsFactor) / decimalsFactor;
143
- }
144
- static getAverage(data) {
145
- return this.getSum(data) / data.length;
146
- }
147
- static getSum(data) {
148
- return data.reduce((sumbuff, value) => {
149
- sumbuff += value;
150
- return sumbuff;
151
- }, 0);
152
- }
153
- static getDataTypeMax(activity, streamType, startDate, endDate) {
154
- return this.getActivityDataTypeMinOrMax(activity, streamType, true, startDate, endDate);
155
- }
156
- static getDataTypeMin(activity, streamType, startDate, endDate, filterOver) {
157
- return this.getActivityDataTypeMinOrMax(activity, streamType, false, startDate, endDate, filterOver);
158
- }
159
- static getDataTypeMinToMaxDifference(activity, streamType, startDate, endDate) {
160
- return (this.getDataTypeMax(activity, streamType, startDate, endDate) -
161
- this.getDataTypeMin(activity, streamType, startDate, endDate));
162
- }
163
- static getDataTypeFirst(activity, streamType, startDate, endDate) {
164
- const data = activity.getSquashedStreamData(streamType, startDate, endDate);
165
- return data[0];
166
- }
167
- static getDataTypeLast(activity, streamType, startDate, endDate) {
168
- const data = activity.getSquashedStreamData(streamType, startDate, endDate);
169
- return data[data.length - 1];
170
- }
171
- static cropDistance(startDistance, endDistance, activity) {
172
- // Short to do the search just in case
173
- let startDistanceDate; // Does not sound right
174
- let endDistanceDate;
175
- // debugger;
176
- activity.getStreamData(DataDistance.type).forEach((distanceFromData, index) => {
177
- // Find the index with greater dinstnce and convert it to time
178
- if (startDistance && !startDistanceDate && distanceFromData && distanceFromData >= startDistance) {
179
- startDistanceDate = new Date(activity.startDate.getTime() + index * 1000);
180
- return;
181
- }
182
- // Same for end
183
- if (endDistance && !endDistanceDate && distanceFromData && distanceFromData >= endDistance) {
184
- endDistanceDate = new Date(activity.startDate.getTime() + index * 1000);
185
- return;
186
- }
187
- });
188
- if (!startDistanceDate && !endDistanceDate) {
189
- return activity;
190
- }
191
- activity = this.cropTime(activity, startDistanceDate, endDistanceDate);
192
- // Remove because it is invalid, you cannot just offset the distance as a stream I think
193
- const distanceStream = activity.getAllStreams().find(s => DataDistance.type === s.type);
194
- if (distanceStream) {
195
- activity.removeStream(distanceStream);
196
- }
197
- const gnssDistanceStream = activity.getAllStreams().find(s => DataGNSSDistance.type === s.type);
198
- if (gnssDistanceStream) {
199
- activity.removeStream(gnssDistanceStream);
200
- }
201
- return activity;
202
- }
203
- /**
204
- * Crops left,right on time.
205
- * Start and end date need to be relative to the activity start / end time
206
- * @param activity
207
- * @param startDate
208
- * @param endDate
209
- */
210
- static cropTime(activity, startDate, endDate) {
211
- activity.getAllStreams().forEach(stream => {
212
- // Get the data for the range specified
213
- const trimmedStreamData = activity.getStreamData(stream.type, startDate, endDate);
214
- activity.removeStream(stream);
215
- activity.addStream(new Stream(stream.type, trimmedStreamData));
216
- });
217
- activity.startDate = startDate || activity.startDate;
218
- activity.endDate = endDate || activity.endDate;
219
- // debugger
220
- return activity;
221
- }
222
- static getStreamDataTypesBasedOnDataType(streamToBaseOn, streams) {
223
- return streamToBaseOn.getData().reduce((accu, streamDataItem, index) => {
224
- if (!isNumberOrString(streamDataItem)) {
225
- return accu;
226
- }
227
- const dataItem = {
228
- [streamToBaseOn.type]: streamDataItem
229
- };
230
- streams.forEach(stream => {
231
- dataItem[stream.type] = stream.getData()[index];
232
- });
233
- accu.push(dataItem);
234
- return accu;
235
- }, []);
236
- }
237
- static getStreamDataTypesBasedOnTime(startDate, endDate, streams) {
238
- const streamDataBasedOnTime = {};
239
- for (let i = 0; i < this.getDataLength(startDate, endDate); i++) {
240
- // Perhaps this can be optimized with a search function
241
- streams.forEach((stream) => {
242
- if (isNumber(stream.getData()[i])) {
243
- streamDataBasedOnTime[startDate.getTime() + i * 1000] =
244
- streamDataBasedOnTime[startDate.getTime() + i * 1000] || {};
245
- streamDataBasedOnTime[startDate.getTime() + i * 1000][stream.type] = stream.getData()[i];
246
- }
247
- });
248
- }
249
- return streamDataBasedOnTime;
250
- }
251
- static getDataLength(startDate, endDate) {
252
- return Math.ceil((+endDate - +startDate) / 1000) + 1;
253
- }
254
- static generateMissingStreamsAndStatsForActivity(activity) {
255
- this.generateMissingStreams(activity);
256
- this.fixAbnormalStreamData(activity);
257
- this.generateMissingStatsForActivity(activity);
258
- this.generateMissingSpeedDerivedStatsForActivity(activity);
259
- this.generateMissingUnitStatsForActivity(activity); // Perhaps this needs to happen on user level so needs to go out of here
260
- }
261
- static fixAbnormalStreamData(activity) {
262
- var _a, _b, _c;
263
- // Check if fix abnormal speed option has been enable and if we have stream data and position data (e.g. do not fix for swim pool activities)
264
- if (((_c = (_b = (_a = activity.parseOptions) === null || _a === void 0 ? void 0 : _a.streams) === null || _b === void 0 ? void 0 : _b.fixAbnormal) === null || _c === void 0 ? void 0 : _c.speed) &&
265
- activity.hasStreamData(DataSpeed.type) &&
266
- activity.hasStreamData(DataLatitudeDegrees.type) &&
267
- activity.hasStreamData(DataLongitudeDegrees.type)) {
268
- // Check for speed data dispersion using standard deviation
269
- const speedStdDev = standardDeviation(activity.getSquashedStreamData(DataSpeed.type));
270
- // Get speed standard deviation threshold at which we will attempt to fix the stream
271
- const stdDevThreshold = SPEED_STREAM_STD_DEV_THRESHOLD_MAP.get(ActivityTypesHelper.getActivityGroupForActivityType(activity.type)) ||
272
- SPEED_STREAM_STD_DEV_THRESHOLD_DEFAULT;
273
- if (speedStdDev > stdDevThreshold) {
274
- // Fix/Predict speed stream through Kalman filtering
275
- this.shapeStream(DataSpeed.type, activity, squashedSpeedData => {
276
- // Grade stream
277
- const SPEED_KALMAN_SMOOTHING = {
278
- R: 0.01, // Speed model calculation is something stable
279
- Q: speedStdDev * 2 // We intend to get a measurement error which can be under and over std dev (explaining the double factor)
280
- };
281
- // Apply kalman filter
282
- const kf = new KalmanFilter(SPEED_KALMAN_SMOOTHING);
283
- return squashedSpeedData.map(v => (v === null ? null : kf.filter(v)));
284
- });
285
- }
286
- }
287
- }
288
- static generateMissingStreams(activity) {
289
- // Compute missing streams
290
- this.generateMissingStreamsForActivity(activity);
291
- // Always include derived base streams (like Pace), but conditionally include unit variants
292
- const includeUnitVariants = !activity.parseOptions || activity.parseOptions.generateUnitStreams;
293
- activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type, undefined, {
294
- includeDerivedTypes: true, // Always include derived base types (Pace etc)
295
- includeUnitVariants
296
- }));
297
- }
298
- static getSummaryStatsForActivities(activities) {
299
- const stats = [];
300
- // If only one
301
- if (activities.length === 1) {
302
- return activities[0].getStatsAsArray();
303
- }
304
- let duration = 0;
305
- let ascent = 0;
306
- let descent = 0;
307
- let energy = 0;
308
- let distance = 0;
309
- let pauseTime = 0;
310
- let averageHeartRate = 0;
311
- let averagePower = 0;
312
- let averageCadence = 0;
313
- let averageSpeed = 0;
314
- let averageGradeAdjustedSpeed = 0;
315
- let averagePace = 0;
316
- let averageGradeAdjustedPace = 0;
317
- let averageSwimPace = 0;
318
- let averageTemperature = 0;
319
- let averageFeeling = 0;
320
- let averageRPE = 0;
321
- // Sum Duration
322
- activities.forEach(activity => {
323
- duration += activity.getDuration().getValue();
324
- });
325
- stats.push(new DataDuration(duration));
326
- // Sum pause time
327
- activities.forEach(activity => {
328
- pauseTime += activity.getPause().getValue();
329
- });
330
- stats.push(new DataPause(pauseTime));
331
- // Sum Distance
332
- activities.forEach(activity => {
333
- distance += activity.getDistance().getValue();
334
- });
335
- stats.push(new DataDistance(distance));
336
- // Sum ascent
337
- activities.forEach(activity => {
338
- const activityAscent = activity.getStat(DataAscent.type);
339
- if (activityAscent) {
340
- ascent += activityAscent.getValue();
341
- }
342
- });
343
- stats.push(new DataAscent(ascent));
344
- // Sum descent
345
- activities.forEach(activity => {
346
- const activityDescent = activity.getStat(DataDescent.type);
347
- if (activityDescent) {
348
- descent += activityDescent.getValue();
349
- }
350
- });
351
- stats.push(new DataDescent(descent));
352
- // Sum energy
353
- activities.forEach(activity => {
354
- const activityEnergy = activity.getStat(DataEnergy.type);
355
- if (activityEnergy) {
356
- energy += activityEnergy.getValue();
357
- }
358
- });
359
- stats.push(new DataEnergy(energy));
360
- // Avg Avg HR
361
- activities.forEach(activity => {
362
- const activityAvgHeartRate = activity.getStat(DataHeartRateAvg.type);
363
- if (activityAvgHeartRate) {
364
- // The below will fallback for 0
365
- averageHeartRate = averageHeartRate
366
- ? (averageHeartRate + activityAvgHeartRate.getValue()) / 2
367
- : activityAvgHeartRate.getValue();
368
- }
369
- });
370
- if (averageHeartRate) {
371
- stats.push(new DataHeartRateAvg(averageHeartRate));
372
- }
373
- // Avg Avg HR
374
- activities.forEach(activity => {
375
- const activityAvgHeartRate = activity.getStat(DataHeartRateAvg.type);
376
- if (activityAvgHeartRate) {
377
- // The below will fallback for 0
378
- averageHeartRate = averageHeartRate
379
- ? (averageHeartRate + activityAvgHeartRate.getValue()) / 2
380
- : activityAvgHeartRate.getValue();
381
- }
382
- });
383
- if (averageHeartRate) {
384
- stats.push(new DataHeartRateAvg(averageHeartRate));
385
- }
386
- // Avg Avg Power
387
- activities.forEach(activity => {
388
- const activityAvgPower = activity.getStat(DataPowerAvg.type);
389
- if (activityAvgPower) {
390
- // The below will fallback for 0
391
- averagePower = averagePower
392
- ? (averagePower + activityAvgPower.getValue()) / 2
393
- : activityAvgPower.getValue();
394
- }
395
- });
396
- if (averagePower) {
397
- stats.push(new DataPowerAvg(averagePower));
398
- }
399
- // Avg Avg Cadence
400
- activities.forEach(activity => {
401
- const activityAvgCadence = activity.getStat(DataCadenceAvg.type);
402
- if (activityAvgCadence) {
403
- // The below will fallback for 0
404
- averageCadence = averageCadence
405
- ? (averageCadence + activityAvgCadence.getValue()) / 2
406
- : activityAvgCadence.getValue();
407
- }
408
- });
409
- if (averageCadence) {
410
- stats.push(new DataCadenceAvg(averageCadence));
411
- }
412
- // Avg Avg Speed
413
- activities.forEach(activity => {
414
- const activityAvgSpeed = activity.getStat(DataSpeedAvg.type);
415
- if (activityAvgSpeed) {
416
- // The below will fallback for 0
417
- averageSpeed = averageSpeed
418
- ? (averageSpeed + activityAvgSpeed.getValue()) / 2
419
- : activityAvgSpeed.getValue();
420
- }
421
- });
422
- if (averageSpeed) {
423
- stats.push(new DataSpeedAvg(averageSpeed));
424
- }
425
- // Avg Avg Gap Speed
426
- activities.forEach(activity => {
427
- const activityAvgGradeAdjustedSpeed = activity.getStat(DataGradeAdjustedSpeedAvg.type);
428
- if (activityAvgGradeAdjustedSpeed) {
429
- // The below will fallback for 0
430
- averageGradeAdjustedSpeed = averageGradeAdjustedSpeed
431
- ? (averageGradeAdjustedSpeed + activityAvgGradeAdjustedSpeed.getValue()) / 2
432
- : activityAvgGradeAdjustedSpeed.getValue();
433
- }
434
- });
435
- if (averageGradeAdjustedSpeed) {
436
- stats.push(new DataGradeAdjustedSpeedAvg(averageGradeAdjustedSpeed));
437
- }
438
- // Avg Avg Pace
439
- activities.forEach(activity => {
440
- const activityAvgPace = activity.getStat(DataPaceAvg.type);
441
- if (activityAvgPace) {
442
- // The below will fallback for 0
443
- averagePace = averagePace
444
- ? (averagePace + activityAvgPace.getValue()) / 2
445
- : activityAvgPace.getValue();
446
- }
447
- });
448
- if (averagePace) {
449
- stats.push(new DataPaceAvg(averagePace));
450
- }
451
- // Avg Avg GAP Pace
452
- activities.forEach(activity => {
453
- const activityAvgGradeAdjustedPace = activity.getStat(DataGradeAdjustedPaceAvg.type);
454
- if (activityAvgGradeAdjustedPace) {
455
- // The below will fallback for 0
456
- averageGradeAdjustedPace = averageGradeAdjustedPace
457
- ? (averageGradeAdjustedPace + activityAvgGradeAdjustedPace.getValue()) / 2
458
- : activityAvgGradeAdjustedPace.getValue();
459
- }
460
- });
461
- if (averageGradeAdjustedPace) {
462
- stats.push(new DataGradeAdjustedPaceAvg(averageGradeAdjustedPace));
463
- }
464
- // Avg Avg SwimPace
465
- activities.forEach(activity => {
466
- const activityAvgSwimPace = activity.getStat(DataSwimPaceAvg.type);
467
- if (activityAvgSwimPace) {
468
- // The below will fallback for 0
469
- averageSwimPace = averageSwimPace
470
- ? (averageSwimPace + activityAvgSwimPace.getValue()) / 2
471
- : activityAvgSwimPace.getValue();
472
- }
473
- });
474
- if (averageSwimPace) {
475
- stats.push(new DataSwimPaceAvg(averageSwimPace));
476
- }
477
- // Avg Avg Temperature
478
- activities.forEach(activity => {
479
- const activityAvgTemperature = activity.getStat(DataTemperatureAvg.type);
480
- if (activityAvgTemperature) {
481
- // The below will fallback for 0
482
- averageTemperature = averageTemperature
483
- ? (averageTemperature + activityAvgTemperature.getValue()) / 2
484
- : activityAvgTemperature.getValue();
485
- }
486
- });
487
- if (averageTemperature) {
488
- stats.push(new DataTemperatureAvg(averageTemperature));
489
- }
490
- // Avg Feeling
491
- activities.forEach(activity => {
492
- const activityAvgFeeling = activity.getStat(DataFeeling.type);
493
- if (activityAvgFeeling) {
494
- // The below will fallback for 0
495
- averageFeeling = averageFeeling
496
- ? Math.ceil((averageFeeling + activityAvgFeeling.getValue()) / 2)
497
- : activityAvgFeeling.getValue();
498
- }
499
- });
500
- if (averageFeeling) {
501
- stats.push(new DataFeeling(averageFeeling));
502
- }
503
- // Avg RPE
504
- activities.forEach(activity => {
505
- const activityAvgRPE = activity.getStat(DataFeeling.type);
506
- if (activityAvgRPE) {
507
- // The below will fallback for 0
508
- averageRPE = averageRPE
509
- ? Math.ceil((averageRPE + activityAvgRPE.getValue()) / 2)
510
- : activityAvgRPE.getValue();
511
- }
512
- });
513
- if (averageRPE) {
514
- stats.push(new DataRPE(averageRPE));
515
- }
516
- stats.push(...this.getIntensityZonesStatsAggregated(activities));
517
- // Add start and end position
518
- // This expects the to be sorted
519
- const activitiesWithStartPosition = activities.filter(activity => activity.getStat(DataStartPosition.type));
520
- const activitiesWithEndPosition = activities.filter(activity => activity.getStat(DataEndPosition.type));
521
- if (activitiesWithStartPosition && activitiesWithStartPosition.length) {
522
- const startPositionStat = activitiesWithStartPosition[0].getStat(DataStartPosition.type);
523
- stats.push(new DataStartPosition(startPositionStat.getValue()));
524
- }
525
- if (activitiesWithEndPosition && activitiesWithEndPosition.length) {
526
- const endPositionStat = (activitiesWithEndPosition[activitiesWithEndPosition.length - 1].getStat(DataEndPosition.type));
527
- stats.push(new DataEndPosition(endPositionStat.getValue()));
528
- }
529
- // debugger;
530
- return stats;
531
- }
532
- static getIntensityZonesStatsAggregated(statClassInstances) {
533
- return [
534
- DataHeartRateZoneOneDuration.type,
535
- DataHeartRateZoneTwoDuration.type,
536
- DataHeartRateZoneThreeDuration.type,
537
- DataHeartRateZoneFourDuration.type,
538
- DataHeartRateZoneFiveDuration.type,
539
- DataPowerZoneOneDuration.type,
540
- DataPowerZoneTwoDuration.type,
541
- DataPowerZoneThreeDuration.type,
542
- DataPowerZoneFourDuration.type,
543
- DataPowerZoneFiveDuration.type,
544
- DataSpeedZoneOneDuration.type,
545
- DataSpeedZoneTwoDuration.type,
546
- DataSpeedZoneThreeDuration.type,
547
- DataSpeedZoneFourDuration.type,
548
- DataSpeedZoneFiveDuration.type
549
- ].reduce((statsArray, zone) => {
550
- const zoneDuration = statClassInstances.reduce((duration, statClassInstance) => {
551
- const durationStat = statClassInstance.getStat(zone);
552
- if (durationStat) {
553
- duration = duration || 0;
554
- duration += durationStat.getValue();
555
- }
556
- return duration;
557
- }, null);
558
- if (isNumber(zoneDuration)) {
559
- statsArray.push(DynamicDataLoader.getDataInstanceFromDataType(zone, zoneDuration));
560
- }
561
- return statsArray;
562
- }, []);
563
- }
564
- static getActivityDataTypeGain(activity, streamType, starDate, endDate, minDiff) {
565
- return this.getActivityDataTypeGainOrLoss(activity, streamType, true, starDate, endDate, minDiff);
566
- }
567
- static getActivityDataTypeLoss(activity, streamType, starDate, endDate, minDiff) {
568
- return this.getActivityDataTypeGainOrLoss(activity, streamType, false, starDate, endDate, minDiff);
569
- }
570
- static getGainOrLoss(data, gain, minDiff = 2) {
571
- let gainOrLoss = 0;
572
- if (!(data === null || data === void 0 ? void 0 : data.length)) {
573
- return null;
574
- }
575
- data.reduce((previousValue, nextValue) => {
576
- // For gain
577
- if (gain) {
578
- // Increase the gain if eligible first check to be greater plus diff [200, 300, 400, 100, 101, 102]
579
- if (previousValue + minDiff <= nextValue) {
580
- gainOrLoss += nextValue - previousValue;
581
- return nextValue;
582
- }
583
- // if not eligible check if smaller without the diff and if yes do not register it and send it back as the last to check against
584
- if (previousValue < nextValue) {
585
- return previousValue;
586
- }
587
- return nextValue;
588
- }
589
- // For Loss
590
- if (previousValue - minDiff >= nextValue) {
591
- gainOrLoss += previousValue - nextValue;
592
- return nextValue;
593
- }
594
- // if not eligible check if smaller without the diff and if yes do not register it and send it back as the last to check against
595
- if (previousValue > nextValue) {
596
- return previousValue;
597
- }
598
- return nextValue;
599
- }, data[0]);
600
- return gainOrLoss;
601
- }
602
- static getMax(data) {
603
- return data.reduce((previousValue, currentValue) => Math.max(previousValue, currentValue), -Infinity);
604
- }
605
- static getMin(data) {
606
- return data.reduce((previousValue, currentValue) => Math.min(previousValue, currentValue), Infinity);
607
- }
608
- static calculateTotalDistanceForActivity(activity, startDate, endDate) {
609
- return this.geoLibAdapter.getDistance(activity.getPositionData(startDate, endDate).filter(position => position !== null));
610
- }
611
- /**
612
- * Returns streams that derive from speed based on the activity type
613
- * @param speedStream
614
- * @param activityType
615
- */
616
- static createByActivityTypeSpeedBasedStreams(speedStream, activityType) {
617
- return ActivityTypesHelper.speedDerivedDataTypesToUseForActivityType(activityType).reduce((array, dataType) => {
618
- switch (dataType) {
619
- case DataPace.type:
620
- return array.concat([
621
- new Stream(DataPace.type, speedStream.getData().map(dataValue => {
622
- if (!isNumber(dataValue)) {
623
- return null;
624
- }
625
- return convertSpeedToPace(dataValue);
626
- }))
627
- ]);
628
- case DataSwimPace.type:
629
- return array.concat([
630
- new Stream(DataSwimPace.type, speedStream.getData().map(dataValue => {
631
- if (!isNumber(dataValue)) {
632
- return null;
633
- }
634
- return convertSpeedToSwimPace(dataValue);
635
- }))
636
- ]);
637
- case DataSpeed.type:
638
- return array.concat(speedStream);
639
- default:
640
- return array;
641
- }
642
- }, []);
643
- }
644
- /**
645
- * Returns streams that derive from grade adjusted speed based on the activity type
646
- * @param gradeAdjustedSpeedStream
647
- * @param activityType
648
- */
649
- static createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType) {
650
- return ActivityTypesHelper.altiDistanceSpeedDerivedDataTypesToUseForActivityType(activityType).reduce((array, dataType) => {
651
- switch (dataType) {
652
- case DataGradeAdjustedPace.type:
653
- return array.concat([
654
- new Stream(DataGradeAdjustedPace.type, gradeAdjustedSpeedStream.getData().map(dataValue => {
655
- if (!isNumber(dataValue)) {
656
- return null;
657
- }
658
- return convertSpeedToPace(dataValue);
659
- }))
660
- ]);
661
- case DataGradeAdjustedSpeed.type:
662
- return array.concat(gradeAdjustedSpeedStream);
663
- default:
664
- return array;
665
- }
666
- }, []);
667
- }
668
- /**
669
-
670
- * @todo unit test (get the pun?)
671
- * This creates streams that are deriving as unit based streams
672
- * For example it will create pace from speed, swim pace from speed but also speed in km/h as a unitstream
673
- * @param streams
674
- * @param activityType
675
- * @param unitStreamTypes DynamicDataLoader.allUnitDerivedDataTypes this acts like a whitelist for the unit derived units ONLY!
676
- * @param options
677
- */
678
- static createUnitStreamsFromStreams(streams, activityType, unitStreamTypes, options = {
679
- includeDerivedTypes: true,
680
- includeUnitVariants: true
681
- }) {
682
- // @todo perhaps check input to be unitStreamTypesStrictly
683
- const unitStreamTypesToCreate = unitStreamTypes || [
684
- ...DynamicDataLoader.allUnitDerivedDataTypes,
685
- ...DynamicDataLoader.speedDerivedDataTypes
686
- ];
687
- let baseUnitStreams = [];
688
- // Iterate over all possible base types that can have unit variants
689
- // This allows us to dynamically include ALL base streams (like Distance, Power, etc.) that need unit conversion
690
- Object.keys(DynamicDataLoader.dataTypeUnitGroups).forEach(baseDataType => {
691
- const stream = streams.find(s => s.type === baseDataType);
692
- if (!stream) {
693
- return;
694
- }
695
- // Special handling for derived types (Pace from Speed, etc.)
696
- if (baseDataType === DataSpeed.type && options.includeDerivedTypes) {
697
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(stream, activityType));
698
- return;
699
- }
700
- if (baseDataType === DataGradeAdjustedSpeed.type && options.includeDerivedTypes) {
701
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(stream, activityType));
702
- return;
703
- }
704
- if (baseDataType === DataVerticalSpeed.type) {
705
- // Vertical speed handling
706
- if (ActivityTypesHelper.verticalSpeedDerivedDataTypesToUseForActivityType(activityType).length) {
707
- baseUnitStreams.push(stream);
708
- }
709
- return;
710
- }
711
- // For everything else (like Distance), just add the base stream so it can be used for unit generation
712
- baseUnitStreams.push(stream);
713
- });
714
- const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
715
- if (options.includeUnitVariants === false) {
716
- return startWith;
717
- }
718
- return Object.keys(DynamicDataLoader.dataTypeUnitGroups).reduce((array, baseDataType) => {
719
- const baseStream = baseUnitStreams.find(stream => stream.type === baseDataType);
720
- if (!baseStream) {
721
- return array;
722
- }
723
- const unitStreams = Object.keys(DynamicDataLoader.dataTypeUnitGroups[baseDataType])
724
- .filter(unitBasedDataType => unitStreamTypesToCreate.indexOf(unitBasedDataType) !== -1) // @todo perhaps dont filter
725
- .map(unitBasedDataType => {
726
- return new Stream(unitBasedDataType, baseStream.getData().map(dataValue => {
727
- if (!isNumber(dataValue)) {
728
- return null;
729
- }
730
- return DynamicDataLoader.dataTypeUnitGroups[baseDataType][unitBasedDataType](dataValue);
731
- }));
732
- });
733
- return array.concat(unitStreams);
734
- }, startWith);
735
- }
736
- /**
737
- * Generates missing streams for an activity such as distance etc if they are missing
738
- * This will always create a steam even if the distance is 0
739
- * @param activity
740
- */
741
- static generateMissingStreamsForActivity(activity) {
742
- var _a, _b, _c, _d, _e, _f;
743
- // Create derived primitive streams which will be needed for others streams & stats computations
744
- this.createDerivedStreams(activity);
745
- // First add any missing data to the streams via interpolating and extrapolating
746
- this.addMissingDataToStreams(activity);
747
- if (activity.hasStreamData(DataLatitudeDegrees.type) &&
748
- activity.hasStreamData(DataLongitudeDegrees.type) &&
749
- (!activity.hasStreamData(DataDistance.type) || !activity.hasStreamData(DataGNSSDistance.type))) {
750
- const streamData = activity.createStream(DataDistance.type).getData(); // Creating does not add it to activity just presets the resolution to 1s
751
- let distance = 0;
752
- streamData[0] = distance; // Force first distance sample to be equal to 0 instead of null
753
- activity
754
- .getPositionData()
755
- .reduce((prevPosition, position, index) => {
756
- if (!position) {
757
- return prevPosition;
758
- }
759
- if (prevPosition && position) {
760
- distance += this.geoLibAdapter.getDistance([prevPosition, position]);
761
- }
762
- streamData[index] = this.round(distance, 2);
763
- return position;
764
- });
765
- if (!activity.hasStreamData(DataDistance.type)) {
766
- activity.addStream(new Stream(DataDistance.type, streamData));
767
- }
768
- if (!activity.hasStreamData(DataGNSSDistance.type)) {
769
- activity.addStream(new Stream(DataGNSSDistance.type, streamData));
770
- }
771
- if (!activity.hasStreamData(DataSpeed.type)) {
772
- const speedStreamData = activity.createStream(DataSpeed.type).getData();
773
- const distanceStream = activity.getStreamDataByDuration(DataDistance.type);
774
- let previousDistanceItem;
775
- distanceStream.forEach((distanceItem, index) => {
776
- // Use the first distance item value if previous distance is unknown
777
- if (!previousDistanceItem) {
778
- previousDistanceItem = distanceItem;
779
- }
780
- // If know distance then compute speed from last known distance item
781
- if (Number.isFinite(distanceItem.value)) {
782
- const deltaTime = (distanceItem.time - previousDistanceItem.time) / 1000;
783
- const deltaDistance = (distanceItem === null || distanceItem === void 0 ? void 0 : distanceItem.value) ? distanceItem.value - ((previousDistanceItem === null || previousDistanceItem === void 0 ? void 0 : previousDistanceItem.value) || 0) : 0;
784
- speedStreamData[index] = this.round(deltaTime > 0 ? deltaDistance / deltaTime : 0, 3);
785
- // Keep tracking of last know distance item
786
- previousDistanceItem = distanceItem;
787
- }
788
- else {
789
- speedStreamData[index] = null;
790
- }
791
- });
792
- activity.addStream(new Stream(DataSpeed.type, speedStreamData));
793
- }
794
- }
795
- // Check if we can get a grade stream
796
- if (((_c = (_b = (_a = activity.parseOptions) === null || _a === void 0 ? void 0 : _a.streams) === null || _b === void 0 ? void 0 : _b.smooth) === null || _c === void 0 ? void 0 : _c.grade) &&
797
- !activity.hasStreamData(DataGrade.type) &&
798
- activity.hasStreamData(DataDistance.type) &&
799
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
800
- const distanceData = activity.getStreamData(DataDistance.type);
801
- const altitudeData = activity.getStreamData(activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type);
802
- // Create the grade stream from time, distance and altitude non-squashed streams
803
- const timeData = activity.generateTimeStream([DataDistance.type]);
804
- const gradeStreamData = GradeCalculator.computeGradeStream(timeData.getData(), distanceData, altitudeData);
805
- // Append new grade stream to activity
806
- activity.addStream(new Stream(DataGrade.type, gradeStreamData));
807
- if ((_f = (_e = (_d = activity.parseOptions) === null || _d === void 0 ? void 0 : _d.streams) === null || _e === void 0 ? void 0 : _e.smooth) === null || _f === void 0 ? void 0 : _f.gradeSmooth) {
808
- // Duplicate and create an altitude smooth stream (we want to keep original altitude stream available)
809
- // Activity stats and grade adjusted speed will be computed on the smoothed altitude stream
810
- this.cloneStream(activity, DataGrade.type, DataGradeSmooth.type);
811
- // Smooth grade computed stream
812
- this.shapeStream(DataGradeSmooth.type, activity, squashedGradeData => {
813
- // Grade stream
814
- const GRADE_KALMAN_SMOOTHING = {
815
- R: 0.01, // Grade model is stable
816
- Q: 0.5 // Grade measurement error which can be expected
817
- };
818
- // Predict proper grade values
819
- const kf = new KalmanFilter(GRADE_KALMAN_SMOOTHING);
820
- return squashedGradeData.map(v => (v === null ? null : kf.filter(v)));
821
- });
822
- }
823
- }
824
- // Get a grade adjusted speed (the model applies to running only)
825
- if ((ActivityTypesHelper.getActivityGroupForActivityType(activity.type) === ActivityTypeGroups.Running ||
826
- ActivityTypesHelper.getActivityGroupForActivityType(activity.type) === ActivityTypeGroups.TrailRunning) &&
827
- !activity.hasStreamData(DataGradeAdjustedSpeed.type) &&
828
- activity.hasStreamData(DataGradeSmooth.type) &&
829
- activity.hasStreamData(DataSpeed.type)) {
830
- const speedStreamData = activity.getStreamData(DataSpeed.type);
831
- const gradeStreamData = activity.getStreamData(DataGradeSmooth.type);
832
- const gradeAdjustedSpeedData = speedStreamData.map((value, index) => value === null ? null : this.round(GradeCalculator.estimateAdjustedSpeed(value, gradeStreamData[index] || 0), 2));
833
- // Ensure first grade adjusted pace dont start with 0 (it's common) meaning infinity
834
- if (!gradeAdjustedSpeedData[0]) {
835
- const firstKnownValue = gradeAdjustedSpeedData.find(v => v > 0);
836
- gradeAdjustedSpeedData[0] = firstKnownValue ? firstKnownValue : gradeAdjustedSpeedData[0];
837
- }
838
- activity.addStream(new Stream(DataGradeAdjustedSpeed.type, gradeAdjustedSpeedData));
839
- }
840
- if (activity.hasStreamData(DataPower.type) &&
841
- activity.hasStreamData(DataRightBalance.type) &&
842
- !activity.hasStreamData(DataPowerRight.type)) {
843
- const rightPowerStream = activity.createStream(DataPowerRight.type);
844
- const powerStreamData = activity.getStreamData(DataPower.type);
845
- const rightBalanceStreamData = activity.getStreamData(DataRightBalance.type);
846
- rightPowerStream.setData(rightBalanceStreamData.reduce((accu, streamData, index) => {
847
- const powerStreamDataItem = powerStreamData[index];
848
- if (streamData === null || !powerStreamData || powerStreamDataItem === null) {
849
- return accu;
850
- }
851
- accu[index] = (streamData / 100) * powerStreamDataItem;
852
- return accu;
853
- }, []));
854
- activity.addStream(rightPowerStream);
855
- }
856
- if (activity.hasStreamData(DataPower.type) &&
857
- activity.hasStreamData(DataLeftBalance.type) &&
858
- !activity.hasStreamData(DataPowerLeft.type)) {
859
- const leftPowerStream = activity.createStream(DataPowerLeft.type);
860
- const powerStreamData = activity.getStreamData(DataPower.type);
861
- const leftBalanceStreamData = activity.getStreamData(DataLeftBalance.type);
862
- leftPowerStream.setData(leftBalanceStreamData.reduce((accu, streamData, index) => {
863
- const powerStreamDataItem = powerStreamData[index];
864
- if (streamData === null || !powerStreamData || powerStreamDataItem === null) {
865
- return accu;
866
- }
867
- accu[index] = (streamData / 100) * powerStreamDataItem;
868
- return accu;
869
- }, []));
870
- activity.addStream(leftPowerStream);
871
- }
872
- // If left stance time stream available, then add the right balance stream too
873
- if (activity.hasStreamData(DataStanceTimeBalanceLeft.type) &&
874
- !activity.hasStreamData(DataStanceTimeBalanceRight.type)) {
875
- const rightStanceBalanceTimeStream = activity.createStream(DataStanceTimeBalanceRight.type);
876
- const leftStanceBalanceTimeStream = activity.getStreamData(DataStanceTimeBalanceLeft.type);
877
- const rightStanceBalanceTimeData = leftStanceBalanceTimeStream.map(leftBalance => {
878
- return Number.isFinite(leftBalance) ? 100 - leftBalance : null;
879
- });
880
- rightStanceBalanceTimeStream.setData(rightStanceBalanceTimeData);
881
- activity.addStream(rightStanceBalanceTimeStream);
882
- }
883
- return activity;
884
- }
885
- /**
886
- * Provides squashed stream data through callback for data manipulation.
887
- * Then rebuild the stream based on duration including the missing values (null, Infinity, ...) like the source stream
888
- * @param streamType
889
- * @param activity
890
- * @param shapeStreamData
891
- */
892
- static shapeStream(streamType, activity, shapeStreamData) {
893
- let streamDataByDuration = activity.getStreamDataByDuration(streamType, true, true);
894
- // Shape data along function param
895
- const streamData = shapeStreamData(streamDataByDuration.map(item => item.value));
896
- // Update streamDataByDuration with shaped data
897
- streamDataByDuration = streamDataByDuration.map((item, index) => {
898
- item.value = streamData[index];
899
- return item;
900
- });
901
- // Rebuild/replace stream with new shaped value
902
- activity.removeStream(streamType);
903
- activity.addStream(activity.createStream(streamType));
904
- const activityStartTime = activity.startDate.getTime();
905
- streamDataByDuration.forEach(item => {
906
- activity.addDataToStream(streamType, new Date(activityStartTime + item.time), item.value);
907
- });
908
- }
909
- static cloneStream(activity, sourceStreamType, targetStreamType) {
910
- const sourceStream = activity.getStream(sourceStreamType);
911
- const targetStream = activity.createStream(targetStreamType);
912
- targetStream.setData(Array.from(sourceStream.getData())); // Shallow copy data to new stream
913
- activity.addStream(targetStream);
914
- }
915
- /**
916
- * Create derived primitive streams which will be needed for others streams & stats computations
917
- * @param activity
918
- */
919
- static createDerivedStreams(activity) {
920
- var _a, _b, _c;
921
- if (((_c = (_b = (_a = activity.parseOptions) === null || _a === void 0 ? void 0 : _a.streams) === null || _b === void 0 ? void 0 : _b.smooth) === null || _c === void 0 ? void 0 : _c.altitudeSmooth) &&
922
- activity.hasStreamData(DataAltitude.type) &&
923
- !activity.hasStreamData(DataAltitudeSmooth.type)) {
924
- // Duplicate and create an altitude smooth stream (we want to keep original altitude stream available)
925
- // Activity stats will be computed on the smoothed altitude stream
926
- this.cloneStream(activity, DataAltitude.type, DataAltitudeSmooth.type);
927
- // Remove spiky data altitudes
928
- this.shapeStream(DataAltitudeSmooth.type, activity, squashedAltData => {
929
- squashedAltData = medianFilter(squashedAltData, ALTITUDE_SPIKES_FILTER_WIN); // Remove data spikes
930
- squashedAltData = LowPassFilter.smooth(squashedAltData); // Remove too high altitude frequencies
931
- return squashedAltData;
932
- });
933
- }
934
- return activity;
935
- }
936
- /**
937
- * Back and forth fills an activity's stream data so they can be more "tree" like
938
- * It does this for:
939
- *
940
- * [DataAltitude.type,
941
- * DataHeartRate.type,
942
- * DataCadence.type,
943
- * DataDistance.type]
944
- *
945
- * Example
946
- *
947
- * Distance[0, 10, 30, 40, 50,null,60] #null here is legit eg missing record
948
- * Altitude[100, 101, null, 103, null, null, 106]
949
- * Should be
950
- * Altitude[100,101,101,103,103,103,106]
951
- *
952
- * @param activity
953
- */
954
- static addMissingDataToStreams(activity) {
955
- /**
956
- * This tries to align data with Strava.
957
- * Strava fills HR alti cadence with the last value.
958
- * For Power and temperature it doesn't but keeps nulls.
959
- * However, if you keep nulls for paused portions then strava doens't give back null
960
- * that typically indicates a sensor disconnect I suppose.
961
- */
962
- const streamTypesToBackAndForthFill = [
963
- DataAltitude.type,
964
- DataHeartRate.type,
965
- DataCadence.type,
966
- DataDistance.type
967
- // DataSpeed.type, @todo should we be backfilling speed?
968
- ];
969
- // First generate the time stream
970
- const timeStream = activity.generateTimeStream();
971
- /**
972
- * We do a second pass here and we add missing data on crossing time indexes
973
- * for example:
974
- * Time[0,1,2,3,4,5,7]
975
- * Distance[0, 10, 30, 40, 50,null,60] #null here is legit eg missing record
976
- * Altitude[100, 101, null, 103, null, null, 106]
977
- * Should be
978
- * Altitude[100,101,101,103,103,103,106]
979
- */
980
- activity
981
- .getAllStreams()
982
- .filter(stream => streamTypesToBackAndForthFill.indexOf(stream.type) !== -1)
983
- .forEach(stream => {
984
- // Find the first sample value
985
- let currentValue = stream.getData(true, true)[0];
986
- // The time stream will always have more length than each stream when not back/forthfilled
987
- const timeStreamData = timeStream.getData();
988
- stream.setData(timeStreamData.reduce((data, time, timeIndex) => {
989
- // If there is no timeslot put whatever was
990
- if (!isNumber(time)) {
991
- data.push(stream.getData()[timeIndex]);
992
- return data;
993
- }
994
- // We have a time slot here on ... (for the first run, old is the very first next)
995
- // If it's a number set the current , else leave it to old to forth fill
996
- if (isNumber(stream.getData()[time])) {
997
- currentValue = stream.getData()[time];
998
- }
999
- // Fill the current or old...
1000
- data.push(currentValue);
1001
- return data;
1002
- }, []));
1003
- });
1004
- /**
1005
- * @todo
1006
- * Linear fill distance where:
1007
- * a) There is not distance but it's not paused
1008
- * b) There is no corespoding lat/long but there is distace (aka distance = not trusted)
1009
- * About B I am not sure. That is because if there is for example an internal accelerometer
1010
- * that reports better this can help with pace and other things. Even for GAP
1011
- */
1012
- // Fix activity having broken start lat/lng
1013
- // Case: "fixtures/others/broken-start-latlng.fit"
1014
- if (activity.hasStreamData(DataLongitudeDegrees.type)) {
1015
- this.shapeStream(DataLongitudeDegrees.type, activity, (squashedData) => {
1016
- const firstKnownCoord = squashedData.find(l => l != 0);
1017
- if (firstKnownCoord != null) {
1018
- let index = 0;
1019
- while (squashedData[index] === 0) {
1020
- squashedData[index] = firstKnownCoord;
1021
- index++;
1022
- }
1023
- }
1024
- return squashedData;
1025
- });
1026
- }
1027
- if (activity.hasStreamData(DataLatitudeDegrees.type)) {
1028
- this.shapeStream(DataLatitudeDegrees.type, activity, (squashedData) => {
1029
- const firstKnownCoord = squashedData.find(l => l != 0);
1030
- if (firstKnownCoord != null) {
1031
- let index = 0;
1032
- while (squashedData[index] === 0) {
1033
- squashedData[index] = firstKnownCoord;
1034
- index++;
1035
- }
1036
- }
1037
- return squashedData;
1038
- });
1039
- }
1040
- }
1041
- /**
1042
- *
1043
- * @param secondsPer100m
1044
- * @param avgStrokesPerMin
1045
- * @param poolLength
1046
- */
1047
- static computeSwimSwolf(secondsPer100m, avgStrokesPerMin, poolLength) {
1048
- const minutesPer100m = secondsPer100m / 60;
1049
- const avgStrokePer100m = avgStrokesPerMin * minutesPer100m;
1050
- const strokesPerMeter = avgStrokePer100m / 100;
1051
- const secondsPerMeter = secondsPer100m / 100;
1052
- return this.round((secondsPerMeter + strokesPerMeter) * poolLength, 1);
1053
- }
1054
- /**
1055
- * Andrew Coggan weighted power compute method
1056
- * 1) starting at the 30s mark, calculate a rolling 30 s average (of the preceding time points, obviously).
1057
- * 2) raise all the values obtained in step #1 to the 4th power.
1058
- * 3) take the average of all of the values obtained in step #2.
1059
- * 4) take the 4th root of the value obtained in step #3.
1060
- * (And when you get tired of exporting every file to, e.g., Excel to perform such calculations, help develop a program
1061
- * like WKO+ to do the work for you <g>.)
1062
- */
1063
- static computeNormalizedPower(powerArray, timeArray) {
1064
- const WEIGHTED_WATTS_TIME_BUFFER = 30; // Seconds
1065
- const poweredWeightedWatts = [];
1066
- let accumulatedTimeInBuffer = 0; // seconds
1067
- let wattsInBuffer = [];
1068
- for (const [index, current] of timeArray.entries()) {
1069
- if (index === 0) {
1070
- continue;
1071
- }
1072
- wattsInBuffer.push(powerArray[index]);
1073
- if (accumulatedTimeInBuffer >= WEIGHTED_WATTS_TIME_BUFFER) {
1074
- const meanWatts = this.getAverage(wattsInBuffer);
1075
- if (Number.isFinite(meanWatts)) {
1076
- poweredWeightedWatts.push(Math.pow(meanWatts, 4));
1077
- }
1078
- // Reset
1079
- accumulatedTimeInBuffer = 0;
1080
- wattsInBuffer = [];
1081
- }
1082
- accumulatedTimeInBuffer += current - timeArray[index - 1];
1083
- }
1084
- return Math.sqrt(Math.sqrt(this.getAverage(poweredWeightedWatts)));
1085
- }
1086
- static getActivityDataTypeGainOrLoss(activity, streamType, gain, startDate, endDate, minDiff) {
1087
- return this.getGainOrLoss(activity.getSquashedStreamData(streamType, startDate, endDate), gain, minDiff);
1088
- }
1089
- static getActivityDataTypeMinOrMax(activity, streamType, max, startDate, endDate, filterOver) {
1090
- const data = activity
1091
- .getSquashedStreamData(streamType, startDate, endDate)
1092
- .filter(streamData => streamData !== Infinity &&
1093
- streamData !== -Infinity &&
1094
- (Number.isFinite(filterOver) ? streamData > filterOver : true));
1095
- if (max) {
1096
- return this.getMax(data);
1097
- }
1098
- return this.getMin(data);
1099
- }
1100
- /**
1101
- * Generates the stats for an activity
1102
- * @todo move to factory with next version
1103
- * @param activity
1104
- */
1105
- static generateMissingStatsForActivity(activity) {
1106
- // If there is no distance or distance for some reason is 0
1107
- const activityDistanceStat = activity.getStat(DataDistance.type);
1108
- if (!activityDistanceStat || activityDistanceStat.getValue() === 0) {
1109
- let distance = 0;
1110
- if (activity.hasStreamData(DataDistance.type)) {
1111
- const distanceData = activity.getSquashedStreamData(DataDistance.type);
1112
- distance = distanceData[distanceData.length - 1] - distanceData[0] || 0;
1113
- }
1114
- else if (activity.hasStreamData(DataLongitudeDegrees.type) &&
1115
- activity.hasStreamData(DataLatitudeDegrees.type)) {
1116
- distance = this.calculateTotalDistanceForActivity(activity, activity.startDate, activity.endDate);
1117
- }
1118
- activity.addStat(new DataDistance(distance));
1119
- }
1120
- if (!activity.getStat(DataGNSSDistance.type) && activity.hasStreamData(DataGNSSDistance.type)) {
1121
- activity.addStat(new DataGNSSDistance(activity.getSquashedStreamData(DataGNSSDistance.type)[activity.getSquashedStreamData(DataGNSSDistance.type).length - 1]));
1122
- }
1123
- // Ascent (altitude gain)
1124
- if (!activity.getStat(DataAscent.type) &&
1125
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
1126
- const gain = this.getActivityDataTypeGain(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type);
1127
- if (gain !== null) {
1128
- activity.addStat(new DataAscent(gain));
1129
- }
1130
- }
1131
- // Descent (altitude loss)
1132
- if (!activity.getStat(DataDescent.type) &&
1133
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
1134
- const loss = this.getActivityDataTypeLoss(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type);
1135
- if (loss !== null) {
1136
- activity.addStat(new DataDescent(loss));
1137
- }
1138
- }
1139
- // Altitude Max
1140
- if (!activity.getStat(DataAltitudeMax.type) &&
1141
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
1142
- activity.addStat(new DataAltitudeMax(this.getDataTypeMax(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)));
1143
- }
1144
- // Altitude Min
1145
- if (!activity.getStat(DataAltitudeMin.type) &&
1146
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
1147
- activity.addStat(new DataAltitudeMin(this.getDataTypeMin(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)));
1148
- }
1149
- // Altitude Avg
1150
- if (!activity.getStat(DataAltitudeAvg.type) &&
1151
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type))) {
1152
- activity.addStat(new DataAltitudeAvg(this.getDataTypeAvg(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)));
1153
- }
1154
- // Altitude start
1155
- if (!activity.getStat(DataStartAltitude.type) &&
1156
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type)) &&
1157
- this.getDataTypeFirst(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)) {
1158
- activity.addStat(new DataStartAltitude(this.getDataTypeFirst(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)));
1159
- }
1160
- // Altitude end
1161
- if (!activity.getStat(DataEndAltitude.type) &&
1162
- (activity.hasStreamData(DataAltitudeSmooth.type) || activity.hasStreamData(DataAltitude.type)) &&
1163
- this.getDataTypeLast(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)) {
1164
- activity.addStat(new DataEndAltitude(this.getDataTypeLast(activity, activity.hasStreamData(DataAltitudeSmooth.type) ? DataAltitudeSmooth.type : DataAltitude.type)));
1165
- }
1166
- // Heart Rate Max
1167
- if (!activity.getStat(DataHeartRateMax.type) && activity.hasStreamData(DataHeartRate.type)) {
1168
- activity.addStat(new DataHeartRateMax(this.getDataTypeMax(activity, DataHeartRate.type)));
1169
- }
1170
- // Heart Rate Min
1171
- if (!activity.getStat(DataHeartRateMin.type) && activity.hasStreamData(DataHeartRate.type)) {
1172
- activity.addStat(new DataHeartRateMin(this.getDataTypeMin(activity, DataHeartRate.type)));
1173
- }
1174
- // Heart Rate Avg
1175
- if (!activity.getStat(DataHeartRateAvg.type) && activity.hasStreamData(DataHeartRate.type)) {
1176
- activity.addStat(new DataHeartRateAvg(this.round(this.getDataTypeAvg(activity, DataHeartRate.type))));
1177
- }
1178
- // Cadence Max
1179
- if (!activity.getStat(DataCadenceMax.type) && activity.hasStreamData(DataCadence.type)) {
1180
- activity.addStat(new DataCadenceMax(this.getDataTypeMax(activity, DataCadence.type)));
1181
- }
1182
- // Cadence Min
1183
- if (!activity.getStat(DataCadenceMin.type) && activity.hasStreamData(DataCadence.type)) {
1184
- // Get min cadence except 0. A 0 cadence is not meaningful.
1185
- const minCadenceOver = 0;
1186
- activity.addStat(new DataCadenceMin(this.getDataTypeMin(activity, DataCadence.type, undefined, undefined, minCadenceOver)));
1187
- }
1188
- // Cadence Avg
1189
- if (!activity.getStat(DataCadenceAvg.type) && activity.hasStreamData(DataCadence.type)) {
1190
- // Get avg cadence except 0 values. Platforms like garmin/strava don't include 0 cadences in their averages.
1191
- const avgCadenceOver = 0;
1192
- const avgCadence = this.getDataTypeAvg(activity, DataCadence.type, undefined, undefined, avgCadenceOver);
1193
- activity.addStat(new DataCadenceAvg(this.round(avgCadence)));
1194
- }
1195
- // Speed Max
1196
- if (!activity.getStat(DataSpeedMax.type) && activity.hasStreamData(DataSpeed.type)) {
1197
- activity.addStat(new DataSpeedMax(this.getDataTypeMax(activity, DataSpeed.type)));
1198
- }
1199
- // Speed Min
1200
- if (!activity.getStat(DataSpeedMin.type) && activity.hasStreamData(DataSpeed.type)) {
1201
- activity.addStat(new DataSpeedMin(this.getDataTypeMin(activity, DataSpeed.type)));
1202
- }
1203
- // Speed Avg
1204
- if (!activity.getStat(DataSpeedAvg.type) && activity.hasStreamData(DataSpeed.type)) {
1205
- activity.addStat(new DataSpeedAvg(this.getDataTypeAvg(activity, DataSpeed.type)));
1206
- }
1207
- // Grade Adjusted Speed Max
1208
- if (!activity.getStat(DataGradeAdjustedSpeedMax.type) && activity.hasStreamData(DataGradeAdjustedSpeed.type)) {
1209
- activity.addStat(new DataGradeAdjustedSpeedMax(this.getDataTypeMax(activity, DataGradeAdjustedSpeed.type)));
1210
- }
1211
- // Grade Adjusted Speed Min
1212
- if (!activity.getStat(DataGradeAdjustedSpeedMin.type) && activity.hasStreamData(DataGradeAdjustedSpeed.type)) {
1213
- activity.addStat(new DataGradeAdjustedSpeedMin(this.getDataTypeMin(activity, DataGradeAdjustedSpeed.type)));
1214
- }
1215
- // Grade Adjusted Speed Avg
1216
- if (!activity.getStat(DataGradeAdjustedSpeedAvg.type) && activity.hasStreamData(DataGradeAdjustedSpeed.type)) {
1217
- activity.addStat(new DataGradeAdjustedSpeedAvg(this.getDataTypeAvg(activity, DataGradeAdjustedSpeed.type)));
1218
- }
1219
- // Vertical Speed Max
1220
- if (!activity.getStat(DataVerticalSpeedMax.type) && activity.hasStreamData(DataVerticalSpeed.type)) {
1221
- activity.addStat(new DataVerticalSpeedMax(this.getDataTypeMax(activity, DataVerticalSpeed.type)));
1222
- }
1223
- // Vertical Speed Min
1224
- if (!activity.getStat(DataVerticalSpeedMin.type) && activity.hasStreamData(DataVerticalSpeed.type)) {
1225
- activity.addStat(new DataVerticalSpeedMin(this.getDataTypeMin(activity, DataVerticalSpeed.type)));
1226
- }
1227
- // Vertical Speed Avg
1228
- if (!activity.getStat(DataVerticalSpeedAvg.type) && activity.hasStreamData(DataVerticalSpeed.type)) {
1229
- activity.addStat(new DataVerticalSpeedAvg(this.getDataTypeAvg(activity, DataVerticalSpeed.type)));
1230
- }
1231
- // Power Max
1232
- if (!activity.getStat(DataPowerMax.type) && activity.hasStreamData(DataPower.type)) {
1233
- activity.addStat(new DataPowerMax(this.getDataTypeMax(activity, DataPower.type)));
1234
- }
1235
- // Power Min
1236
- if (!activity.getStat(DataPowerMin.type) && activity.hasStreamData(DataPower.type)) {
1237
- activity.addStat(new DataPowerMin(this.getDataTypeMin(activity, DataPower.type)));
1238
- }
1239
- // Power AVG
1240
- if (!activity.getStat(DataPowerAvg.type) && activity.hasStreamData(DataPower.type)) {
1241
- activity.addStat(new DataPowerAvg(this.getDataTypeAvg(activity, DataPower.type)));
1242
- }
1243
- // Power Normalized
1244
- if (!activity.getStat(DataPowerNormalized.type) && activity.hasStreamData(DataPower.type)) {
1245
- const powerDurationStream = activity.getStreamDataByDuration(DataPower.type, true, true);
1246
- const timeStream = powerDurationStream.map(item => item.time / 1000);
1247
- const powerStream = powerDurationStream.map(item => item.value);
1248
- const normalizedPower = this.computeNormalizedPower(powerStream, timeStream);
1249
- activity.addStat(new DataPowerNormalized(normalizedPower));
1250
- }
1251
- // Air AirPower Max
1252
- if (!activity.getStat(DataAirPowerMax.type) && activity.hasStreamData(DataAirPower.type)) {
1253
- activity.addStat(new DataAirPowerMax(this.getDataTypeMax(activity, DataAirPower.type)));
1254
- }
1255
- // Air AirPower Min
1256
- if (!activity.getStat(DataAirPowerMin.type) && activity.hasStreamData(DataAirPower.type)) {
1257
- activity.addStat(new DataAirPowerMin(this.getDataTypeMin(activity, DataAirPower.type)));
1258
- }
1259
- // Air AirPower AVG
1260
- if (!activity.getStat(DataAirPowerAvg.type) && activity.hasStreamData(DataAirPower.type)) {
1261
- activity.addStat(new DataAirPowerAvg(this.getDataTypeAvg(activity, DataAirPower.type)));
1262
- }
1263
- // Temperature Max
1264
- if (!activity.getStat(DataTemperatureMax.type) && activity.hasStreamData(DataTemperature.type)) {
1265
- activity.addStat(new DataTemperatureMax(this.getDataTypeMax(activity, DataTemperature.type)));
1266
- }
1267
- // Temperature Min
1268
- if (!activity.getStat(DataTemperatureMin.type) && activity.hasStreamData(DataTemperature.type)) {
1269
- activity.addStat(new DataTemperatureMin(this.getDataTypeMin(activity, DataTemperature.type)));
1270
- }
1271
- // Temperature Avg
1272
- if (!activity.getStat(DataTemperatureAvg.type) && activity.hasStreamData(DataTemperature.type)) {
1273
- activity.addStat(new DataTemperatureAvg(this.getDataTypeAvg(activity, DataTemperature.type)));
1274
- }
1275
- // Battery Consumption Avg
1276
- if (!activity.getStat(DataBatteryConsumption.type) && activity.hasStreamData(DataBatteryCharge.type)) {
1277
- activity.addStat(new DataBatteryConsumption(this.getDataTypeMinToMaxDifference(activity, DataBatteryCharge.type)));
1278
- }
1279
- // Battery Life Estimation based on Consumption
1280
- if (!activity.getStat(DataBatteryLifeEstimation.type)) {
1281
- const consumption = activity.getStat(DataBatteryConsumption.type);
1282
- if (consumption && consumption.getValue()) {
1283
- activity.addStat(new DataBatteryLifeEstimation(Number(((+activity.endDate - +activity.startDate) / 1000) * 100) / Number(consumption.getValue())));
1284
- }
1285
- }
1286
- // Start and end position
1287
- if ((!activity.getStat(DataStartPosition.type) || !activity.getStat(DataEndPosition.type)) &&
1288
- activity.hasPositionData()) {
1289
- const activityPositionData = activity.getPositionData().filter(data => data !== null);
1290
- const startPosition = activityPositionData[0];
1291
- const endPosition = activityPositionData[activityPositionData.length - 1];
1292
- if (startPosition && !activity.getStat(DataStartPosition.type)) {
1293
- activity.addStat(new DataStartPosition(startPosition));
1294
- }
1295
- if (endPosition && !activity.getStat(DataEndPosition.type)) {
1296
- activity.addStat(new DataEndPosition(endPosition));
1297
- }
1298
- }
1299
- // Assign L/R balance from streams if exists
1300
- if (!activity.getStat(DataRightBalance.type) && activity.hasStreamData(DataRightBalance.type)) {
1301
- const avgRightBalance = this.round(this.getDataTypeAvg(activity, DataRightBalance.type), 2);
1302
- activity.addStat(new DataRightBalance(avgRightBalance));
1303
- activity.addStat(new DataLeftBalance(100 - avgRightBalance));
1304
- }
1305
- // Assign L/R balance stance time from streams if exists
1306
- if (!activity.getStat(DataStanceTimeBalanceLeft.type) && activity.hasStreamData(DataStanceTimeBalanceLeft.type)) {
1307
- const avgStanceTimeLeftBalance = this.round(this.getDataTypeAvg(activity, DataStanceTimeBalanceLeft.type), 2);
1308
- activity.addStat(new DataStanceTimeBalanceLeft(avgStanceTimeLeftBalance));
1309
- activity.addStat(new DataStanceTimeBalanceRight(100 - avgStanceTimeLeftBalance));
1310
- }
1311
- }
1312
- static generateMissingSpeedDerivedStatsForActivity(activity) {
1313
- // Pace
1314
- const speedMax = activity.getStat(DataSpeedMax.type);
1315
- if (speedMax && !activity.getStat(DataPaceMax.type)) {
1316
- activity.addStat(new DataPaceMax(convertSpeedToPace(speedMax.getValue())));
1317
- }
1318
- const speedMin = activity.getStat(DataSpeedMin.type);
1319
- if (speedMin && !activity.getStat(DataPaceMin.type)) {
1320
- activity.addStat(new DataPaceMin(convertSpeedToPace(speedMin.getValue())));
1321
- }
1322
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1323
- if (speedAvg && !activity.getStat(DataPaceAvg.type)) {
1324
- activity.addStat(new DataPaceAvg(convertSpeedToPace(speedAvg.getValue())));
1325
- }
1326
- // GAP
1327
- const gradeAdjustedSpeedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1328
- if (gradeAdjustedSpeedMax && !activity.getStat(DataGradeAdjustedPaceMax.type)) {
1329
- const targetAdjustedSpeed = gradeAdjustedSpeedMax.getValue() < speedMax.getValue()
1330
- ? speedMax.getValue()
1331
- : gradeAdjustedSpeedMax.getValue();
1332
- activity.addStat(new DataGradeAdjustedPaceMax(convertSpeedToPace(targetAdjustedSpeed)));
1333
- }
1334
- const gradeAdjustedSpeedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1335
- if (gradeAdjustedSpeedMin && !activity.getStat(DataGradeAdjustedPaceMin.type)) {
1336
- const targetAdjustedSpeed = gradeAdjustedSpeedMin.getValue() < speedMin.getValue()
1337
- ? speedMin.getValue()
1338
- : gradeAdjustedSpeedMin.getValue();
1339
- activity.addStat(new DataGradeAdjustedPaceMin(convertSpeedToPace(targetAdjustedSpeed)));
1340
- }
1341
- const gradeAdjustedSpeedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1342
- if (gradeAdjustedSpeedAvg && !activity.getStat(DataGradeAdjustedPaceAvg.type)) {
1343
- const targetAdjustedSpeed = gradeAdjustedSpeedAvg.getValue() < speedAvg.getValue()
1344
- ? speedAvg.getValue()
1345
- : gradeAdjustedSpeedAvg.getValue();
1346
- activity.addStat(new DataGradeAdjustedPaceAvg(convertSpeedToPace(targetAdjustedSpeed)));
1347
- }
1348
- // Swim Pace
1349
- if (speedMax && !activity.getStat(DataSwimPaceMax.type)) {
1350
- activity.addStat(new DataSwimPaceMax(convertSpeedToSwimPace(speedMax.getValue())));
1351
- }
1352
- if (speedMin && !activity.getStat(DataSwimPaceMin.type)) {
1353
- activity.addStat(new DataSwimPaceMin(convertSpeedToSwimPace(speedMin.getValue())));
1354
- }
1355
- if (speedAvg && !activity.getStat(DataSwimPaceAvg.type)) {
1356
- activity.addStat(new DataSwimPaceAvg(convertSpeedToSwimPace(speedAvg.getValue())));
1357
- }
1358
- }
1359
- // @todo move to factory
1360
- static generateMissingUnitStatsForActivity(activity) {
1361
- var _a, _b, _c;
1362
- // Pace
1363
- if (!activity.getStat(DataPaceMaxMinutesPerMile.type)) {
1364
- const paceMax = activity.getStat(DataPaceMax.type);
1365
- if (paceMax) {
1366
- activity.addStat(new DataPaceMaxMinutesPerMile(convertPaceToPaceInMinutesPerMile(paceMax.getValue())));
1367
- }
1368
- }
1369
- if (!activity.getStat(DataPaceMinMinutesPerMile.type)) {
1370
- const paceMin = activity.getStat(DataPaceMin.type);
1371
- if (paceMin) {
1372
- activity.addStat(new DataPaceMinMinutesPerMile(convertPaceToPaceInMinutesPerMile(paceMin.getValue())));
1373
- }
1374
- }
1375
- if (!activity.getStat(DataPaceAvgMinutesPerMile.type)) {
1376
- const paceAvg = activity.getStat(DataPaceAvg.type);
1377
- if (paceAvg) {
1378
- activity.addStat(new DataPaceAvgMinutesPerMile(convertPaceToPaceInMinutesPerMile(paceAvg.getValue())));
1379
- }
1380
- }
1381
- // Grade Adjusted Pace
1382
- if (!activity.getStat(DataGradeAdjustedPaceMaxMinutesPerMile.type)) {
1383
- const gradeAdjustedPaceMax = activity.getStat(DataGradeAdjustedPaceMax.type);
1384
- if (gradeAdjustedPaceMax) {
1385
- activity.addStat(new DataGradeAdjustedPaceMaxMinutesPerMile(convertPaceToPaceInMinutesPerMile(gradeAdjustedPaceMax.getValue())));
1386
- }
1387
- }
1388
- if (!activity.getStat(DataGradeAdjustedPaceMinMinutesPerMile.type)) {
1389
- const gradeAdjustedPaceMin = activity.getStat(DataGradeAdjustedPaceMin.type);
1390
- if (gradeAdjustedPaceMin) {
1391
- activity.addStat(new DataGradeAdjustedPaceMinMinutesPerMile(convertPaceToPaceInMinutesPerMile(gradeAdjustedPaceMin.getValue())));
1392
- }
1393
- }
1394
- if (!activity.getStat(DataGradeAdjustedPaceAvgMinutesPerMile.type)) {
1395
- const gradeAdjustedPaceAvg = activity.getStat(DataGradeAdjustedPaceAvg.type);
1396
- if (gradeAdjustedPaceAvg) {
1397
- activity.addStat(new DataGradeAdjustedPaceAvgMinutesPerMile(convertPaceToPaceInMinutesPerMile(gradeAdjustedPaceAvg.getValue())));
1398
- }
1399
- }
1400
- // Swim Pace
1401
- if (!activity.getStat(DataSwimPaceMaxMinutesPer100Yard.type)) {
1402
- const swimPaceMax = activity.getStat(DataSwimPaceMax.type);
1403
- if (swimPaceMax) {
1404
- activity.addStat(new DataSwimPaceMaxMinutesPer100Yard(convertSwimPaceToSwimPacePer100Yard(swimPaceMax.getValue())));
1405
- }
1406
- }
1407
- if (!activity.getStat(DataSwimPaceMinMinutesPer100Yard.type)) {
1408
- const swimPaceMin = activity.getStat(DataSwimPaceMin.type);
1409
- if (swimPaceMin) {
1410
- activity.addStat(new DataSwimPaceMinMinutesPer100Yard(convertSwimPaceToSwimPacePer100Yard(swimPaceMin.getValue())));
1411
- }
1412
- }
1413
- if (!activity.getStat(DataSwimPaceAvgMinutesPer100Yard.type)) {
1414
- const swimPaceAvg = activity.getStat(DataPaceAvg.type);
1415
- if (swimPaceAvg) {
1416
- activity.addStat(new DataSwimPaceAvgMinutesPer100Yard(convertSwimPaceToSwimPacePer100Yard(swimPaceAvg.getValue())));
1417
- }
1418
- }
1419
- // Speed
1420
- if (!activity.getStat(DataSpeedMaxKilometersPerHour.type)) {
1421
- const speedMax = activity.getStat(DataSpeedMax.type);
1422
- if (speedMax) {
1423
- activity.addStat(new DataSpeedMaxKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedMax.getValue())));
1424
- }
1425
- }
1426
- if (!activity.getStat(DataSpeedMaxMilesPerHour.type)) {
1427
- const speedMax = activity.getStat(DataSpeedMax.type);
1428
- if (speedMax) {
1429
- activity.addStat(new DataSpeedMaxMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedMax.getValue())));
1430
- }
1431
- }
1432
- if (!activity.getStat(DataSpeedMaxFeetPerSecond.type)) {
1433
- const speedMax = activity.getStat(DataSpeedMax.type);
1434
- if (speedMax) {
1435
- activity.addStat(new DataSpeedMaxFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedMax.getValue())));
1436
- }
1437
- }
1438
- if (!activity.getStat(DataSpeedMaxFeetPerMinute.type)) {
1439
- const speedMax = activity.getStat(DataSpeedMax.type);
1440
- if (speedMax) {
1441
- activity.addStat(new DataSpeedMaxFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedMax.getValue())));
1442
- }
1443
- }
1444
- if (!activity.getStat(DataSpeedMaxMetersPerMinute.type)) {
1445
- const speedMax = activity.getStat(DataSpeedMax.type);
1446
- if (speedMax) {
1447
- activity.addStat(new DataSpeedMaxMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedMax.getValue())));
1448
- }
1449
- }
1450
- if (!activity.getStat(DataSpeedMaxKnots.type)) {
1451
- const speedMax = activity.getStat(DataSpeedMax.type);
1452
- if (speedMax) {
1453
- activity.addStat(new DataSpeedMaxKnots(convertSpeedToSpeedInKnots(speedMax.getValue())));
1454
- }
1455
- }
1456
- if (!activity.getStat(DataSpeedMinKilometersPerHour.type)) {
1457
- const speedMin = activity.getStat(DataSpeedMin.type);
1458
- if (speedMin) {
1459
- activity.addStat(new DataSpeedMinKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedMin.getValue())));
1460
- }
1461
- }
1462
- if (!activity.getStat(DataSpeedMinMilesPerHour.type)) {
1463
- const speedMin = activity.getStat(DataSpeedMin.type);
1464
- if (speedMin) {
1465
- activity.addStat(new DataSpeedMinMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedMin.getValue())));
1466
- }
1467
- }
1468
- if (!activity.getStat(DataSpeedMinFeetPerSecond.type)) {
1469
- const speedMin = activity.getStat(DataSpeedMin.type);
1470
- if (speedMin) {
1471
- activity.addStat(new DataSpeedMinFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedMin.getValue())));
1472
- }
1473
- }
1474
- if (!activity.getStat(DataSpeedMinFeetPerMinute.type)) {
1475
- const speedMin = activity.getStat(DataSpeedMin.type);
1476
- if (speedMin) {
1477
- activity.addStat(new DataSpeedMinFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedMin.getValue())));
1478
- }
1479
- }
1480
- if (!activity.getStat(DataSpeedMinMetersPerMinute.type)) {
1481
- const speedMin = activity.getStat(DataSpeedMin.type);
1482
- if (speedMin) {
1483
- activity.addStat(new DataSpeedMinMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedMin.getValue())));
1484
- }
1485
- }
1486
- if (!activity.getStat(DataSpeedMinKnots.type)) {
1487
- const speedMin = activity.getStat(DataSpeedMin.type);
1488
- if (speedMin) {
1489
- activity.addStat(new DataSpeedMinKnots(convertSpeedToSpeedInKnots(speedMin.getValue())));
1490
- }
1491
- }
1492
- if (!activity.getStat(DataSpeedAvgKilometersPerHour.type)) {
1493
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1494
- if (speedAvg) {
1495
- activity.addStat(new DataSpeedAvgKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedAvg.getValue())));
1496
- }
1497
- }
1498
- if (!activity.getStat(DataSpeedAvgMilesPerHour.type)) {
1499
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1500
- if (speedAvg) {
1501
- activity.addStat(new DataSpeedAvgMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedAvg.getValue())));
1502
- }
1503
- }
1504
- if (!activity.getStat(DataSpeedAvgFeetPerSecond.type)) {
1505
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1506
- if (speedAvg) {
1507
- activity.addStat(new DataSpeedAvgFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedAvg.getValue())));
1508
- }
1509
- }
1510
- if (!activity.getStat(DataSpeedAvgFeetPerMinute.type)) {
1511
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1512
- if (speedAvg) {
1513
- activity.addStat(new DataSpeedAvgFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedAvg.getValue())));
1514
- }
1515
- }
1516
- if (!activity.getStat(DataSpeedAvgMetersPerMinute.type)) {
1517
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1518
- if (speedAvg) {
1519
- activity.addStat(new DataSpeedAvgMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedAvg.getValue())));
1520
- }
1521
- }
1522
- if (!activity.getStat(DataSpeedAvgKnots.type)) {
1523
- const speedAvg = activity.getStat(DataSpeedAvg.type);
1524
- if (speedAvg) {
1525
- activity.addStat(new DataSpeedAvgKnots(convertSpeedToSpeedInKnots(speedAvg.getValue())));
1526
- }
1527
- }
1528
- // Grade Adjusted Speed
1529
- if (!activity.getStat(DataGradeAdjustedSpeedMaxKilometersPerHour.type)) {
1530
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1531
- if (speedMax) {
1532
- activity.addStat(new DataGradeAdjustedSpeedMaxKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedMax.getValue())));
1533
- }
1534
- }
1535
- if (!activity.getStat(DataGradeAdjustedSpeedMaxMilesPerHour.type)) {
1536
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1537
- if (speedMax) {
1538
- activity.addStat(new DataGradeAdjustedSpeedMaxMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedMax.getValue())));
1539
- }
1540
- }
1541
- if (!activity.getStat(DataGradeAdjustedSpeedMaxFeetPerSecond.type)) {
1542
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1543
- if (speedMax) {
1544
- activity.addStat(new DataGradeAdjustedSpeedMaxFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedMax.getValue())));
1545
- }
1546
- }
1547
- if (!activity.getStat(DataGradeAdjustedSpeedMaxFeetPerMinute.type)) {
1548
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1549
- if (speedMax) {
1550
- activity.addStat(new DataGradeAdjustedSpeedMaxFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedMax.getValue())));
1551
- }
1552
- }
1553
- if (!activity.getStat(DataGradeAdjustedSpeedMaxMetersPerMinute.type)) {
1554
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1555
- if (speedMax) {
1556
- activity.addStat(new DataGradeAdjustedSpeedMaxMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedMax.getValue())));
1557
- }
1558
- }
1559
- if (!activity.getStat(DataGradeAdjustedSpeedMaxKnots.type)) {
1560
- const speedMax = activity.getStat(DataGradeAdjustedSpeedMax.type);
1561
- if (speedMax) {
1562
- activity.addStat(new DataGradeAdjustedSpeedMaxKnots(convertSpeedToSpeedInKnots(speedMax.getValue())));
1563
- }
1564
- }
1565
- if (!activity.getStat(DataGradeAdjustedSpeedMinKilometersPerHour.type)) {
1566
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1567
- if (speedMin) {
1568
- activity.addStat(new DataGradeAdjustedSpeedMinKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedMin.getValue())));
1569
- }
1570
- }
1571
- if (!activity.getStat(DataGradeAdjustedSpeedMinMilesPerHour.type)) {
1572
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1573
- if (speedMin) {
1574
- activity.addStat(new DataGradeAdjustedSpeedMinMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedMin.getValue())));
1575
- }
1576
- }
1577
- if (!activity.getStat(DataGradeAdjustedSpeedMinFeetPerSecond.type)) {
1578
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1579
- if (speedMin) {
1580
- activity.addStat(new DataGradeAdjustedSpeedMinFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedMin.getValue())));
1581
- }
1582
- }
1583
- if (!activity.getStat(DataGradeAdjustedSpeedMinFeetPerMinute.type)) {
1584
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1585
- if (speedMin) {
1586
- activity.addStat(new DataGradeAdjustedSpeedMinFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedMin.getValue())));
1587
- }
1588
- }
1589
- if (!activity.getStat(DataGradeAdjustedSpeedMinMetersPerMinute.type)) {
1590
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1591
- if (speedMin) {
1592
- activity.addStat(new DataGradeAdjustedSpeedMinMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedMin.getValue())));
1593
- }
1594
- }
1595
- if (!activity.getStat(DataGradeAdjustedSpeedMinKnots.type)) {
1596
- const speedMin = activity.getStat(DataGradeAdjustedSpeedMin.type);
1597
- if (speedMin) {
1598
- activity.addStat(new DataGradeAdjustedSpeedMinKnots(convertSpeedToSpeedInKnots(speedMin.getValue())));
1599
- }
1600
- }
1601
- if (!activity.getStat(DataGradeAdjustedSpeedAvgKilometersPerHour.type)) {
1602
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1603
- if (speedAvg) {
1604
- activity.addStat(new DataGradeAdjustedSpeedAvgKilometersPerHour(convertSpeedToSpeedInKilometersPerHour(speedAvg.getValue())));
1605
- }
1606
- }
1607
- if (!activity.getStat(DataGradeAdjustedSpeedAvgMilesPerHour.type)) {
1608
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1609
- if (speedAvg) {
1610
- activity.addStat(new DataGradeAdjustedSpeedAvgMilesPerHour(convertSpeedToSpeedInMilesPerHour(speedAvg.getValue())));
1611
- }
1612
- }
1613
- if (!activity.getStat(DataGradeAdjustedSpeedAvgFeetPerSecond.type)) {
1614
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1615
- if (speedAvg) {
1616
- activity.addStat(new DataGradeAdjustedSpeedAvgFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(speedAvg.getValue())));
1617
- }
1618
- }
1619
- if (!activity.getStat(DataGradeAdjustedSpeedAvgFeetPerMinute.type)) {
1620
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1621
- if (speedAvg) {
1622
- activity.addStat(new DataGradeAdjustedSpeedAvgFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(speedAvg.getValue())));
1623
- }
1624
- }
1625
- if (!activity.getStat(DataGradeAdjustedSpeedAvgMetersPerMinute.type)) {
1626
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1627
- if (speedAvg) {
1628
- activity.addStat(new DataGradeAdjustedSpeedAvgMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(speedAvg.getValue())));
1629
- }
1630
- }
1631
- if (!activity.getStat(DataGradeAdjustedSpeedAvgKnots.type)) {
1632
- const speedAvg = activity.getStat(DataGradeAdjustedSpeedAvg.type);
1633
- if (speedAvg) {
1634
- activity.addStat(new DataGradeAdjustedSpeedAvgKnots(convertSpeedToSpeedInKnots(speedAvg.getValue())));
1635
- }
1636
- }
1637
- // Vertical speed
1638
- if (!activity.getStat(DataVerticalSpeedAvgFeetPerSecond.type)) {
1639
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1640
- if (verticalSpeedAvg) {
1641
- activity.addStat(new DataVerticalSpeedAvgFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(verticalSpeedAvg.getValue())));
1642
- }
1643
- }
1644
- if (!activity.getStat(DataVerticalSpeedAvgMetersPerMinute.type)) {
1645
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1646
- if (verticalSpeedAvg) {
1647
- activity.addStat(new DataVerticalSpeedAvgMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(verticalSpeedAvg.getValue())));
1648
- }
1649
- }
1650
- if (!activity.getStat(DataVerticalSpeedAvgFeetPerMinute.type)) {
1651
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1652
- if (verticalSpeedAvg) {
1653
- activity.addStat(new DataVerticalSpeedAvgFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(verticalSpeedAvg.getValue())));
1654
- }
1655
- }
1656
- if (!activity.getStat(DataVerticalSpeedAvgMetersPerHour.type)) {
1657
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1658
- if (verticalSpeedAvg) {
1659
- activity.addStat(new DataVerticalSpeedAvgMetersPerHour(convertSpeedToSpeedInMetersPerHour(verticalSpeedAvg.getValue())));
1660
- }
1661
- }
1662
- if (!activity.getStat(DataVerticalSpeedAvgFeetPerHour.type)) {
1663
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1664
- if (verticalSpeedAvg) {
1665
- activity.addStat(new DataVerticalSpeedAvgFeetPerHour(convertSpeedToSpeedInFeetPerHour(verticalSpeedAvg.getValue())));
1666
- }
1667
- }
1668
- if (!activity.getStat(DataVerticalSpeedAvgKilometerPerHour.type)) {
1669
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1670
- if (verticalSpeedAvg) {
1671
- activity.addStat(new DataVerticalSpeedAvgKilometerPerHour(convertSpeedToSpeedInKilometersPerHour(verticalSpeedAvg.getValue())));
1672
- }
1673
- }
1674
- if (!activity.getStat(DataVerticalSpeedAvgMilesPerHour.type)) {
1675
- const verticalSpeedAvg = activity.getStat(DataVerticalSpeedAvg.type);
1676
- if (verticalSpeedAvg) {
1677
- activity.addStat(new DataVerticalSpeedAvgMilesPerHour(convertSpeedToSpeedInMilesPerHour(verticalSpeedAvg.getValue())));
1678
- }
1679
- }
1680
- if (!activity.getStat(DataVerticalSpeedMaxFeetPerSecond.type)) {
1681
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1682
- if (verticalSpeedMax) {
1683
- activity.addStat(new DataVerticalSpeedMaxFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(verticalSpeedMax.getValue())));
1684
- }
1685
- }
1686
- if (!activity.getStat(DataVerticalSpeedMaxMetersPerMinute.type)) {
1687
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1688
- if (verticalSpeedMax) {
1689
- activity.addStat(new DataVerticalSpeedMaxMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(verticalSpeedMax.getValue())));
1690
- }
1691
- }
1692
- if (!activity.getStat(DataVerticalSpeedMaxFeetPerMinute.type)) {
1693
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1694
- if (verticalSpeedMax) {
1695
- activity.addStat(new DataVerticalSpeedMaxFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(verticalSpeedMax.getValue())));
1696
- }
1697
- }
1698
- if (!activity.getStat(DataVerticalSpeedMaxMetersPerHour.type)) {
1699
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1700
- if (verticalSpeedMax) {
1701
- activity.addStat(new DataVerticalSpeedMaxMetersPerHour(convertSpeedToSpeedInMetersPerHour(verticalSpeedMax.getValue())));
1702
- }
1703
- }
1704
- if (!activity.getStat(DataVerticalSpeedMaxFeetPerHour.type)) {
1705
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1706
- if (verticalSpeedMax) {
1707
- activity.addStat(new DataVerticalSpeedMaxFeetPerHour(convertSpeedToSpeedInFeetPerHour(verticalSpeedMax.getValue())));
1708
- }
1709
- }
1710
- if (!activity.getStat(DataVerticalSpeedMaxKilometerPerHour.type)) {
1711
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1712
- if (verticalSpeedMax) {
1713
- activity.addStat(new DataVerticalSpeedMaxKilometerPerHour(convertSpeedToSpeedInKilometersPerHour(verticalSpeedMax.getValue())));
1714
- }
1715
- }
1716
- if (!activity.getStat(DataVerticalSpeedMaxMilesPerHour.type)) {
1717
- const verticalSpeedMax = activity.getStat(DataVerticalSpeedMax.type);
1718
- if (verticalSpeedMax) {
1719
- activity.addStat(new DataVerticalSpeedMaxMilesPerHour(convertSpeedToSpeedInMilesPerHour(verticalSpeedMax.getValue())));
1720
- }
1721
- }
1722
- if (!activity.getStat(DataVerticalSpeedMinFeetPerSecond.type)) {
1723
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1724
- if (verticalSpeedMin) {
1725
- activity.addStat(new DataVerticalSpeedMinFeetPerSecond(convertSpeedToSpeedInFeetPerSecond(verticalSpeedMin.getValue())));
1726
- }
1727
- }
1728
- if (!activity.getStat(DataVerticalSpeedMinMetersPerMinute.type)) {
1729
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1730
- if (verticalSpeedMin) {
1731
- activity.addStat(new DataVerticalSpeedMinMetersPerMinute(convertSpeedToSpeedInMetersPerMinute(verticalSpeedMin.getValue())));
1732
- }
1733
- }
1734
- if (!activity.getStat(DataVerticalSpeedMinFeetPerMinute.type)) {
1735
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1736
- if (verticalSpeedMin) {
1737
- activity.addStat(new DataVerticalSpeedMinFeetPerMinute(convertSpeedToSpeedInFeetPerMinute(verticalSpeedMin.getValue())));
1738
- }
1739
- }
1740
- if (!activity.getStat(DataVerticalSpeedMinMetersPerHour.type)) {
1741
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1742
- if (verticalSpeedMin) {
1743
- activity.addStat(new DataVerticalSpeedMinMetersPerHour(convertSpeedToSpeedInMetersPerHour(verticalSpeedMin.getValue())));
1744
- }
1745
- }
1746
- if (!activity.getStat(DataVerticalSpeedMinFeetPerHour.type)) {
1747
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1748
- if (verticalSpeedMin) {
1749
- activity.addStat(new DataVerticalSpeedMinFeetPerHour(convertSpeedToSpeedInFeetPerHour(verticalSpeedMin.getValue())));
1750
- }
1751
- }
1752
- if (!activity.getStat(DataVerticalSpeedMinKilometerPerHour.type)) {
1753
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1754
- if (verticalSpeedMin) {
1755
- activity.addStat(new DataVerticalSpeedMinKilometerPerHour(convertSpeedToSpeedInKilometersPerHour(verticalSpeedMin.getValue())));
1756
- }
1757
- }
1758
- if (!activity.getStat(DataVerticalSpeedMinMilesPerHour.type)) {
1759
- const verticalSpeedMin = activity.getStat(DataVerticalSpeedMin.type);
1760
- if (verticalSpeedMin) {
1761
- activity.addStat(new DataVerticalSpeedMinMilesPerHour(convertSpeedToSpeedInMilesPerHour(verticalSpeedMin.getValue())));
1762
- }
1763
- }
1764
- // Test SWOLF existence for swimming activities
1765
- if ((activity.type === ActivityTypes.Swimming || activity.type === ActivityTypes.OpenWaterSwimming) &&
1766
- (!activity.getStat(DataSWOLF25m.type) || !activity.getStat(DataSWOLF50m.type)) &&
1767
- ((_a = activity.getStat(DataSpeedAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue()) &&
1768
- ((_b = activity.getStat(DataCadenceAvg.type)) === null || _b === void 0 ? void 0 : _b.getValue())) {
1769
- const avgPace100m = 100 / activity.getStat(DataSpeedAvg.type).getValue();
1770
- const avgCadence = activity.getStat(DataCadenceAvg.type).getValue();
1771
- if (!activity.getStat(DataSWOLF25m.type)) {
1772
- const swolf25m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 25);
1773
- activity.addStat(new DataSWOLF25m(swolf25m));
1774
- }
1775
- if (!activity.getStat(DataSWOLF50m.type)) {
1776
- const swolf50m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 50);
1777
- activity.addStat(new DataSWOLF50m(swolf50m));
1778
- }
1779
- }
1780
- if (!activity.getStat(DataDuration.type)) {
1781
- activity.addStat(new DataDuration((activity.endDate.getTime() - activity.startDate.getTime()) / 1000));
1782
- }
1783
- // If timer time not set, then assign elapsed time by default (e.g. GPX file dont support timer time)
1784
- if (!activity.getStat(DataTimerTime.type)) {
1785
- activity.addStat(new DataTimerTime(this.round(activity.getDuration().getValue(), 2)));
1786
- }
1787
- // If missing moving time
1788
- // Or moving time equals duration, then try to build real moving from laps if available
1789
- if (!activity.getStat(DataMovingTime.type)) {
1790
- let movingTime = 0;
1791
- // First try to compute moving time from laps
1792
- const laps = activity.getLaps();
1793
- if (laps && laps.length > 0) {
1794
- activity.getLaps().forEach(lap => {
1795
- const stat = lap.getStat(DataMovingTime.type);
1796
- if (stat) {
1797
- movingTime += stat.getValue();
1798
- }
1799
- });
1800
- }
1801
- // Get timer time...
1802
- const timerTime = (_c = activity.getStat(DataTimerTime.type)) === null || _c === void 0 ? void 0 : _c.getValue();
1803
- // ... and compare with moving time and determine if moving time is like "moving time"
1804
- const isMovingTimeAlike = movingTime > 0 && movingTime < timerTime;
1805
- // If moving time from laps is not valid
1806
- if (!isMovingTimeAlike && activity.hasStreamData(DataSpeed.type)) {
1807
- // ...then re-compute moving time but using global records.
1808
- movingTime = 0;
1809
- const speedByDurationStream = activity.getStreamDataByDuration(DataSpeed.type, true, true);
1810
- const speedThreshold = ActivityTypesMoving.getSpeedThreshold(activity.type);
1811
- speedByDurationStream.forEach((speedItem, index) => {
1812
- var _a;
1813
- if (speedItem.value !== null && speedItem.value > speedThreshold) {
1814
- movingTime += (speedByDurationStream[index].time - (((_a = speedByDurationStream[index - 1]) === null || _a === void 0 ? void 0 : _a.time) || 0)) / 1000;
1815
- }
1816
- });
1817
- }
1818
- // In case moving time would be invalid, set it to timer time "at max"
1819
- if (!movingTime || movingTime > timerTime) {
1820
- movingTime = timerTime;
1821
- }
1822
- activity.addStat(new DataMovingTime(movingTime));
1823
- }
1824
- // Add Power Work if missing when avg power and moving time are available
1825
- if (!activity.getStat(DataPowerWork.type) &&
1826
- activity.getStat(DataPowerAvg.type) &&
1827
- activity.getStat(DataMovingTime.type)) {
1828
- const movingTime = activity.getStat(DataMovingTime.type).getValue();
1829
- const avgPower = activity.getStat(DataPowerAvg.type).getValue();
1830
- const powerWork = Math.round((avgPower * movingTime) / 1000);
1831
- activity.addStat(new DataPowerWork(powerWork));
1832
- }
1833
- // If there is no pause defined then get it from duration and moving time (if available)
1834
- if (!activity.getStat(DataPause.type) || !activity.getStat(DataPause.type).getValue()) {
1835
- const movingTimeStat = activity.getStat(DataMovingTime.type);
1836
- const pauseTime = movingTimeStat && movingTimeStat.getValue() ? activity.getDuration().getValue() - movingTimeStat.getValue() : 0;
1837
- activity.addStat(new DataPause(this.round(pauseTime, 2)));
1838
- }
1839
- }
1840
- }
1841
- ActivityUtilities.geoLibAdapter = new GeoLibAdapter();