First attempt: support buffer-size configuration for named maps
This commit is contained in:
@@ -474,6 +474,11 @@ TemplateMaps.prototype.instance = function(template, params) {
|
||||
|
||||
// NOTE: we're deep-cloning the layergroup here
|
||||
var layergroup = JSON.parse(JSON.stringify(template.layergroup));
|
||||
|
||||
if (layergroup.buffersize) {
|
||||
layergroup.buffersize = _replaceVars(layergroup.buffersize, all_params);
|
||||
}
|
||||
|
||||
for (var i=0; i<layergroup.layers.length; ++i) {
|
||||
var lyropt = layergroup.layers[i].options;
|
||||
|
||||
|
||||
@@ -2,10 +2,35 @@ require('../support/test_helper');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var TestClient = require('../support/test-client');
|
||||
var IMAGE_TOLERANCE_PER_MIL = 20;
|
||||
var IMAGE_TOLERANCE_PER_MIL = 0;
|
||||
var mapnik = require('windshaft').mapnik;
|
||||
|
||||
function createMapConfig (bufferSize) {
|
||||
var CARTOCSS_LABELS = [
|
||||
'#layer {',
|
||||
' polygon-fill: #374C70;',
|
||||
' polygon-opacity: 0.9;',
|
||||
' line-width: 1;',
|
||||
' line-color: #FFF;',
|
||||
' line-opacity: 0.5;',
|
||||
'}',
|
||||
'#layer::labels {',
|
||||
' text-name: [name];',
|
||||
' text-face-name: \'DejaVu Sans Book\';',
|
||||
' text-size: 20;',
|
||||
' text-fill: #FFFFFF;',
|
||||
' text-label-position-tolerance: 0;',
|
||||
' text-halo-radius: 1;',
|
||||
' text-halo-fill: #6F808D;',
|
||||
' text-dy: -10;',
|
||||
' text-allow-overlap: true;',
|
||||
' text-placement: point;',
|
||||
' text-placement-type: dummy;',
|
||||
'}'
|
||||
].join('\n')
|
||||
|
||||
function createMapConfig (bufferSize, cartocss) {
|
||||
cartocss = cartocss || CARTOCSS_LABELS;
|
||||
|
||||
return {
|
||||
version: '1.6.0',
|
||||
buffersize: bufferSize,
|
||||
@@ -18,28 +43,7 @@ function createMapConfig (bufferSize) {
|
||||
'from',
|
||||
' populated_places_simple_reduced',
|
||||
].join('\n'),
|
||||
cartocss: [
|
||||
'#layer {',
|
||||
' polygon-fill: #374C70;',
|
||||
' polygon-opacity: 0.9;',
|
||||
' line-width: 1;',
|
||||
' line-color: #FFF;',
|
||||
' line-opacity: 0.5;',
|
||||
'}',
|
||||
'#layer::labels {',
|
||||
' text-name: [name];',
|
||||
' text-face-name: \'DejaVu Sans Book\';',
|
||||
' text-size: 20;',
|
||||
' text-fill: #FFFFFF;',
|
||||
' text-label-position-tolerance: 0;',
|
||||
' text-halo-radius: 1;',
|
||||
' text-halo-fill: #6F808D;',
|
||||
' text-dy: -10;',
|
||||
' text-allow-overlap: true;',
|
||||
' text-placement: point;',
|
||||
' text-placement-type: dummy;',
|
||||
'}'
|
||||
].join('\n'),
|
||||
cartocss: cartocss,
|
||||
cartocss_version: '2.3.0',
|
||||
interactivity: 'cartodb_id'
|
||||
}
|
||||
@@ -114,11 +118,73 @@ describe('buffer size per format', function () {
|
||||
testClient.getTile(coords.z, coords.x, coords.y, { format: test.format }, function (err, res, tile) {
|
||||
assert.ifError(err);
|
||||
// To generate images use:
|
||||
// tile.save(test.fixturePath);
|
||||
tile.save(test.fixturePath);
|
||||
test.assert(tile, function () {
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createBufferSizeTemplate (name, cartocss) {
|
||||
cartocss = cartocss || CARTOCSS_LABELS;
|
||||
return {
|
||||
"version": "0.0.1",
|
||||
"name": name,
|
||||
"placeholders": {
|
||||
"buffersize": {
|
||||
"type": "number",
|
||||
"default": "0"
|
||||
}
|
||||
},
|
||||
"layergroup": {
|
||||
version: '1.6.0',
|
||||
buffersize: '<%= buffersize %>',
|
||||
layers: [{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: [
|
||||
'select',
|
||||
' *',
|
||||
'from',
|
||||
' populated_places_simple_reduced',
|
||||
].join('\n'),
|
||||
cartocss: cartocss,
|
||||
cartocss_version: '2.3.0',
|
||||
interactivity: 'cartodb_id'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe.only('buffer size per format for named maps', function () {
|
||||
var testCases = [
|
||||
{
|
||||
desc: 'should get png tile using buffer-size 0',
|
||||
coords: { z: 7, x: 64, y: 48 },
|
||||
format: 'png',
|
||||
fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.png',
|
||||
template: createBufferSizeTemplate('named-buffer-size'),
|
||||
assert: function (tile, callback) {
|
||||
assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
testCases.forEach(function (test) {
|
||||
it(test.desc, function (done) {
|
||||
var testClient = new TestClient(undefined, 1234, test.template);
|
||||
var coords = test.coords;
|
||||
testClient.getNamedTile(coords.z, coords.x, coords.y, { format: test.format }, function (err, res, tile) {
|
||||
assert.ifError(err);
|
||||
// To generate images use:
|
||||
// tile.save('./test/fixtures/buffer-size/tile-7.64.48-buffer-size-64.png');
|
||||
test.assert(tile, function () {
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+164
-1
@@ -16,9 +16,10 @@ var serverOptions = require('../../lib/cartodb/server_options');
|
||||
serverOptions.analysis.batch.inlineExecution = true;
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
function TestClient(mapConfig, apiKey) {
|
||||
function TestClient(mapConfig, apiKey, template) {
|
||||
this.mapConfig = mapConfig;
|
||||
this.apiKey = apiKey;
|
||||
this.template = template;
|
||||
this.keysToDelete = {};
|
||||
}
|
||||
|
||||
@@ -696,3 +697,165 @@ module.exports.getStaticMap = function getStaticMap(templateName, params, callba
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TestClient.prototype.getNamedTile = function(z, x, y, params, callback) {
|
||||
if (!this.template) {
|
||||
throw new Error('Template is not defined');
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (!callback) {
|
||||
callback = params;
|
||||
params = {};
|
||||
}
|
||||
|
||||
if (!params.placeholders) {
|
||||
params.placeholder = {};
|
||||
}
|
||||
|
||||
var urlNamed = '/api/v1/map/named';
|
||||
var url = '/api/v1/map';
|
||||
|
||||
|
||||
if (this.apiKey) {
|
||||
url += '?' + qs.stringify({api_key: this.apiKey});
|
||||
}
|
||||
|
||||
var templateName;
|
||||
var layergroupId;
|
||||
step(
|
||||
function createTemplate () {
|
||||
var next = this;
|
||||
console.log(urlNamed + '?' + qs.stringify({api_key: self.apiKey}))
|
||||
assert.response(server,
|
||||
{
|
||||
url: urlNamed + '?' + qs.stringify({api_key: self.apiKey}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(self.template)
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
},
|
||||
function (res, err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return next(null, JSON.parse(res.body).template_id);
|
||||
}
|
||||
);
|
||||
},
|
||||
function createLayergroup(err, templateId) {
|
||||
var next = this;
|
||||
console.log(urlNamed + '/' + templateId + '?' + qs.stringify({api_key: self.apiKey}))
|
||||
assert.response(server,
|
||||
{
|
||||
url: urlNamed + '/' + templateId + '?' + qs.stringify({api_key: self.apiKey}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(params.placeholders)
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
},
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return next(null, JSON.parse(res.body).layergroupid);
|
||||
}
|
||||
);
|
||||
},
|
||||
function getTileResult(err, _layergroupId) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
layergroupId = _layergroupId;
|
||||
|
||||
url = '/api/v1/map/' + layergroupId + '/';
|
||||
|
||||
var layers = params.layers;
|
||||
|
||||
if (layers !== undefined) {
|
||||
layers = Array.isArray(layers) ? layers : [layers];
|
||||
url += layers.join(',') + '/';
|
||||
}
|
||||
|
||||
var format = params.format || 'png';
|
||||
|
||||
url += [z,x,y].join('/');
|
||||
url += '.' + format;
|
||||
|
||||
if (self.apiKey) {
|
||||
url += '?' + qs.stringify({api_key: self.apiKey});
|
||||
}
|
||||
|
||||
var request = {
|
||||
url: url,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
};
|
||||
|
||||
var expectedResponse = {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
};
|
||||
|
||||
var isPng = format.match(/png$/);
|
||||
|
||||
if (isPng) {
|
||||
request.encoding = 'binary';
|
||||
expectedResponse.headers['Content-Type'] = 'image/png';
|
||||
}
|
||||
|
||||
var isMvt = format.match(/mvt$/);
|
||||
|
||||
if (isMvt) {
|
||||
request.encoding = 'binary';
|
||||
expectedResponse.headers['Content-Type'] = 'application/x-protobuf';
|
||||
}
|
||||
|
||||
assert.response(server, request, expectedResponse, function(res, err) {
|
||||
assert.ifError(err);
|
||||
|
||||
var obj;
|
||||
|
||||
if (isPng) {
|
||||
obj = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
||||
}
|
||||
else if (isMvt) {
|
||||
obj = new mapnik.VectorTile(z, x, y);
|
||||
obj.setDataSync(new Buffer(res.body, 'binary'));
|
||||
}
|
||||
|
||||
else {
|
||||
obj = JSON.parse(res.body);
|
||||
}
|
||||
|
||||
next(null, res, obj);
|
||||
});
|
||||
},
|
||||
function finish(err, res, image) {
|
||||
self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
|
||||
self.keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
return callback(err, res, image);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user