diff --git a/js/source/worker.js b/js/source/worker.js index 841984379d6..ecfbb5899e2 100644 --- a/js/source/worker.js +++ b/js/source/worker.js @@ -15,29 +15,28 @@ function Worker(self) { this.self = self; this.actor = new Actor(self, this); - // simple accessor object for passing to WorkerSources - var styleLayers = { - getLayers: function () { return this.layers; }.bind(this), - getLayerFamilies: function () { return this.layerFamilies; }.bind(this) - }; + this.layers = {}; + this.layerFamilies = {}; - this.workerSources = { - vector: new VectorTileWorkerSource(this.actor, styleLayers), - geojson: new GeoJSONWorkerSource(this.actor, styleLayers) + this.workerSourceTypes = { + vector: VectorTileWorkerSource, + geojson: GeoJSONWorkerSource }; + // [mapId][sourceType] => worker source instance + this.workerSources = {}; + this.self.registerWorkerSource = function (name, WorkerSource) { - if (this.workerSources[name]) { + if (this.workerSourceTypes[name]) { throw new Error('Worker source with name "' + name + '" already registered.'); } - this.workerSources[name] = new WorkerSource(this.actor, styleLayers); + this.workerSourceTypes[name] = WorkerSource; }.bind(this); } util.extend(Worker.prototype, { - 'set layers': function(layers) { - this.layers = {}; - var that = this; + 'set layers': function(mapId, layers) { + var styleLayers = this.layers[mapId] = {}; // Filter layers and create an id -> layer map var childLayerIndicies = []; @@ -60,20 +59,21 @@ util.extend(Worker.prototype, { function setLayer(serializedLayer) { var styleLayer = StyleLayer.create( serializedLayer, - serializedLayer.ref && that.layers[serializedLayer.ref] + serializedLayer.ref && styleLayers[serializedLayer.ref] ); styleLayer.updatePaintTransitions({}, {transition: false}); - that.layers[styleLayer.id] = styleLayer; + styleLayers[styleLayer.id] = styleLayer; } - this.layerFamilies = createLayerFamilies(this.layers); + this.layerFamilies[mapId] = createLayerFamilies(this.layers[mapId]); }, - 'update layers': function(layers) { - var that = this; + 'update layers': function(mapId, layers) { var id; var layer; + var styleLayers = this.layers[mapId]; + // Update ref parents for (id in layers) { layer = layers[id]; @@ -87,41 +87,41 @@ util.extend(Worker.prototype, { } function updateLayer(layer) { - var refLayer = that.layers[layer.ref]; - if (that.layers[layer.id]) { - that.layers[layer.id].set(layer, refLayer); + var refLayer = styleLayers[layer.ref]; + if (styleLayers[layer.id]) { + styleLayers[layer.id].set(layer, refLayer); } else { - that.layers[layer.id] = StyleLayer.create(layer, refLayer); + styleLayers[layer.id] = StyleLayer.create(layer, refLayer); } - that.layers[layer.id].updatePaintTransitions({}, {transition: false}); + styleLayers[layer.id].updatePaintTransitions({}, {transition: false}); } - this.layerFamilies = createLayerFamilies(this.layers); + this.layerFamilies[mapId] = createLayerFamilies(this.layers[mapId]); }, - 'load tile': function(params, callback) { + 'load tile': function(mapId, params, callback) { var type = params.type || 'vector'; - this.workerSources[type].loadTile(params, callback); + this.getWorkerSource(mapId, type).loadTile(params, callback); }, - 'reload tile': function(params, callback) { + 'reload tile': function(mapId, params, callback) { var type = params.type || 'vector'; - this.workerSources[type].reloadTile(params, callback); + this.getWorkerSource(mapId, type).reloadTile(params, callback); }, - 'abort tile': function(params) { + 'abort tile': function(mapId, params) { var type = params.type || 'vector'; - this.workerSources[type].abortTile(params); + this.getWorkerSource(mapId, type).abortTile(params); }, - 'remove tile': function(params) { + 'remove tile': function(mapId, params) { var type = params.type || 'vector'; - this.workerSources[type].removeTile(params); + this.getWorkerSource(mapId, type).removeTile(params); }, - 'redo placement': function(params, callback) { + 'redo placement': function(mapId, params, callback) { var type = params.type || 'vector'; - this.workerSources[type].redoPlacement(params, callback); + this.getWorkerSource(mapId, type).redoPlacement(params, callback); }, /** @@ -130,13 +130,28 @@ util.extend(Worker.prototype, { * function taking `(name, workerSourceObject)`. * @private */ - 'load worker source': function(params, callback) { + 'load worker source': function(map, params, callback) { try { this.self.importScripts(params.url); callback(); } catch (e) { callback(e); } + }, + + getWorkerSource: function(mapId, type) { + if (!this.workerSources[mapId]) + this.workerSources[mapId] = {}; + if (!this.workerSources[mapId][type]) { + // simple accessor object for passing to WorkerSources + var styleLayers = { + getLayers: function () { return this.layers[mapId]; }.bind(this), + getLayerFamilies: function () { return this.layerFamilies[mapId]; }.bind(this) + }; + this.workerSources[mapId][type] = new this.workerSourceTypes[type](this.actor, styleLayers); + } + + return this.workerSources[mapId][type]; } }); diff --git a/js/style/style.js b/js/style/style.js index 9641d24825c..6ca6481c572 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -731,7 +731,7 @@ Style.prototype = util.inherit(Evented, { // Callbacks from web workers - 'get sprite json': function(params, callback) { + 'get sprite json': function(_, params, callback) { var sprite = this.sprite; if (sprite.loaded()) { callback(null, { sprite: sprite.data, retina: sprite.retina }); @@ -742,7 +742,7 @@ Style.prototype = util.inherit(Evented, { } }, - 'get icons': function(params, callback) { + 'get icons': function(_, params, callback) { var sprite = this.sprite; var spriteAtlas = this.spriteAtlas; if (sprite.loaded()) { @@ -756,7 +756,7 @@ Style.prototype = util.inherit(Evented, { } }, - 'get glyphs': function(params, callback) { + 'get glyphs': function(_, params, callback) { var stacks = params.stacks, remaining = Object.keys(stacks).length, allGlyphs = {}; diff --git a/js/util/actor.js b/js/util/actor.js index dc09086cfeb..0c0fd9da40c 100644 --- a/js/util/actor.js +++ b/js/util/actor.js @@ -10,11 +10,13 @@ module.exports = Actor; * * @param {WebWorker} target * @param {WebWorker} parent + * @param {string|number} mapId A unique identifier for the Map instance using this Actor. * @private */ -function Actor(target, parent) { +function Actor(target, parent, mapId) { this.target = target; this.parent = parent; + this.mapId = mapId; this.callbacks = {}; this.callbackID = 0; this.receive = this.receive.bind(this); @@ -32,17 +34,19 @@ Actor.prototype.receive = function(message) { if (callback) callback(data.error || null, data.data); } else if (typeof data.id !== 'undefined' && this.parent[data.type]) { // data.type == 'load tile', 'remove tile', etc. - this.parent[data.type](data.data, done.bind(this)); - } else if (typeof data.id !== 'undefined' && this.parent.workerSources) { + this.parent[data.type](data.mapId, data.data, done.bind(this)); + } else if (typeof data.id !== 'undefined' && this.parent.getWorkerSource) { // data.type == sourcetype.method var keys = data.type.split('.'); - this.parent.workerSources[keys[0]][keys[1]](data.data, done.bind(this)); + var workerSource = this.parent.getWorkerSource(data.mapId, keys[0]); + workerSource[keys[1]](data.data, done.bind(this)); } else { this.parent[data.type](data.data); } function done(err, data, buffers) { this.postMessage({ + mapId: this.mapId, type: '', id: String(id), error: err ? String(err) : null, @@ -54,7 +58,7 @@ Actor.prototype.receive = function(message) { Actor.prototype.send = function(type, data, callback, buffers) { var id = null; if (callback) this.callbacks[id = this.callbackID++] = callback; - this.postMessage({ type: type, id: String(id), data: data }, buffers); + this.postMessage({ mapId: this.mapId, type: type, id: String(id), data: data }, buffers); }; /** diff --git a/js/util/dispatcher.js b/js/util/dispatcher.js index 7ca9bd7c367..cc7a9206e9b 100644 --- a/js/util/dispatcher.js +++ b/js/util/dispatcher.js @@ -16,9 +16,10 @@ module.exports = Dispatcher; function Dispatcher(length, parent) { this.actors = []; this.currentActor = 0; + this.id = util.uniqueId(); for (var i = 0; i < length; i++) { var worker = new WebWorker(); - var actor = new Actor(worker, parent); + var actor = new Actor(worker, parent, this.id); actor.name = "Worker " + i; this.actors.push(actor); }