tileserver-gl-light 4.8.0 → 4.10.0

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.
@@ -13,11 +13,12 @@ Styles
13
13
 
14
14
  Rendered tiles
15
15
  ==============
16
- * Rendered tiles are served at ``/styles/{id}/{z}/{x}/{y}[@2x].{format}``
16
+ * Rendered tiles are served at ``/styles/{id}[/{tileSize}]/{z}/{x}/{y}[@2x].{format}``
17
17
 
18
- * The optional ``@2x`` (or ``@3x``, ``@4x``) part can be used to render HiDPI (retina) tiles
18
+ * The optional ratio ``@2x`` (ex. ``@2x``, ``@3x``, ``@4x``) part can be used to render HiDPI (retina) tiles
19
+ * The optional tile size ``/{tileSize}`` (ex. ``/256``, ``/512``). if omitted, tileSize defaults to 256.
19
20
  * Available formats: ``png``, ``jpg`` (``jpeg``), ``webp``
20
- * TileJSON at ``/styles/{id}.json``
21
+ * TileJSON at ``/styles[/{tileSize}]/{id}.json``
21
22
 
22
23
  * The rendered tiles are not available in the ``tileserver-gl-light`` version.
23
24
 
@@ -91,13 +92,13 @@ Static images
91
92
 
92
93
  Source data
93
94
  ===========
94
- * Source data are served at ``/data/{mbtiles}/{z}/{x}/{y}.{format}``
95
+ * Source data are served at ``/data/{id}/{z}/{x}/{y}.{format}``
95
96
 
96
97
  * Format depends on the source file (usually ``png`` or ``pbf``)
97
98
 
98
99
  * ``geojson`` is also available (useful for inspecting the tiles) in case the original format is ``pbf``
99
100
 
100
- * TileJSON at ``/data/{mbtiles}.json``
101
+ * TileJSON at ``/data/{id}.json``
101
102
 
102
103
  TileJSON arrays
103
104
  ===============
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tileserver-gl-light",
3
- "version": "4.8.0",
3
+ "version": "4.10.0",
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",
@@ -22,10 +22,10 @@
22
22
  "@mapbox/polyline": "^1.2.1",
23
23
  "@mapbox/sphericalmercator": "1.2.0",
24
24
  "@mapbox/vector-tile": "1.3.1",
25
- "@maplibre/maplibre-gl-style-spec": "18.0.0",
25
+ "@maplibre/maplibre-gl-style-spec": "20.1.0",
26
26
  "@sindresorhus/fnv1a": "3.1.0",
27
27
  "advanced-pool": "0.3.3",
28
- "axios": "^1.6.5",
28
+ "axios": "^1.6.7",
29
29
  "chokidar": "3.5.3",
30
30
  "clone": "2.1.2",
31
31
  "color": "4.2.3",
@@ -124,6 +124,7 @@
124
124
 
125
125
  for (tile_url in tile_urls) {
126
126
  L.tileLayer(tile_urls[tile_url], {
127
+ tileSize: 256,
127
128
  minZoom: tile_minzoom,
128
129
  maxZoom: tile_maxzoom,
129
130
  attribution: tile_attribution
@@ -38,7 +38,7 @@
38
38
  <a href="{{public_url}}styles/{{@key}}/style.json{{&../key_query}}">GL Style</a>
39
39
  {{/if}}
40
40
  {{#if serving_rendered}}
41
- {{#if serving_data}}| {{/if}}<a href="{{public_url}}styles/{{@key}}.json{{&../key_query}}">TileJSON</a>
41
+ {{#if serving_data}}| {{/if}}<a href="{{public_url}}styles/512/{{@key}}.json{{&../key_query}}">TileJSON</a>
42
42
  {{/if}}
43
43
  {{#if serving_rendered}}
44
44
  | <a href="{{public_url}}styles/{{@key}}/wmts.xml{{&../key_query}}">WMTS</a>
@@ -77,11 +77,11 @@
77
77
  selectThreshold: 5
78
78
  }));
79
79
  } else {
80
- var map = L.map('map', { zoomControl: false });
80
+ var map = L.map('map', { minZoom: 1, zoomControl: false });
81
81
  new L.Control.Zoom({ position: 'topright' }).addTo(map);
82
82
 
83
83
  var tile_urls = [], tile_attribution, tile_minzoom, tile_maxzoom;
84
- var url = '{{public_url}}styles/{{id}}.json' + keyParam;
84
+ var url = '{{public_url}}styles/512/{{id}}.json' + keyParam;
85
85
  var req = new XMLHttpRequest();
86
86
  req.overrideMimeType("application/json");
87
87
  req.open('GET', url, true);
@@ -107,6 +107,8 @@
107
107
 
108
108
  for (tile_url in tile_urls) {
109
109
  L.tileLayer(tile_urls[tile_url], {
110
+ tileSize: 512,
111
+ zoomOffset: -1,
110
112
  minZoom: tile_minzoom,
111
113
  maxZoom: tile_maxzoom,
112
114
  attribution: tile_attribution
@@ -11,7 +11,7 @@
11
11
  <ows:Operation name="GetCapabilities">
12
12
  <ows:DCP>
13
13
  <ows:HTTP>
14
- <ows:Get xlink:href="{{baseUrl}}wmts/{{id}}/">
14
+ <ows:Get xlink:href="{{baseUrl}}styles/{{id}}/wmts.xml">
15
15
  <ows:Constraint name="GetEncoding">
16
16
  <ows:AllowedValues>
17
17
  <ows:Value>RESTful</ows:Value>
@@ -24,7 +24,7 @@
24
24
  <ows:Operation name="GetTile">
25
25
  <ows:DCP>
26
26
  <ows:HTTP>
27
- <ows:Get xlink:href="{{baseUrl}}styles/">
27
+ <ows:Get xlink:href="{{baseUrl}}styles/{{id}}/wmts.xml">
28
28
  <ows:Constraint name="GetEncoding">
29
29
  <ows:AllowedValues>
30
30
  <ows:Value>RESTful</ows:Value>
@@ -36,9 +36,9 @@
36
36
  </ows:Operation>
37
37
  </ows:OperationsMetadata>
38
38
  <Contents>
39
- <Layer>
40
- <ows:Title>{{name}}</ows:Title>
41
- <ows:Identifier>{{id}}</ows:Identifier>
39
+ <Layer>
40
+ <ows:Title>{{name}}-256</ows:Title>
41
+ <ows:Identifier>{{id}}-256</ows:Identifier>
42
42
  <ows:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84">
43
43
  <ows:LowerCorner>-180 -85.051128779807</ows:LowerCorner>
44
44
  <ows:UpperCorner>180 85.051128779807</ows:UpperCorner>
@@ -48,13 +48,30 @@
48
48
  </Style>
49
49
  <Format>image/png</Format>
50
50
  <TileMatrixSetLink>
51
- <TileMatrixSet>GoogleMapsCompatible</TileMatrixSet>
51
+ <TileMatrixSet>GoogleMapsCompatible_256</TileMatrixSet>
52
52
  </TileMatrixSetLink>
53
- <ResourceURL format="image/png" resourceType="tile" template="{{baseUrl}}styles/{{id}}/{TileMatrix}/{TileCol}/{TileRow}.png{{key_query}}"/>
54
- </Layer><TileMatrixSet>
55
- <ows:Title>GoogleMapsCompatible</ows:Title>
56
- <ows:Abstract>GoogleMapsCompatible EPSG:3857</ows:Abstract>
57
- <ows:Identifier>GoogleMapsCompatible</ows:Identifier>
53
+ <ResourceURL format="image/png" resourceType="tile" template="{{baseUrl}}styles/{{id}}/256/{TileMatrix}/{TileCol}/{TileRow}.png{{key_query}}"/>
54
+ </Layer>
55
+ <Layer>
56
+ <ows:Title>{{name}}-512</ows:Title>
57
+ <ows:Identifier>{{id}}-512</ows:Identifier>
58
+ <ows:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84">
59
+ <ows:LowerCorner>-180 -85.051128779807</ows:LowerCorner>
60
+ <ows:UpperCorner>180 85.051128779807</ows:UpperCorner>
61
+ </ows:WGS84BoundingBox>
62
+ <Style isDefault="true">
63
+ <ows:Identifier>default</ows:Identifier>
64
+ </Style>
65
+ <Format>image/png</Format>
66
+ <TileMatrixSetLink>
67
+ <TileMatrixSet>GoogleMapsCompatible_512</TileMatrixSet>
68
+ </TileMatrixSetLink>
69
+ <ResourceURL format="image/png" resourceType="tile" template="{{baseUrl}}styles/{{id}}/512/{TileMatrix}/{TileCol}/{TileRow}.png{{key_query}}"/>
70
+ </Layer>
71
+ <TileMatrixSet>
72
+ <ows:Title>GoogleMapsCompatible_256</ows:Title>
73
+ <ows:Abstract>GoogleMapsCompatible_256 EPSG:3857</ows:Abstract>
74
+ <ows:Identifier>GoogleMapsCompatible_256</ows:Identifier>
58
75
  <ows:SupportedCRS>urn:ogc:def:crs:EPSG::3857</ows:SupportedCRS>
59
76
  <TileMatrix>
60
77
  <ows:Identifier>0</ows:Identifier>
@@ -226,10 +243,189 @@
226
243
  <TileHeight>256</TileHeight>
227
244
  <MatrixWidth>262144</MatrixWidth>
228
245
  <MatrixHeight>262144</MatrixHeight>
229
- </TileMatrix></TileMatrixSet><TileMatrixSet>
230
- <ows:Title>WGS84</ows:Title>
231
- <ows:Abstract>WGS84 EPSG:4326</ows:Abstract>
232
- <ows:Identifier>WGS84</ows:Identifier>
246
+ </TileMatrix>
247
+ </TileMatrixSet>
248
+ <TileMatrixSet>
249
+ <ows:Title>GoogleMapsCompatible_512</ows:Title>
250
+ <ows:Abstract>GoogleMapsCompatible_512 EPSG:3857</ows:Abstract>
251
+ <ows:Identifier>GoogleMapsCompatible_512</ows:Identifier>
252
+ <ows:SupportedCRS>urn:ogc:def:crs:EPSG::3857</ows:SupportedCRS>
253
+ <TileMatrix>
254
+ <ows:Identifier>0</ows:Identifier>
255
+ <ScaleDenominator>279541132.0143589</ScaleDenominator>
256
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
257
+ <TileWidth>512</TileWidth>
258
+ <TileHeight>512</TileHeight>
259
+ <MatrixWidth>1</MatrixWidth>
260
+ <MatrixHeight>1</MatrixHeight>
261
+ </TileMatrix>
262
+ <TileMatrix>
263
+ <ows:Identifier>1</ows:Identifier>
264
+ <ScaleDenominator>139770566.0071794</ScaleDenominator>
265
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
266
+ <TileWidth>512</TileWidth>
267
+ <TileHeight>512</TileHeight>
268
+ <MatrixWidth>2</MatrixWidth>
269
+ <MatrixHeight>2</MatrixHeight>
270
+ </TileMatrix>
271
+ <TileMatrix>
272
+ <ows:Identifier>2</ows:Identifier>
273
+ <ScaleDenominator>69885283.00358972</ScaleDenominator>
274
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
275
+ <TileWidth>512</TileWidth>
276
+ <TileHeight>512</TileHeight>
277
+ <MatrixWidth>4</MatrixWidth>
278
+ <MatrixHeight>4</MatrixHeight>
279
+ </TileMatrix>
280
+ <TileMatrix>
281
+ <ows:Identifier>3</ows:Identifier>
282
+ <ScaleDenominator>34942641.501795</ScaleDenominator>
283
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
284
+ <TileWidth>512</TileWidth>
285
+ <TileHeight>512</TileHeight>
286
+ <MatrixWidth>8</MatrixWidth>
287
+ <MatrixHeight>8</MatrixHeight>
288
+ </TileMatrix>
289
+ <TileMatrix>
290
+ <ows:Identifier>4</ows:Identifier>
291
+ <ScaleDenominator>17471320.750897</ScaleDenominator>
292
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
293
+ <TileWidth>512</TileWidth>
294
+ <TileHeight>512</TileHeight>
295
+ <MatrixWidth>16</MatrixWidth>
296
+ <MatrixHeight>16</MatrixHeight>
297
+ </TileMatrix>
298
+ <TileMatrix>
299
+ <ows:Identifier>5</ows:Identifier>
300
+ <ScaleDenominator>8735660.3754487</ScaleDenominator>
301
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
302
+ <TileWidth>512</TileWidth>
303
+ <TileHeight>512</TileHeight>
304
+ <MatrixWidth>32</MatrixWidth>
305
+ <MatrixHeight>32</MatrixHeight>
306
+ </TileMatrix>
307
+ <TileMatrix>
308
+ <ows:Identifier>6</ows:Identifier>
309
+ <ScaleDenominator>4367830.1877244</ScaleDenominator>
310
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
311
+ <TileWidth>512</TileWidth>
312
+ <TileHeight>512</TileHeight>
313
+ <MatrixWidth>64</MatrixWidth>
314
+ <MatrixHeight>64</MatrixHeight>
315
+ </TileMatrix>
316
+ <TileMatrix>
317
+ <ows:Identifier>7</ows:Identifier>
318
+ <ScaleDenominator>2183915.0938622</ScaleDenominator>
319
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
320
+ <TileWidth>512</TileWidth>
321
+ <TileHeight>512</TileHeight>
322
+ <MatrixWidth>128</MatrixWidth>
323
+ <MatrixHeight>128</MatrixHeight>
324
+ </TileMatrix>
325
+ <TileMatrix>
326
+ <ows:Identifier>8</ows:Identifier>
327
+ <ScaleDenominator>1091957.5469311</ScaleDenominator>
328
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
329
+ <TileWidth>512</TileWidth>
330
+ <TileHeight>512</TileHeight>
331
+ <MatrixWidth>256</MatrixWidth>
332
+ <MatrixHeight>256</MatrixHeight>
333
+ </TileMatrix>
334
+ <TileMatrix>
335
+ <ows:Identifier>9</ows:Identifier>
336
+ <ScaleDenominator>545978.77346554</ScaleDenominator>
337
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
338
+ <TileWidth>512</TileWidth>
339
+ <TileHeight>512</TileHeight>
340
+ <MatrixWidth>512</MatrixWidth>
341
+ <MatrixHeight>512</MatrixHeight>
342
+ </TileMatrix>
343
+ <TileMatrix>
344
+ <ows:Identifier>10</ows:Identifier>
345
+ <ScaleDenominator>272989.38673277</ScaleDenominator>
346
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
347
+ <TileWidth>512</TileWidth>
348
+ <TileHeight>512</TileHeight>
349
+ <MatrixWidth>1024</MatrixWidth>
350
+ <MatrixHeight>1024</MatrixHeight>
351
+ </TileMatrix>
352
+ <TileMatrix>
353
+ <ows:Identifier>11</ows:Identifier>
354
+ <ScaleDenominator>136494.69336639</ScaleDenominator>
355
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
356
+ <TileWidth>512</TileWidth>
357
+ <TileHeight>512</TileHeight>
358
+ <MatrixWidth>2048</MatrixWidth>
359
+ <MatrixHeight>2048</MatrixHeight>
360
+ </TileMatrix>
361
+ <TileMatrix>
362
+ <ows:Identifier>12</ows:Identifier>
363
+ <ScaleDenominator>68247.346683193</ScaleDenominator>
364
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
365
+ <TileWidth>512</TileWidth>
366
+ <TileHeight>512</TileHeight>
367
+ <MatrixWidth>4096</MatrixWidth>
368
+ <MatrixHeight>4096</MatrixHeight>
369
+ </TileMatrix>
370
+ <TileMatrix>
371
+ <ows:Identifier>13</ows:Identifier>
372
+ <ScaleDenominator>34123.673341597</ScaleDenominator>
373
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
374
+ <TileWidth>512</TileWidth>
375
+ <TileHeight>512</TileHeight>
376
+ <MatrixWidth>8192</MatrixWidth>
377
+ <MatrixHeight>8192</MatrixHeight>
378
+ </TileMatrix>
379
+ <TileMatrix>
380
+ <ows:Identifier>14</ows:Identifier>
381
+ <ScaleDenominator>17061.836670798</ScaleDenominator>
382
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
383
+ <TileWidth>512</TileWidth>
384
+ <TileHeight>512</TileHeight>
385
+ <MatrixWidth>16384</MatrixWidth>
386
+ <MatrixHeight>16384</MatrixHeight>
387
+ </TileMatrix>
388
+ <TileMatrix>
389
+ <ows:Identifier>15</ows:Identifier>
390
+ <ScaleDenominator>8530.9183353991</ScaleDenominator>
391
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
392
+ <TileWidth>512</TileWidth>
393
+ <TileHeight>512</TileHeight>
394
+ <MatrixWidth>32768</MatrixWidth>
395
+ <MatrixHeight>32768</MatrixHeight>
396
+ </TileMatrix>
397
+ <TileMatrix>
398
+ <ows:Identifier>16</ows:Identifier>
399
+ <ScaleDenominator>4265.4591676996</ScaleDenominator>
400
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
401
+ <TileWidth>512</TileWidth>
402
+ <TileHeight>512</TileHeight>
403
+ <MatrixWidth>65536</MatrixWidth>
404
+ <MatrixHeight>65536</MatrixHeight>
405
+ </TileMatrix>
406
+ <TileMatrix>
407
+ <ows:Identifier>17</ows:Identifier>
408
+ <ScaleDenominator>2132.7295838498</ScaleDenominator>
409
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
410
+ <TileWidth>512</TileWidth>
411
+ <TileHeight>512</TileHeight>
412
+ <MatrixWidth>131072</MatrixWidth>
413
+ <MatrixHeight>131072</MatrixHeight>
414
+ </TileMatrix>
415
+ <TileMatrix>
416
+ <ows:Identifier>18</ows:Identifier>
417
+ <ScaleDenominator>1066.364791924892</ScaleDenominator>
418
+ <TopLeftCorner>-20037508.34 20037508.34</TopLeftCorner>
419
+ <TileWidth>512</TileWidth>
420
+ <TileHeight>512</TileHeight>
421
+ <MatrixWidth>262144</MatrixWidth>
422
+ <MatrixHeight>262144</MatrixHeight>
423
+ </TileMatrix>
424
+ </TileMatrixSet>
425
+ <TileMatrixSet>
426
+ <ows:Title>WGS84_256</ows:Title>
427
+ <ows:Abstract>WGS84_256 EPSG:4326</ows:Abstract>
428
+ <ows:Identifier>WGS84_256</ows:Identifier>
233
429
  <ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
234
430
  <TileMatrix>
235
431
  <ows:Identifier>0</ows:Identifier>
@@ -401,7 +597,185 @@
401
597
  <TileHeight>256</TileHeight>
402
598
  <MatrixWidth>524288</MatrixWidth>
403
599
  <MatrixHeight>262144</MatrixHeight>
404
- </TileMatrix></TileMatrixSet>
600
+ </TileMatrix>
601
+ </TileMatrixSet>
602
+ <TileMatrixSet>
603
+ <ows:Title>WGS84_512</ows:Title>
604
+ <ows:Abstract>WGS84_512 EPSG:4326</ows:Abstract>
605
+ <ows:Identifier>WGS84_512</ows:Identifier>
606
+ <ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
607
+ <TileMatrix>
608
+ <ows:Identifier>0</ows:Identifier>
609
+ <ScaleDenominator>139770566.00718</ScaleDenominator>
610
+ <TopLeftCorner>90 -180</TopLeftCorner>
611
+ <TileWidth>512</TileWidth>
612
+ <TileHeight>512</TileHeight>
613
+ <MatrixWidth>2</MatrixWidth>
614
+ <MatrixHeight>1</MatrixHeight>
615
+ </TileMatrix>
616
+ <TileMatrix>
617
+ <ows:Identifier>1</ows:Identifier>
618
+ <ScaleDenominator>69885283.00359</ScaleDenominator>
619
+ <TopLeftCorner>90 -180</TopLeftCorner>
620
+ <TileWidth>512</TileWidth>
621
+ <TileHeight>512</TileHeight>
622
+ <MatrixWidth>4</MatrixWidth>
623
+ <MatrixHeight>2</MatrixHeight>
624
+ </TileMatrix>
625
+ <TileMatrix>
626
+ <ows:Identifier>2</ows:Identifier>
627
+ <ScaleDenominator>34942641.501795</ScaleDenominator>
628
+ <TopLeftCorner>90 -180</TopLeftCorner>
629
+ <TileWidth>512</TileWidth>
630
+ <TileHeight>512</TileHeight>
631
+ <MatrixWidth>8</MatrixWidth>
632
+ <MatrixHeight>4</MatrixHeight>
633
+ </TileMatrix>
634
+ <TileMatrix>
635
+ <ows:Identifier>3</ows:Identifier>
636
+ <ScaleDenominator>17471320.750897</ScaleDenominator>
637
+ <TopLeftCorner>90 -180</TopLeftCorner>
638
+ <TileWidth>512</TileWidth>
639
+ <TileHeight>512</TileHeight>
640
+ <MatrixWidth>16</MatrixWidth>
641
+ <MatrixHeight>8</MatrixHeight>
642
+ </TileMatrix>
643
+ <TileMatrix>
644
+ <ows:Identifier>4</ows:Identifier>
645
+ <ScaleDenominator>8735660.3754487</ScaleDenominator>
646
+ <TopLeftCorner>90 -180</TopLeftCorner>
647
+ <TileWidth>512</TileWidth>
648
+ <TileHeight>512</TileHeight>
649
+ <MatrixWidth>32</MatrixWidth>
650
+ <MatrixHeight>16</MatrixHeight>
651
+ </TileMatrix>
652
+ <TileMatrix>
653
+ <ows:Identifier>5</ows:Identifier>
654
+ <ScaleDenominator>4367830.1877244</ScaleDenominator>
655
+ <TopLeftCorner>90 -180</TopLeftCorner>
656
+ <TileWidth>512</TileWidth>
657
+ <TileHeight>512</TileHeight>
658
+ <MatrixWidth>64</MatrixWidth>
659
+ <MatrixHeight>32</MatrixHeight>
660
+ </TileMatrix>
661
+ <TileMatrix>
662
+ <ows:Identifier>6</ows:Identifier>
663
+ <ScaleDenominator>2183915.0938622</ScaleDenominator>
664
+ <TopLeftCorner>90 -180</TopLeftCorner>
665
+ <TileWidth>512</TileWidth>
666
+ <TileHeight>512</TileHeight>
667
+ <MatrixWidth>128</MatrixWidth>
668
+ <MatrixHeight>64</MatrixHeight>
669
+ </TileMatrix>
670
+ <TileMatrix>
671
+ <ows:Identifier>7</ows:Identifier>
672
+ <ScaleDenominator>1091957.5469311</ScaleDenominator>
673
+ <TopLeftCorner>90 -180</TopLeftCorner>
674
+ <TileWidth>512</TileWidth>
675
+ <TileHeight>512</TileHeight>
676
+ <MatrixWidth>256</MatrixWidth>
677
+ <MatrixHeight>128</MatrixHeight>
678
+ </TileMatrix>
679
+ <TileMatrix>
680
+ <ows:Identifier>8</ows:Identifier>
681
+ <ScaleDenominator>545978.77346554</ScaleDenominator>
682
+ <TopLeftCorner>90 -180</TopLeftCorner>
683
+ <TileWidth>512</TileWidth>
684
+ <TileHeight>512</TileHeight>
685
+ <MatrixWidth>512</MatrixWidth>
686
+ <MatrixHeight>256</MatrixHeight>
687
+ </TileMatrix>
688
+ <TileMatrix>
689
+ <ows:Identifier>9</ows:Identifier>
690
+ <ScaleDenominator>272989.38673277</ScaleDenominator>
691
+ <TopLeftCorner>90 -180</TopLeftCorner>
692
+ <TileWidth>512</TileWidth>
693
+ <TileHeight>512</TileHeight>
694
+ <MatrixWidth>1024</MatrixWidth>
695
+ <MatrixHeight>512</MatrixHeight>
696
+ </TileMatrix>
697
+ <TileMatrix>
698
+ <ows:Identifier>10</ows:Identifier>
699
+ <ScaleDenominator>136494.69336639</ScaleDenominator>
700
+ <TopLeftCorner>90 -180</TopLeftCorner>
701
+ <TileWidth>512</TileWidth>
702
+ <TileHeight>512</TileHeight>
703
+ <MatrixWidth>2048</MatrixWidth>
704
+ <MatrixHeight>1024</MatrixHeight>
705
+ </TileMatrix>
706
+ <TileMatrix>
707
+ <ows:Identifier>11</ows:Identifier>
708
+ <ScaleDenominator>68247.346683193</ScaleDenominator>
709
+ <TopLeftCorner>90 -180</TopLeftCorner>
710
+ <TileWidth>512</TileWidth>
711
+ <TileHeight>512</TileHeight>
712
+ <MatrixWidth>4096</MatrixWidth>
713
+ <MatrixHeight>2048</MatrixHeight>
714
+ </TileMatrix>
715
+ <TileMatrix>
716
+ <ows:Identifier>12</ows:Identifier>
717
+ <ScaleDenominator>34123.673341597</ScaleDenominator>
718
+ <TopLeftCorner>90 -180</TopLeftCorner>
719
+ <TileWidth>512</TileWidth>
720
+ <TileHeight>512</TileHeight>
721
+ <MatrixWidth>8192</MatrixWidth>
722
+ <MatrixHeight>4096</MatrixHeight>
723
+ </TileMatrix>
724
+ <TileMatrix>
725
+ <ows:Identifier>13</ows:Identifier>
726
+ <ScaleDenominator>17061.836670798</ScaleDenominator>
727
+ <TopLeftCorner>90 -180</TopLeftCorner>
728
+ <TileWidth>512</TileWidth>
729
+ <TileHeight>512</TileHeight>
730
+ <MatrixWidth>16384</MatrixWidth>
731
+ <MatrixHeight>8192</MatrixHeight>
732
+ </TileMatrix>
733
+ <TileMatrix>
734
+ <ows:Identifier>14</ows:Identifier>
735
+ <ScaleDenominator>8530.9183353991</ScaleDenominator>
736
+ <TopLeftCorner>90 -180</TopLeftCorner>
737
+ <TileWidth>512</TileWidth>
738
+ <TileHeight>512</TileHeight>
739
+ <MatrixWidth>32768</MatrixWidth>
740
+ <MatrixHeight>16384</MatrixHeight>
741
+ </TileMatrix>
742
+ <TileMatrix>
743
+ <ows:Identifier>15</ows:Identifier>
744
+ <ScaleDenominator>4265.4591676996</ScaleDenominator>
745
+ <TopLeftCorner>90 -180</TopLeftCorner>
746
+ <TileWidth>512</TileWidth>
747
+ <TileHeight>512</TileHeight>
748
+ <MatrixWidth>65536</MatrixWidth>
749
+ <MatrixHeight>32768</MatrixHeight>
750
+ </TileMatrix>
751
+ <TileMatrix>
752
+ <ows:Identifier>16</ows:Identifier>
753
+ <ScaleDenominator>2132.7295838498</ScaleDenominator>
754
+ <TopLeftCorner>90 -180</TopLeftCorner>
755
+ <TileWidth>512</TileWidth>
756
+ <TileHeight>512</TileHeight>
757
+ <MatrixWidth>131072</MatrixWidth>
758
+ <MatrixHeight>65536</MatrixHeight>
759
+ </TileMatrix>
760
+ <TileMatrix>
761
+ <ows:Identifier>17</ows:Identifier>
762
+ <ScaleDenominator>1066.3647919249</ScaleDenominator>
763
+ <TopLeftCorner>90 -180</TopLeftCorner>
764
+ <TileWidth>512</TileWidth>
765
+ <TileHeight>512</TileHeight>
766
+ <MatrixWidth>262144</MatrixWidth>
767
+ <MatrixHeight>131072</MatrixHeight>
768
+ </TileMatrix>
769
+ <TileMatrix>
770
+ <ows:Identifier>18</ows:Identifier>
771
+ <ScaleDenominator>533.182</ScaleDenominator>
772
+ <TopLeftCorner>90 -180</TopLeftCorner>
773
+ <TileWidth>512</TileWidth>
774
+ <TileHeight>512</TileHeight>
775
+ <MatrixWidth>524288</MatrixWidth>
776
+ <MatrixHeight>262144</MatrixHeight>
777
+ </TileMatrix>
778
+ </TileMatrixSet>
405
779
  </Contents>
406
- <ServiceMetadataURL xlink:href="{{baseUrl}}wmts/{{id}}/"/>
780
+ <ServiceMetadataURL xlink:href="{{baseUrl}}styles/{{id}}/wmts.xml"/>
407
781
  </Capabilities>
package/src/serve_data.js CHANGED
@@ -173,11 +173,13 @@ export const serve_data = {
173
173
  if (!item) {
174
174
  return res.sendStatus(404);
175
175
  }
176
+ const tileSize = undefined;
176
177
  const info = clone(item.tileJSON);
177
178
  info.tiles = getTileUrls(
178
179
  req,
179
180
  info.tiles,
180
181
  `data/${req.params.id}`,
182
+ tileSize,
181
183
  info.format,
182
184
  item.publicUrl,
183
185
  {
@@ -413,7 +413,14 @@ const respondImage = (
413
413
  pool = item.map.renderersStatic[scale];
414
414
  }
415
415
  pool.acquire((err, renderer) => {
416
- const mlglZ = Math.max(0, z - 1);
416
+ // For 512px tiles, use the actual maplibre-native zoom. For 256px tiles, use zoom - 1
417
+ let mlglZ;
418
+ if (width === 512) {
419
+ mlglZ = Math.max(0, z);
420
+ } else {
421
+ mlglZ = Math.max(0, z - 1);
422
+ }
423
+
417
424
  const params = {
418
425
  zoom: mlglZ,
419
426
  center: [lon, lat],
@@ -423,12 +430,14 @@ const respondImage = (
423
430
  height,
424
431
  };
425
432
 
426
- if (z === 0) {
433
+ // HACK(Part 1) 256px tiles are a zoom level lower than maplibre-native default tiles. this hack allows tileserver-gl to support zoom 0 256px tiles, which would actually be zoom -1 in maplibre-native. Since zoom -1 isn't supported, a double sized zoom 0 tile is requested and resized in Part 2.
434
+ if (z === 0 && width === 256) {
427
435
  params.width *= 2;
428
436
  params.height *= 2;
429
437
  }
438
+ // END HACK(Part 1)
430
439
 
431
- if (z > 2 && tileMargin > 0) {
440
+ if (z > 0 && tileMargin > 0) {
432
441
  params.width += tileMargin * 2;
433
442
  params.height += tileMargin * 2;
434
443
  }
@@ -449,9 +458,9 @@ const respondImage = (
449
458
  },
450
459
  });
451
460
 
452
- if (z > 2 && tileMargin > 0) {
453
- const [_, y] = mercator.px(params.center, z);
454
- let yoffset = Math.max(
461
+ if (z > 0 && tileMargin > 0) {
462
+ const y = mercator.px(params.center, z)[1];
463
+ const yoffset = Math.max(
455
464
  Math.min(0, y - 128 - tileMargin),
456
465
  y + 128 + tileMargin - Math.pow(2, z + 8),
457
466
  );
@@ -463,10 +472,11 @@ const respondImage = (
463
472
  });
464
473
  }
465
474
 
466
- if (z === 0) {
467
- // HACK: when serving zoom 0, resize the 0 tile from 512 to 256
475
+ // HACK(Part 2) 256px tiles are a zoom level lower than maplibre-native default tiles. this hack allows tileserver-gl to support zoom 0 256px tiles, which would actually be zoom -1 in maplibre-native. Since zoom -1 isn't supported, a double sized zoom 0 tile is requested and resized here.
476
+ if (z === 0 && width === 256) {
468
477
  image.resize(width * scale, height * scale);
469
478
  }
479
+ // END HACK(Part 2)
470
480
 
471
481
  const composites = [];
472
482
  if (overlay) {
@@ -532,7 +542,7 @@ export const serve_rendered = {
532
542
  const app = express().disable('x-powered-by');
533
543
 
534
544
  app.get(
535
- `/:id/:z(\\d+)/:x(\\d+)/:y(\\d+):scale(${scalePattern})?.:format([\\w]+)`,
545
+ `/:id/(:tileSize(256|512)/)?:z(\\d+)/:x(\\d+)/:y(\\d+):scale(${scalePattern})?.:format([\\w]+)`,
536
546
  (req, res, next) => {
537
547
  const item = repo[req.params.id];
538
548
  if (!item) {
@@ -552,6 +562,8 @@ export const serve_rendered = {
552
562
  const y = req.params.y | 0;
553
563
  const scale = getScale(req.params.scale);
554
564
  const format = req.params.format;
565
+ const tileSize = parseInt(req.params.tileSize, 10) || 256;
566
+
555
567
  if (
556
568
  z < 0 ||
557
569
  x < 0 ||
@@ -562,7 +574,7 @@ export const serve_rendered = {
562
574
  ) {
563
575
  return res.status(404).send('Out of bounds');
564
576
  }
565
- const tileSize = 256;
577
+
566
578
  const tileCenter = mercator.ll(
567
579
  [
568
580
  ((x + 0.5) / (1 << z)) * (256 << z),
@@ -821,16 +833,18 @@ export const serve_rendered = {
821
833
  );
822
834
  }
823
835
 
824
- app.get('/:id.json', (req, res, next) => {
836
+ app.get('/(:tileSize(256|512)/)?:id.json', (req, res, next) => {
825
837
  const item = repo[req.params.id];
826
838
  if (!item) {
827
839
  return res.sendStatus(404);
828
840
  }
841
+ const tileSize = parseInt(req.params.tileSize, 10) || undefined;
829
842
  const info = clone(item.tileJSON);
830
843
  info.tiles = getTileUrls(
831
844
  req,
832
845
  info.tiles,
833
846
  `styles/${req.params.id}`,
847
+ tileSize,
834
848
  info.format,
835
849
  item.publicUrl,
836
850
  );
@@ -5,7 +5,7 @@ import fs from 'node:fs';
5
5
 
6
6
  import clone from 'clone';
7
7
  import express from 'express';
8
- import { validate } from '@maplibre/maplibre-gl-style-spec';
8
+ import { validateStyleMin } from '@maplibre/maplibre-gl-style-spec';
9
9
 
10
10
  import { getPublicUrl } from './utils.js';
11
11
 
@@ -86,7 +86,8 @@ export const serve_style = {
86
86
  return false;
87
87
  }
88
88
 
89
- const validationErrors = validate(styleFileData);
89
+ const styleJSON = JSON.parse(styleFileData);
90
+ const validationErrors = validateStyleMin(styleJSON);
90
91
  if (validationErrors.length > 0) {
91
92
  console.log(`The file "${params.style}" is not a valid style file:`);
92
93
  for (const err of validationErrors) {
@@ -94,7 +95,6 @@ export const serve_style = {
94
95
  }
95
96
  return false;
96
97
  }
97
- const styleJSON = JSON.parse(styleFileData);
98
98
 
99
99
  for (const name of Object.keys(styleJSON.sources)) {
100
100
  const source = styleJSON.sources[name];
package/src/server.js CHANGED
@@ -356,6 +356,7 @@ function start(opts) {
356
356
 
357
357
  const addTileJSONs = (arr, req, type) => {
358
358
  for (const id of Object.keys(serving[type])) {
359
+ const tileSize = 256;
359
360
  const info = clone(serving[type][id].tileJSON);
360
361
  let path = '';
361
362
  if (type === 'rendered') {
@@ -367,6 +368,7 @@ function start(opts) {
367
368
  req,
368
369
  info.tiles,
369
370
  path,
371
+ tileSize,
370
372
  info.format,
371
373
  opts.publicUrl,
372
374
  {
@@ -454,20 +456,19 @@ function start(opts) {
454
456
  if (style.serving_rendered) {
455
457
  const { center } = style.serving_rendered.tileJSON;
456
458
  if (center) {
457
- style.viewer_hash = `#${center[2]}/${center[1].toFixed(
458
- 5,
459
- )}/${center[0].toFixed(5)}`;
459
+ style.viewer_hash = `#${center[2]}/${center[1].toFixed(5)}/${center[0].toFixed(5)}`;
460
460
 
461
461
  const centerPx = mercator.px([center[0], center[1]], center[2]);
462
- style.thumbnail = `${center[2]}/${Math.floor(
463
- centerPx[0] / 256,
464
- )}/${Math.floor(centerPx[1] / 256)}.png`;
462
+ // Set thumbnail default size to be 256px x 256px
463
+ style.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.png`;
465
464
  }
466
465
 
466
+ const tileSize = 512;
467
467
  style.xyz_link = getTileUrls(
468
468
  req,
469
469
  style.serving_rendered.tileJSON.tiles,
470
470
  `styles/${id}`,
471
+ tileSize,
471
472
  style.serving_rendered.tileJSON.format,
472
473
  opts.publicUrl,
473
474
  )[0];
@@ -493,22 +494,23 @@ function start(opts) {
493
494
  if (!data.is_vector) {
494
495
  if (center) {
495
496
  const centerPx = mercator.px([center[0], center[1]], center[2]);
496
- data.thumbnail = `${center[2]}/${Math.floor(
497
- centerPx[0] / 256,
498
- )}/${Math.floor(centerPx[1] / 256)}.${tileJSON.format}`;
497
+ data.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.${tileJSON.format}`;
499
498
  }
500
-
501
- data.xyz_link = getTileUrls(
502
- req,
503
- tileJSON.tiles,
504
- `data/${id}`,
505
- tileJSON.format,
506
- opts.publicUrl,
507
- {
508
- pbf: options.pbfAlias,
509
- },
510
- )[0];
511
499
  }
500
+
501
+ const tileSize = undefined;
502
+ data.xyz_link = getTileUrls(
503
+ req,
504
+ tileJSON.tiles,
505
+ `data/${id}`,
506
+ tileSize,
507
+ tileJSON.format,
508
+ opts.publicUrl,
509
+ {
510
+ pbf: options.pbfAlias,
511
+ },
512
+ )[0];
513
+
512
514
  if (data.filesize) {
513
515
  let suffix = 'kB';
514
516
  let size = parseInt(tileJSON.filesize, 10) / 1024;
package/src/utils.js CHANGED
@@ -26,7 +26,15 @@ export const getPublicUrl = (publicUrl, req) => {
26
26
  return getUrlObject(req).toString();
27
27
  };
28
28
 
29
- export const getTileUrls = (req, domains, path, format, publicUrl, aliases) => {
29
+ export const getTileUrls = (
30
+ req,
31
+ domains,
32
+ path,
33
+ tileSize,
34
+ format,
35
+ publicUrl,
36
+ aliases,
37
+ ) => {
30
38
  const urlObject = getUrlObject(req);
31
39
  if (domains) {
32
40
  if (domains.constructor === String && domains.length > 0) {
@@ -67,15 +75,20 @@ export const getTileUrls = (req, domains, path, format, publicUrl, aliases) => {
67
75
  format = aliases[format];
68
76
  }
69
77
 
78
+ let tileParams = `{z}/{x}/{y}`;
79
+ if (tileSize && ['png', 'jpg', 'jpeg', 'webp'].includes(format)) {
80
+ tileParams = `${tileSize}/{z}/{x}/{y}`;
81
+ }
82
+
70
83
  const uris = [];
71
84
  if (!publicUrl) {
72
85
  for (const domain of domains) {
73
86
  uris.push(
74
- `${req.protocol}://${domain}/${path}/{z}/{x}/{y}.${format}${query}`,
87
+ `${req.protocol}://${domain}/${path}/${tileParams}.${format}${query}`,
75
88
  );
76
89
  }
77
90
  } else {
78
- uris.push(`${publicUrl}${path}/{z}/{x}/{y}.${format}${query}`);
91
+ uris.push(`${publicUrl}${path}/${tileParams}.${format}${query}`);
79
92
  }
80
93
 
81
94
  return uris;
@@ -1,8 +1,30 @@
1
- const testTile = function (prefix, z, x, y, format, status, scale, type) {
1
+ var testTile = function (
2
+ prefix,
3
+ tileSize = 256,
4
+ z,
5
+ x,
6
+ y,
7
+ format,
8
+ status,
9
+ scale,
10
+ type,
11
+ ) {
2
12
  if (scale) y += '@' + scale + 'x';
3
- const path = '/styles/' + prefix + '/' + z + '/' + x + '/' + y + '.' + format;
13
+ var path =
14
+ '/styles/' +
15
+ prefix +
16
+ '/' +
17
+ tileSize +
18
+ '/' +
19
+ z +
20
+ '/' +
21
+ x +
22
+ '/' +
23
+ y +
24
+ '.' +
25
+ format;
4
26
  it(path + ' returns ' + status, function (done) {
5
- const test = supertest(app).get(path);
27
+ var test = supertest(app).get(path);
6
28
  test.expect(status);
7
29
  if (type) test.expect('Content-Type', type);
8
30
  test.end(done);
@@ -14,33 +36,40 @@ const prefix = 'test-style';
14
36
  describe('Raster tiles', function () {
15
37
  describe('valid requests', function () {
16
38
  describe('various formats', function () {
17
- testTile(prefix, 0, 0, 0, 'png', 200, undefined, /image\/png/);
18
- testTile(prefix, 0, 0, 0, 'jpg', 200, undefined, /image\/jpeg/);
19
- testTile(prefix, 0, 0, 0, 'jpeg', 200, undefined, /image\/jpeg/);
20
- testTile(prefix, 0, 0, 0, 'webp', 200, undefined, /image\/webp/);
39
+ testTile(prefix, 256, 0, 0, 0, 'png', 200, undefined, /image\/png/);
40
+ testTile(prefix, 512, 0, 0, 0, 'png', 200, undefined, /image\/png/);
41
+ testTile(prefix, 256, 0, 0, 0, 'jpg', 200, undefined, /image\/jpeg/);
42
+ testTile(prefix, 512, 0, 0, 0, 'jpg', 200, undefined, /image\/jpeg/);
43
+ testTile(prefix, 256, 0, 0, 0, 'jpeg', 200, undefined, /image\/jpeg/);
44
+ testTile(prefix, 512, 0, 0, 0, 'jpeg', 200, undefined, /image\/jpeg/);
45
+ testTile(prefix, 256, 0, 0, 0, 'webp', 200, undefined, /image\/webp/);
46
+ testTile(prefix, 512, 0, 0, 0, 'webp', 200, undefined, /image\/webp/);
21
47
  });
22
48
 
23
49
  describe('different coordinates and scales', function () {
24
- testTile(prefix, 1, 1, 1, 'png', 200);
25
-
26
- testTile(prefix, 0, 0, 0, 'png', 200, 2);
27
- testTile(prefix, 0, 0, 0, 'png', 200, 3);
28
- testTile(prefix, 2, 1, 1, 'png', 200, 3);
50
+ testTile(prefix, 256, 1, 0, 0, 'png', 200);
51
+ testTile(prefix, 512, 1, 0, 0, 'png', 200);
52
+ testTile(prefix, 256, 0, 0, 0, 'png', 200, 2);
53
+ testTile(prefix, 512, 0, 0, 0, 'png', 200, 2);
54
+ testTile(prefix, 256, 0, 0, 0, 'png', 200, 3);
55
+ testTile(prefix, 512, 0, 0, 0, 'png', 200, 3);
56
+ testTile(prefix, 256, 2, 1, 1, 'png', 200, 3);
57
+ testTile(prefix, 512, 2, 1, 1, 'png', 200, 3);
29
58
  });
30
59
  });
31
60
 
32
61
  describe('invalid requests return 4xx', function () {
33
- testTile('non_existent', 0, 0, 0, 'png', 404);
34
- testTile(prefix, -1, 0, 0, 'png', 404);
35
- testTile(prefix, 25, 0, 0, 'png', 404);
36
- testTile(prefix, 0, 1, 0, 'png', 404);
37
- testTile(prefix, 0, 0, 1, 'png', 404);
38
- testTile(prefix, 0, 0, 0, 'gif', 400);
39
- testTile(prefix, 0, 0, 0, 'pbf', 400);
62
+ testTile('non_existent', 256, 0, 0, 0, 'png', 404);
63
+ testTile(prefix, 256, -1, 0, 0, 'png', 404);
64
+ testTile(prefix, 256, 25, 0, 0, 'png', 404);
65
+ testTile(prefix, 256, 0, 1, 0, 'png', 404);
66
+ testTile(prefix, 256, 0, 0, 1, 'png', 404);
67
+ testTile(prefix, 256, 0, 0, 0, 'gif', 400);
68
+ testTile(prefix, 256, 0, 0, 0, 'pbf', 400);
40
69
 
41
- testTile(prefix, 0, 0, 0, 'png', 404, 1);
42
- testTile(prefix, 0, 0, 0, 'png', 404, 5);
70
+ testTile(prefix, 256, 0, 0, 0, 'png', 404, 1);
71
+ testTile(prefix, 256, 0, 0, 0, 'png', 404, 5);
43
72
 
44
- // testTile('hybrid', 0, 0, 0, 'png', 404); //TODO: test this
73
+ testTile(prefix, 300, 0, 0, 0, 'png', 404);
45
74
  });
46
75
  });