tileserver-gl-light 4.3.4 โ 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.github/workflows/automerger.yml +1 -5
- package/.github/workflows/ci.yml +51 -0
- package/.github/workflows/codeql.yml +2 -0
- package/.github/workflows/ct.yml +19 -6
- package/.github/workflows/pipeline.yml +43 -0
- package/.github/workflows/release.yml +11 -5
- package/.hadolint.yml +3 -0
- package/.nvmrc +1 -0
- package/.prettierignore +1 -0
- package/Dockerfile +1 -1
- package/Dockerfile_test +1 -1
- package/docs/endpoints.rst +2 -0
- package/docs/installation.rst +1 -1
- package/package.json +6 -5
- package/src/serve_rendered.js +158 -88
package/.eslintignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
public
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
name: 'Auto Merge PRs'
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
4
|
+
workflow_call:
|
|
7
5
|
|
|
8
6
|
permissions:
|
|
9
7
|
pull-requests: write
|
|
@@ -12,8 +10,6 @@ permissions:
|
|
|
12
10
|
jobs:
|
|
13
11
|
automerge:
|
|
14
12
|
runs-on: ubuntu-latest
|
|
15
|
-
if: >
|
|
16
|
-
github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]'
|
|
17
13
|
steps:
|
|
18
14
|
- uses: fastify/github-action-merge-dependabot@v3
|
|
19
15
|
with:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: 'Continuous Integration'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
checks: write
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
ci:
|
|
12
|
+
runs-on: ubuntu-20.04
|
|
13
|
+
steps:
|
|
14
|
+
- name: Check out repository โจ (non-dependabot)
|
|
15
|
+
if: ${{ github.actor != 'dependabot[bot]' }}
|
|
16
|
+
uses: actions/checkout@v3
|
|
17
|
+
|
|
18
|
+
- name: Check out repository ๐ (dependabot)
|
|
19
|
+
if: ${{ github.actor == 'dependabot[bot]' }}
|
|
20
|
+
uses: actions/checkout@v3
|
|
21
|
+
with:
|
|
22
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
23
|
+
|
|
24
|
+
- name: Setup node env ๐ฆ
|
|
25
|
+
uses: actions/setup-node@v3
|
|
26
|
+
with:
|
|
27
|
+
node-version-file: 'package.json'
|
|
28
|
+
check-latest: true
|
|
29
|
+
cache: 'npm'
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies ๐
|
|
32
|
+
run: npm ci --prefer-offline --no-audit --omit=optional
|
|
33
|
+
|
|
34
|
+
- name: Run linter(s) ๐
|
|
35
|
+
uses: wearerequired/lint-action@v2
|
|
36
|
+
with:
|
|
37
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
+
continue_on_error: false
|
|
39
|
+
git_name: github-actions[bot]
|
|
40
|
+
git_email: github-actions[bot]@users.noreply.github.com
|
|
41
|
+
auto_fix: false
|
|
42
|
+
eslint: true
|
|
43
|
+
eslint_extensions: js,cjs,mjs,ts
|
|
44
|
+
prettier: true
|
|
45
|
+
prettier_extensions: js,cjs,ts,json
|
|
46
|
+
|
|
47
|
+
- name: Run hadolint ๐ณ
|
|
48
|
+
uses: hadolint/hadolint-action@v3.0.0
|
|
49
|
+
with:
|
|
50
|
+
dockerfile: Dockerfile
|
|
51
|
+
ignore: DL3008,DL3015
|
package/.github/workflows/ct.yml
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
name: 'Continuous Testing'
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- master
|
|
4
|
+
workflow_call:
|
|
10
5
|
|
|
11
6
|
permissions:
|
|
12
7
|
checks: write
|
|
@@ -55,3 +50,21 @@ jobs:
|
|
|
55
50
|
|
|
56
51
|
- name: Run tests ๐งช
|
|
57
52
|
run: xvfb-run --server-args="-screen 0 1024x768x24" npm test
|
|
53
|
+
|
|
54
|
+
- name: Set up QEMU
|
|
55
|
+
uses: docker/setup-qemu-action@v2
|
|
56
|
+
with:
|
|
57
|
+
platforms: 'arm64'
|
|
58
|
+
|
|
59
|
+
- name: Set up Docker Buildx
|
|
60
|
+
uses: docker/setup-buildx-action@v2
|
|
61
|
+
|
|
62
|
+
- name: Test Docker Build
|
|
63
|
+
uses: docker/build-push-action@v3
|
|
64
|
+
with:
|
|
65
|
+
context: .
|
|
66
|
+
push: false
|
|
67
|
+
platforms: linux/arm64,linux/amd64
|
|
68
|
+
# experimental: https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api
|
|
69
|
+
cache-from: type=gha
|
|
70
|
+
cache-to: type=gha,mode=max
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: 'The Pipeline'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- master
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}-1
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
extract-branch:
|
|
17
|
+
name: 'Fetch branch'
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
outputs:
|
|
20
|
+
current_branch: ${{ steps.get-branch.outputs.current_branch }}
|
|
21
|
+
steps:
|
|
22
|
+
- name: Extract branch name ๐
|
|
23
|
+
id: get-branch
|
|
24
|
+
run: echo "current_branch=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
|
|
25
|
+
ci:
|
|
26
|
+
name: 'CI'
|
|
27
|
+
needs:
|
|
28
|
+
- extract-branch
|
|
29
|
+
uses: maptiler/tileserver-gl/.github/workflows/ci.yml@master
|
|
30
|
+
ct:
|
|
31
|
+
name: 'CT'
|
|
32
|
+
needs:
|
|
33
|
+
- extract-branch
|
|
34
|
+
uses: maptiler/tileserver-gl/.github/workflows/ct.yml@master
|
|
35
|
+
automerger:
|
|
36
|
+
name: 'Automerge Dependabot PRs'
|
|
37
|
+
needs:
|
|
38
|
+
- ci
|
|
39
|
+
- ct
|
|
40
|
+
- extract-branch
|
|
41
|
+
if: >
|
|
42
|
+
github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]'
|
|
43
|
+
uses: maptiler/tileserver-gl/.github/workflows/automerger.yml@master
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: 'Build, Test, Release'
|
|
2
2
|
|
|
3
|
-
on:
|
|
3
|
+
on:
|
|
4
4
|
workflow_dispatch:
|
|
5
5
|
inputs:
|
|
6
6
|
docker_user:
|
|
7
|
-
description: 'Docker Username'
|
|
7
|
+
description: 'Docker Username'
|
|
8
8
|
required: true
|
|
9
9
|
docker_token:
|
|
10
|
-
description: 'Docker Token'
|
|
10
|
+
description: 'Docker Token'
|
|
11
11
|
required: true
|
|
12
12
|
npm_token:
|
|
13
13
|
description: 'NPM Token'
|
|
@@ -15,7 +15,7 @@ on:
|
|
|
15
15
|
|
|
16
16
|
jobs:
|
|
17
17
|
release:
|
|
18
|
-
name:
|
|
18
|
+
name: 'Build, Test, Publish'
|
|
19
19
|
runs-on: ubuntu-20.04
|
|
20
20
|
steps:
|
|
21
21
|
- name: Check out repository โจ
|
|
@@ -86,6 +86,9 @@ jobs:
|
|
|
86
86
|
push: true
|
|
87
87
|
tags: maptiler/tileserver-gl:latest, maptiler/tileserver-gl:v${{ env.PACKAGE_VERSION }}
|
|
88
88
|
platforms: linux/arm64,linux/amd64
|
|
89
|
+
# experimental: https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api
|
|
90
|
+
cache-from: type=gha
|
|
91
|
+
cache-to: type=gha,mode=max
|
|
89
92
|
|
|
90
93
|
- name: Create Tileserver Light Directory
|
|
91
94
|
run: node publish.js --no-publish
|
|
@@ -110,3 +113,6 @@ jobs:
|
|
|
110
113
|
push: true
|
|
111
114
|
tags: maptiler/tileserver-gl-light:latest, maptiler/tileserver-gl-light:v${{ env.PACKAGE_VERSION }}
|
|
112
115
|
platforms: linux/arm64,linux/amd64
|
|
116
|
+
# experimental: https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api
|
|
117
|
+
cache-from: type=gha
|
|
118
|
+
cache-to: type=gha,mode=max
|
package/.hadolint.yml
ADDED
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18
|
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
public
|
package/Dockerfile
CHANGED
|
@@ -13,7 +13,7 @@ RUN set -ex; \
|
|
|
13
13
|
apt-get -y --no-install-recommends install \
|
|
14
14
|
ca-certificates \
|
|
15
15
|
wget; \
|
|
16
|
-
wget -qO- https://deb.nodesource.com/
|
|
16
|
+
wget -qO- https://deb.nodesource.com/setup_18.x | bash; \
|
|
17
17
|
apt-get install -y nodejs; \
|
|
18
18
|
apt-get -y remove wget; \
|
|
19
19
|
apt-get -y --purge autoremove; \
|
package/Dockerfile_test
CHANGED
package/docs/endpoints.rst
CHANGED
|
@@ -39,6 +39,8 @@ Static images
|
|
|
39
39
|
|
|
40
40
|
* e.g. ``5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8``
|
|
41
41
|
* can be provided multiple times
|
|
42
|
+
* or pass the path as per [Maptiler Cloud API](https://docs.maptiler.com/cloud/api/static-maps/)
|
|
43
|
+
* Match pattern: ((fill|stroke|width)\:[^\|]+\|)*((enc:.+)|((-?\d+\.?\d*,-?\d+\.?\d*\|)+(-?\d+\.?\d*,-?\d+\.?\d*)))
|
|
42
44
|
|
|
43
45
|
* ``latlng`` - indicates coordinates are in ``lat,lng`` order rather than the usual ``lng,lat``
|
|
44
46
|
* ``fill`` - color to use as the fill (e.g. ``red``, ``rgba(255,255,255,0.5)``, ``#0000ff``)
|
package/docs/installation.rst
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileserver-gl-light",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "Map tile server for JSON GL styles - serving vector tiles",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": "src/main.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@mapbox/glyph-pbf-composite": "0.0.3",
|
|
21
21
|
"@mapbox/mbtiles": "0.12.1",
|
|
22
|
+
"@mapbox/polyline": "^1.1.1",
|
|
22
23
|
"@mapbox/sphericalmercator": "1.2.0",
|
|
23
24
|
"@mapbox/vector-tile": "1.3.1",
|
|
24
25
|
"@maplibre/maplibre-gl-style-spec": "17.0.2",
|
|
@@ -26,17 +27,17 @@
|
|
|
26
27
|
"chokidar": "3.5.3",
|
|
27
28
|
"clone": "2.1.2",
|
|
28
29
|
"color": "4.2.3",
|
|
29
|
-
"commander": "
|
|
30
|
+
"commander": "10.0.0",
|
|
30
31
|
"cors": "2.8.5",
|
|
31
32
|
"express": "4.18.2",
|
|
32
33
|
"handlebars": "4.7.7",
|
|
33
34
|
"http-shutdown": "1.2.2",
|
|
34
35
|
"morgan": "1.10.0",
|
|
35
36
|
"pbf": "3.2.1",
|
|
36
|
-
"proj4": "2.8.
|
|
37
|
+
"proj4": "2.8.1",
|
|
37
38
|
"request": "2.88.2",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
39
|
+
"sanitize-filename": "1.6.3",
|
|
40
|
+
"tileserver-gl-styles": "2.0.0"
|
|
40
41
|
},
|
|
41
42
|
"keywords": [
|
|
42
43
|
"maptiler",
|
package/src/serve_rendered.js
CHANGED
|
@@ -15,11 +15,14 @@ import sanitize from 'sanitize-filename';
|
|
|
15
15
|
import SphericalMercator from '@mapbox/sphericalmercator';
|
|
16
16
|
import mlgl from '@maplibre/maplibre-gl-native';
|
|
17
17
|
import MBTiles from '@mapbox/mbtiles';
|
|
18
|
+
import polyline from '@mapbox/polyline';
|
|
18
19
|
import proj4 from 'proj4';
|
|
19
20
|
import request from 'request';
|
|
20
21
|
import { getFontsPbf, getTileUrls, fixTileJSONCenter } from './utils.js';
|
|
21
22
|
|
|
22
23
|
const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+.?\\d+)';
|
|
24
|
+
const PATH_PATTERN =
|
|
25
|
+
/^((fill|stroke|width)\:[^\|]+\|)*((enc:.+)|((-?\d+\.?\d*,-?\d+\.?\d*\|)+(-?\d+\.?\d*,-?\d+\.?\d*)))/;
|
|
23
26
|
const httpTester = /^(http(s)?:)?\/\//;
|
|
24
27
|
|
|
25
28
|
const mercator = new SphericalMercator();
|
|
@@ -147,47 +150,67 @@ const parseCoordinates = (coordinatePair, query, transformer) => {
|
|
|
147
150
|
* @param {Function} transformer Optional transform function.
|
|
148
151
|
*/
|
|
149
152
|
const extractPathsFromQuery = (query, transformer) => {
|
|
153
|
+
// Initiate paths array
|
|
154
|
+
const paths = [];
|
|
150
155
|
// Return an empty list if no paths have been provided
|
|
151
|
-
if (!query.path) {
|
|
152
|
-
return
|
|
156
|
+
if ('path' in query && !query.path) {
|
|
157
|
+
return paths;
|
|
153
158
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (pair === null) {
|
|
179
|
-
continue;
|
|
159
|
+
// Parse paths provided via path query argument
|
|
160
|
+
if ('path' in query) {
|
|
161
|
+
const providedPaths = Array.isArray(query.path) ? query.path : [query.path];
|
|
162
|
+
// Iterate through paths, parse and validate them
|
|
163
|
+
for (const providedPath of providedPaths) {
|
|
164
|
+
// Logic for pushing coords to path when path includes google polyline
|
|
165
|
+
if (
|
|
166
|
+
providedPath.includes('enc:') &&
|
|
167
|
+
PATH_PATTERN.test(decodeURIComponent(providedPath))
|
|
168
|
+
) {
|
|
169
|
+
const encodedPaths = providedPath.split(',');
|
|
170
|
+
for (const path of encodedPaths) {
|
|
171
|
+
const line = path
|
|
172
|
+
.split('|')
|
|
173
|
+
.filter(
|
|
174
|
+
(x) =>
|
|
175
|
+
!x.startsWith('fill') &&
|
|
176
|
+
!x.startsWith('stroke') &&
|
|
177
|
+
!x.startsWith('width'),
|
|
178
|
+
)
|
|
179
|
+
.join('')
|
|
180
|
+
.replace('enc:', '');
|
|
181
|
+
const coords = polyline.decode(line).map(([lat, lng]) => [lng, lat]);
|
|
182
|
+
paths.push(coords);
|
|
180
183
|
}
|
|
184
|
+
} else {
|
|
185
|
+
// Iterate through paths, parse and validate them
|
|
186
|
+
const currentPath = [];
|
|
187
|
+
|
|
188
|
+
// Extract coordinate-list from path
|
|
189
|
+
const pathParts = (providedPath || '').split('|');
|
|
190
|
+
|
|
191
|
+
// Iterate through coordinate-list, parse the coordinates and validate them
|
|
192
|
+
for (const pair of pathParts) {
|
|
193
|
+
// Extract coordinates from coordinate pair
|
|
194
|
+
const pairParts = pair.split(',');
|
|
195
|
+
// Ensure we have two coordinates
|
|
196
|
+
if (pairParts.length === 2) {
|
|
197
|
+
const pair = parseCoordinates(pairParts, query, transformer);
|
|
198
|
+
|
|
199
|
+
// Ensure coordinates could be parsed and skip them if not
|
|
200
|
+
if (pair === null) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
181
203
|
|
|
182
|
-
|
|
183
|
-
|
|
204
|
+
// Add the coordinate-pair to the current path if they are valid
|
|
205
|
+
currentPath.push(pair);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Extend list of paths with current path if it contains coordinates
|
|
209
|
+
if (currentPath.length) {
|
|
210
|
+
paths.push(currentPath);
|
|
211
|
+
}
|
|
184
212
|
}
|
|
185
213
|
}
|
|
186
|
-
|
|
187
|
-
// Extend list of paths with current path if it contains coordinates
|
|
188
|
-
if (currentPath.length) {
|
|
189
|
-
paths.push(currentPath);
|
|
190
|
-
}
|
|
191
214
|
}
|
|
192
215
|
return paths;
|
|
193
216
|
};
|
|
@@ -422,65 +445,109 @@ const drawMarkers = async (ctx, markers, z) => {
|
|
|
422
445
|
* @param {number} z Map zoom level.
|
|
423
446
|
*/
|
|
424
447
|
const drawPath = (ctx, path, query, z) => {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
448
|
+
const renderPath = (splitPaths) => {
|
|
449
|
+
if (!path || path.length < 2) {
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
428
452
|
|
|
429
|
-
|
|
453
|
+
ctx.beginPath();
|
|
430
454
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
455
|
+
// Transform coordinates to pixel on canvas and draw lines between points
|
|
456
|
+
for (const pair of path) {
|
|
457
|
+
const px = precisePx(pair, z);
|
|
458
|
+
ctx.lineTo(px[0], px[1]);
|
|
459
|
+
}
|
|
436
460
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
461
|
+
// Check if first coordinate matches last coordinate
|
|
462
|
+
if (
|
|
463
|
+
path[0][0] === path[path.length - 1][0] &&
|
|
464
|
+
path[0][1] === path[path.length - 1][1]
|
|
465
|
+
) {
|
|
466
|
+
ctx.closePath();
|
|
467
|
+
}
|
|
444
468
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
469
|
+
// Optionally fill drawn shape with a rgba color from query
|
|
470
|
+
const pathHasFill =
|
|
471
|
+
splitPaths.filter((x) => x.startsWith('fill')).length > 0;
|
|
472
|
+
if (query.fill !== undefined || pathHasFill) {
|
|
473
|
+
if ('fill' in query) {
|
|
474
|
+
ctx.fillStyle = query.fill || 'rgba(255,255,255,0.4)';
|
|
475
|
+
}
|
|
476
|
+
if (pathHasFill) {
|
|
477
|
+
ctx.fillStyle = splitPaths
|
|
478
|
+
.find((x) => x.startsWith('fill:'))
|
|
479
|
+
.replace('fill:', '');
|
|
480
|
+
}
|
|
481
|
+
ctx.fill();
|
|
482
|
+
}
|
|
450
483
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
//
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
// Set
|
|
477
|
-
|
|
478
|
-
ctx.
|
|
484
|
+
// Get line width from query and fall back to 1 if not provided
|
|
485
|
+
const pathHasWidth =
|
|
486
|
+
splitPaths.filter((x) => x.startsWith('width')).length > 0;
|
|
487
|
+
if (query.width !== undefined || pathHasWidth) {
|
|
488
|
+
let lineWidth = 1;
|
|
489
|
+
// Get line width from query
|
|
490
|
+
if ('width' in query) {
|
|
491
|
+
lineWidth = Number(query.width);
|
|
492
|
+
}
|
|
493
|
+
// Get line width from path in query
|
|
494
|
+
if (pathHasWidth) {
|
|
495
|
+
lineWidth = Number(
|
|
496
|
+
splitPaths.find((x) => x.startsWith('width:')).replace('width:', ''),
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
// Get border width from query and fall back to 10% of line width
|
|
500
|
+
const borderWidth =
|
|
501
|
+
query.borderwidth !== undefined
|
|
502
|
+
? parseFloat(query.borderwidth)
|
|
503
|
+
: lineWidth * 0.1;
|
|
504
|
+
|
|
505
|
+
// Set rendering style for the start and end points of the path
|
|
506
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap
|
|
507
|
+
ctx.lineCap = query.linecap || 'butt';
|
|
508
|
+
|
|
509
|
+
// Set rendering style for overlapping segments of the path with differing directions
|
|
510
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
|
|
511
|
+
ctx.lineJoin = query.linejoin || 'miter';
|
|
512
|
+
|
|
513
|
+
// In order to simulate a border we draw the path two times with the first
|
|
514
|
+
// beeing the wider border part.
|
|
515
|
+
if (query.border !== undefined && borderWidth > 0) {
|
|
516
|
+
// We need to double the desired border width and add it to the line width
|
|
517
|
+
// in order to get the desired border on each side of the line.
|
|
518
|
+
ctx.lineWidth = lineWidth + borderWidth * 2;
|
|
519
|
+
// Set border style as rgba
|
|
520
|
+
ctx.strokeStyle = query.border;
|
|
521
|
+
ctx.stroke();
|
|
522
|
+
}
|
|
523
|
+
ctx.lineWidth = lineWidth;
|
|
479
524
|
}
|
|
480
525
|
|
|
481
|
-
|
|
482
|
-
|
|
526
|
+
const pathHasStroke =
|
|
527
|
+
splitPaths.filter((x) => x.startsWith('stroke')).length > 0;
|
|
528
|
+
if (query.stroke !== undefined || pathHasStroke) {
|
|
529
|
+
if ('stroke' in query) {
|
|
530
|
+
ctx.strokeStyle = query.stroke;
|
|
531
|
+
}
|
|
532
|
+
// Path Width gets higher priority
|
|
533
|
+
if (pathHasWidth) {
|
|
534
|
+
ctx.strokeStyle = splitPaths
|
|
535
|
+
.find((x) => x.startsWith('stroke:'))
|
|
536
|
+
.replace('stroke:', '');
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
ctx.strokeStyle = 'rgba(0,64,255,0.7)';
|
|
540
|
+
}
|
|
483
541
|
ctx.stroke();
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Check if path in query is valid
|
|
545
|
+
if (Array.isArray(query.path)) {
|
|
546
|
+
for (let i = 0; i < query.path.length; i += 1) {
|
|
547
|
+
renderPath(decodeURIComponent(query.path.at(i)).split('|'));
|
|
548
|
+
}
|
|
549
|
+
} else {
|
|
550
|
+
renderPath(decodeURIComponent(query.path).split('|'));
|
|
484
551
|
}
|
|
485
552
|
};
|
|
486
553
|
|
|
@@ -615,6 +682,7 @@ export const serve_rendered = {
|
|
|
615
682
|
) {
|
|
616
683
|
return res.status(400).send('Invalid center');
|
|
617
684
|
}
|
|
685
|
+
|
|
618
686
|
if (
|
|
619
687
|
Math.min(width, height) <= 0 ||
|
|
620
688
|
Math.max(width, height) * scale > (options.maxSize || 2048) ||
|
|
@@ -623,6 +691,7 @@ export const serve_rendered = {
|
|
|
623
691
|
) {
|
|
624
692
|
return res.status(400).send('Invalid size');
|
|
625
693
|
}
|
|
694
|
+
|
|
626
695
|
if (format === 'png' || format === 'webp') {
|
|
627
696
|
} else if (format === 'jpg' || format === 'jpeg') {
|
|
628
697
|
format = 'jpeg';
|
|
@@ -630,8 +699,9 @@ export const serve_rendered = {
|
|
|
630
699
|
return res.status(400).send('Invalid format');
|
|
631
700
|
}
|
|
632
701
|
|
|
702
|
+
const tileMargin = Math.max(options.tileMargin || 0, 0);
|
|
633
703
|
let pool;
|
|
634
|
-
if (opt_mode === 'tile') {
|
|
704
|
+
if (opt_mode === 'tile' && tileMargin === 0) {
|
|
635
705
|
pool = item.map.renderers[scale];
|
|
636
706
|
} else {
|
|
637
707
|
pool = item.map.renderers_static[scale];
|
|
@@ -646,12 +716,12 @@ export const serve_rendered = {
|
|
|
646
716
|
width: width,
|
|
647
717
|
height: height,
|
|
648
718
|
};
|
|
719
|
+
|
|
649
720
|
if (z === 0) {
|
|
650
721
|
params.width *= 2;
|
|
651
722
|
params.height *= 2;
|
|
652
723
|
}
|
|
653
724
|
|
|
654
|
-
const tileMargin = Math.max(options.tileMargin || 0, 0);
|
|
655
725
|
if (z > 2 && tileMargin > 0) {
|
|
656
726
|
params.width += tileMargin * 2;
|
|
657
727
|
params.height += tileMargin * 2;
|