Merge 3e84297b30 into 1d734f9b42
This commit is contained in:
commit
fc6976c4d0
11 changed files with 295 additions and 219 deletions
11
.eslintrc.json
Normal file
11
.eslintrc.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es6": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
FROM node:6
|
|
||||||
MAINTAINER Petr Sloup <petr.sloup@klokantech.com>
|
|
||||||
|
|
||||||
ENV NODE_ENV="production"
|
|
||||||
EXPOSE 80
|
|
||||||
VOLUME /data
|
|
||||||
WORKDIR /data
|
|
||||||
ENTRYPOINT ["node", "/usr/src/app/", "-p", "80"]
|
|
||||||
|
|
||||||
RUN mkdir -p /usr/src/app
|
|
||||||
COPY / /usr/src/app
|
|
||||||
RUN cd /usr/src/app && npm install --production
|
|
||||||
3
Jenkinsfile
vendored
Normal file
3
Jenkinsfile
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
@Library("jenkins-devops-scripts") _
|
||||||
|
tileserver-gl {
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ TileServer GL
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Copyright (c) 2016, Klokan Technologies GmbH
|
Copyright (c) 2016, Klokan Technologies GmbH
|
||||||
|
Copyright (c) 2018, Beat (markers feature)
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
|
|
||||||
44
README.md
44
README.md
|
|
@ -1,48 +1,14 @@
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
# TileServer GL
|
# TileServer GL
|
||||||
[](https://travis-ci.org/klokantech/tileserver-gl)
|
|
||||||
[](https://hub.docker.com/r/klokantech/tileserver-gl/)
|
|
||||||
|
|
||||||
Vector and raster maps with GL styles. Server side rendering by Mapbox GL Native. Map tile server for Mapbox GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc.
|
Vector and raster maps with GL styles. Server side rendering by Mapbox GL Native. Map tile server for Mapbox GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc.
|
||||||
|
|
||||||
## Get Started
|
This fork adds features used by BEAT, including:
|
||||||
|
|
||||||
Make sure you have Node.js version **6** installed (running `node -v` it should output something like `v6.11.3`).
|
* Marker support in the static (rendered) maps
|
||||||
|
* Prometheus compatible `/metrics` endpoint
|
||||||
|
* Improved `/health` endpoint
|
||||||
|
|
||||||
Install `tileserver-gl` with server-side raster rendering of vector tiles with npm
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -g tileserver-gl
|
|
||||||
```
|
|
||||||
|
|
||||||
Now download vector tiles from [OpenMapTiles](https://openmaptiles.org/downloads/).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -o zurich_switzerland.mbtiles https://[GET-YOUR-LINK]/extracts/zurich_switzerland.mbtiles
|
|
||||||
```
|
|
||||||
|
|
||||||
Start `tileserver-gl` with the downloaded vector tiles.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tileserver-gl zurich_switzerland.mbtiles
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can use the `tileserver-gl-light` package instead, which is pure javascript (does not have any native dependencies) and can run anywhere, but does not contain rasterization on the server side made with MapBox GL Native.
|
|
||||||
|
|
||||||
## Using Docker
|
|
||||||
|
|
||||||
An alternative to npm to start the packed software easier is to install [Docker](http://www.docker.com/) on your computer and then run in the directory with the downloaded MBTiles the command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
|
|
||||||
```
|
|
||||||
|
|
||||||
This will download and start a ready to use container on your computer and the maps are going to be available in webbrowser on localhost:8080.
|
|
||||||
|
|
||||||
On laptop you can use [Docker Kitematic](https://kitematic.com/) and search "tileserver-gl" and run it, then drop in the 'data' folder the MBTiles.
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
You can read full documentation of this project at http://tileserver.readthedocs.io/.
|
You can read full documentation of the upstream project at http://tileserver.readthedocs.io/.
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
# TileServer GL light
|
|
||||||
[](https://travis-ci.org/klokantech/tileserver-gl)
|
|
||||||
[](https://hub.docker.com/r/klokantech/tileserver-gl/)
|
|
||||||
|
|
||||||
Vector maps with GL styles. Map tile server for Mapbox Android, iOS, GL JS, Leaflet, OpenLayers, etc. without server side rendering.
|
|
||||||
|
|
||||||
## Quickstart
|
|
||||||
Use `npm install -g tileserver-gl-light` to install the package from npm.
|
|
||||||
|
|
||||||
Then you can simply run `tileserver-gl-light zurich_switzerland.mbtiles` to start the server for the given mbtiles.
|
|
||||||
|
|
||||||
See also `tileserver-gl` which contains server side rendering.
|
|
||||||
|
|
||||||
Prepared vector tiles can be downloaded from [OSM2VectorTiles](http://osm2vectortiles.org/).
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
You can read full documentation of this project at http://tileserver.readthedocs.io/.
|
|
||||||
18
package.json
18
package.json
|
|
@ -19,13 +19,13 @@
|
||||||
"test": "mocha test/**.js --timeout 10000"
|
"test": "mocha test/**.js --timeout 10000"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/mapbox-gl-native": "3.5.4",
|
"@mapbox/mapbox-gl-native": "3.5.8",
|
||||||
"@mapbox/mbtiles": "0.9.0",
|
"@mapbox/mbtiles": "0.9.0",
|
||||||
"@mapbox/sphericalmercator": "1.0.5",
|
"@mapbox/sphericalmercator": "1.0.5",
|
||||||
"@mapbox/vector-tile": "1.3.0",
|
"@mapbox/vector-tile": "1.3.0",
|
||||||
"advanced-pool": "0.3.3",
|
"advanced-pool": "0.3.3",
|
||||||
"base64url": "2.0.0",
|
"base64url": "2.0.0",
|
||||||
"canvas": "1.6.8",
|
"canvas": "^1.6.8",
|
||||||
"clone": "2.1.1",
|
"clone": "2.1.1",
|
||||||
"color": "1.0.3",
|
"color": "1.0.3",
|
||||||
"commander": "2.1.0",
|
"commander": "2.1.0",
|
||||||
|
|
@ -35,15 +35,25 @@
|
||||||
"handlebars": "4.0.11",
|
"handlebars": "4.0.11",
|
||||||
"http-shutdown": "^1.2.0",
|
"http-shutdown": "^1.2.0",
|
||||||
"morgan": "1.9.0",
|
"morgan": "1.9.0",
|
||||||
|
"nomnom": "1.8.1",
|
||||||
|
"npm": "^5.8.0",
|
||||||
"pbf": "3.0.5",
|
"pbf": "3.0.5",
|
||||||
"proj4": "2.4.4",
|
"proj4": "2.4.4",
|
||||||
|
"prom-client": "11.0.0",
|
||||||
"request": "2.83.0",
|
"request": "2.83.0",
|
||||||
"sharp": "0.18.2",
|
"sharp": "^0.20.0",
|
||||||
"tileserver-gl-styles": "1.2.0"
|
"tileserver-gl-styles": "1.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"eslint-config-standard": "^11.0.0",
|
||||||
|
"eslint-plugin-import": "^2.11.0",
|
||||||
|
"eslint-plugin-node": "^6.0.1",
|
||||||
|
"eslint-plugin-promise": "^3.7.0",
|
||||||
|
"eslint-plugin-standard": "^3.1.0",
|
||||||
|
"mocha": "^3.2.0",
|
||||||
"should": "^11.2.0",
|
"should": "^11.2.0",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^3.2.0",
|
||||||
"supertest": "^3.0.0"
|
"supertest": "^3.0.0",
|
||||||
|
"eslint": "^4.19.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
src/avgresp.js
Normal file
42
src/avgresp.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var prometheus = require('prom-client');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
avgresp: avgresp
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var history;
|
||||||
|
var samples;
|
||||||
|
var fullhistory = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create middleware to record and output average response times
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {function}
|
||||||
|
*/
|
||||||
|
function avgresp(options) {
|
||||||
|
|
||||||
|
var opts = options || {};
|
||||||
|
|
||||||
|
history = 50;
|
||||||
|
samples = new Array(history);
|
||||||
|
var currentIndex = 0;
|
||||||
|
|
||||||
|
const respSummary = new prometheus.Summary({
|
||||||
|
name: "tileserver_static_latency_seconds",
|
||||||
|
help: "The tileserver response time in seconds"
|
||||||
|
});
|
||||||
|
|
||||||
|
return function avgresp(req, res, next) {
|
||||||
|
var end = respSummary.startTimer();
|
||||||
|
|
||||||
|
res.on('finish', function() {
|
||||||
|
end();
|
||||||
|
})
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,31 +1,30 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var advancedPool = require('advanced-pool'),
|
let advancedPool = require('advanced-pool');
|
||||||
fs = require('fs'),
|
let fs = require('fs');
|
||||||
path = require('path'),
|
let path = require('path');
|
||||||
url = require('url'),
|
let url = require('url');
|
||||||
util = require('util'),
|
let util = require('util');
|
||||||
zlib = require('zlib');
|
let zlib = require('zlib');
|
||||||
|
|
||||||
// sharp has to be required before node-canvas
|
// sharp has to be required before node-canvas
|
||||||
// see https://github.com/lovell/sharp/issues/371
|
// see https://github.com/lovell/sharp/issues/371
|
||||||
var sharp = require('sharp');
|
let sharp = require('sharp');
|
||||||
|
let Canvas = require('canvas');
|
||||||
|
let clone = require('clone');
|
||||||
|
let Color = require('color');
|
||||||
|
let express = require('express');
|
||||||
|
let mercator = new (require('@mapbox/sphericalmercator'))();
|
||||||
|
let mbgl = require('@mapbox/mapbox-gl-native');
|
||||||
|
let mbtiles = require('@mapbox/mbtiles');
|
||||||
|
let proj4 = require('proj4');
|
||||||
|
let request = require('request');
|
||||||
|
|
||||||
var Canvas = require('canvas'),
|
let utils = require('./utils');
|
||||||
clone = require('clone'),
|
let markerSize = 15;
|
||||||
Color = require('color'),
|
let FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
|
||||||
express = require('express'),
|
|
||||||
mercator = new (require('@mapbox/sphericalmercator'))(),
|
|
||||||
mbgl = require('@mapbox/mapbox-gl-native'),
|
|
||||||
mbtiles = require('@mapbox/mbtiles'),
|
|
||||||
proj4 = require('proj4'),
|
|
||||||
request = require('request');
|
|
||||||
|
|
||||||
var utils = require('./utils');
|
let getScale = function(scale) {
|
||||||
|
|
||||||
var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
|
|
||||||
|
|
||||||
var getScale = function(scale) {
|
|
||||||
return (scale || '@1x').slice(1, 2) | 0;
|
return (scale || '@1x').slice(1, 2) | 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -38,18 +37,18 @@ mbgl.on('message', function(e) {
|
||||||
/**
|
/**
|
||||||
* Lookup of sharp output formats by file extension.
|
* Lookup of sharp output formats by file extension.
|
||||||
*/
|
*/
|
||||||
var extensionToFormat = {
|
let extensionToFormat = {
|
||||||
'.jpg': 'jpeg',
|
'.jpg': 'jpeg',
|
||||||
'.jpeg': 'jpeg',
|
'.jpeg': 'jpeg',
|
||||||
'.png': 'png',
|
'.png': 'png',
|
||||||
'.webp': 'webp'
|
'.webp': 'webp',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of response data by sharp output format and color. Entry for empty
|
* Cache of response data by sharp output format and color. Entry for empty
|
||||||
* string is for unknown or unsupported formats.
|
* string is for unknown or unsupported formats.
|
||||||
*/
|
*/
|
||||||
var cachedEmptyResponses = {
|
let cachedEmptyResponses = {
|
||||||
'': new Buffer(0)
|
'': new Buffer(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -61,26 +60,9 @@ var cachedEmptyResponses = {
|
||||||
*/
|
*/
|
||||||
function createEmptyResponse(format, color, callback) {
|
function createEmptyResponse(format, color, callback) {
|
||||||
if (!format || format === 'pbf') {
|
if (!format || format === 'pbf') {
|
||||||
callback(null, {data: cachedEmptyResponses['']});
|
callback(null, { data: cachedEmptyResponses[''] });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === 'jpg') {
|
|
||||||
format = 'jpeg';
|
|
||||||
}
|
|
||||||
if (!color) {
|
|
||||||
color = 'rgba(255,255,255,0)';
|
|
||||||
}
|
|
||||||
|
|
||||||
var cacheKey = format + ',' + color;
|
|
||||||
var data = cachedEmptyResponses[cacheKey];
|
|
||||||
if (data) {
|
|
||||||
callback(null, {data: data});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an "empty" response image
|
|
||||||
var color = new Color(color);
|
|
||||||
var array = color.array();
|
var array = color.array();
|
||||||
var channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
|
var channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
|
||||||
sharp(new Buffer(array), {
|
sharp(new Buffer(array), {
|
||||||
|
|
@ -93,7 +75,7 @@ function createEmptyResponse(format, color, callback) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
cachedEmptyResponses[cacheKey] = buffer;
|
cachedEmptyResponses[cacheKey] = buffer;
|
||||||
}
|
}
|
||||||
callback(null, {data: buffer});
|
callback(null, { data: buffer });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,10 +88,10 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
scalePattern += i.toFixed();
|
scalePattern += i.toFixed();
|
||||||
}
|
}
|
||||||
scalePattern = '@[' + scalePattern + ']x';
|
scalePattern = '@[' + scalePattern + ']x';
|
||||||
|
4
|
||||||
var lastModified = new Date().toUTCString();
|
var lastModified = new Date().toUTCString();
|
||||||
|
|
||||||
var rootPath = options.paths.root;
|
// var rootPath = options.paths.root;
|
||||||
|
|
||||||
var watermark = params.watermark || options.watermark;
|
var watermark = params.watermark || options.watermark;
|
||||||
|
|
||||||
|
|
@ -162,9 +144,9 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
utils.getFontsPbf(
|
utils.getFontsPbf(
|
||||||
null, options.paths[protocol], fontstack, range, existingFonts
|
null, options.paths[protocol], fontstack, range, existingFonts
|
||||||
).then(function(concated) {
|
).then(function(concated) {
|
||||||
callback(null, {data: concated});
|
callback(null, { data: concated });
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
callback(err, {data: null});
|
callback(err, { data: null });
|
||||||
});
|
});
|
||||||
} else if (protocol == 'mbtiles') {
|
} else if (protocol == 'mbtiles') {
|
||||||
var parts = req.url.split('/');
|
var parts = req.url.split('/');
|
||||||
|
|
@ -172,9 +154,9 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
var source = map.sources[sourceId];
|
var source = map.sources[sourceId];
|
||||||
var sourceInfo = styleJSON.sources[sourceId];
|
var sourceInfo = styleJSON.sources[sourceId];
|
||||||
var z = parts[3] | 0,
|
var z = parts[3] | 0,
|
||||||
x = parts[4] | 0,
|
x = parts[4] | 0,
|
||||||
y = parts[5].split('.')[0] | 0,
|
y = parts[5].split('.')[0] | 0,
|
||||||
format = parts[5].split('.')[1];
|
format = parts[5].split('.')[1];
|
||||||
source.getTile(z, x, y, function(err, data, headers) {
|
source.getTile(z, x, y, function(err, data, headers) {
|
||||||
if (err) {
|
if (err) {
|
||||||
//console.log('MBTiles error, serving empty', err);
|
//console.log('MBTiles error, serving empty', err);
|
||||||
|
|
@ -204,34 +186,34 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
|
|
||||||
callback(null, response);
|
callback(null, response);
|
||||||
});
|
});
|
||||||
} else if (protocol == 'http' || protocol == 'https') {
|
} else if (protocol === 'http' || protocol === 'https') {
|
||||||
request({
|
request({
|
||||||
url: req.url,
|
url: req.url,
|
||||||
encoding: null,
|
encoding: null,
|
||||||
gzip: true
|
gzip: true
|
||||||
}, function(err, res, body) {
|
}, function(err, res, body) {
|
||||||
var parts = url.parse(req.url);
|
var parts = url.parse(req.url);
|
||||||
var extension = path.extname(parts.pathname).toLowerCase();
|
var extension = path.extname(parts.pathname).toLowerCase();
|
||||||
var format = extensionToFormat[extension] || '';
|
var format = extensionToFormat[extension] || '';
|
||||||
if (err || res.statusCode < 200 || res.statusCode >= 300) {
|
if (err || res.statusCode < 200 || res.statusCode >= 300) {
|
||||||
// console.log('HTTP error', err || res.statusCode);
|
// console.log('HTTP error', err || res.statusCode);
|
||||||
createEmptyResponse(format, '', callback);
|
createEmptyResponse(format, '', callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = {};
|
var response = {};
|
||||||
if (res.headers.modified) {
|
if (res.headers.modified) {
|
||||||
response.modified = new Date(res.headers.modified);
|
response.modified = new Date(res.headers.modified);
|
||||||
}
|
}
|
||||||
if (res.headers.expires) {
|
if (res.headers.expires) {
|
||||||
response.expires = new Date(res.headers.expires);
|
response.expires = new Date(res.headers.expires);
|
||||||
}
|
}
|
||||||
if (res.headers.etag) {
|
if (res.headers.etag) {
|
||||||
response.etag = res.headers.etag;
|
response.etag = res.headers.etag;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.data = body;
|
response.data = body;
|
||||||
callback(null, response);
|
callback(null, response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,14 +237,35 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
var httpTester = /^(http(s)?:)?\/\//;
|
var httpTester = /^(http(s)?:)?\/\//;
|
||||||
if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
|
if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
|
||||||
styleJSON.sprite = 'sprites://' +
|
styleJSON.sprite = 'sprites://' +
|
||||||
styleJSON.sprite
|
styleJSON.sprite
|
||||||
.replace('{style}', path.basename(styleFile, '.json'))
|
.replace('{style}', path.basename(styleFile, '.json'))
|
||||||
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath)));
|
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath)));
|
||||||
}
|
}
|
||||||
if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
|
if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
|
||||||
styleJSON.glyphs = 'fonts://' + styleJSON.glyphs;
|
styleJSON.glyphs = 'fonts://' + styleJSON.glyphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var markerImages = [];
|
||||||
|
var markerImageNames = ['pickup', 'dropoff'];
|
||||||
|
|
||||||
|
|
||||||
|
var markerLoadPromise = new Promise(function(resolveCallback, rejectCallback) {
|
||||||
|
|
||||||
|
markerImageNames.forEach(function(imageName) {
|
||||||
|
fs.readFile(path.join(__dirname, "../public/resources/images/") + imageName + '-marker.png', function(err, fileData) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
rejectCallback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mkrImage = new Canvas.Image();
|
||||||
|
mkrImage.src = fileData;
|
||||||
|
markerImages.push(mkrImage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
resolveCallback();
|
||||||
|
});
|
||||||
|
|
||||||
var tileJSON = {
|
var tileJSON = {
|
||||||
'tilejson': '2.0.0',
|
'tilejson': '2.0.0',
|
||||||
'name': styleJSON.name,
|
'name': styleJSON.name,
|
||||||
|
|
@ -291,7 +294,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
|
|
||||||
var mbtilesFile = url.substring('mbtiles://'.length);
|
var mbtilesFile = url.substring('mbtiles://'.length);
|
||||||
var fromData = mbtilesFile[0] == '{' &&
|
var fromData = mbtilesFile[0] == '{' &&
|
||||||
mbtilesFile[mbtilesFile.length - 1] == '}';
|
mbtilesFile[mbtilesFile.length - 1] == '}';
|
||||||
|
|
||||||
if (fromData) {
|
if (fromData) {
|
||||||
mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2);
|
mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2);
|
||||||
|
|
@ -342,7 +345,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attributionOverride &&
|
if (!attributionOverride &&
|
||||||
source.attribution && source.attribution.length > 0) {
|
source.attribution && source.attribution.length > 0) {
|
||||||
if (tileJSON.attribution.length > 0) {
|
if (tileJSON.attribution.length > 0) {
|
||||||
tileJSON.attribution += '; ';
|
tileJSON.attribution += '; ';
|
||||||
}
|
}
|
||||||
|
|
@ -371,25 +374,27 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
repo[id] = tileJSON;
|
repo[id] = tileJSON;
|
||||||
|
|
||||||
var tilePattern = '/' + id + '/:z(\\d+)/:x(\\d+)/:y(\\d+)' +
|
var tilePattern = '/' + id + '/:z(\\d+)/:x(\\d+)/:y(\\d+)' +
|
||||||
':scale(' + scalePattern + ')?\.:format([\\w]+)';
|
':scale(' + scalePattern + ')?\.:format([\\w]+)';
|
||||||
|
|
||||||
var respondImage = function(z, lon, lat, bearing, pitch,
|
var respondImage = function(z, lon, lat, bearing, pitch,
|
||||||
width, height, scale, format, res, next,
|
width, height, scale, format, res, next,
|
||||||
opt_overlay) {
|
opt_overlay) {
|
||||||
if (Math.abs(lon) > 180 || Math.abs(lat) > 85.06 ||
|
if (Math.abs(lon) > 180 || Math.abs(lat) > 85.06 ||
|
||||||
lon != lon || lat != lat) {
|
lon != lon || lat != lat) {
|
||||||
return res.status(400).send('Invalid center');
|
return res.status(400).send('Invalid center');
|
||||||
}
|
}
|
||||||
if (Math.min(width, height) <= 0 ||
|
if (Math.min(width, height) <= 0 ||
|
||||||
Math.max(width, height) * scale > (options.maxSize || 2048) ||
|
Math.max(width, height) * scale > (options.maxSize || 2048) ||
|
||||||
width != width || height != height) {
|
width != width || height != height) {
|
||||||
return res.status(400).send('Invalid size');
|
return res.status(400).send('Invalid size');
|
||||||
}
|
}
|
||||||
if (format == 'png' || format == 'webp') {
|
|
||||||
} else if (format == 'jpg' || format == 'jpeg') {
|
let formatIndex = ['jpg', 'jpeg', 'png', 'webp'].indexOf(format);
|
||||||
format = 'jpeg';
|
|
||||||
} else {
|
if (formatIndex == -1) {
|
||||||
return res.status(400).send('Invalid format');
|
return res.status(400).send('Invalid format');
|
||||||
|
} else if (formatIndex < 2) {
|
||||||
|
format = 'jpeg';
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool = map.renderers[scale];
|
var pool = map.renderers[scale];
|
||||||
|
|
@ -445,14 +450,14 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var formatQuality = (params.formatQuality || {})[format] ||
|
var formatQuality = (params.formatQuality || {})[format] ||
|
||||||
(options.formatQuality || {})[format];
|
(options.formatQuality || {})[format];
|
||||||
|
|
||||||
if (format == 'png') {
|
if (format == 'png') {
|
||||||
image.png({adaptiveFiltering: false});
|
image.png({ adaptiveFiltering: false });
|
||||||
} else if (format == 'jpeg') {
|
} else if (format == 'jpeg') {
|
||||||
image.jpeg({quality: formatQuality || 80});
|
image.jpeg({ quality: formatQuality || 80 });
|
||||||
} else if (format == 'webp') {
|
} else if (format == 'webp') {
|
||||||
image.webp({quality: formatQuality || 90});
|
image.webp({ quality: formatQuality || 90 });
|
||||||
}
|
}
|
||||||
image.toBuffer(function(err, buffer, info) {
|
image.toBuffer(function(err, buffer, info) {
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
|
|
@ -478,12 +483,12 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var z = req.params.z | 0,
|
var z = req.params.z | 0,
|
||||||
x = req.params.x | 0,
|
x = req.params.x | 0,
|
||||||
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;
|
||||||
if (z < 0 || x < 0 || y < 0 ||
|
if (z < 0 || x < 0 || y < 0 ||
|
||||||
z > 20 || x >= Math.pow(2, z) || y >= Math.pow(2, z)) {
|
z > 20 || x >= Math.pow(2, z) || y >= Math.pow(2, z)) {
|
||||||
return res.status(404).send('Out of bounds');
|
return res.status(404).send('Out of bounds');
|
||||||
}
|
}
|
||||||
var tileSize = 256;
|
var tileSize = 256;
|
||||||
|
|
@ -492,7 +497,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
((y + 0.5) / (1 << z)) * (256 << z)
|
((y + 0.5) / (1 << z)) * (256 << z)
|
||||||
], z);
|
], z);
|
||||||
return respondImage(z, tileCenter[0], tileCenter[1], 0, 0,
|
return respondImage(z, tileCenter[0], tileCenter[1], 0, 0,
|
||||||
tileSize, tileSize, scale, format, res, next);
|
tileSize, tileSize, scale, format, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
var extractPathFromQuery = function(query, transformer) {
|
var extractPathFromQuery = function(query, transformer) {
|
||||||
|
|
@ -516,8 +521,40 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var drawMarker = function(ctx, coordinates, scale, outerColour = "rgb(0,0,0)", innerColour = "rgb(255,255,255)", outerRadius = markerSize, innerRadius = markerSize * 0.35) {
|
||||||
|
|
||||||
|
[outerRadius, innerRadius, coordinates[0], coordinates[1]].map(console.log);
|
||||||
|
|
||||||
|
outerRadius = parseInt(outerRadius);
|
||||||
|
innerRadius = parseInt(innerRadius);
|
||||||
|
let x = parseInt(coordinates[0]);
|
||||||
|
let y = parseInt(coordinates[1]);
|
||||||
|
|
||||||
|
let validParams = [outerRadius, innerRadius, x, y].reduce(function(acc, element) {
|
||||||
|
if (isNaN(element)) {
|
||||||
|
console.log("element: " + element + " is invalid.");
|
||||||
|
}
|
||||||
|
return acc && !isNaN(element);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
if (!validParams) {
|
||||||
|
console.log("invalid parameters!");
|
||||||
|
}
|
||||||
|
// outer circle.
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, outerRadius, 0, 2 * Math.PI, false);
|
||||||
|
ctx.fillStyle = outerColour;
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// inner circle.
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, innerRadius, 0, 2 * Math.PI, false);
|
||||||
|
ctx.fillStyle = innerColour;
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
|
||||||
var renderOverlay = function(z, x, y, bearing, pitch, w, h, scale,
|
var renderOverlay = function(z, x, y, bearing, pitch, w, h, scale,
|
||||||
path, query) {
|
path, query) {
|
||||||
if (!path || path.length < 2) {
|
if (!path || path.length < 2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -550,7 +587,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
ctx.translate(-center[0] + w / 2, -center[1] + h / 2);
|
ctx.translate(-center[0] + w / 2, -center[1] + h / 2);
|
||||||
}
|
}
|
||||||
var lineWidth = query.width !== undefined ?
|
var lineWidth = query.width !== undefined ?
|
||||||
parseFloat(query.width) : 1;
|
parseFloat(query.width) : 1;
|
||||||
ctx.lineWidth = lineWidth;
|
ctx.lineWidth = lineWidth;
|
||||||
ctx.strokeStyle = query.stroke || 'rgba(0,64,255,0.7)';
|
ctx.strokeStyle = query.stroke || 'rgba(0,64,255,0.7)';
|
||||||
ctx.fillStyle = query.fill || 'rgba(255,255,255,0.4)';
|
ctx.fillStyle = query.fill || 'rgba(255,255,255,0.4)';
|
||||||
|
|
@ -560,7 +597,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
ctx.lineTo(px[0], px[1]);
|
ctx.lineTo(px[0], px[1]);
|
||||||
});
|
});
|
||||||
if (path[0][0] == path[path.length - 1][0] &&
|
if (path[0][0] == path[path.length - 1][0] &&
|
||||||
path[0][1] == path[path.length - 1][1]) {
|
path[0][1] == path[path.length - 1][1]) {
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
}
|
}
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
@ -568,6 +605,12 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query.showMarkers && query.showMarkers == 1) {
|
||||||
|
// Add the markers, if requested to do so.
|
||||||
|
drawMarker(ctx,precisePx(path[path.length-1],z),scale, "rgba(179, 0, 0, 0.7)");
|
||||||
|
drawMarker(ctx,precisePx(path[0],z),scale, "rgba(0, 151, 25, 0.7)");
|
||||||
|
}
|
||||||
|
|
||||||
return canvas.toBuffer();
|
return canvas.toBuffer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -575,10 +618,10 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
var z = 25;
|
var z = 25;
|
||||||
|
|
||||||
var padding = query.padding !== undefined ?
|
var padding = query.padding !== undefined ?
|
||||||
parseFloat(query.padding) : 0.1;
|
parseFloat(query.padding) : 0.1;
|
||||||
|
|
||||||
var minCorner = mercator.px([bbox[0], bbox[3]], z),
|
var minCorner = mercator.px([bbox[0], bbox[3]], z),
|
||||||
maxCorner = mercator.px([bbox[2], bbox[1]], z);
|
maxCorner = mercator.px([bbox[2], bbox[1]], z);
|
||||||
var w_ = w / (1 + 2 * padding);
|
var w_ = w / (1 + 2 * padding);
|
||||||
var h_ = h / (1 + 2 * padding);
|
var h_ = h / (1 + 2 * padding);
|
||||||
|
|
||||||
|
|
@ -594,28 +637,28 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
|
|
||||||
if (options.serveStaticMaps !== false) {
|
if (options.serveStaticMaps !== false) {
|
||||||
var staticPattern =
|
var staticPattern =
|
||||||
'/' + id + '/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+)' +
|
'/' + id + '/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+)' +
|
||||||
':scale(' + scalePattern + ')?\.:format([\\w]+)';
|
':scale(' + scalePattern + ')?.:format([\\w]+)';
|
||||||
|
|
||||||
var centerPattern =
|
var centerPattern =
|
||||||
util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?',
|
util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?',
|
||||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
|
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
|
||||||
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) {
|
||||||
var raw = req.params.raw;
|
var raw = req.params.raw;
|
||||||
var z = +req.params.z,
|
var z = +req.params.z,
|
||||||
x = +req.params.x,
|
x = +req.params.x,
|
||||||
y = +req.params.y,
|
y = +req.params.y,
|
||||||
bearing = +(req.params.bearing || '0'),
|
bearing = +(req.params.bearing || '0'),
|
||||||
pitch = +(req.params.pitch || '0'),
|
pitch = +(req.params.pitch || '0'),
|
||||||
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),
|
scale = getScale(req.params.scale),
|
||||||
format = req.params.format;
|
format = req.params.format;
|
||||||
|
|
||||||
if (z < 0) {
|
if (z < 0) {
|
||||||
return res.status(404).send('Invalid zoom');
|
return res.status(400).send('Invalid zoom');
|
||||||
}
|
}
|
||||||
|
|
||||||
var transformer = raw ?
|
var transformer = raw ?
|
||||||
|
|
@ -629,16 +672,16 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
|
|
||||||
var path = extractPathFromQuery(req.query, transformer);
|
var path = extractPathFromQuery(req.query, transformer);
|
||||||
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
||||||
path, req.query);
|
path, req.query);
|
||||||
|
|
||||||
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
||||||
res, next, overlay);
|
res, next, overlay);
|
||||||
});
|
});
|
||||||
|
|
||||||
var serveBounds = function(req, res, next) {
|
var serveBounds = function(req, res, next) {
|
||||||
var raw = req.params.raw;
|
var raw = req.params.raw;
|
||||||
var bbox = [+req.params.minx, +req.params.miny,
|
var bbox = [+req.params.minx, +req.params.miny,
|
||||||
+req.params.maxx, +req.params.maxy];
|
+req.params.maxx, +req.params.maxy];
|
||||||
var center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
var center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
||||||
|
|
||||||
var transformer = raw ?
|
var transformer = raw ?
|
||||||
|
|
@ -655,26 +698,26 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var w = req.params.width | 0,
|
var w = req.params.width | 0,
|
||||||
h = req.params.height | 0,
|
h = req.params.height | 0,
|
||||||
scale = getScale(req.params.scale),
|
scale = getScale(req.params.scale),
|
||||||
format = req.params.format;
|
format = req.params.format;
|
||||||
|
|
||||||
var z = calcZForBBox(bbox, w, h, req.query),
|
var z = calcZForBBox(bbox, w, h, req.query),
|
||||||
x = center[0],
|
x = center[0],
|
||||||
y = center[1],
|
y = center[1],
|
||||||
bearing = 0,
|
bearing = 0,
|
||||||
pitch = 0;
|
pitch = 0;
|
||||||
|
|
||||||
var path = extractPathFromQuery(req.query, transformer);
|
var path = extractPathFromQuery(req.query, transformer);
|
||||||
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
||||||
path, req.query);
|
path, req.query);
|
||||||
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
||||||
res, next, overlay);
|
res, next, overlay);
|
||||||
};
|
};
|
||||||
|
|
||||||
var boundsPattern =
|
var boundsPattern =
|
||||||
util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)',
|
util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)',
|
||||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
||||||
|
|
||||||
app.get(util.format(staticPattern, boundsPattern), serveBounds);
|
app.get(util.format(staticPattern, boundsPattern), serveBounds);
|
||||||
|
|
||||||
|
|
@ -705,11 +748,11 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
app.get(util.format(staticPattern, autoPattern), function(req, res, next) {
|
app.get(util.format(staticPattern, autoPattern), function(req, res, next) {
|
||||||
var raw = req.params.raw;
|
var raw = req.params.raw;
|
||||||
var w = req.params.width | 0,
|
var w = req.params.width | 0,
|
||||||
h = req.params.height | 0,
|
h = req.params.height | 0,
|
||||||
bearing = 0,
|
bearing = 0,
|
||||||
pitch = 0,
|
pitch = 0,
|
||||||
scale = getScale(req.params.scale),
|
scale = getScale(req.params.scale),
|
||||||
format = req.params.format;
|
format = req.params.format;
|
||||||
|
|
||||||
var transformer = raw ?
|
var transformer = raw ?
|
||||||
mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS;
|
mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS;
|
||||||
|
|
@ -733,25 +776,25 @@ module.exports = function(options, repo, params, id, dataResolver) {
|
||||||
);
|
);
|
||||||
|
|
||||||
var z = calcZForBBox(bbox, w, h, req.query),
|
var z = calcZForBBox(bbox, w, h, req.query),
|
||||||
x = center[0],
|
x = center[0],
|
||||||
y = center[1];
|
y = center[1];
|
||||||
|
|
||||||
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
|
||||||
path, req.query);
|
path, req.query);
|
||||||
|
|
||||||
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
|
||||||
res, next, overlay);
|
res, next, overlay);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/' + id + '.json', function(req, res, next) {
|
app.get('/' + id + '.json', function(req, res, next) {
|
||||||
var info = clone(tileJSON);
|
var info = clone(tileJSON);
|
||||||
info.tiles = utils.getTileUrls(req, info.tiles,
|
info.tiles = utils.getTileUrls(req, info.tiles,
|
||||||
'styles/' + id, info.format);
|
'styles/' + id, info.format);
|
||||||
return res.send(info);
|
return res.send(info);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all([fontListingPromise, renderersReadyPromise]).then(function() {
|
return Promise.all([markerLoadPromise, fontListingPromise, renderersReadyPromise]).then(function() {
|
||||||
return app;
|
return app;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,11 @@ var packageJson = require('../package'),
|
||||||
serve_rendered = null,
|
serve_rendered = null,
|
||||||
serve_style = require('./serve_style'),
|
serve_style = require('./serve_style'),
|
||||||
serve_data = require('./serve_data'),
|
serve_data = require('./serve_data'),
|
||||||
utils = require('./utils');
|
utils = require('./utils'),
|
||||||
|
avgresp = require('./avgresp'),
|
||||||
|
prometheus = require('prom-client');
|
||||||
|
|
||||||
|
prometheus.collectDefaultMetrics({ timeout: 5000 });
|
||||||
|
|
||||||
var isLight = packageJson.name.slice(-6) == '-light';
|
var isLight = packageJson.name.slice(-6) == '-light';
|
||||||
if (!isLight) {
|
if (!isLight) {
|
||||||
|
|
@ -52,6 +56,8 @@ function start(opts) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.use(/\/styles\/.*\/static\/.*$/, avgresp.avgresp());
|
||||||
|
|
||||||
var config = opts.config || null;
|
var config = opts.config || null;
|
||||||
var configPath = null;
|
var configPath = null;
|
||||||
if (opts.configPath) {
|
if (opts.configPath) {
|
||||||
|
|
@ -391,12 +397,30 @@ function start(opts) {
|
||||||
console.log('Startup complete');
|
console.log('Startup complete');
|
||||||
startupComplete = true;
|
startupComplete = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/health', function(req, res, next) {
|
app.get('/health', function(req, res, next) {
|
||||||
|
|
||||||
|
var healthTemplate = {
|
||||||
|
"service": "tileserver",
|
||||||
|
"status": "200",
|
||||||
|
"message": "OK"
|
||||||
|
};
|
||||||
|
|
||||||
|
var statusCode = 200;
|
||||||
|
|
||||||
if (startupComplete) {
|
if (startupComplete) {
|
||||||
return res.status(200).send('OK');
|
statusCode = 200;
|
||||||
|
healthTemplate.message = "OK";
|
||||||
} else {
|
} else {
|
||||||
return res.status(503).send('Starting');
|
statusCode = 503;
|
||||||
|
healthTemplate.message = "Starting";
|
||||||
}
|
}
|
||||||
|
healthTemplate.status = statusCode;
|
||||||
|
return res.status(statusCode).send(healthTemplate);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/metrics', function(req, res, next){
|
||||||
|
res.end(prometheus.register.metrics());
|
||||||
});
|
});
|
||||||
|
|
||||||
var server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() {
|
var server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ describe('Static endpoints', function() {
|
||||||
testStatic(prefix, '0,0,0/256x256', 'gif', 400);
|
testStatic(prefix, '0,0,0/256x256', 'gif', 400);
|
||||||
testStatic(prefix, '0,0,0/256x256', 'png', 404, 1);
|
testStatic(prefix, '0,0,0/256x256', 'png', 404, 1);
|
||||||
|
|
||||||
testStatic(prefix, '0,0,-1/256x256', 'png', 404);
|
testStatic(prefix, '0,0,-1/256x256', 'png', 400);
|
||||||
testStatic(prefix, '0,0,0/256.5x256.5', 'png', 404);
|
testStatic(prefix, '0,0,0/256.5x256.5', 'png', 404);
|
||||||
|
|
||||||
testStatic(prefix, '0,0,0,/256x256', 'png', 404);
|
testStatic(prefix, '0,0,0,/256x256', 'png', 404);
|
||||||
|
|
@ -91,6 +91,11 @@ describe('Static endpoints', function() {
|
||||||
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20');
|
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20');
|
||||||
testStatic(prefix, 'auto/200x200', 'png', 200, 3, /image\/png/, '?path=-10,-10|-20,-20');
|
testStatic(prefix, 'auto/200x200', 'png', 200, 3, /image\/png/, '?path=-10,-10|-20,-20');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('with markers', function() {
|
||||||
|
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20&showMarkers=1');
|
||||||
|
testStatic(prefix, 'auto/20x20', 'png', 200, 2, /image\/png/, '?path=10,10|20,20&showMarkers=0');
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('invalid requests return 4xx', function() {
|
describe('invalid requests return 4xx', function() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue