GithubHelp home page GithubHelp logo

sports-alliance / sports-lib Goto Github PK

View Code? Open in Web Editor NEW
149.0 13.0 21.0 14.56 MB

A Library for processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

License: GNU Affero General Public License v3.0

TypeScript 99.90% JavaScript 0.10%
tcx gpx garmin strava polar movescount json fit processing-gpx sports-lib

sports-lib's People

Contributors

davidjcohen avatar dependabot[bot] avatar jimmykane avatar rc-787 avatar rdjs avatar sitebase avatar thomaschampagne avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sports-lib's Issues

Null check missing if there are no activities

Hi!
I am trying to parse some tcx-files.

If there is for some reason no "Activity" in it, then the importer.tcx.tx blows up hard, because a null-check is missing.

TypeError: Cannot read property 'startDate' of undefined at /home/felix/example_project/node_modules/@sports-alliance/sports-lib/lib/events/adapters/importers/tcx/importer.tcx.js:83:63

https://github.com/sports-alliance/sports-lib/blob/develop/src/events/adapters/importers/tcx/importer.tcx.ts#L99


How did the Garmin hackers escape?
They just ransomware.

(Found in the internet)

Check if paused

Hi, is there a way to check if the device is paused at each point of the data stream for FIT files? I can get the total time paused but I can't see a way to check at specific times.

Cheers

Fails to import the tracklog from a Garmin Etrex 30x generated GPX

Used the following functions.

   
   // For GPX you need a string 

   SportsLib.importFromGPX(inputFile,DOMParser).then((result) => {
       // do Stuff with the file

        // convert to gpx
   const gpxPromise = new EventExporterGPX().getAsString(result);
   gpxPromise.then((gpxString) => {
       // writes the gpx to file
       fs.writeFileSync(`${userPath}/result.gpx`, gpxString, 'utf8');
       });

The input GPS looks like this

image

The output GPX looks like this

image

It's gone from 1348 trackpoints on the input file to 6 trackpoints on the output file.

It seems to generate the statistics ok, it just doesn't work when it comes to preserving the tracklog data from an Etrex30x GPX file.

[Discussion] Should Data values be stored to their precision?

Due to several calculations eg adding up distance the result can have many decimal places

eg

1.2348292993

During the Strava compliance tests eg strava reports distance with 1 decimal

1.2

  • Should this rounding be applied on the consumer (App using this lib)?
  • Should this rounding be defined at least in this library eg getValue(precise)?
  • Should it all fall to the side of the consumer (App using this lib)

Import GPX: timestamp for each data point?

Hi,
Thanks for your hard work with this, it looks very good.
I'm looking through the imported data from a gpx file though and I can find all the data somewhere except the timestamp for the data point - I can only find the start and end times for an activity. Am I missing something?
Sorry if its obvious and I missed it.

Unable to import/parse TCX file

Hi ! Thanks for your lib !

I'm unable to parse your garmin.tcx sample or a tcx file exported from garmin connect (source Edge 1000) without getting the below error:

(node:30906) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'length' of undefined
    at /home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:99:33
    at Array.reduce (<anonymous>)
    at Function.EventImporterTCX.getPoints (/home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:96:44)
    at /home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:74:18
    at Array.map (<anonymous>)
    at /home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:73:67
    at Array.map (<anonymous>)
    at /home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:41:10
    at new Promise (<anonymous>)
    at Function.EventImporterTCX.getFromXML (/home/thomas/Documents/.me/projects/quantified-self-lib/src/events/adapters/importers/tcx/importer.tcx.ts:38:12)
(node:30906) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:30906) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Thanks for your help! Need your library for sure :)

"Cannot read property 'length' of undefined" while parsing attached GPX file

Hey Dimi!

Small issue while parsing file mytrail_export.gpx (mytrail_export.zip). It produces the following error: TypeError: Cannot read property 'length' of undefined

Error is raised at importer.gpx.ts:49:136:

 const endDate = isActivity ?
          new Date(trackOrRoute.trkseg[trackOrRoute.trkseg.length - 1].trkpt[trackOrRoute.trkseg
[trackOrRoute.trkseg.length - 1].trkpt.length // HERE !
 - 1].time[0]) :
          new Date(startDate.getTime() + samples.length * 1000);

Here a jasmine which reproduce the bug on the file.

    it('should parse a MyTrail GPX file', done => {

      // Given
      const path = __dirname + '/fixtures/others/mytrail_export.gpx';
      const gpxString = fs.readFileSync(path).toString();

      // When
      const eventInterfacePromise = SportsLib.importFromGPX(gpxString);

      // Then
      eventInterfacePromise.then((event: EventInterface) => {
        expect(event.getFirstActivity().type).toBeDefined();
        done();
      });

Not sure how to fix it properly. Let me know if you need more investigation from me.

(File is coming from my elevate app testers)

Using xmldom as default DOMParser

This library has been of great help, but the guide should be clear that in NodeJS usage, another DOMParser (e.g. xmldom) should be included as an argument in 'importFromGPX()'. Had to trawl the importer js files to find out.

In the case of Node JS:
npm i xmldom

import {SportsLib} from '@sports-alliance/sports-lib';
import { DOMParser } from 'xmldom'

// For GPX you need a string 
const gpxString = 'Some string from a file etc';
SportsLib.importFromGPX(gpxString, DOMParser).then((event)=>{
...
});

Write FIT file/stream

Question:
Hi, is it possible to convert TCX/GPS to FIT? or even just the ability to create a FIT file/stream with this? I've been looking for a JS library to create FIT files. If not, any chance this might be added in future?

Cheers

GXParser DOMParser issues

The problem is in GXParser depend. which DOMParser is not included

(node:2030) UnhandledPromiseRejectionWarning: ReferenceError: DOMParser is not defined
at GXParser (/mnt/c/greyp.workspace/playground/g6simulator/node_modules/gxparser/GXParser.js:40:16)
at /mnt/c/greyp.workspace/playground/g6simulator/node_modules/quantified-self-lib/lib/events/adapters/importers/gpx/importer.gpx.js:34:29

FIT to GPX - Code Sample

Hey guys,

I thought I'd contribute with a little code sample.
Hope this helps someone / somehow.


filename: fit-converter.js

'use strict';

import fs from 'fs';
import sportsLibPkg from '@sports-alliance/sports-lib';
import exporterPkg from '@sports-alliance/sports-lib/lib/events/adapters/exporters/exporter.gpx.js'

const { SportsLib } = sportsLibPkg;
const { EventExporterGPX } = exporterPkg;

// Input and output file path
const inputFilePath = '/tmp/test.fit';
const outputGpxFilePath = '/tmp/test.gpx';

// reads the FIT file into memory
const inputFile = fs.readFileSync(inputFilePath, null);
if (inputFile && inputFile.buffer) {
    const inputFileBuffer = inputFile.buffer;
    // uses lib to read the FIT file
    SportsLib.importFromFit(inputFileBuffer).then((event) => {
        // convert to gpx
        const gpxPromise = new EventExporterGPX().getAsString(event);
        gpxPromise.then((gpxString) => {
            // writes the gpx to file
            fs.writeFileSync(outputGpxFilePath, gpxString, (wError) => {
                if (error) {
                    console.error('Ooops, something went wrong while saving the GPX file, see details below.');
                    console.error(JSON.stringify(wError));
                }
            });
            // all done, celebrate!
            console.log('Converted FIT file to GPX successfully!');
            console.log('GPX file saved here: ' + outputGpxFilePath);
        }).catch((cError) => {
            console.error('Ooops, something went wrong while converting the FIT file, see details below');
            console.error(JSON.stringify(cError));
        });
    });
} else {
    console.error('Ooops, could not read the inputFile or it does not exists, see details below');
    console.error(JSON.stringify(inputFilePath));
}

to run it:

node fit-converter.js

requirements: a "/tmp" folder with a valid test.fit file in it.


Many thanks for the easy to use lib!

Confused on conversions with averages

Hi @thomaschampagne I might need your help here.

I am having some calc inconsistency when trying to figure out some averages. Apparently I am doing something wrong, but I cannot figure it out.

I have an array of speed samples example:

[
  3.3,
  3.3,
  3.32,
  3.32,
  3.22,
  3.22,
  3.14,
  3.14,
  3,
  3,
  3,
  3,
  3.02,
  3.02,
  2.96,
  2.96,
  2.92,
  2.92,
  2.88,
  2.88,
  2.88,
  2.88,
  2.86,
  2.86,
  2.86,
  2.86,
  2.86,
  2.86,
  2.88,
  2.88,
  2.88,
  2.88,
  2.86,
  2.86,
  2.84,
  2.84,
  2.86,
  2.86,
  2.88,
  2.88,
  2.9,
  2.9,
  2.86,
  2.86,
  2.84,
  2.84,
  2.84,
  2.84,
  2.82,
  2.82,
  2.8,
  2.8,
  2.64,
  2.64,
  0,
  0,
  2.22,
  2.22,
  2.3,
  2.3,
  2.4,
  2.4,
  2.44,
  2.44,
  2.58,
  2.58,
  2.6,
  2.6,
  2.62,
  2.62,
  2.62,
  2.62,
  2.58,
  2.58,
  2.54,
  2.54,
  2.52,
  2.52,
  2.5,
  2.5,
  2.5,
  2.5,
  2.5,
  2.5,
  2.48,
  2.48,
  2.46,
  2.46,
  2.44,
  2.44,
  2.44,
  2.44,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42
]

Now in order to find the average speed I do

[
  3.3,
  3.3,
  3.32,
  3.32,
  3.22,
  3.22,
  3.14,
  3.14,
  3,
  3,
  3,
  3,
  3.02,
  3.02,
  2.96,
  2.96,
  2.92,
  2.92,
  2.88,
  2.88,
  2.88,
  2.88,
  2.86,
  2.86,
  2.86,
  2.86,
  2.86,
  2.86,
  2.88,
  2.88,
  2.88,
  2.88,
  2.86,
  2.86,
  2.84,
  2.84,
  2.86,
  2.86,
  2.88,
  2.88,
  2.9,
  2.9,
  2.86,
  2.86,
  2.84,
  2.84,
  2.84,
  2.84,
  2.82,
  2.82,
  2.8,
  2.8,
  2.64,
  2.64,
  0,
  0,
  2.22,
  2.22,
  2.3,
  2.3,
  2.4,
  2.4,
  2.44,
  2.44,
  2.58,
  2.58,
  2.6,
  2.6,
  2.62,
  2.62,
  2.62,
  2.62,
  2.58,
  2.58,
  2.54,
  2.54,
  2.52,
  2.52,
  2.5,
  2.5,
  2.5,
  2.5,
  2.5,
  2.5,
  2.48,
  2.48,
  2.46,
  2.46,
  2.44,
  2.44,
  2.44,
  2.44,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42,
  2.42
].reduce(function(acc, val) { return acc + val; }, 0)/100

The result is: (m/s)

2.670800000000001

Now to convert to pace I do

1000/2.670800000000001 = 374.41964954320787

So 374.41964954320787 seconds

Now if I first convert that array of speed values to pace with the same conversion like

speedArray.map(v => 1000/v)

I get this array

[
  303.03030303030306,
  303.03030303030306,
  301.20481927710847,
  301.20481927710847,
  310.55900621118013,
  310.55900621118013,
  318.4713375796178,
  318.4713375796178,
  333.3333333333333,
  333.3333333333333,
  333.3333333333333,
  333.3333333333333,
  331.12582781456956,
  331.12582781456956,
  337.83783783783787,
  337.83783783783787,
  342.4657534246575,
  342.4657534246575,
  347.22222222222223,
  347.22222222222223,
  347.22222222222223,
  347.22222222222223,
  349.65034965034965,
  349.65034965034965,
  349.65034965034965,
  349.65034965034965,
  349.65034965034965,
  349.65034965034965,
  347.22222222222223,
  347.22222222222223,
  347.22222222222223,
  347.22222222222223,
  349.65034965034965,
  349.65034965034965,
  352.11267605633805,
  352.11267605633805,
  349.65034965034965,
  349.65034965034965,
  347.22222222222223,
  347.22222222222223,
  344.82758620689657,
  344.82758620689657,
  349.65034965034965,
  349.65034965034965,
  352.11267605633805,
  352.11267605633805,
  352.11267605633805,
  352.11267605633805,
  354.6099290780142,
  354.6099290780142,
  357.14285714285717,
  357.14285714285717,
  378.78787878787875,
  378.78787878787875,
  Infinity,
  Infinity,
  450.45045045045043,
  450.45045045045043,
  434.7826086956522,
  434.7826086956522,
  416.6666666666667,
  416.6666666666667,
  409.8360655737705,
  409.8360655737705,
  387.5968992248062,
  387.5968992248062,
  384.6153846153846,
  384.6153846153846,
  381.6793893129771,
  381.6793893129771,
  381.6793893129771,
  381.6793893129771,
  387.5968992248062,
  387.5968992248062,
  393.7007874015748,
  393.7007874015748,
  396.8253968253968,
  396.8253968253968,
  400,
  400,
  400,
  400,
  400,
  400,
  403.2258064516129,
  403.2258064516129,
  406.5040650406504,
  406.5040650406504,
  409.8360655737705,
  409.8360655737705,
  409.8360655737705,
  409.8360655737705,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777,
  413.22314049586777
]

Now running the save AVG calculation on that

Like this .filter(v => v !== Infinity).reduce(function(acc, val) { return acc + val; }, 0)/100

The AVG pace of those samples is:

362.8961108433509

Which is not the same as converting the AVG SPEED to Pace

What can I be doing wrong? (Working on GAP)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.