Vector tiles standards
This guide on vector tile standards explains how data is stored and encoded in vector tiles.
Just as applications make assumptions about what information exists in a database, so do Mapbox tools make assumptions about how vector tiles store geographic information. Understanding these standards can help you understand how to work with Mapbox vector tiles.
This guide covers file format, examples of geometry encoding and attribute encoding, an explanation of the importance of winding order, and a list of concepts not included in the Mapbox vector tile specification.
For information about file formats and extensions, projections and bounds, and the internal structure of vector tiles, you can read the Mapbox Vector Tile Specification on GitHub.
Format
Vector tiles are encoded as Google Protobufs (PBF), which allow for serializing structured data. For clarity, Mapbox Vector Tiles use the .mvt
file suffix. The specification details are largely structured around the rules implemented in the base .proto
file.
Mapbox Vector Tiles are not related at all to OpenStreetMap PBF files. PBFs are a format, much like XML and can take many forms. Mapbox Vector Tiles and OpenStreetMap PBFs are protobuf files, but conform to completely different specifications and are used in different ways.
Encoding geometry
To encode geographic information into a vector tile a tool must convert geographic coordinates, such as latitude and longitude, into vector tile grid coordinates. Vector tiles hold no concept of geographic information. They encode points, lines, and polygons as x
/y
pairs relative to the top left of the grid in a right-down manner.
This is a step-by-step example showing how a single vector tile encodes geometry in the grid. It follows the commands of the "pen" to encode two rings.
Encoding attributes
Attributes are encoded in a series of tag
s that exist within a feature in the vector that have integer values that reference keys
and values
designating the original key:value pairs from the geometry. For large geometry, this removes redundancy for attributes that have the same keys and similar values.
Take a look at the original GeoJSON FeatureCollection
on the left and see how its individual parts are encoded into the proper tags
of the vector tile protobuf.
Hover over the features and the properties of the GeoJSON.
Original geojson
{"type": "FeatureCollection", "features": []}{"geometry": { ... }, "type": "Feature", "properties": {},}"hello": "world","h": "world","count": 1.23{"geometry": { ... }, "type": "Feature", "properties": {}}"hello": "again","count": 2
Final vector tile
Winding order
Winding order refers to the direction the vector tile draws a ring, either clockwise or counter-clockwise. Many geometries are multipolygons with "holes," which are also represented as polygon rings. It is important to be able to infer winding order to extract source data from a vector tile and understand if the geometry is part of a multipolygon or a unique polygon.
Extracting the original data from images has been difficult on maps in the past, because of the loss of underlying metadata from the geometry that might have been used to create the image. Yet, with the introduction of client side rendering of vector tiles via GL technologies, the raw geometry data has become useful for a source of information outside of rendering.
For renderers to appropriately distinguish which polygons are holes and which are unique geometries, the specification requires all polygons to be valid (OGC validity). Any polygon interior ring must be oriented with the winding order opposite that of their parent exterior ring and all interior rings must directly follow the exterior ring to which they belong. Exterior rings must be oriented clockwise and interior rings must be oriented counter-clockwise (when viewed in screen coordinates).
The following example geometries show how encoding a ring's winding order can affect the rendered result. Each example assumes all rings are part of the same multipolygon.
Note: the Y
axis is positive-downward in vector tile coordinates!
A single ring, in clockwise order is rendered as a single, solid polygon.
Ring 1: Clockwise
Two rings with the same winding order will render as two unique polygons overlapping.
Ring 1: Clockwise Ring 2: Clockwise
Two rings, the first (exterior) ring is in clockwise order, while the second is counter-clockwise. This results in a "hole" in the final render.
Ring 1: Clockwise Ring 2: Counter-Clockwise
Three rings in a multipolygon that alternate winding order.
Ring 1: Clockwise Ring 2: Counter-Clockwise Ring 3: Clockwise
Implementations
Implementations of the Mapbox Vector Tile Specification are far and wide. Many of them fall into one of the following categories:
- Parsers & generators: libraries that read and/or encode vector tiles, some also have command line utilities
- Clients: web-based tools that render vector tiles that conform to the specification
- Applications: browser-based tools for creating and visualizing vector tiles
- Servers: support rendering and serving up vector tiles (note: the specification doesn't go into how to do this explicitly)
Visit Mapbox Vector Tiles for a list of tools implementing vector tiles.
What the spec doesn't cover
This specification is explicit in the way a vector tile should pack data. But, there are some related concepts that this specification does not cover.
How to use vector tiles as a dataset
This specification IS NOT intended to explain how to use vector tiles as a dataset. This is something that has been considered for the future, but it will likely be a separate specification. This specification does not cover how to store, request, or share vector tiles. Consider this specification like how the PNG spec explains how to pack data.
How to encode attributes that aren't strings or numbers
Attributes in geometric data, such as the properties
object in GeoJSON can include more than strings and numbers. They can be arrays or objects. The specification doesn't cover how to encode these values and is up to the encoder to decide. Tools like Mapnik will turn arrays and objects into strings, which requires the decoder to parse them. For example, if you had a GeoJSON property called categories
and it was an array:
"categories": ["one", "two", "three"]
It would be converted into a string and stored in the protobuf like this:
keys: "categories"
values: {
string_value: "[\"one\",\"two\",\"three\"]"
}
Clipping
The specification does not explain how geographic data should be clipped between vector tiles since clipping, like simplification, can be executed in many ways. Mapbox specifically clips features at a buffer around the tile (see the encoding example above). Any geometry within this buffer is assumed to carry over to another tile. This is up for consideration for a future release.
Note: encoded geometry in vector tiles can extend beyond the bound of the tile. This means features are not required to be clipped.
A common question, when it comes to clipping is "how do renderers know which lines to connect for clipped geometry?". This is the reason Mapbox adds a buffer to vector tiles and clipped geometry. When it is time to render, Mapbox sets the canvas to the exact tile size, which sets the edges outside of the visual frame, thus the tiles all line up. So, there is no need to know which nodes are part of others for rendering purposes. Although, you could use the id
field in the protobuf to store information necessary for reconstructing polygons.
Simplification
The conversion from geographic coordinates (latitude and longitude) to vector tile coordinates (x, y) is an important step, but can be implemented in many different ways before vector tile encoding. It is not included in this specification, but there are some important GOTCHAs worth noting.
Simplification can cause invalid polygons according to the OGC standards by oversimplifying polygon rings to the point where their edges overlap. See below how simplifying one line changes the rendering of a polygon by pushing the interior ring outside of the exterior ring.
When spatial coordinates are converted to tile coordinates, they are rounded to integers. Simplifying (rounding) the coordinates can reverse the winding order. Consider a triangle polygon that is simplified to the vector tile grid. The rounded point can cross over the polygon and "flip" it, rendering its winding order reversed.