mapbox-gl
Version:
A WebGL interactive maps library
164 lines (137 loc) • 5.07 kB
JavaScript
'use strict';
var util = require('../util/util');
var Tile = require('./tile');
var LngLat = require('../geo/lng_lat');
var Point = require('point-geometry');
var Evented = require('../util/evented');
var ajax = require('../util/ajax');
var EXTENT = require('../data/buffer').EXTENT;
module.exports = ImageSource;
/**
* Create an Image source instance given an options object
* @class ImageSource
* @param {Object} [options]
* @param {string} options.url A string URL of an image file
* @param {Array} options.coordinates lng, lat coordinates in order clockwise
* starting at the top left: tl, tr, br, bl
* @example
* var sourceObj = new mapboxgl.ImageSource({
* url: 'https://www.mapbox.com/images/foo.png',
* coordinates: [
* [-76.54335737228394, 39.18579907229748],
* [-76.52803659439087, 39.1838364847587],
* [-76.5295386314392, 39.17683392507606],
* [-76.54520273208618, 39.17876344106642]
* ]
* });
* map.addSource('some id', sourceObj); // add
* map.removeSource('some id'); // remove
*/
function ImageSource(options) {
this.urls = options.urls;
this.coordinates = options.coordinates;
ajax.getImage(options.url, function(err, image) {
// @TODO handle errors via event.
if (err) return;
this.image = image;
this.image.addEventListener('load', function() {
this.map._rerender();
}.bind(this));
this._loaded = true;
if (this.map) {
this.createTile(options.coordinates);
this.fire('change');
}
}.bind(this));
}
ImageSource.prototype = util.inherit(Evented, {
onAdd: function(map) {
this.map = map;
if (this.image) {
this.createTile();
}
},
/**
* Calculate which mercator tile is suitable for rendering the image in
* and create a buffer with the corner coordinates. These coordinates
* may be outside the tile, because raster tiles aren't clipped when rendering.
* @private
*/
createTile: function(cornerGeoCoords) {
var map = this.map;
var cornerZ0Coords = cornerGeoCoords.map(function(coord) {
return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0);
});
var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords);
var tileCoords = cornerZ0Coords.map(function(coord) {
var zoomedCoord = coord.zoomTo(centerCoord.zoom);
return new Point(
Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
Math.round((zoomedCoord.row - centerCoord.row) * EXTENT));
});
var gl = map.painter.gl;
var maxInt16 = 32767;
var array = new Int16Array([
tileCoords[0].x, tileCoords[0].y, 0, 0,
tileCoords[1].x, tileCoords[1].y, maxInt16, 0,
tileCoords[3].x, tileCoords[3].y, 0, maxInt16,
tileCoords[2].x, tileCoords[2].y, maxInt16, maxInt16
]);
this.tile = new Tile();
this.tile.buckets = {};
this.tile.boundsBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.tile.boundsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
},
loaded: function() {
return this.image && this.image.complete;
},
update: function() {
// noop
},
reload: function() {
// noop
},
prepare: function() {
if (!this._loaded || !this.loaded()) return;
var painter = this.map.painter;
var gl = painter.gl;
if (!this.tile.texture) {
this.tile.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.image);
} else {
gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.image);
}
},
getVisibleCoordinates: function() {
if (this.centerCoord) return [this.centerCoord];
else return [];
},
getTile: function() {
return this.tile;
},
/**
* An ImageSource doesn't have any vector features that could
* be selectable, so always return an empty array.
* @private
*/
featuresAt: function(point, params, callback) {
return callback(null, []);
},
featuresIn: function(bbox, params, callback) {
return callback(null, []);
},
serialize: function() {
return {
type: 'image',
urls: this.urls,
coordinates: this.coordinates
};
}
});