Optimize static endpoints (remove abaculus dependency) (closes #2)
This commit is contained in:
parent
e39ae90bc8
commit
4f9b8c1a1b
2 changed files with 44 additions and 119 deletions
|
@ -13,9 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "1.5.2",
|
"async": "1.5.2",
|
||||||
"async-lock": "0.3.8",
|
"async-lock": "0.3.8",
|
||||||
"abaculus": "1.3.0",
|
|
||||||
"clone": "1.0.2",
|
"clone": "1.0.2",
|
||||||
"concat-stream": "1.5.1",
|
|
||||||
"cors": "2.7.1",
|
"cors": "2.7.1",
|
||||||
"express": "4.13.4",
|
"express": "4.13.4",
|
||||||
"mapbox-gl-native": "3.0.2-earcut",
|
"mapbox-gl-native": "3.0.2-earcut",
|
||||||
|
|
|
@ -8,9 +8,7 @@ var async = require('async'),
|
||||||
util = require('util'),
|
util = require('util'),
|
||||||
zlib = require('zlib');
|
zlib = require('zlib');
|
||||||
|
|
||||||
var abaculus = require('abaculus'),
|
var clone = require('clone'),
|
||||||
clone = require('clone'),
|
|
||||||
concat = require('concat-stream'),
|
|
||||||
express = require('express'),
|
express = require('express'),
|
||||||
mercator = new (require('sphericalmercator'))(),
|
mercator = new (require('sphericalmercator'))(),
|
||||||
mbgl = require('mapbox-gl-native'),
|
mbgl = require('mapbox-gl-native'),
|
||||||
|
@ -180,24 +178,16 @@ module.exports = function(maps, options, prefix) {
|
||||||
.replace('{y}', ':y(\\d+)')
|
.replace('{y}', ':y(\\d+)')
|
||||||
.replace('{format}', ':format([\\w\\.]+)');
|
.replace('{format}', ':format([\\w\\.]+)');
|
||||||
|
|
||||||
var getTile = function(z, x, y, scale, format, callback) {
|
var respondImage = function(z, lon, lat, width, height, scale, format, res, next) {
|
||||||
if (format == 'png' || format == 'webp') {
|
if (format == 'png' || format == 'webp') {
|
||||||
} else if (format == 'jpg' || format == 'jpeg') {
|
} else if (format == 'jpg' || format == 'jpeg') {
|
||||||
format = 'jpeg';
|
format = 'jpeg';
|
||||||
} else {
|
} else {
|
||||||
return callback(null, null);
|
return res.status(404).send('Invalid format');
|
||||||
}
|
}
|
||||||
|
|
||||||
var mbglZ = Math.max(0, z - 1);
|
var mbglZ = Math.max(0, z - 1);
|
||||||
|
|
||||||
var tileSize = 256;
|
|
||||||
var tileCenter = mercator.ll([
|
|
||||||
((x + 0.5) / (1 << z)) * (256 << z),
|
|
||||||
((y + 0.5) / (1 << z)) * (256 << z)
|
|
||||||
], z);
|
|
||||||
|
|
||||||
var renderer = map.renderers[scale];
|
var renderer = map.renderers[scale];
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
/*
|
/*
|
||||||
debug: {
|
debug: {
|
||||||
|
@ -208,9 +198,9 @@ module.exports = function(maps, options, prefix) {
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
zoom: mbglZ,
|
zoom: mbglZ,
|
||||||
center: tileCenter,
|
center: [lon, lat],
|
||||||
width: tileSize,
|
width: width,
|
||||||
height: tileSize
|
height: height
|
||||||
};
|
};
|
||||||
if (z == 0) {
|
if (z == 0) {
|
||||||
params.width *= 2;
|
params.width *= 2;
|
||||||
|
@ -221,51 +211,32 @@ module.exports = function(maps, options, prefix) {
|
||||||
done();
|
done();
|
||||||
if (err) console.log(err);
|
if (err) console.log(err);
|
||||||
|
|
||||||
if (z == 0) {
|
var image = sharp(data, {
|
||||||
// HACK: when serving zoom 0, resize the 0 tile from 512 to 256
|
|
||||||
var data_ = clone(data);
|
|
||||||
var dataSize_ = 2 * tileSize * scale;
|
|
||||||
var newSize_ = dataSize_ / 2;
|
|
||||||
data = new Buffer(4 * newSize_ * newSize_);
|
|
||||||
for (var x = 0; x < newSize_; x++) {
|
|
||||||
for (var y = 0; y < newSize_; y++) {
|
|
||||||
for (var b = 0; b < 4; b++) {
|
|
||||||
data[4 * (x * newSize_ + y) + b] = (
|
|
||||||
data_[4 * (2 * x * dataSize_ + 2 * y) + b] +
|
|
||||||
data_[4 * (2 * x * dataSize_ + (2 * y + 1)) + b] +
|
|
||||||
data_[4 * ((2 * x + 1) * dataSize_ + 2 * y) + b] +
|
|
||||||
data_[4 * ((2 * x + 1) * dataSize_ + (2 * y + 1)) + b]
|
|
||||||
) / 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sharp(data, {
|
|
||||||
raw: {
|
raw: {
|
||||||
width: tileSize * scale,
|
width: params.width * scale,
|
||||||
height: tileSize * scale,
|
height: params.height * scale,
|
||||||
channels: 4
|
channels: 4
|
||||||
}
|
}
|
||||||
}).toFormat(format)
|
});
|
||||||
|
|
||||||
|
if (z == 0) {
|
||||||
|
// HACK: when serving zoom 0, resize the 0 tile from 512 to 256
|
||||||
|
image.resize(width * scale, height * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
image.toFormat(format)
|
||||||
.compressionLevel(9)
|
.compressionLevel(9)
|
||||||
.toBuffer(function(err, buffer, info) {
|
.toBuffer(function(err, buffer, info) {
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return callback(null, null);
|
return res.status(404).send('Not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
var md5 = crypto.createHash('md5').update(buffer).digest('base64');
|
var md5 = crypto.createHash('md5').update(buffer).digest('base64');
|
||||||
var headers = {
|
res.set({
|
||||||
'content-md5': md5,
|
'content-md5': md5,
|
||||||
'content-type': 'image/' + format
|
'content-type': 'image/' + format
|
||||||
};
|
});
|
||||||
/*
|
return res.status(200).send(buffer);
|
||||||
if (format === 'pbf') {
|
|
||||||
headers['content-type'] = 'application/x-protobuf';
|
|
||||||
headers['content-encoding'] = 'gzip';
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return callback(null, buffer, headers);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -277,59 +248,15 @@ module.exports = function(maps, options, prefix) {
|
||||||
y = req.params.y | 0,
|
y = req.params.y | 0,
|
||||||
scale = getScale(req.params.scale),
|
scale = getScale(req.params.scale),
|
||||||
format = req.params.format;
|
format = req.params.format;
|
||||||
return getTile(z, x, y, scale, format, function(err, data, headers) {
|
var tileSize = 256;
|
||||||
if (err) {
|
var tileCenter = mercator.ll([
|
||||||
return next(err);
|
((x + 0.5) / (1 << z)) * (256 << z),
|
||||||
}
|
((y + 0.5) / (1 << z)) * (256 << z)
|
||||||
if (headers) {
|
], z);
|
||||||
res.set(headers);
|
return respondImage(z, tileCenter[0], tileCenter[1], tileSize, tileSize,
|
||||||
}
|
scale, format, res, next);
|
||||||
if (data == null) {
|
|
||||||
return res.status(404).send('Not found');
|
|
||||||
} else {
|
|
||||||
return res.status(200).send(data);
|
|
||||||
}
|
|
||||||
}, res, next);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var processStaticMap = function(areaParams, req, res, next) {
|
|
||||||
var scale = getScale(req.params.scale),
|
|
||||||
format = req.params.format,
|
|
||||||
params = {
|
|
||||||
zoom: req.params.z | 0,
|
|
||||||
scale: scale,
|
|
||||||
bbox: areaParams.bbox,
|
|
||||||
center: areaParams.center,
|
|
||||||
format: format,
|
|
||||||
limit: 4097,
|
|
||||||
getTile: function(z, x, y, callback) {
|
|
||||||
return getTile(z, x, y, scale, format, function(err, data, headers) {
|
|
||||||
if (!err && data == null) {
|
|
||||||
err = new Error('Not found');
|
|
||||||
err.status = 404;
|
|
||||||
}
|
|
||||||
callback(err, data, headers);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
return abaculus(params, function(err, data, headers) {
|
|
||||||
if (err && !err.status) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
if (headers) {
|
|
||||||
headers['Content-Type'] = 'image/' + format;
|
|
||||||
res.set(headers);
|
|
||||||
}
|
|
||||||
res.status((err && err.status) || 200);
|
|
||||||
return res.send((err && err.message) || data);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
res.status(400);
|
|
||||||
return res.send(e.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var staticPattern =
|
var staticPattern =
|
||||||
'/static/%s:scale(' + SCALE_PATTERN + ')?\.:format([\\w\\.]+)';
|
'/static/%s:scale(' + SCALE_PATTERN + ')?\.:format([\\w\\.]+)';
|
||||||
|
|
||||||
|
@ -338,14 +265,14 @@ module.exports = function(maps, options, prefix) {
|
||||||
FLOAT_PATTERN, FLOAT_PATTERN);
|
FLOAT_PATTERN, FLOAT_PATTERN);
|
||||||
|
|
||||||
app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
|
app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
|
||||||
return processStaticMap({
|
var z = req.params.z | 0,
|
||||||
center: {
|
x = +req.params.lon,
|
||||||
x: +req.params.lon,
|
y = +req.params.lat,
|
||||||
y: +req.params.lat,
|
w = req.params.width | 0,
|
||||||
w: req.params.width | 0,
|
h = req.params.height | 0,
|
||||||
h: req.params.height | 0
|
scale = getScale(req.params.scale),
|
||||||
}
|
format = req.params.format;
|
||||||
}, req, res, next);
|
return respondImage(z, x, y, w, h, scale, format, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
var boundsPattern =
|
var boundsPattern =
|
||||||
|
@ -353,14 +280,14 @@ module.exports = function(maps, options, prefix) {
|
||||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
||||||
|
|
||||||
app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
|
app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
|
||||||
return processStaticMap({
|
var z = req.params.z | 0,
|
||||||
bbox: [
|
x = ((+req.params.minx) + (+req.params.maxx)) / 2,
|
||||||
+req.params.minx,
|
y = ((+req.params.miny) + (+req.params.maxy)) / 2,
|
||||||
+req.params.miny,
|
w = req.params.width | 0,
|
||||||
+req.params.maxx,
|
h = req.params.height | 0,
|
||||||
+req.params.maxy
|
scale = getScale(req.params.scale),
|
||||||
]
|
format = req.params.format;
|
||||||
}, req, res, next);
|
return respondImage(z, x, y, w, h, scale, format, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/index.json', function(req, res, next) {
|
app.get('/index.json', function(req, res, next) {
|
||||||
|
|
Loading…
Reference in a new issue