Skip to main content

GeoJSON Vector Tiling

GeoJSONVectorTileDataSource turns app-owned GeoJSON into vector tiles a VectorTileLayer styles with CartoCSS — so routes, tracks and result sets get the same renderer, styling and terrain draping as the base map, instead of the VectorLayer element path.

Fork feature

The source exists upstream; the fork rebuilt its tiler on geojson-vt (PR #54) — a real tile pyramid instead of a per-tile scan of every feature.

Add a GeoJSON line, running live on the web SDK. The code →

Usage​

import com.massifmaps.datasources.GeoJSONVectorTileDataSource
import com.massifmaps.layers.VectorTileLayer

val source = GeoJSONVectorTileDataSource(0, 24).apply {
simplifyTolerance = 1.0f // tile pixels
defaultLayerBuffer = 4f // tile pixels, for layers created afterwards
}

val routes = source.createLayer("routes") // returns the layer index
source.setLayerGeoJSONString(routes, geoJsonText) // or setLayerGeoJSON(Variant) / setLayerFeatureCollection

mapView.layers.add(VectorTileLayer(source, MBVectorTileDecoder(styleSet)))

With the surface API​

// The source re-tiles whatever it is given, so an update is one call rather than a rebuild.
MassifSource tour = map.source("tour-data", Spec.of("geojson").set("maxZoom", 14));
int layer = tour.createLayer("tour");
tour.setLayerGeoJSON(layer, routeGeoJson);

map.addLayer("tour", Spec.of("vector")
.set("source", "tour-data")
.set("style", "route-style"));

addFeature, updateFeature and removeFeature are reachable the same way, so incremental edits need no object-API access either. Runnable, on four platforms (live on the web): the GeoJSON line example.

Style it by layer name, like any other vector source:

#routes { line-color: #3388ff; line-width: 5; line-join: round; line-cap: round; }
MethodDoes
createLayer(name) / deleteLayer(index)add / drop a named layer
setLayerGeoJSON / setLayerGeoJSONStringreplace a layer's whole content, from a FeatureCollection or a single Feature
setLayerFeatureCollection(index, projection, collection)replace it from SDK geometry
addGeoJSONFeature / updateGeoJSONFeature / removeGeoJSONFeatureincremental edits (also …StringFeature)
SimplifyToleranceDouglas-Peucker tolerance, in tile pixels
DefaultLayerBuffertile overflow, in tile pixels of a 256-px tile (default 4); applies to layers created afterwards

Why it changed​

The old tiler scanned every feature of a layer for every tile, and kept one re-simplified copy of the dataset per zoom level. Long lines were the worst case: re-clipped from full resolution on every tile they touched. The geojson-vt pyramid clips once per level from the parent.

Measured on a device (Adreno 610), 640 tiles z8–z17:

DatasetBeforeAfter
8 routes of 100–250 km (303k points)1709 ms513 ms
5000 short routes (165k points)1319 ms1176 ms

Known regression, documented rather than fixed: many small features at a single zoom are 1.6× slower (209 → 328 ms over 256 tiles at z14).

Binary cost: +104 KiB on libmassif.so (arm64-v8a, stripped) — header-only template instantiation, nothing new linked.

See also​