s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
132 lines (131 loc) • 5.49 kB
JavaScript
import ProcessManager from './process/index.js';
import { VectorTile } from 'open-vector-tile';
import { rebuildVectorTile } from './process/util/rebuildVectorTile.js';
/**
* # Tile Worker
*
* A TileWorker has one job: prebuild tile data for the WebGL / WebGPU instance
* During construction, the tileworker is given the map's id to send the data to the correct recepient
* and also the style sheet to build the proper source data
*
* A TileWorker maintains map references to know how and who to send data back to
*/
export default class TileWorker extends ProcessManager {
/**
* Given a tile message, process it according to its type
* @param tileMessage - the tile message
*/
onMessage(tileMessage) {
const { data, ports } = tileMessage;
const { type } = data;
if (type === 'port')
this.#loadWorkerPort(ports[0], ports[1], data.id, data.totalWorkers);
else {
const { mapID } = data;
if (type === 'style')
this.#loadStyle(mapID, data.style);
else if (type === 'vector')
void this.processVector(mapID, data.tile, data.sourceName, new VectorTile(new Uint8Array(data.data)));
else if (type === 'raster')
this.processRaster(mapID, data.tile, data.sourceName, data.data, data.size);
else if (type === 'jsondata')
this.#processJSONData(mapID, data.tile, data.sourceName, data.data);
else if (type === 'glyphmetadata')
this.processMetadata(mapID, data.glyphMetadata, data.imageMetadata);
else if (type === 'glyphresponse')
this.processGlyphResponse(mapID, data.reqID, data.glyphMetadata, data.familyName);
else if (type === 'addLayer')
this.#addLayer(mapID, data.layer, data.index);
else if (type === 'deleteLayer')
this.#deleteLayer(mapID, data.index);
else if (type === 'reorderLayers')
this.#reorderLayers(mapID, data.layerChanges);
}
}
/**
* Load a message channel with the source worker
* @param messagePort - the message port to recieve messages from the source worker
* @param postPort - the post port to talk to the source worker
* @param id - the worker id
* @param totalWorkers - the total number of tile workers
*/
#loadWorkerPort(messagePort, postPort, id, totalWorkers) {
// maintain communication channel with source worker
messagePort.onmessage = this.onMessage.bind(this);
this.sourceWorker = postPort; // Source Worker
this.messagePort = messagePort; // WorkerPool
this.id = id;
this._buildIDGen(totalWorkers);
}
/**
* pull in the layers and preprocess them
* @param mapID - the map id to build data for
* @param style - the style package associated with the map
*/
#loadStyle(mapID, style) {
this.setupStyle(mapID, style);
}
/**
* Add a new style layer to a map
* @param _mapID - the map id to add the layer to
* @param _layer - the layer to add
* @param _index - the index to add it at
*/
#addLayer(_mapID, _layer, _index) {
// const layers = this.maps[mapID]
// layers.splice(index, 0, layer)
// for (let i = index + 1, ll = layers.length; i < ll; i++) {
// const layer = layers[i]
// layer.layerIndex++
// }
}
/**
* Delete a style layer from a map
* @param _mapID - the map id to delete the layer from
* @param _index - the index to delete
*/
#deleteLayer(_mapID, _index) {
// const layers = this.maps[mapID]
// layers.splice(index, 1)
// for (let i = index, ll = layers.length; i < ll; i++) {
// const layer = layers[i]
// layer.layerIndex--
// }
}
/**
* Reorder style layers
* @param _mapID - the map id to reorder
* @param _layerChanges - the layer changes
*/
#reorderLayers(_mapID, _layerChanges) {
// const layers = this.maps[mapID]
// const newLayers: LayerDefinition[] = []
// // move the layer to its new position
// for (const [from, to] of Object.entries<number>(layerChanges)) {
// const layer = layers[+from]
// layer.layerIndex = to
// newLayers[to] = layer
// }
// // because other classes depend upon the current array, we just update array items
// for (let i = 0; i < layers.length; i++) layers[i] = newLayers[i]
}
/**
* Process vector data
* @param mapID - the map id to build data for
* @param tile - the tile request associated with the data
* @param sourceName - the name of the source the data to belongs to
* @param data - the tile vector data
*/
#processJSONData(mapID, tile, sourceName, data) {
// step 1: convert data to a JSON object
const vectorTile = JSON.parse(this.textDecoder.decode(new Uint8Array(data)));
// step 2: build functions back into the vector tile and its layers & features
rebuildVectorTile(vectorTile);
// step 3: process the vector data
void this.processVector(mapID, tile, sourceName, vectorTile);
}
}
// create the tileworker
const tileWorker = new TileWorker();
// expose and bind the onmessage function
self.onmessage = tileWorker.onMessage.bind(tileWorker);