diff --git a/lib/cartodb/controllers/base.js b/lib/cartodb/controllers/base.js index 79d4e407..e5952ff6 100644 --- a/lib/cartodb/controllers/base.js +++ b/lib/cartodb/controllers/base.js @@ -14,6 +14,9 @@ var REQUEST_QUERY_PARAMS_WHITELIST = [ 'api_key', 'auth_token', 'callback', + 'zoom', + 'lon', + 'lat', // widgets & filters 'filters', // json 'own_filter', // 0, 1 diff --git a/lib/cartodb/controllers/named_maps.js b/lib/cartodb/controllers/named_maps.js index 38ae91e8..e2c28948 100644 --- a/lib/cartodb/controllers/named_maps.js +++ b/lib/cartodb/controllers/named_maps.js @@ -140,7 +140,7 @@ NamedMapsController.prototype.staticMap = function(req, res) { function prepareImageOptions(err, _namedMapProvider) { assert.ifError(err); namedMapProvider = _namedMapProvider; - self.getStaticImageOptions(cdbUser, namedMapProvider, this); + self.getStaticImageOptions(cdbUser, req.params, namedMapProvider, this); }, function getImage(err, imageOpts) { assert.ifError(err); @@ -192,9 +192,37 @@ var DEFAULT_ZOOM_CENTER = { } }; -NamedMapsController.prototype.getStaticImageOptions = function(cdbUser, namedMapProvider, callback) { +function numMapper(n) { + return +n; +} + +NamedMapsController.prototype.getStaticImageOptions = function(cdbUser, params, namedMapProvider, callback) { var self = this; + if ([params.zoom, params.lon, params.lat].map(numMapper).every(Number.isFinite)) { + return callback(null, { + zoom: params.zoom, + center: { + lng: params.lon, + lat: params.lat + } + }); + } + + if (params.bbox) { + var bbox = params.bbox.split(',').map(numMapper); + if (bbox.length === 4 && bbox.every(Number.isFinite)) { + return callback(null, { + bounds: { + west: bbox[0], + south: bbox[1], + east: bbox[2], + north: bbox[3] + } + }); + } + } + step( function getTemplate() { namedMapProvider.getTemplate(this); @@ -205,6 +233,9 @@ NamedMapsController.prototype.getStaticImageOptions = function(cdbUser, namedMap if (template.view) { var zoomCenter = templateZoomCenter(template.view); if (zoomCenter) { + if (Number.isFinite(+params.zoom)) { + zoomCenter.zoom = +params.zoom; + } return zoomCenter; } diff --git a/test/acceptance/named_maps_static_view.js b/test/acceptance/named_maps_static_view.js index f091c213..91026226 100644 --- a/test/acceptance/named_maps_static_view.js +++ b/test/acceptance/named_maps_static_view.js @@ -1,3 +1,4 @@ +var qs = require('querystring'); var testHelper = require('../support/test_helper'); var RedisPool = require('redis-mpool'); @@ -53,10 +54,18 @@ describe('named maps static view', function() { templateMaps.delTemplate(username, templateName, done); }); - function getStaticMap(callback) { + function getStaticMap(params, callback) { + if (!callback) { + callback = params; + params = null; + } var url = '/api/v1/map/static/named/' + templateName + '/640/480.png'; + if (params !== null) { + url += '?' + qs.stringify(params); + } + var requestOptions = { url: url, method: 'GET', @@ -163,4 +172,30 @@ describe('named maps static view', function() { }); }); + it('should return override zoom', function (done) { + var view = { + bounds: { + west: 0, + south: 0, + east: 45, + north: 45 + }, + zoom: 4, + center: { + lng: 40, + lat: 20 + } + }; + templateMaps.addTemplate(username, createTemplate(view), function (err) { + if (err) { + return done(err); + } + getStaticMap({ zoom: 3 }, function(err, img) { + assert.ok(!err); + img.save('/tmp/static.png'); + assert.imageIsSimilarToFile(img, previewFixture('override-zoom'), IMAGE_TOLERANCE, done); + }); + }); + }); + }); diff --git a/test/fixtures/previews/populated_places_simple_reduced-override-zoom.png b/test/fixtures/previews/populated_places_simple_reduced-override-zoom.png new file mode 100644 index 00000000..0587670c Binary files /dev/null and b/test/fixtures/previews/populated_places_simple_reduced-override-zoom.png differ