Skip to content

Improve performance and prevent browser tab crashes by reworking the trails tileset #141

@jake-low

Description

@jake-low

OpenTrailMap's main map view currently has some significant performance problems:

  1. The initial page load takes several seconds to render the map:

    opentrailmap.loading.mp4
  2. When panning the map, tiles often take longer than they should to render:

    opentrailmap.panning.mp4
  3. When zooming the map often gets stuck displaying low-zoom tiles for many seconds:

    opentrailmap.zooming.mp4
  4. Panning or zooming the map too much often causes the browser tab to freeze up entirely, forcing the user to close the tab and open a new one.


All of the above symptoms are caused by the fact that the tiles in the trails tileset are very large.

Max tile sizes
                    z4    z5    z6    z7    z8    z9   z10   z11   z12   z13   z14   all
             park 233k  185k  190k  223k  210k  228k  145k   84k   50k   25k   17k  233k
        trail_poi  16k   16k   15k    1M  517k  291k  161k   97k   91k   84k  1.3M  1.3M
            trail    0  801k  1.7M  3.1M  3.9M  4.9M  2.6M  2.1M  1.2M  718k  426k  4.9M
     barrier_area    0     0     0   495   814  1.2k  1.8k  3.8k  4.3k  3.8k  5.7k  5.7k
     barrier_line    0     0     0  9.4k   10k  9.7k   25k   30k   42k   15k   11k   42k
trail_centerpoint    0     0     0  991k  432k  235k  109k   86k   82k   35k   23k  991k
        full tile 250k    1M  1.8M  4.6M  3.9M  4.9M  2.6M  2.1M  1.2M  727k  1.3M  4.9M
          gzipped 160k  605k  1.1M  2.7M  2.1M  2.6M  1.4M  1.2M  727k  414k  305k  2.7M

Note: These are the maximum tile sizes, not averages, but it's actually a better indicator in some ways because many tiles are largely empty (and this becomes even more true at high zooms), which skews the average tilesize downwards.

MapLibre fetches and parses dozens of tiles per second as you pan and zoom the map. Even on a fast internet connection where fetching is quick, parsing a large tile and preparing it for rendering requires significant work: reading PBF data, triangulating polygon geometries and computing normals for line geometries, and generating collision boxes for symbols.

This work happens on the CPU, and once it starts it can't be interrupted (unlike fetching, which can via an AbortController). This explains why zooming on OpenTrailMap is especially laggy: as you pass through each intermediate zoom level, new tiles are requested, and if any of them finish loading before the final zoom level is reached, that tile will be parsed and prepared for rendering, tying up the thread and preventing other tiles which are needed at the final zoom level from being processed. Ironically this means that the lag is worst on a fast internet connection, since more tile fetch requests will "win the race" against the AbortController and enter the processing queue.

To fix this, tiles in the trails tileset need to be made much smaller: at least 10x smaller if not more. Fortunately, this is pretty achievable. While OpenTrailMap does require more data in the vector tiles than a traditional map (in order to support filtering and color-coding trails by a bunch of different tags), a large fraction of the total tile size can be explained by a few design choices that could be revisited.

Here are a couple ideas:

Increase the tileset minzoom. The table above shows that z7-z9 are the largest layers; we could only generate trails tiles for z10+. This would also help with the zoom lag issue, since if these tiles don't exist, they won't be fetched and clog up the processing queue as a user zooms in. Lower zooms would still display a map, but it wouldn't be interactive or filterable until you zoom in.

Remove unnecessary attributes from features. The only attributes that need to be present on tile features are the ones used for styling or filtering the map. Other metadata that's only displayed when you click on a feature could be loaded on demand from the OSM API. There are a bunch of attributes that could be removed with minimal/no loss in functionality, for example:

  • OSM_CHANGESET, OSM_USER_NAME, and OSM_VERSION (not used for rendering at all AFAIK)
  • OSM_TYPE and OSM_ID (can be decoded from the feature ID assigned by Planetiler instead)
  • OSM_TIMESTAMP (only used for "last modified date" filtering; should be replaced by a lower cardinality value like YYYY-MM)
  • MIN_LON, MIN_LAT, MAX_LON, and MAX_LAT (only used to zoom the map to a selected feature; these four fields alone are responsible for ~10% of the data in a tile I tested because each feature tends to have unique values).
  • AREA_Z0_PX2 (used on label points for areas; should instead compute a reasonable minzoom at build time)

Some of these changes require removing existing features in OpenTrailMap (such as certain filter types, or "zoom to feature"), but I think this is worth considering as a way to improve the overall usefulness of the tool and make it possible to continue to extend and improve it in the future.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions