@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.
- package/lib/esm/index.js +12034 -152
- package/package.json +2 -2
- package/lib/esm/activities/activity-parsing-options.js +0 -19
- package/lib/esm/activities/activity.interface.js +0 -1
- package/lib/esm/activities/activity.js +0 -281
- package/lib/esm/activities/activity.json.interface.js +0 -1
- package/lib/esm/activities/activity.spec.js +0 -348
- package/lib/esm/activities/activity.types.js +0 -1046
- package/lib/esm/activities/activityt-types.spec.js +0 -16
- package/lib/esm/activities/devices/device.interface.js +0 -1
- package/lib/esm/activities/devices/device.js +0 -26
- package/lib/esm/activities/devices/device.json.interface.js +0 -1
- package/lib/esm/constants/constants.js +0 -8
- package/lib/esm/creators/creator.interface.js +0 -1
- package/lib/esm/creators/creator.js +0 -37
- package/lib/esm/creators/creator.json.interface.js +0 -1
- package/lib/esm/creators/creator.spec.js +0 -25
- package/lib/esm/data/data-active-lap.js +0 -4
- package/lib/esm/data/data-active-lengths.js +0 -4
- package/lib/esm/data/data-aerobic-training-effect.js +0 -8
- package/lib/esm/data/data-anaerobic-training-effect.js +0 -8
- package/lib/esm/data/data-stance-time-balance-left.js +0 -4
- package/lib/esm/data/data-stance-time-balance-right.js +0 -4
- package/lib/esm/data/data-stance-time-balance.js +0 -3
- package/lib/esm/data/data-store.spec.js +0 -78
- package/lib/esm/data/data-total-cycles.js +0 -4
- package/lib/esm/data/data.absolute-pressure.js +0 -5
- package/lib/esm/data/data.accumulated-power.js +0 -8
- package/lib/esm/data/data.activity-types.js +0 -7
- package/lib/esm/data/data.air-power-avg.js +0 -4
- package/lib/esm/data/data.air-power-max.js +0 -4
- package/lib/esm/data/data.air-power-min.js +0 -4
- package/lib/esm/data/data.air-power.js +0 -8
- package/lib/esm/data/data.alti-baro-profile.js +0 -4
- package/lib/esm/data/data.altitude-avg.js +0 -4
- package/lib/esm/data/data.altitude-gps.js +0 -5
- package/lib/esm/data/data.altitude-max.js +0 -4
- package/lib/esm/data/data.altitude-min.js +0 -4
- package/lib/esm/data/data.altitude-smooth.js +0 -4
- package/lib/esm/data/data.altitude.js +0 -8
- package/lib/esm/data/data.array.js +0 -13
- package/lib/esm/data/data.ascent-time.js +0 -4
- package/lib/esm/data/data.ascent.js +0 -4
- package/lib/esm/data/data.auto-lap-distance.js +0 -5
- package/lib/esm/data/data.auto-lap-duration.js +0 -4
- package/lib/esm/data/data.auto-lap-used.js +0 -7
- package/lib/esm/data/data.auto-pause-used.js +0 -7
- package/lib/esm/data/data.avg-stride-length.js +0 -4
- package/lib/esm/data/data.balance.js +0 -6
- package/lib/esm/data/data.bare.js +0 -4
- package/lib/esm/data/data.battery-charge.js +0 -8
- package/lib/esm/data/data.battery-consumption.js +0 -8
- package/lib/esm/data/data.battery-current.js +0 -8
- package/lib/esm/data/data.battery-life-estimation.js +0 -4
- package/lib/esm/data/data.battery-voltage.js +0 -8
- package/lib/esm/data/data.bike-pod-used.js +0 -7
- package/lib/esm/data/data.boolean.js +0 -9
- package/lib/esm/data/data.cadence-avg.js +0 -4
- package/lib/esm/data/data.cadence-max.js +0 -4
- package/lib/esm/data/data.cadence-min.js +0 -4
- package/lib/esm/data/data.cadence.js +0 -8
- package/lib/esm/data/data.cycling-dynamics.js +0 -3
- package/lib/esm/data/data.cycling-position.js +0 -37
- package/lib/esm/data/data.cycling-seated-time.js +0 -5
- package/lib/esm/data/data.cycling-standing-time.js +0 -5
- package/lib/esm/data/data.descent-time.js +0 -4
- package/lib/esm/data/data.descent.js +0 -4
- package/lib/esm/data/data.description.js +0 -4
- package/lib/esm/data/data.device-location.js +0 -4
- package/lib/esm/data/data.device-names.js +0 -7
- package/lib/esm/data/data.distance.js +0 -15
- package/lib/esm/data/data.duration.js +0 -56
- package/lib/esm/data/data.ehpe.js +0 -5
- package/lib/esm/data/data.enabled-navigation-systems.js +0 -4
- package/lib/esm/data/data.end-altitude.js +0 -4
- package/lib/esm/data/data.end-position.js +0 -4
- package/lib/esm/data/data.energy.js +0 -8
- package/lib/esm/data/data.epoc.js +0 -5
- package/lib/esm/data/data.event.js +0 -3
- package/lib/esm/data/data.evpe.js +0 -4
- package/lib/esm/data/data.feeling.js +0 -15
- package/lib/esm/data/data.foot-pod-used.js +0 -7
- package/lib/esm/data/data.form-power.js +0 -4
- package/lib/esm/data/data.fused-altitude.js +0 -7
- package/lib/esm/data/data.fused-location.js +0 -7
- package/lib/esm/data/data.gnss-distance.js +0 -4
- package/lib/esm/data/data.grade-adjusted-pace-avg.js +0 -15
- package/lib/esm/data/data.grade-adjusted-pace-max.js +0 -15
- package/lib/esm/data/data.grade-adjusted-pace-min.js +0 -15
- package/lib/esm/data/data.grade-adjusted-pace.js +0 -25
- package/lib/esm/data/data.grade-adjusted-speed-avg.js +0 -46
- package/lib/esm/data/data.grade-adjusted-speed-max.js +0 -46
- package/lib/esm/data/data.grade-adjusted-speed-min.js +0 -46
- package/lib/esm/data/data.grade-adjusted-speed.js +0 -78
- package/lib/esm/data/data.grade-smooth.js +0 -7
- package/lib/esm/data/data.grade.js +0 -7
- package/lib/esm/data/data.ground-time.js +0 -8
- package/lib/esm/data/data.heart-rate-avg.js +0 -4
- package/lib/esm/data/data.heart-rate-max.js +0 -4
- package/lib/esm/data/data.heart-rate-min.js +0 -4
- package/lib/esm/data/data.heart-rate-used.js +0 -7
- package/lib/esm/data/data.heart-rate-zone-five-duration.js +0 -4
- package/lib/esm/data/data.heart-rate-zone-four-duration.js +0 -4
- package/lib/esm/data/data.heart-rate-zone-one-duration.js +0 -4
- package/lib/esm/data/data.heart-rate-zone-three-duration.js +0 -4
- package/lib/esm/data/data.heart-rate-zone-two-duration.js +0 -4
- package/lib/esm/data/data.heart-rate.js +0 -8
- package/lib/esm/data/data.ibi.js +0 -8
- package/lib/esm/data/data.interface.js +0 -5
- package/lib/esm/data/data.js +0 -62
- package/lib/esm/data/data.json.interface.js +0 -1
- package/lib/esm/data/data.latitude-degrees.js +0 -5
- package/lib/esm/data/data.left-balance.js +0 -4
- package/lib/esm/data/data.leg-stiffness.js +0 -16
- package/lib/esm/data/data.longitude-degrees.js +0 -5
- package/lib/esm/data/data.moving-time.js +0 -4
- package/lib/esm/data/data.number-of-satellites.js +0 -7
- package/lib/esm/data/data.number-of.samples.js +0 -4
- package/lib/esm/data/data.number.js +0 -13
- package/lib/esm/data/data.pace-avg.js +0 -8
- package/lib/esm/data/data.pace-max.js +0 -8
- package/lib/esm/data/data.pace-min.js +0 -8
- package/lib/esm/data/data.pace.js +0 -46
- package/lib/esm/data/data.pause.js +0 -4
- package/lib/esm/data/data.peak-epoc.js +0 -7
- package/lib/esm/data/data.peak-training-effect.js +0 -4
- package/lib/esm/data/data.percent.js +0 -4
- package/lib/esm/data/data.pool-length.js +0 -5
- package/lib/esm/data/data.position.interface.js +0 -1
- package/lib/esm/data/data.position.js +0 -18
- package/lib/esm/data/data.power-avg.js +0 -4
- package/lib/esm/data/data.power-down.js +0 -4
- package/lib/esm/data/data.power-intensity-factor.js +0 -5
- package/lib/esm/data/data.power-left.js +0 -4
- package/lib/esm/data/data.power-max.js +0 -4
- package/lib/esm/data/data.power-min.js +0 -4
- package/lib/esm/data/data.power-normalized.js +0 -4
- package/lib/esm/data/data.power-pedal-smoothness-left.js +0 -4
- package/lib/esm/data/data.power-pedal-smoothness-right.js +0 -4
- package/lib/esm/data/data.power-pod-used.js +0 -7
- package/lib/esm/data/data.power-right.js +0 -4
- package/lib/esm/data/data.power-torque-effectiveness-left.js +0 -4
- package/lib/esm/data/data.power-torque-effectiveness-right.js +0 -4
- package/lib/esm/data/data.power-training-stress-score.js +0 -5
- package/lib/esm/data/data.power-up.js +0 -4
- package/lib/esm/data/data.power-work.js +0 -5
- package/lib/esm/data/data.power-zone-five-duration.js +0 -4
- package/lib/esm/data/data.power-zone-four-duration.js +0 -4
- package/lib/esm/data/data.power-zone-one-duration.js +0 -4
- package/lib/esm/data/data.power-zone-three-duration.js +0 -4
- package/lib/esm/data/data.power-zone-two-duration.js +0 -4
- package/lib/esm/data/data.power.js +0 -8
- package/lib/esm/data/data.recovery-time.js +0 -7
- package/lib/esm/data/data.rider-position-change-event.js +0 -8
- package/lib/esm/data/data.right-balance.js +0 -4
- package/lib/esm/data/data.rpe.js +0 -23
- package/lib/esm/data/data.satellite-5-best-snr.js +0 -4
- package/lib/esm/data/data.sea-level-pressure.js +0 -5
- package/lib/esm/data/data.spec.js +0 -25
- package/lib/esm/data/data.speed-avg.js +0 -46
- package/lib/esm/data/data.speed-max.js +0 -46
- package/lib/esm/data/data.speed-min.js +0 -46
- package/lib/esm/data/data.speed-zone-five-duration.js +0 -4
- package/lib/esm/data/data.speed-zone-four-duration.js +0 -4
- package/lib/esm/data/data.speed-zone-one-duration.js +0 -4
- package/lib/esm/data/data.speed-zone-three-duration.js +0 -4
- package/lib/esm/data/data.speed-zone-two-duration.js +0 -4
- package/lib/esm/data/data.speed.js +0 -88
- package/lib/esm/data/data.sport-profile-name.js +0 -4
- package/lib/esm/data/data.stance-time.js +0 -5
- package/lib/esm/data/data.start-altitude.js +0 -4
- package/lib/esm/data/data.start-event.js +0 -4
- package/lib/esm/data/data.start-position.js +0 -4
- package/lib/esm/data/data.step-length.js +0 -4
- package/lib/esm/data/data.steps-old.js +0 -4
- package/lib/esm/data/data.steps.js +0 -4
- package/lib/esm/data/data.stop-all-event.js +0 -4
- package/lib/esm/data/data.stop-event.js +0 -4
- package/lib/esm/data/data.store.export.spec.js +0 -66
- package/lib/esm/data/data.store.js +0 -1213
- package/lib/esm/data/data.string.js +0 -13
- package/lib/esm/data/data.stryd-altitude.js +0 -4
- package/lib/esm/data/data.stryd-distance.js +0 -4
- package/lib/esm/data/data.stryd-speed.js +0 -4
- package/lib/esm/data/data.swim-pace-avg.js +0 -8
- package/lib/esm/data/data.swim-pace-max.js +0 -8
- package/lib/esm/data/data.swim-pace-min.js +0 -8
- package/lib/esm/data/data.swim-pace.js +0 -19
- package/lib/esm/data/data.swolf-25m.js +0 -4
- package/lib/esm/data/data.swolf-50m.js +0 -4
- package/lib/esm/data/data.target-distance.js +0 -4
- package/lib/esm/data/data.target-heart-rate-zone.js +0 -4
- package/lib/esm/data/data.target-power-zone.js +0 -4
- package/lib/esm/data/data.target-speed-zone.js +0 -4
- package/lib/esm/data/data.target-time.js +0 -4
- package/lib/esm/data/data.temperature-avg.js +0 -4
- package/lib/esm/data/data.temperature-max.js +0 -4
- package/lib/esm/data/data.temperature-min.js +0 -4
- package/lib/esm/data/data.temperature.js +0 -8
- package/lib/esm/data/data.time.js +0 -6
- package/lib/esm/data/data.timer-time.js +0 -4
- package/lib/esm/data/data.vertical-oscillation.js +0 -5
- package/lib/esm/data/data.vertical-ratio.js +0 -5
- package/lib/esm/data/data.vertical-speed-avg.js +0 -53
- package/lib/esm/data/data.vertical-speed-max.js +0 -53
- package/lib/esm/data/data.vertical-speed-min.js +0 -53
- package/lib/esm/data/data.vertical-speed.js +0 -103
- package/lib/esm/data/data.vo2-max.js +0 -7
- package/lib/esm/data/ibi/data.ibi.filters.js +0 -52
- package/lib/esm/data/ibi/data.ibi.js +0 -98
- package/lib/esm/data/ibi/data.ibi.spec.js +0 -66
- package/lib/esm/duration/duration.class.abstract.js +0 -36
- package/lib/esm/duration/duration.class.interface.js +0 -1
- package/lib/esm/errors/duration-exceeded-event-lib.error.js +0 -9
- package/lib/esm/errors/empty-event-sports-libs.error.js +0 -9
- package/lib/esm/errors/event-lib.error.js +0 -8
- package/lib/esm/errors/lib.error.js +0 -6
- package/lib/esm/errors/parsing-event-lib.error.js +0 -9
- package/lib/esm/events/adapters/exporters/exporter.gpx.js +0 -75
- package/lib/esm/events/adapters/exporters/exporter.interface.js +0 -1
- package/lib/esm/events/adapters/exporters/exporter.json.js +0 -20
- package/lib/esm/events/adapters/file-type.enum.js +0 -7
- package/lib/esm/events/adapters/importers/fit/importer.fit.ant-plus.device.names.js +0 -25
- package/lib/esm/events/adapters/importers/fit/importer.fit.coros.device.names.js +0 -5
- package/lib/esm/events/adapters/importers/fit/importer.fit.development.device.names.js +0 -4
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.device.names.js +0 -462
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.data.js +0 -877
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.js +0 -106
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.spec.js +0 -32
- package/lib/esm/events/adapters/importers/fit/importer.fit.hammerhead.device.names.js +0 -4
- package/lib/esm/events/adapters/importers/fit/importer.fit.integration.spec.js +0 -44
- package/lib/esm/events/adapters/importers/fit/importer.fit.js +0 -978
- package/lib/esm/events/adapters/importers/fit/importer.fit.lezyne.device.names.js +0 -3
- package/lib/esm/events/adapters/importers/fit/importer.fit.magellan.device.names.js +0 -5
- package/lib/esm/events/adapters/importers/fit/importer.fit.mapper.js +0 -231
- package/lib/esm/events/adapters/importers/fit/importer.fit.saris.device.names.js +0 -3
- package/lib/esm/events/adapters/importers/fit/importer.fit.spec.js +0 -326
- package/lib/esm/events/adapters/importers/fit/importer.fit.srm.device.names.js +0 -7
- package/lib/esm/events/adapters/importers/fit/importer.fit.suunto.device.names.js +0 -16
- package/lib/esm/events/adapters/importers/fit/importer.fit.wahoo.device.names.js +0 -10
- package/lib/esm/events/adapters/importers/gpx/gx-parser.js +0 -36
- package/lib/esm/events/adapters/importers/gpx/importer.gpx.integration.spec.js +0 -44
- package/lib/esm/events/adapters/importers/gpx/importer.gpx.js +0 -102
- package/lib/esm/events/adapters/importers/gpx/importer.gpx.mapper.js +0 -142
- package/lib/esm/events/adapters/importers/gpx/importer.gpx.spec.js +0 -71
- package/lib/esm/events/adapters/importers/json/importer.json.js +0 -160
- package/lib/esm/events/adapters/importers/sample-info.interface.js +0 -1
- package/lib/esm/events/adapters/importers/suunto/importer.suunto.activity.ids.js +0 -85
- package/lib/esm/events/adapters/importers/suunto/importer.suunto.device.names.js +0 -26
- package/lib/esm/events/adapters/importers/suunto/importer.suunto.integration.spec.js +0 -44
- package/lib/esm/events/adapters/importers/suunto/importer.suunto.json.js +0 -717
- package/lib/esm/events/adapters/importers/suunto/importer.suunto.sml.js +0 -125
- package/lib/esm/events/adapters/importers/tcx/importer.tcx.integration.spec.js +0 -46
- package/lib/esm/events/adapters/importers/tcx/importer.tcx.js +0 -442
- package/lib/esm/events/adapters/importers/tcx/importer.tcx.mapper.js +0 -91
- package/lib/esm/events/adapters/importers/tcx/utils.tcx.js +0 -36
- package/lib/esm/events/event.interface.js +0 -1
- package/lib/esm/events/event.js +0 -123
- package/lib/esm/events/event.json.interface.js +0 -1
- package/lib/esm/events/event.spec.js +0 -51
- package/lib/esm/events/utilities/activity.utilities.js +0 -1841
- package/lib/esm/events/utilities/activity.utilities.spec.js +0 -373
- package/lib/esm/events/utilities/event.utilities.js +0 -57
- package/lib/esm/events/utilities/grade-calculator/grade-calculator.js +0 -121
- package/lib/esm/events/utilities/grade-calculator/grade-calculator.spec.js +0 -93
- package/lib/esm/events/utilities/grade-calculator/low-pass-filter.js +0 -86
- package/lib/esm/events/utilities/helpers.js +0 -162
- package/lib/esm/geodesy/adapters/adapter.interface.js +0 -1
- package/lib/esm/geodesy/adapters/geolib.adapter.js +0 -28
- package/lib/esm/id/id.abstract.class.js +0 -9
- package/lib/esm/id/id.class.interface.js +0 -1
- package/lib/esm/id/id.class.spec.js +0 -13
- package/lib/esm/intensity-zones/intensity-zones.interface.js +0 -1
- package/lib/esm/intensity-zones/intensity-zones.js +0 -29
- package/lib/esm/intensity-zones/intensity-zones.json.interface.js +0 -1
- package/lib/esm/intensity-zones/intensity-zones.spec.js +0 -30
- package/lib/esm/laps/lap.interface.js +0 -1
- package/lib/esm/laps/lap.js +0 -29
- package/lib/esm/laps/lap.json.interface.js +0 -1
- package/lib/esm/laps/lap.types.js +0 -52
- package/lib/esm/meta-data/event-meta-data.interface.js +0 -6
- package/lib/esm/meta-data/meta-data.js +0 -57
- package/lib/esm/meta-data/meta-data.json.interface.js +0 -1
- package/lib/esm/privacy/privacy.class.interface.js +0 -5
- package/lib/esm/serializable/serializable.class.interface.js +0 -1
- package/lib/esm/service-tokens/oauth1-service-token.interface.js +0 -1
- package/lib/esm/service-tokens/oauth2-service-token.interface.js +0 -1
- package/lib/esm/specs/activities-parsing.integration.spec.js +0 -1847
- package/lib/esm/specs/activity-duration-stream.integration.spec.js +0 -57
- package/lib/esm/specs/fixtures/streams/strava/rides/3171472783.json +0 -52534
- package/lib/esm/specs/fixtures/streams/strava/rides/3171487458.json +0 -78818
- package/lib/esm/specs/fixtures/streams/strava/rides/343080886.json +0 -105090
- package/lib/esm/specs/fixtures/streams/strava/rides/5910143591.json +0 -110711
- package/lib/esm/specs/fixtures/streams/strava/runs/2451375851.json +0 -74846
- package/lib/esm/specs/fixtures/streams/strava/runs/2709634581.json +0 -66817
- package/lib/esm/specs/fixtures/streams/strava/runs/3156040843.json +0 -17594
- package/lib/esm/specs/fixtures/streams/strava/runs/3182900697.json +0 -17322
- package/lib/esm/specs/fixtures/streams/strava/runs/3183465494.json +0 -20463
- package/lib/esm/specs/fixtures/streams/strava/runs/3183490558.json +0 -58202
- package/lib/esm/specs/spec-utils.js +0 -159
- package/lib/esm/specs/strava-streams-compliance.spec.js +0 -951
- package/lib/esm/stats/stats.class.abstract.js +0 -32
- package/lib/esm/stats/stats.class.interface.js +0 -1
- package/lib/esm/stats/stats.json.interface.js +0 -1
- package/lib/esm/streams/compressed.stream.interface.js +0 -12
- package/lib/esm/streams/ibi-stream.js +0 -43
- package/lib/esm/streams/low-pass.stream.filter.js +0 -9
- package/lib/esm/streams/stream.filter.interface.js +0 -1
- package/lib/esm/streams/stream.interface.js +0 -1
- package/lib/esm/streams/stream.js +0 -72
- package/lib/esm/streams/stream.spec.js +0 -168
- package/lib/esm/tiles/tile.settings.interface.js +0 -41
- package/lib/esm/users/settings/dashboard/user.dashboard.settings.interface.js +0 -13
- package/lib/esm/users/settings/user.app.settings.interface.js +0 -5
- package/lib/esm/users/settings/user.chart.settings.interface.js +0 -23
- package/lib/esm/users/settings/user.map.settings.interface.js +0 -22
- package/lib/esm/users/settings/user.my-tracks.settings.interface.js +0 -1
- package/lib/esm/users/settings/user.settings.interface.js +0 -1
- package/lib/esm/users/settings/user.stats-settings.interface.js +0 -1
- package/lib/esm/users/settings/user.summaries.settings.interface.js +0 -1
- package/lib/esm/users/settings/user.unit.settings.interface.js +0 -73
- package/lib/esm/users/user.account.privileges.interface.js +0 -1
- package/lib/esm/users/user.export-to-csv.settings.interface.js +0 -1
- package/lib/esm/users/user.interface.js +0 -1
- package/lib/esm/users/user.js +0 -38
- package/lib/esm/users/user.service.meta.interface.js +0 -1
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { EventImporterSuuntoJSON } from './importer.suunto.json';
|
|
2
|
-
import { isNumber } from '../../../utilities/helpers';
|
|
3
|
-
import { ActivityParsingOptions } from '../../../../activities/activity-parsing-options';
|
|
4
|
-
import { XMLParser } from 'fast-xml-parser';
|
|
5
|
-
export class EventImporterSuuntoSML {
|
|
6
|
-
static getFromXML(contents, options = ActivityParsingOptions.DEFAULT, name = 'New Event') {
|
|
7
|
-
const parser = new XMLParser();
|
|
8
|
-
const json = parser.parse(contents).sml;
|
|
9
|
-
// debugger;
|
|
10
|
-
// A few mods here to convert it to compatible json suunto string
|
|
11
|
-
json.DeviceLog.Samples = json.DeviceLog.Samples.Sample;
|
|
12
|
-
const samplesWithUTC = json.DeviceLog.Samples.filter((sample) => !!sample.UTC);
|
|
13
|
-
// Find the first UTC timestamped sample and use it later for start date
|
|
14
|
-
const startDate = samplesWithUTC.length
|
|
15
|
-
? new Date(samplesWithUTC[0].UTC)
|
|
16
|
-
: new Date(json.DeviceLog.Header.DateTime);
|
|
17
|
-
// Determine the end date
|
|
18
|
-
const endDate = samplesWithUTC.length > 1
|
|
19
|
-
? samplesWithUTC[samplesWithUTC.length - 1].UTC
|
|
20
|
-
: new Date(startDate.getTime() + json.DeviceLog.Header.Duration * 1000);
|
|
21
|
-
// Filter out the old activity type
|
|
22
|
-
json.DeviceLog.Samples = json.DeviceLog.Samples.filter((sample) => {
|
|
23
|
-
return !(sample.Events && sample.Events.Activity);
|
|
24
|
-
});
|
|
25
|
-
// Convert the events
|
|
26
|
-
json.DeviceLog.Samples.filter((sample) => !!sample.Events).forEach((sample) => {
|
|
27
|
-
sample.Events = [sample.Events];
|
|
28
|
-
});
|
|
29
|
-
// Inject start and end sample with event
|
|
30
|
-
json.DeviceLog.Samples.unshift({
|
|
31
|
-
Events: [
|
|
32
|
-
{
|
|
33
|
-
Activity: { ActivityType: json.DeviceLog.Header.ActivityType }
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
TimeISO8601: startDate.toISOString()
|
|
37
|
-
});
|
|
38
|
-
// Add the end time and adjust the start time
|
|
39
|
-
json.DeviceLog.Header.TimeISO8601 = json.DeviceLog.Header.TimeISO8601 || endDate;
|
|
40
|
-
// Add the time on the samples
|
|
41
|
-
json.DeviceLog.Samples.forEach((sample) => {
|
|
42
|
-
if (sample.TimeISO8601) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (sample.UTC) {
|
|
46
|
-
sample.TimeISO8601 = new Date(sample.UTC).toISOString();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (isNumber(sample.Time)) {
|
|
50
|
-
sample.TimeISO8601 = new Date(startDate.getTime() + sample.Time * 1000).toISOString();
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
// Convert the RR
|
|
55
|
-
if (json.DeviceLog['R-R']) {
|
|
56
|
-
json.DeviceLog['R-R'].Data = json.DeviceLog['R-R'].Data.split(' ').map((dataString) => Number(dataString));
|
|
57
|
-
}
|
|
58
|
-
json.DeviceLog.Header.Altitude = json.DeviceLog.Header.Altitude ? [json.DeviceLog.Header.Altitude] : null;
|
|
59
|
-
json.DeviceLog.Header.HR = json.DeviceLog.Header.HR ? [json.DeviceLog.Header.HR] : null;
|
|
60
|
-
json.DeviceLog.Header.Cadence = json.DeviceLog.Header.Cadence ? [json.DeviceLog.Header.Cadence] : null;
|
|
61
|
-
json.DeviceLog.Header.Speed = json.DeviceLog.Header.Speed ? [json.DeviceLog.Header.Speed] : null;
|
|
62
|
-
json.DeviceLog.Header.Power = json.DeviceLog.Header.Power ? [json.DeviceLog.Header.Power] : null;
|
|
63
|
-
json.DeviceLog.Header.Temperature = json.DeviceLog.Header.Temperature ? [json.DeviceLog.Header.Temperature] : null;
|
|
64
|
-
json.DeviceLog.Windows = [{ Window: Object.assign({ Type: 'Activity' }, json.DeviceLog.Header) }];
|
|
65
|
-
// debugger;
|
|
66
|
-
return EventImporterSuuntoJSON.getFromJSONString(JSON.stringify(json), options);
|
|
67
|
-
}
|
|
68
|
-
static getFromJSONString(jsonString, options = ActivityParsingOptions.DEFAULT) {
|
|
69
|
-
const json = JSON.parse(jsonString);
|
|
70
|
-
let samples;
|
|
71
|
-
// Try to be a hero here
|
|
72
|
-
try {
|
|
73
|
-
samples = json.Samples.filter((sample) => !!JSON.parse(sample.Attributes)['suunto/sml'].Sample).map((sample) => {
|
|
74
|
-
return Object.assign({ TimeISO8601: sample.TimeISO8601 }, JSON.parse(sample.Attributes)['suunto/sml'].Sample);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
samples = json.Samples.filter((sample) => !!sample.Attributes['suunto/sml'].Sample).map((sample) => {
|
|
79
|
-
return Object.assign({ TimeISO8601: sample.TimeISO8601 }, sample.Attributes['suunto/sml'].Sample);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
let rr;
|
|
83
|
-
try {
|
|
84
|
-
rr = {
|
|
85
|
-
Data: json.Samples.filter((sample) => !!JSON.parse(sample.Attributes)['suunto/sml']['R-R'])
|
|
86
|
-
.map((sample) => {
|
|
87
|
-
return JSON.parse(sample.Attributes)['suunto/sml']['R-R'];
|
|
88
|
-
})
|
|
89
|
-
.reduce((accu, rrSample) => {
|
|
90
|
-
return accu.concat(rrSample.Data.split(',').map((dataString) => Number(dataString)));
|
|
91
|
-
}, [])
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
catch (e) {
|
|
95
|
-
rr = {
|
|
96
|
-
Data: json.Samples.filter((sample) => !!sample.Attributes['suunto/sml']['R-R'])
|
|
97
|
-
.map((sample) => {
|
|
98
|
-
return sample.Attributes['suunto/sml']['R-R'];
|
|
99
|
-
})
|
|
100
|
-
.reduce((accu, rrSample) => {
|
|
101
|
-
return accu.concat(rrSample.IBI);
|
|
102
|
-
}, [])
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
// debugger;
|
|
106
|
-
const suuntoJSON = {
|
|
107
|
-
DeviceLog: {
|
|
108
|
-
Header: {},
|
|
109
|
-
Device: {
|
|
110
|
-
Name: 'Suunto unknown',
|
|
111
|
-
Info: {
|
|
112
|
-
HW: 0,
|
|
113
|
-
SW: 0,
|
|
114
|
-
SerialNumber: 0
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
Windows: [],
|
|
118
|
-
Samples: samples,
|
|
119
|
-
['R-R']: rr
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
// debugger;
|
|
123
|
-
return EventImporterSuuntoJSON.getFromJSONString(JSON.stringify(suuntoJSON), options);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import * as path from 'path';
|
|
12
|
-
import { DOMParser } from '@xmldom/xmldom';
|
|
13
|
-
import { EventImporterTCX } from './importer.tcx';
|
|
14
|
-
describe('EventImporterTCX Integration', () => {
|
|
15
|
-
// Go up 5 levels from src/events/adapters/importers/tcx -> sports-lib root
|
|
16
|
-
const samplesDir = path.resolve(__dirname, '../../../../../samples/tcx');
|
|
17
|
-
it('should parse all sample tcx files', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
-
if (!fs.existsSync(samplesDir)) {
|
|
19
|
-
console.warn(`Samples directory not found at ${samplesDir}. Skipping integration tests.`);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const files = fs.readdirSync(samplesDir).filter(f => f.endsWith('.tcx'));
|
|
23
|
-
if (files.length === 0) {
|
|
24
|
-
console.warn('No .tcx files found in samples directory.');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
console.log(`Found ${files.length} .tcx files to test:`, files);
|
|
28
|
-
const parser = new DOMParser();
|
|
29
|
-
for (const file of files) {
|
|
30
|
-
const filePath = path.join(samplesDir, file);
|
|
31
|
-
const fileString = fs.readFileSync(filePath, 'utf-8');
|
|
32
|
-
try {
|
|
33
|
-
// Parse string to XML Document
|
|
34
|
-
const xmlDoc = parser.parseFromString(fileString, 'text/xml');
|
|
35
|
-
const event = yield EventImporterTCX.getFromXML(xmlDoc, undefined, file);
|
|
36
|
-
expect(event).toBeDefined();
|
|
37
|
-
expect(event.getActivities().length).toBeGreaterThan(0);
|
|
38
|
-
console.log(`✅ Successfully parsed ${file}`);
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
console.error(`❌ Failed to parse ${file}:`, error);
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}));
|
|
46
|
-
});
|
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
import { Event } from '../../../event';
|
|
2
|
-
import { Activity } from '../../../../activities/activity';
|
|
3
|
-
import { Creator } from '../../../../creators/creator';
|
|
4
|
-
import { Lap } from '../../../../laps/lap';
|
|
5
|
-
import { DataEnergy } from '../../../../data/data.energy';
|
|
6
|
-
import { DataDuration } from '../../../../data/data.duration';
|
|
7
|
-
import { DataDistance } from '../../../../data/data.distance';
|
|
8
|
-
import { DataPause } from '../../../../data/data.pause';
|
|
9
|
-
import { DataSpeedMax } from '../../../../data/data.speed-max';
|
|
10
|
-
import { DataHeartRateAvg } from '../../../../data/data.heart-rate-avg';
|
|
11
|
-
import { DataHeartRateMax } from '../../../../data/data.heart-rate-max';
|
|
12
|
-
import { ActivityTypes, ActivityTypesMoving } from '../../../../activities/activity.types';
|
|
13
|
-
import { DataSpeedAvg } from '../../../../data/data.speed-avg';
|
|
14
|
-
import { LapTypes } from '../../../../laps/lap.types';
|
|
15
|
-
import { ImporterSuuntoDeviceNames } from '../suunto/importer.suunto.device.names';
|
|
16
|
-
import { TCXSampleMapper } from './importer.tcx.mapper';
|
|
17
|
-
import { EventUtilities } from '../../../utilities/event.utilities';
|
|
18
|
-
import { convertSpeedToPace, isNumber } from '../../../utilities/helpers';
|
|
19
|
-
import { DataMovingTime } from '../../../../data/data.moving-time';
|
|
20
|
-
import { DataTimerTime } from '../../../../data/data.timer-time';
|
|
21
|
-
import { findLapExtensionValue, findTrackPointExtensionValue } from './utils.tcx';
|
|
22
|
-
import { DataTotalCycles } from '../../../../data/data-total-cycles';
|
|
23
|
-
import { DataPaceAvg } from '../../../../data/data.pace-avg';
|
|
24
|
-
import { ActivityUtilities } from '../../../utilities/activity.utilities';
|
|
25
|
-
import { DataPowerAvg } from '../../../../data/data.power-avg';
|
|
26
|
-
import { DataPowerMax } from '../../../../data/data.power-max';
|
|
27
|
-
import { DataCadenceAvg } from '../../../../data/data.cadence-avg';
|
|
28
|
-
import { DataActiveLap } from '../../../../data/data-active-lap';
|
|
29
|
-
import { DataSWOLF25m } from '../../../../data/data.swolf-25m';
|
|
30
|
-
import { DataSWOLF50m } from '../../../../data/data.swolf-50m';
|
|
31
|
-
import { FileType } from '../../file-type.enum';
|
|
32
|
-
import { DataCadence } from '../../../../data/data.cadence';
|
|
33
|
-
import { ActivityParsingOptions } from '../../../../activities/activity-parsing-options';
|
|
34
|
-
export class EventImporterTCX {
|
|
35
|
-
/**
|
|
36
|
-
* Returns active or rest state of a lap. This is pretty use-full on swim pool activities which are decomposed of many active or rest laps
|
|
37
|
-
*/
|
|
38
|
-
static isActiveLap(lapElement) {
|
|
39
|
-
const lapHasDistance = lapElement.getElementsByTagName('DistanceMeters').length > 0;
|
|
40
|
-
const lapHasMaxSpeed = lapElement.getElementsByTagName('MaximumSpeed').length > 0;
|
|
41
|
-
let lapDistance = 0;
|
|
42
|
-
let lapMaxSpeed = 0;
|
|
43
|
-
if (lapHasDistance) {
|
|
44
|
-
lapDistance = Number(lapElement.getElementsByTagName('DistanceMeters')[0].textContent);
|
|
45
|
-
}
|
|
46
|
-
if (lapHasMaxSpeed) {
|
|
47
|
-
lapMaxSpeed = Number(lapElement.getElementsByTagName('MaximumSpeed')[0].textContent);
|
|
48
|
-
}
|
|
49
|
-
return lapDistance > 0 || lapMaxSpeed > 0;
|
|
50
|
-
}
|
|
51
|
-
static getFromXML(xml, options = ActivityParsingOptions.DEFAULT, name = 'New Event') {
|
|
52
|
-
return new Promise((resolve, reject) => {
|
|
53
|
-
// Activities
|
|
54
|
-
const activities = Array.from(xml.getElementsByTagName('TrainingCenterDatabase')[0].getElementsByTagName('Activity')).map(activityElement => {
|
|
55
|
-
var _a;
|
|
56
|
-
// Getting activity type
|
|
57
|
-
const activityType = ActivityTypes[activityElement.getAttribute('Sport') || 'unknown'];
|
|
58
|
-
// TCX begins with laps, get them
|
|
59
|
-
const laps = this.getLaps(activityElement.getElementsByTagName('Lap'), activityType);
|
|
60
|
-
// Create activity
|
|
61
|
-
const startDate = new Date(activityElement.getElementsByTagName('Lap')[0].getAttribute('StartTime'));
|
|
62
|
-
const endDate = laps[laps.length - 1].endDate;
|
|
63
|
-
let activity = new Activity(startDate, endDate, activityType, this.getCreator(activityElement.getElementsByTagName('Creator')[0]), options);
|
|
64
|
-
// Extract activity stats from laps retrieved
|
|
65
|
-
activity = this.extractAndAssignActivityStatsFromLaps(laps, activity);
|
|
66
|
-
// Extract activity stats provided by the root tcx file
|
|
67
|
-
activity = this.extractAndAssignActivityStatsFromTcxRootDef(activityElement, activity);
|
|
68
|
-
// Creates a array of track points elements
|
|
69
|
-
let hasGpsData = false;
|
|
70
|
-
const trackPointElements = Array.from(activityElement.getElementsByTagName('Lap')).reduce((trackPointElementArray, lapElement) => {
|
|
71
|
-
Array.from(lapElement.getElementsByTagName('Trackpoint')).forEach(trackPointElement => {
|
|
72
|
-
trackPointElementArray.push(trackPointElement);
|
|
73
|
-
if (!hasGpsData) {
|
|
74
|
-
hasGpsData = !!trackPointElement.getElementsByTagName('Position')[0];
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
return trackPointElementArray;
|
|
78
|
-
}, []);
|
|
79
|
-
// Update activity type to indoor when no GPS data detected
|
|
80
|
-
activity = this.updateActivityTypeCaseIndoor(hasGpsData, activity);
|
|
81
|
-
if (!((_a = activity.getDistance()) === null || _a === void 0 ? void 0 : _a.getValue()) &&
|
|
82
|
-
trackPointElements.length &&
|
|
83
|
-
trackPointElements[trackPointElements.length - 1].getElementsByTagName('DistanceMeters')[0]) {
|
|
84
|
-
// If the distance from laps is 0 and there is a last track-point with distance use that
|
|
85
|
-
activity.setDistance(new DataDistance(Number(trackPointElements[trackPointElements.length - 1].getElementsByTagName('DistanceMeters')[0].textContent)));
|
|
86
|
-
}
|
|
87
|
-
// Setup sample info which could be use when getting sample values
|
|
88
|
-
const hasPowerMeter = trackPointElements.findIndex(trackPointElement => Number.isFinite(findTrackPointExtensionValue(trackPointElement.childNodes, 'Watts'))) !== -1;
|
|
89
|
-
const samplesInfo = { hasPowerMeter: hasPowerMeter };
|
|
90
|
-
TCXSampleMapper.forEach(sampleMapping => {
|
|
91
|
-
// Should check the children
|
|
92
|
-
const subjectTrackPointElements = trackPointElements.filter((element) => {
|
|
93
|
-
return isNumber(sampleMapping.getSampleValue(element, samplesInfo));
|
|
94
|
-
});
|
|
95
|
-
if (subjectTrackPointElements.length) {
|
|
96
|
-
if (activity.hasStreamData(sampleMapping.dataType)) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
activity.addStream(activity.createStream(sampleMapping.dataType));
|
|
100
|
-
subjectTrackPointElements.forEach((subjectTrackPointElement) => {
|
|
101
|
-
activity.addDataToStream(sampleMapping.dataType, new Date(subjectTrackPointElement.getElementsByTagName('Time')[0].textContent), sampleMapping.getSampleValue(subjectTrackPointElement, samplesInfo));
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
return activity;
|
|
106
|
-
});
|
|
107
|
-
// Init the event
|
|
108
|
-
const event = new Event(name, activities[0].startDate, activities[activities.length - 1].endDate, FileType.TCX);
|
|
109
|
-
activities.forEach(activity => event.addActivity(activity));
|
|
110
|
-
EventUtilities.generateStatsForAll(event);
|
|
111
|
-
resolve(event);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
static updateActivityTypeCaseIndoor(hasGpsData, activity) {
|
|
115
|
-
if (!hasGpsData) {
|
|
116
|
-
switch (activity.type) {
|
|
117
|
-
case ActivityTypes.Running:
|
|
118
|
-
activity.type = ActivityTypes.IndoorRunning;
|
|
119
|
-
break;
|
|
120
|
-
case ActivityTypes.Cycling:
|
|
121
|
-
activity.type = ActivityTypes.IndoorCycling;
|
|
122
|
-
break;
|
|
123
|
-
case ActivityTypes.Rowing:
|
|
124
|
-
activity.type = ActivityTypes.IndoorRowing;
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return activity;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Extract activity stats from laps retrieved
|
|
132
|
-
*/
|
|
133
|
-
static extractAndAssignActivityStatsFromLaps(laps, activity) {
|
|
134
|
-
// Go over the laps and start filling up the stats and creating the points
|
|
135
|
-
laps.forEach((lap) => {
|
|
136
|
-
var _a, _b, _c, _d, _e, _f;
|
|
137
|
-
if (lap.getDuration().getValue() === 0) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// Append duration to whole activity
|
|
141
|
-
if (((_a = lap.getDuration()) === null || _a === void 0 ? void 0 : _a.getValue()) > 0) {
|
|
142
|
-
if (!activity.getDuration()) {
|
|
143
|
-
activity.setDuration(new DataDuration(0));
|
|
144
|
-
}
|
|
145
|
-
activity.getDuration().setValue(activity.getDuration().getValue() + lap.getDuration().getValue());
|
|
146
|
-
}
|
|
147
|
-
// Append timer time to whole activity
|
|
148
|
-
if (((_b = lap.getTimer()) === null || _b === void 0 ? void 0 : _b.getValue()) > 0) {
|
|
149
|
-
if (!activity.getTimer()) {
|
|
150
|
-
activity.setTimer(new DataTimerTime(0));
|
|
151
|
-
}
|
|
152
|
-
activity.getTimer().setValue(activity.getTimer().getValue() + lap.getTimer().getValue());
|
|
153
|
-
}
|
|
154
|
-
// Append moving time to whole activity
|
|
155
|
-
if (((_c = lap.getMovingTime()) === null || _c === void 0 ? void 0 : _c.getValue()) > 0) {
|
|
156
|
-
if (!activity.getMovingTime()) {
|
|
157
|
-
activity.setMovingTime(new DataMovingTime(0));
|
|
158
|
-
}
|
|
159
|
-
activity.getMovingTime().setValue(activity.getMovingTime().getValue() + lap.getMovingTime().getValue());
|
|
160
|
-
}
|
|
161
|
-
// Append pause time to whole activity
|
|
162
|
-
if (((_d = lap.getPause()) === null || _d === void 0 ? void 0 : _d.getValue()) > 0) {
|
|
163
|
-
if (!activity.getPause()) {
|
|
164
|
-
activity.setPause(new DataPause(0));
|
|
165
|
-
}
|
|
166
|
-
activity.getPause().setValue(activity.getPause().getValue() + lap.getPause().getValue());
|
|
167
|
-
}
|
|
168
|
-
// Append distance to whole activity
|
|
169
|
-
if (((_e = lap.getDistance()) === null || _e === void 0 ? void 0 : _e.getValue()) > 0) {
|
|
170
|
-
if (!activity.getDistance()) {
|
|
171
|
-
activity.setDistance(new DataDistance(0));
|
|
172
|
-
}
|
|
173
|
-
activity.getDistance().setValue(activity.getDistance().getValue() + lap.getDistance().getValue());
|
|
174
|
-
}
|
|
175
|
-
// Append energy to whole activity
|
|
176
|
-
if (((_f = lap.getStat(DataEnergy.type)) === null || _f === void 0 ? void 0 : _f.getValue()) > 0) {
|
|
177
|
-
if (!activity.getStat(DataEnergy.type)) {
|
|
178
|
-
activity.addStat(new DataEnergy(0));
|
|
179
|
-
}
|
|
180
|
-
activity.addStat(new DataEnergy(activity.getStat(DataEnergy.type).getValue() +
|
|
181
|
-
lap.getStat(DataEnergy.type).getValue()));
|
|
182
|
-
}
|
|
183
|
-
activity.addLap(lap);
|
|
184
|
-
});
|
|
185
|
-
// Looping on laps to assign stats to activity
|
|
186
|
-
if (laps === null || laps === void 0 ? void 0 : laps.length) {
|
|
187
|
-
// Getting avg speed/pace from laps:
|
|
188
|
-
const lapAvgSpeeds = laps
|
|
189
|
-
.filter(lap => { var _a; return ((_a = lap.getStat(DataSpeedAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue()) >= 0; })
|
|
190
|
-
.map(lap => { var _a; return (_a = lap.getStat(DataSpeedAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue(); });
|
|
191
|
-
if (lapAvgSpeeds.length) {
|
|
192
|
-
const avgSpeed = ActivityUtilities.getAverage(lapAvgSpeeds);
|
|
193
|
-
if (avgSpeed > 0) {
|
|
194
|
-
activity.addStat(new DataSpeedAvg(avgSpeed));
|
|
195
|
-
activity.addStat(new DataPaceAvg(convertSpeedToPace(avgSpeed)));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Cycles
|
|
199
|
-
const lapTotalsCycles = laps
|
|
200
|
-
.map(lap => { var _a; return ((_a = lap.getStat(DataTotalCycles.type)) === null || _a === void 0 ? void 0 : _a.getValue()) || 0; })
|
|
201
|
-
.filter(count => count > 0);
|
|
202
|
-
if (lapTotalsCycles.length) {
|
|
203
|
-
const lapTotalCycles = ActivityUtilities.getSum(lapTotalsCycles);
|
|
204
|
-
if (lapTotalCycles > 0) {
|
|
205
|
-
activity.addStat(new DataTotalCycles(lapTotalCycles));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
// Avg cadence
|
|
209
|
-
const lapDataCadenceAverages = laps
|
|
210
|
-
.map(lap => { var _a; return ((_a = lap.getStat(DataCadenceAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue()) || 0; })
|
|
211
|
-
.filter(cad => cad > 0);
|
|
212
|
-
if (lapDataCadenceAverages.length) {
|
|
213
|
-
const dataCadenceAvg = ActivityUtilities.getAverage(lapDataCadenceAverages);
|
|
214
|
-
if (dataCadenceAvg > 0) {
|
|
215
|
-
activity.addStat(new DataCadenceAvg(Math.round(dataCadenceAvg)));
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return activity;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Extract activity stats provided by the root tcx file
|
|
223
|
-
*/
|
|
224
|
-
static extractAndAssignActivityStatsFromTcxRootDef(activityElement, activity) {
|
|
225
|
-
var _a, _b;
|
|
226
|
-
if (!(((_a = activity.getStat(DataEnergy.type)) === null || _a === void 0 ? void 0 : _a.getValue()) > 0) &&
|
|
227
|
-
activityElement.getElementsByTagName('Calories')[0]) {
|
|
228
|
-
const calories = Number(activityElement.getElementsByTagName('Calories')[0].textContent);
|
|
229
|
-
if (calories > 0) {
|
|
230
|
-
activity.addStat(new DataEnergy(calories));
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (!(((_b = activity.getStat(DataDistance.type)) === null || _b === void 0 ? void 0 : _b.getValue()) > 0) &&
|
|
234
|
-
activityElement.getElementsByTagName('DistanceMeters')[0]) {
|
|
235
|
-
activity.addStat(new DataDistance(Number(activityElement.getElementsByTagName('DistanceMeters')[0].textContent)));
|
|
236
|
-
}
|
|
237
|
-
if (activityElement.getElementsByTagName('MaximumSpeed')[0]) {
|
|
238
|
-
activity.addStat(new DataSpeedMax(Number(activityElement.getElementsByTagName('MaximumSpeed')[0].textContent)));
|
|
239
|
-
}
|
|
240
|
-
return activity;
|
|
241
|
-
}
|
|
242
|
-
static getCreator(creatorElement) {
|
|
243
|
-
const creator = new Creator('Unknown Device');
|
|
244
|
-
if (!creatorElement) {
|
|
245
|
-
return creator;
|
|
246
|
-
}
|
|
247
|
-
// Try to see if its a listed Suunto Device name
|
|
248
|
-
if (creatorElement.getElementsByTagName('Name')[0]) {
|
|
249
|
-
creator.name =
|
|
250
|
-
ImporterSuuntoDeviceNames[creatorElement.getElementsByTagName('Name')[0].textContent] ||
|
|
251
|
-
creatorElement.getElementsByTagName('Name')[0].textContent ||
|
|
252
|
-
creator.name;
|
|
253
|
-
}
|
|
254
|
-
if (creatorElement.getElementsByTagName('Version')[0]) {
|
|
255
|
-
creator.swInfo = creatorElement.getElementsByTagName('Version')[0].textContent;
|
|
256
|
-
}
|
|
257
|
-
return creator;
|
|
258
|
-
}
|
|
259
|
-
static getLaps(lapElements, activityType) {
|
|
260
|
-
return Array.from(lapElements).reduce((lapArray, lapElement, lapIndex) => {
|
|
261
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
262
|
-
// Calculating lap time data (moving time, timer time, elapsed time...)
|
|
263
|
-
const speedThreshold = ActivityTypesMoving.getSpeedThreshold(activityType);
|
|
264
|
-
let movingTime = 0;
|
|
265
|
-
let elapsedTime = 0;
|
|
266
|
-
const timerTime = lapElement.getElementsByTagName('TotalTimeSeconds').length
|
|
267
|
-
? Number(lapElement.getElementsByTagName('TotalTimeSeconds')[0].textContent)
|
|
268
|
-
: 0;
|
|
269
|
-
// Loop on track-points to detect moving speed
|
|
270
|
-
const trackSpeeds = [];
|
|
271
|
-
const trackElements = Array.from(lapElement.getElementsByTagName('Track'));
|
|
272
|
-
trackElements.forEach(trackElement => {
|
|
273
|
-
var _a;
|
|
274
|
-
const trackPointsElements = Array.from(trackElement.getElementsByTagName('Trackpoint'));
|
|
275
|
-
if (!(trackPointsElements === null || trackPointsElements === void 0 ? void 0 : trackPointsElements.length)) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
// Setting lap elapsed time from first and last track point
|
|
279
|
-
const firstTrackPoint = trackPointsElements[0];
|
|
280
|
-
const lastTrackPoint = trackPointsElements[trackPointsElements.length - 1];
|
|
281
|
-
// Assign elapsed time if time available on first and last point
|
|
282
|
-
if ((_a = lastTrackPoint === null || lastTrackPoint === void 0 ? void 0 : lastTrackPoint.getElementsByTagName('Time')) === null || _a === void 0 ? void 0 : _a.length) {
|
|
283
|
-
elapsedTime =
|
|
284
|
-
(new Date(lastTrackPoint.getElementsByTagName('Time')[0].textContent).getTime() -
|
|
285
|
-
new Date(firstTrackPoint.getElementsByTagName('Time')[0].textContent).getTime()) /
|
|
286
|
-
1000;
|
|
287
|
-
}
|
|
288
|
-
// Parsing each track points to determine moving speed
|
|
289
|
-
trackPointsElements.forEach((trackPointElement, index) => {
|
|
290
|
-
// Skipping first record to be able to get delta with previous one
|
|
291
|
-
if (index === 0) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
// Getting current time of track point
|
|
295
|
-
const currentTime = new Date(trackPointElement.getElementsByTagName('Time')[0].textContent).getTime();
|
|
296
|
-
const previousTime = new Date(trackPointsElements[index - 1].getElementsByTagName('Time')[0].textContent).getTime();
|
|
297
|
-
const seconds = (currentTime - previousTime) / 1000;
|
|
298
|
-
let speed = findTrackPointExtensionValue(trackPointElement.childNodes, 'Speed');
|
|
299
|
-
// Try to get m/s using delta distance if speed extension is missing
|
|
300
|
-
if (speed === null) {
|
|
301
|
-
// If distance available on track point, then compute speed with it
|
|
302
|
-
if (trackPointElement.getElementsByTagName('DistanceMeters').length &&
|
|
303
|
-
trackPointsElements[index - 1].getElementsByTagName('DistanceMeters').length) {
|
|
304
|
-
const currentDistance = Number(trackPointElement.getElementsByTagName('DistanceMeters')[0].textContent);
|
|
305
|
-
const previousDistance = Number(trackPointsElements[index - 1].getElementsByTagName('DistanceMeters')[0].textContent);
|
|
306
|
-
const meters = currentDistance - previousDistance;
|
|
307
|
-
speed = meters / seconds;
|
|
308
|
-
trackSpeeds.push(speed);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
trackSpeeds.push(speed);
|
|
313
|
-
}
|
|
314
|
-
// We track moving time only if speed available on track points and upper than threshold
|
|
315
|
-
if (speed !== null && speed > speedThreshold) {
|
|
316
|
-
movingTime += seconds;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
// Active or rest lap?
|
|
321
|
-
const isActiveLap = this.isActiveLap(lapElement);
|
|
322
|
-
// If no moving time detected, try to detect from active laps
|
|
323
|
-
if (movingTime === 0) {
|
|
324
|
-
// Lap is considered as active. Track moving time..
|
|
325
|
-
if (isActiveLap) {
|
|
326
|
-
movingTime = timerTime;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
// If elapsed time not defined or lower than timer time then use timer time as elapsed time
|
|
330
|
-
if (!elapsedTime || timerTime > elapsedTime) {
|
|
331
|
-
elapsedTime = timerTime;
|
|
332
|
-
}
|
|
333
|
-
// Now creating the lap
|
|
334
|
-
const startDate = new Date(lapElement.getAttribute('StartTime'));
|
|
335
|
-
const endDate = new Date(startDate);
|
|
336
|
-
endDate.setSeconds(endDate.getSeconds() + elapsedTime);
|
|
337
|
-
const lap = new Lap(startDate, endDate, lapIndex + 1, LapTypes.AutoLap);
|
|
338
|
-
// Add elapsed & timer stats to lap
|
|
339
|
-
lap.addStat(new DataDuration(elapsedTime));
|
|
340
|
-
lap.addStat(new DataTimerTime(Math.round(timerTime * 10) / 10));
|
|
341
|
-
// Append moving stat only if moving time has been detected
|
|
342
|
-
// We need that to compute total global moving time later
|
|
343
|
-
if (movingTime > 0) {
|
|
344
|
-
lap.addStat(new DataMovingTime(Math.round(movingTime * 10) / 10));
|
|
345
|
-
}
|
|
346
|
-
// Pause TIME on Object (activity, lap...)
|
|
347
|
-
const pause = elapsedTime > movingTime ? Math.round((elapsedTime - movingTime) * 100) / 100 : 0;
|
|
348
|
-
lap.setPause(new DataPause(pause));
|
|
349
|
-
// Assign is active lap status
|
|
350
|
-
lap.addStat(new DataActiveLap(isActiveLap));
|
|
351
|
-
if (lapElement.getElementsByTagName('TriggerMethod')[0]) {
|
|
352
|
-
lap.type = LapTypes[lapElement.getElementsByTagName('TriggerMethod')[0].textContent];
|
|
353
|
-
}
|
|
354
|
-
if (lapElement.getElementsByTagName('Calories')[0]) {
|
|
355
|
-
lap.addStat(new DataEnergy(Number(lapElement.getElementsByTagName('Calories')[0].textContent)));
|
|
356
|
-
}
|
|
357
|
-
// Create a stats (required TCX fields)
|
|
358
|
-
lap.addStat(new DataDistance(0));
|
|
359
|
-
if (lapElement.getElementsByTagName('DistanceMeters')[0]) {
|
|
360
|
-
lap.addStat(new DataDistance(Number(lapElement.getElementsByTagName('DistanceMeters')[0].textContent)));
|
|
361
|
-
}
|
|
362
|
-
// Optionals
|
|
363
|
-
if (trackSpeeds.length) {
|
|
364
|
-
const maxSpeed = ActivityUtilities.getMax(trackSpeeds);
|
|
365
|
-
lap.addStat(new DataSpeedMax(maxSpeed));
|
|
366
|
-
}
|
|
367
|
-
else if (lapElement.getElementsByTagName('MaximumSpeed')[0]) {
|
|
368
|
-
const maxSpeed = Number(lapElement.getElementsByTagName('MaximumSpeed')[0].textContent);
|
|
369
|
-
lap.addStat(new DataSpeedMax(maxSpeed));
|
|
370
|
-
}
|
|
371
|
-
if (lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) {
|
|
372
|
-
const value = ((_b = (_a = lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) === null || _a === void 0 ? void 0 : _a.getElementsByTagName('Value')[0]) === null || _b === void 0 ? void 0 : _b.textContent) ||
|
|
373
|
-
((_c = lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) === null || _c === void 0 ? void 0 : _c.textContent);
|
|
374
|
-
if (value) {
|
|
375
|
-
lap.addStat(new DataHeartRateAvg(Number(value)));
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
if (lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) {
|
|
379
|
-
const value = ((_e = (_d = lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) === null || _d === void 0 ? void 0 : _d.getElementsByTagName('Value')[0]) === null || _e === void 0 ? void 0 : _e.textContent) ||
|
|
380
|
-
((_f = lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) === null || _f === void 0 ? void 0 : _f.textContent);
|
|
381
|
-
if (value) {
|
|
382
|
-
lap.addStat(new DataHeartRateMax(Number(value)));
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
if (lapElement.getElementsByTagName('Cadence')[0]) {
|
|
386
|
-
lap.addStat(new DataCadence(Number(lapElement.getElementsByTagName('Cadence')[0].textContent)));
|
|
387
|
-
}
|
|
388
|
-
// Fetching activity lap speed from records or from extensions if exists according https://www8.garmin.com/xmlschemas/ActivityExtensionv2.xsd schema
|
|
389
|
-
const lapAvgSpeed = trackSpeeds.length
|
|
390
|
-
? ActivityUtilities.getAverage(trackSpeeds)
|
|
391
|
-
: findLapExtensionValue(lapElement.childNodes, 'AvgSpeed');
|
|
392
|
-
if (lapAvgSpeed !== null) {
|
|
393
|
-
lap.addStat(new DataSpeedAvg(lapAvgSpeed));
|
|
394
|
-
lap.addStat(new DataPaceAvg(convertSpeedToPace(lapAvgSpeed)));
|
|
395
|
-
}
|
|
396
|
-
// Cycles
|
|
397
|
-
const lapTotalCycle = findLapExtensionValue(lapElement.childNodes, 'Steps');
|
|
398
|
-
if (lapTotalCycle !== null) {
|
|
399
|
-
lap.addStat(new DataTotalCycles(lapTotalCycle));
|
|
400
|
-
}
|
|
401
|
-
// Avg Watts
|
|
402
|
-
const lapAvgWatts = findLapExtensionValue(lapElement.childNodes, 'AvgWatts');
|
|
403
|
-
if (lapAvgWatts !== null) {
|
|
404
|
-
lap.addStat(new DataPowerAvg(lapAvgWatts));
|
|
405
|
-
}
|
|
406
|
-
// Max Watts
|
|
407
|
-
const lapMaxWatts = findLapExtensionValue(lapElement.childNodes, 'MaxWatts');
|
|
408
|
-
if (lapMaxWatts !== null) {
|
|
409
|
-
lap.addStat(new DataPowerMax(lapMaxWatts));
|
|
410
|
-
}
|
|
411
|
-
// AvgRunCadence
|
|
412
|
-
const lapAvgRunCadence = findLapExtensionValue(lapElement.childNodes, 'AvgRunCadence');
|
|
413
|
-
if (lapAvgRunCadence !== null) {
|
|
414
|
-
lap.addStat(new DataCadenceAvg(lapAvgRunCadence));
|
|
415
|
-
}
|
|
416
|
-
// Try to set avg cadence from total cycle if not set on swimming activities only
|
|
417
|
-
if (isActiveLap &&
|
|
418
|
-
(activityType === ActivityTypes.Swimming || activityType === ActivityTypes.OpenWaterSwimming) &&
|
|
419
|
-
!((_g = lap.getStat(DataCadenceAvg.type)) === null || _g === void 0 ? void 0 : _g.getValue()) &&
|
|
420
|
-
timerTime &&
|
|
421
|
-
lapTotalCycle) {
|
|
422
|
-
const lapAvgCadence = Math.round((lapTotalCycle / timerTime) * 60);
|
|
423
|
-
lap.addStat(new DataCadenceAvg(lapAvgCadence));
|
|
424
|
-
}
|
|
425
|
-
// Average SWOLF in 25m and 50m pool
|
|
426
|
-
if (isActiveLap &&
|
|
427
|
-
(activityType === ActivityTypes.Swimming || activityType === ActivityTypes.OpenWaterSwimming) &&
|
|
428
|
-
((_h = lap.getStat(DataCadenceAvg.type)) === null || _h === void 0 ? void 0 : _h.getValue()) > 0 &&
|
|
429
|
-
((_j = lap.getStat(DataSpeedAvg.type)) === null || _j === void 0 ? void 0 : _j.getValue()) > 0) {
|
|
430
|
-
const avgCadence = lap.getStat(DataCadenceAvg.type).getValue();
|
|
431
|
-
const avgSpeed = lap.getStat(DataSpeedAvg.type).getValue();
|
|
432
|
-
const avgPace100m = 100 / avgSpeed;
|
|
433
|
-
const swolf25m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 25);
|
|
434
|
-
lap.addStat(new DataSWOLF25m(swolf25m));
|
|
435
|
-
const swolf50m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 50);
|
|
436
|
-
lap.addStat(new DataSWOLF50m(swolf50m));
|
|
437
|
-
}
|
|
438
|
-
lapArray.push(lap);
|
|
439
|
-
return lapArray;
|
|
440
|
-
}, []);
|
|
441
|
-
}
|
|
442
|
-
}
|