@versatiles/style 5.8.3 → 5.9.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.
- package/README.md +38 -32
- package/dist/index.d.ts +21 -15
- package/dist/index.js +719 -419
- package/dist/index.js.map +1 -1
- package/package.json +22 -17
- package/src/color/abstract.ts +1 -1
- package/src/color/hsl.test.ts +11 -18
- package/src/color/hsl.ts +11 -23
- package/src/color/hsv.test.ts +4 -10
- package/src/color/hsv.ts +38 -22
- package/src/color/index.test.ts +91 -5
- package/src/color/index.ts +4 -2
- package/src/color/random.test.ts +55 -1
- package/src/color/random.ts +130 -26
- package/src/color/rgb.test.ts +60 -38
- package/src/color/rgb.ts +34 -56
- package/src/color/utils.test.ts +4 -6
- package/src/color/utils.ts +2 -4
- package/src/guess_style/guess_style.test.ts +49 -43
- package/src/guess_style/guess_style.ts +67 -22
- package/src/guess_style/index.ts +0 -1
- package/src/index.test.ts +35 -8
- package/src/index.ts +41 -21
- package/src/lib/utils.test.ts +86 -3
- package/src/lib/utils.ts +12 -20
- package/src/shortbread/index.ts +0 -1
- package/src/shortbread/layers.test.ts +15 -1
- package/src/shortbread/layers.ts +204 -199
- package/src/shortbread/properties.test.ts +3 -4
- package/src/shortbread/properties.ts +18 -4
- package/src/shortbread/template.test.ts +7 -2
- package/src/shortbread/template.ts +7 -14
- package/src/style_builder/decorator.test.ts +4 -4
- package/src/style_builder/decorator.ts +46 -31
- package/src/style_builder/recolor.test.ts +6 -31
- package/src/style_builder/recolor.ts +38 -31
- package/src/style_builder/style_builder.test.ts +50 -13
- package/src/style_builder/style_builder.ts +35 -34
- package/src/style_builder/types.ts +44 -2
- package/src/styles/LICENSE.md +15 -15
- package/src/styles/colorful.test.ts +91 -0
- package/src/styles/colorful.ts +229 -122
- package/src/styles/eclipse.ts +1 -1
- package/src/styles/empty.ts +1 -1
- package/src/styles/graybeard.ts +2 -2
- package/src/styles/index.ts +2 -3
- package/src/styles/neutrino.ts +14 -16
- package/src/styles/satellite.test.ts +146 -0
- package/src/styles/satellite.ts +106 -0
- package/src/styles/shadow.ts +2 -2
- package/src/types/index.ts +0 -1
- package/src/types/maplibre.ts +17 -3
- package/src/types/tilejson.test.ts +17 -14
- package/src/types/tilejson.ts +59 -37
- package/src/types/vector_layer.test.ts +5 -2
- package/src/types/vector_layer.ts +8 -10
package/dist/index.js
CHANGED
|
@@ -145,7 +145,7 @@ function mod(value, max) {
|
|
|
145
145
|
value = value % max;
|
|
146
146
|
if (value < 0)
|
|
147
147
|
value += max;
|
|
148
|
-
if (value
|
|
148
|
+
if (value === 0)
|
|
149
149
|
return 0;
|
|
150
150
|
return value;
|
|
151
151
|
}
|
|
@@ -236,7 +236,7 @@ function randomColor(options) {
|
|
|
236
236
|
function randomWithin(range) {
|
|
237
237
|
//Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
|
|
238
238
|
seed = (seed * 9301 + 49297) % 233280;
|
|
239
|
-
return Math.floor(range[0] + seed / 233280.0 * (range[1] - range[0]));
|
|
239
|
+
return Math.floor(range[0] + (seed / 233280.0) * (range[1] - range[0]));
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
function inputToSeed(input) {
|
|
@@ -261,14 +261,81 @@ function initColorDictionary() {
|
|
|
261
261
|
brightnessRange: [colorful[1], greyest[1]],
|
|
262
262
|
});
|
|
263
263
|
};
|
|
264
|
-
defineColor('monochrome', null, [
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
defineColor('
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
264
|
+
defineColor('monochrome', null, [
|
|
265
|
+
[0, 0],
|
|
266
|
+
[100, 0],
|
|
267
|
+
]);
|
|
268
|
+
defineColor('red', [-26, 18], [
|
|
269
|
+
[20, 100],
|
|
270
|
+
[30, 92],
|
|
271
|
+
[40, 89],
|
|
272
|
+
[50, 85],
|
|
273
|
+
[60, 78],
|
|
274
|
+
[70, 70],
|
|
275
|
+
[80, 60],
|
|
276
|
+
[90, 55],
|
|
277
|
+
[100, 50],
|
|
278
|
+
]);
|
|
279
|
+
defineColor('orange', [18, 46], [
|
|
280
|
+
[20, 100],
|
|
281
|
+
[30, 93],
|
|
282
|
+
[40, 88],
|
|
283
|
+
[50, 86],
|
|
284
|
+
[60, 85],
|
|
285
|
+
[70, 70],
|
|
286
|
+
[100, 70],
|
|
287
|
+
]);
|
|
288
|
+
defineColor('yellow', [46, 62], [
|
|
289
|
+
[25, 100],
|
|
290
|
+
[40, 94],
|
|
291
|
+
[50, 89],
|
|
292
|
+
[60, 86],
|
|
293
|
+
[70, 84],
|
|
294
|
+
[80, 82],
|
|
295
|
+
[90, 80],
|
|
296
|
+
[100, 75],
|
|
297
|
+
]);
|
|
298
|
+
defineColor('green', [62, 178], [
|
|
299
|
+
[30, 100],
|
|
300
|
+
[40, 90],
|
|
301
|
+
[50, 85],
|
|
302
|
+
[60, 81],
|
|
303
|
+
[70, 74],
|
|
304
|
+
[80, 64],
|
|
305
|
+
[90, 50],
|
|
306
|
+
[100, 40],
|
|
307
|
+
]);
|
|
308
|
+
defineColor('blue', [178, 257], [
|
|
309
|
+
[20, 100],
|
|
310
|
+
[30, 86],
|
|
311
|
+
[40, 80],
|
|
312
|
+
[50, 74],
|
|
313
|
+
[60, 60],
|
|
314
|
+
[70, 52],
|
|
315
|
+
[80, 44],
|
|
316
|
+
[90, 39],
|
|
317
|
+
[100, 35],
|
|
318
|
+
]);
|
|
319
|
+
defineColor('purple', [257, 282], [
|
|
320
|
+
[20, 100],
|
|
321
|
+
[30, 87],
|
|
322
|
+
[40, 79],
|
|
323
|
+
[50, 70],
|
|
324
|
+
[60, 65],
|
|
325
|
+
[70, 59],
|
|
326
|
+
[80, 52],
|
|
327
|
+
[90, 45],
|
|
328
|
+
[100, 42],
|
|
329
|
+
]);
|
|
330
|
+
defineColor('pink', [282, 334], [
|
|
331
|
+
[20, 100],
|
|
332
|
+
[30, 90],
|
|
333
|
+
[40, 86],
|
|
334
|
+
[60, 84],
|
|
335
|
+
[80, 80],
|
|
336
|
+
[90, 75],
|
|
337
|
+
[100, 73],
|
|
338
|
+
]);
|
|
272
339
|
return dict;
|
|
273
340
|
}
|
|
274
341
|
function getColorInfo(hue) {
|
|
@@ -280,7 +347,7 @@ function getColorInfo(hue) {
|
|
|
280
347
|
return color;
|
|
281
348
|
}
|
|
282
349
|
}
|
|
283
|
-
throw Error(
|
|
350
|
+
throw new Error(`getColorInfo: No color info found for hue value ${hue}. This indicates a gap in the color dictionary hue ranges.`);
|
|
284
351
|
}
|
|
285
352
|
|
|
286
353
|
/**
|
|
@@ -370,7 +437,9 @@ class RGB extends Color {
|
|
|
370
437
|
return `#${r}${g}${b}`.toUpperCase();
|
|
371
438
|
}
|
|
372
439
|
else {
|
|
373
|
-
const a = Math.round(this.a * 255)
|
|
440
|
+
const a = Math.round(this.a * 255)
|
|
441
|
+
.toString(16)
|
|
442
|
+
.padStart(2, '0');
|
|
374
443
|
return `#${r}${g}${b}${a}`.toUpperCase();
|
|
375
444
|
}
|
|
376
445
|
}
|
|
@@ -408,7 +477,6 @@ class RGB extends Color {
|
|
|
408
477
|
s = delta / (2 - max - min);
|
|
409
478
|
return new HSL(h, s * 100, l * 100, this.a);
|
|
410
479
|
}
|
|
411
|
-
;
|
|
412
480
|
/**
|
|
413
481
|
* Converts the RGB color to an HSV color.
|
|
414
482
|
*
|
|
@@ -433,9 +501,9 @@ class RGB extends Color {
|
|
|
433
501
|
if (r === v)
|
|
434
502
|
h = bdif - gdif;
|
|
435
503
|
else if (g === v)
|
|
436
|
-
h =
|
|
504
|
+
h = 1 / 3 + rdif - bdif;
|
|
437
505
|
else if (b === v)
|
|
438
|
-
h =
|
|
506
|
+
h = 2 / 3 + gdif - rdif;
|
|
439
507
|
if (h < 0)
|
|
440
508
|
h += 1;
|
|
441
509
|
else if (h > 1)
|
|
@@ -451,14 +519,6 @@ class RGB extends Color {
|
|
|
451
519
|
asRGB() {
|
|
452
520
|
return this.clone();
|
|
453
521
|
}
|
|
454
|
-
/**
|
|
455
|
-
* Returns the RGB color.
|
|
456
|
-
*
|
|
457
|
-
* @returns The current RGB instance.
|
|
458
|
-
*/
|
|
459
|
-
toRGB() {
|
|
460
|
-
return this;
|
|
461
|
-
}
|
|
462
522
|
/**
|
|
463
523
|
* Parses a string or Color instance into an RGB color.
|
|
464
524
|
*
|
|
@@ -551,7 +611,7 @@ class RGB extends Color {
|
|
|
551
611
|
if (value > 1)
|
|
552
612
|
value = 1;
|
|
553
613
|
const a = 1 - Math.abs(value);
|
|
554
|
-
const b =
|
|
614
|
+
const b = value < 0 ? 0 : 255 * value;
|
|
555
615
|
return new RGB(this.r * a + b, this.g * a + b, this.b * a + b, this.a);
|
|
556
616
|
}
|
|
557
617
|
/**
|
|
@@ -682,7 +742,7 @@ class HSV extends Color {
|
|
|
682
742
|
const v = this.v / 100;
|
|
683
743
|
const k = (2 - s) * v;
|
|
684
744
|
const q = k < 1 ? k : 2 - k;
|
|
685
|
-
return new HSL(this.h, q
|
|
745
|
+
return new HSL(this.h, q === 0 ? 0 : (100 * s * v) / q, (100 * k) / 2, this.a);
|
|
686
746
|
}
|
|
687
747
|
/**
|
|
688
748
|
* Returns the current HSV color.
|
|
@@ -849,13 +909,6 @@ class HSL extends Color {
|
|
|
849
909
|
asHSL() {
|
|
850
910
|
return this.clone();
|
|
851
911
|
}
|
|
852
|
-
/**
|
|
853
|
-
* Returns the current HSL color.
|
|
854
|
-
* @returns The current HSL color.
|
|
855
|
-
*/
|
|
856
|
-
toHSL() {
|
|
857
|
-
return this;
|
|
858
|
-
}
|
|
859
912
|
/**
|
|
860
913
|
* Converts the HSL color to an HSV color.
|
|
861
914
|
* @returns A new HSV color representing the same color.
|
|
@@ -963,7 +1016,7 @@ Color.parse = function (input) {
|
|
|
963
1016
|
case 'hsla(':
|
|
964
1017
|
return HSL.parse(input);
|
|
965
1018
|
default:
|
|
966
|
-
throw Error(
|
|
1019
|
+
throw new Error(`Color.parse: Unknown color format "${input}". Expected formats: "#RRGGBB", "#RGB", "rgb(...)", "rgba(...)", "hsl(...)", or "hsla(...)".`);
|
|
967
1020
|
}
|
|
968
1021
|
};
|
|
969
1022
|
Color.HSL = HSL;
|
|
@@ -983,19 +1036,12 @@ function getShortbreadTemplate() {
|
|
|
983
1036
|
sources: {
|
|
984
1037
|
'versatiles-shortbread': {
|
|
985
1038
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
|
986
|
-
tiles: [
|
|
987
|
-
'https://tiles.versatiles.org/tiles/osm/{z}/{x}/{y}',
|
|
988
|
-
],
|
|
1039
|
+
tiles: ['https://tiles.versatiles.org/tiles/osm/{z}/{x}/{y}'],
|
|
989
1040
|
type: 'vector',
|
|
990
1041
|
scheme: 'xyz',
|
|
991
|
-
bounds: [
|
|
992
|
-
-180,
|
|
993
|
-
-85.0511287798066,
|
|
994
|
-
180,
|
|
995
|
-
85.0511287798066,
|
|
996
|
-
],
|
|
1042
|
+
bounds: [-180, -85.0511287798066, 180, 85.0511287798066],
|
|
997
1043
|
minzoom: 0,
|
|
998
|
-
maxzoom
|
|
1044
|
+
maxzoom,
|
|
999
1045
|
},
|
|
1000
1046
|
},
|
|
1001
1047
|
layers: [],
|
|
@@ -1006,12 +1052,7 @@ function getShortbreadLayers(option) {
|
|
|
1006
1052
|
const { language } = option;
|
|
1007
1053
|
let nameField = ['get', 'name'];
|
|
1008
1054
|
if (language) {
|
|
1009
|
-
nameField = [
|
|
1010
|
-
'case',
|
|
1011
|
-
['to-boolean', ['get', 'name_' + language]],
|
|
1012
|
-
['get', 'name_' + language],
|
|
1013
|
-
['get', 'name']
|
|
1014
|
-
];
|
|
1055
|
+
nameField = ['case', ['to-boolean', ['get', 'name_' + language]], ['get', 'name_' + language], ['get', 'name']];
|
|
1015
1056
|
}
|
|
1016
1057
|
return [
|
|
1017
1058
|
// background
|
|
@@ -1021,14 +1062,27 @@ function getShortbreadLayers(option) {
|
|
|
1021
1062
|
// land
|
|
1022
1063
|
{
|
|
1023
1064
|
id: 'land-glacier',
|
|
1024
|
-
type: 'fill',
|
|
1065
|
+
type: 'fill',
|
|
1066
|
+
'source-layer': 'water_polygons',
|
|
1025
1067
|
filter: ['all', ['==', 'kind', 'glacier']],
|
|
1026
1068
|
},
|
|
1027
1069
|
...[
|
|
1028
1070
|
{ id: 'commercial', kinds: ['commercial', 'retail'] },
|
|
1029
1071
|
{ id: 'industrial', kinds: ['industrial', 'quarry', 'railway'] },
|
|
1030
1072
|
{ id: 'residential', kinds: ['garages', 'residential'] },
|
|
1031
|
-
{
|
|
1073
|
+
{
|
|
1074
|
+
id: 'agriculture',
|
|
1075
|
+
kinds: [
|
|
1076
|
+
'brownfield',
|
|
1077
|
+
'farmland',
|
|
1078
|
+
'farmyard',
|
|
1079
|
+
'greenfield',
|
|
1080
|
+
'greenhouse_horticulture',
|
|
1081
|
+
'orchard',
|
|
1082
|
+
'plant_nursery',
|
|
1083
|
+
'vineyard',
|
|
1084
|
+
],
|
|
1085
|
+
},
|
|
1032
1086
|
{ id: 'waste', kinds: ['landfill'] },
|
|
1033
1087
|
{ id: 'park', kinds: ['park', 'village_green', 'recreation_ground'] },
|
|
1034
1088
|
{ id: 'garden', kinds: ['allotments', 'garden'] },
|
|
@@ -1044,45 +1098,63 @@ function getShortbreadLayers(option) {
|
|
|
1044
1098
|
id: 'land-' + id,
|
|
1045
1099
|
type: 'fill',
|
|
1046
1100
|
'source-layer': 'land',
|
|
1047
|
-
filter: ['all',
|
|
1048
|
-
['in', 'kind', ...kinds],
|
|
1049
|
-
],
|
|
1101
|
+
filter: ['all', ['in', 'kind', ...kinds]],
|
|
1050
1102
|
})),
|
|
1051
1103
|
// water-lines
|
|
1052
1104
|
...['river', 'canal', 'stream', 'ditch'].map((t) => ({
|
|
1053
1105
|
id: 'water-' + t,
|
|
1054
1106
|
type: 'line',
|
|
1055
1107
|
'source-layer': 'water_lines',
|
|
1056
|
-
filter: ['all',
|
|
1057
|
-
['in', 'kind', t],
|
|
1058
|
-
['!=', 'tunnel', true],
|
|
1059
|
-
['!=', 'bridge', true],
|
|
1060
|
-
],
|
|
1108
|
+
filter: ['all', ['in', 'kind', t], ['!=', 'tunnel', true], ['!=', 'bridge', true]],
|
|
1061
1109
|
})),
|
|
1062
1110
|
// water polygons
|
|
1063
1111
|
{
|
|
1064
1112
|
id: 'water-area',
|
|
1065
|
-
type: 'fill',
|
|
1113
|
+
type: 'fill',
|
|
1114
|
+
'source-layer': 'water_polygons',
|
|
1066
1115
|
filter: ['==', 'kind', 'water'],
|
|
1067
1116
|
},
|
|
1068
1117
|
{
|
|
1069
1118
|
id: 'water-area-river',
|
|
1070
|
-
type: 'fill',
|
|
1119
|
+
type: 'fill',
|
|
1120
|
+
'source-layer': 'water_polygons',
|
|
1071
1121
|
filter: ['==', 'kind', 'river'],
|
|
1072
1122
|
},
|
|
1073
1123
|
{
|
|
1074
1124
|
id: 'water-area-small',
|
|
1075
|
-
type: 'fill',
|
|
1125
|
+
type: 'fill',
|
|
1126
|
+
'source-layer': 'water_polygons',
|
|
1076
1127
|
filter: ['in', 'kind', 'reservoir', 'basin', 'dock'],
|
|
1077
1128
|
},
|
|
1078
1129
|
// dam
|
|
1079
1130
|
{ id: 'water-dam-area', type: 'fill', 'source-layer': 'dam_polygons', filter: ['==', 'kind', 'dam'] },
|
|
1080
1131
|
{ id: 'water-dam', type: 'line', 'source-layer': 'dam_lines', filter: ['==', 'kind', 'dam'] },
|
|
1081
1132
|
// pier
|
|
1082
|
-
{
|
|
1083
|
-
|
|
1133
|
+
{
|
|
1134
|
+
id: 'water-pier-area',
|
|
1135
|
+
type: 'fill',
|
|
1136
|
+
'source-layer': 'pier_polygons',
|
|
1137
|
+
filter: ['in', 'kind', 'pier', 'breakwater', 'groyne'],
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
id: 'water-pier',
|
|
1141
|
+
type: 'line',
|
|
1142
|
+
'source-layer': 'pier_lines',
|
|
1143
|
+
filter: ['in', 'kind', 'pier', 'breakwater', 'groyne'],
|
|
1144
|
+
},
|
|
1084
1145
|
// site
|
|
1085
|
-
...[
|
|
1146
|
+
...[
|
|
1147
|
+
'danger_area',
|
|
1148
|
+
'sports_center',
|
|
1149
|
+
'university',
|
|
1150
|
+
'college',
|
|
1151
|
+
'school',
|
|
1152
|
+
'hospital',
|
|
1153
|
+
'prison',
|
|
1154
|
+
'parking',
|
|
1155
|
+
'bicycle_parking',
|
|
1156
|
+
'construction',
|
|
1157
|
+
].map((t) => ({
|
|
1086
1158
|
id: 'site-' + t.replace(/_/g, ''),
|
|
1087
1159
|
type: 'fill',
|
|
1088
1160
|
'source-layer': 'sites',
|
|
@@ -1091,32 +1163,44 @@ function getShortbreadLayers(option) {
|
|
|
1091
1163
|
// airport
|
|
1092
1164
|
{
|
|
1093
1165
|
id: 'airport-area',
|
|
1094
|
-
type: 'fill',
|
|
1166
|
+
type: 'fill',
|
|
1167
|
+
'source-layer': 'street_polygons',
|
|
1168
|
+
filter: ['in', 'kind', 'runway', 'taxiway'],
|
|
1095
1169
|
},
|
|
1096
1170
|
{
|
|
1097
1171
|
id: 'airport-taxiway:outline',
|
|
1098
|
-
type: 'line',
|
|
1172
|
+
type: 'line',
|
|
1173
|
+
'source-layer': 'streets',
|
|
1174
|
+
filter: ['==', 'kind', 'taxiway'],
|
|
1099
1175
|
},
|
|
1100
1176
|
{
|
|
1101
1177
|
id: 'airport-runway:outline',
|
|
1102
|
-
type: 'line',
|
|
1178
|
+
type: 'line',
|
|
1179
|
+
'source-layer': 'streets',
|
|
1180
|
+
filter: ['==', 'kind', 'runway'],
|
|
1103
1181
|
},
|
|
1104
1182
|
{
|
|
1105
1183
|
id: 'airport-taxiway',
|
|
1106
|
-
type: 'line',
|
|
1184
|
+
type: 'line',
|
|
1185
|
+
'source-layer': 'streets',
|
|
1186
|
+
filter: ['==', 'kind', 'taxiway'],
|
|
1107
1187
|
},
|
|
1108
1188
|
{
|
|
1109
1189
|
id: 'airport-runway',
|
|
1110
|
-
type: 'line',
|
|
1190
|
+
type: 'line',
|
|
1191
|
+
'source-layer': 'streets',
|
|
1192
|
+
filter: ['==', 'kind', 'runway'],
|
|
1111
1193
|
},
|
|
1112
1194
|
// building
|
|
1113
1195
|
{
|
|
1114
1196
|
id: 'building:outline',
|
|
1115
|
-
type: 'fill',
|
|
1197
|
+
type: 'fill',
|
|
1198
|
+
'source-layer': 'buildings',
|
|
1116
1199
|
},
|
|
1117
1200
|
{
|
|
1118
1201
|
id: 'building',
|
|
1119
|
-
type: 'fill',
|
|
1202
|
+
type: 'fill',
|
|
1203
|
+
'source-layer': 'buildings',
|
|
1120
1204
|
},
|
|
1121
1205
|
// tunnel-, street-, bridges-bridge
|
|
1122
1206
|
...['tunnel', 'street', 'bridge'].flatMap((c) => {
|
|
@@ -1131,7 +1215,10 @@ function getShortbreadLayers(option) {
|
|
|
1131
1215
|
suffixes = [':outline', ''];
|
|
1132
1216
|
break;
|
|
1133
1217
|
case 'street':
|
|
1134
|
-
filter = [
|
|
1218
|
+
filter = [
|
|
1219
|
+
['!=', 'bridge', true],
|
|
1220
|
+
['!=', 'tunnel', true],
|
|
1221
|
+
];
|
|
1135
1222
|
prefix = '';
|
|
1136
1223
|
suffixes = [':outline', ''];
|
|
1137
1224
|
break;
|
|
@@ -1155,85 +1242,64 @@ function getShortbreadLayers(option) {
|
|
|
1155
1242
|
type: 'fill',
|
|
1156
1243
|
'source-layer': 'bridges',
|
|
1157
1244
|
});
|
|
1158
|
-
suffixes.forEach(suffix => {
|
|
1245
|
+
suffixes.forEach((suffix) => {
|
|
1159
1246
|
// pedestrian zone — no outline
|
|
1160
1247
|
if (suffix === ':outline')
|
|
1161
1248
|
results.push({
|
|
1162
1249
|
id: prefix + 'street-pedestrian-zone',
|
|
1163
1250
|
type: 'fill',
|
|
1164
1251
|
'source-layer': 'street_polygons',
|
|
1165
|
-
filter: ['all',
|
|
1166
|
-
...filter,
|
|
1167
|
-
['==', 'kind', 'pedestrian'],
|
|
1168
|
-
],
|
|
1252
|
+
filter: ['all', ...filter, ['==', 'kind', 'pedestrian']],
|
|
1169
1253
|
});
|
|
1170
1254
|
// non-car streets
|
|
1171
|
-
['footway', 'steps', 'path', 'cycleway'].forEach(t => {
|
|
1255
|
+
['footway', 'steps', 'path', 'cycleway'].forEach((t) => {
|
|
1172
1256
|
results.push({
|
|
1173
1257
|
id: prefix + 'way-' + t.replace(/_/g, '') + suffix,
|
|
1174
1258
|
type: 'line',
|
|
1175
1259
|
'source-layer': 'streets',
|
|
1176
|
-
filter: ['all',
|
|
1177
|
-
...filter,
|
|
1178
|
-
['in', 'kind', t],
|
|
1179
|
-
],
|
|
1260
|
+
filter: ['all', ...filter, ['in', 'kind', t]],
|
|
1180
1261
|
});
|
|
1181
1262
|
});
|
|
1182
1263
|
// no links
|
|
1183
|
-
['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach(t => {
|
|
1264
|
+
['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach((t) => {
|
|
1184
1265
|
results.push({
|
|
1185
1266
|
id: prefix + 'street-' + t.replace(/_/g, '') + suffix,
|
|
1186
1267
|
type: 'line',
|
|
1187
1268
|
'source-layer': 'streets',
|
|
1188
|
-
filter: ['all',
|
|
1189
|
-
['==', 'kind', t],
|
|
1190
|
-
...filter,
|
|
1191
|
-
],
|
|
1269
|
+
filter: ['all', ['==', 'kind', t], ...filter],
|
|
1192
1270
|
});
|
|
1193
1271
|
});
|
|
1194
1272
|
// no links, bicycle=designated
|
|
1195
1273
|
if (suffix === '')
|
|
1196
|
-
['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach(t => {
|
|
1274
|
+
['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach((t) => {
|
|
1197
1275
|
results.push({
|
|
1198
1276
|
id: prefix + 'street-' + t.replace(/_/g, '') + '-bicycle',
|
|
1199
1277
|
type: 'line',
|
|
1200
1278
|
'source-layer': 'streets',
|
|
1201
|
-
filter: ['all',
|
|
1202
|
-
['==', 'kind', t],
|
|
1203
|
-
['==', 'bicycle', 'designated'],
|
|
1204
|
-
...filter,
|
|
1205
|
-
],
|
|
1279
|
+
filter: ['all', ['==', 'kind', t], ['==', 'bicycle', 'designated'], ...filter],
|
|
1206
1280
|
});
|
|
1207
1281
|
});
|
|
1208
1282
|
// links
|
|
1209
|
-
['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach(t => {
|
|
1283
|
+
['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach((t) => {
|
|
1210
1284
|
results.push({
|
|
1211
1285
|
id: prefix + 'street-' + t.replace(/_/g, '') + '-link' + suffix,
|
|
1212
1286
|
type: 'line',
|
|
1213
1287
|
'source-layer': 'streets',
|
|
1214
|
-
filter: ['all',
|
|
1215
|
-
...filter,
|
|
1216
|
-
['in', 'kind', t],
|
|
1217
|
-
['==', 'link', true],
|
|
1218
|
-
],
|
|
1288
|
+
filter: ['all', ...filter, ['in', 'kind', t], ['==', 'link', true]],
|
|
1219
1289
|
});
|
|
1220
1290
|
});
|
|
1221
1291
|
// main
|
|
1222
|
-
['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach(t => {
|
|
1292
|
+
['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach((t) => {
|
|
1223
1293
|
results.push({
|
|
1224
1294
|
id: prefix + 'street-' + t.replace(/_/g, '') + suffix,
|
|
1225
1295
|
type: 'line',
|
|
1226
1296
|
'source-layer': 'streets',
|
|
1227
|
-
filter: ['all',
|
|
1228
|
-
...filter,
|
|
1229
|
-
['in', 'kind', t],
|
|
1230
|
-
['!=', 'link', true],
|
|
1231
|
-
],
|
|
1297
|
+
filter: ['all', ...filter, ['in', 'kind', t], ['!=', 'link', true]],
|
|
1232
1298
|
});
|
|
1233
1299
|
});
|
|
1234
1300
|
});
|
|
1235
1301
|
// separate outline for trains
|
|
1236
|
-
[':outline', ''].forEach(suffix => {
|
|
1302
|
+
[':outline', ''].forEach((suffix) => {
|
|
1237
1303
|
// with service distinction
|
|
1238
1304
|
['rail', 'light_rail', 'subway', 'narrow_gauge', 'tram'].reverse().forEach((t) => {
|
|
1239
1305
|
// main rail
|
|
@@ -1241,22 +1307,14 @@ function getShortbreadLayers(option) {
|
|
|
1241
1307
|
id: prefix + 'transport-' + t.replace(/_/g, '') + suffix,
|
|
1242
1308
|
type: 'line',
|
|
1243
1309
|
'source-layer': 'streets',
|
|
1244
|
-
filter: ['all',
|
|
1245
|
-
['in', 'kind', t],
|
|
1246
|
-
['!has', 'service'],
|
|
1247
|
-
...filter,
|
|
1248
|
-
],
|
|
1310
|
+
filter: ['all', ['in', 'kind', t], ['!has', 'service'], ...filter],
|
|
1249
1311
|
});
|
|
1250
1312
|
// service rail (crossover, siding, spur, yard)
|
|
1251
1313
|
results.push({
|
|
1252
1314
|
id: prefix + 'transport-' + t.replace(/_/g, '') + '-service' + suffix,
|
|
1253
1315
|
type: 'line',
|
|
1254
1316
|
'source-layer': 'streets',
|
|
1255
|
-
filter: ['all',
|
|
1256
|
-
['in', 'kind', t],
|
|
1257
|
-
['has', 'service'],
|
|
1258
|
-
...filter,
|
|
1259
|
-
],
|
|
1317
|
+
filter: ['all', ['in', 'kind', t], ['has', 'service'], ...filter],
|
|
1260
1318
|
});
|
|
1261
1319
|
});
|
|
1262
1320
|
// other transport
|
|
@@ -1265,23 +1323,19 @@ function getShortbreadLayers(option) {
|
|
|
1265
1323
|
id: prefix + 'transport-' + t.replace(/_/g, '') + suffix,
|
|
1266
1324
|
type: 'line',
|
|
1267
1325
|
'source-layer': 'streets',
|
|
1268
|
-
filter: ['all',
|
|
1269
|
-
['in', 'kind', t],
|
|
1270
|
-
...filter,
|
|
1271
|
-
],
|
|
1326
|
+
filter: ['all', ['in', 'kind', t], ...filter],
|
|
1272
1327
|
});
|
|
1273
1328
|
});
|
|
1274
1329
|
if (c === 'street') {
|
|
1275
1330
|
// aerialway, no bridges, above street evel
|
|
1276
|
-
['cable_car', 'gondola', 'goods', 'chair_lift', 'drag_lift', 't-bar', 'j-bar', 'platter', 'rope-tow']
|
|
1331
|
+
['cable_car', 'gondola', 'goods', 'chair_lift', 'drag_lift', 't-bar', 'j-bar', 'platter', 'rope-tow']
|
|
1332
|
+
.reverse()
|
|
1333
|
+
.forEach((t) => {
|
|
1277
1334
|
results.push({
|
|
1278
1335
|
id: 'aerialway-' + t.replace(/[_-]+/g, '') + suffix,
|
|
1279
1336
|
type: 'line',
|
|
1280
1337
|
'source-layer': 'aerialways',
|
|
1281
|
-
filter: ['all',
|
|
1282
|
-
...filter,
|
|
1283
|
-
['in', 'kind', t],
|
|
1284
|
-
],
|
|
1338
|
+
filter: ['all', ...filter, ['in', 'kind', t]],
|
|
1285
1339
|
});
|
|
1286
1340
|
});
|
|
1287
1341
|
// ferry — only on street level
|
|
@@ -1307,7 +1361,8 @@ function getShortbreadLayers(option) {
|
|
|
1307
1361
|
id: 'boundary-country' + suffix,
|
|
1308
1362
|
type: 'line',
|
|
1309
1363
|
'source-layer': 'boundaries',
|
|
1310
|
-
filter: [
|
|
1364
|
+
filter: [
|
|
1365
|
+
'all',
|
|
1311
1366
|
['==', 'admin_level', 2],
|
|
1312
1367
|
['!=', 'maritime', true],
|
|
1313
1368
|
['!=', 'disputed', true],
|
|
@@ -1318,7 +1373,8 @@ function getShortbreadLayers(option) {
|
|
|
1318
1373
|
id: 'boundary-country-disputed' + suffix,
|
|
1319
1374
|
type: 'line',
|
|
1320
1375
|
'source-layer': 'boundaries',
|
|
1321
|
-
filter: [
|
|
1376
|
+
filter: [
|
|
1377
|
+
'all',
|
|
1322
1378
|
['==', 'admin_level', 2],
|
|
1323
1379
|
['==', 'disputed', true],
|
|
1324
1380
|
['!=', 'maritime', true],
|
|
@@ -1329,7 +1385,8 @@ function getShortbreadLayers(option) {
|
|
|
1329
1385
|
id: 'boundary-country-maritime' + suffix,
|
|
1330
1386
|
type: 'line',
|
|
1331
1387
|
'source-layer': 'boundaries',
|
|
1332
|
-
filter: [
|
|
1388
|
+
filter: [
|
|
1389
|
+
'all',
|
|
1333
1390
|
['==', 'admin_level', 2],
|
|
1334
1391
|
['==', 'maritime', true],
|
|
1335
1392
|
['!=', 'disputed', true],
|
|
@@ -1340,7 +1397,8 @@ function getShortbreadLayers(option) {
|
|
|
1340
1397
|
id: 'boundary-state' + suffix,
|
|
1341
1398
|
type: 'line',
|
|
1342
1399
|
'source-layer': 'boundaries',
|
|
1343
|
-
filter: [
|
|
1400
|
+
filter: [
|
|
1401
|
+
'all',
|
|
1344
1402
|
['==', 'admin_level', 4],
|
|
1345
1403
|
['!=', 'maritime', true],
|
|
1346
1404
|
['!=', 'disputed', true],
|
|
@@ -1382,7 +1440,14 @@ function getShortbreadLayers(option) {
|
|
|
1382
1440
|
layout: { 'text-field': nameField },
|
|
1383
1441
|
})),
|
|
1384
1442
|
// label-place of small places
|
|
1385
|
-
...[
|
|
1443
|
+
...[
|
|
1444
|
+
/*'locality', 'island', 'farm', 'dwelling',*/ 'neighbourhood',
|
|
1445
|
+
'quarter',
|
|
1446
|
+
'suburb',
|
|
1447
|
+
'hamlet',
|
|
1448
|
+
'village',
|
|
1449
|
+
'town',
|
|
1450
|
+
].map((id) => ({
|
|
1386
1451
|
id: 'label-place-' + id.replace(/_/g, ''),
|
|
1387
1452
|
type: 'symbol',
|
|
1388
1453
|
'source-layer': 'place_labels',
|
|
@@ -1409,31 +1474,21 @@ function getShortbreadLayers(option) {
|
|
|
1409
1474
|
id: 'label-boundary-country-small',
|
|
1410
1475
|
type: 'symbol',
|
|
1411
1476
|
'source-layer': 'boundary_labels',
|
|
1412
|
-
filter: ['all',
|
|
1413
|
-
['in', 'admin_level', 2, '2'],
|
|
1414
|
-
['<=', 'way_area', 10000000],
|
|
1415
|
-
],
|
|
1477
|
+
filter: ['all', ['in', 'admin_level', 2, '2'], ['<=', 'way_area', 10000000]],
|
|
1416
1478
|
layout: { 'text-field': nameField },
|
|
1417
1479
|
},
|
|
1418
1480
|
{
|
|
1419
1481
|
id: 'label-boundary-country-medium',
|
|
1420
1482
|
type: 'symbol',
|
|
1421
1483
|
'source-layer': 'boundary_labels',
|
|
1422
|
-
filter: ['all',
|
|
1423
|
-
['in', 'admin_level', 2, '2'],
|
|
1424
|
-
['<', 'way_area', 90000000],
|
|
1425
|
-
['>', 'way_area', 10000000],
|
|
1426
|
-
],
|
|
1484
|
+
filter: ['all', ['in', 'admin_level', 2, '2'], ['<', 'way_area', 90000000], ['>', 'way_area', 10000000]],
|
|
1427
1485
|
layout: { 'text-field': nameField },
|
|
1428
1486
|
},
|
|
1429
1487
|
{
|
|
1430
1488
|
id: 'label-boundary-country-large',
|
|
1431
1489
|
type: 'symbol',
|
|
1432
1490
|
'source-layer': 'boundary_labels',
|
|
1433
|
-
filter: ['all',
|
|
1434
|
-
['in', 'admin_level', 2, '2'],
|
|
1435
|
-
['>=', 'way_area', 90000000],
|
|
1436
|
-
],
|
|
1491
|
+
filter: ['all', ['in', 'admin_level', 2, '2'], ['>=', 'way_area', 90000000]],
|
|
1437
1492
|
layout: { 'text-field': nameField },
|
|
1438
1493
|
},
|
|
1439
1494
|
// marking
|
|
@@ -1441,7 +1496,8 @@ function getShortbreadLayers(option) {
|
|
|
1441
1496
|
id: 'marking-oneway', // streets → oneway
|
|
1442
1497
|
type: 'symbol',
|
|
1443
1498
|
'source-layer': 'streets',
|
|
1444
|
-
filter: [
|
|
1499
|
+
filter: [
|
|
1500
|
+
'all',
|
|
1445
1501
|
['==', 'oneway', true],
|
|
1446
1502
|
['in', 'kind', 'trunk', 'primary', 'secondary', 'tertiary', 'unclassified', 'residential', 'living_street'],
|
|
1447
1503
|
],
|
|
@@ -1458,7 +1514,8 @@ function getShortbreadLayers(option) {
|
|
|
1458
1514
|
id: 'marking-oneway-reverse', // oneway_reverse
|
|
1459
1515
|
type: 'symbol',
|
|
1460
1516
|
'source-layer': 'streets',
|
|
1461
|
-
filter: [
|
|
1517
|
+
filter: [
|
|
1518
|
+
'all',
|
|
1462
1519
|
['==', 'oneway_reverse', true],
|
|
1463
1520
|
['in', 'kind', 'trunk', 'primary', 'secondary', 'tertiary', 'unclassified', 'residential', 'living_street'],
|
|
1464
1521
|
],
|
|
@@ -1475,10 +1532,7 @@ function getShortbreadLayers(option) {
|
|
|
1475
1532
|
id: 'marking-bicycle', // bicycle=designated or kind=cycleway
|
|
1476
1533
|
type: 'symbol',
|
|
1477
1534
|
'source-layer': 'streets',
|
|
1478
|
-
filter: ['all',
|
|
1479
|
-
['==', 'bicycle', 'designated'],
|
|
1480
|
-
['==', 'kind', 'cycleway'],
|
|
1481
|
-
],
|
|
1535
|
+
filter: ['all', ['==', 'bicycle', 'designated'], ['==', 'kind', 'cycleway']],
|
|
1482
1536
|
layout: {
|
|
1483
1537
|
'symbol-placement': 'line',
|
|
1484
1538
|
'symbol-spacing': 50,
|
|
@@ -1503,50 +1557,35 @@ function getShortbreadLayers(option) {
|
|
|
1503
1557
|
id: 'symbol-transit-subway',
|
|
1504
1558
|
type: 'symbol',
|
|
1505
1559
|
'source-layer': 'public_transport',
|
|
1506
|
-
filter: ['all',
|
|
1507
|
-
['in', 'kind', 'station', 'halt'],
|
|
1508
|
-
['==', 'station', 'subway'],
|
|
1509
|
-
],
|
|
1560
|
+
filter: ['all', ['in', 'kind', 'station', 'halt'], ['==', 'station', 'subway']],
|
|
1510
1561
|
layout: { 'text-field': nameField },
|
|
1511
1562
|
},
|
|
1512
1563
|
{
|
|
1513
1564
|
id: 'symbol-transit-lightrail',
|
|
1514
1565
|
type: 'symbol',
|
|
1515
1566
|
'source-layer': 'public_transport',
|
|
1516
|
-
filter: ['all',
|
|
1517
|
-
['in', 'kind', 'station', 'halt'],
|
|
1518
|
-
['==', 'station', 'light_rail'],
|
|
1519
|
-
],
|
|
1567
|
+
filter: ['all', ['in', 'kind', 'station', 'halt'], ['==', 'station', 'light_rail']],
|
|
1520
1568
|
layout: { 'text-field': nameField },
|
|
1521
1569
|
},
|
|
1522
1570
|
{
|
|
1523
1571
|
id: 'symbol-transit-station',
|
|
1524
1572
|
type: 'symbol',
|
|
1525
1573
|
'source-layer': 'public_transport',
|
|
1526
|
-
filter: ['all',
|
|
1527
|
-
['in', 'kind', 'station', 'halt'],
|
|
1528
|
-
['!in', 'station', 'light_rail', 'subway'],
|
|
1529
|
-
],
|
|
1574
|
+
filter: ['all', ['in', 'kind', 'station', 'halt'], ['!in', 'station', 'light_rail', 'subway']],
|
|
1530
1575
|
layout: { 'text-field': nameField },
|
|
1531
1576
|
},
|
|
1532
1577
|
{
|
|
1533
1578
|
id: 'symbol-transit-airfield',
|
|
1534
1579
|
type: 'symbol',
|
|
1535
1580
|
'source-layer': 'public_transport',
|
|
1536
|
-
filter: ['all',
|
|
1537
|
-
['==', 'kind', 'aerodrome'],
|
|
1538
|
-
['!has', 'iata'],
|
|
1539
|
-
],
|
|
1581
|
+
filter: ['all', ['==', 'kind', 'aerodrome'], ['!has', 'iata']],
|
|
1540
1582
|
layout: { 'text-field': nameField },
|
|
1541
1583
|
},
|
|
1542
1584
|
{
|
|
1543
1585
|
id: 'symbol-transit-airport',
|
|
1544
1586
|
type: 'symbol',
|
|
1545
1587
|
'source-layer': 'public_transport',
|
|
1546
|
-
filter: ['all',
|
|
1547
|
-
['==', 'kind', 'aerodrome'],
|
|
1548
|
-
['has', 'iata'],
|
|
1549
|
-
],
|
|
1588
|
+
filter: ['all', ['==', 'kind', 'aerodrome'], ['has', 'iata']],
|
|
1550
1589
|
layout: { 'text-field': nameField },
|
|
1551
1590
|
},
|
|
1552
1591
|
];
|
|
@@ -1915,7 +1954,12 @@ const propertyDefs = [
|
|
|
1915
1954
|
{ parent: 'layout', types: 'symbol', key: 'text-rotation-alignment', valueType: 'enum' },
|
|
1916
1955
|
{ parent: 'layout', types: 'symbol', key: 'text-size', short: 'size', valueType: 'number' },
|
|
1917
1956
|
{ parent: 'layout', types: 'symbol', key: 'text-transform', valueType: 'enum' },
|
|
1918
|
-
{
|
|
1957
|
+
{
|
|
1958
|
+
parent: 'layout',
|
|
1959
|
+
types: 'symbol',
|
|
1960
|
+
key: 'text-variable-anchor-offset',
|
|
1961
|
+
valueType: 'variableAnchorOffsetCollection',
|
|
1962
|
+
},
|
|
1919
1963
|
{ parent: 'layout', types: 'symbol', key: 'text-variable-anchor', valueType: 'array' },
|
|
1920
1964
|
{ parent: 'layout', types: 'symbol', key: 'text-writing-mode', valueType: 'array' },
|
|
1921
1965
|
{ parent: 'paint', types: 'background', key: 'background-color', short: 'color', valueType: 'color' },
|
|
@@ -1996,7 +2040,8 @@ function deepClone(obj) {
|
|
|
1996
2040
|
case 'string':
|
|
1997
2041
|
case 'undefined':
|
|
1998
2042
|
return obj;
|
|
1999
|
-
default:
|
|
2043
|
+
default:
|
|
2044
|
+
throw new Error(`Not implemented yet: "${type}" case`);
|
|
2000
2045
|
}
|
|
2001
2046
|
}
|
|
2002
2047
|
if (isSimpleObject(obj)) {
|
|
@@ -2010,9 +2055,7 @@ function deepClone(obj) {
|
|
|
2010
2055
|
}
|
|
2011
2056
|
if (obj == null)
|
|
2012
2057
|
return obj;
|
|
2013
|
-
|
|
2014
|
-
console.log('obj.prototype', Object.getPrototypeOf(obj));
|
|
2015
|
-
throw Error();
|
|
2058
|
+
throw new Error(`deepClone: Unsupported object type "${Object.getPrototypeOf(obj)?.constructor?.name ?? 'unknown'}"`);
|
|
2016
2059
|
}
|
|
2017
2060
|
function isSimpleObject(item) {
|
|
2018
2061
|
if (item === null)
|
|
@@ -2038,7 +2081,7 @@ function isBasicType(item) {
|
|
|
2038
2081
|
case 'object':
|
|
2039
2082
|
return false;
|
|
2040
2083
|
default:
|
|
2041
|
-
throw Error(
|
|
2084
|
+
throw new Error(`isBasicType: Unknown type "${typeof item}"`);
|
|
2042
2085
|
}
|
|
2043
2086
|
}
|
|
2044
2087
|
function deepMerge(source0, ...sources) {
|
|
@@ -2050,9 +2093,7 @@ function deepMerge(source0, ...sources) {
|
|
|
2050
2093
|
if (!(key in source))
|
|
2051
2094
|
continue;
|
|
2052
2095
|
const sourceValue = source[key];
|
|
2053
|
-
//
|
|
2054
|
-
// overwrite
|
|
2055
|
-
// *********
|
|
2096
|
+
// Handle basic types (number, string, boolean) - always overwrite
|
|
2056
2097
|
switch (typeof sourceValue) {
|
|
2057
2098
|
case 'number':
|
|
2058
2099
|
case 'string':
|
|
@@ -2060,28 +2101,23 @@ function deepMerge(source0, ...sources) {
|
|
|
2060
2101
|
target[key] = sourceValue;
|
|
2061
2102
|
continue;
|
|
2062
2103
|
}
|
|
2104
|
+
// If target is a basic type, overwrite with deep clone of source
|
|
2063
2105
|
if (isBasicType(target[key])) {
|
|
2064
2106
|
target[key] = deepClone(sourceValue);
|
|
2065
2107
|
continue;
|
|
2066
2108
|
}
|
|
2109
|
+
// Handle Color instances - clone the source color
|
|
2067
2110
|
if (sourceValue instanceof Color) {
|
|
2068
2111
|
target[key] = sourceValue.clone();
|
|
2069
2112
|
continue;
|
|
2070
2113
|
}
|
|
2114
|
+
// If both are simple objects, merge them recursively
|
|
2071
2115
|
if (isSimpleObject(target[key]) && isSimpleObject(sourceValue)) {
|
|
2072
2116
|
target[key] = deepMerge(target[key], sourceValue);
|
|
2073
2117
|
continue;
|
|
2074
2118
|
}
|
|
2075
|
-
//
|
|
2076
|
-
|
|
2077
|
-
// *********
|
|
2078
|
-
if (isSimpleObject(target[key]) && isSimpleObject(sourceValue)) {
|
|
2079
|
-
target[key] = deepMerge(target[key], sourceValue);
|
|
2080
|
-
continue;
|
|
2081
|
-
}
|
|
2082
|
-
console.log('target[key]:', target[key]);
|
|
2083
|
-
console.log('source[key]:', source[key]);
|
|
2084
|
-
throw Error('unpredicted case');
|
|
2119
|
+
// Incompatible types - throw error
|
|
2120
|
+
throw new Error(`deepMerge: Cannot merge incompatible types for key "${String(key)}" (target: ${typeof target[key]}, source: ${typeof sourceValue})`);
|
|
2085
2121
|
}
|
|
2086
2122
|
}
|
|
2087
2123
|
return target;
|
|
@@ -2108,7 +2144,7 @@ function basename(url) {
|
|
|
2108
2144
|
}
|
|
2109
2145
|
|
|
2110
2146
|
function decorate(layers, rules, recolor) {
|
|
2111
|
-
const layerIds = layers.map(l => l.id);
|
|
2147
|
+
const layerIds = layers.map((l) => l.id);
|
|
2112
2148
|
const layerIdSet = new Set(layerIds);
|
|
2113
2149
|
// Initialize a new map to hold final styles for layers
|
|
2114
2150
|
const layerStyles = new Map();
|
|
@@ -2117,25 +2153,25 @@ function decorate(layers, rules, recolor) {
|
|
|
2117
2153
|
if (layerStyle == null)
|
|
2118
2154
|
return;
|
|
2119
2155
|
// Expand any braces in IDs and filter them through a RegExp if necessary
|
|
2120
|
-
const ids = expandTop(idDef).flatMap(id => {
|
|
2156
|
+
const ids = expandTop(idDef).flatMap((id) => {
|
|
2121
2157
|
if (!id.includes('*'))
|
|
2122
2158
|
return id;
|
|
2123
|
-
const regExpString = id.replace(/[^a-z_:-]/g, c => {
|
|
2159
|
+
const regExpString = id.replace(/[^a-z_:-]/g, (c) => {
|
|
2124
2160
|
if (c === '*')
|
|
2125
2161
|
return '[a-z_-]*';
|
|
2126
|
-
throw new Error(
|
|
2162
|
+
throw new Error(`decorator: Invalid character ${JSON.stringify(c)} in layer ID pattern "${id}". Only alphanumeric, underscore, colon, hyphen, and asterisk are allowed.`);
|
|
2127
2163
|
});
|
|
2128
2164
|
const regExp = new RegExp(`^${regExpString}$`, 'i');
|
|
2129
|
-
return layerIds.filter(layerId => regExp.test(layerId));
|
|
2165
|
+
return layerIds.filter((layerId) => regExp.test(layerId));
|
|
2130
2166
|
});
|
|
2131
|
-
ids.forEach(id => {
|
|
2167
|
+
ids.forEach((id) => {
|
|
2132
2168
|
if (!layerIdSet.has(id))
|
|
2133
2169
|
return;
|
|
2134
2170
|
layerStyles.set(id, deepMerge(layerStyles.get(id) ?? {}, layerStyle));
|
|
2135
2171
|
});
|
|
2136
2172
|
});
|
|
2137
2173
|
// Deep clone the original layers and apply styles
|
|
2138
|
-
return layers.flatMap(layer => {
|
|
2174
|
+
return layers.flatMap((layer) => {
|
|
2139
2175
|
// Get the id and style of the layer
|
|
2140
2176
|
const layerStyle = layerStyles.get(layer.id);
|
|
2141
2177
|
// Don't export layers that have no style
|
|
@@ -2150,11 +2186,11 @@ function decorate(layers, rules, recolor) {
|
|
|
2150
2186
|
if (ruleValue == null)
|
|
2151
2187
|
continue;
|
|
2152
2188
|
// CamelCase to not-camel-case
|
|
2153
|
-
const ruleKey = ruleKeyCamelCase.replace(/[A-Z]/g, c => '-' + c.toLowerCase());
|
|
2189
|
+
const ruleKey = ruleKeyCamelCase.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase());
|
|
2154
2190
|
const propertyDefs = propertyLookup.get(layer.type + '/' + ruleKey);
|
|
2155
2191
|
if (!propertyDefs)
|
|
2156
2192
|
continue;
|
|
2157
|
-
propertyDefs.forEach(propertyDef => {
|
|
2193
|
+
propertyDefs.forEach((propertyDef) => {
|
|
2158
2194
|
const { key } = propertyDef;
|
|
2159
2195
|
let value = ruleValue;
|
|
2160
2196
|
switch (propertyDef.valueType) {
|
|
@@ -2172,27 +2208,25 @@ function decorate(layers, rules, recolor) {
|
|
|
2172
2208
|
case 'number':
|
|
2173
2209
|
value = processExpression(value);
|
|
2174
2210
|
break;
|
|
2175
|
-
default:
|
|
2211
|
+
default:
|
|
2212
|
+
throw new Error(`decorator: Unknown property value type "${propertyDef.valueType}" for key "${key}" on layer type "${layer.type}". This may indicate a MapLibre property definition mismatch.`);
|
|
2176
2213
|
}
|
|
2177
2214
|
switch (propertyDef.parent) {
|
|
2178
2215
|
case 'layer':
|
|
2179
|
-
// @ts-expect-error: too complex to handle
|
|
2180
2216
|
layer[key] = value;
|
|
2181
2217
|
break;
|
|
2182
2218
|
case 'layout':
|
|
2183
2219
|
if (!layer.layout)
|
|
2184
2220
|
layer.layout = {};
|
|
2185
|
-
// @ts-expect-error: too complex to handle
|
|
2186
2221
|
layer.layout[key] = value;
|
|
2187
2222
|
break;
|
|
2188
2223
|
case 'paint':
|
|
2189
2224
|
if (!layer.paint)
|
|
2190
2225
|
layer.paint = {};
|
|
2191
|
-
// @ts-expect-error: too complex to handle
|
|
2192
2226
|
layer.paint[key] = value;
|
|
2193
2227
|
break;
|
|
2194
2228
|
default:
|
|
2195
|
-
throw new Error(`
|
|
2229
|
+
throw new Error(`decorator: Unknown property parent "${propertyDef.parent}" for key "${key}" on layer type "${layer.type}". Expected "layer", "layout", or "paint".`);
|
|
2196
2230
|
}
|
|
2197
2231
|
});
|
|
2198
2232
|
}
|
|
@@ -2203,12 +2237,12 @@ function decorate(layers, rules, recolor) {
|
|
|
2203
2237
|
const color = recolor.do(value);
|
|
2204
2238
|
return color.asString();
|
|
2205
2239
|
}
|
|
2206
|
-
throw new Error(`
|
|
2240
|
+
throw new Error(`decorator.processColor: Expected a color string or Color instance, but got ${typeof value}. Value: ${JSON.stringify(value)}`);
|
|
2207
2241
|
}
|
|
2208
2242
|
function processFont(value) {
|
|
2209
2243
|
if (typeof value === 'string')
|
|
2210
2244
|
return [value];
|
|
2211
|
-
throw new Error(`
|
|
2245
|
+
throw new Error(`decorator.processFont: Expected a font name string, but got ${typeof value}. Value: ${JSON.stringify(value)}`);
|
|
2212
2246
|
}
|
|
2213
2247
|
function processExpression(value, cbValue) {
|
|
2214
2248
|
if (typeof value === 'object') {
|
|
@@ -2255,7 +2289,7 @@ function getDefaultRecolorFlags() {
|
|
|
2255
2289
|
* Checks if the given options object contains any active recolor transformations.
|
|
2256
2290
|
* @param opt The recolor options to validate.
|
|
2257
2291
|
*/
|
|
2258
|
-
function
|
|
2292
|
+
function hasActiveRecolorOptions(opt) {
|
|
2259
2293
|
if (!opt)
|
|
2260
2294
|
return false;
|
|
2261
2295
|
return (opt.invertBrightness ||
|
|
@@ -2276,14 +2310,20 @@ class CachedRecolor {
|
|
|
2276
2310
|
skip;
|
|
2277
2311
|
opt;
|
|
2278
2312
|
cache;
|
|
2313
|
+
parsedTintColor;
|
|
2314
|
+
parsedBlendColor;
|
|
2279
2315
|
/**
|
|
2280
2316
|
* Creates a cached recolor instance.
|
|
2281
2317
|
* @param opt Optional recolor options.
|
|
2282
2318
|
*/
|
|
2283
2319
|
constructor(opt) {
|
|
2284
|
-
this.skip = !
|
|
2320
|
+
this.skip = !hasActiveRecolorOptions(opt);
|
|
2285
2321
|
this.cache = new Map();
|
|
2286
2322
|
this.opt = opt;
|
|
2323
|
+
if (opt?.tint && opt.tintColor != null)
|
|
2324
|
+
this.parsedTintColor = Color.parse(opt.tintColor);
|
|
2325
|
+
if (opt?.blend && opt.blendColor != null)
|
|
2326
|
+
this.parsedBlendColor = Color.parse(opt.blendColor);
|
|
2287
2327
|
}
|
|
2288
2328
|
/**
|
|
2289
2329
|
* Applies cached recoloring to a given color.
|
|
@@ -2296,7 +2336,7 @@ class CachedRecolor {
|
|
|
2296
2336
|
const key = color.asHex();
|
|
2297
2337
|
if (this.cache.has(key))
|
|
2298
2338
|
return this.cache.get(key);
|
|
2299
|
-
const recolored = recolor(color, this.opt);
|
|
2339
|
+
const recolored = recolor(color, this.opt, this.parsedTintColor, this.parsedBlendColor);
|
|
2300
2340
|
this.cache.set(key, recolored);
|
|
2301
2341
|
return recolored;
|
|
2302
2342
|
}
|
|
@@ -2305,10 +2345,12 @@ class CachedRecolor {
|
|
|
2305
2345
|
* Applies the specified recoloring transformations to a single color.
|
|
2306
2346
|
* @param color The original color.
|
|
2307
2347
|
* @param opt Optional recolor options.
|
|
2348
|
+
* @param parsedTintColor Optional pre-parsed tint color to avoid repeated parsing.
|
|
2349
|
+
* @param parsedBlendColor Optional pre-parsed blend color to avoid repeated parsing.
|
|
2308
2350
|
* @returns A new `Color` instance with applied transformations.
|
|
2309
2351
|
*/
|
|
2310
|
-
function recolor(color, opt) {
|
|
2311
|
-
if (!
|
|
2352
|
+
function recolor(color, opt, parsedTintColor, parsedBlendColor) {
|
|
2353
|
+
if (!hasActiveRecolorOptions(opt))
|
|
2312
2354
|
return color;
|
|
2313
2355
|
if (opt.invertBrightness)
|
|
2314
2356
|
color = color.invertLuminosity();
|
|
@@ -2316,35 +2358,77 @@ function recolor(color, opt) {
|
|
|
2316
2358
|
color = color.rotateHue(opt.rotate);
|
|
2317
2359
|
if (opt.saturate)
|
|
2318
2360
|
color = color.saturate(opt.saturate);
|
|
2319
|
-
if (opt.gamma != null && opt.gamma
|
|
2361
|
+
if (opt.gamma != null && opt.gamma !== 1)
|
|
2320
2362
|
color = color.gamma(opt.gamma);
|
|
2321
|
-
if (opt.contrast != null && opt.contrast
|
|
2363
|
+
if (opt.contrast != null && opt.contrast !== 1)
|
|
2322
2364
|
color = color.contrast(opt.contrast);
|
|
2323
2365
|
if (opt.brightness)
|
|
2324
2366
|
color = color.brightness(opt.brightness);
|
|
2325
2367
|
if (opt.tint && opt.tintColor != null)
|
|
2326
|
-
color = color.tint(opt.tint, Color.parse(opt.tintColor));
|
|
2368
|
+
color = color.tint(opt.tint, parsedTintColor ?? Color.parse(opt.tintColor));
|
|
2327
2369
|
if (opt.blend && opt.blendColor != null)
|
|
2328
|
-
color = color.blend(opt.blend, Color.parse(opt.blendColor));
|
|
2370
|
+
color = color.blend(opt.blend, parsedBlendColor ?? Color.parse(opt.blendColor));
|
|
2329
2371
|
return color;
|
|
2330
2372
|
}
|
|
2331
2373
|
|
|
2332
|
-
const styleBuilderColorKeys = [
|
|
2374
|
+
const styleBuilderColorKeys = [
|
|
2375
|
+
'agriculture',
|
|
2376
|
+
'boundary',
|
|
2377
|
+
'building',
|
|
2378
|
+
'buildingbg',
|
|
2379
|
+
'burial',
|
|
2380
|
+
'commercial',
|
|
2381
|
+
'construction',
|
|
2382
|
+
'cycle',
|
|
2383
|
+
'danger',
|
|
2384
|
+
'disputed',
|
|
2385
|
+
'education',
|
|
2386
|
+
'foot',
|
|
2387
|
+
'glacier',
|
|
2388
|
+
'grass',
|
|
2389
|
+
'hospital',
|
|
2390
|
+
'industrial',
|
|
2391
|
+
'label',
|
|
2392
|
+
'labelHalo',
|
|
2393
|
+
'land',
|
|
2394
|
+
'leisure',
|
|
2395
|
+
'motorway',
|
|
2396
|
+
'motorwaybg',
|
|
2397
|
+
'park',
|
|
2398
|
+
'parking',
|
|
2399
|
+
'poi',
|
|
2400
|
+
'prison',
|
|
2401
|
+
'rail',
|
|
2402
|
+
'residential',
|
|
2403
|
+
'rock',
|
|
2404
|
+
'sand',
|
|
2405
|
+
'shield',
|
|
2406
|
+
'street',
|
|
2407
|
+
'streetbg',
|
|
2408
|
+
'subway',
|
|
2409
|
+
'symbol',
|
|
2410
|
+
'trunk',
|
|
2411
|
+
'trunkbg',
|
|
2412
|
+
'waste',
|
|
2413
|
+
'water',
|
|
2414
|
+
'wetland',
|
|
2415
|
+
'wood',
|
|
2416
|
+
];
|
|
2333
2417
|
|
|
2334
2418
|
// StyleBuilder class definition
|
|
2335
2419
|
class StyleBuilder {
|
|
2336
2420
|
#sourceName = 'versatiles-shortbread';
|
|
2337
2421
|
build(options) {
|
|
2338
2422
|
options ??= {};
|
|
2339
|
-
|
|
2340
|
-
const baseUrl = options.baseUrl ??
|
|
2341
|
-
const glyphs = options.glyphs ??
|
|
2342
|
-
const sprite = options.sprite ??
|
|
2343
|
-
const tiles = options.tiles ??
|
|
2344
|
-
const bounds = options.bounds ??
|
|
2345
|
-
const hideLabels = options.hideLabels ??
|
|
2346
|
-
const language = options.language ??
|
|
2347
|
-
const recolorOptions = options.recolor ??
|
|
2423
|
+
const defaults = this.getDefaultOptions();
|
|
2424
|
+
const baseUrl = options.baseUrl ?? defaults.baseUrl;
|
|
2425
|
+
const glyphs = options.glyphs ?? defaults.glyphs;
|
|
2426
|
+
const sprite = options.sprite ?? defaults.sprite;
|
|
2427
|
+
const tiles = options.tiles ?? defaults.tiles;
|
|
2428
|
+
const bounds = options.bounds ?? defaults.bounds;
|
|
2429
|
+
const hideLabels = options.hideLabels ?? defaults.hideLabels;
|
|
2430
|
+
const language = options.language ?? defaults.language;
|
|
2431
|
+
const recolorOptions = options.recolor ?? defaults.recolor;
|
|
2348
2432
|
const colors = this.getColors(this.defaultColors);
|
|
2349
2433
|
if (options.colors) {
|
|
2350
2434
|
let key;
|
|
@@ -2374,8 +2458,9 @@ class StyleBuilder {
|
|
|
2374
2458
|
const layerStyleRules = this.getStyleRules(styleRuleOptions);
|
|
2375
2459
|
// get shortbread layers
|
|
2376
2460
|
const layerDefinitions = getShortbreadLayers({ language });
|
|
2377
|
-
let layers = layerDefinitions.map(layer => {
|
|
2378
|
-
|
|
2461
|
+
let layers = layerDefinitions.map((layer) => {
|
|
2462
|
+
const { type, id } = layer;
|
|
2463
|
+
switch (type) {
|
|
2379
2464
|
case 'background':
|
|
2380
2465
|
return layer;
|
|
2381
2466
|
case 'fill':
|
|
@@ -2386,17 +2471,17 @@ class StyleBuilder {
|
|
|
2386
2471
|
...layer,
|
|
2387
2472
|
};
|
|
2388
2473
|
}
|
|
2389
|
-
throw Error(
|
|
2474
|
+
throw new Error(`StyleBuilder: Unknown layer type "${type}" for layer "${id}". Expected "background", "fill", "line", or "symbol".`);
|
|
2390
2475
|
});
|
|
2391
2476
|
// apply layer rules
|
|
2392
2477
|
layers = decorate(layers, layerStyleRules, new CachedRecolor(recolorOptions));
|
|
2393
2478
|
// hide labels, if wanted
|
|
2394
2479
|
if (hideLabels)
|
|
2395
|
-
layers = layers.filter(l => l.type !== 'symbol');
|
|
2480
|
+
layers = layers.filter((l) => l.type !== 'symbol');
|
|
2396
2481
|
style.layers = layers;
|
|
2397
2482
|
style.name = 'versatiles-' + this.name.toLowerCase();
|
|
2398
2483
|
style.glyphs = resolveUrl(baseUrl, glyphs);
|
|
2399
|
-
if (typeof sprite
|
|
2484
|
+
if (typeof sprite === 'string') {
|
|
2400
2485
|
style.sprite = [{ id: basename(sprite), url: resolveUrl(baseUrl, sprite) }];
|
|
2401
2486
|
}
|
|
2402
2487
|
else {
|
|
@@ -2404,7 +2489,7 @@ class StyleBuilder {
|
|
|
2404
2489
|
}
|
|
2405
2490
|
const source = style.sources[this.#sourceName];
|
|
2406
2491
|
if ('tiles' in source)
|
|
2407
|
-
source.tiles = tiles.map(url => resolveUrl(baseUrl, url));
|
|
2492
|
+
source.tiles = tiles.map((url) => resolveUrl(baseUrl, url));
|
|
2408
2493
|
if ('bounds' in source)
|
|
2409
2494
|
source.bounds = bounds;
|
|
2410
2495
|
return style;
|
|
@@ -2416,18 +2501,14 @@ class StyleBuilder {
|
|
|
2416
2501
|
}
|
|
2417
2502
|
getDefaultOptions() {
|
|
2418
2503
|
return {
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
],
|
|
2426
|
-
glyphs: '',
|
|
2427
|
-
sprite: '',
|
|
2428
|
-
tiles: [],
|
|
2504
|
+
// @ts-expect-error globalThis may be undefined in some environments
|
|
2505
|
+
baseUrl: globalThis?.document?.location?.origin ?? 'https://tiles.versatiles.org',
|
|
2506
|
+
bounds: [-180, -85.0511287798066, 180, 85.0511287798066],
|
|
2507
|
+
glyphs: '/assets/glyphs/{fontstack}/{range}.pbf',
|
|
2508
|
+
sprite: [{ id: 'basics', url: '/assets/sprites/basics/sprites' }],
|
|
2509
|
+
tiles: ['/tiles/osm/{z}/{x}/{y}'],
|
|
2429
2510
|
hideLabels: false,
|
|
2430
|
-
language:
|
|
2511
|
+
language: '',
|
|
2431
2512
|
colors: deepClone(this.defaultColors),
|
|
2432
2513
|
fonts: deepClone(this.defaultFonts),
|
|
2433
2514
|
recolor: getDefaultRecolorFlags(),
|
|
@@ -2535,7 +2616,7 @@ class Colorful extends StyleBuilder {
|
|
|
2535
2616
|
const { colors, fonts } = options;
|
|
2536
2617
|
return {
|
|
2537
2618
|
// background
|
|
2538
|
-
|
|
2619
|
+
background: {
|
|
2539
2620
|
color: colors.land,
|
|
2540
2621
|
},
|
|
2541
2622
|
// boundary
|
|
@@ -2689,7 +2770,8 @@ class Colorful extends StyleBuilder {
|
|
|
2689
2770
|
color: colors.buildingbg,
|
|
2690
2771
|
opacity: { 14: 0, 15: 1 },
|
|
2691
2772
|
},
|
|
2692
|
-
|
|
2773
|
+
building: {
|
|
2774
|
+
// fake 2.5d with translate
|
|
2693
2775
|
color: colors.building,
|
|
2694
2776
|
opacity: { 14: 0, 15: 1 },
|
|
2695
2777
|
fillTranslate: [-2, -2],
|
|
@@ -2722,7 +2804,7 @@ class Colorful extends StyleBuilder {
|
|
|
2722
2804
|
opacity: { 13: 0, 14: 1 },
|
|
2723
2805
|
},
|
|
2724
2806
|
// bridge
|
|
2725
|
-
|
|
2807
|
+
bridge: {
|
|
2726
2808
|
color: colors.land.darken(0.02),
|
|
2727
2809
|
fillAntialias: true,
|
|
2728
2810
|
opacity: 0.8,
|
|
@@ -2768,37 +2850,37 @@ class Colorful extends StyleBuilder {
|
|
|
2768
2850
|
opacity: 0.5,
|
|
2769
2851
|
},
|
|
2770
2852
|
'bridge-street-motorway:bridge': {
|
|
2771
|
-
size: { '5': 0, '6': 3, '10': 7, '14': 7, '16': 20, '18': 53, '19': 118, '20': 235 }
|
|
2853
|
+
size: { '5': 0, '6': 3, '10': 7, '14': 7, '16': 20, '18': 53, '19': 118, '20': 235 },
|
|
2772
2854
|
},
|
|
2773
2855
|
'bridge-street-trunk:bridge': {
|
|
2774
|
-
size: { '7': 0, '8': 3, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 }
|
|
2856
|
+
size: { '7': 0, '8': 3, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 },
|
|
2775
2857
|
},
|
|
2776
2858
|
'bridge-street-primary:bridge': {
|
|
2777
|
-
size: { '8': 0, '9': 1, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 }
|
|
2859
|
+
size: { '8': 0, '9': 1, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 },
|
|
2778
2860
|
},
|
|
2779
2861
|
'bridge-street-secondary:bridge': {
|
|
2780
2862
|
size: { '11': 3, '14': 7, '16': 11, '18': 42, '19': 95, '20': 193 },
|
|
2781
|
-
opacity: { '11': 0, '12': 1 }
|
|
2863
|
+
opacity: { '11': 0, '12': 1 },
|
|
2782
2864
|
},
|
|
2783
2865
|
'bridge-street-motorway-link:bridge': {
|
|
2784
2866
|
minzoom: 12,
|
|
2785
|
-
size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 }
|
|
2867
|
+
size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 },
|
|
2786
2868
|
},
|
|
2787
2869
|
'bridge-street-{trunk,primary,secondary}-link:bridge': {
|
|
2788
2870
|
minzoom: 13,
|
|
2789
|
-
size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 }
|
|
2871
|
+
size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 },
|
|
2790
2872
|
},
|
|
2791
2873
|
'bridge-street-{tertiary,tertiary-link,unclassified,residential,livingstreet,pedestrian}*:bridge': {
|
|
2792
2874
|
size: { '12': 3, '14': 4, '16': 8, '18': 36, '19': 90, '20': 179 },
|
|
2793
|
-
opacity: { '12': 0, '13': 1 }
|
|
2875
|
+
opacity: { '12': 0, '13': 1 },
|
|
2794
2876
|
},
|
|
2795
2877
|
'bridge-street-{service,track}:bridge': {
|
|
2796
2878
|
size: { '14': 3, '16': 6, '18': 25, '19': 67, '20': 134 },
|
|
2797
|
-
opacity: { '14': 0, '15': 1 }
|
|
2879
|
+
opacity: { '14': 0, '15': 1 },
|
|
2798
2880
|
},
|
|
2799
2881
|
'bridge-way-*:bridge': {
|
|
2800
2882
|
size: { '15': 0, '16': 7, '18': 10, '19': 17, '20': 31 },
|
|
2801
|
-
minzoom: 15
|
|
2883
|
+
minzoom: 15,
|
|
2802
2884
|
},
|
|
2803
2885
|
// special color: motorway
|
|
2804
2886
|
'{bridge-,}street-motorway{-link,}:outline': {
|
|
@@ -3228,177 +3310,285 @@ class Colorful extends StyleBuilder {
|
|
|
3228
3310
|
color: colors.poi,
|
|
3229
3311
|
},
|
|
3230
3312
|
'poi-amenity': {
|
|
3231
|
-
image: [
|
|
3313
|
+
image: [
|
|
3314
|
+
'match',
|
|
3232
3315
|
['get', 'amenity'],
|
|
3233
|
-
'arts_centre',
|
|
3234
|
-
'
|
|
3235
|
-
'
|
|
3236
|
-
'
|
|
3237
|
-
'
|
|
3238
|
-
'
|
|
3239
|
-
'
|
|
3240
|
-
'
|
|
3241
|
-
'
|
|
3242
|
-
'
|
|
3243
|
-
'
|
|
3244
|
-
'
|
|
3316
|
+
'arts_centre',
|
|
3317
|
+
'basics:icon-art_gallery',
|
|
3318
|
+
'atm',
|
|
3319
|
+
'basics:icon-atm',
|
|
3320
|
+
'bank',
|
|
3321
|
+
'basics:icon-bank',
|
|
3322
|
+
'bar',
|
|
3323
|
+
'basics:icon-bar',
|
|
3324
|
+
'bench',
|
|
3325
|
+
'basics:icon-bench',
|
|
3326
|
+
'bicycle_rental',
|
|
3327
|
+
'basics:icon-bicycle_share',
|
|
3328
|
+
'biergarten',
|
|
3329
|
+
'basics:icon-beergarden',
|
|
3330
|
+
'cafe',
|
|
3331
|
+
'basics:icon-cafe',
|
|
3332
|
+
'car_rental',
|
|
3333
|
+
'basics:icon-car_rental',
|
|
3334
|
+
'car_sharing',
|
|
3335
|
+
'basics:icon-car_rental',
|
|
3336
|
+
'car_wash',
|
|
3337
|
+
'basics:icon-car_wash',
|
|
3338
|
+
'cinema',
|
|
3339
|
+
'basics:icon-cinema',
|
|
3245
3340
|
//'clinic', 'basics:icon-clinic',
|
|
3246
|
-
'college',
|
|
3247
|
-
'
|
|
3341
|
+
'college',
|
|
3342
|
+
'basics:icon-college',
|
|
3343
|
+
'community_centre',
|
|
3344
|
+
'basics:icon-community',
|
|
3248
3345
|
//'courthouse', 'basics:icon-courthouse',
|
|
3249
|
-
'dentist',
|
|
3250
|
-
'
|
|
3251
|
-
'
|
|
3252
|
-
'
|
|
3253
|
-
'
|
|
3254
|
-
'
|
|
3255
|
-
'
|
|
3346
|
+
'dentist',
|
|
3347
|
+
'basics:icon-dentist',
|
|
3348
|
+
'doctors',
|
|
3349
|
+
'basics:icon-doctor',
|
|
3350
|
+
'dog_park',
|
|
3351
|
+
'basics:icon-dog_park',
|
|
3352
|
+
'drinking_water',
|
|
3353
|
+
'basics:icon-drinking_water',
|
|
3354
|
+
'embassy',
|
|
3355
|
+
'basics:icon-embassy',
|
|
3356
|
+
'fast_food',
|
|
3357
|
+
'basics:icon-fast_food',
|
|
3358
|
+
'fire_station',
|
|
3359
|
+
'basics:icon-fire_station',
|
|
3256
3360
|
//'food_court', 'basics:icon-food_court',
|
|
3257
|
-
'fountain',
|
|
3258
|
-
'
|
|
3259
|
-
'
|
|
3260
|
-
'
|
|
3261
|
-
'
|
|
3262
|
-
'
|
|
3263
|
-
'
|
|
3264
|
-
'
|
|
3265
|
-
'
|
|
3266
|
-
'
|
|
3267
|
-
'
|
|
3268
|
-
'
|
|
3269
|
-
'
|
|
3270
|
-
'
|
|
3271
|
-
'
|
|
3272
|
-
'
|
|
3361
|
+
'fountain',
|
|
3362
|
+
'basics:icon-fountain',
|
|
3363
|
+
'grave_yard',
|
|
3364
|
+
'basics:icon-cemetery',
|
|
3365
|
+
'hospital',
|
|
3366
|
+
'basics:icon-hospital',
|
|
3367
|
+
'hunting_stand',
|
|
3368
|
+
'basics:icon-huntingstand',
|
|
3369
|
+
'library',
|
|
3370
|
+
'basics:icon-library',
|
|
3371
|
+
'marketplace',
|
|
3372
|
+
'basics:icon-marketplace',
|
|
3373
|
+
'nightclub',
|
|
3374
|
+
'basics:icon-nightclub',
|
|
3375
|
+
'nursing_home',
|
|
3376
|
+
'basics:icon-nursinghome',
|
|
3377
|
+
'pharmacy',
|
|
3378
|
+
'basics:icon-pharmacy',
|
|
3379
|
+
'place_of_worship',
|
|
3380
|
+
'basics:icon-place_of_worship',
|
|
3381
|
+
'playground',
|
|
3382
|
+
'basics:icon-playground',
|
|
3383
|
+
'police',
|
|
3384
|
+
'basics:icon-police',
|
|
3385
|
+
'post_box',
|
|
3386
|
+
'basics:icon-postbox',
|
|
3387
|
+
'post_office',
|
|
3388
|
+
'basics:icon-post',
|
|
3389
|
+
'prison',
|
|
3390
|
+
'basics:icon-prison',
|
|
3391
|
+
'pub',
|
|
3392
|
+
'basics:icon-beer',
|
|
3273
3393
|
//'public_building', 'basics:icon-public_building',
|
|
3274
|
-
'recycling',
|
|
3275
|
-
'
|
|
3276
|
-
'
|
|
3277
|
-
'
|
|
3278
|
-
'
|
|
3279
|
-
'
|
|
3280
|
-
'
|
|
3281
|
-
'
|
|
3394
|
+
'recycling',
|
|
3395
|
+
'basics:icon-recycling',
|
|
3396
|
+
'restaurant',
|
|
3397
|
+
'basics:icon-restaurant',
|
|
3398
|
+
'school',
|
|
3399
|
+
'basics:icon-school',
|
|
3400
|
+
'shelter',
|
|
3401
|
+
'basics:icon-shelter',
|
|
3402
|
+
'telephone',
|
|
3403
|
+
'basics:icon-telephone',
|
|
3404
|
+
'theatre',
|
|
3405
|
+
'basics:icon-theatre',
|
|
3406
|
+
'toilets',
|
|
3407
|
+
'basics:icon-toilet',
|
|
3408
|
+
'townhall',
|
|
3409
|
+
'basics:icon-town_hall',
|
|
3282
3410
|
//'university', 'basics:icon-university',
|
|
3283
|
-
'vending_machine',
|
|
3284
|
-
'
|
|
3285
|
-
'
|
|
3411
|
+
'vending_machine',
|
|
3412
|
+
'basics:icon-vendingmachine',
|
|
3413
|
+
'veterinary',
|
|
3414
|
+
'basics:icon-veterinary',
|
|
3415
|
+
'waste_basket',
|
|
3416
|
+
'basics:icon-waste_basket',
|
|
3286
3417
|
'',
|
|
3287
3418
|
],
|
|
3288
3419
|
},
|
|
3289
3420
|
'poi-leisure': {
|
|
3290
|
-
image: [
|
|
3421
|
+
image: [
|
|
3422
|
+
'match',
|
|
3291
3423
|
['get', 'leisure'],
|
|
3292
|
-
'golf_course',
|
|
3293
|
-
'
|
|
3294
|
-
'
|
|
3424
|
+
'golf_course',
|
|
3425
|
+
'basics:icon-golf',
|
|
3426
|
+
'ice_rink',
|
|
3427
|
+
'basics:icon-icerink',
|
|
3428
|
+
'pitch',
|
|
3429
|
+
'basics:icon-pitch',
|
|
3295
3430
|
//'sports_centre', 'basics:icon-sports_centre',
|
|
3296
|
-
'stadium',
|
|
3297
|
-
'
|
|
3298
|
-
'
|
|
3431
|
+
'stadium',
|
|
3432
|
+
'basics:icon-stadium',
|
|
3433
|
+
'swimming_pool',
|
|
3434
|
+
'basics:icon-swimming',
|
|
3435
|
+
'water_park',
|
|
3436
|
+
'basics:icon-waterpark',
|
|
3299
3437
|
'basics:icon-sports',
|
|
3300
3438
|
],
|
|
3301
3439
|
},
|
|
3302
3440
|
'poi-tourism': {
|
|
3303
|
-
image: [
|
|
3441
|
+
image: [
|
|
3442
|
+
'match',
|
|
3304
3443
|
['get', 'tourism'],
|
|
3305
3444
|
//'alpine_hut', 'basics:icon-alpine_hut',
|
|
3306
3445
|
//'bed_and_breakfast', 'basics:icon-bed_and_breakfast',
|
|
3307
3446
|
//'camp_site', 'basics:icon-camp_site',
|
|
3308
3447
|
//'caravan_site', 'basics:icon-caravan_site',
|
|
3309
|
-
'chalet',
|
|
3448
|
+
'chalet',
|
|
3449
|
+
'basics:icon-chalet',
|
|
3310
3450
|
//'guest_house', 'basics:icon-guest_house',
|
|
3311
3451
|
//'hostel', 'basics:icon-hostel',
|
|
3312
3452
|
//'hotel', 'basics:icon-hotel',
|
|
3313
|
-
'information',
|
|
3453
|
+
'information',
|
|
3454
|
+
'basics:transport-information',
|
|
3314
3455
|
//'motel', 'basics:icon-motel',
|
|
3315
|
-
'picnic_site',
|
|
3456
|
+
'picnic_site',
|
|
3457
|
+
'basics:icon-picnic_site',
|
|
3316
3458
|
//'theme_park', 'basics:icon-theme_park',
|
|
3317
|
-
'viewpoint',
|
|
3318
|
-
'
|
|
3459
|
+
'viewpoint',
|
|
3460
|
+
'basics:icon-viewpoint',
|
|
3461
|
+
'zoo',
|
|
3462
|
+
'basics:icon-zoo',
|
|
3319
3463
|
'',
|
|
3320
3464
|
],
|
|
3321
3465
|
},
|
|
3322
3466
|
'poi-shop': {
|
|
3323
|
-
image: [
|
|
3467
|
+
image: [
|
|
3468
|
+
'match',
|
|
3324
3469
|
['get', 'shop'],
|
|
3325
|
-
'alcohol',
|
|
3326
|
-
'
|
|
3327
|
-
'
|
|
3328
|
-
'
|
|
3470
|
+
'alcohol',
|
|
3471
|
+
'basics:icon-alcohol_shop',
|
|
3472
|
+
'bakery',
|
|
3473
|
+
'basics:icon-bakery',
|
|
3474
|
+
'beauty',
|
|
3475
|
+
'basics:icon-beauty',
|
|
3476
|
+
'beverages',
|
|
3477
|
+
'basics:icon-beverages',
|
|
3329
3478
|
//'bicycle', 'basics:icon-bicycle',
|
|
3330
|
-
'books',
|
|
3331
|
-
'
|
|
3479
|
+
'books',
|
|
3480
|
+
'basics:icon-books',
|
|
3481
|
+
'butcher',
|
|
3482
|
+
'basics:icon-butcher',
|
|
3332
3483
|
//'car', 'basics:icon-car',
|
|
3333
|
-
'chemist',
|
|
3334
|
-
'
|
|
3484
|
+
'chemist',
|
|
3485
|
+
'basics:icon-chemist',
|
|
3486
|
+
'clothes',
|
|
3487
|
+
'basics:icon-clothes',
|
|
3335
3488
|
//'computer', 'basics:icon-computer',
|
|
3336
3489
|
//'convinience', 'basics:icon-convinience',
|
|
3337
3490
|
//'department_store', 'basics:icon-department_store',
|
|
3338
|
-
'doityourself',
|
|
3339
|
-
'
|
|
3340
|
-
'
|
|
3341
|
-
'
|
|
3342
|
-
'
|
|
3343
|
-
'
|
|
3344
|
-
'
|
|
3345
|
-
'
|
|
3346
|
-
'
|
|
3347
|
-
'
|
|
3348
|
-
'
|
|
3349
|
-
'
|
|
3350
|
-
'
|
|
3491
|
+
'doityourself',
|
|
3492
|
+
'basics:icon-doityourself',
|
|
3493
|
+
'dry_cleaning',
|
|
3494
|
+
'basics:icon-drycleaning',
|
|
3495
|
+
'florist',
|
|
3496
|
+
'basics:icon-florist',
|
|
3497
|
+
'furniture',
|
|
3498
|
+
'basics:icon-furniture',
|
|
3499
|
+
'garden_centre',
|
|
3500
|
+
'basics:icon-garden_centre',
|
|
3501
|
+
'general',
|
|
3502
|
+
'basics:icon-shop',
|
|
3503
|
+
'gift',
|
|
3504
|
+
'basics:icon-gift',
|
|
3505
|
+
'greengrocer',
|
|
3506
|
+
'basics:icon-greengrocer',
|
|
3507
|
+
'hairdresser',
|
|
3508
|
+
'basics:icon-hairdresser',
|
|
3509
|
+
'hardware',
|
|
3510
|
+
'basics:icon-hardware',
|
|
3511
|
+
'jewelry',
|
|
3512
|
+
'basics:icon-jewelry_store',
|
|
3513
|
+
'kiosk',
|
|
3514
|
+
'basics:icon-kiosk',
|
|
3515
|
+
'laundry',
|
|
3516
|
+
'basics:icon-laundry',
|
|
3351
3517
|
//'mall', 'basics:icon-mall',
|
|
3352
3518
|
//'mobile_phone', 'basics:icon-mobile_phone',
|
|
3353
|
-
'newsagent',
|
|
3354
|
-
'
|
|
3355
|
-
'
|
|
3356
|
-
'
|
|
3357
|
-
'
|
|
3358
|
-
'
|
|
3519
|
+
'newsagent',
|
|
3520
|
+
'basics:icon-newsagent',
|
|
3521
|
+
'optican',
|
|
3522
|
+
'basics:icon-optician',
|
|
3523
|
+
'outdoor',
|
|
3524
|
+
'basics:icon-outdoor',
|
|
3525
|
+
'shoes',
|
|
3526
|
+
'basics:icon-shoes',
|
|
3527
|
+
'sports',
|
|
3528
|
+
'basics:icon-sports',
|
|
3529
|
+
'stationery',
|
|
3530
|
+
'basics:icon-stationery',
|
|
3359
3531
|
//'supermarket', 'basics:icon-supermarket',
|
|
3360
|
-
'toys',
|
|
3361
|
-
'
|
|
3362
|
-
'
|
|
3532
|
+
'toys',
|
|
3533
|
+
'basics:icon-toys',
|
|
3534
|
+
'travel_agency',
|
|
3535
|
+
'basics:icon-travel_agent',
|
|
3536
|
+
'video',
|
|
3537
|
+
'basics:icon-video',
|
|
3363
3538
|
'basics:icon-shop',
|
|
3364
3539
|
],
|
|
3365
3540
|
},
|
|
3366
3541
|
'poi-man_made': {
|
|
3367
|
-
image: [
|
|
3542
|
+
image: [
|
|
3543
|
+
'match',
|
|
3368
3544
|
['get', 'man_made'],
|
|
3369
|
-
'lighthouse',
|
|
3370
|
-
'
|
|
3371
|
-
'
|
|
3545
|
+
'lighthouse',
|
|
3546
|
+
'basics:icon-lighthouse',
|
|
3547
|
+
'surveillance',
|
|
3548
|
+
'basics:icon-surveillance',
|
|
3549
|
+
'tower',
|
|
3550
|
+
'basics:icon-observation_tower',
|
|
3372
3551
|
//'wastewater_plant', 'basics:icon-wastewater_plant',
|
|
3373
3552
|
//'water_well', 'basics:icon-water_well',
|
|
3374
3553
|
//'water_works', 'basics:icon-water_works',
|
|
3375
|
-
'watermill',
|
|
3376
|
-
'
|
|
3554
|
+
'watermill',
|
|
3555
|
+
'basics:icon-watermill',
|
|
3556
|
+
'windmill',
|
|
3557
|
+
'basics:icon-windmill',
|
|
3377
3558
|
'',
|
|
3378
3559
|
],
|
|
3379
3560
|
},
|
|
3380
3561
|
'poi-historic': {
|
|
3381
|
-
image: [
|
|
3562
|
+
image: [
|
|
3563
|
+
'match',
|
|
3382
3564
|
['get', 'historic'],
|
|
3383
3565
|
//'archaelogical_site', 'basics:icon-archaelogical_site',
|
|
3384
|
-
'artwork',
|
|
3566
|
+
'artwork',
|
|
3567
|
+
'basics:icon-artwork',
|
|
3385
3568
|
//'battlefield', 'basics:icon-battlefield',
|
|
3386
|
-
'castle',
|
|
3569
|
+
'castle',
|
|
3570
|
+
'basics:icon-castle',
|
|
3387
3571
|
//'fort', 'basics:icon-fort',
|
|
3388
3572
|
//'memorial', 'basics:icon-memorial',
|
|
3389
|
-
'monument',
|
|
3573
|
+
'monument',
|
|
3574
|
+
'basics:icon-monument',
|
|
3390
3575
|
//'ruins', 'basics:icon-ruins',
|
|
3391
3576
|
//'wayside_cross', 'basics:icon-wayside_cross',
|
|
3392
|
-
'wayside_shrine',
|
|
3577
|
+
'wayside_shrine',
|
|
3578
|
+
'basics:icon-shrine',
|
|
3393
3579
|
'basics:icon-historic',
|
|
3394
3580
|
],
|
|
3395
3581
|
},
|
|
3396
3582
|
'poi-emergency': {
|
|
3397
|
-
image: [
|
|
3583
|
+
image: [
|
|
3584
|
+
'match',
|
|
3398
3585
|
['get', 'emergency'],
|
|
3399
|
-
'defibrillator',
|
|
3400
|
-
'
|
|
3401
|
-
'
|
|
3586
|
+
'defibrillator',
|
|
3587
|
+
'basics:icon-defibrillator',
|
|
3588
|
+
'fire_hydrant',
|
|
3589
|
+
'basics:icon-hydrant',
|
|
3590
|
+
'phone',
|
|
3591
|
+
'basics:icon-emergency_phone',
|
|
3402
3592
|
'',
|
|
3403
3593
|
],
|
|
3404
3594
|
},
|
|
@@ -3426,7 +3616,7 @@ class Eclipse extends Colorful {
|
|
|
3426
3616
|
name = 'Eclipse';
|
|
3427
3617
|
constructor() {
|
|
3428
3618
|
super();
|
|
3429
|
-
this.transformDefaultColors(color => color.invertLuminosity());
|
|
3619
|
+
this.transformDefaultColors((color) => color.invertLuminosity());
|
|
3430
3620
|
}
|
|
3431
3621
|
}
|
|
3432
3622
|
|
|
@@ -3434,7 +3624,7 @@ class Graybeard extends Colorful {
|
|
|
3434
3624
|
name = 'Graybeard';
|
|
3435
3625
|
constructor() {
|
|
3436
3626
|
super();
|
|
3437
|
-
this.transformDefaultColors(color => color.saturate(-1));
|
|
3627
|
+
this.transformDefaultColors((color) => color.saturate(-1));
|
|
3438
3628
|
}
|
|
3439
3629
|
}
|
|
3440
3630
|
|
|
@@ -3442,7 +3632,7 @@ class Shadow extends Colorful {
|
|
|
3442
3632
|
name = 'Shadow';
|
|
3443
3633
|
constructor() {
|
|
3444
3634
|
super();
|
|
3445
|
-
this.transformDefaultColors(color => color.saturate(-1).invert().brightness(0.2));
|
|
3635
|
+
this.transformDefaultColors((color) => color.saturate(-1).invert().brightness(0.2));
|
|
3446
3636
|
}
|
|
3447
3637
|
}
|
|
3448
3638
|
|
|
@@ -3511,7 +3701,7 @@ class Neutrino extends Colorful {
|
|
|
3511
3701
|
getStyleRules(options) {
|
|
3512
3702
|
const { colors, fonts } = options;
|
|
3513
3703
|
return {
|
|
3514
|
-
|
|
3704
|
+
background: {
|
|
3515
3705
|
color: colors.land,
|
|
3516
3706
|
},
|
|
3517
3707
|
'boundary-{country,state}': {
|
|
@@ -3582,11 +3772,11 @@ class Neutrino extends Colorful {
|
|
|
3582
3772
|
'site-{bicycleparking,parking}': {
|
|
3583
3773
|
color: colors.commercial,
|
|
3584
3774
|
},
|
|
3585
|
-
|
|
3775
|
+
building: {
|
|
3586
3776
|
color: colors.building,
|
|
3587
3777
|
opacity: { 14: 0, 15: 1 },
|
|
3588
3778
|
},
|
|
3589
|
-
|
|
3779
|
+
bridge: {
|
|
3590
3780
|
color: colors.land.darken(0.01),
|
|
3591
3781
|
},
|
|
3592
3782
|
'{tunnel-,bridge-,}street-*': {
|
|
@@ -3853,6 +4043,92 @@ class Empty extends Colorful {
|
|
|
3853
4043
|
}
|
|
3854
4044
|
}
|
|
3855
4045
|
|
|
4046
|
+
function buildSatelliteStyle(options) {
|
|
4047
|
+
options ??= {};
|
|
4048
|
+
const baseUrl = options.baseUrl ?? 'https://tiles.versatiles.org';
|
|
4049
|
+
const rasterTiles = options.rasterTiles ?? [`${baseUrl}/tiles/satellite/{z}/{x}/{y}`];
|
|
4050
|
+
const overlay = options.overlay ?? true;
|
|
4051
|
+
let style;
|
|
4052
|
+
if (overlay) {
|
|
4053
|
+
// Generate graybeard style for overlay
|
|
4054
|
+
style = new Graybeard().build({
|
|
4055
|
+
baseUrl,
|
|
4056
|
+
tiles: options.overlayTiles,
|
|
4057
|
+
language: options.language,
|
|
4058
|
+
});
|
|
4059
|
+
// Filter out background, fill layers, and unwanted layer groups
|
|
4060
|
+
style.layers = style.layers.filter((l) => l.id !== 'background' && l.type !== 'fill' && !/^(land|water|site|airport|tunnel)-/.test(l.id));
|
|
4061
|
+
// Modify remaining layers
|
|
4062
|
+
for (const layer of style.layers) {
|
|
4063
|
+
if (layer.type === 'symbol') {
|
|
4064
|
+
// Bold font, white text, black halo
|
|
4065
|
+
if (layer.layout?.['text-font']) {
|
|
4066
|
+
layer.layout['text-font'] = ['noto_sans_bold'];
|
|
4067
|
+
}
|
|
4068
|
+
if (layer.paint) {
|
|
4069
|
+
layer.paint['text-color'] = '#fff';
|
|
4070
|
+
layer.paint['text-halo-color'] = '#000';
|
|
4071
|
+
if ('text-halo-blur' in layer.paint)
|
|
4072
|
+
layer.paint['text-halo-blur'] = 0;
|
|
4073
|
+
if ('text-halo-width' in layer.paint)
|
|
4074
|
+
layer.paint['text-halo-width'] = 1;
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
if (layer.type === 'line' && layer.paint) {
|
|
4078
|
+
// Multiply existing opacity by 0.2
|
|
4079
|
+
const v = layer.paint['line-opacity'];
|
|
4080
|
+
if (v == null) {
|
|
4081
|
+
layer.paint['line-opacity'] = 0.2;
|
|
4082
|
+
}
|
|
4083
|
+
else if (typeof v === 'number') {
|
|
4084
|
+
layer.paint['line-opacity'] = v * 0.2;
|
|
4085
|
+
}
|
|
4086
|
+
else if (typeof v === 'object' && 'stops' in v) {
|
|
4087
|
+
v.stops = v.stops.map((s) => [s[0], s[1] * 0.2]);
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
else {
|
|
4093
|
+
// Minimal style with no overlay
|
|
4094
|
+
style = { version: 8, sources: {}, layers: [] };
|
|
4095
|
+
}
|
|
4096
|
+
// Build raster paint properties
|
|
4097
|
+
const rasterPaint = {};
|
|
4098
|
+
if (options.rasterOpacity != null)
|
|
4099
|
+
rasterPaint['raster-opacity'] = options.rasterOpacity;
|
|
4100
|
+
if (options.rasterHueRotate != null)
|
|
4101
|
+
rasterPaint['raster-hue-rotate'] = options.rasterHueRotate;
|
|
4102
|
+
if (options.rasterBrightnessMin != null)
|
|
4103
|
+
rasterPaint['raster-brightness-min'] = options.rasterBrightnessMin;
|
|
4104
|
+
if (options.rasterBrightnessMax != null)
|
|
4105
|
+
rasterPaint['raster-brightness-max'] = options.rasterBrightnessMax;
|
|
4106
|
+
if (options.rasterSaturation != null)
|
|
4107
|
+
rasterPaint['raster-saturation'] = options.rasterSaturation;
|
|
4108
|
+
if (options.rasterContrast != null)
|
|
4109
|
+
rasterPaint['raster-contrast'] = options.rasterContrast;
|
|
4110
|
+
// Add raster source
|
|
4111
|
+
style.sources.satellite = {
|
|
4112
|
+
type: 'raster',
|
|
4113
|
+
tiles: rasterTiles,
|
|
4114
|
+
tileSize: 512,
|
|
4115
|
+
attribution: "<a href='https://versatiles.org/sources/'>VersaTiles sources</a>",
|
|
4116
|
+
bounds: [-178.187256, -21.401934, 55.846252, 58.061897],
|
|
4117
|
+
minzoom: 0,
|
|
4118
|
+
maxzoom: 17,
|
|
4119
|
+
};
|
|
4120
|
+
// Add raster layer at bottom
|
|
4121
|
+
style.layers.unshift({
|
|
4122
|
+
id: 'satellite',
|
|
4123
|
+
type: 'raster',
|
|
4124
|
+
source: 'satellite',
|
|
4125
|
+
minzoom: 0,
|
|
4126
|
+
...(Object.keys(rasterPaint).length > 0 ? { paint: rasterPaint } : {}),
|
|
4127
|
+
});
|
|
4128
|
+
style.name = 'versatiles-satellite';
|
|
4129
|
+
return style;
|
|
4130
|
+
}
|
|
4131
|
+
|
|
3856
4132
|
// import styles
|
|
3857
4133
|
function getStyleBuilder(styleBuilder) {
|
|
3858
4134
|
const fn = function (options) {
|
|
@@ -3870,88 +4146,88 @@ const neutrino = getStyleBuilder(Neutrino);
|
|
|
3870
4146
|
getStyleBuilder(Empty);
|
|
3871
4147
|
|
|
3872
4148
|
/**
|
|
3873
|
-
* Checks if an object adheres to the TileJSON specification.
|
|
3874
|
-
* Throws errors if the object does not conform to the expected structure or types.
|
|
3875
|
-
*/
|
|
4149
|
+
* Checks if an object adheres to the TileJSON specification.
|
|
4150
|
+
* Throws errors if the object does not conform to the expected structure or types.
|
|
4151
|
+
*/
|
|
3876
4152
|
function isTileJSONSpecification(spec) {
|
|
3877
4153
|
if (typeof spec !== 'object' || spec === null) {
|
|
3878
|
-
throw Error(
|
|
4154
|
+
throw new Error(`TileJSON validation: spec must be an object, but got ${typeof spec}`);
|
|
3879
4155
|
}
|
|
3880
4156
|
const obj = spec;
|
|
3881
4157
|
// Common property validation
|
|
3882
4158
|
if (obj.data != null && obj.tilejson !== '3.0.0') {
|
|
3883
|
-
throw Error(
|
|
4159
|
+
throw new Error(`TileJSON validation: spec.tilejson must be "3.0.0", but got "${obj.tilejson}"`);
|
|
3884
4160
|
}
|
|
3885
4161
|
if (obj.attribution != null && typeof obj.attribution !== 'string') {
|
|
3886
|
-
throw Error(
|
|
4162
|
+
throw new Error(`TileJSON validation: spec.attribution must be a string if present, but got ${typeof obj.attribution}`);
|
|
3887
4163
|
}
|
|
3888
4164
|
if (obj.bounds != null) {
|
|
3889
|
-
if (!Array.isArray(obj.bounds) || obj.bounds.length !== 4 || obj.bounds.some(num => typeof num !== 'number')) {
|
|
3890
|
-
throw Error(
|
|
4165
|
+
if (!Array.isArray(obj.bounds) || obj.bounds.length !== 4 || obj.bounds.some((num) => typeof num !== 'number')) {
|
|
4166
|
+
throw new Error(`TileJSON validation: spec.bounds must be an array of four numbers if present, but got ${JSON.stringify(obj.bounds)}`);
|
|
3891
4167
|
}
|
|
3892
4168
|
const a = obj.bounds;
|
|
3893
4169
|
if (a[0] < -180 || a[0] > 180)
|
|
3894
|
-
throw Error(
|
|
4170
|
+
throw new Error(`TileJSON validation: spec.bounds[0] (longitude) must be between -180 and 180, but got ${a[0]}`);
|
|
3895
4171
|
if (a[1] < -90 || a[1] > 90)
|
|
3896
|
-
throw Error(
|
|
4172
|
+
throw new Error(`TileJSON validation: spec.bounds[1] (latitude) must be between -90 and 90, but got ${a[1]}`);
|
|
3897
4173
|
if (a[2] < -180 || a[2] > 180)
|
|
3898
|
-
throw Error(
|
|
4174
|
+
throw new Error(`TileJSON validation: spec.bounds[2] (longitude) must be between -180 and 180, but got ${a[2]}`);
|
|
3899
4175
|
if (a[3] < -90 || a[3] > 90)
|
|
3900
|
-
throw Error(
|
|
4176
|
+
throw new Error(`TileJSON validation: spec.bounds[3] (latitude) must be between -90 and 90, but got ${a[3]}`);
|
|
3901
4177
|
if (a[0] > a[2])
|
|
3902
|
-
throw Error(
|
|
4178
|
+
throw new Error(`TileJSON validation: spec.bounds[0] must be smaller than spec.bounds[2] (min longitude < max longitude), but got [${a[0]}, ${a[2]}]`);
|
|
3903
4179
|
if (a[1] > a[3])
|
|
3904
|
-
throw Error(
|
|
4180
|
+
throw new Error(`TileJSON validation: spec.bounds[1] must be smaller than spec.bounds[3] (min latitude < max latitude), but got [${a[1]}, ${a[3]}]`);
|
|
3905
4181
|
}
|
|
3906
4182
|
if (obj.center != null) {
|
|
3907
|
-
if (!Array.isArray(obj.center) || obj.center.length !== 2 || obj.center.some(num => typeof num !== 'number')) {
|
|
3908
|
-
throw Error(
|
|
4183
|
+
if (!Array.isArray(obj.center) || obj.center.length !== 2 || obj.center.some((num) => typeof num !== 'number')) {
|
|
4184
|
+
throw new Error(`TileJSON validation: spec.center must be an array of two numbers if present, but got ${JSON.stringify(obj.center)}`);
|
|
3909
4185
|
}
|
|
3910
4186
|
const a = obj.center;
|
|
3911
4187
|
if (a[0] < -180 || a[0] > 180)
|
|
3912
|
-
throw Error(
|
|
4188
|
+
throw new Error(`TileJSON validation: spec.center[0] (longitude) must be between -180 and 180, but got ${a[0]}`);
|
|
3913
4189
|
if (a[1] < -90 || a[1] > 90)
|
|
3914
|
-
throw Error(
|
|
4190
|
+
throw new Error(`TileJSON validation: spec.center[1] (latitude) must be between -90 and 90, but got ${a[1]}`);
|
|
3915
4191
|
}
|
|
3916
|
-
if (obj.data != null && (!Array.isArray(obj.data) || obj.data.some(url => typeof url !== 'string'))) {
|
|
3917
|
-
throw Error('spec.data must be an array of strings if present');
|
|
4192
|
+
if (obj.data != null && (!Array.isArray(obj.data) || obj.data.some((url) => typeof url !== 'string'))) {
|
|
4193
|
+
throw new Error('TileJSON validation: spec.data must be an array of strings if present');
|
|
3918
4194
|
}
|
|
3919
4195
|
if (obj.description != null && typeof obj.description !== 'string') {
|
|
3920
|
-
throw Error(
|
|
4196
|
+
throw new Error(`TileJSON validation: spec.description must be a string if present, but got ${typeof obj.description}`);
|
|
3921
4197
|
}
|
|
3922
|
-
if (obj.fillzoom != null && (typeof obj.fillzoom !== 'number' ||
|
|
3923
|
-
throw Error(
|
|
4198
|
+
if (obj.fillzoom != null && (typeof obj.fillzoom !== 'number' || obj.fillzoom < 0)) {
|
|
4199
|
+
throw new Error(`TileJSON validation: spec.fillzoom must be a positive integer if present, but got ${obj.fillzoom}`);
|
|
3924
4200
|
}
|
|
3925
|
-
if (obj.grids != null && (!Array.isArray(obj.grids) || obj.grids.some(url => typeof url !== 'string'))) {
|
|
3926
|
-
throw Error('spec.grids must be an array of strings if present');
|
|
4201
|
+
if (obj.grids != null && (!Array.isArray(obj.grids) || obj.grids.some((url) => typeof url !== 'string'))) {
|
|
4202
|
+
throw new Error('TileJSON validation: spec.grids must be an array of strings if present');
|
|
3927
4203
|
}
|
|
3928
4204
|
if (obj.legend != null && typeof obj.legend !== 'string') {
|
|
3929
|
-
throw Error(
|
|
4205
|
+
throw new Error(`TileJSON validation: spec.legend must be a string if present, but got ${typeof obj.legend}`);
|
|
3930
4206
|
}
|
|
3931
|
-
if (obj.minzoom != null && (typeof obj.minzoom !== 'number' ||
|
|
3932
|
-
throw Error(
|
|
4207
|
+
if (obj.minzoom != null && (typeof obj.minzoom !== 'number' || obj.minzoom < 0)) {
|
|
4208
|
+
throw new Error(`TileJSON validation: spec.minzoom must be a positive integer if present, but got ${obj.minzoom}`);
|
|
3933
4209
|
}
|
|
3934
|
-
if (obj.maxzoom != null && (typeof obj.maxzoom !== 'number' ||
|
|
3935
|
-
throw Error(
|
|
4210
|
+
if (obj.maxzoom != null && (typeof obj.maxzoom !== 'number' || obj.maxzoom < 0)) {
|
|
4211
|
+
throw new Error(`TileJSON validation: spec.maxzoom must be a positive integer if present, but got ${obj.maxzoom}`);
|
|
3936
4212
|
}
|
|
3937
4213
|
if (obj.name != null && typeof obj.name !== 'string') {
|
|
3938
|
-
throw Error(
|
|
4214
|
+
throw new Error(`TileJSON validation: spec.name must be a string if present, but got ${typeof obj.name}`);
|
|
3939
4215
|
}
|
|
3940
4216
|
if (obj.scheme != null && obj.scheme !== 'xyz' && obj.scheme !== 'tms') {
|
|
3941
|
-
throw Error(
|
|
4217
|
+
throw new Error(`TileJSON validation: spec.scheme must be "tms" or "xyz" if present, but got "${obj.scheme}"`);
|
|
3942
4218
|
}
|
|
3943
4219
|
if (obj.template != null && typeof obj.template !== 'string') {
|
|
3944
|
-
throw Error(
|
|
4220
|
+
throw new Error(`TileJSON validation: spec.template must be a string if present, but got ${typeof obj.template}`);
|
|
3945
4221
|
}
|
|
3946
|
-
if (!Array.isArray(obj.tiles) || obj.tiles.length === 0 || obj.tiles.some(url => typeof url !== 'string')) {
|
|
3947
|
-
throw Error('spec.tiles must be
|
|
4222
|
+
if (!Array.isArray(obj.tiles) || obj.tiles.length === 0 || obj.tiles.some((url) => typeof url !== 'string')) {
|
|
4223
|
+
throw new Error('TileJSON validation: spec.tiles must be a non-empty array of strings');
|
|
3948
4224
|
}
|
|
3949
4225
|
return true;
|
|
3950
4226
|
}
|
|
3951
4227
|
function isRasterTileJSONSpecification(spec) {
|
|
3952
4228
|
if (!isTileJSONSpecification(spec))
|
|
3953
4229
|
;
|
|
3954
|
-
if (
|
|
4230
|
+
if ('vector_layers' in spec && spec.vector_layers != null)
|
|
3955
4231
|
return false;
|
|
3956
4232
|
return true;
|
|
3957
4233
|
}
|
|
@@ -3971,10 +4247,9 @@ function guessStyle(tileJSON, options) {
|
|
|
3971
4247
|
tileJSON = deepClone(tileJSON);
|
|
3972
4248
|
if (options && options.baseUrl) {
|
|
3973
4249
|
const { baseUrl } = options;
|
|
3974
|
-
tileJSON.tiles = tileJSON.tiles.map(url => resolveUrl(baseUrl, url));
|
|
4250
|
+
tileJSON.tiles = tileJSON.tiles.map((url) => resolveUrl(baseUrl, url));
|
|
3975
4251
|
}
|
|
3976
|
-
if (!isTileJSONSpecification(tileJSON))
|
|
3977
|
-
;
|
|
4252
|
+
if (!isTileJSONSpecification(tileJSON)) ;
|
|
3978
4253
|
let style;
|
|
3979
4254
|
if (isRasterTileJSONSpecification(tileJSON)) {
|
|
3980
4255
|
style = getRasterStyle(tileJSON);
|
|
@@ -4000,9 +4275,36 @@ function isShortbread(spec) {
|
|
|
4000
4275
|
return false;
|
|
4001
4276
|
if (!Array.isArray(spec.vector_layers))
|
|
4002
4277
|
return false;
|
|
4003
|
-
const layerIds = new Set(spec.vector_layers.map(l => String(l.id)));
|
|
4004
|
-
const shortbreadIds = [
|
|
4005
|
-
|
|
4278
|
+
const layerIds = new Set(spec.vector_layers.map((l) => String(l.id)));
|
|
4279
|
+
const shortbreadIds = [
|
|
4280
|
+
'place_labels',
|
|
4281
|
+
'boundaries',
|
|
4282
|
+
'boundary_labels',
|
|
4283
|
+
'addresses',
|
|
4284
|
+
'water_lines',
|
|
4285
|
+
'water_lines_labels',
|
|
4286
|
+
'dam_lines',
|
|
4287
|
+
'dam_polygons',
|
|
4288
|
+
'pier_lines',
|
|
4289
|
+
'pier_polygons',
|
|
4290
|
+
'bridges',
|
|
4291
|
+
'street_polygons',
|
|
4292
|
+
'streets_polygons_labels',
|
|
4293
|
+
'ferries',
|
|
4294
|
+
'streets',
|
|
4295
|
+
'street_labels',
|
|
4296
|
+
'street_labels_points',
|
|
4297
|
+
'aerialways',
|
|
4298
|
+
'public_transport',
|
|
4299
|
+
'buildings',
|
|
4300
|
+
'water_polygons',
|
|
4301
|
+
'ocean',
|
|
4302
|
+
'water_polygons_labels',
|
|
4303
|
+
'land',
|
|
4304
|
+
'sites',
|
|
4305
|
+
'pois',
|
|
4306
|
+
];
|
|
4307
|
+
return shortbreadIds.every((id) => layerIds.has(id));
|
|
4006
4308
|
}
|
|
4007
4309
|
function getShortbreadStyle(spec, builderOption) {
|
|
4008
4310
|
return colorful({
|
|
@@ -4032,7 +4334,7 @@ function getShortbreadStyle(spec, builderOption) {
|
|
|
4032
4334
|
function getInspectorStyle(spec) {
|
|
4033
4335
|
const sourceName = 'vectorSource';
|
|
4034
4336
|
const layers = { background: [], circle: [], line: [], fill: [] };
|
|
4035
|
-
layers.background.push({
|
|
4337
|
+
layers.background.push({ id: 'background', type: 'background', paint: { 'background-color': '#fff' } });
|
|
4036
4338
|
spec.vector_layers.forEach((vector_layer) => {
|
|
4037
4339
|
let luminosity = 'bright', saturation, hue;
|
|
4038
4340
|
if (/water|ocean|lake|sea|river/.test(vector_layer.id))
|
|
@@ -4091,12 +4393,7 @@ function getInspectorStyle(spec) {
|
|
|
4091
4393
|
sources: {
|
|
4092
4394
|
[sourceName]: sourceFromSpec(spec, 'vector'),
|
|
4093
4395
|
},
|
|
4094
|
-
layers: [
|
|
4095
|
-
...layers.background,
|
|
4096
|
-
...layers.fill,
|
|
4097
|
-
...layers.line,
|
|
4098
|
-
...layers.circle,
|
|
4099
|
-
],
|
|
4396
|
+
layers: [...layers.background, ...layers.fill, ...layers.line, ...layers.circle],
|
|
4100
4397
|
};
|
|
4101
4398
|
}
|
|
4102
4399
|
function getRasterStyle(spec) {
|
|
@@ -4106,11 +4403,13 @@ function getRasterStyle(spec) {
|
|
|
4106
4403
|
sources: {
|
|
4107
4404
|
[sourceName]: sourceFromSpec(spec, 'raster'),
|
|
4108
4405
|
},
|
|
4109
|
-
layers: [
|
|
4406
|
+
layers: [
|
|
4407
|
+
{
|
|
4110
4408
|
id: 'raster',
|
|
4111
4409
|
type: 'raster',
|
|
4112
4410
|
source: sourceName,
|
|
4113
|
-
}
|
|
4411
|
+
},
|
|
4412
|
+
],
|
|
4114
4413
|
};
|
|
4115
4414
|
}
|
|
4116
4415
|
function sourceFromSpec(spec, type) {
|
|
@@ -4213,7 +4512,8 @@ const styles = {
|
|
|
4213
4512
|
graybeard,
|
|
4214
4513
|
shadow,
|
|
4215
4514
|
neutrino,
|
|
4515
|
+
satellite: buildSatelliteStyle,
|
|
4216
4516
|
};
|
|
4217
4517
|
|
|
4218
|
-
export { Color, colorful, eclipse, graybeard, guessStyle, neutrino, shadow, styles };
|
|
4518
|
+
export { Color, colorful, eclipse, graybeard, guessStyle, neutrino, buildSatelliteStyle as satellite, shadow, styles };
|
|
4219
4519
|
//# sourceMappingURL=index.js.map
|