JavaScript library for parsing Mapbox Vector Tiles and accessing layers and features
npx @tessl/cli install tessl/npm-mapbox--vector-tile@2.0.0Vector Tile is a JavaScript library for parsing Mapbox Vector Tiles and accessing their layers and features. It provides a straightforward API for loading vector tile data from Protobuf format, extracting individual layers, iterating through features, and accessing geometry and properties with GeoJSON conversion support.
npm install @mapbox/vector-tileimport { VectorTile } from '@mapbox/vector-tile';For accessing all exports:
import { VectorTile, VectorTileLayer, VectorTileFeature, classifyRings } from '@mapbox/vector-tile';For CommonJS environments:
const { VectorTile, VectorTileLayer, VectorTileFeature } = require('@mapbox/vector-tile');import { VectorTile } from '@mapbox/vector-tile';
import Protobuf from 'pbf';
// Parse a vector tile from binary data
const tile = new VectorTile(new Protobuf(data));
// Access layers by name
const landuse = tile.layers.landuse;
// Get number of features in layer
console.log(landuse.length);
// Access individual features
const feature = landuse.feature(0);
// Get feature properties
console.log(feature.properties);
console.log(feature.type); // 0, 1, 2, or 3
console.log(VectorTileFeature.types[feature.type]); // "Unknown", "Point", "LineString", "Polygon"
// Load geometry as Point arrays from @mapbox/point-geometry
const geometry = feature.loadGeometry();
console.log(geometry); // Array of Point arrays
// Get bounding box
const bbox = feature.bbox(); // [x1, y1, x2, y2]
// Convert to GeoJSON (requires tile coordinates)
const geoJSON = feature.toGeoJSON(8801, 5371, 14);For gzip-encoded tiles (common in serialtiles-spec):
import { VectorTile } from '@mapbox/vector-tile';
import Protobuf from 'pbf';
import { gunzipSync } from 'zlib';
const buffer = gunzipSync(data);
const tile = new VectorTile(new Protobuf(buffer));Working with different geometry types:
// Iterate through all features in a layer
for (let i = 0; i < layer.length; i++) {
const feature = layer.feature(i);
switch (feature.type) {
case 1: // Point
console.log('Point feature:', feature.properties);
break;
case 2: // LineString
console.log('LineString feature:', feature.properties);
break;
case 3: // Polygon
console.log('Polygon feature:', feature.properties);
break;
}
// Convert any feature to GeoJSON
const geoJSON = feature.toGeoJSON(x, y, z);
}
// Use classifyRings for polygon processing
import { classifyRings } from '@mapbox/vector-tile';
const rings = feature.loadGeometry();
const polygons = classifyRings(rings);Vector Tile is built around three main components:
The library uses lazy parsing - geometry is only decoded when explicitly requested through loadGeometry().
Parse binary vector tiles from Protobuf format and access contained layers.
/**
* Main class for parsing vector tile data
*/
class VectorTile {
/**
* Parses vector tile data from Protobuf object
* @param pbf - Protobuf parser instance
* @param end - Optional end position for parsing
*/
constructor(pbf: Protobuf, end?: number);
/** Object containing all parsed layers by name */
layers: Record<string, VectorTileLayer>;
}Access and iterate through layers within a vector tile.
/**
* Represents a single vector tile layer
*/
class VectorTileLayer {
/**
* Creates layer from Protobuf data
* @param pbf - Protobuf parser instance
* @param end - Optional end position for parsing
*/
constructor(pbf: Protobuf, end?: number);
/** Layer version number (default: 1) */
version: number;
/** Layer name */
name: string;
/** Tile extent size (default: 4096) */
extent: number;
/** Number of features in the layer */
length: number;
/**
* Get feature by index from the layer
* @param i - Feature index (0-based)
* @returns Feature at the specified index
* @throws Error if index is out of bounds
*/
feature(i: number): VectorTileFeature;
}Access feature data, geometry, and properties with conversion capabilities.
/**
* Represents a single feature with geometry and properties
*/
class VectorTileFeature {
/**
* Creates feature from Protobuf data
* @param pbf - Protobuf parser instance
* @param end - End position for parsing
* @param extent - Feature extent size
* @param keys - Property keys array
* @param values - Property values array
*/
constructor(
pbf: Protobuf,
end: number,
extent: number,
keys: string[],
values: (number | string | boolean)[]
);
/** Feature properties object */
properties: Record<string, number | string | boolean>;
/** Feature extent size */
extent: number;
/** Feature type: 0=Unknown, 1=Point, 2=LineString, 3=Polygon */
type: 0 | 1 | 2 | 3;
/** Feature identifier if present */
id: number | undefined;
/**
* Parses and returns feature geometry as Point arrays
* @returns Array of Point arrays representing the geometry
* @throws Error for unknown geometry commands
*/
loadGeometry(): Point[][];
/**
* Calculates and returns bounding box of the feature
* @returns Bounding box as [x1, y1, x2, y2]
*/
bbox(): [number, number, number, number];
/**
* Converts feature to GeoJSON representation
* @param x - Tile X coordinate
* @param y - Tile Y coordinate
* @param z - Tile zoom level
* @returns GeoJSON Feature object
* @throws Error for unknown feature types
*/
toGeoJSON(x: number, y: number, z: number): GeoJSONFeature;
/** Static array mapping type numbers to names */
static types: ['Unknown', 'Point', 'LineString', 'Polygon'];
}Utility functions for processing vector tile geometry data.
/**
* Classifies array of rings into polygons with outer rings and holes
* @param rings - Array of Point arrays representing rings
* @returns Array of polygons, each containing arrays of rings
*/
function classifyRings(rings: Point[][]): Point[][][];/**
* Point geometry from @mapbox/point-geometry package
*/
interface Point {
/** X coordinate in tile coordinate space */
x: number;
/** Y coordinate in tile coordinate space */
y: number;
/** Creates a copy of this point */
clone(): Point;
}
/**
* Protobuf parser from pbf package used for reading binary vector tile data
*/
interface Protobuf {
/** Current position in the buffer */
pos: number;
/** Read structured fields using a callback function */
readFields(fn: (tag: number, obj: any, pbf: Protobuf) => void, obj: any, end?: number): any;
/** Read variable-length integer */
readVarint(): number;
/** Read signed variable-length integer */
readSVarint(): number;
/** Read UTF-8 string */
readString(): string;
/** Read 32-bit float */
readFloat(): number;
/** Read 64-bit double */
readDouble(): number;
/** Read 64-bit variable-length integer */
readVarint64(): number;
/** Read boolean value */
readBoolean(): boolean;
}
/**
* GeoJSON Feature interface from @types/geojson
*/
interface GeoJSONFeature {
type: 'Feature';
geometry: GeoJSONGeometry;
properties: Record<string, any>;
id?: number | string;
}
interface GeoJSONGeometry {
type: 'Point' | 'MultiPoint' | 'LineString' | 'MultiLineString' | 'Polygon' | 'MultiPolygon';
coordinates: any[];
}The library throws errors in several scenarios:
Error with message "feature index out of bounds" when i < 0 or i >= layer.lengthError with message "unknown command {cmd}" for invalid geometry commands (valid commands: 1=MoveTo, 2=LineTo, 7=ClosePath)Error with message "unknown command {cmd}" for invalid geometry commands during bounding box calculationError with message "unknown feature type" for invalid feature.type valuesError with message "unknown feature value" when Protobuf value parsing failsExample error handling:
try {
// Safely access features with bounds checking
if (i >= 0 && i < layer.length) {
const feature = layer.feature(i);
const geometry = feature.loadGeometry(); // May throw for corrupted geometry data
const bbox = feature.bbox(); // May throw for corrupted geometry data
const geoJSON = feature.toGeoJSON(x, y, z); // May throw for unknown feature types
}
} catch (error) {
console.error('Vector tile processing error:', error.message);
// Handle specific error types
if (error.message.includes('unknown command')) {
console.error('Corrupted geometry data detected');
} else if (error.message.includes('feature index out of bounds')) {
console.error('Invalid feature index');
}
}