Compare commits

..

No commits in common. "master" and "v5.1.0" have entirely different histories.

37 changed files with 5411 additions and 4111 deletions

View file

@ -14,4 +14,3 @@ jobs:
- uses: fastify/github-action-merge-dependabot@v3 - uses: fastify/github-action-merge-dependabot@v3
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
target: minor

View file

@ -21,11 +21,6 @@ jobs:
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies (Ubuntu) 🚀
run: >-
sudo apt-get install -qq libcairo2-dev libjpeg8-dev libpango1.0-dev
libgif-dev build-essential
- name: Setup node env 📦 - name: Setup node env 📦
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View file

@ -65,22 +65,6 @@ jobs:
context: . context: .
push: false push: false
platforms: linux/arm64,linux/amd64 platforms: linux/arm64,linux/amd64
cache-from: type=gha # experimental: https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api
cache-to: type=gha,mode=max
- name: Create Tileserver Light Directory
run: node publish.js --no-publish
- name: Install node dependencies
run: npm ci --prefer-offline --no-audit
working-directory: ./light
- name: Test Light Version to Docker Hub
uses: docker/build-push-action@v6
with:
context: ./light
file: ./light/Dockerfile
push: false
platforms: linux/arm64,linux/amd64
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max

11
.gitignore vendored
View file

@ -1,15 +1,4 @@
docs/_build docs/_build
public/resources/leaflet-hash.js
public/resources/leaflet.css
public/resources/leaflet.js
public/resources/leaflet.js.map
public/resources/mapbox-gl-rtl-text.js
public/resources/maplibre-gl-inspect.css
public/resources/maplibre-gl-inspect.js
public/resources/maplibre-gl-inspect.js.map
public/resources/maplibre-gl.css
public/resources/maplibre-gl.js
public/resources/maplibre-gl.js.map
node_modules node_modules
test_data test_data
test_data.zip test_data.zip

View file

@ -1,24 +1,5 @@
# tileserver-gl changelog # tileserver-gl changelog
## 5.2.0
* Use npm packages for public/resources (https://github.com/maptiler/tileserver-gl/pull/1427) by @okimiko
* use ttf files of googlefonts/opensans (https://github.com/maptiler/tileserver-gl/pull/1447) by @okimiko
* Limit Elevation Lat/Long Output Length (https://github.com/maptiler/tileserver-gl/pull/1457) by @okimiko
* Fetch style from url (https://github.com/maptiler/tileserver-gl/pull/1462) by @YoelRidgway
* fix: memory leak on SIGHUP (https://github.com/maptiler/tileserver-gl/pull/1455) by @okimiko
* fix: resolves Unimplemented type: 3 error for geojson format (https://github.com/maptiler/tileserver-gl/pull/1465) by @rjdjohnston
* fix: Test light version in ct workflow - fix sqlite build in light (https://github.com/maptiler/tileserver-gl/pull/1477) by @acalcutt
* fix: light version docker entrypoint permissions (https://github.com/maptiler/tileserver-gl/pull/1478) by @acalcutt
## 5.1.3
* Fix SIGHUP (broken since 5.1.x) (https://github.com/maptiler/tileserver-gl/pull/1452) by @okimiko
## 5.1.2
* Fix broken light (invalid use of heavy dependencies) (https://github.com/maptiler/tileserver-gl/pull/1449) by @okimiko
## 5.1.1
* Fix wrong node version in Docker image (https://github.com/maptiler/tileserver-gl/pull/1442) by @acalcutt
## 5.1.0 ## 5.1.0
* Update recommended node to v22 + Update docker images to use node 22 (https://github.com/maptiler/tileserver-gl/pull/1438) by @acalcutt * Update recommended node to v22 + Update docker images to use node 22 (https://github.com/maptiler/tileserver-gl/pull/1438) by @acalcutt
* Upgrade Express to v5 + Canvas to v3 + code cleanup (https://github.com/maptiler/tileserver-gl/pull/1429) by @acalcutt * Upgrade Express to v5 + Canvas to v3 + code cleanup (https://github.com/maptiler/tileserver-gl/pull/1429) by @acalcutt
@ -29,4 +10,4 @@
* Update Maplibre-Native to [v6.0.0](https://github.com/maplibre/maplibre-native/releases/tag/node-v6.0.0) release by @acalcutt in https://github.com/maptiler/tileserver-gl/pull/1376 and @dependabot in https://github.com/maptiler/tileserver-gl/pull/1381 * Update Maplibre-Native to [v6.0.0](https://github.com/maplibre/maplibre-native/releases/tag/node-v6.0.0) release by @acalcutt in https://github.com/maptiler/tileserver-gl/pull/1376 and @dependabot in https://github.com/maptiler/tileserver-gl/pull/1381
* This first release that use Metal for rendering instead of OpenGL (ES) for macOS. * This first release that use Metal for rendering instead of OpenGL (ES) for macOS.
* This the first release that uses OpenGL (ES) 3.0 on Windows and Linux * This the first release that uses OpenGL (ES) 3.0 on Windows and Linux
* Note: Windows users may need to update their [c++ redistributable ](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170) for maplibre-native v6.0.0 * Note: Windows users may need to update their [c++ redistributable ](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170) for maplibre-native v6.0.0

View file

@ -2,11 +2,10 @@ FROM ubuntu:jammy AS builder
ENV NODE_ENV="production" ENV NODE_ENV="production"
SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN set -ex; \
export DEBIAN_FRONTEND=noninteractive; \
RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get -qq update; \
apt-get update && \ apt-get -y --no-install-recommends install \
apt-get install -y --no-install-recommends --no-install-suggests \
build-essential \ build-essential \
ca-certificates \ ca-certificates \
curl \ curl \
@ -27,17 +26,23 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
librsvg2-common \ librsvg2-common \
libcurl4-openssl-dev \ libcurl4-openssl-dev \
libpixman-1-dev \ libpixman-1-dev \
libpixman-1-0 && \ libpixman-1-0; \
mkdir -p /etc/apt/keyrings && \ apt-get -y --purge autoremove; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ apt-get clean; \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ rm -rf /var/lib/apt/lists/*;
apt-get -qq update && \
apt-get install -y --no-install-recommends --no-install-suggests nodejs && \ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
npm i -g npm@latest && \
apt-get -y remove curl gnupg && \ RUN mkdir -p /etc/apt/keyrings; \
apt-get -y --purge autoremove && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; \
apt-get clean && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list; \
rm -rf /var/lib/apt/lists/* apt-get -qq update; \
apt-get install -y nodejs; \
npm i -g npm@latest; \
apt-get -y remove curl gnupg; \
apt-get -y --purge autoremove; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
RUN mkdir -p /usr/src/app RUN mkdir -p /usr/src/app
@ -46,12 +51,12 @@ WORKDIR /usr/src/app
COPY package.json /usr/src/app COPY package.json /usr/src/app
COPY package-lock.json /usr/src/app COPY package-lock.json /usr/src/app
RUN npm config set maxsockets 1 && \ RUN npm config set maxsockets 1; \
npm config set fetch-retries 5 && \ npm config set fetch-retries 5; \
npm config set fetch-retry-mintimeout 100000 && \ npm config set fetch-retry-mintimeout 100000; \
npm config set fetch-retry-maxtimeout 600000 && \ npm config set fetch-retry-maxtimeout 600000; \
npm ci --omit=dev && \ npm ci --omit=dev; \
chown -R root:root /usr/src/app chown -R root:root /usr/src/app;
FROM ubuntu:jammy AS final FROM ubuntu:jammy AS final
@ -60,13 +65,12 @@ ENV \
CHOKIDAR_USEPOLLING=1 \ CHOKIDAR_USEPOLLING=1 \
CHOKIDAR_INTERVAL=500 CHOKIDAR_INTERVAL=500
SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN set -ex; \
export DEBIAN_FRONTEND=noninteractive; \
RUN export DEBIAN_FRONTEND=noninteractive && \ groupadd -r node; \
groupadd -r node && \ useradd -r -g node node; \
useradd -r -g node node && \ apt-get -qq update; \
apt-get -qq update && \ apt-get -y --no-install-recommends install \
apt-get install -y --no-install-recommends --no-install-suggests \
ca-certificates \ ca-certificates \
curl \ curl \
gnupg \ gnupg \
@ -81,17 +85,23 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libpixman-1-0 \ libpixman-1-0 \
libcurl4 \ libcurl4 \
librsvg2-2 \ librsvg2-2 \
libpango-1.0-0 && \ libpango-1.0-0; \
mkdir -p /etc/apt/keyrings && \ apt-get -y --purge autoremove; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ apt-get clean; \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ rm -rf /var/lib/apt/lists/*;
apt-get -qq update && \
apt-get install -y --no-install-recommends --no-install-suggests nodejs && \ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
npm i -g npm@latest && \
apt-get -y remove curl gnupg && \ RUN mkdir -p /etc/apt/keyrings; \
apt-get -y --purge autoremove && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; \
apt-get clean && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list; \
rm -rf /var/lib/apt/lists/* apt-get -qq update; \
apt-get install -y nodejs; \
npm i -g npm@latest; \
apt-get -y remove curl gnupg; \
apt-get -y --purge autoremove; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
COPY --from=builder /usr/src/app /usr/src/app COPY --from=builder /usr/src/app /usr/src/app

View file

@ -1,38 +0,0 @@
FROM ubuntu:jammy AS builder
ENV NODE_ENV="devel"
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
build-essential \
ca-certificates \
curl \
gnupg \
pkg-config \
xvfb \
libglfw3-dev \
libuv1-dev \
libjpeg-turbo8 \
libicu70 \
libcairo2-dev \
libpango1.0-dev \
libjpeg-dev \
libgif-dev \
librsvg2-dev \
gir1.2-rsvg-2.0 \
librsvg2-2 \
librsvg2-common \
libcurl4-openssl-dev \
libpixman-1-dev \
libpixman-1-0 && \
mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
apt-get -qq update && \
apt-get install -y --no-install-recommends --no-install-suggests nodejs && \
npm i -g npm@latest && \
apt-get -y remove curl gnupg && \
apt-get -y --purge autoremove && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

View file

@ -1,84 +1,53 @@
FROM ubuntu:jammy AS builder FROM ubuntu:jammy
ENV NODE_ENV="production"
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
build-essential \
ca-certificates \
curl \
gnupg && \
mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
apt-get -qq update && \
apt-get install -y --no-install-recommends --no-install-suggests nodejs && \
npm i -g npm@latest && \
apt-get -y remove curl gnupg && \
apt-get -y --purge autoremove && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app
COPY package-lock.json /usr/src/app
RUN npm config set maxsockets 1 && \
npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 100000 && \
npm config set fetch-retry-maxtimeout 600000 && \
npm ci --omit=dev && \
chown -R root:root /usr/src/app
FROM ubuntu:jammy AS final
ENV \ ENV \
NODE_ENV="production" \ NODE_ENV="production" \
CHOKIDAR_USEPOLLING=1 \ CHOKIDAR_USEPOLLING=1 \
CHOKIDAR_INTERVAL=500 CHOKIDAR_INTERVAL=500
SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN set -ex; \
export DEBIAN_FRONTEND=noninteractive; \
RUN export DEBIAN_FRONTEND=noninteractive && \ groupadd -r node; \
groupadd -r node && \ useradd -r -g node node; \
useradd -r -g node node && \ apt-get -qq update; \
apt-get -qq update && \ apt-get -y --no-install-recommends install \
apt-get install -y --no-install-recommends --no-install-suggests \
ca-certificates \ ca-certificates \
curl \ curl \
gnupg && \ gnupg; \
mkdir -p /etc/apt/keyrings && \ mkdir -p /etc/apt/keyrings; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list; \
apt-get -qq update && \ apt-get -qq update; \
apt-get install -y --no-install-recommends --no-install-suggests nodejs && \ apt-get install -y nodejs; \
npm i -g npm@latest && \ npm i -g npm@latest; \
apt-get -y remove curl gnupg && \ apt-get -y remove curl gnupg; \
apt-get -y --purge autoremove && \ apt-get -y --purge autoremove; \
apt-get clean && \ apt-get clean; \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*;
COPY --from=builder /usr/src/app /usr/src/app
COPY . /usr/src/app
RUN mkdir -p /data && \
chown node:node /data && \
chmod +x /usr/src/app/docker-entrypoint.sh
VOLUME /data
WORKDIR /data
EXPOSE 8080 EXPOSE 8080
RUN mkdir -p /data; \
chown node:node /data; \
mkdir -p /usr/src/app;
VOLUME /data
WORKDIR /data
COPY / /usr/src/app
RUN cd /usr/src/app; \
npm config set maxsockets 1; \
npm config set fetch-retries 5; \
npm config set fetch-retry-mintimeout 100000; \
npm config set fetch-retry-maxtimeout 600000; \
npm install --omit=dev; \
chown -R root:root /usr/src/app; \
chmod +x /usr/src/app/docker-entrypoint.sh;
USER node:node USER node:node
ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"] ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"]
HEALTHCHECK CMD node /usr/src/app/src/healthcheck.js HEALTHCHECK CMD node /usr/src/app/src/healthcheck.js

View file

@ -13,8 +13,7 @@ RUN set -ex; \
unzip \ unzip \
build-essential \ build-essential \
ca-certificates \ ca-certificates \
curl \ wget \
gnupg \
pkg-config \ pkg-config \
xvfb \ xvfb \
libglfw3-dev \ libglfw3-dev \
@ -26,33 +25,16 @@ RUN set -ex; \
libjpeg-dev \ libjpeg-dev \
libgif-dev \ libgif-dev \
librsvg2-dev \ librsvg2-dev \
gir1.2-rsvg-2.0 \
librsvg2-2 \
librsvg2-common \
libcurl4-openssl-dev \ libcurl4-openssl-dev \
libpixman-1-dev \ libpixman-1-dev; \
libpixman-1-0; \ wget -qO- https://deb.nodesource.com/setup_18.x | bash; \
apt-get -y --purge autoremove; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN mkdir -p /etc/apt/keyrings; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list; \
apt-get -qq update; \
apt-get install -y nodejs; \ apt-get install -y nodejs; \
npm i -g npm@latest; \ apt-get clean;
apt-get -y remove gnupg; \
apt-get -y --purge autoremove; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
RUN mkdir -p /usr/src/app RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app WORKDIR /usr/src/app
RUN curl -L -o test_data.zip https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip; \ RUN wget -O test_data.zip https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip; \
unzip -q test_data.zip -d test_data unzip -q test_data.zip -d test_data
COPY package.json . COPY package.json .

View file

@ -1,112 +1,19 @@
# Publishing a New Version # Publishing new version
This document outlines the process for publishing new versions of this project. We use a GitHub workflow for automated releases, but also provide manual steps for specific situations. 1.) Change the version number in package.json. Run the following command in the package root directory, replacing <update_type> with one of the semantic versioning release types (prerelease, prepatch, preminor, premajor, patch, minor, major):
npm version <update_type> --preid pre --no-git-tag-version
## Automated Publishing via GitHub Workflow (Recommended) --preid specifies which suffix to use in the release such as pre, next, beta, rc, etc.
This is the preferred method for publishing new versions. It automates the entire process, including version bumping, tagging, building, and publishing. prepatch, preminor, and premajor start a new series of pre-releases while bumping the patch, minor, or major version. E.g. premajor with --preid pre would do a prerelease for a new major using the -pre suffix (i.e. it would be a new major with -pre.0)
1. **Prepare the Release:** You can use prerelease to bump the version for a new pre-release version. E.g. you could run npm version prerelease --preid pre --no-git-tag-version to go from -pre.0 to -pre.1.
* **Choose the Version Increment:** Determine the appropriate semantic versioning increment (prerelease, prepatch, preminor, premajor, patch, minor, major). For regular versions, you can use patch, minor, or major. E.g. npm version major --no-git-tag-version.
* **Update `package.json`:** Use the `npm version` command to bump the version number. This command also supports creating pre-release versions using the `--preid pre` flag. 2.) Update the changelog, which can be found in CHANGELOG.md. The heading must match ## <VERSION> exactly, or it will not be picked up. For example, for version 5.0.0:
```## 5.0.0```
```bash 3.) Commit and push the changes.
# Example: Increment to a new patch version
npm version patch --no-git-tag-version
# Example: Increment to a new minor version 4.) Run the 'Build, Test, Release' github workflow. The workflow will create a NPM, Docker, and Github release and Tag.
npm version minor --no-git-tag-version
# Example: Increment to a new major version
npm version major --no-git-tag-version
# Example: Create a pre-release (e.g., -pre.0) version
npm version prepatch --preid pre --no-git-tag-version
# OR
npm version preminor --preid pre --no-git-tag-version
# OR
npm version premajor --preid pre --no-git-tag-version
# Example: Increment an existing pre-release version (e.g., -pre.0 to -pre.1)
npm version prerelease --preid pre --no-git-tag-version
```
* `--no-git-tag-version`: This prevents `npm version` from automatically creating a git tag, as the GitHub workflow will handle this later.
* `--preid pre`: Specifies that "pre" is the pre-release identifier.
* **Update the Changelog (`CHANGELOG.md`):** Add a new section for the release. The heading *must* exactly match the format `## <VERSION>`, where `<VERSION>` is the full version number from `package.json`. Describe the changes included in the release.
```markdown
## 1.2.3
* Added new feature X.
```
2. **Commit and Push:** Commit the changes to `package.json`, `package-lock.json` and `CHANGELOG.md` to a the `master` branch. Create a pull request (PR) for review. If you are an administrator, you may push directly, but a PR is generally recommended for code review.
3. **Run the GitHub Workflow:** Once the PR is merged (or changes pushed directly), trigger the "Build, Test, Release" GitHub workflow. This workflow is responsible for:
* Building the project.
* Running tests.
* Creating an NPM package.
* Building and pushing Docker images.
* Creating a GitHub Release.
* Creating a Git tag for the release.
## Manual Publishing (For Special Cases)
Use the following steps *only* when the automated workflow is not suitable (e.g., for debugging, specific environment needs).
1. **Update Version in `package.json`:** Modify the `version` field in `package.json` to the desired version number.
2. **Create and Push Git Tag:**
```bash
git tag vX.X.X # Replace X.X.X with the version number
git push origin --tags
```
3. **NPM Publish Options (Choose ONE):**
* **Option A: Publish only the full `tileserver-gl` version:**
```bash
npm publish --access public
```
* **Option B: Build and Publish both `tileserver-gl` and `tileserver-gl-light` using `publish.js`:**
```bash
# This script builds the light version and publishes both tileserver-gl and tileserver-gl-light to NPM.
node publish.js
```
* **Option C: Build only the `tileserver-gl-light` version (no publish):**
```bash
# This script ONLY builds the light version (e.g., for local testing or Docker image creation) without publishing.
node publish.js --no-publish
```
4. **Build and Push Docker Images:**
```bash
# Build the main image
docker buildx build --platform linux/amd64 -t maptiler/tileserver-gl:latest -t maptiler/tileserver-gl:X.X.X . # Replace X.X.X
docker push maptiler/tileserver-gl --all-tags
# Build the light image
cd light
docker buildx build --platform linux/amd64 -t maptiler/tileserver-gl-light:latest -t maptiler/tileserver-gl-light:X.X.X . # Replace X.X.X
docker push maptiler/tileserver-gl-light --all-tags
cd .. # Return to the project root
```
* Make sure you are logged into the docker registry before pushing. `docker login`
**Important Considerations for Manual Publishing:**
* **Consistency:** Ensure the version number in `package.json`, the Git tag, and the Docker image tags are identical.
* **Credentials:** Verify that you have the necessary permissions to push Docker images and publish to NPM.
* **Cleanliness:** Before building Docker images, ensure your working directory is clean to avoid including unwanted files in the image.
* **Error Handling:** Manually publishing is more prone to errors. Double-check each step to avoid issues.

View file

@ -1,32 +1,5 @@
![tileserver-gl](https://cloud.githubusercontent.com/assets/59284/18173467/fa3aa2ca-7069-11e6-86b1-0f1266befeb6.jpeg) ![tileserver-gl](https://cloud.githubusercontent.com/assets/59284/18173467/fa3aa2ca-7069-11e6-86b1-0f1266befeb6.jpeg)
# My TileServer GL
creare un folder dove mettere la mappa e i layers
Download vector tiles from [OpenMapTiles](https://data.maptiler.com/downloads/planet/).
scaricare i layers
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip
unzip test_data.zip
modificare nano config.json per inserire il nome del file .mbtiles (x es planetOSM.mbtiles )
far partire il docker
services:
tileserver-gl:
volumes:
- /home/nvme/dockerdata/tileserver:/data
ports:
- 8115:8080
image: maptiler/tileserver-gl:latest
oppure
sudo docker run -d -v /home/nvme/dockerdata/tileserver:/data -p 8115:8080 maptiler/tileserver-gl:latest
# TileServer GL # TileServer GL
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/maptiler/tileserver-gl/pipeline.yml)](https://github.com/maptiler/tileserver-gl/actions/workflows/pipeline.yml) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/maptiler/tileserver-gl/pipeline.yml)](https://github.com/maptiler/tileserver-gl/actions/workflows/pipeline.yml)
[![Docker Hub](https://img.shields.io/badge/docker-hub-blue.svg)](https://hub.docker.com/r/maptiler/tileserver-gl/) [![Docker Hub](https://img.shields.io/badge/docker-hub-blue.svg)](https://hub.docker.com/r/maptiler/tileserver-gl/)

View file

@ -57,9 +57,6 @@ Example:
"tilejson": { "tilejson": {
"format": "webp" "format": "webp"
} }
},
"remote": {
"style": "https://demotiles.maplibre.org/style.json"
} }
}, },
"data": { "data": {
@ -212,7 +209,7 @@ Not used by default.
Each item in this object defines one style (map). It can have the following options: Each item in this object defines one style (map). It can have the following options:
* ``style`` -- name of the style json file or url of a remote hosted style [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 access 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

View file

@ -108,8 +108,6 @@ Source data
* the result will be a json object like ``{"z":7,"x":68,"y":45,"red":134,"green":66,"blue":0,"latitude":11.84069,"longitude":46.04798,"elevation":1602}`` * the result will be a json object like ``{"z":7,"x":68,"y":45,"red":134,"green":66,"blue":0,"latitude":11.84069,"longitude":46.04798,"elevation":1602}``
* The elevation api is not available in the ``tileserver-gl-light`` version.
Static files Static files
=========== ===========
* Static files are served at ``/files/{filename}`` * Static files are served at ``/files/{filename}``

4930
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,11 @@
{ {
"name": "tileserver-gl", "name": "tileserver-gl",
"version": "5.2.0", "version": "5.1.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",
"type": "module", "type": "module",
"scripts": { "scripts": {
"prepare": "npm run copy:maplibre && npm run copy:maplibre-inspect && npm run copy:mapbox-rtl-text && npm run copy:leaflet && npm run copy:leaflet-hash",
"copy:maplibre": "copyfiles -EVf node_modules/maplibre-gl/dist/maplibre-gl.js node_modules/maplibre-gl/dist/maplibre-gl.js.map node_modules/maplibre-gl/dist/maplibre-gl.css public/resources/",
"copy:maplibre-inspect": "copyfiles -EVf node_modules/@maplibre/maplibre-gl-inspect/dist/maplibre-gl-inspect.js node_modules/@maplibre/maplibre-gl-inspect/dist/maplibre-gl-inspect.js.map node_modules/@maplibre/maplibre-gl-inspect/dist/maplibre-gl-inspect.css public/resources/",
"copy:mapbox-rtl-text": "copyfiles -EVf node_modules/@mapbox/mapbox-gl-rtl-text/dist/mapbox-gl-rtl-text.js public/resources/",
"copy:leaflet": "copyfiles -EVf node_modules/leaflet/dist/leaflet.js node_modules/leaflet/dist/leaflet.js.map node_modules/leaflet/dist/leaflet.css node_modules/leaflet/dist/leaflet-hash.js public/resources/",
"copy:leaflet-hash": "copyfiles -EVf node_modules/leaflet-hash/leaflet-hash.js public/resources/",
"test": "mocha test/**.js --timeout 10000 --exit", "test": "mocha test/**.js --timeout 10000 --exit",
"test-docker": "xvfb-run npm test", "test-docker": "xvfb-run npm test",
"lint:yml": "yamllint --schema=CORE_SCHEMA *.{yml,yaml}", "lint:yml": "yamllint --schema=CORE_SCHEMA *.{yml,yaml}",
@ -25,30 +19,24 @@
}, },
"dependencies": { "dependencies": {
"@jsse/pbfont": "^0.2.2", "@jsse/pbfont": "^0.2.2",
"@mapbox/mapbox-gl-rtl-text": "0.3.0",
"@mapbox/mbtiles": "0.12.1", "@mapbox/mbtiles": "0.12.1",
"@mapbox/polyline": "^1.2.1", "@mapbox/polyline": "^1.2.1",
"@mapbox/sphericalmercator": "1.2.0", "@mapbox/sphericalmercator": "1.2.0",
"@mapbox/vector-tile": "2.0.3", "@mapbox/vector-tile": "2.0.3",
"@maplibre/maplibre-gl-inspect": "1.7.0",
"@maplibre/maplibre-gl-native": "6.0.0", "@maplibre/maplibre-gl-native": "6.0.0",
"@maplibre/maplibre-gl-style-spec": "20.3.1", "@maplibre/maplibre-gl-style-spec": "20.3.1",
"@sindresorhus/fnv1a": "3.1.0", "@sindresorhus/fnv1a": "3.1.0",
"advanced-pool": "0.3.3", "advanced-pool": "0.3.3",
"axios": "^1.8.2", "axios": "^1.7.7",
"canvas": "3.0.1", "canvas": "3.0.1",
"chokidar": "3.6.0", "chokidar": "3.6.0",
"clone": "2.1.2", "clone": "2.1.2",
"color": "4.2.3", "color": "4.2.3",
"commander": "12.1.0", "commander": "12.1.0",
"copyfiles": "2.4.1",
"cors": "2.8.5", "cors": "2.8.5",
"express": "5.0.1", "express": "5.0.1",
"handlebars": "4.7.8", "handlebars": "4.7.8",
"http-shutdown": "1.2.2", "http-shutdown": "1.2.2",
"leaflet": "1.9.4",
"leaflet-hash": "0.2.1",
"maplibre-gl": "4.7.1",
"morgan": "1.10.0", "morgan": "1.10.0",
"pbf": "4.0.1", "pbf": "4.0.1",
"pmtiles": "3.0.7", "pmtiles": "3.0.7",

View file

@ -18,7 +18,7 @@ class ElevationInfoControl {
map.on('click', (e) => { map.on('click', (e) => {
var url = this.url; var url = this.url;
var coord = {"z": Math.floor(map.getZoom()), "x": e.lngLat["lng"].toFixed(7), "y": e.lngLat["lat"].toFixed(7)}; var coord = {"z": Math.floor(map.getZoom()), "x": e.lngLat["lng"], "y": e.lngLat["lat"]};
for(var key in coord) { for(var key in coord) {
url = url.replace(new RegExp('{'+ key +'}','g'), coord[key]); url = url.replace(new RegExp('{'+ key +'}','g'), coord[key]);
} }

View file

@ -0,0 +1,162 @@
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.Hash = function(map) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map);
}
};
L.Hash.parseHash = function(hash) {
if(hash.indexOf('#') === 0) {
hash = hash.substr(1);
}
var args = hash.split("/");
if (args.length == 3) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]);
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom
};
}
} else {
return false;
}
};
L.Hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
return "#" + [zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision)
].join("/");
},
L.Hash.prototype = {
map: null,
lastHash: null,
parseHash: L.Hash.parseHash,
formatHash: L.Hash.formatHash,
init: function(map) {
this.map = map;
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
}
};
L.hash = function(map) {
return new L.Hash(map);
};
L.Map.prototype.addHash = function() {
this._hash = L.hash(this);
};
L.Map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);

View file

@ -0,0 +1,661 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
.maplibregl-inspect_popup {
color: #333;
display: table;
}
.maplibregl-inspect_feature:not(:last-child) {
border-bottom: 1px solid #ccc;
}
.maplibregl-inspect_layer:before {
content: '#';
}
.maplibregl-inspect_layer {
display: block;
font-weight: bold;
}
.maplibregl-inspect_property {
display: table-row;
}
.maplibregl-inspect_property-value {
display: table-cell;
word-break: break-all;
}
.maplibregl-inspect_property-name {
display: table-cell;
padding-right: 10px;
word-break: break-all;
}
.maplibregl-ctrl-inspect {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23333333' preserveAspectRatio='xMidYMid meet' viewBox='-10 -10 60 60'%3E%3Cg%3E%3Cpath d='m15 21.6q0-2 1.5-3.5t3.5-1.5 3.5 1.5 1.5 3.5-1.5 3.6-3.5 1.4-3.5-1.4-1.5-3.6z m18.4 11.1l-6.4-6.5q1.4-2.1 1.4-4.6 0-3.4-2.5-5.8t-5.9-2.4-5.9 2.4-2.5 5.8 2.5 5.9 5.9 2.5q2.4 0 4.6-1.4l7.4 7.4q-0.9 0.6-2 0.6h-20q-1.3 0-2.3-0.9t-1.1-2.3l0.1-26.8q0-1.3 1-2.3t2.3-0.9h13.4l10 10v19.3z'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
}
.maplibregl-ctrl-map {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23333333' viewBox='-10 -10 60 60' preserveAspectRatio='xMidYMid meet'%3E%3Cg%3E%3Cpath d='m25 31.640000000000004v-19.766666666666673l-10-3.511666666666663v19.766666666666666z m9.140000000000008-26.640000000000004q0.8599999999999923 0 0.8599999999999923 0.8600000000000003v25.156666666666666q0 0.625-0.625 0.783333333333335l-9.375 3.1999999999999993-10-3.5133333333333354-8.906666666666668 3.4383333333333326-0.2333333333333334 0.07833333333333314q-0.8616666666666664 0-0.8616666666666664-0.8599999999999994v-25.156666666666663q0-0.625 0.6233333333333331-0.7833333333333332l9.378333333333334-3.198333333333334 10 3.5133333333333336 8.905000000000001-3.4383333333333344z'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9,9 +9,7 @@
<link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl-inspect.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl-inspect.css{{&key_query}}" />
<script src="{{public_url}}maplibre-gl.js{{&key_query}}"></script> <script src="{{public_url}}maplibre-gl.js{{&key_query}}"></script>
<script src="{{public_url}}maplibre-gl-inspect.js{{&key_query}}"></script> <script src="{{public_url}}maplibre-gl-inspect.js{{&key_query}}"></script>
{{^is_light}}
<script src="{{public_url}}elevation-control.js{{&key_query}}"></script> <script src="{{public_url}}elevation-control.js{{&key_query}}"></script>
{{/is_light}}
<style> <style>
body {background:#fff;color:#333;font-family:Arial, sans-serif;} body {background:#fff;color:#333;font-family:Arial, sans-serif;}
{{^is_terrain}} {{^is_terrain}}
@ -23,9 +21,7 @@
h1 {position:absolute;top:5px;right:0;width:240px;margin:0;line-height:20px;font-size:20px;} h1 {position:absolute;top:5px;right:0;width:240px;margin:0;line-height:20px;font-size:20px;}
#layerList {position:absolute;top:35px;right:0;bottom:0;width:240px;overflow:auto;} #layerList {position:absolute;top:35px;right:0;bottom:0;width:240px;overflow:auto;}
#layerList div div {width:15px;height:15px;display:inline-block;} #layerList div div {width:15px;height:15px;display:inline-block;}
{{^is_light}}
.maplibre-ctrl-elevation { padding-left: 5px; padding-right: 5px; } .maplibre-ctrl-elevation { padding-left: 5px; padding-right: 5px; }
{{/is_light}}
</style> </style>
{{/use_maplibre}} {{/use_maplibre}}
{{^use_maplibre}} {{^use_maplibre}}
@ -139,13 +135,11 @@
}) })
); );
{{^is_light}}
map.addControl( map.addControl(
new ElevationInfoControl({ new ElevationInfoControl({
url: "{{public_url}}data/{{id}}/elevation/{z}/{x}/{y}" url: "{{public_url}}data/{{id}}/elevation/{z}/{x}/{y}"
}) })
); );
{{/is_light}}
{{/is_terrain}} {{/is_terrain}}
{{^is_terrain}} {{^is_terrain}}

View file

@ -124,9 +124,9 @@
{{/is_vector}} {{/is_vector}}
{{^is_vector}} {{^is_vector}}
<a class="btn" href="{{public_url}}data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a> <a class="btn" href="{{public_url}}data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a>
{{#is_terrain}} {{#elevation_link}}
<a class="btn" href="{{public_url}}data/preview/{{@key}}/{{&../key_query}}{{viewer_hash}}">Preview Terrain</a> <a class="btn" href="{{public_url}}data/preview/{{@key}}/{{&../key_query}}{{viewer_hash}}">Preview Terrain</a>
{{/is_terrain}} {{/elevation_link}}
{{/is_vector}} {{/is_vector}}
</div> </div>
</div> </div>

View file

@ -8,6 +8,8 @@ import express from 'express';
import Pbf from 'pbf'; import Pbf from 'pbf';
import { VectorTile } from '@mapbox/vector-tile'; import { VectorTile } from '@mapbox/vector-tile';
import SphericalMercator from '@mapbox/sphericalmercator'; import SphericalMercator from '@mapbox/sphericalmercator';
import { Image, createCanvas } from 'canvas';
import sharp from 'sharp';
import { import {
fixTileJSONCenter, fixTileJSONCenter,
@ -19,21 +21,6 @@ import { getPMtilesInfo, openPMtiles } from './pmtiles_adapter.js';
import { gunzipP, gzipP } from './promises.js'; import { gunzipP, gzipP } from './promises.js';
import { openMbTilesWrapper } from './mbtiles_wrapper.js'; import { openMbTilesWrapper } from './mbtiles_wrapper.js';
import fs from 'node:fs';
import { fileURLToPath } from 'url';
const packageJson = JSON.parse(
fs.readFileSync(
path.dirname(fileURLToPath(import.meta.url)) + '/../package.json',
'utf8',
),
);
const isLight = packageJson.name.slice(-6) === '-light';
const serve_rendered = (
await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`)
).serve_rendered;
export const serve_data = { export const serve_data = {
/** /**
* Initializes the serve_data module. * Initializes the serve_data module.
@ -114,13 +101,12 @@ export const serve_data = {
let headers = fetchTile.headers; let headers = fetchTile.headers;
let isGzipped = data.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0; let isGzipped = data.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0;
if (isGzipped) {
data = await gunzipP(data);
isGzipped = false;
}
if (tileJSONFormat === 'pbf') { if (tileJSONFormat === 'pbf') {
if (options.dataDecoratorFunc) { if (options.dataDecoratorFunc) {
if (isGzipped) {
data = await gunzipP(data);
isGzipped = false;
}
data = options.dataDecoratorFunc( data = options.dataDecoratorFunc(
req.params.id, req.params.id,
'data', 'data',
@ -260,20 +246,79 @@ export const serve_data = {
if (fetchTile == null) return res.status(204).send(); if (fetchTile == null) return res.status(204).send();
let data = fetchTile.data; let data = fetchTile.data;
var param = { const image = new Image();
long: bbox[0].toFixed(7), await new Promise(async (resolve, reject) => {
lat: bbox[1].toFixed(7), image.onload = async () => {
encoding, const canvas = createCanvas(TILE_SIZE, TILE_SIZE);
format, const context = canvas.getContext('2d');
tile_size: TILE_SIZE, context.drawImage(image, 0, 0);
z: zoom, const long = bbox[0];
x: xy[0], const lat = bbox[1];
y: xy[1],
};
res // calculate pixel coordinate of tile,
.status(200) // see https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
.send(await serve_rendered.getTerrainElevation(data, param)); let siny = Math.sin((lat * Math.PI) / 180);
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
// about a third of a tile past the edge of the world tile.
siny = Math.min(Math.max(siny, -0.9999), 0.9999);
const xWorld = TILE_SIZE * (0.5 + long / 360);
const yWorld =
TILE_SIZE *
(0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI));
const scale = 1 << zoom;
const xTile = Math.floor((xWorld * scale) / TILE_SIZE);
const yTile = Math.floor((yWorld * scale) / TILE_SIZE);
const xPixel = Math.floor(xWorld * scale) - xTile * TILE_SIZE;
const yPixel = Math.floor(yWorld * scale) - yTile * TILE_SIZE;
if (
xPixel < 0 ||
yPixel < 0 ||
xPixel >= TILE_SIZE ||
yPixel >= TILE_SIZE
) {
return reject('Out of bounds Pixel');
}
const imgdata = context.getImageData(xPixel, yPixel, 1, 1);
const red = imgdata.data[0];
const green = imgdata.data[1];
const blue = imgdata.data[2];
let elevation;
if (encoding === 'mapbox') {
elevation = -10000 + (red * 256 * 256 + green * 256 + blue) * 0.1;
} else if (encoding === 'terrarium') {
elevation = red * 256 + green + blue / 256 - 32768;
} else {
elevation = 'invalid encoding';
}
resolve(
res.status(200).send({
z: zoom,
x: xy[0],
y: xy[1],
red,
green,
blue,
latitude: lat,
longitude: long,
elevation,
}),
);
};
image.onerror = (err) => reject(err);
if (format === 'webp') {
try {
const img = await sharp(data).toFormat('png').toBuffer();
image.src = img;
} catch (err) {
reject(err);
}
} else {
image.src = data;
}
});
} catch (err) { } catch (err) {
return res return res
.status(500) .status(500)

View file

@ -6,9 +6,4 @@ export const serve_rendered = {
init: (options, repo, programOpts) => {}, init: (options, repo, programOpts) => {},
add: (options, repo, params, id, programOpts, dataResolver) => {}, add: (options, repo, params, id, programOpts, dataResolver) => {},
remove: (repo, id) => {}, remove: (repo, id) => {},
clear: (repo) => {},
getTerrainElevation: (data, param) => {
param['elevation'] = 'not supported in light';
return param;
},
}; };

View file

@ -7,7 +7,7 @@
// This happens on ARM: // This happens on ARM:
// > terminate called after throwing an instance of 'std::runtime_error' // > terminate called after throwing an instance of 'std::runtime_error'
// > what(): Cannot read GLX extensions. // > what(): Cannot read GLX extensions.
import { Image, createCanvas } from 'canvas'; import 'canvas';
import '@maplibre/maplibre-gl-native'; import '@maplibre/maplibre-gl-native';
// //
// SECTION END // SECTION END
@ -15,6 +15,7 @@ import '@maplibre/maplibre-gl-native';
import advancedPool from 'advanced-pool'; import advancedPool from 'advanced-pool';
import path from 'path'; import path from 'path';
import url from 'url'; import url from 'url';
import util from 'util';
import sharp from 'sharp'; import sharp from 'sharp';
import clone from 'clone'; import clone from 'clone';
import Color from 'color'; import Color from 'color';
@ -1027,19 +1028,10 @@ export const serve_rendered = {
* @param {object} params Parameters object. * @param {object} params Parameters object.
* @param {string} id ID of the item. * @param {string} id ID of the item.
* @param {object} programOpts - An object containing the program options * @param {object} programOpts - An object containing the program options
* @param {object} style pre-fetched/read StyleJSON object.
* @param {Function} dataResolver Function to resolve data. * @param {Function} dataResolver Function to resolve data.
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
add: async function ( add: async function (options, repo, params, id, programOpts, dataResolver) {
options,
repo,
params,
id,
programOpts,
style,
dataResolver,
) {
const map = { const map = {
renderers: [], renderers: [],
renderersStatic: [], renderersStatic: [],
@ -1049,7 +1041,7 @@ export const serve_rendered = {
const { publicUrl, verbose } = programOpts; const { publicUrl, verbose } = programOpts;
const styleJSON = clone(style); let styleJSON;
/** /**
* Creates a pool of renderers. * Creates a pool of renderers.
* @param {number} ratio Pixel ratio * @param {number} ratio Pixel ratio
@ -1238,6 +1230,12 @@ export const serve_rendered = {
const styleFile = params.style; const styleFile = params.style;
const styleJSONPath = path.resolve(options.paths.styles, styleFile); const styleJSONPath = path.resolve(options.paths.styles, styleFile);
try {
styleJSON = JSON.parse(await fsp.readFile(styleJSONPath));
} catch (e) {
console.log('Error parsing style file');
return false;
}
if (styleJSON.sprite) { if (styleJSON.sprite) {
if (!Array.isArray(styleJSON.sprite)) { if (!Array.isArray(styleJSON.sprite)) {
@ -1460,94 +1458,4 @@ export const serve_rendered = {
} }
delete repo[id]; delete repo[id];
}, },
/**
* Removes all items from the repository.
* @param {object} repo Repository object.
* @returns {void}
*/
clear: function (repo) {
Object.keys(repo).forEach((id) => {
const item = repo[id];
if (item) {
item.map.renderers.forEach((pool) => {
pool.close();
});
item.map.renderersStatic.forEach((pool) => {
pool.close();
});
}
delete repo[id];
});
},
/**
* Get the elevation of terrain tile data by rendering it to a canvas image
* @param {object} data The background color (or empty string for transparent).
* @param {object} param Required parameters (coordinates e.g.)
* @returns {object}
*/
getTerrainElevation: async function (data, param) {
return await new Promise(async (resolve, reject) => {
const image = new Image();
image.onload = async () => {
const canvas = createCanvas(param['tile_size'], param['tile_size']);
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
// calculate pixel coordinate of tile,
// see https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
let siny = Math.sin((param['lat'] * Math.PI) / 180);
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
// about a third of a tile past the edge of the world tile.
siny = Math.min(Math.max(siny, -0.9999), 0.9999);
const xWorld = param['tile_size'] * (0.5 + param['long'] / 360);
const yWorld =
param['tile_size'] *
(0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI));
const scale = 1 << param['z'];
const xTile = Math.floor((xWorld * scale) / param['tile_size']);
const yTile = Math.floor((yWorld * scale) / param['tile_size']);
const xPixel = Math.floor(xWorld * scale) - xTile * param['tile_size'];
const yPixel = Math.floor(yWorld * scale) - yTile * param['tile_size'];
if (
xPixel < 0 ||
yPixel < 0 ||
xPixel >= param['tile_size'] ||
yPixel >= param['tile_size']
) {
return reject('Out of bounds Pixel');
}
const imgdata = context.getImageData(xPixel, yPixel, 1, 1);
const red = imgdata.data[0];
const green = imgdata.data[1];
const blue = imgdata.data[2];
let elevation;
if (param['encoding'] === 'mapbox') {
elevation = -10000 + (red * 256 * 256 + green * 256 + blue) * 0.1;
} else if (param['encoding'] === 'terrarium') {
elevation = red * 256 + green + blue / 256 - 32768;
} else {
elevation = 'invalid encoding';
}
param['elevation'] = elevation;
param['red'] = red;
param['green'] = green;
param['blue'] = blue;
resolve(param);
};
image.onerror = (err) => reject(err);
if (param['format'] === 'webp') {
try {
const img = await sharp(data).toFormat('png').toBuffer();
image.src = img;
} catch (err) {
reject(err);
}
} else {
image.src = data;
}
});
},
}; };

View file

@ -196,10 +196,9 @@ export const serve_style = {
* @param {object} params Parameters object containing style path * @param {object} params Parameters object containing style path
* @param {string} id ID of the style. * @param {string} id ID of the style.
* @param {object} programOpts - An object containing the program options * @param {object} programOpts - An object containing the program options
* @param {object} style pre-fetched/read StyleJSON object.
* @param {Function} reportTiles Function for reporting tile sources. * @param {Function} reportTiles Function for reporting tile sources.
* @param {Function} reportFont Function for reporting font usage * @param {Function} reportFont Function for reporting font usage
* @returns {boolean} true if add is successful * @returns {boolean} true if add is succesful
*/ */
add: function ( add: function (
options, options,
@ -207,14 +206,21 @@ export const serve_style = {
params, params,
id, id,
programOpts, programOpts,
style,
reportTiles, reportTiles,
reportFont, reportFont,
) { ) {
const { publicUrl } = programOpts; const { publicUrl } = programOpts;
const styleFile = path.resolve(options.paths.styles, params.style); const styleFile = path.resolve(options.paths.styles, params.style);
const styleJSON = clone(style);
let styleFileData;
try {
styleFileData = fs.readFileSync(styleFile); // TODO: could be made async if this function was
} catch (e) {
console.log(`Error reading style file "${params.style}"`);
return false;
}
const styleJSON = JSON.parse(styleFileData);
const validationErrors = validateStyleMin(styleJSON); const validationErrors = validateStyleMin(styleJSON);
if (validationErrors.length > 0) { if (validationErrors.length > 0) {
console.log(`The file "${params.style}" is not a valid style file:`); console.log(`The file "${params.style}" is not a valid style file:`);

View file

@ -24,12 +24,13 @@ import {
} from './utils.js'; } from './utils.js';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJson = JSON.parse( const packageJson = JSON.parse(
fs.readFileSync(__dirname + '/../package.json', 'utf8'), fs.readFileSync(__dirname + '/../package.json', 'utf8'),
); );
const isLight = packageJson.name.slice(-6) === '-light';
const isLight = packageJson.name.slice(-6) === '-light';
const serve_rendered = ( const serve_rendered = (
await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`) await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`)
).serve_rendered; ).serve_rendered;
@ -178,29 +179,10 @@ async function start(opts) {
* @param {object} item - The style configuration object. * @param {object} item - The style configuration object.
* @param {boolean} allowMoreData - Whether to allow adding more data sources. * @param {boolean} allowMoreData - Whether to allow adding more data sources.
* @param {boolean} reportFonts - Whether to report fonts. * @param {boolean} reportFonts - Whether to report fonts.
* @returns {Promise<void>} * @returns {void}
*/ */
async function addStyle(id, item, allowMoreData, reportFonts) { function addStyle(id, item, allowMoreData, reportFonts) {
let success = true; let success = true;
let styleJSON;
try {
if (isValidHttpUrl(item.style)) {
const res = await fetch(item.style);
if (!res.ok) {
throw new Error(`fetch error ${res.status}`);
}
styleJSON = await res.json();
} else {
const styleFile = path.resolve(options.paths.styles, item.style);
const styleFileData = await fs.promises.readFile(styleFile);
styleJSON = JSON.parse(styleFileData);
}
} catch (e) {
console.log(`Error getting style file "${item.style}"`);
return false;
}
if (item.serve_data !== false) { if (item.serve_data !== false) {
success = serve_style.add( success = serve_style.add(
options, options,
@ -208,7 +190,6 @@ async function start(opts) {
item, item,
id, id,
opts, opts,
styleJSON,
(styleSourceId, protocol) => { (styleSourceId, protocol) => {
let dataItemId; let dataItemId;
for (const id of Object.keys(data)) { for (const id of Object.keys(data)) {
@ -266,7 +247,6 @@ async function start(opts) {
item, item,
id, id,
opts, opts,
styleJSON,
function dataResolver(styleSourceId) { function dataResolver(styleSourceId) {
let fileType; let fileType;
let inputFile; let inputFile;
@ -292,7 +272,6 @@ async function start(opts) {
item.serve_rendered = false; item.serve_rendered = false;
} }
} }
return success;
} }
for (const id of Object.keys(config.styles || {})) { for (const id of Object.keys(config.styles || {})) {
@ -301,7 +280,8 @@ async function start(opts) {
console.log(`Missing "style" property for ${id}`); console.log(`Missing "style" property for ${id}`);
continue; continue;
} }
startupPromises.push(addStyle(id, item, true, true));
addStyle(id, item, true, true);
} }
startupPromises.push( startupPromises.push(
serve_font(options, serving.fonts, opts).then((sub) => { serve_font(options, serving.fonts, opts).then((sub) => {
@ -595,14 +575,11 @@ async function start(opts) {
tileJSON.encoding === 'terrarium' || tileJSON.encoding === 'terrarium' ||
tileJSON.encoding === 'mapbox' tileJSON.encoding === 'mapbox'
) { ) {
if (!isLight) { data.elevation_link = getTileUrls(
data.elevation_link = getTileUrls( req,
req, tileJSON.tiles,
tileJSON.tiles, `data/${id}/elevation`,
`data/${id}/elevation`, )[0];
)[0];
}
data.is_terrain = true;
} }
if (center) { if (center) {
const centerPx = mercator.px([center[0], center[1]], center[2]); const centerPx = mercator.px([center[0], center[1]], center[2]);
@ -721,7 +698,6 @@ async function start(opts) {
is_terrain: is_terrain, is_terrain: is_terrain,
is_terrainrgb: data.tileJSON.encoding === 'mapbox', is_terrainrgb: data.tileJSON.encoding === 'mapbox',
terrain_encoding: data.tileJSON.encoding, terrain_encoding: data.tileJSON.encoding,
is_light: isLight,
}; };
}); });
@ -764,7 +740,6 @@ async function start(opts) {
app, app,
server, server,
startupPromise, startupPromise,
serving,
}; };
} }
/** /**
@ -797,15 +772,10 @@ export async function server(opts) {
console.log(`Caught signal ${signal}, refreshing`); console.log(`Caught signal ${signal}, refreshing`);
console.log('Stopping server and reloading config'); console.log('Stopping server and reloading config');
running.server.shutdown(async () => { running.server.shutdown(() => {
const restarted = await start(opts); const restarted = start(opts);
if (!isLight) {
serve_rendered.clear(running.serving.rendered);
}
running.server = restarted.server; running.server = restarted.server;
running.app = restarted.app; running.app = restarted.app;
running.startupPromise = restarted.startupPromise;
running.serving = restarted.serving;
}); });
}); });
return running; return running;