mapbox-gl
Version:
A WebGL interactive maps library
179 lines (147 loc) • 4.83 kB
JavaScript
'use strict';
var util = require('../util/util');
var Evented = require('../util/evented');
var TilePyramid = require('./tile_pyramid');
var Source = require('./source');
var urlResolve = require('resolve-url');
module.exports = GeoJSONSource;
/**
* Create a GeoJSON data source instance given an options object
* @class GeoJSONSource
* @param {Object} [options]
* @param {Object|string} options.data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.
* @param {number} [options.maxzoom=14] Maximum zoom to preserve detail at.
* @example
* var sourceObj = new mapboxgl.GeoJSONSource({
* data: {
* "type": "FeatureCollection",
* "features": [{
* "type": "Feature",
* "geometry": {
* "type": "Point",
* "coordinates": [
* -76.53063297271729,
* 39.18174077994108
* ]
* }
* }]
* }
* });
* map.addSource('some id', sourceObj); // add
* map.removeSource('some id'); // remove
*/
function GeoJSONSource(options) {
options = options || {};
this._data = options.data;
if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom;
this._pyramid = new TilePyramid({
tileSize: 512,
minzoom: this.minzoom,
maxzoom: this.maxzoom,
cacheSize: 20,
load: this._loadTile.bind(this),
abort: this._abortTile.bind(this),
unload: this._unloadTile.bind(this),
add: this._addTile.bind(this),
remove: this._removeTile.bind(this)
});
}
GeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototype */{
minzoom: 0,
maxzoom: 14,
_dirty: true,
/**
* Update source geojson data and rerender map
*
* @param {Object|string} data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.
* @returns {GeoJSONSource} this
*/
setData: function(data) {
this._data = data;
this._dirty = true;
this.fire('change');
if (this.map)
this.update(this.map.transform);
return this;
},
onAdd: function(map) {
this.map = map;
},
loaded: function() {
return this._loaded && this._pyramid.loaded();
},
update: function(transform) {
if (this._dirty) {
this._updateData();
}
if (this._loaded) {
this._pyramid.update(this.used, transform);
}
},
reload: function() {
this._pyramid.reload();
},
render: Source._renderTiles,
featuresAt: Source._vectorFeaturesAt,
_updateData: function() {
this._dirty = false;
var data = this._data;
if (typeof data === 'string') {
data = urlResolve(window.location.href, data);
}
this.workerID = this.dispatcher.send('parse geojson', {
data: data,
tileSize: 512,
source: this.id,
maxZoom: this.maxzoom
}, function(err) {
if (err) {
this.fire('error', {error: err});
return;
}
this._loaded = true;
this._pyramid.reload();
this.fire('change');
}.bind(this));
},
_loadTile: function(tile) {
var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1;
var params = {
uid: tile.uid,
coord: tile.coord,
zoom: tile.coord.z,
maxZoom: this.maxzoom,
tileSize: 512,
source: this.id,
overscaling: overscaling,
angle: this.map.transform.angle,
pitch: this.map.transform.pitch,
collisionDebug: this.map.collisionDebug
};
tile.workerID = this.dispatcher.send('load geojson tile', params, function(err, data) {
tile.unloadVectorData(this.map.painter);
if (tile.aborted)
return;
if (err) {
this.fire('tile.error', {tile: tile});
return;
}
tile.loadVectorData(data);
this.fire('tile.load', {tile: tile});
}.bind(this), this.workerID);
},
_abortTile: function(tile) {
tile.aborted = true;
},
_addTile: function(tile) {
this.fire('tile.add', {tile: tile});
},
_removeTile: function(tile) {
this.fire('tile.remove', {tile: tile});
},
_unloadTile: function(tile) {
tile.unloadVectorData(this.map.painter);
this.glyphAtlas.removeGlyphs(tile.uid);
this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, null, tile.workerID);
}
});