@@ -4,6 +4,23 @@
|
||||
|
||||
This option is no longer needed, so it was removed from the API.
|
||||
|
||||
#### XHR loading for `ol.source.TileUTFGrid`
|
||||
|
||||
The `ol.source.TileUTFGrid` now uses XMLHttpRequest to load UTFGrid tiles by default. This works out of the box with the v4 Mapbox API. To work with the v3 API, you must use the new `jsonp` option on the source. See the examples below for detail.
|
||||
|
||||
```js
|
||||
// To work with the v4 API
|
||||
var v4source = new ol.source.TileUTFGrid({
|
||||
url: 'https://api.tiles.mapbox.com/v4/example.json?access_token=' + YOUR_KEY_HERE
|
||||
});
|
||||
|
||||
// To work with the v3 API
|
||||
var v3source = new ol.source.TileUTFGrid({
|
||||
jsonp: true, // <--- this is required for v3
|
||||
url: 'http://api.tiles.mapbox.com/v3/example.json'
|
||||
});
|
||||
```
|
||||
|
||||
### v3.15.0
|
||||
|
||||
#### Internet Explorer 9 support
|
||||
|
||||
@@ -6,6 +6,8 @@ docs: >
|
||||
<p>Point to a country to see its name and flag.</p>
|
||||
Tiles made with [TileMill](http://tilemill.com). Hosting on MapBox.com or with open-source [TileServer](https://github.com/klokantech/tileserver-php/).
|
||||
tags: "utfgrid, tileutfgrid, tilejson"
|
||||
cloak:
|
||||
pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiRk1kMWZaSSJ9.E5BkluenyWQMsBLsuByrmg: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div style="display: none;">
|
||||
|
||||
@@ -5,14 +5,17 @@ goog.require('ol.layer.Tile');
|
||||
goog.require('ol.source.TileJSON');
|
||||
goog.require('ol.source.TileUTFGrid');
|
||||
|
||||
var key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiRk1kMWZaSSJ9.E5BkluenyWQMsBLsuByrmg';
|
||||
|
||||
var mapLayer = new ol.layer.Tile({
|
||||
source: new ol.source.TileJSON({
|
||||
url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json'
|
||||
url: 'http://api.tiles.mapbox.com/v4/mapbox.geography-class.json?access_token=' + key
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var gridSource = new ol.source.TileUTFGrid({
|
||||
url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json'
|
||||
url: 'http://api.tiles.mapbox.com/v4/mapbox.geography-class.json?access_token=' + key
|
||||
});
|
||||
|
||||
var gridLayer = new ol.layer.Tile({source: gridSource});
|
||||
|
||||
@@ -4193,6 +4193,7 @@ olx.source.ClusterOptions.prototype.wrapX;
|
||||
|
||||
/**
|
||||
* @typedef {{preemptive: (boolean|undefined),
|
||||
* jsonp: (boolean|undefined),
|
||||
* tileJSON: (TileJSON|undefined),
|
||||
* url: (string|undefined)}}
|
||||
* @api
|
||||
@@ -4200,6 +4201,15 @@ olx.source.ClusterOptions.prototype.wrapX;
|
||||
olx.source.TileUTFGridOptions;
|
||||
|
||||
|
||||
/**
|
||||
* Use JSONP with callback to load the TileJSON. Useful when the server
|
||||
* does not support CORS. Default is `false`.
|
||||
* @type {boolean|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.source.TileUTFGridOptions.prototype.jsonp;
|
||||
|
||||
|
||||
/**
|
||||
* If `true` the TileUTFGrid source loads the tiles based on their "visibility".
|
||||
* This improves the speed of response, but increases traffic.
|
||||
|
||||
@@ -49,8 +49,23 @@ ol.source.TileUTFGrid = function(options) {
|
||||
*/
|
||||
this.template_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.jsonp_ = options.jsonp || false;
|
||||
|
||||
if (options.url) {
|
||||
ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this));
|
||||
if (this.jsonp_) {
|
||||
ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
|
||||
this.handleTileJSONError.bind(this));
|
||||
} else {
|
||||
var client = new XMLHttpRequest();
|
||||
client.addEventListener('load', this.onXHRLoad_.bind(this));
|
||||
client.addEventListener('error', this.onXHRError_.bind(this));
|
||||
client.open('GET', options.url);
|
||||
client.send();
|
||||
}
|
||||
} else if (options.tileJSON) {
|
||||
this.handleTileJSONResponse(options.tileJSON);
|
||||
} else {
|
||||
@@ -60,6 +75,36 @@ ol.source.TileUTFGrid = function(options) {
|
||||
goog.inherits(ol.source.TileUTFGrid, ol.source.Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The load event.
|
||||
*/
|
||||
ol.source.TileUTFGrid.prototype.onXHRLoad_ = function(event) {
|
||||
var client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
if (client.status >= 200 && client.status < 300) {
|
||||
var response;
|
||||
try {
|
||||
response = /** @type {TileJSON} */(JSON.parse(client.responseText));
|
||||
} catch (err) {
|
||||
this.handleTileJSONError();
|
||||
return;
|
||||
}
|
||||
this.handleTileJSONResponse(response);
|
||||
} else {
|
||||
this.handleTileJSONError();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The error event.
|
||||
*/
|
||||
ol.source.TileUTFGrid.prototype.onXHRError_ = function(event) {
|
||||
this.handleTileJSONError();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the template from TileJSON.
|
||||
* @return {string|undefined} The template from TileJSON.
|
||||
@@ -76,7 +121,7 @@ ol.source.TileUTFGrid.prototype.getTemplate = function() {
|
||||
* in case of an error).
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {function(this: T, Object)} callback Callback.
|
||||
* @param {function(this: T, *)} callback Callback.
|
||||
* @param {T=} opt_this The object to use as `this` in the callback.
|
||||
* @param {boolean=} opt_request If `true` the callback is always async.
|
||||
* The tile data is requested if not yet loaded.
|
||||
@@ -103,6 +148,14 @@ ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function(
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
ol.source.TileUTFGrid.prototype.handleTileJSONError = function() {
|
||||
this.setState(ol.source.State.ERROR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TODO: very similar to ol.source.TileJSON#handleTileJSONResponse
|
||||
* @protected
|
||||
@@ -185,7 +238,8 @@ ol.source.TileUTFGrid.prototype.getTile = function(z, x, y, pixelRatio, projecti
|
||||
tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
|
||||
tileUrl !== undefined ? tileUrl : '',
|
||||
this.tileGrid.getTileCoordExtent(tileCoord),
|
||||
this.preemptive_);
|
||||
this.preemptive_,
|
||||
this.jsonp_);
|
||||
this.tileCache.set(tileCoordKey, tile);
|
||||
return tile;
|
||||
}
|
||||
@@ -211,9 +265,10 @@ ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {
|
||||
* @param {string} src Image source URI.
|
||||
* @param {ol.Extent} extent Extent of the tile.
|
||||
* @param {boolean} preemptive Load the tile when visible (before it's needed).
|
||||
* @param {boolean} jsonp Load the tile as a script.
|
||||
* @private
|
||||
*/
|
||||
ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive) {
|
||||
ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive, jsonp) {
|
||||
|
||||
goog.base(this, tileCoord, state);
|
||||
|
||||
@@ -252,6 +307,14 @@ ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive)
|
||||
* @type {Object.<string, Object>|undefined}
|
||||
*/
|
||||
this.data_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.jsonp_ = jsonp;
|
||||
|
||||
};
|
||||
goog.inherits(ol.source.TileUTFGridTile_, ol.Tile);
|
||||
|
||||
@@ -270,10 +333,10 @@ ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) {
|
||||
/**
|
||||
* Synchronously returns data at given coordinate (if available).
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {Object} The data.
|
||||
* @return {*} The data.
|
||||
*/
|
||||
ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) {
|
||||
if (!this.grid_ || !this.keys_ || !this.data_) {
|
||||
if (!this.grid_ || !this.keys_) {
|
||||
return null;
|
||||
}
|
||||
var xRelative = (coordinate[0] - this.extent_[0]) /
|
||||
@@ -296,7 +359,16 @@ ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) {
|
||||
}
|
||||
code -= 32;
|
||||
|
||||
return (code in this.keys_) ? this.data_[this.keys_[code]] : null;
|
||||
var data = null;
|
||||
if (code in this.keys_) {
|
||||
var id = this.keys_[code];
|
||||
if (this.data_ && id in this.data_) {
|
||||
data = this.data_[id];
|
||||
} else {
|
||||
data = id;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
@@ -304,7 +376,7 @@ ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) {
|
||||
* Calls the callback (synchronously by default) with the available data
|
||||
* for given coordinate (or `null` if not yet loaded).
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {function(this: T, Object)} callback Callback.
|
||||
* @param {function(this: T, *)} callback Callback.
|
||||
* @param {T=} opt_this The object to use as `this` in the callback.
|
||||
* @param {boolean=} opt_request If `true` the callback is always async.
|
||||
* The tile data is requested if not yet loaded.
|
||||
@@ -365,12 +437,50 @@ ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) {
|
||||
ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() {
|
||||
if (this.state == ol.TileState.IDLE) {
|
||||
this.state = ol.TileState.LOADING;
|
||||
ol.net.jsonp(this.src_, this.handleLoad_.bind(this),
|
||||
this.handleError_.bind(this));
|
||||
if (this.jsonp_) {
|
||||
ol.net.jsonp(this.src_, this.handleLoad_.bind(this),
|
||||
this.handleError_.bind(this));
|
||||
} else {
|
||||
var client = new XMLHttpRequest();
|
||||
client.addEventListener('load', this.onXHRLoad_.bind(this));
|
||||
client.addEventListener('error', this.onXHRError_.bind(this));
|
||||
client.open('GET', this.src_);
|
||||
client.send();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The load event.
|
||||
*/
|
||||
ol.source.TileUTFGridTile_.prototype.onXHRLoad_ = function(event) {
|
||||
var client = /** @type {XMLHttpRequest} */ (event.target);
|
||||
if (client.status >= 200 && client.status < 300) {
|
||||
var response;
|
||||
try {
|
||||
response = /** @type {!UTFGridJSON} */(JSON.parse(client.responseText));
|
||||
} catch (err) {
|
||||
this.handleError_();
|
||||
return;
|
||||
}
|
||||
this.handleLoad_(response);
|
||||
} else {
|
||||
this.handleError_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} event The error event.
|
||||
*/
|
||||
ol.source.TileUTFGridTile_.prototype.onXHRError_ = function(event) {
|
||||
this.handleError_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
*/
|
||||
|
||||
@@ -2,11 +2,10 @@ goog.provide('ol.test.source.TileUTFGrid');
|
||||
|
||||
describe('ol.source.TileUTFGrid', function() {
|
||||
|
||||
var url = 'spec/ol/data/tileutfgrid.json';
|
||||
var tileJson = null;
|
||||
// Called once for this describe section, this method loads a local
|
||||
// tileutfgrid and stores it in a variable to compare it in the actual
|
||||
// tests. This way we can test `handleTileJSONResponse` and also remove
|
||||
// the dependency from the external service / URL.
|
||||
|
||||
// Load and parse the UTFGrid fixture
|
||||
before(function(done) {
|
||||
var client = new XMLHttpRequest();
|
||||
client.addEventListener('load', function() {
|
||||
@@ -14,68 +13,77 @@ describe('ol.source.TileUTFGrid', function() {
|
||||
done();
|
||||
});
|
||||
client.addEventListener('error', function() {
|
||||
done(new Error('Failed to fetch local tileutfgrid.json'))
|
||||
done(new Error('Failed to fetch ' + url));
|
||||
});
|
||||
client.open('GET', 'spec/ol/data/tileutfgrid.json');
|
||||
client.open('GET', url);
|
||||
client.send();
|
||||
});
|
||||
|
||||
after(function() {
|
||||
tileJson = null;
|
||||
});
|
||||
|
||||
var url = 'some-tileutfgrid-url';
|
||||
function getTileUTFGrid() {
|
||||
var source = new ol.source.TileUTFGrid({
|
||||
return new ol.source.TileUTFGrid({
|
||||
url: url
|
||||
});
|
||||
return source;
|
||||
}
|
||||
|
||||
describe('constructor', function() {
|
||||
|
||||
it('needs to be constructed with url option', function() {
|
||||
var source;
|
||||
|
||||
var source = new ol.source.TileUTFGrid({url: url});
|
||||
expect(source).to.be.an(ol.source.TileUTFGrid);
|
||||
expect(source).to.be.an(ol.source.Tile);
|
||||
|
||||
expect(function() {
|
||||
// no options: will throw
|
||||
source = new ol.source.TileUTFGrid();
|
||||
return new ol.source.TileUTFGrid();
|
||||
}).to.throwException();
|
||||
expect(source).to.be(undefined);
|
||||
|
||||
expect(function() {
|
||||
// no url-option: will throw
|
||||
source = new ol.source.TileUTFGrid({});
|
||||
return new ol.source.TileUTFGrid({});
|
||||
}).to.throwException();
|
||||
expect(source).to.be(undefined);
|
||||
|
||||
expect(function() {
|
||||
// with a (bogus) url option all is fine
|
||||
source = new ol.source.TileUTFGrid({
|
||||
url: url
|
||||
});
|
||||
}).to.not.throwException();
|
||||
expect(source).to.be.an(ol.source.TileUTFGrid);
|
||||
|
||||
expect(function() {
|
||||
// also test our utility method
|
||||
source = getTileUTFGrid();
|
||||
}).to.not.throwException();
|
||||
expect(source).to.be.an(ol.source.TileUTFGrid);
|
||||
expect(getTileUTFGrid()).to.be.an(ol.source.TileUTFGrid);
|
||||
});
|
||||
|
||||
it('immediately fetches the passed URL', function() {
|
||||
// spy on the jsonp method
|
||||
var jsonpSpy = sinon.spy(ol.net, 'jsonp');
|
||||
});
|
||||
|
||||
getTileUTFGrid();
|
||||
expect(jsonpSpy.calledOnce).to.be(true);
|
||||
expect(jsonpSpy.lastCall.calledWith(url)).to.be(true);
|
||||
describe('change event (ready)', function() {
|
||||
it('is fired when the source is ready', function(done) {
|
||||
var source = new ol.source.TileUTFGrid({
|
||||
url: url
|
||||
});
|
||||
expect(source.getState()).to.be(ol.source.State.LOADING);
|
||||
expect(source.tileGrid).to.be(null);
|
||||
|
||||
// cleanup
|
||||
ol.net.jsonp.restore();
|
||||
jsonpSpy = null;
|
||||
source.on('change', function(event) {
|
||||
if (source.getState() === ol.source.State.READY) {
|
||||
expect(source.tileGrid).to.be.an(ol.tilegrid.TileGrid);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('change event (error)', function(done) {
|
||||
it('is fired when the source fails to initialize', function(done) {
|
||||
var source = new ol.source.TileUTFGrid({
|
||||
url: 'Bogus UTFGrid URL'
|
||||
});
|
||||
expect(source.getState()).to.be(ol.source.State.LOADING);
|
||||
expect(source.tileGrid).to.be(null);
|
||||
|
||||
source.on('change', function(event) {
|
||||
if (source.getState() === ol.source.State.ERROR) {
|
||||
expect(source.tileGrid).to.be(null);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#handleTileJSONResponse', function() {
|
||||
@@ -281,6 +289,7 @@ describe('ol.source.TileUTFGrid', function() {
|
||||
goog.require('ol.net');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.State');
|
||||
goog.require('ol.source.Tile');
|
||||
goog.require('ol.source.TileUTFGrid');
|
||||
goog.require('ol.tilegrid.TileGrid');
|
||||
goog.require('ol.TileState');
|
||||
|
||||
Reference in New Issue
Block a user