@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,373 +0,0 @@
|
|
|
1
|
-
import { Event } from '../event';
|
|
2
|
-
import { DataSpeedMaxKilometersPerHour } from '../../data/data.speed-max';
|
|
3
|
-
import { Activity } from '../../activities/activity';
|
|
4
|
-
import { ActivityParsingOptions } from '../../activities/activity-parsing-options';
|
|
5
|
-
import { DataHeartRate } from '../../data/data.heart-rate';
|
|
6
|
-
import { DataAltitude } from '../../data/data.altitude';
|
|
7
|
-
import { DataDistance, DataDistanceMiles } from '../../data/data.distance';
|
|
8
|
-
import { DataDuration } from '../../data/data.duration';
|
|
9
|
-
import { Creator } from '../../creators/creator';
|
|
10
|
-
import { ActivityTypes } from '../../activities/activity.types';
|
|
11
|
-
import { Stream } from '../../streams/stream';
|
|
12
|
-
import { ActivityUtilities } from './activity.utilities';
|
|
13
|
-
import { DataSpeed } from '../../data/data.speed';
|
|
14
|
-
import { Lap } from '../../laps/lap';
|
|
15
|
-
import { DataSpeedAvg } from '../../data/data.speed-avg';
|
|
16
|
-
import { LapTypes } from '../../laps/lap.types';
|
|
17
|
-
import { DataTime } from '../../data/data.time';
|
|
18
|
-
import { FileType } from '../adapters/file-type.enum';
|
|
19
|
-
import { EventImporterJSON } from '../adapters/importers/json/importer.json';
|
|
20
|
-
import { DataPace, DataPaceMinutesPerMile } from '../../data/data.pace';
|
|
21
|
-
import { DataSpeedKilometersPerHour } from '../../data/data.speed';
|
|
22
|
-
import { DataSwimPace } from '../../data/data.swim-pace';
|
|
23
|
-
describe('Activity Utilities', () => {
|
|
24
|
-
let event;
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
event = new Event('New name', new Date(0), new Date(200), FileType.FIT);
|
|
27
|
-
const activity = new Activity(new Date(0), new Date(new Date(0).getTime() + 10000), ActivityTypes.Running, new Creator('Test'));
|
|
28
|
-
activity.setDuration(new DataDuration(10));
|
|
29
|
-
activity.setDistance(new DataDistance(10));
|
|
30
|
-
event.addActivity(activity);
|
|
31
|
-
});
|
|
32
|
-
it('should get the correct minimum for a DataType', () => {
|
|
33
|
-
event.getFirstActivity().addStream(new Stream(DataHeartRate.type, [0, 50, 100]));
|
|
34
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
35
|
-
expect(ActivityUtilities.getDataTypeMin(event.getFirstActivity(), DataHeartRate.type)).toBe(0);
|
|
36
|
-
expect(ActivityUtilities.getDataTypeMin(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
37
|
-
});
|
|
38
|
-
it('should get the correct maximum for a DataType', () => {
|
|
39
|
-
event.getFirstActivity().addStream(new Stream(DataHeartRate.type, [0, 50, 100]));
|
|
40
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
41
|
-
expect(ActivityUtilities.getDataTypeMax(event.getFirstActivity(), DataHeartRate.type)).toBe(100);
|
|
42
|
-
expect(ActivityUtilities.getDataTypeMax(event.getFirstActivity(), DataAltitude.type)).toBe(400);
|
|
43
|
-
});
|
|
44
|
-
it('should get the correct difference for a DataType', () => {
|
|
45
|
-
event.getFirstActivity().addStream(new Stream(DataHeartRate.type, [0, 50, 100]));
|
|
46
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
47
|
-
expect(ActivityUtilities.getDataTypeMinToMaxDifference(event.getFirstActivity(), DataHeartRate.type)).toBe(100);
|
|
48
|
-
expect(ActivityUtilities.getDataTypeMinToMaxDifference(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
49
|
-
});
|
|
50
|
-
it('should get the correct average for a DataType', () => {
|
|
51
|
-
event.getFirstActivity().addStream(new Stream(DataHeartRate.type, [0, 50, 100]));
|
|
52
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
53
|
-
expect(ActivityUtilities.getDataTypeAvg(event.getFirstActivity(), DataHeartRate.type)).toBe(50);
|
|
54
|
-
expect(ActivityUtilities.getDataTypeAvg(event.getFirstActivity(), DataAltitude.type)).toBe(300);
|
|
55
|
-
});
|
|
56
|
-
it('should get the correct gain for a DataType', () => {
|
|
57
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
58
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
59
|
-
// Add more altitude data but this time descending so it would not affect the gain
|
|
60
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(400);
|
|
61
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(300);
|
|
62
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(200);
|
|
63
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
64
|
-
// Add more for gain
|
|
65
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(400); // Gain 400 (from prev)
|
|
66
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(300);
|
|
67
|
-
// Gain 400
|
|
68
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(400); // Gain 500
|
|
69
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type)).toBe(500);
|
|
70
|
-
});
|
|
71
|
-
it('should get the correct gain for a DataType with a changed min difference', () => {
|
|
72
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, 400]));
|
|
73
|
-
// With a diff of 100,200 the gain should be included
|
|
74
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 100)).toBe(200);
|
|
75
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 200)).toBe(200);
|
|
76
|
-
// with a diff of 201 it shouldn't
|
|
77
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 201)).toBe(0);
|
|
78
|
-
// Add more
|
|
79
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(100);
|
|
80
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(101);
|
|
81
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(102);
|
|
82
|
-
// Up to now we have 200m, 300m, 400m, 100m, 101m, 102m
|
|
83
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 100)).toBe(200);
|
|
84
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 200)).toBe(200);
|
|
85
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 300)).toBe(0);
|
|
86
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 1)).toBe(202);
|
|
87
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 2)).toBe(202);
|
|
88
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 3)).toBe(200);
|
|
89
|
-
});
|
|
90
|
-
it('should get the correct gain for a DataType with a set of points of non data', () => {
|
|
91
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [100, 300, 200, 400]));
|
|
92
|
-
expect(ActivityUtilities.getActivityDataTypeGain(event.getFirstActivity(), DataAltitude.type)).toBe(400);
|
|
93
|
-
});
|
|
94
|
-
it('should get the correct loss for a DataType', () => {
|
|
95
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [400, 300, 200]));
|
|
96
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
97
|
-
// Add more altitude data but this time ascenting so it would not affect the Loss
|
|
98
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(200); // Loss 0
|
|
99
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(300); // Loss 0
|
|
100
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(400); // Loss 0
|
|
101
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type)).toBe(200);
|
|
102
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(200); // loss 200
|
|
103
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(300); // loss 0
|
|
104
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(200); // Gain 100 a total (see above of 500)
|
|
105
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type)).toBe(500);
|
|
106
|
-
});
|
|
107
|
-
it('should get the correct loss for a DataType with a changed min difference', () => {
|
|
108
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [400, 300, 200]));
|
|
109
|
-
// With a diff of 100,200 the gain should be included
|
|
110
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 100)).toBe(200);
|
|
111
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 200)).toBe(200);
|
|
112
|
-
// with a diff of 201 it shouldn't
|
|
113
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 201)).toBe(0);
|
|
114
|
-
// Add more
|
|
115
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(500);
|
|
116
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(499);
|
|
117
|
-
event.getFirstActivity().getStreamData(DataAltitude.type).push(498);
|
|
118
|
-
// 200m, 300m, 400m, 100m, 101m, 102m
|
|
119
|
-
// Up to now we have 400m, 300m, 200m, 500m, 499m, 498m
|
|
120
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 100)).toBe(200);
|
|
121
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 200)).toBe(200);
|
|
122
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 300)).toBe(0);
|
|
123
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 1)).toBe(202);
|
|
124
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 2)).toBe(202);
|
|
125
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type, void 0, void 0, 3)).toBe(200);
|
|
126
|
-
});
|
|
127
|
-
it('should get the correct loss for a DataType with a set of points of non data', () => {
|
|
128
|
-
event
|
|
129
|
-
.getFirstActivity()
|
|
130
|
-
.getAllStreams()
|
|
131
|
-
.push(new Stream(DataAltitude.type, [400, 200, 300, 100]) // loos 0, 200, 0, 400
|
|
132
|
-
);
|
|
133
|
-
expect(ActivityUtilities.getActivityDataTypeLoss(event.getFirstActivity(), DataAltitude.type)).toBe(400);
|
|
134
|
-
});
|
|
135
|
-
it('should get the correct data length', () => {
|
|
136
|
-
const activity = event.getFirstActivity(); // 10s
|
|
137
|
-
// 10 seconds = 11 slugs; from second 1 eg
|
|
138
|
-
// [1,2,3,4,5,6,7,8,9,10] ->
|
|
139
|
-
// [0, 1, 2,3,4,5,6,7,8,9,10]
|
|
140
|
-
expect(ActivityUtilities.getDataLength(activity.startDate, activity.endDate)).toBe(11);
|
|
141
|
-
// Change start / end date to <1s
|
|
142
|
-
activity.startDate = new Date(0);
|
|
143
|
-
activity.endDate = new Date(50); // 50ms
|
|
144
|
-
// More than 0 = 1 slug
|
|
145
|
-
expect(ActivityUtilities.getDataLength(activity.startDate, activity.endDate)).toBe(2);
|
|
146
|
-
// Change start / end date to >9999ms and <100000s
|
|
147
|
-
activity.startDate = new Date(0);
|
|
148
|
-
activity.endDate = new Date(9999); // 9.9 seconds
|
|
149
|
-
// more than 9 is 10 slugs
|
|
150
|
-
expect(ActivityUtilities.getDataLength(activity.startDate, activity.endDate)).toBe(11);
|
|
151
|
-
});
|
|
152
|
-
it('should provide serialization/deserialization through toJSON', () => {
|
|
153
|
-
var _a, _b;
|
|
154
|
-
// Given
|
|
155
|
-
const activity = event.getFirstActivity();
|
|
156
|
-
activity.startDate = new Date();
|
|
157
|
-
activity.endDate = new Date(activity.startDate.getTime() + 3000);
|
|
158
|
-
event.getFirstActivity().addStream(new Stream(DataDistance.type, [0, 9, null, 30]));
|
|
159
|
-
event.getFirstActivity().addStream(new Stream(DataSpeed.type, [0, 10, null, 15]));
|
|
160
|
-
event.getFirstActivity().addStream(new Stream(DataHeartRate.type, [0, 50, null, 100]));
|
|
161
|
-
event.getFirstActivity().addStream(new Stream(DataAltitude.type, [200, 300, null, 400]));
|
|
162
|
-
const lap1 = new Lap(activity.startDate, activity.endDate, 1, LapTypes.Autolap);
|
|
163
|
-
lap1.addStat(new DataSpeedAvg(10));
|
|
164
|
-
activity.addLap(lap1);
|
|
165
|
-
const lap2 = new Lap(activity.startDate, activity.endDate, 2, LapTypes.Autolap);
|
|
166
|
-
lap2.addStat(new DataSpeedAvg(15));
|
|
167
|
-
activity.addLap(lap2);
|
|
168
|
-
// When serialize
|
|
169
|
-
const activitySerialized = activity.toJSON();
|
|
170
|
-
// Then
|
|
171
|
-
expect(activitySerialized.name).toBeNull();
|
|
172
|
-
expect(activitySerialized.startDate).toEqual(activity.startDate.getTime());
|
|
173
|
-
expect(activitySerialized.endDate).toEqual(activity.endDate.getTime());
|
|
174
|
-
expect(activitySerialized.powerMeter).toBeFalsy();
|
|
175
|
-
expect(activitySerialized.trainer).toBeFalsy();
|
|
176
|
-
expect(activitySerialized.laps.length).toEqual(activity.getLaps().length);
|
|
177
|
-
expect(activitySerialized.laps[0].startIndex).toEqual(0);
|
|
178
|
-
expect(activitySerialized.laps[0].endIndex).toEqual(3);
|
|
179
|
-
expect(activitySerialized.laps[0].stats[DataSpeedAvg.type]).toEqual(activity.getLaps()[0].getStat(DataSpeedAvg.type).getValue());
|
|
180
|
-
expect(activitySerialized.streams.length).toEqual(activity.getAllStreams().length + 1); // +1 because we add time stream
|
|
181
|
-
expect((_a = activitySerialized.streams.find(s => s.type == DataTime.type)) === null || _a === void 0 ? void 0 : _a.data.length).toEqual((_b = activitySerialized.streams.find(s => s.type == DataDistance.type)) === null || _b === void 0 ? void 0 : _b.data.length);
|
|
182
|
-
// When deserialize
|
|
183
|
-
const activityDeserialized = EventImporterJSON.getActivityFromJSON(activitySerialized);
|
|
184
|
-
// Then
|
|
185
|
-
expect(activityDeserialized.startDate).toEqual(activity.startDate);
|
|
186
|
-
expect(activityDeserialized.endDate).toEqual(activity.endDate);
|
|
187
|
-
expect(activityDeserialized.hasPowerMeter()).toEqual(activity.hasPowerMeter());
|
|
188
|
-
expect(activityDeserialized.getLaps().length).toEqual(activity.getLaps().length);
|
|
189
|
-
expect(activityDeserialized.getLaps()[0].getStat(DataSpeedAvg.type).getValue()).toEqual(activity.getLaps()[0].getStat(DataSpeedAvg.type).getValue());
|
|
190
|
-
expect(activityDeserialized.getStream(DataDistance.type).getData().length).toEqual(activity.getStream(DataDistance.type).getData().length);
|
|
191
|
-
expect(activityDeserialized.getStream(DataDistance.type)).toEqual(activity.getStream(DataDistance.type));
|
|
192
|
-
expect(activityDeserialized.getStream(DataSpeed.type)).toEqual(activity.getStream(DataSpeed.type));
|
|
193
|
-
expect(activityDeserialized.getStream(DataHeartRate.type)).toEqual(activity.getStream(DataHeartRate.type));
|
|
194
|
-
expect(activityDeserialized.getStream(DataAltitude.type)).toEqual(activity.getStream(DataAltitude.type));
|
|
195
|
-
expect(activityDeserialized.hasStreamData(DataTime.type)).toBeFalsy();
|
|
196
|
-
});
|
|
197
|
-
describe('Fill streams', () => {
|
|
198
|
-
const createFakeActivityWithStreams = (lengthInSeconds, streams) => {
|
|
199
|
-
const startDate = new Date();
|
|
200
|
-
const endDate = new Date(startDate.getTime() + lengthInSeconds * 1000);
|
|
201
|
-
const activity = new Activity(startDate, endDate, ActivityTypes.Running, new Creator('creator'));
|
|
202
|
-
streams.forEach(stream => {
|
|
203
|
-
activity.addStream(new Stream(stream.type).setData(stream.data));
|
|
204
|
-
});
|
|
205
|
-
return activity;
|
|
206
|
-
};
|
|
207
|
-
it('should add missing data to streams (1)', done => {
|
|
208
|
-
// Given
|
|
209
|
-
const timeData = [0, 1, 2, 3, 4, 5, 6]; // 6 seconds
|
|
210
|
-
const seconds = timeData.length - 1;
|
|
211
|
-
const distanceData = [0, 10, 20, 25, 40, 45, 55];
|
|
212
|
-
const altitudeData = [null, 13, 10, null, 8, 7, null];
|
|
213
|
-
const heartRateData = [123, 135, null, null, null, null, null];
|
|
214
|
-
const expectedAltitudes = [13, 13, 10, 10, 8, 7, 7];
|
|
215
|
-
const expectedHeartRates = [123, 135, 135, 135, 135, 135, 135];
|
|
216
|
-
const activity = createFakeActivityWithStreams(seconds, [
|
|
217
|
-
{ type: DataDistance.type, data: distanceData },
|
|
218
|
-
{ type: DataAltitude.type, data: altitudeData },
|
|
219
|
-
{ type: DataHeartRate.type, data: heartRateData }
|
|
220
|
-
]);
|
|
221
|
-
// When
|
|
222
|
-
ActivityUtilities.addMissingDataToStreams(activity);
|
|
223
|
-
// Then
|
|
224
|
-
expect(activity.getStreamData(DataDistance.type)).toEqual(distanceData);
|
|
225
|
-
expect(activity.getStreamData(DataAltitude.type)).toEqual(expectedAltitudes);
|
|
226
|
-
expect(activity.getStreamData(DataHeartRate.type)).toEqual(expectedHeartRates);
|
|
227
|
-
done();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
describe('createUnitStreamsFromStreams', () => {
|
|
231
|
-
it('should include derived types and unit variants by default', () => {
|
|
232
|
-
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
233
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running);
|
|
234
|
-
const paceStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
235
|
-
const kmhStream = result.find(s => s.type === DataSpeedKilometersPerHour.type);
|
|
236
|
-
expect(paceStream).toBeDefined();
|
|
237
|
-
expect(kmhStream).toBeDefined();
|
|
238
|
-
});
|
|
239
|
-
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
240
|
-
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
241
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, undefined, {
|
|
242
|
-
includeDerivedTypes: false,
|
|
243
|
-
includeUnitVariants: true
|
|
244
|
-
});
|
|
245
|
-
const paceStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
246
|
-
const kmhStream = result.find(s => s.type === DataSpeedKilometersPerHour.type);
|
|
247
|
-
expect(paceStream).toBeUndefined();
|
|
248
|
-
expect(kmhStream).toBeDefined();
|
|
249
|
-
});
|
|
250
|
-
it('should exclude unit variants when includeUnitVariants is false', () => {
|
|
251
|
-
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
252
|
-
// We pass DataPace.type in unitStreamTypes so we can check if the derived base stream is present
|
|
253
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], {
|
|
254
|
-
includeDerivedTypes: true,
|
|
255
|
-
includeUnitVariants: false
|
|
256
|
-
});
|
|
257
|
-
const paceStream = result.find(s => s.type === DataPace.type);
|
|
258
|
-
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
259
|
-
expect(paceStream).toBeDefined(); // Derived type should be there
|
|
260
|
-
expect(paceUnitStream).toBeUndefined(); // Unit variant should be gone
|
|
261
|
-
});
|
|
262
|
-
it('should exclude both derived types and unit variants', () => {
|
|
263
|
-
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
264
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], {
|
|
265
|
-
includeDerivedTypes: false,
|
|
266
|
-
includeUnitVariants: false
|
|
267
|
-
});
|
|
268
|
-
const paceStream = result.find(s => s.type === DataPace.type);
|
|
269
|
-
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
270
|
-
expect(paceStream).toBeUndefined();
|
|
271
|
-
expect(paceUnitStream).toBeUndefined();
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
describe('generateMissingStreams', () => {
|
|
275
|
-
it('should generate unit streams when generateUnitStreams = true', () => {
|
|
276
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'), new ActivityParsingOptions({ generateUnitStreams: true }));
|
|
277
|
-
// Add a speed stream
|
|
278
|
-
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
279
|
-
ActivityUtilities.generateMissingStreams(activity);
|
|
280
|
-
// Should have generated "sister" types (e.g. Pace) and unit variants (e.g. Speed km/h)
|
|
281
|
-
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(true);
|
|
282
|
-
expect(activity.hasStreamData(DataPaceMinutesPerMile.type)).toBe(true);
|
|
283
|
-
});
|
|
284
|
-
it('should NOT generate unit streams when generateUnitStreams = false', () => {
|
|
285
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
286
|
-
// Mock parsing options
|
|
287
|
-
activity.parseOptions = {
|
|
288
|
-
streams: { smooth: {}, fixAbnormal: {} },
|
|
289
|
-
maxActivityDurationDays: 14,
|
|
290
|
-
generateUnitStreams: false
|
|
291
|
-
};
|
|
292
|
-
// Add a speed stream
|
|
293
|
-
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
294
|
-
ActivityUtilities.generateMissingStreams(activity);
|
|
295
|
-
// Should NOT have generated unit variants
|
|
296
|
-
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
297
|
-
// It might still generate some "derived" streams depending on other flags, but our specific unit loop should be skipped
|
|
298
|
-
// The Pace stream comes from createUnitStreamsFromStreams too, so it should also be missing
|
|
299
|
-
expect(activity.hasStreamData(DataPaceMinutesPerMile.type)).toBe(false);
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
describe('generateMissingStreamsAndStatsForActivity', () => {
|
|
303
|
-
it('should generate unit STATS even if unit STREAMS are disabled', () => {
|
|
304
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
305
|
-
activity.parseOptions = {
|
|
306
|
-
streams: { smooth: {}, fixAbnormal: {} },
|
|
307
|
-
maxActivityDurationDays: 14,
|
|
308
|
-
generateUnitStreams: false // DISABLE streams
|
|
309
|
-
};
|
|
310
|
-
// Add a speed stream [10 m/s, 20 m/s]
|
|
311
|
-
// Max speed = 20 m/s
|
|
312
|
-
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
313
|
-
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
314
|
-
// 1. Verify Unit Streams are missing (as requested)
|
|
315
|
-
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
316
|
-
// 2. Verify Derived Base Streams are PRESENT (The fix)
|
|
317
|
-
expect(activity.hasStreamData(DataPace.type)).toBe(true);
|
|
318
|
-
// 3. Verify Stats are PRESENT (Safety Check)
|
|
319
|
-
// 20 m/s = 72 km/h
|
|
320
|
-
const allStats = Array.from(activity.getStats().values());
|
|
321
|
-
const speedMaxKmh = allStats.find(s => s.getType() === DataSpeedMaxKilometersPerHour.type);
|
|
322
|
-
expect(speedMaxKmh).toBeDefined();
|
|
323
|
-
expect(speedMaxKmh === null || speedMaxKmh === void 0 ? void 0 : speedMaxKmh.getValue()).toBe(72);
|
|
324
|
-
});
|
|
325
|
-
it('should generate DataSwimPace when generateUnitStreams = false for swimming', () => {
|
|
326
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Swimming, new Creator('test'));
|
|
327
|
-
activity.parseOptions = {
|
|
328
|
-
streams: { smooth: {}, fixAbnormal: {} },
|
|
329
|
-
maxActivityDurationDays: 14,
|
|
330
|
-
generateUnitStreams: false
|
|
331
|
-
};
|
|
332
|
-
activity.addStream(new Stream(DataSpeed.type, [1, 2])); // m/s
|
|
333
|
-
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
334
|
-
// Verify Unit Streams missing
|
|
335
|
-
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
336
|
-
// Verify Derived Base Stream (Swim Pace) IS present
|
|
337
|
-
expect(activity.hasStreamData(DataSwimPace.type)).toBe(true);
|
|
338
|
-
});
|
|
339
|
-
it('should generate DataDistanceMiles when generateUnitStreams = true', () => {
|
|
340
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'), new ActivityParsingOptions({ generateUnitStreams: true }));
|
|
341
|
-
activity.addStream(new Stream(DataDistance.type, [1000, 2000]));
|
|
342
|
-
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
343
|
-
// Should generate miles
|
|
344
|
-
expect(activity.hasStreamData(DataDistanceMiles.type)).toBe(true);
|
|
345
|
-
});
|
|
346
|
-
it('should NOT generate DataDistanceMiles when generateUnitStreams = false', () => {
|
|
347
|
-
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
348
|
-
activity.parseOptions = {
|
|
349
|
-
streams: { smooth: {}, fixAbnormal: {} },
|
|
350
|
-
maxActivityDurationDays: 14,
|
|
351
|
-
generateUnitStreams: false
|
|
352
|
-
};
|
|
353
|
-
activity.addStream(new Stream(DataDistance.type, [1000, 2000]));
|
|
354
|
-
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
355
|
-
// Should NOT generate miles
|
|
356
|
-
expect(activity.hasStreamData(DataDistanceMiles.type)).toBe(false);
|
|
357
|
-
// But base Distance should still be there (it was added manually)
|
|
358
|
-
expect(activity.hasStreamData(DataDistance.type)).toBe(true);
|
|
359
|
-
});
|
|
360
|
-
it('should generate unit streams for Mountain Biking using DataSpeed', () => {
|
|
361
|
-
const speedData = [10, 20, 30]; // m/s
|
|
362
|
-
const speedStream = new Stream(DataSpeed.type, speedData);
|
|
363
|
-
// Mountain Biking (defaults to Cycling group)
|
|
364
|
-
const unitStreams = ActivityUtilities.createUnitStreamsFromStreams([speedStream], ActivityTypes.MountainBiking, undefined, // Auto-detect all known unit types
|
|
365
|
-
{ includeDerivedTypes: true, includeUnitVariants: true });
|
|
366
|
-
const kmhStream = unitStreams.find(s => s.type === 'Speed in kilometers per hour');
|
|
367
|
-
expect(kmhStream).toBeDefined();
|
|
368
|
-
if (kmhStream) {
|
|
369
|
-
expect(kmhStream.getData()[0]).toBeCloseTo(36, 1); // 10 m/s = 36 km/h
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Event } from '../event';
|
|
2
|
-
import { DataActivityTypes } from '../../data/data.activity-types';
|
|
3
|
-
import { DataDeviceNames } from '../../data/data.device-names';
|
|
4
|
-
import { Privacy } from '../../privacy/privacy.class.interface';
|
|
5
|
-
import { DataDescription } from '../../data/data.description';
|
|
6
|
-
import { ActivityUtilities } from './activity.utilities';
|
|
7
|
-
export class EventUtilities {
|
|
8
|
-
static mergeEvents(events) {
|
|
9
|
-
events.sort((eventA, eventB) => {
|
|
10
|
-
return +eventA.getFirstActivity().startDate - +eventB.getFirstActivity().startDate;
|
|
11
|
-
});
|
|
12
|
-
const activities = events
|
|
13
|
-
.reduce((activitiesArray, event) => {
|
|
14
|
-
activitiesArray.push(...event.getActivities());
|
|
15
|
-
return activitiesArray;
|
|
16
|
-
}, [])
|
|
17
|
-
.map(activity => {
|
|
18
|
-
return activity.setID(null);
|
|
19
|
-
});
|
|
20
|
-
const event = new Event(`Merged at ${new Date().toISOString()}`, activities[0].startDate, activities[activities.length - 1].endDate, events[0].srcFileType, Privacy.Private, `A merge of 2 or more activities `, true);
|
|
21
|
-
event.addActivities(activities);
|
|
22
|
-
this.generateStatsForAll(event);
|
|
23
|
-
return event;
|
|
24
|
-
}
|
|
25
|
-
static generateStatsForAll(event) {
|
|
26
|
-
// First generate that stats on the activity it self
|
|
27
|
-
event.getActivities().forEach((activity) => {
|
|
28
|
-
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
29
|
-
});
|
|
30
|
-
this.reGenerateStatsForEvent(event);
|
|
31
|
-
}
|
|
32
|
-
static reGenerateStatsForEvent(event) {
|
|
33
|
-
event.clearStats();
|
|
34
|
-
event.startDate = event.getFirstActivity().startDate;
|
|
35
|
-
event.endDate = event.getLastActivity().endDate;
|
|
36
|
-
event.addStat(new DataActivityTypes(event.getActivities().map(activity => activity.type)));
|
|
37
|
-
event.addStat(new DataDeviceNames(event.getActivities().map(activity => activity.creator.name)));
|
|
38
|
-
// If only one
|
|
39
|
-
if (event.getActivities().length === 1) {
|
|
40
|
-
event
|
|
41
|
-
.getFirstActivity()
|
|
42
|
-
.getStats()
|
|
43
|
-
.forEach(stat => {
|
|
44
|
-
event.addStat(stat);
|
|
45
|
-
});
|
|
46
|
-
// Add the description
|
|
47
|
-
const description = event.getStat(DataDescription.type);
|
|
48
|
-
if (description && description.getValue()) {
|
|
49
|
-
event.description = description.getValue();
|
|
50
|
-
}
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
event.startDate = event.getFirstActivity().startDate;
|
|
54
|
-
event.endDate = event.getLastActivity().endDate;
|
|
55
|
-
ActivityUtilities.getSummaryStatsForActivities(event.getActivities()).forEach(stat => event.addStat(stat));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
export const CLAMP = 50;
|
|
2
|
-
export const LOOK_AHEAD_IN_METERS = 10;
|
|
3
|
-
export class GradeCalculator {
|
|
4
|
-
static computeGradeStream(timeStream, distanceStream, altitudeStream, aheadMeters = LOOK_AHEAD_IN_METERS, clamp = CLAMP) {
|
|
5
|
-
const [squashedAlignedTime, squashedAlignedDist, squashedAlignedAlt] = GradeCalculator.squashAlignStreams(timeStream, distanceStream, altitudeStream);
|
|
6
|
-
const squashedAlignedGrade = [];
|
|
7
|
-
let indexNow = 0;
|
|
8
|
-
do {
|
|
9
|
-
// Remove first index of distances & altitudes stream at every loop
|
|
10
|
-
const aheadDistances = squashedAlignedDist.slice(indexNow);
|
|
11
|
-
const aheadAltitudes = squashedAlignedAlt.slice(indexNow);
|
|
12
|
-
// Take our current distance travelled & altitude
|
|
13
|
-
const distanceNow = aheadDistances[0];
|
|
14
|
-
const altitudeNow = aheadAltitudes[0];
|
|
15
|
-
// Find ahead index matching minimal distance travelled
|
|
16
|
-
let aheadIndex = aheadDistances.findIndex(dist => distanceNow + aheadMeters <= dist);
|
|
17
|
-
// Validate we find an index with distance ahead for sure, else use last index of ahead distances
|
|
18
|
-
aheadIndex = aheadIndex >= 0 ? aheadIndex : aheadDistances.length - 1;
|
|
19
|
-
// Compute deltas & grade
|
|
20
|
-
const aheadDeltaDistance = aheadDistances[aheadIndex] - distanceNow;
|
|
21
|
-
const aheadDeltaAltitude = aheadAltitudes[aheadIndex] - altitudeNow;
|
|
22
|
-
const aheadGrade = aheadDeltaDistance > 0 ? Math.min(Math.max((aheadDeltaAltitude / aheadDeltaDistance) * 100, -clamp), clamp) : 0;
|
|
23
|
-
squashedAlignedGrade.push(Math.round(aheadGrade * 10) / 10);
|
|
24
|
-
indexNow++;
|
|
25
|
-
} while (indexNow < squashedAlignedTime.length);
|
|
26
|
-
// Rebuild grade stream with empty values using computed squashed/aligned time & grade streams
|
|
27
|
-
const gradeStream = Array(altitudeStream.length).fill(null);
|
|
28
|
-
for (const [index, seconds] of squashedAlignedTime.entries()) {
|
|
29
|
-
gradeStream[seconds] = squashedAlignedGrade[index];
|
|
30
|
-
}
|
|
31
|
-
return gradeStream;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Repair distance and altitude streams based on time streams
|
|
35
|
-
* @param timeData
|
|
36
|
-
* @param distanceData
|
|
37
|
-
* @param altitudeData
|
|
38
|
-
*/
|
|
39
|
-
static squashAlignStreams(timeData, distanceData, altitudeData) {
|
|
40
|
-
const squashedAlignedTime = [];
|
|
41
|
-
const squashedAlignedDist = [];
|
|
42
|
-
const squashedAlignedAlt = [];
|
|
43
|
-
let lastKnownDistance = distanceData.find(dist => Number.isFinite(dist));
|
|
44
|
-
let lastKnownAlt = altitudeData.find(alt => Number.isFinite(alt));
|
|
45
|
-
timeData.forEach((seconds, index) => {
|
|
46
|
-
// If we have time data
|
|
47
|
-
if (Number.isFinite(seconds)) {
|
|
48
|
-
if (Number.isFinite(distanceData[index]) && Number.isFinite(altitudeData[index])) {
|
|
49
|
-
// If we have finite distance and altitude, store values
|
|
50
|
-
squashedAlignedTime.push(seconds);
|
|
51
|
-
squashedAlignedDist.push(distanceData[index]);
|
|
52
|
-
squashedAlignedAlt.push(altitudeData[index]);
|
|
53
|
-
// Then track last known dist and alt
|
|
54
|
-
lastKnownDistance = distanceData[index];
|
|
55
|
-
lastKnownAlt = altitudeData[index];
|
|
56
|
-
}
|
|
57
|
-
else if (!Number.isFinite(distanceData[index]) && Number.isFinite(altitudeData[index])) {
|
|
58
|
-
// If only altitude is finite, then store altitude, and use last known distance instead of empty distance
|
|
59
|
-
squashedAlignedTime.push(seconds);
|
|
60
|
-
squashedAlignedDist.push(lastKnownDistance);
|
|
61
|
-
squashedAlignedAlt.push(altitudeData[index]);
|
|
62
|
-
// Then track last known alt
|
|
63
|
-
lastKnownAlt = altitudeData[index];
|
|
64
|
-
}
|
|
65
|
-
else if (Number.isFinite(distanceData[index]) && !Number.isFinite(altitudeData[index])) {
|
|
66
|
-
// If only distance is finite, then store distance, and use last known altitude instead of empty altitude
|
|
67
|
-
squashedAlignedTime.push(seconds);
|
|
68
|
-
squashedAlignedDist.push(distanceData[index]);
|
|
69
|
-
squashedAlignedAlt.push(lastKnownAlt);
|
|
70
|
-
// Then track last known distance
|
|
71
|
-
lastKnownDistance = distanceData[index];
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
// Do nothing. Don't store any time or distance data
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
// Do nothing. Don't store any time or distance data
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
return [squashedAlignedTime, squashedAlignedDist, squashedAlignedAlt];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Contains a 5th order equation which models the Strava GAP behavior described on picture "./strava_gap_modelization.png"
|
|
85
|
-
* ------------------------------------------------------------------------------------
|
|
86
|
-
* Get Real Strava Premium Grade Adjusted Pace on every strava activities with below gist
|
|
87
|
-
* https://gist.github.com/thomaschampagne/2781dce212d12cd048728e70ae791a30
|
|
88
|
-
* ------------------------------------------------------------------------------------
|
|
89
|
-
*
|
|
90
|
-
* This Strava GAP behavior is described by the below data
|
|
91
|
-
* [{ grade: -34, speedFactor: 1.7 }, { grade: -32, speedFactor: 1.6 }, { grade: -30, speedFactor: 1.5 },
|
|
92
|
-
* { grade: -28, speedFactor: 1.4 }, { grade: -26, speedFactor: 1.3 }, { grade: -24, speedFactor: 1.235 },
|
|
93
|
-
* { grade: -22, speedFactor: 1.15 }, { grade: -20, speedFactor: 1.09 }, { grade: -18, speedFactor: 1.02 },
|
|
94
|
-
* { grade: -16, speedFactor: 0.95 }, { grade: -14, speedFactor: 0.91 }, { grade: -12, speedFactor: 0.89 },
|
|
95
|
-
* { grade: -10, speedFactor: 0.88 }, { grade: -8, speedFactor: 0.88 }, { grade: -6, speedFactor: 0.89 },
|
|
96
|
-
* { grade: -4, speedFactor: 0.91 }, { grade: -2, speedFactor: 0.95 }, { grade: 0, speedFactor: 1 },
|
|
97
|
-
* { grade: 2, speedFactor: 1.05 }, { grade: 4, speedFactor: 1.14 }, { grade: 6, speedFactor: 1.24 },
|
|
98
|
-
* { grade: 8, speedFactor: 1.34 }, { grade: 10, speedFactor: 1.47 }, { grade: 12, speedFactor: 1.5 },
|
|
99
|
-
* { grade: 14, speedFactor: 1.76 }, { grade: 16, speedFactor: 1.94 }, { grade: 18, speedFactor: 2.11 },
|
|
100
|
-
* { grade: 20, speedFactor: 2.3 }, { grade: 22, speedFactor: 2.4 }, { grade: 24, speedFactor: 2.48 },
|
|
101
|
-
* { grade: 26, speedFactor: 2.81 }, { grade: 28, speedFactor: 3 }, { grade: 30, speedFactor: 3.16 },
|
|
102
|
-
* { grade: 32, speedFactor: 3.31 }, { grade: 34, speedFactor: 3.49 } ]
|
|
103
|
-
*
|
|
104
|
-
* The 5th order equation has been curve fitted using plot.ly
|
|
105
|
-
*/
|
|
106
|
-
static estimateAdjustedSpeed(speedMeterSeconds, grade) {
|
|
107
|
-
const kA = 1;
|
|
108
|
-
const kB = 0.029290920646623777;
|
|
109
|
-
const kC = 0.0018083953212790634;
|
|
110
|
-
const kD = 4.0662425671715924e-7;
|
|
111
|
-
const kE = -3.686186584867523e-7;
|
|
112
|
-
const kF = -2.6628107325930747e-9;
|
|
113
|
-
const speedAdjust = kA +
|
|
114
|
-
kB * grade +
|
|
115
|
-
kC * Math.pow(grade, 2) +
|
|
116
|
-
kD * Math.pow(grade, 3) +
|
|
117
|
-
kE * Math.pow(grade, 4) +
|
|
118
|
-
kF * Math.pow(grade, 5);
|
|
119
|
-
return speedMeterSeconds * speedAdjust;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { GradeCalculator } from './grade-calculator';
|
|
2
|
-
const floor = (value, decimals) => {
|
|
3
|
-
const pow = Math.pow(10, decimals);
|
|
4
|
-
return Math.floor(value * pow) / pow;
|
|
5
|
-
};
|
|
6
|
-
describe('GradeCalculator', () => {
|
|
7
|
-
it('should align and squash distance & altitude along time', done => {
|
|
8
|
-
// Given
|
|
9
|
-
const timeData = [0, null, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
10
|
-
const distanceData = [0, null, 20, null, 40, 56, null, 73, 85, 99];
|
|
11
|
-
const altitudeData = [100, null, 102, 303, null, 205, null, 207, 308, 109];
|
|
12
|
-
const expectedSquashedAlignTime = [0, 2, 3, 4, 5, 7, 8, 9];
|
|
13
|
-
const expectedSquashedAlignDistance = [0, 20, 20, 40, 56, 73, 85, 99];
|
|
14
|
-
const expectedSquashedAlignAltitude = [100, 102, 303, 303, 205, 207, 308, 109];
|
|
15
|
-
// When
|
|
16
|
-
const [squashedAlignedTime, squashedAlignedDist, squashedAlignedAlt] = GradeCalculator.squashAlignStreams(timeData, distanceData, altitudeData);
|
|
17
|
-
// Then
|
|
18
|
-
expect(squashedAlignedDist.length).toEqual(squashedAlignedTime.length);
|
|
19
|
-
expect(squashedAlignedAlt.length).toEqual(squashedAlignedTime.length);
|
|
20
|
-
expect(squashedAlignedTime).toEqual(expectedSquashedAlignTime);
|
|
21
|
-
expect(squashedAlignedDist).toEqual(expectedSquashedAlignDistance);
|
|
22
|
-
expect(squashedAlignedAlt).toEqual(expectedSquashedAlignAltitude);
|
|
23
|
-
done();
|
|
24
|
-
});
|
|
25
|
-
describe('Grade compute', () => {
|
|
26
|
-
it('should calculate grade on flat terrain', done => {
|
|
27
|
-
// Given
|
|
28
|
-
const timeData = [0, null, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
29
|
-
const distanceData = [10, null, 20, null, 30, 35, null, 45, 50, 55];
|
|
30
|
-
const altitudeData = [10, null, 10, 10, 10, 10, null, 10, 10, 10];
|
|
31
|
-
const gradeData = [0, null, 0, 0, 0, 0, null, 0, 0, 0];
|
|
32
|
-
// When
|
|
33
|
-
const gradeStream = GradeCalculator.computeGradeStream(timeData, distanceData, altitudeData);
|
|
34
|
-
// Then
|
|
35
|
-
expect(gradeStream.length).toEqual(timeData.length);
|
|
36
|
-
expect(gradeStream.length).toEqual(gradeData.length);
|
|
37
|
-
expect(gradeStream).toEqual(gradeData);
|
|
38
|
-
done();
|
|
39
|
-
});
|
|
40
|
-
it('should calculate grade on hilly terrain', done => {
|
|
41
|
-
// Given
|
|
42
|
-
const timeData = [0, null, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
43
|
-
const distanceData = [10, null, 20, null, 30, 35, null, 45, 50, 55];
|
|
44
|
-
const altitudeData = [10, null, 10, 11, 13, 16, null, 15, 14, 13];
|
|
45
|
-
const expectedGradeData = [0, null, 30, 20, 13.3, -10, null, -20, -20, 0];
|
|
46
|
-
// When
|
|
47
|
-
const gradeStream = GradeCalculator.computeGradeStream(timeData, distanceData, altitudeData, 10, 50);
|
|
48
|
-
// Then
|
|
49
|
-
expect(gradeStream.length).toEqual(timeData.length);
|
|
50
|
-
expect(gradeStream.length).toEqual(expectedGradeData.length);
|
|
51
|
-
expect(gradeStream).toEqual(expectedGradeData);
|
|
52
|
-
done();
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
describe('Grade adjusted speed', () => {
|
|
56
|
-
it('should model grade adjusted pace at grade of -32', () => {
|
|
57
|
-
// Given
|
|
58
|
-
const speedMeterSeconds = 10;
|
|
59
|
-
const grade = -30;
|
|
60
|
-
// When
|
|
61
|
-
const gradeAdjustedSpeed = GradeCalculator.estimateAdjustedSpeed(speedMeterSeconds, grade);
|
|
62
|
-
// Then
|
|
63
|
-
expect(floor(gradeAdjustedSpeed, 1)).toEqual(15);
|
|
64
|
-
});
|
|
65
|
-
it('should model grade adjusted pace at grade of 0', () => {
|
|
66
|
-
// Given
|
|
67
|
-
const speedMeterSeconds = 10;
|
|
68
|
-
const grade = 0;
|
|
69
|
-
// When
|
|
70
|
-
const gradeAdjustedSpeed = GradeCalculator.estimateAdjustedSpeed(speedMeterSeconds, grade);
|
|
71
|
-
// Then
|
|
72
|
-
expect(floor(gradeAdjustedSpeed, 1)).toEqual(10);
|
|
73
|
-
});
|
|
74
|
-
it('should model grade adjusted pace at grade of 6', () => {
|
|
75
|
-
// Given
|
|
76
|
-
const speedMeterSeconds = 10;
|
|
77
|
-
const grade = 6;
|
|
78
|
-
// When
|
|
79
|
-
const gradeAdjustedSpeed = GradeCalculator.estimateAdjustedSpeed(speedMeterSeconds, grade);
|
|
80
|
-
// Then
|
|
81
|
-
expect(floor(gradeAdjustedSpeed, 1)).toEqual(12.4);
|
|
82
|
-
});
|
|
83
|
-
it('should model grade adjusted pace at grade of 28', () => {
|
|
84
|
-
// Given
|
|
85
|
-
const speedMeterSeconds = 10;
|
|
86
|
-
const grade = 28;
|
|
87
|
-
// When
|
|
88
|
-
const gradeAdjustedSpeed = GradeCalculator.estimateAdjustedSpeed(speedMeterSeconds, grade);
|
|
89
|
-
// Then
|
|
90
|
-
expect(floor(gradeAdjustedSpeed, 1)).toEqual(29.7);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|