project
December 20, 2019

Project DASH - an open source strava dashboard

I have been running since June 2016, and each year I set a goal for the total distance I want to cover over the year. In 2017, I aimed for 365 kilometres, and in 2018 I aimed for 588 kilometres (which is 365 miles). For 2019, I kept the bar at 588 kilometres, and focused on increasing my pace.

I use Strava to track my runs, and it does a great job at this. I want to track my progress over the year and compare it to the previous years, but this isn’t possible inside Strava.

I want to build and release a website that lets you connect your Strava account and visualize your running data.

Project Goals

  • A website that visualizes running progress.
  • Connect your account via Strava API.
  • Display the total distance run each year.
  • Display the number of runs per week.
  • Display average pace over time.

Roadmap

This is my rough plan for how I want to tackle this project:

  1. Get it working locally for me with hardcoded credentials.
  2. Support other peoples accounts.
  3. Launch at https://dash.stayradiated.com.

Getting the data

Fortunately, Strava make this really easy - they have a fantastic API I can use to extract my data. I signed up for API access and created a basic Node.js app to authenticate via OAuth to get my access token.

It didn’t take long to get a JSON dump of all my activities. I used the RESTful-stream.ts library to create an async iterator - this is a nice way to paginate over all the available activities.

const PER_PAGE = 100

const getActivities = async (accessToken, page) => {
  const response = await got(
    'https://www.strava.com/api/v3/athlete/activities',
    {
      searchParams: {
        access_token: accessToken,
        per_page: PER_PAGE,
        page
      },
      responseType: 'json'
    }
  )

  return {
    page
    body: response.body,
  }
}

const getAllActivities = (accessToken) => {
  const ctrl = {
    hasNext(item) { return item.body.length === PER_PAGE },
    next(item) { return getActivities(accessToken, item.page + 1) },
    parse(item) { return item.body }
  };

  return iterate(parse(ctrl, getActivities(accessToken, 1)))
}

for await (const activity of getAllActivities(accessToken)) {
  // iterate over each activity
  console.log( JSON.stringify(activity) )
}

Visualizing the data

The hard part is figuring out how to visualize the data. I’m a big fan of Grafana, they make it easy to display time series data, along with controls for zooming in and out. However, I couldn’t find out how to use their graphing library independent of the rest of the project, so I need to find an alternative.

D3 is a fantastic library, and has been around for ages, however it is quite low level and isn’t the easiest to work with. I found some libraries that abstract the complexity, such as Rickshaw and NVD3, but they don’t quite cover what I am looking for.

I stumbled across React Timeseries Charts. This library uses d3 under the hood, but exposes a clean React interface to build a chart. The creator, ESNet, also wrote a library for working with time series data, called Pond.js. These libraries are quite well documented, and have plenty of examples I can learn from — however, it is still a struggle to get it working just right.

Right now, I currently have a chart displaying my running distance for each year. The code is a mess, but I’m happy that it’s working. Next step is to refactor the code, add a legend, and have an option to select which years to show.

Work in progress


© 2020 George Czabania