Skip to content

TileJsonPlugin

TileJsonPlugin fetches a TileJSON 3.0.0 document and registers it as a single Navara source. Instead of hand-copying a tile URL template, zoom range, and attribution into view.addSource(), you point the plugin at the document URL and it derives those fields for you.

addSource() mirrors ThreeView.addSource: you pass a discriminated type plus an optional id, with url pointing at the TileJSON document rather than at a tile template.

The document’s attribution credit is surfaced through the view’s built-in attribution UI (view.attribution) automatically.

TileJSON has no field that reliably distinguishes raster imagery from vector or elevation tiles, so the target source type ("raster-tile", "vector-tile", or "raster-dem") is declared by the caller.

To build a custom credit UI instead, opt out of the built-in one (new ThreeView({ defaultAttribution: false })) and read each document’s attribution from the loaded event.

import ThreeView from "@navaramap/three";
import { DefaultPlugin } from "@navaramap/three-default-plugin";
import { TileJsonPlugin } from "@navaramap/three-plugins";
const view = new ThreeView({ container });
const tilejson = new TileJsonPlugin();
view.addPlugin(new DefaultPlugin());
view.addPlugin(tilejson);
await view.init();
// Fetch a TileJSON document and register it as a raster source. The document's
// `minzoom` / `maxzoom` / `scheme` are forwarded to the source, and its
// `attribution` is shown by the built-in attribution UI.
const source = await tilejson.addSource({
type: "raster-tile",
id: "basemap",
url: "https://example.com/tiles.json",
});
// Reference the source by the returned handle...
view.addLayer({ type: "raster", source });
// ...or directly by id.
view.addLayer({ type: "raster", source: "basemap" });
const dem = await tilejson.addSource({
type: "raster-dem",
url: "https://example.com/terrain.json",
});
view.addLayer({ type: "terrain", source: dem });
new TileJsonPlugin();

Register the plugin with view.addPlugin() before view.init(). The constructor takes no options: attribution is handled through the view’s built-in UI, and callers who want a custom UI subscribe to the loaded event.

addSource(desc: TileJsonSourceDescription): Promise<Source>

Fetches the TileJSON document at desc.url, then creates one source of the requested desc.type from it. Must be called after view.init(). Otherwise the call throws.

The mapping from the document to the created source is:

TileJSON fieldraster-tile sourceraster-dem sourcevector-tile source
tiles[0]urlurlurl
minzoomminZoomminZoom(engine has no field)
maxzoommaxZoommaxZoommaxZoom
scheme: "tms"tms: truetms: true(engine has no field)
tileSizetileSize (default 512)
encodingelevationDecoder (default "mapbox")
attributionshown via view.attributionshown via view.attributionshown via view.attribution

Every field in the table except tiles[0] and attribution can also be set on desc under the same name. A field set there takes precedence over the fetched document. For raster-dem, encoding selects the elevation decoder ("mapbox" or "terrarium"), and an unknown encoding rejects the call rather than creating a source with a wrong decoder.

A TileJSON tiles array may list several mirror endpoints for the same tileset. Navara sources take a single URL, so only the first endpoint is used. Any extra endpoints are ignored with a console.warn.

attribution credit is added to the view’s built-in attribution UI (view.attribution). Credits from multiple addSource() calls are de-duplicated, so a shared or repeated credit renders once. When the built-in UI is disabled (defaultAttribution: false), this step is skipped. Read the attribution from the loaded event instead.

After the source is registered, a loaded event fires with the created source, the parsed document, and its attribution.

Returns the created Source handle. Layers can reference it either by the returned handle or by desc.id.

on<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void
once<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void
off<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void

Subscribe to, subscribe once to, or unsubscribe from a plugin event. See loaded for the payload.

dispose(): void

Removes the credits this plugin contributed to view.attribution (matched structurally by their HTML) and drops all event listeners. The built-in UI is owned by the view, not the plugin, so only this plugin’s own credits are removed, not the whole UI. When the view is disposed first, view.attribution is already gone and this is a no-op.

Subscribe with on / once and unsubscribe with off.

Fires once per successful addSource(), after the source is registered. Its payload lets callers drive a custom credit UI without relying on the built-in one.

PropertyTypeDescription
sourceSourceThe Navara source created for the document.
tilejsonTileJsonThe fetched and validated TileJSON document.
attributionstring | undefinedThe document’s attribution HTML, when it declares one.
const view = new ThreeView({ container, defaultAttribution: false });
const tilejson = new TileJsonPlugin();
view.addPlugin(tilejson);
await view.init();
tilejson.on("loaded", ({ source, attribution }) => {
if (attribution) renderMyCredit(source.id, attribution);
});
type TileJsonSourceType = "raster-tile" | "vector-tile" | "raster-dem";

Which Navara source type a TileJSON document is materialized into. Declared by the caller because TileJSON has no field that reliably distinguishes raster imagery from vector or elevation tiles.

type TileJsonSourceDescription =
| TileJsonRasterTileSourceDescription
| TileJsonVectorTileSourceDescription
| TileJsonRasterDemSourceDescription;

A discriminated union over type. Every variant shares the fields below. A field marked “overrides the document” is optional and, when set, takes precedence over the fetched document’s value of the same name.

PropertyTypeDescription
typeTileJsonSourceTypeNavara source type to create, as in addSource.
urlstringURL of the TileJSON 3.0.0 document to fetch and expand (not a tile template).
idstring | undefinedOptional caller-provided source id. Handy for referencing the source from layers by id without holding the returned handle. When omitted, the engine generates one.
minzoomnumber | undefinedOverrides the document’s minzoom.
maxzoomnumber | undefinedOverrides the document’s maxzoom.
scheme"xyz" | "tms" | undefinedOverrides the document’s scheme.

The raster-dem variant (TileJsonRasterDemSourceDescription) additionally accepts:

PropertyTypeDescription
tileSizenumber | undefinedOverrides the document’s tileSize. Defaults to 512.
encodingTileJsonDemEncoding | undefinedOverrides the document’s encoding. Defaults to "mapbox".
type TileJsonDemEncoding = "mapbox" | "terrarium";

How a raster-dem document’s RGB tiles encode elevation, matching MapLibre’s encoding values. MapLibre’s "custom" (free-form decode factors) is not supported.

Payload of the loaded event. See the table above.

The subset of a TileJSON 3.0.0 document this plugin consumes. Other spec fields (bounds, center, grids, …) are ignored.

PropertyTypeDefaultDescription
tilejsonstringSemver of the TileJSON spec the document conforms to, e.g. "3.0.0". Required.
tilesstring[]Tile URL templates ({z}/{x}/{y}). Required and non-empty per the spec.
attributionstring | undefinedAttribution / credit HTML shown through the view’s built-in attribution UI.
minzoomnumber | undefined0Minimum zoom level. Applied to raster sources only.
maxzoomnumber | undefined30Maximum zoom level.
scheme"xyz" | "tms""xyz"Tiling scheme. "tms" flips the Y axis (raster sources only).
tileSizenumber | undefined512Tile size in pixels. Not part of the TileJSON spec, but emitted by MapLibre-oriented tile servers. Applied to raster-dem sources only.
encodingTileJsonDemEncoding | undefined"mapbox"Elevation encoding of DEM tiles. Not part of the TileJSON spec, but emitted by MapLibre-oriented tile servers. Applied to raster-dem sources only.

The document is validated when fetched: addSource() rejects if tilejson is missing or is not a major.minor.patch version, or if tiles is missing or empty.

  • The document URL, not a tile template. desc.url is the address of the TileJSON JSON document. The tile URL template comes from the document’s tiles field. Don’t pass a {z}/{x}/{y} template here.
  • The source type is your choice. TileJSON does not mark a tileset as raster imagery, vector, or elevation data, so pick "raster-tile", "vector-tile", or "raster-dem" to match the tiles the document serves.
  • Vector sources ignore minzoom and scheme. The engine’s vector-tile source has no minZoom or tms field, so only maxzoom carries over for "vector-tile".
  • tileSize and encoding are MapLibre extensions. They are not part of the TileJSON spec, but MapLibre-oriented DEM tile servers commonly include them, and the defaults (512 / "mapbox") match MapLibre’s. An encoding other than "mapbox" or "terrarium" rejects addSource().