Wednesday, September 3, 2014

Tile Loading

WhirlyGlobe-Maply 2.3 saw some significant improvements in tile loading.  Most of this was focused on maps. Let's take a look at how it used to work and what's available now.

Images and tile numbers

Loading From the Top: Globe


WhirlyGlobe-Maply is called that because the globe came first.  It's often used as a whole globe with the user starting zoomed way out.

Mapbox Terrain Style

The image tile loading worked like this.

  • Start at the the lowest resolution tile (e.g. [0: 0,0])
  • While there are tiles to load
    • Load the current most important tile.
    • Did it fail?  Okay we're done here
    • Did it succeed?  Great, add the four children to the list.

Who doesn't love pseudo-code?  Let's just see what that looks like.

By the numbers

That approach had some advantages.  Tile sources can be sparse and it's a little resistant to network failure.  Most important (to me), there are never any holes in the globe.  There's always something to look at, even if it's blurry.

Loading From the Top: Map


One secret of WhirlyGlobe-Maply is that the globe and map share most of their code.  So when I got the map working, I used the same tile loading scheme.

Loading from the Top with Mapbox imagery


That worked okay, but if you start out zoomed in to the map you're waiting a long time to see the right tiles.  There's a whole lot of blurry for far too long.  It gets worse the farther you're zoomed in.  Here's how that looks with tile numbers.

Loading from the top by the numbers

The flashy colors at the beginning are low res tiles we can't see the numbers for.  I could probably argue there are cases where that works well.  But not for a map.

Loading the Current Zoom Level


The obvious thing to do for a map is to load the zoom level we need for the area we're looking at.  If it's a flat (2D) map, that's actually pretty easy.

Single level load with imagery


Simple, but I don't like it.  You're looking at too much blank screen.  For a retina display and a remote tile source this is irritating.

Still, there are cases where this may be appropriate and it's easy enough to activate.  When you set up your MaplyQuadImageTilesLayer set useTargetZoomLevel and singleLevelLoading to YES.

Single level load by the numbers


And again, the tile loading with numbers.  Fine for some cases, like a weather overlay.  But we can do better.

Loading Multiple Zoom Levels


Focusing on a single zoom level is great for performance, but bad for display.  I'd rather have a hybrid that loads a few low res tiles and then fills in the rest.  Like this.

Multi-level load with Mapbox imagery

That's nice.  We've got something reasonable to look at almost immediately, then we get some detail.  When the highest resolution comes in we probably didn't realize it wasn't already sharp.

Multi-level load by the numbers


Pretty good, but the levels you want to load may depend on your tile source.  Luckily, it's configurable.  When you create your MaplyQuadImageTilesLayer set useTargetZoomLevel and singleLevelLoading to YES and then assign an array of numbers to multiLevelLoads.

For example, try @[-4,-2] in multiLevelLoads.  If the user should be looking at level 22 data, then the layer will start out loading level 18, then work on level 20 and then fill in level 22.

Summary


The old tile loading logic could feel out a sparse tile source efficiently.  The new tile logic can do it too, but wow was that complicated.  And perhaps less efficient.  If you've got a normal tile source, it shouldn't be a problem.

I like the multi level loading approach.  But it does cost more memory and rendering time than the single level approach.  Use it thoughtfully and test it in your app.

This is all available in WhirlyGlobe-Maply 2.3.