Merge pull request #290 from CartoDB/289-torque-limits
Return custom torque tile when limits are reached
This commit is contained in:
commit
27306dd917
36
dist/torque.full.js
vendored
36
dist/torque.full.js
vendored
File diff suppressed because one or more lines are too long
16951
dist/torque.full.uncompressed.js
vendored
16951
dist/torque.full.uncompressed.js
vendored
File diff suppressed because one or more lines are too long
8
dist/torque.js
vendored
8
dist/torque.js
vendored
File diff suppressed because one or more lines are too long
89
dist/torque.uncompressed.js
vendored
89
dist/torque.uncompressed.js
vendored
@ -1781,15 +1781,24 @@ GMapsTorqueLayer.prototype = torque.extend({},
|
||||
// for each tile shown on the map request the data
|
||||
onTileAdded: function(t) {
|
||||
var self = this;
|
||||
this.provider.getTileData(t, t.zoom, function(tileData) {
|
||||
var callback = function (tileData, error) {
|
||||
// don't load tiles that are not being shown
|
||||
if (t.zoom !== self.map.getZoom()) return;
|
||||
|
||||
self._tileLoaded(t, tileData);
|
||||
self.fire('tileLoaded');
|
||||
|
||||
if (tileData) {
|
||||
self.redraw();
|
||||
}
|
||||
});
|
||||
|
||||
self.fire('tileLoaded');
|
||||
|
||||
if (error) {
|
||||
self.fire('tileError', error);
|
||||
}
|
||||
}
|
||||
|
||||
this.provider.getTileData(t, t.zoom, callback);
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
@ -2638,7 +2647,6 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
this.setDuration = this.animator.duration.bind(this.animator);
|
||||
this.isRunning = this.animator.isRunning.bind(this.animator);
|
||||
|
||||
|
||||
L.CanvasLayer.prototype.initialize.call(this, options);
|
||||
|
||||
this.options.renderer = this.options.renderer || 'point';
|
||||
@ -2646,6 +2654,8 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
|
||||
if (this.options.tileJSON) this.options.provider = 'tileJSON';
|
||||
|
||||
this.showLimitErrors = options.showLimitErrors;
|
||||
|
||||
this.provider = new this.providers[this.options.provider](options);
|
||||
options.layer = this;
|
||||
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
|
||||
@ -2669,21 +2679,28 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
|
||||
this.renderer.on("allIconsLoaded", this.render.bind(this));
|
||||
|
||||
|
||||
// for each tile shown on the map request the data
|
||||
this.on('tileAdded', function(t) {
|
||||
var tileData = this.provider.getTileData(t, t.zoom, function(tileData) {
|
||||
var callback = function (tileData, error) {
|
||||
// don't load tiles that are not being shown
|
||||
if (t.zoom !== self._map.getZoom()) return;
|
||||
|
||||
self._tileLoaded(t, tileData);
|
||||
self._clearTileCaches();
|
||||
|
||||
if (tileData) {
|
||||
self.redraw();
|
||||
}
|
||||
self.fire('tileLoaded');
|
||||
});
|
||||
}, this);
|
||||
|
||||
self.fire('tileLoaded');
|
||||
|
||||
if (error) {
|
||||
self.fire('tileError', error);
|
||||
}
|
||||
};
|
||||
|
||||
var tileData = this.provider.getTileData(t, t.zoom, callback);
|
||||
}, this);
|
||||
},
|
||||
|
||||
_clearTileCaches: function() {
|
||||
@ -5459,6 +5476,17 @@ var Profiler = require('../profiler');
|
||||
};
|
||||
},
|
||||
|
||||
proccessTileError: function(error, coord, zoom) {
|
||||
return {
|
||||
error: error,
|
||||
coord: {
|
||||
x: coord.x,
|
||||
y: coord.y,
|
||||
z: zoom
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/*setCartoCSS: function(c) {
|
||||
this.options.cartocss = c;
|
||||
},*/
|
||||
@ -5568,11 +5596,18 @@ var Profiler = require('../profiler');
|
||||
.replace('{s}', subdomains[index])
|
||||
|
||||
var extra = this._extraParams();
|
||||
torque.net.get( url + (extra ? "?" + extra: ''), function (data) {
|
||||
torque.net.get( url + (extra ? "?" + extra: ''), function (response) {
|
||||
prof_fetch_time.end();
|
||||
if (data && data.responseText) {
|
||||
var rows = JSON.parse(data.responseText);
|
||||
callback(self.proccessTile(rows, coord, zoom));
|
||||
if (response && response.responseText) {
|
||||
var body = JSON.parse(response.responseText);
|
||||
|
||||
if (response.status === 429) {
|
||||
var error = body.errors_with_context[0];
|
||||
|
||||
callback(self.proccessTileError(error, coord, zoom), error);
|
||||
} else {
|
||||
callback(self.proccessTile(body, coord, zoom));
|
||||
}
|
||||
} else {
|
||||
Profiler.metric('torque.provider.windshaft.tile.error').inc();
|
||||
callback(null);
|
||||
@ -5922,7 +5957,8 @@ var Filters = require('./torque_filters');
|
||||
var turbocarto = require('turbo-carto');
|
||||
var CartoDatasource = require('./datasource');
|
||||
|
||||
var TAU = Math.PI * 2;
|
||||
var ERROR_IMG_URL = 'http://s3.amazonaws.com/com.cartodb.assets.static/error.svg';
|
||||
|
||||
var DEFAULT_CARTOCSS = [
|
||||
'#layer {',
|
||||
' marker-fill: #662506;',
|
||||
@ -6036,6 +6072,10 @@ var CartoDatasource = require('./datasource');
|
||||
if (PointRenderer.isTurboCarto(cartocss)) {
|
||||
var datasource = new CartoDatasource(self.layer._tiles);
|
||||
turbocarto(cartocss, datasource, function (err, parsedCartoCSS) {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
self.setShader(new carto.RendererJS().render(parsedCartoCSS));
|
||||
self.layer.redraw();
|
||||
self.layer.animator.start();
|
||||
@ -6053,6 +6093,10 @@ var CartoDatasource = require('./datasource');
|
||||
this._shader = shader;
|
||||
this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
|
||||
var img_names = this._shader.getImageURLs();
|
||||
if (this.layer.showLimitErrors) {
|
||||
img_names.push(ERROR_IMG_URL);
|
||||
}
|
||||
|
||||
this._preloadIcons(img_names);
|
||||
},
|
||||
|
||||
@ -6128,6 +6172,12 @@ var CartoDatasource = require('./datasource');
|
||||
// renders all the layers (and frames for each layer) from cartocss
|
||||
//
|
||||
renderTile: function(tile, keys, callback) {
|
||||
if (tile.error) {
|
||||
this._renderErrorTile(tile);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._iconsToLoad > 0) {
|
||||
this.on('allIconsLoaded', function() {
|
||||
this.renderTile.apply(this, [tile, keys, callback]);
|
||||
@ -6199,6 +6249,13 @@ var CartoDatasource = require('./datasource');
|
||||
}
|
||||
},
|
||||
|
||||
_renderErrorTile: function(tile) {
|
||||
if(this.layer.showLimitErrors) {
|
||||
var img = this._icons[ERROR_IMG_URL];
|
||||
img && this._ctx.drawImage(img, 0, 0, this.TILE_SIZE, this.TILE_SIZE);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// renders a tile in the canvas for key defined in
|
||||
// the torque tile
|
||||
@ -6420,7 +6477,7 @@ var CartoDatasource = require('./datasource');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
PointRenderer.isTurboCarto = function (cartocss) {
|
||||
var reservedWords = ['ramp', 'colorbrewer', 'buckets']
|
||||
@ -6760,7 +6817,7 @@ var torque = require('./core');
|
||||
function respond() {
|
||||
var status = req.status, result;
|
||||
var r = options.responseType === 'arraybuffer' ? req.response: req.responseText;
|
||||
if (!status && r || status >= 200 && status < 300 || status === 304) {
|
||||
if (!status && r || status >= 200 && status < 300 || status === 304 || status === 429) {
|
||||
callback(req);
|
||||
} else {
|
||||
callback(null);
|
||||
|
@ -180,20 +180,24 @@ GMapsTorqueLayer.prototype = torque.extend({},
|
||||
// for each tile shown on the map request the data
|
||||
onTileAdded: function(t) {
|
||||
var self = this;
|
||||
var successCallback = function (tileData) {
|
||||
var callback = function (tileData, error) {
|
||||
// don't load tiles that are not being shown
|
||||
if (t.zoom !== self.map.getZoom()) return;
|
||||
|
||||
self._tileLoaded(t, tileData);
|
||||
self.fire('tileLoaded');
|
||||
|
||||
if (tileData) {
|
||||
self.redraw();
|
||||
}
|
||||
};
|
||||
var errorCallback = function (error) {
|
||||
|
||||
self.fire('tileLoaded');
|
||||
|
||||
if (error) {
|
||||
self.fire('tileError', error);
|
||||
}
|
||||
}
|
||||
|
||||
this.provider.getTileData(t, t.zoom, successCallback, errorCallback);
|
||||
this.provider.getTileData(t, t.zoom, callback);
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
|
@ -72,7 +72,6 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
this.setDuration = this.animator.duration.bind(this.animator);
|
||||
this.isRunning = this.animator.isRunning.bind(this.animator);
|
||||
|
||||
|
||||
L.CanvasLayer.prototype.initialize.call(this, options);
|
||||
|
||||
this.options.renderer = this.options.renderer || 'point';
|
||||
@ -80,6 +79,8 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
|
||||
if (this.options.tileJSON) this.options.provider = 'tileJSON';
|
||||
|
||||
this.showLimitErrors = options.showLimitErrors;
|
||||
|
||||
this.provider = new this.providers[this.options.provider](options);
|
||||
options.layer = this;
|
||||
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
|
||||
@ -103,26 +104,28 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
|
||||
this.renderer.on("allIconsLoaded", this.render.bind(this));
|
||||
|
||||
|
||||
// for each tile shown on the map request the data
|
||||
this.on('tileAdded', function(t) {
|
||||
var successCallback = function (tileData) {
|
||||
var callback = function (tileData, error) {
|
||||
// don't load tiles that are not being shown
|
||||
if (t.zoom !== self._map.getZoom()) return;
|
||||
|
||||
self._tileLoaded(t, tileData);
|
||||
self._clearTileCaches();
|
||||
|
||||
if (tileData) {
|
||||
self.redraw();
|
||||
}
|
||||
|
||||
self.fire('tileLoaded');
|
||||
};
|
||||
var errorCallback = function (error) {
|
||||
|
||||
if (error) {
|
||||
self.fire('tileError', error);
|
||||
}
|
||||
};
|
||||
|
||||
var tileData = this.provider.getTileData(t, t.zoom, successCallback, errorCallback);
|
||||
var tileData = this.provider.getTileData(t, t.zoom, callback);
|
||||
}, this);
|
||||
|
||||
},
|
||||
|
||||
_clearTileCaches: function() {
|
||||
|
@ -186,6 +186,17 @@
|
||||
};
|
||||
},
|
||||
|
||||
proccessTileError: function(error, coord, zoom) {
|
||||
return {
|
||||
error: error,
|
||||
coord: {
|
||||
x: coord.x,
|
||||
y: coord.y,
|
||||
z: zoom
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/*setCartoCSS: function(c) {
|
||||
this.options.cartocss = c;
|
||||
},*/
|
||||
@ -256,11 +267,11 @@
|
||||
return null;
|
||||
},
|
||||
|
||||
getTileData: function(coord, zoom, successCallback, errorCallback) {
|
||||
getTileData: function(coord, zoom, callback) {
|
||||
if(!this._ready) {
|
||||
this._tileQueue.push([coord, zoom, successCallback, errorCallback]);
|
||||
this._tileQueue.push([coord, zoom, callback]);
|
||||
} else {
|
||||
this._getTileData(coord, zoom, successCallback, errorCallback);
|
||||
this._getTileData(coord, zoom, callback);
|
||||
}
|
||||
},
|
||||
|
||||
@ -281,7 +292,7 @@
|
||||
* `coord` object like {x : tilex, y: tiley }
|
||||
* `zoom` quadtree zoom level
|
||||
*/
|
||||
_getTileData: function(coord, zoom, successCallback, errorCallback) {
|
||||
_getTileData: function(coord, zoom, callback) {
|
||||
var self = this;
|
||||
var prof_fetch_time = Profiler.metric('torque.provider.windshaft.tile.fetch').start();
|
||||
var subdomains = this.options.subdomains || '0123';
|
||||
@ -300,12 +311,16 @@
|
||||
if (response && response.responseText) {
|
||||
var body = JSON.parse(response.responseText);
|
||||
|
||||
response.status === 429
|
||||
? errorCallback(body.errors_with_context[0])
|
||||
: successCallback(self.proccessTile(body, coord, zoom));
|
||||
if (response.status === 429) {
|
||||
var error = body.errors_with_context[0];
|
||||
|
||||
callback(self.proccessTileError(error, coord, zoom), error);
|
||||
} else {
|
||||
callback(self.proccessTile(body, coord, zoom));
|
||||
}
|
||||
} else {
|
||||
Profiler.metric('torque.provider.windshaft.tile.error').inc();
|
||||
successCallback(null);
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -6,7 +6,8 @@ var Filters = require('./torque_filters');
|
||||
var turbocarto = require('turbo-carto');
|
||||
var CartoDatasource = require('./datasource');
|
||||
|
||||
var TAU = Math.PI * 2;
|
||||
var ERROR_IMG_URL = 'http://s3.amazonaws.com/com.cartodb.assets.static/error.svg';
|
||||
|
||||
var DEFAULT_CARTOCSS = [
|
||||
'#layer {',
|
||||
' marker-fill: #662506;',
|
||||
@ -120,6 +121,10 @@ var CartoDatasource = require('./datasource');
|
||||
if (PointRenderer.isTurboCarto(cartocss)) {
|
||||
var datasource = new CartoDatasource(self.layer._tiles);
|
||||
turbocarto(cartocss, datasource, function (err, parsedCartoCSS) {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
self.setShader(new carto.RendererJS().render(parsedCartoCSS));
|
||||
self.layer.redraw();
|
||||
self.layer.animator.start();
|
||||
@ -137,6 +142,10 @@ var CartoDatasource = require('./datasource');
|
||||
this._shader = shader;
|
||||
this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
|
||||
var img_names = this._shader.getImageURLs();
|
||||
if (this.layer.showLimitErrors) {
|
||||
img_names.push(ERROR_IMG_URL);
|
||||
}
|
||||
|
||||
this._preloadIcons(img_names);
|
||||
},
|
||||
|
||||
@ -212,6 +221,12 @@ var CartoDatasource = require('./datasource');
|
||||
// renders all the layers (and frames for each layer) from cartocss
|
||||
//
|
||||
renderTile: function(tile, keys, callback) {
|
||||
if (tile && tile.error) {
|
||||
this._renderErrorTile(tile);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._iconsToLoad > 0) {
|
||||
this.on('allIconsLoaded', function() {
|
||||
this.renderTile.apply(this, [tile, keys, callback]);
|
||||
@ -283,6 +298,13 @@ var CartoDatasource = require('./datasource');
|
||||
}
|
||||
},
|
||||
|
||||
_renderErrorTile: function(tile) {
|
||||
if(this.layer.showLimitErrors) {
|
||||
var img = this._icons[ERROR_IMG_URL];
|
||||
img && this._ctx.drawImage(img, 0, 0, this.TILE_SIZE, this.TILE_SIZE);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// renders a tile in the canvas for key defined in
|
||||
// the torque tile
|
||||
@ -504,7 +526,7 @@ var CartoDatasource = require('./datasource');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
PointRenderer.isTurboCarto = function (cartocss) {
|
||||
var reservedWords = ['ramp', 'colorbrewer', 'buckets']
|
||||
|
@ -19,7 +19,9 @@
|
||||
"Javier Santana <jsantana@vizzuality.com>",
|
||||
"Raúl Ochoa <rochoa@cartodb.com>",
|
||||
"Nicklas Gummesson <nicklas@cartodb.com>",
|
||||
"Francisco Dans <francisco@cartodb.com>"
|
||||
"Francisco Dans <francisco@cartodb.com>",
|
||||
"Carlos Matallín <matallo@carto.com>",
|
||||
"Rubén Moya <ruben@carto.com"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
|
@ -22,7 +22,11 @@ var DEFAULT_CARTOCSS = [
|
||||
var renderer = null;
|
||||
QUnit.testStart(function() {
|
||||
var canvas = document.createElement('canvas');
|
||||
renderer = new torque.renderer.Point(canvas, {});
|
||||
renderer = new torque.renderer.Point(canvas, {
|
||||
layer: {
|
||||
showLimitErros: false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('render shader layers', function() {
|
||||
|
@ -37,6 +37,9 @@ function getTile(jsonRelPath, cartocss, z, x, y, step, callback) {
|
||||
},
|
||||
qualifyURL: function(url) {
|
||||
return url;
|
||||
},
|
||||
layer: {
|
||||
showLimitErros: false
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user