Sunday, March 11, 2012

fun with JavaScript

After adventures in Perl, then Java, then Ruby, I've been immersed in JavaScript, the language of web UI's.

Writing command line apps is straightforward. For example if the user wants to analyze a specific ride, include the ride ID as a command line argument. Done. Now get on to the juicy data analysis.

But with a user interface, things are much more complex. A bunch of my Strava app ideas begin the same: user specifies a ride, app maps the ride for user reference, various analyses are done and/or actions are taken.

In the Strava API some methods require an authorization key from logging in, while others do not. Among those that do is the method which returns a reduced set of coordinates for a route to allow mapping without transferring the full set of data for the ride. This is important for maps, because it substantially reduces the bandwidth requirement, not only loading the data from Strava, but then subsequently uploading it to Google for map generation. And obviously anything which results in activities being modified, like implementing my motorized segment filter to "clean up" ride data where I kept my computer on while in a train or car, also requires logging in.

So I set for myself the task of implementing the following:

  1. User logs in to Strava.
  2. User is presented with a scrollable list of recent rides from which one can be selected. Alternately, the URL for a ride can be entered in a text entry widget.
  3. The ride is mapped (with the Google Maps API).

This was all a surprising amount of work. There's always details. For example, when you download a list of recent activity info from Strava, it sends the latest 50 rides (no runs), but includes only the ID and the name. I also want to see the time and distance. But to get those, I need to make a separate request, one per ride. This takes a lot of time, so I want to at least display the name first, then fill in the data and time as those become available. Fortunately, the jQuery Ajax method works asynchronously, so I can fill in the ride names (which I know) quickly, then as the queries are answered, fill in the distance and data. This was a lot of time, for what is just one small part of the big picture.

I still need to debug it before making anything public. Everything is still a bit rough around the edges.

Then what? Well, I do have that motorized segment filter I want to implement as a first step. It requires accessing the full dataset, then applying smoothing functions, then estimating power (if Strava hasn't already estimated it for me), then scanning the data for potential transitions to/from a motorized vehicle, then analyze whether the gaps between these transitions are consistent with typical human power. It's a decent amount of bandwidth and a good amount of number crunching. If I convert it to Javascript, I dump all that in the lap of the user. If I keep moving with my Ruby implementation, then it stays with the server. I'm leaning toward the Javascript: even an iPhone can match the number-crunching speed of a Cray computer from 1984, and I'm not sure about running all this on random web servers. But maybe I should give the server-side solution a try, since the server is a guaranteed high-bandwidth connection to Strava. This way the client would need to access only the decimated data stream needed for mapping. So I could try both.

No comments: