1

Overview

I have a fairly interesting requirement where I need to load geojson data from a service (not a vector tile service) and then cache that data for offline use (using indexDB). So, when running the application offline I need to load that data from indexDB into the map (using mapbox-gl). The amount of data that could be cached offline (in indexDB) could be quite large and therefore I cannot just bring all of the data into memory and add it to the map (in which case mapbox would handle everything for us internally using geojson-vt).

I realize that if the source was a vector tile service that would make things easier, but unfortunately that is not an option at this point in time.

Attempted Solution

I believe the solution to this problem is to index the data when I store it in indexDB. My thought was that I would figure out each of the UTM grid values for each "feature" and that way when the map moves I can simply query the features in the respective grid(s) and load them into mapbox.

Example IndexDB "Table":

feature_id | properties | utm_tiles ({z}_{x}_{y})
1               ...       14_0_0, 13_1_1, 13_1_2, etc
2               ...       14_0_0, 12_100_100, 12_100_101, etc
etc...

Have the info above I could then query select * from index_db_features where utm_tiles in ('14_0_0', '14_0_1')

While this theoretically seems like it would work, the problem I am having is figuring out all of the tiles that a given feature touches. The geojson-vt library seems to do what I want except it doesn't give you an actual list of all tiles that the feature(s) are found in - it does the reverse, where you need to ask it for features based on a given tile.

Does anyone have any suggestions for finding out what all tiles a given feature touches? Or a better suggestion for spatially indexing geojson data for use in indexDB?

Rusty
  • 109
  • 1
  • 9

1 Answers1

1

Here's my current solution to this problem:

  1. Add a location object with location.lat, location.lon fields to the properties of each geojson feature (I'm using the center of the feature).
  2. Create a compound index in IndexDB (I'm using dexie.js) for location.lon and location.lng
  3. Query the IndexDB database to find all the features that are inside the visible screen (or add padding if needed)

Basically:

// Create DB:
let db = new Dexie("features");
db.version(1).stores({
    pois: "properties.id,[properties.location.lat+properties.location.lon]"
});
// Adding:
db.table("pois").bulkPut(someGeojsonFeaturesArray);
// Getting:
function getFeatures(northEast, southWest): Promise<GeoJSON.Feature[]> {
        return db.table("pois")
            .where("[properties.location.lat+properties.location.lon]")
            .between([southWest.lat, southWest.lon], [northEast.lat, northEast.lon])
            .toArray();
    }

This works and is scalable but I think tiled data should work faster. Feel free to add your comment to this Github Issue: https://github.com/IsraelHikingMap/Site/issues/1169

See implementation here: https://github.com/IsraelHikingMap/Site/blob/e31e4e73107897c9e069f1426ca9d56f13cf7bff/IsraelHiking.Web/sources/application/services/database.service.ts#L30

Harel M
  • 183
  • 7