UNPKG

@loaders.gl/mvt

Version:

Loader for Mapbox Vector Tiles

130 lines 4.3 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright vis.gl contributors import * as MVT from "./mvt-constants.js"; export function writeMVT(tile, pbf) { for (const key in tile.layers) { const context = { layer: tile.layers[key], keys: [], values: [], keycache: {}, valuecache: {} }; pbf.writeMessage(MVT.TileInfo.layers, writeLayer, context); } } function writeLayer(context, pbf) { const { layer } = context; pbf.writeVarintField(MVT.LayerInfo.version, layer.version || 1); pbf.writeStringField(MVT.LayerInfo.name, layer.name || ''); pbf.writeVarintField(MVT.LayerInfo.extent, layer.extent || 4096); for (let i = 0; i < layer.length; i++) { context.feature = layer.feature(i); pbf.writeMessage(MVT.LayerInfo.features, writeFeature, context); } const keys = context.keys; for (let i = 0; i < keys.length; i++) { pbf.writeStringField(MVT.LayerInfo.keys, keys[i]); } const values = context.values; for (let i = 0; i < values.length; i++) { pbf.writeMessage(MVT.LayerInfo.values, writeValue, values[i]); } } function writeFeature(context, pbf) { const feature = context.feature; if (feature.id !== undefined) { pbf.writeVarintField(MVT.FeatureInfo.id, feature.id); } pbf.writeMessage(MVT.FeatureInfo.tags, writeProperties, context); pbf.writeVarintField(MVT.FeatureInfo.type, feature.type); pbf.writeMessage(MVT.FeatureInfo.geometry, writeGeometry, feature); } function writeProperties(context, pbf) { const feature = context.feature; const { keys, values, keycache, valuecache } = context; for (const key in feature.properties) { let keyIndex = keycache[key]; if (typeof keyIndex === 'undefined') { keys.push(key); keyIndex = keys.length - 1; keycache[key] = keyIndex; } pbf.writeVarint(keyIndex); let value = feature.properties[key]; const type = typeof value; if (type !== 'string' && type !== 'boolean' && type !== 'number') { value = JSON.stringify(value); } const valueKey = `${type}:${value}`; let valueIndex = valuecache[valueKey]; if (typeof valueIndex === 'undefined') { values.push(value); valueIndex = values.length - 1; valuecache[valueKey] = valueIndex; } pbf.writeVarint(valueIndex); } } function command(cmd, length) { return (length << 3) + (cmd & 0x7); } function zigzag(num) { return (num << 1) ^ (num >> 31); } function writeGeometry(feature, pbf) { const geometry = feature.loadGeometry(); const type = feature.type; let x = 0; let y = 0; const rings = geometry.length; for (let r = 0; r < rings; r++) { const ring = geometry[r]; let count = 1; if (type === 1) { count = ring.length; } pbf.writeVarint(command(1, count)); // moveto // do not write polygon closing path as lineto const lineCount = type === 3 ? ring.length - 1 : ring.length; for (let i = 0; i < lineCount; i++) { if (i === 1 && type !== 1) { pbf.writeVarint(command(2, lineCount - 1)); // lineto } const dx = ring[i].x - x; const dy = ring[i].y - y; pbf.writeVarint(zigzag(dx)); pbf.writeVarint(zigzag(dy)); x += dx; y += dy; } if (type === 3) { pbf.writeVarint(command(7, 1)); // closepath } } } function writeValue(value, pbf) { switch (typeof value) { case 'string': pbf.writeStringField(1, value); break; case 'boolean': pbf.writeBooleanField(7, value); break; case 'number': if (value % 1 !== 0) { pbf.writeDoubleField(3, value); } else if (value < 0) { pbf.writeSVarintField(6, value); } else { pbf.writeVarintField(5, value); } break; default: // ignore } } //# sourceMappingURL=write-mvt-to-pbf.js.map