Skip to content

Commit

Permalink
Implemented a queue for the tile requests (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
aliceh75 committed Sep 9, 2014
1 parent 6621492 commit 07d26e8
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 10 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ var utfGrid = new L.UtfGrid('http://myserver/amazingness/{z}/{x}/{y}.grid.json',

### Other options

pointerCursor: changes the mouse cursor to a pointer when hovering over an interactive part of the grid. (Default: true)
- pointerCursor: changes the mouse cursor to a pointer when hovering over an interactive part of the grid. (Default: true)
- maxRequests: Maximum number of requests sent at once to the utfgrid tile server. Increasing this will get more processing done at once, however it means your utfgrid tiles will get priority over your visual tiles (as browsers tend to prioritize javascript/json requests). Increasing this will also reduce the number of requests that may get dropped early when users pan the map. There is little point to have this higher than 8. (Default: 4)
- requestTimeout: number of milliseconds after which a request for a tile is considered to have timed out. (Default: 60000)

### Turning interaction on and off

Expand Down
119 changes: 110 additions & 9 deletions src/leaflet.utfgrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ L.Util.ajax = function (url, cb) {
}
};
request.send();
return request;
};
L.UtfGrid = L.Class.extend({
includes: L.Mixin.Events,
Expand All @@ -39,12 +40,20 @@ L.UtfGrid = L.Class.extend({
resolution: 4,

useJsonP: true,
pointerCursor: true
pointerCursor: true,

maxRequests: 4,
requestTimeout: 60000
},

//The thing the mouse is currently on
_mouseOn: null,

// The requests
_requests: {},
_request_queue: [],
_requests_in_process: [],

initialize: function (url, options) {
L.Util.setOptions(this, options);

Expand Down Expand Up @@ -93,11 +102,17 @@ L.UtfGrid = L.Class.extend({
}
},

redraw: function () {
// Clear cache to force all tiles to reload
this._cache = {};
this._update();
},
redraw: function () {
// Clear cache to force all tiles to reload
this._request_queue = [];
for (var req_key in this._requests){
if (this._requests.hasOwnProperty(req_key)){
this._abort_request(req_key);
}
}
this._cache = {};
this._update();
},

_click: function (e) {
this.fire('click', this._objectForEvent(e));
Expand Down Expand Up @@ -176,11 +191,13 @@ L.UtfGrid = L.Class.extend({
max = this._map.options.crs.scale(zoom) / tileSize;

//Load all required ones
var visible_tiles = [];
for (var x = nwTilePoint.x; x <= seTilePoint.x; x++) {
for (var y = nwTilePoint.y; y <= seTilePoint.y; y++) {

var xw = (x + max) % max, yw = (y + max) % max;
var key = zoom + '_' + xw + '_' + yw;
visible_tiles.push(key);

if (!this._cache.hasOwnProperty(key)) {
this._cache[key] = null;
Expand All @@ -193,6 +210,12 @@ L.UtfGrid = L.Class.extend({
}
}
}
// If we still have requests for tiles that have now gone out of sight, attempt to abort them.
for (var req_key in this._requests){
if (visible_tiles.indexOf(req_key) < 0){
this._abort_request(req_key);
}
}
},

_loadTileP: function (zoom, x, y) {
Expand All @@ -218,9 +241,17 @@ L.UtfGrid = L.Class.extend({
self._cache[key] = data;
delete window[wk][functionName];
head.removeChild(script);
self._finish_request(key);
};

head.appendChild(script);
this._queue_request(key, function(){
head.appendChild(script);
return {
abort: function(){
head.removeChild(script);
}
};
});
},

_loadTile: function (zoom, x, y) {
Expand All @@ -233,11 +264,81 @@ L.UtfGrid = L.Class.extend({

var key = zoom + '_' + x + '_' + y;
var self = this;
L.Util.ajax(url, function (data) {
self._cache[key] = data;
this._queue_request(key, function(){
return L.Util.ajax(url, function (data) {
self._cache[key] = data;
self._finish_request(key);
});
});
},

_queue_request: function(key, callback){
this._requests[key] = {
callback: callback,
timeout: null,
handler: null
};
this._request_queue.push(key);
this._process_queued_requests();
},

_finish_request: function(key){
// Remove from requests in process
var pos = this._requests_in_process.indexOf(key);
if (pos >= 0) {
this._requests_in_process.splice(pos, 1);
}
// Remove from request queue
pos = this._request_queue.indexOf(key);
if (pos >= 0){
this._request_queue.splice(pos, 1);
}
// Remove the request entry
if (this._requests[key]) {
if (this._requests[key].timeout) {
window.clearTimeout(this._requests[key].timeout);
}
delete this._requests[key];
}
// Recurse
this._process_queued_requests();
},

_abort_request: function(key){
// Abort the request if possible
if (this._requests[key] && this._requests[key].handler){
if (typeof this._requests[key].handler.abort === 'function'){
this._requests[key].handler.abort();
}
}
// Ensure we don't keep a false copy of the data in the cache
if (this._cache[key] === null){
delete this._cache[key];
}
// And remove the request
this._finish_request(key);
},

_process_queued_requests: function() {
while (this._request_queue.length > 0 && (this.options.maxRequests === 0 ||
this._requests_in_process.length < this.options.maxRequests)){
this._process_request(this._request_queue.pop());
}
},

_process_request: function(key){
var self = this;
this._requests[key].timeout = window.setTimeout(function(){
self._abort_request(key);
}, this.options.requestTimeout);
this._requests_in_process.push(key);
// The callback might call _finish_request, so don't assume _requests[key] still exists.
var handler = this._requests[key].callback();
if (this._requests[key]){
this._requests[key].handler = handler;
}
},

_utfDecode: function (c) {
if (c >= 93) {
c--;
Expand Down

0 comments on commit 07d26e8

Please sign in to comment.