Compare commits
38 Commits
v3.0.0
...
d2d2d38daf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2d2d38daf | ||
|
|
5d5be67efc | ||
|
|
aba60f0c6a | ||
|
|
6027d89623 | ||
|
|
8680a8006a | ||
|
|
09ded526ef | ||
|
|
c89a5ae029 | ||
|
|
a3d7f8bcbd | ||
|
|
7c1420982c | ||
|
|
51baa9b67b | ||
|
|
6b3f557b1f | ||
|
|
8d2ddd8f95 | ||
|
|
9f59f67087 | ||
|
|
1d21648969 | ||
|
|
16de5be673 | ||
|
|
6b96f224ae | ||
|
|
6ff4cae9b9 | ||
|
|
644db6cd8a | ||
|
|
a98404e921 | ||
|
|
559cfc462c | ||
|
|
559c3a913e | ||
|
|
4036d528ec | ||
|
|
6ae4116ccb | ||
|
|
39bb7ffbf1 | ||
|
|
e249a3f67d | ||
|
|
04b49d8a98 | ||
|
|
309d481117 | ||
|
|
7ce4805cdd | ||
|
|
5377414710 | ||
|
|
042b8b986a | ||
|
|
038bfe29d6 | ||
|
|
f8563e1f2b | ||
|
|
10431d70d0 | ||
|
|
a5a8ae1e95 | ||
|
|
3c411cd1ac | ||
|
|
79bd70942b | ||
|
|
5585f49396 | ||
|
|
8126b31081 |
@@ -1,7 +1,6 @@
|
|||||||
.git
|
*
|
||||||
docs/_build
|
!src
|
||||||
node_modules
|
!public
|
||||||
test_data
|
!package.json
|
||||||
light
|
!package-lock.json
|
||||||
config.json
|
!docker-entrypoint.sh
|
||||||
*.mbtiles
|
|
||||||
|
|||||||
67
Dockerfile
67
Dockerfile
@@ -1,30 +1,55 @@
|
|||||||
FROM node:10-stretch
|
FROM node:10-buster AS builder
|
||||||
|
|
||||||
|
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -qq update \
|
||||||
|
&& apt-get -y --no-install-recommends install \
|
||||||
|
apt-transport-https \
|
||||||
|
curl \
|
||||||
|
unzip \
|
||||||
|
build-essential \
|
||||||
|
python \
|
||||||
|
libcairo2-dev \
|
||||||
|
libgles2-mesa-dev \
|
||||||
|
libgbm-dev \
|
||||||
|
libllvm7 \
|
||||||
|
libprotobuf-dev \
|
||||||
|
&& apt-get -y --purge autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY . /usr/src/app
|
||||||
|
|
||||||
|
ENV NODE_ENV="production"
|
||||||
|
|
||||||
|
RUN cd /usr/src/app && npm install --production
|
||||||
|
|
||||||
|
|
||||||
|
FROM node:10-buster-slim AS final
|
||||||
|
|
||||||
|
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -qq update \
|
||||||
|
&& apt-get -y --no-install-recommends install \
|
||||||
|
libgles2-mesa \
|
||||||
|
libegl1 \
|
||||||
|
xvfb \
|
||||||
|
xauth \
|
||||||
|
&& apt-get -y --purge autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=builder /usr/src/app /app
|
||||||
|
|
||||||
ENV NODE_ENV="production"
|
ENV NODE_ENV="production"
|
||||||
ENV CHOKIDAR_USEPOLLING=1
|
ENV CHOKIDAR_USEPOLLING=1
|
||||||
ENV CHOKIDAR_INTERVAL=500
|
ENV CHOKIDAR_INTERVAL=500
|
||||||
|
|
||||||
VOLUME /data
|
VOLUME /data
|
||||||
WORKDIR /data
|
WORKDIR /data
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
ENTRYPOINT ["/bin/bash", "/usr/src/app/run.sh"]
|
|
||||||
|
|
||||||
RUN apt-get -qq update \
|
USER node:node
|
||||||
&& DEBIAN_FRONTEND=noninteractive apt-get -y install \
|
|
||||||
apt-transport-https \
|
|
||||||
curl \
|
|
||||||
unzip \
|
|
||||||
build-essential \
|
|
||||||
python \
|
|
||||||
libcairo2-dev \
|
|
||||||
libgles2-mesa-dev \
|
|
||||||
libgbm-dev \
|
|
||||||
libllvm3.9 \
|
|
||||||
libprotobuf-dev \
|
|
||||||
libxxf86vm-dev \
|
|
||||||
xvfb \
|
|
||||||
x11-utils \
|
|
||||||
&& apt-get clean
|
|
||||||
|
|
||||||
RUN mkdir -p /usr/src/app
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||||
COPY / /usr/src/app
|
|
||||||
RUN cd /usr/src/app && npm install --production
|
CMD ["-p", "80"]
|
||||||
|
|||||||
31
docker-entrypoint.sh
Executable file
31
docker-entrypoint.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
handle() {
|
||||||
|
SIGNAL=$(( $? - 128 ))
|
||||||
|
echo "Caught signal ${SIGNAL}, stopping gracefully"
|
||||||
|
kill -s ${SIGNAL} $(pidof node) 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
trap handle INT TERM
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
SIGNAL=$(( $? - 128 ))
|
||||||
|
echo "Caught signal ${SIGNAL}, refreshing"
|
||||||
|
kill -s ${SIGNAL} $(pidof node) 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
trap refresh HUP
|
||||||
|
|
||||||
|
if ! which -- "${1}"; then
|
||||||
|
# first arg is not an executable
|
||||||
|
xvfb-run -a --server-args="-screen 0 1024x768x24" -- node /app/ "$@" &
|
||||||
|
# Wait exits immediately on signals which have traps set. Store return value and wait
|
||||||
|
# again for all jobs to actually complete before continuing.
|
||||||
|
wait $! || RETVAL=$?
|
||||||
|
wait
|
||||||
|
exit ${RETVAL}
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -4,7 +4,9 @@ Configuration file
|
|||||||
|
|
||||||
The configuration file defines the behavior of the application. It's a regular JSON file.
|
The configuration file defines the behavior of the application. It's a regular JSON file.
|
||||||
|
|
||||||
Example::
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"options": {
|
"options": {
|
||||||
@@ -101,7 +103,7 @@ Default is ``2048``.
|
|||||||
--------------
|
--------------
|
||||||
|
|
||||||
Additional image side length added during tile rendering that is cropped from the delivered tile. This is useful for resolving the issue with cropped labels,
|
Additional image side length added during tile rendering that is cropped from the delivered tile. This is useful for resolving the issue with cropped labels,
|
||||||
but it does come with a performance degradation, because additional, adjacent vector tiles need to be loaded to genenrate a single tile.
|
but it does come with a performance degradation, because additional, adjacent vector tiles need to be loaded to generate a single tile.
|
||||||
Default is ``0`` to disable this processing.
|
Default is ``0`` to disable this processing.
|
||||||
|
|
||||||
``minRendererPoolSizes``
|
``minRendererPoolSizes``
|
||||||
@@ -146,7 +148,7 @@ Each item in this object defines one style (map). It can have the following opti
|
|||||||
|
|
||||||
* ``style`` -- name of the style json file [required]
|
* ``style`` -- name of the style json file [required]
|
||||||
* ``serve_rendered`` -- whether to render the raster tiles for this style or not
|
* ``serve_rendered`` -- whether to render the raster tiles for this style or not
|
||||||
* ``serve_data`` -- whether to allow acces to the original tiles, sprites and required glyphs
|
* ``serve_data`` -- whether to allow access to the original tiles, sprites and required glyphs
|
||||||
* ``tilejson`` -- properties to add to the TileJSON created for the raster data
|
* ``tilejson`` -- properties to add to the TileJSON created for the raster data
|
||||||
|
|
||||||
* ``format`` and ``bounds`` can be especially useful
|
* ``format`` and ``bounds`` can be especially useful
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ Default preview style and configuration
|
|||||||
- If no configuration file is specified, a default preview style (compatible with openmaptiles) is used.
|
- If no configuration file is specified, a default preview style (compatible with openmaptiles) is used.
|
||||||
- If no mbtiles file is specified (and is not found in the current working directory), a sample file is downloaded (showing the Zurich area)
|
- If no mbtiles file is specified (and is not found in the current working directory), a sample file is downloaded (showing the Zurich area)
|
||||||
|
|
||||||
Reloading configuration
|
Reloading the configuration
|
||||||
======
|
======
|
||||||
|
|
||||||
It is possible to reload the configuration file without restarting the whole process by sending a SIGHUP signal to the node process.
|
It is possible to reload the configuration file without restarting the whole process by sending a SIGHUP signal to the node process.
|
||||||
However, this does not currently work when running the tileserver-gl docker container (the signal is not passed to the subprocess, see https://github.com/maptiler/tileserver-gl/issues/420#issuecomment-597507663).
|
|
||||||
|
- The `docker kill -s HUP tileserver-gl` command can be used when running the tileserver-gl docker container.
|
||||||
|
- The `docker-compose -s HUP tileserver-gl-service-name` can be used when tileserver-gl is run as a docker-compose service.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tileserver-gl",
|
"name": "tileserver-gl",
|
||||||
"version": "3.0.0",
|
"version": "3.1.1",
|
||||||
"description": "Map tile server for JSON GL styles - vector and server side generated raster tiles",
|
"description": "Map tile server for JSON GL styles - vector and server side generated raster tiles",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"bin": "src/main.js",
|
"bin": "src/main.js",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"pbf": "3.2.1",
|
"pbf": "3.2.1",
|
||||||
"proj4": "2.6.0",
|
"proj4": "2.6.0",
|
||||||
"request": "2.88.2",
|
"request": "2.88.2",
|
||||||
"sharp": "0.25.1",
|
"sharp": "0.26.2",
|
||||||
"tileserver-gl-styles": "2.0.0"
|
"tileserver-gl-styles": "2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -395,7 +395,7 @@
|
|||||||
</TileMatrix>
|
</TileMatrix>
|
||||||
<TileMatrix>
|
<TileMatrix>
|
||||||
<ows:Identifier>18</ows:Identifier>
|
<ows:Identifier>18</ows:Identifier>
|
||||||
<ScaleDenominator></ScaleDenominator>
|
<ScaleDenominator>1066.3647919249</ScaleDenominator>
|
||||||
<TopLeftCorner>90 -180</TopLeftCorner>
|
<TopLeftCorner>90 -180</TopLeftCorner>
|
||||||
<TileWidth>256</TileWidth>
|
<TileWidth>256</TileWidth>
|
||||||
<TileHeight>256</TileHeight>
|
<TileHeight>256</TileHeight>
|
||||||
@@ -404,4 +404,4 @@
|
|||||||
</TileMatrix></TileMatrixSet>
|
</TileMatrix></TileMatrixSet>
|
||||||
</Contents>
|
</Contents>
|
||||||
<ServiceMetadataURL xlink:href="{{baseUrl}}/wmts/{{id}}/"/>
|
<ServiceMetadataURL xlink:href="{{baseUrl}}/wmts/{{id}}/"/>
|
||||||
</Capabilities>
|
</Capabilities>
|
||||||
|
|||||||
4
run.sh
4
run.sh
@@ -8,7 +8,7 @@ _term() {
|
|||||||
trap _term SIGTERM
|
trap _term SIGTERM
|
||||||
trap _term SIGINT
|
trap _term SIGINT
|
||||||
|
|
||||||
xvfbMaxStartWaitTime=5
|
xvfbMaxStartWaitTime=60
|
||||||
displayNumber=99
|
displayNumber=99
|
||||||
screenNumber=0
|
screenNumber=0
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ rm -rf /tmp/.X11-unix /tmp/.X${displayNumber}-lock ~/xvfb.pid
|
|||||||
echo "Starting Xvfb on display ${displayNumber}"
|
echo "Starting Xvfb on display ${displayNumber}"
|
||||||
start-stop-daemon --start --pidfile ~/xvfb.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :${displayNumber} -screen ${screenNumber} 1024x768x24 -ac +extension GLX +render -noreset
|
start-stop-daemon --start --pidfile ~/xvfb.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :${displayNumber} -screen ${screenNumber} 1024x768x24 -ac +extension GLX +render -noreset
|
||||||
|
|
||||||
# Wait to be able to connect to the port. This will exit if it cannot in 15 minutes.
|
# Wait to be able to connect to the port. This will exit if it cannot in 1 minute.
|
||||||
timeout ${xvfbMaxStartWaitTime} bash -c "while ! xdpyinfo -display :${displayNumber} >/dev/null; do sleep 0.5; done"
|
timeout ${xvfbMaxStartWaitTime} bash -c "while ! xdpyinfo -display :${displayNumber} >/dev/null; do sleep 0.5; done"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Could not connect to display ${displayNumber} in ${xvfbMaxStartWaitTime} seconds time."
|
echo "Could not connect to display ${displayNumber} in ${xvfbMaxStartWaitTime} seconds time."
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ module.exports = {
|
|||||||
pool.release(renderer);
|
pool.release(renderer);
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return;
|
return res.status(500).send(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix semi-transparent outlines on raw, premultiplied input
|
// Fix semi-transparent outlines on raw, premultiplied input
|
||||||
@@ -375,7 +375,7 @@ module.exports = {
|
|||||||
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 > 22 || 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');
|
||||||
}
|
}
|
||||||
const tileSize = 256;
|
const tileSize = 256;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const fixUrl = (req, url, publicUrl, opt_nokey) => {
|
|||||||
}
|
}
|
||||||
const queryParams = [];
|
const queryParams = [];
|
||||||
if (!opt_nokey && req.query.key) {
|
if (!opt_nokey && req.query.key) {
|
||||||
queryParams.unshift(`key=${req.query.key}`);
|
queryParams.unshift(`key=${encodeURIComponent(req.query.key)}`);
|
||||||
}
|
}
|
||||||
let query = '';
|
let query = '';
|
||||||
if (queryParams.length) {
|
if (queryParams.length) {
|
||||||
@@ -43,7 +43,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
// mapbox-gl-js viewer cannot handle sprite urls with query
|
// mapbox-gl-js viewer cannot handle sprite urls with query
|
||||||
if (styleJSON_.sprite) {
|
if (styleJSON_.sprite) {
|
||||||
styleJSON_.sprite = fixUrl(req, styleJSON_.sprite, item.publicUrl, true);
|
styleJSON_.sprite = fixUrl(req, styleJSON_.sprite, item.publicUrl, false);
|
||||||
}
|
}
|
||||||
if (styleJSON_.glyphs) {
|
if (styleJSON_.glyphs) {
|
||||||
styleJSON_.glyphs = fixUrl(req, styleJSON_.glyphs, item.publicUrl, false);
|
styleJSON_.glyphs = fixUrl(req, styleJSON_.glyphs, item.publicUrl, false);
|
||||||
|
|||||||
@@ -121,13 +121,13 @@ function start(opts) {
|
|||||||
success = serve_style.add(options, serving.styles, item, id, opts.publicUrl,
|
success = serve_style.add(options, serving.styles, item, id, opts.publicUrl,
|
||||||
(mbtiles, fromData) => {
|
(mbtiles, fromData) => {
|
||||||
let dataItemId;
|
let dataItemId;
|
||||||
for (const id of Object.keys(data)) {
|
for (const id of Object.keys(serving.data)) {
|
||||||
if (fromData) {
|
if (fromData) {
|
||||||
if (id === mbtiles) {
|
if (id === mbtiles) {
|
||||||
dataItemId = id;
|
dataItemId = id;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (data[id].mbtiles === mbtiles) {
|
if (serving.data[id].mbtiles === mbtiles) {
|
||||||
dataItemId = id;
|
dataItemId = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,11 +136,11 @@ function start(opts) {
|
|||||||
return dataItemId;
|
return dataItemId;
|
||||||
} else {
|
} else {
|
||||||
if (fromData || !allowMoreData) {
|
if (fromData || !allowMoreData) {
|
||||||
console.log(`ERROR: style "${file.name}" using unknown mbtiles "${mbtiles}"! Skipping...`);
|
console.log(`ERROR: style "${item.style}" using unknown mbtiles "${mbtiles}"! Skipping...`);
|
||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
||||||
while (data[id]) id += '_';
|
//while (data[id]) id += '_';
|
||||||
data[id] = {
|
data[id] = {
|
||||||
'mbtiles': mbtiles
|
'mbtiles': mbtiles
|
||||||
};
|
};
|
||||||
@@ -172,6 +172,11 @@ function start(opts) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let addData = (id, item) => {
|
||||||
|
console.log(`Add data ${id}`);
|
||||||
|
Promise.all([serve_data.add(options, serving.data, item, id, opts.publicUrl)]);
|
||||||
|
};
|
||||||
|
|
||||||
for (const id of Object.keys(config.styles || {})) {
|
for (const id of Object.keys(config.styles || {})) {
|
||||||
const item = config.styles[id];
|
const item = config.styles[id];
|
||||||
if (!item.style || item.style.length === 0) {
|
if (!item.style || item.style.length === 0) {
|
||||||
@@ -201,6 +206,21 @@ function start(opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.serveAllStyles) {
|
if (options.serveAllStyles) {
|
||||||
|
fs.readdir(options.paths.mbtiles, {withFileTypes: true}, (err, files) => {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isFile() && path.extname(file.name).toLowerCase() == '.mbtiles') {
|
||||||
|
let id = path.basename(file.name, '.mbtiles');
|
||||||
|
let item = {
|
||||||
|
mbtiles: file.name
|
||||||
|
};
|
||||||
|
addData(id, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fs.readdir(options.paths.styles, {withFileTypes: true}, (err, files) => {
|
fs.readdir(options.paths.styles, {withFileTypes: true}, (err, files) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return;
|
return;
|
||||||
@@ -212,7 +232,24 @@ function start(opts) {
|
|||||||
let item = {
|
let item = {
|
||||||
style: file.name
|
style: file.name
|
||||||
};
|
};
|
||||||
addStyle(id, item, false, false);
|
addStyle(id, item, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const watcherData = chokidar.watch(path.join(options.paths.mbtiles, '*.mbtiles'),
|
||||||
|
{
|
||||||
|
});
|
||||||
|
watcherData.on('all', (eventType, filename) => {
|
||||||
|
if (filename) {
|
||||||
|
let id = path.basename(filename, '.mbtiles');
|
||||||
|
console.log(`Data "${id}" added`);
|
||||||
|
|
||||||
|
if (eventType == "add") {
|
||||||
|
let item = {
|
||||||
|
mbtiles: filename
|
||||||
|
};
|
||||||
|
addData(id, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -235,7 +272,7 @@ function start(opts) {
|
|||||||
let item = {
|
let item = {
|
||||||
style: filename
|
style: filename
|
||||||
};
|
};
|
||||||
addStyle(id, item, false, false);
|
addStyle(id, item, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -243,7 +280,7 @@ function start(opts) {
|
|||||||
|
|
||||||
app.get('/styles.json', (req, res, next) => {
|
app.get('/styles.json', (req, res, next) => {
|
||||||
const result = [];
|
const result = [];
|
||||||
const query = req.query.key ? (`?key=${req.query.key}`) : '';
|
const query = req.query.key ? (`?key=${encodeURIComponent(req.query.key)}`) : '';
|
||||||
for (const id of Object.keys(serving.styles)) {
|
for (const id of Object.keys(serving.styles)) {
|
||||||
const styleJSON = serving.styles[id].styleJSON;
|
const styleJSON = serving.styles[id].styleJSON;
|
||||||
result.push({
|
result.push({
|
||||||
@@ -319,8 +356,8 @@ function start(opts) {
|
|||||||
data['public_url'] = opts.publicUrl || '/';
|
data['public_url'] = opts.publicUrl || '/';
|
||||||
data['is_light'] = isLight;
|
data['is_light'] = isLight;
|
||||||
data['key_query_part'] =
|
data['key_query_part'] =
|
||||||
req.query.key ? `key=${req.query.key}&` : '';
|
req.query.key ? `key=${encodeURIComponent(req.query.key)}&` : '';
|
||||||
data['key_query'] = req.query.key ? `?key=${req.query.key}` : '';
|
data['key_query'] = req.query.key ? `?key=${encodeURIComponent(req.query.key)}` : '';
|
||||||
if (template === 'wmts') res.set('Content-Type', 'text/xml');
|
if (template === 'wmts') res.set('Content-Type', 'text/xml');
|
||||||
return res.status(200).send(compiled(data));
|
return res.status(200).send(compiled(data));
|
||||||
});
|
});
|
||||||
@@ -362,7 +399,7 @@ function start(opts) {
|
|||||||
if (!data_.is_vector) {
|
if (!data_.is_vector) {
|
||||||
if (center) {
|
if (center) {
|
||||||
const centerPx = mercator.px([center[0], center[1]], center[2]);
|
const centerPx = mercator.px([center[0], center[1]], center[2]);
|
||||||
data_.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.${data_.format}`;
|
data_.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.${data_.tileJSON.format}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_.xyz_link = utils.getTileUrls(
|
data_.xyz_link = utils.getTileUrls(
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ module.exports.getTileUrls = (req, domains, path, format, publicUrl, aliases) =>
|
|||||||
const key = req.query.key;
|
const key = req.query.key;
|
||||||
const queryParams = [];
|
const queryParams = [];
|
||||||
if (req.query.key) {
|
if (req.query.key) {
|
||||||
queryParams.push(`key=${req.query.key}`);
|
queryParams.push(`key=${encodeURIComponent(req.query.key)}`);
|
||||||
}
|
}
|
||||||
if (req.query.style) {
|
if (req.query.style) {
|
||||||
queryParams.push(`style=${req.query.style}`);
|
queryParams.push(`style=${encodeURIComponent(req.query.style)}`);
|
||||||
}
|
}
|
||||||
const query = queryParams.length > 0 ? (`?${queryParams.join('&')}`) : '';
|
const query = queryParams.length > 0 ? (`?${queryParams.join('&')}`) : '';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user