rclosner/trails-mobile — pull request #45 by Mr0grog (2014-04-11 01:54:50+00:00)
Title: WIP: Optimized trail rendering

This is just a start at solving the problem. Basically, there are 3 (and a half?) big things we're doing here:

1. We straight up don't load trails that don't have any segments. These are basically just bad data and we should never deal with them when iterating over trails.

2. Simplifying (smoothing) the trail lines. This makes a *big* impact no matter what rendering method we use. Some of these trail lines are crazy complex.

3. Rendering the trails to a canvas instead of letting leaflet do SVG. This seems to be much nicer on the browser. Additionally, rendering is done less often (since we aren't moving SVG DOM elements all over the place; we're just drawing an image and moving it).

3.5. Precalculating layer/bounds information so we don't have to do it every time we try and render a trail.

Notes:

- We could also use `L_PREFER_CANVAS = true` to make leaflet do the canvas rendering. However, this would cause *all* layers to use canvas and is also likely not quite as fast as some of the hand optimizations we could do (and area already doing—see bounds caching above).

- If we really don't want to do canvas rendering, adding `pointerEvents: "none"` to the layer options seems to give a small speed boost to SVG rendering.

- All the bounds precalculation should really be done in a worker so as not to block UI interaction.

- We could probably do all trail projection in a worker as well. This is almost certainly the most expensive part of rendering a trail. There's probably relevant code to steal from either Leaflet or NodeTiles.

- We could cache projections for a given zoom level.

- We could cache tiles. `L.TileLayer` has a `reuseTiles` option which might do this for us. If we do so, we should also see if there's a way to capture iOS's `UIApplicationDidReceiveMemoryWarningNotification` and trigger an event in JS so we can purge the cache. More info here: [https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIApplicationDelegate/applicationDidReceiveMemoryWarning:](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIApplicationDelegate/applicationDidReceiveMemoryWarning:) and here: [https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/c/data/UIApplicationDidReceiveMemoryWarningNotification](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/c/data/UIApplicationDidReceiveMemoryWarningNotification)

- Obviously, the rainbow rendering needs to go and the styles should be tweaked/loaded from somewhere else.

- The render method needs to have other ways of filtering trails (e.g. only render trails of a certain type, highlight the current trail, etc.).

- The line simplification/smoothing should *probably* happen somewhere other than where it is now. It's probably also not quite the *right amount* of smoothing. Haven't looked into very many different values yet.
1. It would be best if it were precalculated in the data on compilation and not done at run-time.
2. It would be great to have a low-detail, smoothed version and a hi-detail, un-smoothed version of each trail line that we could switch between at different zoom levels.