Compare commits

...

86 Commits

Author SHA1 Message Date
Petr Sloup 7acbc93ba9 Update package version to 2.4.0 2018-09-14 08:23:55 +02:00
Petr Sloup bc3d79bfdc Update dependencies 2018-09-14 08:14:28 +02:00
Petr Sloup 58168eb0a5 Merge pull request #307 from spatialillusions/master
Add support for WMTS capabilities
2018-09-14 08:03:59 +02:00
Petr Sloup f993b01387 Merge pull request #303 from loicgasser/update_libs
Update commander and devDeps
2018-09-14 08:00:03 +02:00
Måns Beckman 782c28cd64 Add key to WMTS xml
This should add the key to the wmts xml for hosted services
2018-09-13 17:58:13 +02:00
Måns Beckman 76a0064f0c Remove unused variables 2018-09-13 17:57:06 +02:00
Petr Sloup 55fa8bf8c1 Merge pull request #278 from amirmasud/return-204-when-no-tile-found
Return 204 when mbtiles error is 'Tile does not exist'
2018-09-13 16:26:35 +02:00
Petr Sloup 0c42fdd6b3 Merge pull request #310 from guenhter/fix-restart
Ensure that container can be restarted
2018-09-13 16:25:16 +02:00
Måns Beckman e8b3c02546 Fix formating 2018-09-11 17:51:38 +02:00
Måns Beckman 56089c0a62 Remove base64url 2018-09-11 17:47:44 +02:00
guenhter 857ff2d8d7 Ensure that container can be restarted 2018-09-10 10:31:58 +02:00
Måns Beckman e310fa5165 Merge branch 'master' of https://github.com/spatialillusions/tileserver-gl 2018-08-21 19:33:56 +02:00
Måns Beckman 71fab2a2a1 Add support for WMTS capabilites
https://github.com/klokantech/tileserver-gl/issues/274

Clean up wmts template with correct syntax

Update endpoint URL and change content type

After a good nights sleep I considered the structure of the endpoint link for WMTS, at the same time I cleaned up the code and added the correct content type for the response.
2018-08-21 19:33:37 +02:00
Petr Sloup 1c59e3d742 Fix typo 2018-08-21 19:33:37 +02:00
Måns Beckman 6e24f6ec8e Update endpoint URL and change content type
After a good nights sleep I considered the structure of the endpoint link for WMTS, at the same time I cleaned up the code and added the correct content type for the response.
2018-08-18 12:02:54 +02:00
Måns Beckman 5d5ed1153f Clean up wmts template with correct syntax 2018-08-17 15:48:35 +02:00
Måns Beckman baf01a117b Add support for WMTS capabilites
https://github.com/klokantech/tileserver-gl/issues/274
2018-08-17 13:11:19 +02:00
Gasser Loïc 2cc2cc1b3b Update commander to the latest version 2018-08-08 11:44:46 -04:00
Loïc Gasser 45ed8d90ca Update commander and devDeps, invert default val and function accordingly 2018-08-03 00:05:20 -04:00
Petr Sloup 8e66736955 Fix typo 2018-06-21 19:00:10 +02:00
Masud Zare 72ea5ab05d fix corresponding test scenario 2018-05-07 15:58:32 +04:30
Masud Zare 9d642fa0b3 return 204 when mbtiles error is 'Tile does not exist' 2018-05-07 15:21:41 +04:30
Petr Sloup 1d734f9b42 Merge pull request #270 from geoadmin/fix_doc
Add silent to doc
2018-04-19 08:38:44 +02:00
loicgasser 80146ed7d9 Add silent to doc 2018-03-22 16:12:06 +00:00
Petr Sloup a28df7ef8f Merge pull request #269 from michaill/master
Silent mode (do not log requests with status == 200)
2018-03-22 13:14:40 +01:00
Michal Illovsky c333197a7c Skipping also 304 status codes when in silent mode 2018-03-22 09:02:09 +01:00
Michal Illovsky 45df72df51 Enable silent mode with -s option to not log successful request (status=200) 2018-03-19 13:47:17 +01:00
Petr Sloup e737753891 Merge pull request #263 from geoadmin/nomnom_commander
Replace Nomnom with Commander
2018-03-14 15:17:29 +01:00
loicgasser edff8ce06c Fix version and positional argument for mbtiles 2018-03-12 11:53:11 +00:00
loicgasser df05ce3f2a Add default val in description 2018-03-08 17:55:30 +00:00
loicgasser a74ca20375 Replace nomnom with commander 2018-03-08 16:05:58 +00:00
loicgasser 1c890b0157 Update doc 2018-03-08 16:05:46 +00:00
Petr Sloup 7a9f04a024 Update MB GL JS to v0.43.0 2018-03-01 09:26:56 +01:00
Petr Pridal 1354c7f663 Update README.md 2018-02-19 15:49:08 +01:00
Petr Sloup da3cb1e7f5 Update ISSUE_TEMPLATE.md 2018-01-23 12:17:14 +01:00
Petr Sloup 19e821a8fe Update package version to 2.3.1 2017-12-14 09:56:41 +01:00
Petr Sloup 659289d85c Update dependencies 2017-12-14 09:56:21 +01:00
Petr Sloup 734d1f01f0 Prioritize font fallbacks and try to respect proper font style 2017-12-14 09:55:57 +01:00
Petr Sloup c1055a9647 Update package version to 2.3.0 2017-12-01 11:13:11 +01:00
Petr Sloup 2afb460191 Merge pull request #242 from samizdis/master
Addresses issue #197, send SIGTERM through to node
2017-12-01 10:52:52 +01:00
Sam Brown 8eb736b821 Addresses issue #197, send SIGTERM through to node
Node can't be PID 1, else it can't be term'ed and xvfb won't stop nicely.  So, according to https://docs.docker.com/engine/reference/builder/#entrypoint, we need to make sure it's not the bare entrypoint.

Also we need to be sure that run.sh passes the signal through to node, see https://unix.stackexchange.com/questions/146756/forward-sigterm-to-child-in-bash
2017-11-30 12:30:40 +00:00
Petr Sloup 83e20b7a4e Merge pull request #232 from rani-pinchuk/fix-zlib-incorrect-header-check
Catch incorrect header exceptions
2017-11-13 09:39:06 +01:00
Rani Pinchuk 81f65af3a8 Fix log message when incorrect header exception is caught 2017-11-09 18:00:41 +01:00
Petr Sloup f5ea790878 Stop Xvfb when stopping the container (#197) 2017-11-08 17:01:28 +01:00
Rani Pinchuk a0eb5800fd Catch incorrect header exceptions 2017-11-03 16:53:45 +01:00
Petr Sloup 27eb7f0ed8 Merge pull request #229 from tschaub/handle-rejection
Handle promise rejection
2017-11-01 09:15:02 +01:00
Tim Schaub 2f9059d09e Unnecessary promise wrapping 2017-10-23 10:05:30 -06:00
Tim Schaub e11c8f9315 Reject font listing promise on error 2017-10-23 10:01:43 -06:00
Tim Schaub 650718e0f6 Avoid swallowing rejected font listing promise 2017-10-23 10:01:43 -06:00
Tim Schaub 5ed632c229 Reject source info promise on error 2017-10-23 10:01:32 -06:00
Tim Schaub f545076986 Avoid swallowing rejected source info promise 2017-10-23 10:01:19 -06:00
Tim Schaub 3d48485475 Reject on font loading error 2017-10-23 10:01:16 -06:00
Tim Schaub c060dedf20 Avoid swallowing rejected font loading promise 2017-10-23 10:01:01 -06:00
Tim Schaub cd1f5fd04a Return after rejecting, catch and log 2017-10-23 09:46:04 -06:00
Petr Sloup 82f179b07c Minor fix for correctly serving empty responses for missing tiles 2017-10-02 13:56:32 +02:00
Petr Sloup 51d6ca0880 Merge pull request #222 from otsaloma/renderer-pool-sizes
Make raster tile renderer pool sizes configurable
2017-10-02 10:04:22 +02:00
Osmo Salomaa 89878015bb Make raster tile renderer pool sizes configurable 2017-10-01 18:40:16 +03:00
Petr Pridal ac948b6dee Create ISSUE_TEMPLATE.md 2017-09-28 00:53:05 +02:00
Petr Sloup 440775dbbf Update README.md 2017-09-25 13:23:05 +02:00
Petr Sloup ea408f8ec9 Increase test timeout since travis can be slow on cold start when under load 2017-09-20 08:21:34 +02:00
Petr Sloup da646868c3 Wait longer for xvfb to start up (#197) 2017-09-20 08:05:10 +02:00
Petr Sloup d60996e3c6 Reorganize Dockerfile instructions for faster rebuilds 2017-09-20 08:03:46 +02:00
Petr Sloup 02cf45bbd9 Clean Dockerfile by basing on node:6-stretch 2017-09-20 08:01:35 +02:00
Petr Sloup d9f8582279 Remove node-pngquant-native dependency
- Unnecessary native dependency
- It was disabled by default
- Has issues on certain platforms
- Not optimal for production use (performance)
2017-09-15 17:06:42 +02:00
Petr Sloup 54f11a2125 Update package version to 2.2.0 2017-09-01 11:37:18 +02:00
Petr Sloup 598c8c590b Update package dependencies 2017-09-01 11:30:52 +02:00
Petr Sloup 438a18eec1 Merge pull request #207 from tschaub/handle-request-failures
Try to create the appropriate data type on http errors
2017-08-24 09:33:22 +02:00
Tim Schaub 7bdb7afcb9 Reuse the function for creating empty responses 2017-08-23 11:30:05 -04:00
Tim Schaub 2e46700cd9 Try to create the appropriate data type on http errors 2017-08-22 14:17:53 -04:00
Petr Sloup bb09f3df64 Add --rm to docker run instruction to run it more cleanly 2017-07-28 09:54:12 +02:00
Petr Sloup 42f24c2c99 Add concept of data decorator function 2017-07-28 09:53:32 +02:00
Petr Sloup 427a0f0687 Update package version to 2.1.0 2017-07-03 09:41:27 +02:00
Petr Sloup da5ea4b426 Update Mapbox GL JS to v0.38.0 (close #188) 2017-07-03 09:39:55 +02:00
Petr Sloup 2208ff1e24 Merge pull request #187 from aleksejleonov/debian_stretch_nodejs_repo
Use debian stretch nodejs repo
2017-07-03 09:29:29 +02:00
Oleksii Leonov cf521058be Use debian stretch nodejs repo
Dockerfile based on debian:stretch, so better to use native stretch nodejs repo instead of jessie repo.
2017-06-30 00:54:13 +03:00
Petr Sloup a9b38022bb Give xvfb some time to start up before starting the server in docker (#185) 2017-06-29 10:50:02 +02:00
Petr Sloup 654bdda629 Update package version to 2.0.0 2017-06-23 21:45:11 +02:00
Petr Sloup 537313840e Update node version in documentation 2017-06-23 21:44:40 +02:00
Petr Sloup d30f8464b2 Add some packages to travis and Dockerfile 2017-06-23 21:34:59 +02:00
Petr Sloup 698c527e94 Change endpoint URLs (close #154)
- styles at /style/{id}/style.json
- rendered tiles at /style/{id}/{z}/{x}/{y}.{format}
- TileJSONs at /style/{id}.json
2017-06-22 16:37:32 +02:00
Petr Sloup 8007f1386c Add required package for travis and Dockerfile 2017-06-22 16:37:32 +02:00
Petr Sloup 4f2fdf602b Update Dockerfiles to use node v6 2017-06-22 16:37:32 +02:00
Petr Sloup 6d7397647a Update travis script to use node v6 2017-06-22 16:37:32 +02:00
Petr Sloup 8fd7a9b42b Update dependencies to get ready for node v6 2017-06-22 16:37:32 +02:00
Petr Sloup 95470143b6 Merge pull request #179 from tschaub/err
Log errors to stderr and return
2017-06-20 17:29:39 +02:00
Tim Schaub de83021c3d Log errors to stderr and return 2017-06-20 08:09:59 -07:00
29 changed files with 1565 additions and 714 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- "4" - "6"
env: env:
- CXX=g++-4.8 - CXX=g++-4.8
addons: addons:
@@ -12,7 +12,7 @@ addons:
before_install: before_install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++ - sudo apt-get install -qq libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++
- sudo apt-get install -qq xvfb - sudo apt-get install -qq xvfb libgles2-mesa-dev libgbm-dev libxxf86vm-dev
install: install:
- npm install - npm install
- wget -O test_data.zip https://github.com/klokantech/tileserver-gl/releases/download/v1.3.0/test_data.zip - wget -O test_data.zip https://github.com/klokantech/tileserver-gl/releases/download/v1.3.0/test_data.zip
+11 -15
View File
@@ -1,6 +1,12 @@
FROM debian:stretch FROM node:6-stretch
MAINTAINER Petr Sloup <petr.sloup@klokantech.com> MAINTAINER Petr Sloup <petr.sloup@klokantech.com>
ENV NODE_ENV="production"
VOLUME /data
WORKDIR /data
EXPOSE 80
ENTRYPOINT ["/bin/bash", "/usr/src/app/run.sh"]
RUN apt-get -qq update \ RUN apt-get -qq update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y install \ && DEBIAN_FRONTEND=noninteractive apt-get -y install \
apt-transport-https \ apt-transport-https \
@@ -9,24 +15,14 @@ RUN apt-get -qq update \
build-essential \ build-essential \
python \ python \
libcairo2-dev \ libcairo2-dev \
libgles2-mesa-dev \
libgbm-dev \
libllvm3.9 \
libprotobuf-dev \ libprotobuf-dev \
libxxf86vm-dev \
xvfb \ xvfb \
&& echo "deb https://deb.nodesource.com/node_4.x jessie main" >> /etc/apt/sources.list.d/nodejs.list \
&& echo "deb-src https://deb.nodesource.com/node_4.x jessie main" >> /etc/apt/sources.list.d/nodejs.list \
&& apt-get -qq update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y --allow-unauthenticated install \
nodejs \
&& rm /etc/apt/sources.list.d/nodejs.list \
&& apt-get clean && apt-get clean
RUN mkdir -p /usr/src/app RUN mkdir -p /usr/src/app
COPY / /usr/src/app COPY / /usr/src/app
RUN cd /usr/src/app && npm install --production RUN cd /usr/src/app && npm install --production
VOLUME /data
WORKDIR /data
ENV NODE_ENV="production"
EXPOSE 80
ENTRYPOINT ["/usr/src/app/run.sh"]
+7 -9
View File
@@ -1,14 +1,12 @@
FROM node:4 FROM node:6
MAINTAINER Petr Sloup <petr.sloup@klokantech.com> 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 RUN mkdir -p /usr/src/app
COPY / /usr/src/app COPY / /usr/src/app
RUN cd /usr/src/app && npm install --production RUN cd /usr/src/app && npm install --production
VOLUME /data
WORKDIR /data
ENV NODE_ENV="production"
EXPOSE 80
ENTRYPOINT ["node", "/usr/src/app/", "-p", "80"]
+21
View File
@@ -0,0 +1,21 @@
It is great you want to help us making TileServer GL project better!
This is the right place only for a software bug report or a new software feature request.
NOTE: Questions about OpenMapTiles data, OpenMapTiles Server, TileHosting and other software/products do not belong here (and will not be answered)!
The usage and installation questions belongs to https://stackoverflow.com/questions/tagged/openmaptiles
A guaranteed support and consulting from the core developers via https://openmaptiles.com/support/
Please search this GitHub repo for similar requests before posting (check also closed tickets).
When reporting a problem you have with the TileServer GL software please provide:
- Clear description of the problem: What steps will lead to reproducing the error on our computer? What is exactly wrong?
- Version of the TileServer GL software you have used
- Version and name of the operating system you use or other details of your setup
- Information about your used config / styles / vector tiles
- URL / link to the specific location in a live map demo where a bug is visible is always great
- Screenshot of the problem are cool! Drag&drop an image to the report here...
We love pull requests! If you are able to code, please send us your fix or code modification via GitHub... Thanks!
+4 -2
View File
@@ -9,6 +9,8 @@ Vector and raster maps with GL styles. Server side rendering by Mapbox GL Native
## Get Started ## Get Started
Make sure you have Node.js version **6** installed (running `node -v` it should output something like `v6.11.3`).
Install `tileserver-gl` with server-side raster rendering of vector tiles with npm Install `tileserver-gl` with server-side raster rendering of vector tiles with npm
```bash ```bash
@@ -18,7 +20,7 @@ npm install -g tileserver-gl
Now download vector tiles from [OpenMapTiles](https://openmaptiles.org/downloads/). Now download vector tiles from [OpenMapTiles](https://openmaptiles.org/downloads/).
```bash ```bash
curl -o zurich_switzerland.mbtiles https://openmaptiles.os.zhdk.cloud.switch.ch/v3.3/extracts/zurich_switzerland.mbtiles curl -o zurich_switzerland.mbtiles https://[GET-YOUR-LINK]/extracts/zurich_switzerland.mbtiles
``` ```
Start `tileserver-gl` with the downloaded vector tiles. Start `tileserver-gl` with the downloaded vector tiles.
@@ -34,7 +36,7 @@ Alternatively, you can use the `tileserver-gl-light` package instead, which is p
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: 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 ```bash
docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl 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. 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.
+23 -6
View File
@@ -21,9 +21,7 @@ Example::
], ],
"formatQuality": { "formatQuality": {
"jpeg": 80, "jpeg": 80,
"webp": 90, "webp": 90
"pngQuantization": false,
"png": 90
}, },
"maxScaleFactor": 3, "maxScaleFactor": 3,
"maxSize": 2048, "maxSize": 2048,
@@ -83,8 +81,6 @@ Use ``false`` to disable the front page altogether (404).
Quality of the compression of individual image formats. [0-100] Quality of the compression of individual image formats. [0-100]
The value for ``png`` is only used when ``pngQuantization`` is ``true``.
``maxScaleFactor`` ``maxScaleFactor``
----------- -----------
@@ -99,6 +95,27 @@ Maximum image side length to be allowed to be rendered (including scale factor).
Be careful when changing this value since there are hardware limits that need to be considered. Be careful when changing this value since there are hardware limits that need to be considered.
Default is ``2048``. Default is ``2048``.
``minRendererPoolSizes``
------------------------
Minimum amount of raster tile renderers per scale factor.
The value is an array: the first element is the minimum amount of renderers for scale factor one, the second for scale factor two and so on.
If the array has less elements than ``maxScaleFactor``, then the last element is used for all remaining scale factors as well.
Selecting renderer pool sizes is a trade-off between memory use and speed.
A reasonable value will depend on your hardware and your amount of styles and scale factors.
If you have plenty of memory, you'll want to set this equal to ``maxRendererPoolSizes`` to avoid increased latency due to renderer destruction and recreation.
If you need to conserve memory, you'll want something lower than ``maxRendererPoolSizes``, possibly allocating more renderers to scale factors that are more common.
Default is ``[8, 4, 2]``.
``maxRendererPoolSizes``
------------------------
Maximum amount of raster tile renderers per scale factor.
The value and considerations are similar to ``minRendererPoolSizes`` above.
If you have plenty of memory, try setting these equal to or slightly above your processor count, e.g. if you have four processors, try a value of ``[6]``.
If you need to conserve memory, try lower values for scale factors that are less common.
Default is ``[16, 8, 4]``.
``watermark`` ``watermark``
----------- -----------
@@ -156,7 +173,7 @@ Sprites
If your style requires any sprites, make sure the style JSON contains proper path in the ``sprite`` property. If your style requires any sprites, make sure the style JSON contains proper path in the ``sprite`` property.
It can be a local path (e.g. ``my-style/sprite``) or remove http(s) location (e.g. ``https://mycdn.com/my-style/sprite``). Several possible extension are added to this path, so the following files should be present: It can be a local path (e.g. ``my-style/sprite``) or remote http(s) location (e.g. ``https://mycdn.com/my-style/sprite``). Several possible extension are added to this path, so the following files should be present:
* ``sprite.json`` * ``sprite.json``
* ``sprite.png`` * ``sprite.png``
+7 -3
View File
@@ -6,21 +6,25 @@ If you visit the server on the configured port (default 8080) you can see your m
Styles Styles
====== ======
* Styles are served at ``/styles/{id}.json`` (+ array at ``/styles.json``) * Styles are served at ``/styles/{id}/style.json`` (+ array at ``/styles.json``)
* Sprites at ``/styles/{id}/sprite[@2x].{format}`` * Sprites at ``/styles/{id}/sprite[@2x].{format}``
* Fonts at ``/fonts/{fontstack}/{start}-{end}.pbf`` * Fonts at ``/fonts/{fontstack}/{start}-{end}.pbf``
Rendered tiles Rendered tiles
============== ==============
* Rendered tiles are served at ``/styles/{id}/rendered/{z}/{x}/{y}[@2x].{format}`` * Rendered tiles are served at ``/styles/{id}/{z}/{x}/{y}[@2x].{format}``
* The optional ``@2x`` (or ``@3x``, ``@4x``) part can be used to render HiDPI (retina) tiles * The optional ``@2x`` (or ``@3x``, ``@4x``) part can be used to render HiDPI (retina) tiles
* Available formats: ``png``, ``jpg`` (``jpeg``), ``webp`` * Available formats: ``png``, ``jpg`` (``jpeg``), ``webp``
* TileJSON at ``/styles/{id}/rendered.json`` * TileJSON at ``/styles/{id}.json``
* The rendered tiles are not available in the ``tileserver-gl-light`` version. * The rendered tiles are not available in the ``tileserver-gl-light`` version.
WMTS Capabilities
==============
* WMTS Capabilities are served at ``/styles/{id}/wmts.xml``
Static images Static images
============= =============
* Several endpoints: * Several endpoints:
+2 -2
View File
@@ -7,7 +7,7 @@ Docker
When running docker image, no special installation is needed -- the docker will automatically download the image if not present. When running docker image, no special installation is needed -- the docker will automatically download the image if not present.
Just run ``docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl``. Just run ``docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl``.
Additional options (see :doc:`/usage`) can be passed to the TileServer GL by appending them to the end of this command. You can, for example, do the following: Additional options (see :doc:`/usage`) can be passed to the TileServer GL by appending them to the end of this command. You can, for example, do the following:
@@ -41,7 +41,7 @@ Alternatively, you can use ``tileserver-gl-light`` package instead, which is pur
From source From source
=========== ===========
Make sure you have Node v4 (nvm install 4) and run:: Make sure you have Node v6 (nvm install 6) and run::
npm install npm install
node . node .
+12 -11
View File
@@ -4,21 +4,22 @@ Usage
Getting started Getting started
====== ======
:: ::
Usage: tileserver-gl [mbtiles] [options] Usage: main.js tileserver-gl [mbtiles] [options]
mbtiles MBTiles file (uses demo configuration); Options:
ignored if the configuration file is also specified
Options:
-c, --config Configuration file [config.json]
-b, --bind Bind address
-p, --port Port [8080]
-V, --verbose More verbose output
-v, --version Version info
-h, --help output usage information
--mbtiles <file> MBTiles file (uses demo configuration);
ignored if the configuration file is also specified
-c, --config <file> Configuration file [config.json]
-b, --bind <address> Bind address
-p, --port <port> Port [8080]
-C|--no-cors Disable Cross-origin resource sharing headers
-V, --verbose More verbose output
-s, --silent Less verbose output
-v, --version Version info
Default styles and configuration Default styles and configuration
+24 -26
View File
@@ -1,6 +1,6 @@
{ {
"name": "tileserver-gl", "name": "tileserver-gl",
"version": "1.7.0", "version": "2.4.0",
"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",
@@ -13,38 +13,36 @@
}, },
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"engines": { "engines": {
"node": ">=4.2.1 <5" "node": ">=6 <7"
}, },
"scripts": { "scripts": {
"test": "mocha test/**.js" "test": "mocha test/**.js --timeout 10000"
}, },
"dependencies": { "dependencies": {
"@mapbox/mapbox-gl-native": "3.4.4", "@mapbox/mapbox-gl-native": "3.5.4",
"@mapbox/sphericalmercator": "1.0.5", "@mapbox/mbtiles": "0.10.0",
"advanced-pool": "0.3.2", "@mapbox/sphericalmercator": "1.1.0",
"base64url": "2.0.0", "@mapbox/vector-tile": "1.3.1",
"canvas": "1.6.5", "advanced-pool": "0.3.3",
"clone": "2.1.1", "canvas": "1.6.12",
"color": "1.0.3", "clone": "2.1.2",
"cors": "2.8.3", "color": "3.0.0",
"express": "4.15.2", "commander": "2.18.0",
"cors": "2.8.4",
"express": "4.16.3",
"glyph-pbf-composite": "0.0.2", "glyph-pbf-composite": "0.0.2",
"handlebars": "4.0.8", "handlebars": "4.0.12",
"http-shutdown": "^1.2.0", "http-shutdown": "^1.2.0",
"mbtiles": "0.9.0", "morgan": "1.9.1",
"morgan": "1.8.1", "pbf": "3.1.0",
"node-pngquant-native": "1.0.4", "proj4": "2.5.0",
"nomnom": "1.8.1", "request": "2.88.0",
"pbf": "3.0.5", "sharp": "0.20.8",
"proj4": "2.4.3", "tileserver-gl-styles": "1.2.0"
"request": "2.81.0",
"sharp": "0.17.3",
"tileserver-gl-styles": "1.1.1",
"vector-tile": "1.3.0"
}, },
"devDependencies": { "devDependencies": {
"should": "^11.2.0", "mocha": "^5.2.0",
"mocha": "^3.2.0", "should": "^13.2.0",
"supertest": "^3.0.0" "supertest": "^3.1.0"
} }
} }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -25,7 +25,7 @@
{{#each styles}} {{#each styles}}
<div class="item"> <div class="item">
{{#if thumbnail}} {{#if thumbnail}}
<img src="/styles/{{@key}}/rendered/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" /> <img src="/styles/{{@key}}/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}} {{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" /> <img src="/images/placeholder.png" alt="{{name}} preview" />
{{/if}} {{/if}}
@@ -35,13 +35,13 @@
<p class="services"> <p class="services">
services: services:
{{#if serving_data}} {{#if serving_data}}
<a href="/styles/{{@key}}.json{{&../key_query}}">GL Style</a> <a href="/styles/{{@key}}/style.json{{&../key_query}}">GL Style</a>
{{/if}} {{/if}}
{{#if serving_rendered}} {{#if serving_rendered}}
{{#if serving_data}}| {{/if}}<a href="/styles/{{@key}}/rendered.json{{&../key_query}}">TileJSON</a> {{#if serving_data}}| {{/if}}<a href="/styles/{{@key}}.json{{&../key_query}}">TileJSON</a>
{{/if}} {{/if}}
{{#if wmts_link}} {{#if serving_rendered}}
| <a href="{{&wmts_link}}">WMTS</a> | <a href="/styles/{{@key}}/wmts.xml{{&../key_query}}">WMTS</a>
{{/if}} {{/if}}
{{#if xyz_link}} {{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_style_{{@key}}');">XYZ</a> | <a href="#" onclick="return toggle_xyz('xyz_style_{{@key}}');">XYZ</a>
@@ -110,4 +110,4 @@
</p> </p>
</footer> </footer>
</body> </body>
</html> </html>
+2 -2
View File
@@ -27,12 +27,12 @@
mapboxgl.setRTLTextPlugin('/mapbox-gl-rtl-text.js{{&key_query}}'); mapboxgl.setRTLTextPlugin('/mapbox-gl-rtl-text.js{{&key_query}}');
var map = new mapboxgl.Map({ var map = new mapboxgl.Map({
container: 'map', container: 'map',
style: '/styles/{{id}}.json{{&key_query}}', style: '/styles/{{id}}/style.json{{&key_query}}',
hash: true hash: true
}); });
map.addControl(new mapboxgl.NavigationControl()); map.addControl(new mapboxgl.NavigationControl());
} else { } else {
var map = L.mapbox.map('map', '/styles/{{id}}/rendered.json{{&key_query}}', { zoomControl: false }); var map = L.mapbox.map('map', '/styles/{{id}}.json{{&key_query}}', { zoomControl: false });
new L.Control.Zoom({ position: 'topright' }).addTo(map); new L.Control.Zoom({ position: 'topright' }).addTo(map);
setTimeout(function() { setTimeout(function() {
new L.Hash(map); new L.Hash(map);
+407
View File
@@ -0,0 +1,407 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Capabilities xmlns="http://www.opengis.net/wmts/1.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" xsi:schemaLocation="http://www.opengis.net/wmts/1.0 http://schemas.opengis.net/wmts/1.0/wmtsGetCapabilities_response.xsd" version="1.0.0">
<!-- Service Identification -->
<ows:ServiceIdentification>
<ows:Title>TileServer GL</ows:Title>
<ows:ServiceType>OGC WMTS</ows:ServiceType>
<ows:ServiceTypeVersion>1.0.0</ows:ServiceTypeVersion>
</ows:ServiceIdentification>
<!-- Operations Metadata -->
<ows:OperationsMetadata>
<ows:Operation name="GetCapabilities">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:href="{{baseUrl}}/wmts/{{id}}/">
<ows:Constraint name="GetEncoding">
<ows:AllowedValues>
<ows:Value>RESTful</ows:Value>
</ows:AllowedValues>
</ows:Constraint>
</ows:Get>
</ows:HTTP>
</ows:DCP>
</ows:Operation>
<ows:Operation name="GetTile">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:href="{{baseUrl}}/styles/">
<ows:Constraint name="GetEncoding">
<ows:AllowedValues>
<ows:Value>RESTful</ows:Value>
</ows:AllowedValues>
</ows:Constraint>
</ows:Get>
</ows:HTTP>
</ows:DCP>
</ows:Operation>
</ows:OperationsMetadata>
<Contents>
<Layer>
<ows:Title>{{name}}</ows:Title>
<ows:Identifier>{{id}}</ows:Identifier>
<ows:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84">
<ows:LowerCorner>-180 -85.051128779807</ows:LowerCorner>
<ows:UpperCorner>180 85.051128779807</ows:UpperCorner>
</ows:WGS84BoundingBox>
<Style isDefault="true">
<ows:Identifier>default</ows:Identifier>
</Style>
<Format>image/png</Format>
<TileMatrixSetLink>
<TileMatrixSet>GoogleMapsCompatible</TileMatrixSet>
</TileMatrixSetLink>
<ResourceURL format="image/png" resourceType="tile" template="{{baseUrl}}/styles/{{id}}/{TileMatrix}/{TileCol}/{TileRow}.png{{key_query}}"/>
</Layer><TileMatrixSet>
<ows:Title>GoogleMapsCompatible</ows:Title>
<ows:Abstract>GoogleMapsCompatible EPSG:3857</ows:Abstract>
<ows:Identifier>GoogleMapsCompatible</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:EPSG::3857</ows:SupportedCRS>
<TileMatrix>
<ows:Identifier>0</ows:Identifier>
<ScaleDenominator>559082264.02872</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>1</MatrixWidth>
<MatrixHeight>1</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>1</ows:Identifier>
<ScaleDenominator>279541132.01436</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2</MatrixWidth>
<MatrixHeight>2</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>2</ows:Identifier>
<ScaleDenominator>139770566.00718</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4</MatrixWidth>
<MatrixHeight>4</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>3</ows:Identifier>
<ScaleDenominator>69885283.00359</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8</MatrixWidth>
<MatrixHeight>8</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>4</ows:Identifier>
<ScaleDenominator>34942641.501795</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16</MatrixWidth>
<MatrixHeight>16</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>5</ows:Identifier>
<ScaleDenominator>17471320.750897</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32</MatrixWidth>
<MatrixHeight>32</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>6</ows:Identifier>
<ScaleDenominator>8735660.3754487</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>64</MatrixWidth>
<MatrixHeight>64</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>7</ows:Identifier>
<ScaleDenominator>4367830.1877244</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>128</MatrixWidth>
<MatrixHeight>128</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>8</ows:Identifier>
<ScaleDenominator>2183915.0938622</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>256</MatrixWidth>
<MatrixHeight>256</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>9</ows:Identifier>
<ScaleDenominator>1091957.5469311</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>512</MatrixWidth>
<MatrixHeight>512</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>10</ows:Identifier>
<ScaleDenominator>545978.77346554</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>1024</MatrixWidth>
<MatrixHeight>1024</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>11</ows:Identifier>
<ScaleDenominator>272989.38673277</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2048</MatrixWidth>
<MatrixHeight>2048</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>12</ows:Identifier>
<ScaleDenominator>136494.69336639</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4096</MatrixWidth>
<MatrixHeight>4096</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>13</ows:Identifier>
<ScaleDenominator>68247.346683193</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8192</MatrixWidth>
<MatrixHeight>8192</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>14</ows:Identifier>
<ScaleDenominator>34123.673341597</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16384</MatrixWidth>
<MatrixHeight>16384</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>15</ows:Identifier>
<ScaleDenominator>17061.836670798</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32768</MatrixWidth>
<MatrixHeight>32768</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>16</ows:Identifier>
<ScaleDenominator>8530.9183353991</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>65536</MatrixWidth>
<MatrixHeight>65536</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>17</ows:Identifier>
<ScaleDenominator>4265.4591676996</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>131072</MatrixWidth>
<MatrixHeight>131072</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>18</ows:Identifier>
<ScaleDenominator>2132.7295838498</ScaleDenominator>
<TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>262144</MatrixWidth>
<MatrixHeight>262144</MatrixHeight>
</TileMatrix></TileMatrixSet><TileMatrixSet>
<ows:Title>WGS84</ows:Title>
<ows:Abstract>WGS84 EPSG:4326</ows:Abstract>
<ows:Identifier>WGS84</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
<TileMatrix>
<ows:Identifier>0</ows:Identifier>
<ScaleDenominator>279541132.01436</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2</MatrixWidth>
<MatrixHeight>1</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>1</ows:Identifier>
<ScaleDenominator>139770566.00718</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4</MatrixWidth>
<MatrixHeight>2</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>2</ows:Identifier>
<ScaleDenominator>69885283.00359</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8</MatrixWidth>
<MatrixHeight>4</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>3</ows:Identifier>
<ScaleDenominator>34942641.501795</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16</MatrixWidth>
<MatrixHeight>8</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>4</ows:Identifier>
<ScaleDenominator>17471320.750897</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32</MatrixWidth>
<MatrixHeight>16</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>5</ows:Identifier>
<ScaleDenominator>8735660.3754487</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>64</MatrixWidth>
<MatrixHeight>32</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>6</ows:Identifier>
<ScaleDenominator>4367830.1877244</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>128</MatrixWidth>
<MatrixHeight>64</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>7</ows:Identifier>
<ScaleDenominator>2183915.0938622</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>256</MatrixWidth>
<MatrixHeight>128</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>8</ows:Identifier>
<ScaleDenominator>1091957.5469311</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>512</MatrixWidth>
<MatrixHeight>256</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>9</ows:Identifier>
<ScaleDenominator>545978.77346554</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>1024</MatrixWidth>
<MatrixHeight>512</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>10</ows:Identifier>
<ScaleDenominator>272989.38673277</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2048</MatrixWidth>
<MatrixHeight>1024</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>11</ows:Identifier>
<ScaleDenominator>136494.69336639</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4096</MatrixWidth>
<MatrixHeight>2048</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>12</ows:Identifier>
<ScaleDenominator>68247.346683193</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8192</MatrixWidth>
<MatrixHeight>4096</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>13</ows:Identifier>
<ScaleDenominator>34123.673341597</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16384</MatrixWidth>
<MatrixHeight>8192</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>14</ows:Identifier>
<ScaleDenominator>17061.836670798</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32768</MatrixWidth>
<MatrixHeight>16384</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>15</ows:Identifier>
<ScaleDenominator>8530.9183353991</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>65536</MatrixWidth>
<MatrixHeight>32768</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>16</ows:Identifier>
<ScaleDenominator>4265.4591676996</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>131072</MatrixWidth>
<MatrixHeight>65536</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>17</ows:Identifier>
<ScaleDenominator>2132.7295838498</ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>262144</MatrixWidth>
<MatrixHeight>131072</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>18</ows:Identifier>
<ScaleDenominator></ScaleDenominator>
<TopLeftCorner>90 -180</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>524288</MatrixWidth>
<MatrixHeight>262144</MatrixHeight>
</TileMatrix></TileMatrixSet>
</Contents>
<ServiceMetadataURL xlink:href="{{baseUrl}}/wmts/{{id}}/"/>
</Capabilities>
-1
View File
@@ -23,7 +23,6 @@ packageJson.name += '-light';
packageJson.description = 'Map tile server for JSON GL styles - serving vector tiles'; packageJson.description = 'Map tile server for JSON GL styles - serving vector tiles';
delete packageJson.dependencies['canvas']; delete packageJson.dependencies['canvas'];
delete packageJson.dependencies['@mapbox/mapbox-gl-native']; delete packageJson.dependencies['@mapbox/mapbox-gl-native'];
delete packageJson.dependencies['node-pngquant-native'];
delete packageJson.dependencies['sharp']; delete packageJson.dependencies['sharp'];
delete packageJson.optionalDependencies; delete packageJson.optionalDependencies;
+23 -1
View File
@@ -1,3 +1,25 @@
#!/bin/bash #!/bin/bash
_term() {
echo "Caught signal, stopping gracefully"
kill -TERM "$child" 2>/dev/null
}
trap _term TERM
# Delete files if they were not cleaned by last run
rm -rf /tmp/.X11-unix /tmp/.X99-lock
start-stop-daemon --start --pidfile ~/xvfb.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset
echo "Waiting 3 seconds for xvfb to start..."
sleep 3
export DISPLAY=:99.0
cd /data cd /data
xvfb-run -a -e /dev/stdout --server-args="-screen 0 1024x768x24" node /usr/src/app/ -p 80 "$@" node /usr/src/app/ -p 80 "$@" &
child=$!
wait "$child"
start-stop-daemon --stop --retry 5 --pidfile ~/xvfb.pid # stop xvfb when exiting
rm ~/xvfb.pid
+47 -41
View File
@@ -6,50 +6,55 @@ var fs = require('fs'),
path = require('path'), path = require('path'),
request = require('request'); request = require('request');
var mbtiles = require('mbtiles'); var mbtiles = require('@mapbox/mbtiles');
var packageJson = require('../package'); var packageJson = require('../package');
var opts = require('nomnom') var args = process.argv;
.option('mbtiles', { if (args.length >= 3 && args[2][0] != '-') {
default: undefined, args.splice(2, 0, '--mbtiles');
help: 'MBTiles file (uses demo configuration);\n' + }
'\t ignored if the configuration file is also specified',
position: 0
})
.option('config', {
abbr: 'c',
default: 'config.json',
help: 'Configuration file'
})
.option('bind', {
abbr: 'b',
default: undefined,
help: 'Bind address'
})
.option('port', {
abbr: 'p',
default: 8080,
help: 'Port'
})
.option('cors', {
default: true,
help: 'Enable Cross-origin resource sharing headers'
})
.option('verbose', {
abbr: 'V',
flag: true,
help: 'More verbose output'
})
.option('version', {
abbr: 'v',
flag: true,
help: 'Version info',
callback: function() {
return packageJson.name + ' v' + packageJson.version;
}
}).parse();
var opts = require('commander')
.description('tileserver-gl startup options')
.usage('tileserver-gl [mbtiles] [options]')
.option(
'--mbtiles <file>',
'MBTiles file (uses demo configuration);\n' +
'\t ignored if the configuration file is also specified'
)
.option(
'-c, --config <file>',
'Configuration file [config.json]',
'config.json'
)
.option(
'-b, --bind <address>',
'Bind address'
)
.option(
'-p, --port <port>',
'Port [8080]',
8080,
parseInt
)
.option(
'-C|--no-cors',
'Disable Cross-origin resource sharing headers'
)
.option(
'-V, --verbose',
'More verbose output'
)
.option(
'-s, --silent',
'Less verbose output'
)
.version(
packageJson.version,
'-v, --version'
)
.parse(args);
console.log('Starting ' + packageJson.name + ' v' + packageJson.version); console.log('Starting ' + packageJson.name + ' v' + packageJson.version);
@@ -59,7 +64,8 @@ var startServer = function(configPath, config) {
config: config, config: config,
bind: opts.bind, bind: opts.bind,
port: opts.port, port: opts.port,
cors: opts.cors cors: opts.cors,
silent: opts.silent
}); });
}; };
+24 -7
View File
@@ -6,9 +6,9 @@ var fs = require('fs'),
var clone = require('clone'), var clone = require('clone'),
express = require('express'), express = require('express'),
mbtiles = require('mbtiles'), mbtiles = require('@mapbox/mbtiles'),
pbf = require('pbf'), pbf = require('pbf'),
VectorTile = require('vector-tile').VectorTile; VectorTile = require('@mapbox/vector-tile').VectorTile;
var tileshrinkGl; var tileshrinkGl;
try { try {
@@ -37,7 +37,15 @@ module.exports = function(options, repo, params, id, styles) {
var source; var source;
var sourceInfoPromise = new Promise(function(resolve, reject) { var sourceInfoPromise = new Promise(function(resolve, reject) {
source = new mbtiles(mbtilesFile, function(err) { source = new mbtiles(mbtilesFile, function(err) {
if (err) {
reject(err);
return;
}
source.getInfo(function(err, info) { source.getInfo(function(err, info) {
if (err) {
reject(err);
return;
}
tileJSON['name'] = id; tileJSON['name'] = id;
tileJSON['format'] = 'pbf'; tileJSON['format'] = 'pbf';
@@ -50,6 +58,10 @@ module.exports = function(options, repo, params, id, styles) {
Object.assign(tileJSON, params.tilejson || {}); Object.assign(tileJSON, params.tilejson || {});
utils.fixTileJSONCenter(tileJSON); utils.fixTileJSONCenter(tileJSON);
if (options.dataDecoratorFunc) {
tileJSON = options.dataDecoratorFunc(id, 'tilejson', tileJSON);
}
resolve(); resolve();
}); });
}); });
@@ -77,7 +89,7 @@ module.exports = function(options, repo, params, id, styles) {
source.getTile(z, x, y, function(err, data, headers) { source.getTile(z, x, y, function(err, data, headers) {
if (err) { if (err) {
if (/does not exist/.test(err.message)) { if (/does not exist/.test(err.message)) {
return res.status(404).send(err.message); return res.status(204).send(err.message);
} else { } else {
return res.status(500).send(err.message); return res.status(500).send(err.message);
} }
@@ -114,6 +126,13 @@ module.exports = function(options, repo, params, id, styles) {
//console.log(shrinkers[style].getStats()); //console.log(shrinkers[style].getStats());
} }
} }
if (options.dataDecoratorFunc) {
if (isGzipped) {
data = zlib.unzipSync(data);
isGzipped = false;
}
data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
}
} }
if (format == 'pbf') { if (format == 'pbf') {
headers['Content-Type'] = 'application/x-protobuf'; headers['Content-Type'] = 'application/x-protobuf';
@@ -165,9 +184,7 @@ module.exports = function(options, repo, params, id, styles) {
return res.send(info); return res.send(info);
}); });
return new Promise(function(resolve, reject) { return sourceInfoPromise.then(function() {
sourceInfoPromise.then(function() { return app;
resolve(app);
});
}); });
}; };
+13 -9
View File
@@ -17,13 +17,19 @@ module.exports = function(options, allowedFonts) {
var existingFonts = {}; var existingFonts = {};
var fontListingPromise = new Promise(function(resolve, reject) { var fontListingPromise = new Promise(function(resolve, reject) {
fs.readdir(options.paths.fonts, function(err, files) { fs.readdir(options.paths.fonts, function(err, files) {
if (err) {
reject(err);
return;
}
files.forEach(function(file) { files.forEach(function(file) {
fs.stat(path.join(fontPath, file), function(err, stats) { fs.stat(path.join(fontPath, file), function(err, stats) {
if (!err) { if (err) {
if (stats.isDirectory() && reject(err);
fs.existsSync(path.join(fontPath, file, '0-255.pbf'))) { return;
existingFonts[path.basename(file)] = true; }
} if (stats.isDirectory() &&
fs.existsSync(path.join(fontPath, file, '0-255.pbf'))) {
existingFonts[path.basename(file)] = true;
} }
}); });
}); });
@@ -54,9 +60,7 @@ module.exports = function(options, allowedFonts) {
); );
}); });
return new Promise(function(resolve, reject) { return fontListingPromise.then(function() {
fontListingPromise.then(function() { return app;
resolve(app);
});
}); });
}; };
+148 -95
View File
@@ -3,6 +3,7 @@
var advancedPool = require('advanced-pool'), var advancedPool = require('advanced-pool'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
url = require('url'),
util = require('util'), util = require('util'),
zlib = require('zlib'); zlib = require('zlib');
@@ -16,8 +17,7 @@ var Canvas = require('canvas'),
express = require('express'), express = require('express'),
mercator = new (require('@mapbox/sphericalmercator'))(), mercator = new (require('@mapbox/sphericalmercator'))(),
mbgl = require('@mapbox/mapbox-gl-native'), mbgl = require('@mapbox/mapbox-gl-native'),
mbtiles = require('mbtiles'), mbtiles = require('@mapbox/mbtiles'),
pngquant = require('node-pngquant-native'),
proj4 = require('proj4'), proj4 = require('proj4'),
request = require('request'); request = require('request');
@@ -35,6 +35,68 @@ mbgl.on('message', function(e) {
} }
}); });
/**
* Lookup of sharp output formats by file extension.
*/
var extensionToFormat = {
'.jpg': 'jpeg',
'.jpeg': 'jpeg',
'.png': 'png',
'.webp': 'webp'
};
/**
* Cache of response data by sharp output format and color. Entry for empty
* string is for unknown or unsupported formats.
*/
var cachedEmptyResponses = {
'': new Buffer(0)
};
/**
* Create an appropriate mbgl response for http errors.
* @param {string} format The format (a sharp format or 'pbf').
* @param {string} color The background color (or empty string for transparent).
* @param {Function} callback The mbgl callback.
*/
function createEmptyResponse(format, color, callback) {
if (!format || format === 'pbf') {
callback(null, {data: cachedEmptyResponses['']});
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 channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
sharp(new Buffer(array), {
raw: {
width: 1,
height: 1,
channels: channels
}
}).toFormat(format).toBuffer(function(err, buffer, info) {
if (!err) {
cachedEmptyResponses[cacheKey] = buffer;
}
callback(null, {data: buffer});
});
}
module.exports = function(options, repo, params, id, dataResolver) { module.exports = function(options, repo, params, id, dataResolver) {
var app = express().disable('x-powered-by'); var app = express().disable('x-powered-by');
@@ -60,12 +122,18 @@ module.exports = function(options, repo, params, id, dataResolver) {
var existingFonts = {}; var existingFonts = {};
var fontListingPromise = new Promise(function(resolve, reject) { var fontListingPromise = new Promise(function(resolve, reject) {
fs.readdir(options.paths.fonts, function(err, files) { fs.readdir(options.paths.fonts, function(err, files) {
if (err) {
reject(err);
return;
}
files.forEach(function(file) { files.forEach(function(file) {
fs.stat(path.join(options.paths.fonts, file), function(err, stats) { fs.stat(path.join(options.paths.fonts, file), function(err, stats) {
if (!err) { if (err) {
if (stats.isDirectory()) { reject(err);
existingFonts[path.basename(file)] = true; return;
} }
if (stats.isDirectory()) {
existingFonts[path.basename(file)] = true;
} }
}); });
}); });
@@ -100,7 +168,9 @@ module.exports = function(options, repo, params, id, dataResolver) {
}); });
} else if (protocol == 'mbtiles') { } else if (protocol == 'mbtiles') {
var parts = req.url.split('/'); var parts = req.url.split('/');
var source = map.sources[parts[2]]; var sourceId = parts[2];
var source = map.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,
@@ -108,22 +178,31 @@ module.exports = function(options, repo, params, id, dataResolver) {
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);
callback(null, { data: source.emptyTile }); createEmptyResponse(sourceInfo.format, sourceInfo.color, callback);
} else { return;
var response = {};
if (headers['Last-Modified']) {
response.modified = new Date(headers['Last-Modified']);
}
if (format == 'pbf') {
response.data = zlib.unzipSync(data);
} else {
response.data = data;
}
callback(null, response);
} }
var response = {};
if (headers['Last-Modified']) {
response.modified = new Date(headers['Last-Modified']);
}
if (format == 'pbf') {
try {
response.data = zlib.unzipSync(data);
}
catch (err) {
console.log("Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf", id, z, x, y);
}
if (options.dataDecoratorFunc) {
response.data = options.dataDecoratorFunc(
sourceId, 'data', response.data, z, x, y);
}
} else {
response.data = data;
}
callback(null, response);
}); });
} else if (protocol == 'http' || protocol == 'https') { } else if (protocol == 'http' || protocol == 'https') {
request({ request({
@@ -131,29 +210,28 @@ module.exports = function(options, repo, params, id, dataResolver) {
encoding: null, encoding: null,
gzip: true gzip: true
}, function(err, res, body) { }, function(err, res, body) {
if (err) { var parts = url.parse(req.url);
//console.log('HTTP tile error', err); var extension = path.extname(parts.pathname).toLowerCase();
callback(null, { data: new Buffer(0) }); var format = extensionToFormat[extension] || '';
} else if (res.statusCode == 200) { if (err || res.statusCode < 200 || res.statusCode >= 300) {
var response = {}; // console.log('HTTP error', err || res.statusCode);
createEmptyResponse(format, '', callback);
if (res.headers.modified) { return;
response.modified = new Date(res.headers.modified);
}
if (res.headers.expires) {
response.expires = new Date(res.headers.expires);
}
if (res.headers.etag) {
response.etag = res.headers.etag;
}
response.data = body;
callback(null, response);
} else {
//console.log('HTTP error', JSON.parse(body).message);
callback(null, { data: new Buffer(0) });
} }
var response = {};
if (res.headers.modified) {
response.modified = new Date(res.headers.modified);
}
if (res.headers.expires) {
response.expires = new Date(res.headers.expires);
}
if (res.headers.etag) {
response.etag = res.headers.etag;
}
response.data = body;
callback(null, response);
}); });
} }
} }
@@ -223,7 +301,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
} }
mbtilesFile = dataResolver(mbtilesFile); mbtilesFile = dataResolver(mbtilesFile);
if (!mbtilesFile) { if (!mbtilesFile) {
console.log('ERROR: data "' + mbtilesFile + '" not found!'); console.error('ERROR: data "' + mbtilesFile + '" not found!');
process.exit(1); process.exit(1);
} }
} }
@@ -238,6 +316,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
map.sources[name].getInfo(function(err, info) { map.sources[name].getInfo(function(err, info) {
if (err) { if (err) {
console.error(err); console.error(err);
return;
} }
if (!dataProjWGStoInternalWGS && info.proj4) { if (!dataProjWGStoInternalWGS && info.proj4) {
@@ -257,26 +336,11 @@ module.exports = function(options, repo, params, id, dataResolver) {
'mbtiles://' + name + '/{z}/{x}/{y}.' + (info.format || 'pbf') 'mbtiles://' + name + '/{z}/{x}/{y}.' + (info.format || 'pbf')
]; ];
delete source.scheme; delete source.scheme;
if (source.format == 'pbf') {
map.sources[name].emptyTile = new Buffer(0); if (options.dataDecoratorFunc) {
} else { source = options.dataDecoratorFunc(name, 'tilejson', source);
var color = new Color(source.color || 'rgba(255,255,255,0)');
var format = source.format;
if (format == 'jpg') {
format = 'jpeg';
}
var array = color.array();
var channels = array.length == 4 && format != 'jpeg' ? 4 : 3;
sharp(new Buffer(array), {
raw: {
width: 1,
height: 1,
channels: channels
}
}).toFormat(format).toBuffer(function(err, buffer, info) {
map.sources[name].emptyTile = buffer;
});
} }
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) {
@@ -292,24 +356,21 @@ module.exports = function(options, repo, params, id, dataResolver) {
}); });
var renderersReadyPromise = Promise.all(queue).then(function() { var renderersReadyPromise = Promise.all(queue).then(function() {
// TODO: make pool sizes configurable // standard and @2x tiles are much more usual -> default to larger pools
var minPoolSizes = options.minRendererPoolSizes || [8, 4, 2];
var maxPoolSizes = options.maxRendererPoolSizes || [16, 8, 4];
for (var s = 1; s <= maxScaleFactor; s++) { for (var s = 1; s <= maxScaleFactor; s++) {
var minPoolSize = 2; var i = Math.min(minPoolSizes.length - 1, s - 1);
var j = Math.min(maxPoolSizes.length - 1, s - 1);
// standard and @2x tiles are much more usual -> create larger pools var minPoolSize = minPoolSizes[i];
if (s <= 2) { var maxPoolSize = Math.max(minPoolSize, maxPoolSizes[j]);
minPoolSize *= 2; map.renderers[s] = createPool(s, minPoolSize, maxPoolSize);
if (s <= 1) {
minPoolSize *= 2;
}
}
map.renderers[s] = createPool(s, minPoolSize, 2 * minPoolSize);
} }
}); });
repo[id] = tileJSON; repo[id] = tileJSON;
var tilePattern = '/rendered/: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,
@@ -348,7 +409,10 @@ module.exports = function(options, repo, params, id, dataResolver) {
} }
renderer.render(params, function(err, data) { renderer.render(params, function(err, data) {
pool.release(renderer); pool.release(renderer);
if (err) console.log(err); if (err) {
console.error(err);
return;
}
var image = sharp(data, { var image = sharp(data, {
raw: { raw: {
@@ -395,16 +459,6 @@ module.exports = function(options, repo, params, id, dataResolver) {
return res.status(404).send('Not found'); return res.status(404).send('Not found');
} }
if (format == 'png') {
var usePngQuant =
(options.formatQuality || {}).pngQuantization === true;
if (usePngQuant) {
buffer = pngquant.compress(buffer, {
quality: [0, formatQuality || 90]
});
}
}
res.set({ res.set({
'Last-Modified': lastModified, 'Last-Modified': lastModified,
'Content-Type': 'image/' + format 'Content-Type': 'image/' + format
@@ -540,7 +594,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
if (options.serveStaticMaps !== false) { if (options.serveStaticMaps !== false) {
var staticPattern = var staticPattern =
'/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 =
@@ -624,7 +678,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
app.get(util.format(staticPattern, boundsPattern), serveBounds); app.get(util.format(staticPattern, boundsPattern), serveBounds);
app.get('/static/', function(req, res, next) { app.get('/' + id + '/static/', function(req, res, next) {
for (var key in req.query) { for (var key in req.query) {
req.query[key.toLowerCase()] = req.query[key]; req.query[key.toLowerCase()] = req.query[key];
} }
@@ -690,16 +744,15 @@ module.exports = function(options, repo, params, id, dataResolver) {
}); });
} }
app.get('/rendered.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 + '/rendered', info.format); 'styles/' + id, info.format);
return res.send(info); return res.send(info);
}); });
return new Promise(function(resolve, reject) { return Promise.all([fontListingPromise, renderersReadyPromise]).then(function() {
Promise.all([fontListingPromise, renderersReadyPromise]).then(function() { return app;
resolve(app);
});
}); });
}; };
+1 -1
View File
@@ -62,7 +62,7 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
repo[id] = styleJSON; repo[id] = styleJSON;
app.get('/' + id + '.json', function(req, res, next) { app.get('/' + id + '/style.json', function(req, res, next) {
var fixUrl = function(url, opt_nokey, opt_nostyle) { var fixUrl = function(url, opt_nokey, opt_nostyle) {
if (!url || (typeof url !== 'string') || url.indexOf('local://') !== 0) { if (!url || (typeof url !== 'string') || url.indexOf('local://') !== 0) {
return url; return url;
+40 -20
View File
@@ -7,8 +7,7 @@ process.env.UV_THREADPOOL_SIZE =
var fs = require('fs'), var fs = require('fs'),
path = require('path'); path = require('path');
var base64url = require('base64url'), var clone = require('clone'),
clone = require('clone'),
cors = require('cors'), cors = require('cors'),
enableShutdown = require('http-shutdown'), enableShutdown = require('http-shutdown'),
express = require('express'), express = require('express'),
@@ -43,9 +42,13 @@ function start(opts) {
app.enable('trust proxy'); app.enable('trust proxy');
if (process.env.NODE_ENV == 'production') { if (process.env.NODE_ENV == 'production') {
app.use(morgan('tiny')); app.use(morgan('tiny', {
skip: function(req, res) { return opts.silent && (res.statusCode == 200 || res.statusCode == 304) }
}));
} else if (process.env.NODE_ENV !== 'test') { } else if (process.env.NODE_ENV !== 'test') {
app.use(morgan('dev')); app.use(morgan('dev', {
skip: function(req, res) { return opts.silent && (res.statusCode == 200 || res.statusCode == 304) }
}));
} }
var config = opts.config || null; var config = opts.config || null;
@@ -89,6 +92,12 @@ function start(opts) {
checkPath('sprites'); checkPath('sprites');
checkPath('mbtiles'); checkPath('mbtiles');
if (options.dataDecorator) {
try {
options.dataDecoratorFunc = require(path.resolve(paths.root, options.dataDecorator));
} catch (e) {}
}
var data = clone(config.data || {}); var data = clone(config.data || {});
if (opts.cors) { if (opts.cors) {
@@ -150,7 +159,7 @@ function start(opts) {
return mbtilesFile; return mbtilesFile;
} }
).then(function(sub) { ).then(function(sub) {
app.use('/styles/' + id + '/', sub); app.use('/styles/', sub);
}) })
); );
} else { } else {
@@ -189,7 +198,7 @@ function start(opts) {
name: styleJSON.name, name: styleJSON.name,
id: id, id: id,
url: req.protocol + '://' + req.headers.host + url: req.protocol + '://' + req.headers.host +
'/styles/' + id + '.json' + query '/styles/' + id + '/style.json' + query
}); });
}); });
res.send(result); res.send(result);
@@ -200,7 +209,7 @@ function start(opts) {
var info = clone(serving[type][id]); var info = clone(serving[type][id]);
var path = ''; var path = '';
if (type == 'rendered') { if (type == 'rendered') {
path = 'styles/' + id + '/rendered'; path = 'styles/' + id;
} else { } else {
path = type + '/' + id; path = type + '/' + id;
} }
@@ -240,8 +249,9 @@ function start(opts) {
startupPromises.push(new Promise(function(resolve, reject) { startupPromises.push(new Promise(function(resolve, reject) {
fs.readFile(templateFile, function(err, content) { fs.readFile(templateFile, function(err, content) {
if (err) { if (err) {
console.error('Template not found:', err); err = new Error('Template not found: ' + err.message);
reject(err); reject(err);
return;
} }
var compiled = handlebars.compile(content.toString()); var compiled = handlebars.compile(content.toString());
@@ -258,6 +268,7 @@ function start(opts) {
data['key_query_part'] = data['key_query_part'] =
req.query.key ? 'key=' + req.query.key + '&amp;' : ''; req.query.key ? 'key=' + req.query.key + '&amp;' : '';
data['key_query'] = req.query.key ? '?key=' + req.query.key : ''; data['key_query'] = req.query.key ? '?key=' + req.query.key : '';
if (template === 'wmts') res.set('Content-Type', 'text/xml');
return res.status(200).send(compiled(data)); return res.status(200).send(compiled(data));
}); });
resolve(); resolve();
@@ -284,15 +295,10 @@ function start(opts) {
Math.floor(centerPx[0] / 256) + '/' + Math.floor(centerPx[0] / 256) + '/' +
Math.floor(centerPx[1] / 256) + '.png'; Math.floor(centerPx[1] / 256) + '.png';
} }
var query = req.query.key ? ('?key=' + req.query.key) : '';
style.wmts_link = 'http://wmts.maptiler.com/' +
base64url('http://' + req.headers.host +
'/styles/' + id + '/rendered.json' + query) + '/wmts';
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, style.serving_rendered.tiles, req, style.serving_rendered.tiles,
'styles/' + id + '/rendered', style.serving_rendered.format); 'styles/' + id, style.serving_rendered.format);
style.xyz_link = tiles[0]; style.xyz_link = tiles[0];
} }
}); });
@@ -314,11 +320,6 @@ function start(opts) {
Math.floor(centerPx[1] / 256) + '.' + data_.format; Math.floor(centerPx[1] / 256) + '.' + data_.format;
} }
var query = req.query.key ? ('?key=' + req.query.key) : '';
data_.wmts_link = 'http://wmts.maptiler.com/' +
base64url('http://' + req.headers.host +
'/data/' + id + '.json' + query) + '/wmts';
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, data_.tiles, 'data/' + id, data_.format, { req, data_.tiles, 'data/' + id, data_.format, {
'pbf': options.pbfAlias 'pbf': options.pbfAlias
@@ -363,6 +364,20 @@ function start(opts) {
return res.redirect(301, '/styles/' + req.params.id + '/'); return res.redirect(301, '/styles/' + req.params.id + '/');
}); });
*/ */
serveTemplate('/styles/:id/wmts.xml', 'wmts', function(req) {
var id = req.params.id;
var wmts = clone((config.styles || {})[id]);
if (!wmts) {
return null;
}
if (wmts.hasOwnProperty("serve_rendered") && !wmts.serve_rendered) {
return null;
}
wmts.id = id;
wmts.name = (serving.styles[id] || serving.rendered[id]).name;
wmts.baseUrl = (req.get('X-Forwarded-Protocol')?req.get('X-Forwarded-Protocol'):req.protocol) + '://' + req.get('host');
return wmts;
});
serveTemplate('/data/:id/$', 'data', function(req) { serveTemplate('/data/:id/$', 'data', function(req) {
var id = req.params.id; var id = req.params.id;
@@ -409,6 +424,11 @@ function start(opts) {
module.exports = function(opts) { module.exports = function(opts) {
var running = start(opts); var running = start(opts);
running.startupPromise.catch(function(err) {
console.error(err.message);
process.exit(1);
});
process.on('SIGINT', function() { process.on('SIGINT', function() {
process.exit(); process.exit();
}); });
+16 -5
View File
@@ -84,7 +84,20 @@ var getFontPbf = function(allowedFonts, fontPath, name, range, fallbacks) {
if (err) { if (err) {
console.error('ERROR: Font not found:', name); console.error('ERROR: Font not found:', name);
if (fallbacks && Object.keys(fallbacks).length) { if (fallbacks && Object.keys(fallbacks).length) {
var fallbackName = Object.keys(fallbacks)[0]; var fallbackName;
var fontStyle = name.split(' ').pop();
if (['Regular', 'Bold', 'Italic'].indexOf(fontStyle) < 0) {
fontStyle = 'Regular';
}
fallbackName = 'Noto Sans ' + fontStyle;
if (!fallbacks[fallbackName]) {
fallbackName = 'Open Sans ' + fontStyle;
if (!fallbacks[fallbackName]) {
fallbackName = Object.keys(fallbacks)[0];
}
}
console.error('ERROR: Trying to use', fallbackName, 'as a fallback'); console.error('ERROR: Trying to use', fallbackName, 'as a fallback');
delete fallbacks[fallbackName]; delete fallbacks[fallbackName];
getFontPbf(null, fontPath, fallbackName, range, fallbacks).then(resolve, reject); getFontPbf(null, fontPath, fallbackName, range, fallbacks).then(resolve, reject);
@@ -110,9 +123,7 @@ module.exports.getFontsPbf = function(allowedFonts, fontPath, names, range, fall
); );
}); });
return new Promise(function(resolve, reject) { return Promise.all(queue).then(function(values) {
Promise.all(queue).then(function(values) { return glyphCompose.combine(values);
return resolve(glyphCompose.combine(values));
}, reject);
}); });
}; };
+1 -1
View File
@@ -71,6 +71,6 @@ describe('Metadata', function() {
}); });
}); });
testTileJSON('/styles/test-style/rendered.json'); testTileJSON('/styles/test-style.json');
testTileJSON('/data/openmaptiles.json'); testTileJSON('/data/openmaptiles.json');
}); });
+1 -1
View File
@@ -17,5 +17,5 @@ before(function() {
after(function() { after(function() {
console.log('global teardown'); console.log('global teardown');
global.server.close(function() { console.log('Done'); }); global.server.close(function() { console.log('Done'); process.exit(); });
}); });
+5 -5
View File
@@ -11,12 +11,12 @@ var testIs = function(url, type, status) {
var prefix = 'test-style'; var prefix = 'test-style';
describe('Styles', function() { describe('Styles', function() {
describe('/styles/' + prefix + '.json is valid style', function() { describe('/styles/' + prefix + '/style.json is valid style', function() {
testIs('/styles/' + prefix + '.json', /application\/json/); testIs('/styles/' + prefix + '/style.json', /application\/json/);
it('contains expected properties', function(done) { it('contains expected properties', function(done) {
supertest(app) supertest(app)
.get('/styles/' + prefix + '.json') .get('/styles/' + prefix + '/style.json')
.expect(function(res) { .expect(function(res) {
res.body.version.should.equal(8); res.body.version.should.equal(8);
res.body.name.should.be.String(); res.body.name.should.be.String();
@@ -27,8 +27,8 @@ describe('Styles', function() {
}).end(done); }).end(done);
}); });
}); });
describe('/styles/streets.json is not served', function() { describe('/styles/streets/style.json is not served', function() {
testIs('/styles/streets.json', /./, 404); testIs('/styles/streets/style.json', /./, 404);
}); });
describe('/styles/' + prefix + '/sprite[@2x].{format}', function() { describe('/styles/' + prefix + '/sprite[@2x].{format}', function() {
+1 -1
View File
@@ -23,6 +23,6 @@ describe('Vector tiles', function() {
testTile(prefix, 0, 1, 0, 404); testTile(prefix, 0, 1, 0, 404);
testTile(prefix, 0, 0, 1, 404); testTile(prefix, 0, 0, 1, 404);
testTile(prefix, 14, 0, 0, 404); // non existent tile testTile(prefix, 14, 0, 0, 204); // non existent tile
}); });
}); });
+1 -1
View File
@@ -1,6 +1,6 @@
var testTile = function(prefix, z, x, y, format, status, scale, type) { var testTile = function(prefix, z, x, y, format, status, scale, type) {
if (scale) y += '@' + scale + 'x'; if (scale) y += '@' + scale + 'x';
var path = '/styles/' + prefix + '/rendered/' + z + '/' + x + '/' + y + '.' + format; var path = '/styles/' + prefix + '/' + z + '/' + x + '/' + y + '.' + format;
it(path + ' returns ' + status, function(done) { it(path + ' returns ' + status, function(done) {
var test = supertest(app).get(path); var test = supertest(app).get(path);
test.expect(status); test.expect(status);