@geogdev/styles 0.1.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 +189 -0
- package/dist/cjs/index.cjs +16 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +325 -0
- package/dist/esm/index.d.ts +325 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/styles/dark.json +2909 -0
- package/dist/styles/gray.json +2909 -0
- package/dist/styles/light.json +2909 -0
- package/dist/styles/warm.json +2909 -0
- package/dist/styles.js +16 -0
- package/dist/styles.js.map +1 -0
- package/package.json +52 -0
- package/src/cli.ts +27 -0
- package/src/config/features.json +48 -0
- package/src/config/languages.json +207 -0
- package/src/config/poi.json +205 -0
- package/src/config/styles/dark.json +129 -0
- package/src/config/styles/gray.json +129 -0
- package/src/config/styles/light.json +129 -0
- package/src/config/styles/warm.json +129 -0
- package/src/config/zoom.json +40 -0
- package/src/constants.ts +243 -0
- package/src/generateStyle.ts +70 -0
- package/src/index.ts +76 -0
- package/src/language.ts +320 -0
- package/src/layers/background.ts +91 -0
- package/src/layers/boundaries.ts +51 -0
- package/src/layers/buildings.ts +23 -0
- package/src/layers/index.ts +132 -0
- package/src/layers/labels.ts +775 -0
- package/src/layers/landcover.ts +323 -0
- package/src/layers/pois.ts +165 -0
- package/src/layers/roads.ts +688 -0
- package/src/layers/transit.ts +232 -0
- package/src/styles.ts +182 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExpressionSpecification,
|
|
3
|
+
FilterSpecification,
|
|
4
|
+
LayerSpecification,
|
|
5
|
+
LineLayerSpecification,
|
|
6
|
+
} from "@maplibre/maplibre-gl-style-spec";
|
|
7
|
+
import { FILTERS, LINE_WIDTHS, ROAD_CLASSES, ZOOM } from "../constants";
|
|
8
|
+
import type { Style } from "../styles";
|
|
9
|
+
|
|
10
|
+
// ============================================
|
|
11
|
+
// TYPES
|
|
12
|
+
// ============================================
|
|
13
|
+
|
|
14
|
+
type RoadCategory = "other" | "minor" | "link" | "major" | "highway";
|
|
15
|
+
type BrunnelType = "tunnel" | "bridge" | null;
|
|
16
|
+
|
|
17
|
+
interface RoadLayerConfig {
|
|
18
|
+
source: string;
|
|
19
|
+
style: Style;
|
|
20
|
+
brunnel: BrunnelType;
|
|
21
|
+
category: RoadCategory;
|
|
22
|
+
isCasing: boolean;
|
|
23
|
+
minzoom?: number;
|
|
24
|
+
maxzoom?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============================================
|
|
28
|
+
// HELPER FUNCTIONS
|
|
29
|
+
// ============================================
|
|
30
|
+
|
|
31
|
+
function getRoadClasses(category: RoadCategory): readonly string[] {
|
|
32
|
+
switch (category) {
|
|
33
|
+
case "other":
|
|
34
|
+
return ROAD_CLASSES.OTHER;
|
|
35
|
+
case "minor":
|
|
36
|
+
return ROAD_CLASSES.MINOR;
|
|
37
|
+
case "major":
|
|
38
|
+
return ROAD_CLASSES.MAJOR;
|
|
39
|
+
case "highway":
|
|
40
|
+
return ROAD_CLASSES.HIGHWAY;
|
|
41
|
+
case "link":
|
|
42
|
+
return []; // Link uses ramp filter, not class filter
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildFilter(
|
|
47
|
+
brunnel: BrunnelType,
|
|
48
|
+
category: RoadCategory,
|
|
49
|
+
): FilterSpecification {
|
|
50
|
+
const conditions: ExpressionSpecification[] = [];
|
|
51
|
+
|
|
52
|
+
// Brunnel condition
|
|
53
|
+
if (brunnel === "tunnel") {
|
|
54
|
+
conditions.push(FILTERS.IS_TUNNEL);
|
|
55
|
+
} else if (brunnel === "bridge") {
|
|
56
|
+
conditions.push(FILTERS.IS_BRIDGE);
|
|
57
|
+
} else {
|
|
58
|
+
conditions.push(FILTERS.NOT_BRUNNEL);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Road class condition
|
|
62
|
+
if (category === "link") {
|
|
63
|
+
conditions.push(FILTERS.IS_RAMP);
|
|
64
|
+
} else {
|
|
65
|
+
const classes = getRoadClasses(category);
|
|
66
|
+
if (classes.length > 0) {
|
|
67
|
+
conditions.push([
|
|
68
|
+
"in",
|
|
69
|
+
["get", "class"],
|
|
70
|
+
["literal", classes as unknown as string[]],
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
// Highway excludes ramps
|
|
74
|
+
if (category === "highway") {
|
|
75
|
+
conditions.push(FILTERS.NOT_RAMP);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return conditions.length === 1
|
|
80
|
+
? conditions[0]
|
|
81
|
+
: (["all", ...conditions] as FilterSpecification);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getLayerId(
|
|
85
|
+
brunnel: BrunnelType,
|
|
86
|
+
category: RoadCategory,
|
|
87
|
+
isCasing: boolean,
|
|
88
|
+
): string {
|
|
89
|
+
const prefix =
|
|
90
|
+
brunnel === "tunnel"
|
|
91
|
+
? "roads_tunnels"
|
|
92
|
+
: brunnel === "bridge"
|
|
93
|
+
? "roads_bridges"
|
|
94
|
+
: "roads";
|
|
95
|
+
|
|
96
|
+
const suffix = isCasing ? "_casing" : "";
|
|
97
|
+
return `${prefix}_${category}${suffix}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getCasingColor(
|
|
101
|
+
style: Style,
|
|
102
|
+
brunnel: BrunnelType,
|
|
103
|
+
category: RoadCategory,
|
|
104
|
+
): string {
|
|
105
|
+
if (brunnel === "tunnel") {
|
|
106
|
+
switch (category) {
|
|
107
|
+
case "other":
|
|
108
|
+
return style.tunnel_other_casing;
|
|
109
|
+
case "minor":
|
|
110
|
+
return style.tunnel_minor_casing;
|
|
111
|
+
case "link":
|
|
112
|
+
return style.tunnel_link_casing;
|
|
113
|
+
case "major":
|
|
114
|
+
return style.tunnel_major_casing;
|
|
115
|
+
case "highway":
|
|
116
|
+
return style.tunnel_highway_casing;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (brunnel === "bridge") {
|
|
120
|
+
switch (category) {
|
|
121
|
+
case "other":
|
|
122
|
+
return style.bridges_other_casing;
|
|
123
|
+
case "minor":
|
|
124
|
+
return style.bridges_minor_casing;
|
|
125
|
+
case "link":
|
|
126
|
+
return style.bridges_minor_casing; // Uses minor casing color
|
|
127
|
+
case "major":
|
|
128
|
+
return style.bridges_major_casing;
|
|
129
|
+
case "highway":
|
|
130
|
+
return style.bridges_highway_casing;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Regular roads (no brunnel)
|
|
134
|
+
switch (category) {
|
|
135
|
+
case "other":
|
|
136
|
+
return style.minor_casing; // No dedicated other casing
|
|
137
|
+
case "minor":
|
|
138
|
+
return style.minor_casing;
|
|
139
|
+
case "link":
|
|
140
|
+
return style.minor_casing;
|
|
141
|
+
case "major":
|
|
142
|
+
return style.major_casing_late;
|
|
143
|
+
case "highway":
|
|
144
|
+
return style.highway_casing_late;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getFillColor(
|
|
149
|
+
style: Style,
|
|
150
|
+
brunnel: BrunnelType,
|
|
151
|
+
category: RoadCategory,
|
|
152
|
+
): string | ExpressionSpecification {
|
|
153
|
+
if (brunnel === "tunnel") {
|
|
154
|
+
switch (category) {
|
|
155
|
+
case "other":
|
|
156
|
+
return style.tunnel_other;
|
|
157
|
+
case "minor":
|
|
158
|
+
return style.tunnel_minor;
|
|
159
|
+
case "link":
|
|
160
|
+
return style.tunnel_minor; // Uses minor color
|
|
161
|
+
case "major":
|
|
162
|
+
return style.tunnel_major;
|
|
163
|
+
case "highway":
|
|
164
|
+
return style.tunnel_highway;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (brunnel === "bridge") {
|
|
168
|
+
switch (category) {
|
|
169
|
+
case "other":
|
|
170
|
+
return style.bridges_other;
|
|
171
|
+
case "minor":
|
|
172
|
+
return style.bridges_minor;
|
|
173
|
+
case "link":
|
|
174
|
+
return style.bridges_minor; // Uses minor color
|
|
175
|
+
case "major":
|
|
176
|
+
return style.bridges_major;
|
|
177
|
+
case "highway":
|
|
178
|
+
return style.bridges_highway;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Regular roads (no brunnel)
|
|
182
|
+
switch (category) {
|
|
183
|
+
case "other":
|
|
184
|
+
return style.other;
|
|
185
|
+
case "minor":
|
|
186
|
+
return [
|
|
187
|
+
"interpolate",
|
|
188
|
+
["exponential", 1.6],
|
|
189
|
+
["zoom"],
|
|
190
|
+
11,
|
|
191
|
+
style.minor_a,
|
|
192
|
+
16,
|
|
193
|
+
style.minor_b,
|
|
194
|
+
] as ExpressionSpecification;
|
|
195
|
+
case "link":
|
|
196
|
+
return style.link;
|
|
197
|
+
case "major":
|
|
198
|
+
return style.major;
|
|
199
|
+
case "highway":
|
|
200
|
+
return style.highway;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function getLineWidth(category: RoadCategory): ExpressionSpecification {
|
|
205
|
+
switch (category) {
|
|
206
|
+
case "other":
|
|
207
|
+
return LINE_WIDTHS.OTHER;
|
|
208
|
+
case "minor":
|
|
209
|
+
return LINE_WIDTHS.MINOR;
|
|
210
|
+
case "link":
|
|
211
|
+
return LINE_WIDTHS.LINK;
|
|
212
|
+
case "major":
|
|
213
|
+
return LINE_WIDTHS.MAJOR;
|
|
214
|
+
case "highway":
|
|
215
|
+
return LINE_WIDTHS.HIGHWAY;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function getCasingGapWidth(category: RoadCategory): ExpressionSpecification {
|
|
220
|
+
switch (category) {
|
|
221
|
+
case "other":
|
|
222
|
+
return LINE_WIDTHS.OTHER;
|
|
223
|
+
case "minor":
|
|
224
|
+
return LINE_WIDTHS.MINOR_CASING_GAP;
|
|
225
|
+
case "link":
|
|
226
|
+
return LINE_WIDTHS.LINK_CASING_GAP;
|
|
227
|
+
case "major":
|
|
228
|
+
return LINE_WIDTHS.MAJOR_CASING_GAP;
|
|
229
|
+
case "highway":
|
|
230
|
+
return LINE_WIDTHS.HIGHWAY_CASING_GAP;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getCasingWidth(category: RoadCategory): ExpressionSpecification {
|
|
235
|
+
switch (category) {
|
|
236
|
+
case "other":
|
|
237
|
+
// Other roads don't have explicit casing width
|
|
238
|
+
return LINE_WIDTHS.CASING_THIN;
|
|
239
|
+
case "minor":
|
|
240
|
+
return LINE_WIDTHS.CASING_THIN;
|
|
241
|
+
case "link":
|
|
242
|
+
return LINE_WIDTHS.CASING_THIN;
|
|
243
|
+
case "major":
|
|
244
|
+
return LINE_WIDTHS.CASING_MEDIUM;
|
|
245
|
+
case "highway":
|
|
246
|
+
return LINE_WIDTHS.CASING_THICK;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function getDasharray(
|
|
251
|
+
brunnel: BrunnelType,
|
|
252
|
+
category: RoadCategory,
|
|
253
|
+
isCasing: boolean,
|
|
254
|
+
): number[] | undefined {
|
|
255
|
+
if (brunnel === "tunnel") {
|
|
256
|
+
if (isCasing) {
|
|
257
|
+
// Tunnel casings have dashed outlines
|
|
258
|
+
if (category === "highway") return [6, 0.5];
|
|
259
|
+
if (category !== "other") return [3, 2];
|
|
260
|
+
} else {
|
|
261
|
+
// Tunnel fills for other roads
|
|
262
|
+
if (category === "other") return [4.5, 0.5];
|
|
263
|
+
}
|
|
264
|
+
} else if (brunnel === "bridge") {
|
|
265
|
+
// Bridge other roads have dash
|
|
266
|
+
if (!isCasing && category === "other") return [2, 1];
|
|
267
|
+
} else {
|
|
268
|
+
// Regular other roads have dash
|
|
269
|
+
if (!isCasing && category === "other") return [3, 1];
|
|
270
|
+
}
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ============================================
|
|
275
|
+
// FACTORY FUNCTION
|
|
276
|
+
// ============================================
|
|
277
|
+
|
|
278
|
+
export function createRoadLayer(
|
|
279
|
+
config: RoadLayerConfig,
|
|
280
|
+
): LineLayerSpecification {
|
|
281
|
+
const { source, style, brunnel, category, isCasing, minzoom, maxzoom } =
|
|
282
|
+
config;
|
|
283
|
+
|
|
284
|
+
const layer: LineLayerSpecification = {
|
|
285
|
+
id: getLayerId(brunnel, category, isCasing),
|
|
286
|
+
type: "line",
|
|
287
|
+
source,
|
|
288
|
+
"source-layer": "transportation",
|
|
289
|
+
filter: buildFilter(brunnel, category),
|
|
290
|
+
paint: {},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
if (minzoom !== undefined) layer.minzoom = minzoom;
|
|
294
|
+
if (maxzoom !== undefined) layer.maxzoom = maxzoom;
|
|
295
|
+
|
|
296
|
+
if (isCasing) {
|
|
297
|
+
layer.paint = {
|
|
298
|
+
"line-color": getCasingColor(style, brunnel, category),
|
|
299
|
+
"line-gap-width": getCasingGapWidth(category),
|
|
300
|
+
"line-width": getCasingWidth(category),
|
|
301
|
+
};
|
|
302
|
+
const dasharray = getDasharray(brunnel, category, true);
|
|
303
|
+
if (dasharray) {
|
|
304
|
+
layer.paint["line-dasharray"] = dasharray;
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
layer.paint = {
|
|
308
|
+
"line-color": getFillColor(style, brunnel, category),
|
|
309
|
+
"line-width": getLineWidth(category),
|
|
310
|
+
};
|
|
311
|
+
const dasharray = getDasharray(brunnel, category, false);
|
|
312
|
+
if (dasharray) {
|
|
313
|
+
layer.paint["line-dasharray"] = dasharray;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return layer;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ============================================
|
|
321
|
+
// BATCH CREATION FUNCTIONS
|
|
322
|
+
// ============================================
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Creates all tunnel road layers (casing + fill for each category)
|
|
326
|
+
*/
|
|
327
|
+
export function createTunnelLayers(
|
|
328
|
+
source: string,
|
|
329
|
+
style: Style,
|
|
330
|
+
): LayerSpecification[] {
|
|
331
|
+
const categories: RoadCategory[] = [
|
|
332
|
+
"other",
|
|
333
|
+
"minor",
|
|
334
|
+
"link",
|
|
335
|
+
"major",
|
|
336
|
+
"highway",
|
|
337
|
+
];
|
|
338
|
+
const layers: LayerSpecification[] = [];
|
|
339
|
+
|
|
340
|
+
// Casing layers first
|
|
341
|
+
for (const category of categories) {
|
|
342
|
+
layers.push(
|
|
343
|
+
createRoadLayer({
|
|
344
|
+
source,
|
|
345
|
+
style,
|
|
346
|
+
brunnel: "tunnel",
|
|
347
|
+
category,
|
|
348
|
+
isCasing: true,
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Fill layers
|
|
354
|
+
for (const category of categories) {
|
|
355
|
+
layers.push(
|
|
356
|
+
createRoadLayer({
|
|
357
|
+
source,
|
|
358
|
+
style,
|
|
359
|
+
brunnel: "tunnel",
|
|
360
|
+
category,
|
|
361
|
+
isCasing: false,
|
|
362
|
+
}),
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return layers;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Creates all regular (non-tunnel, non-bridge) road layers
|
|
371
|
+
*/
|
|
372
|
+
export function createRoadLayers(
|
|
373
|
+
source: string,
|
|
374
|
+
style: Style,
|
|
375
|
+
): LayerSpecification[] {
|
|
376
|
+
const layers: LayerSpecification[] = [];
|
|
377
|
+
|
|
378
|
+
// Minor service casing (z16+)
|
|
379
|
+
layers.push({
|
|
380
|
+
id: "roads_minor_service_casing",
|
|
381
|
+
type: "line",
|
|
382
|
+
source,
|
|
383
|
+
"source-layer": "transportation",
|
|
384
|
+
minzoom: ZOOM.ROADS_MINOR_SERVICE_MIN,
|
|
385
|
+
filter: ["all", FILTERS.NOT_BRUNNEL, ["==", ["get", "class"], "service"]],
|
|
386
|
+
paint: {
|
|
387
|
+
"line-color": style.minor_service_casing,
|
|
388
|
+
"line-gap-width": [
|
|
389
|
+
"interpolate",
|
|
390
|
+
["exponential", 1.6],
|
|
391
|
+
["zoom"],
|
|
392
|
+
13,
|
|
393
|
+
0,
|
|
394
|
+
18,
|
|
395
|
+
8,
|
|
396
|
+
],
|
|
397
|
+
"line-width": [
|
|
398
|
+
"interpolate",
|
|
399
|
+
["exponential", 1.6],
|
|
400
|
+
["zoom"],
|
|
401
|
+
13,
|
|
402
|
+
0,
|
|
403
|
+
13.5,
|
|
404
|
+
0.8,
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Minor casing
|
|
410
|
+
layers.push(
|
|
411
|
+
createRoadLayer({
|
|
412
|
+
source,
|
|
413
|
+
style,
|
|
414
|
+
brunnel: null,
|
|
415
|
+
category: "minor",
|
|
416
|
+
isCasing: true,
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
// Link casing (z13+)
|
|
421
|
+
layers.push({
|
|
422
|
+
...createRoadLayer({
|
|
423
|
+
source,
|
|
424
|
+
style,
|
|
425
|
+
brunnel: null,
|
|
426
|
+
category: "link",
|
|
427
|
+
isCasing: true,
|
|
428
|
+
minzoom: ZOOM.ROADS_LINK_MIN,
|
|
429
|
+
}),
|
|
430
|
+
// Override filter to remove NOT_BRUNNEL (link casing shows everywhere)
|
|
431
|
+
filter: FILTERS.IS_RAMP,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Major casing late (z12+)
|
|
435
|
+
layers.push(
|
|
436
|
+
createRoadLayer({
|
|
437
|
+
source,
|
|
438
|
+
style,
|
|
439
|
+
brunnel: null,
|
|
440
|
+
category: "major",
|
|
441
|
+
isCasing: true,
|
|
442
|
+
minzoom: ZOOM.ROADS_MAJOR_CASING_LATE_MIN,
|
|
443
|
+
}),
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// Highway casing late (z12+)
|
|
447
|
+
layers.push(
|
|
448
|
+
createRoadLayer({
|
|
449
|
+
source,
|
|
450
|
+
style,
|
|
451
|
+
brunnel: null,
|
|
452
|
+
category: "highway",
|
|
453
|
+
isCasing: true,
|
|
454
|
+
minzoom: ZOOM.ROADS_HIGHWAY_CASING_LATE_MIN,
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// Other roads fill
|
|
459
|
+
layers.push(
|
|
460
|
+
createRoadLayer({
|
|
461
|
+
source,
|
|
462
|
+
style,
|
|
463
|
+
brunnel: null,
|
|
464
|
+
category: "other",
|
|
465
|
+
isCasing: false,
|
|
466
|
+
}),
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
// Link roads fill
|
|
470
|
+
layers.push({
|
|
471
|
+
...createRoadLayer({
|
|
472
|
+
source,
|
|
473
|
+
style,
|
|
474
|
+
brunnel: null,
|
|
475
|
+
category: "link",
|
|
476
|
+
isCasing: false,
|
|
477
|
+
}),
|
|
478
|
+
// Override filter to remove NOT_BRUNNEL
|
|
479
|
+
filter: FILTERS.IS_RAMP,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Minor service fill
|
|
483
|
+
layers.push({
|
|
484
|
+
id: "roads_minor_service",
|
|
485
|
+
type: "line",
|
|
486
|
+
source,
|
|
487
|
+
"source-layer": "transportation",
|
|
488
|
+
filter: ["all", FILTERS.NOT_BRUNNEL, ["==", ["get", "class"], "service"]],
|
|
489
|
+
paint: {
|
|
490
|
+
"line-color": style.minor_service,
|
|
491
|
+
"line-width": [
|
|
492
|
+
"interpolate",
|
|
493
|
+
["exponential", 1.6],
|
|
494
|
+
["zoom"],
|
|
495
|
+
13,
|
|
496
|
+
0,
|
|
497
|
+
18,
|
|
498
|
+
8,
|
|
499
|
+
],
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// Minor roads fill
|
|
504
|
+
layers.push(
|
|
505
|
+
createRoadLayer({
|
|
506
|
+
source,
|
|
507
|
+
style,
|
|
508
|
+
brunnel: null,
|
|
509
|
+
category: "minor",
|
|
510
|
+
isCasing: false,
|
|
511
|
+
}),
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
// Major casing early (maxzoom 12)
|
|
515
|
+
layers.push({
|
|
516
|
+
id: "roads_major_casing_early",
|
|
517
|
+
type: "line",
|
|
518
|
+
source,
|
|
519
|
+
"source-layer": "transportation",
|
|
520
|
+
maxzoom: ZOOM.ROADS_MAJOR_CASING_EARLY_MAX,
|
|
521
|
+
filter: [
|
|
522
|
+
"all",
|
|
523
|
+
FILTERS.NOT_BRUNNEL,
|
|
524
|
+
["in", ["get", "class"], ["literal", [...ROAD_CLASSES.MAJOR]]],
|
|
525
|
+
],
|
|
526
|
+
paint: {
|
|
527
|
+
"line-color": style.major_casing_early,
|
|
528
|
+
"line-gap-width": LINE_WIDTHS.MAJOR_CASING_GAP,
|
|
529
|
+
"line-width": LINE_WIDTHS.CASING_MEDIUM,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// Major roads fill
|
|
534
|
+
layers.push(
|
|
535
|
+
createRoadLayer({
|
|
536
|
+
source,
|
|
537
|
+
style,
|
|
538
|
+
brunnel: null,
|
|
539
|
+
category: "major",
|
|
540
|
+
isCasing: false,
|
|
541
|
+
}),
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
// Highway casing early (maxzoom 12)
|
|
545
|
+
layers.push({
|
|
546
|
+
id: "roads_highway_casing_early",
|
|
547
|
+
type: "line",
|
|
548
|
+
source,
|
|
549
|
+
"source-layer": "transportation",
|
|
550
|
+
maxzoom: ZOOM.ROADS_HIGHWAY_CASING_EARLY_MAX,
|
|
551
|
+
filter: [
|
|
552
|
+
"all",
|
|
553
|
+
FILTERS.NOT_BRUNNEL,
|
|
554
|
+
["in", ["get", "class"], ["literal", [...ROAD_CLASSES.HIGHWAY]]],
|
|
555
|
+
FILTERS.NOT_RAMP,
|
|
556
|
+
],
|
|
557
|
+
paint: {
|
|
558
|
+
"line-color": style.highway_casing_early,
|
|
559
|
+
"line-gap-width": [
|
|
560
|
+
"interpolate",
|
|
561
|
+
["exponential", 1.6],
|
|
562
|
+
["zoom"],
|
|
563
|
+
3,
|
|
564
|
+
0,
|
|
565
|
+
3.5,
|
|
566
|
+
0.5,
|
|
567
|
+
18,
|
|
568
|
+
10,
|
|
569
|
+
],
|
|
570
|
+
"line-width": [
|
|
571
|
+
"interpolate",
|
|
572
|
+
["exponential", 1.6],
|
|
573
|
+
["zoom"],
|
|
574
|
+
7,
|
|
575
|
+
0,
|
|
576
|
+
7.5,
|
|
577
|
+
1,
|
|
578
|
+
],
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Highway fill
|
|
583
|
+
layers.push(
|
|
584
|
+
createRoadLayer({
|
|
585
|
+
source,
|
|
586
|
+
style,
|
|
587
|
+
brunnel: null,
|
|
588
|
+
category: "highway",
|
|
589
|
+
isCasing: false,
|
|
590
|
+
}),
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
return layers;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Creates all bridge road layers (casing + fill for each category)
|
|
598
|
+
*/
|
|
599
|
+
export function createBridgeLayers(
|
|
600
|
+
source: string,
|
|
601
|
+
style: Style,
|
|
602
|
+
): LayerSpecification[] {
|
|
603
|
+
const categories: RoadCategory[] = ["other", "link", "minor", "major"];
|
|
604
|
+
const layers: LayerSpecification[] = [];
|
|
605
|
+
|
|
606
|
+
// Casing layers first (all at z12+)
|
|
607
|
+
for (const category of categories) {
|
|
608
|
+
layers.push(
|
|
609
|
+
createRoadLayer({
|
|
610
|
+
source,
|
|
611
|
+
style,
|
|
612
|
+
brunnel: "bridge",
|
|
613
|
+
category,
|
|
614
|
+
isCasing: true,
|
|
615
|
+
minzoom: ZOOM.ROADS_BRIDGES_MIN,
|
|
616
|
+
}),
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Fill layers
|
|
621
|
+
for (const category of categories) {
|
|
622
|
+
layers.push(
|
|
623
|
+
createRoadLayer({
|
|
624
|
+
source,
|
|
625
|
+
style,
|
|
626
|
+
brunnel: "bridge",
|
|
627
|
+
category,
|
|
628
|
+
isCasing: false,
|
|
629
|
+
minzoom: ZOOM.ROADS_BRIDGES_MIN,
|
|
630
|
+
}),
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Highway casing (z12+)
|
|
635
|
+
layers.push(
|
|
636
|
+
createRoadLayer({
|
|
637
|
+
source,
|
|
638
|
+
style,
|
|
639
|
+
brunnel: "bridge",
|
|
640
|
+
category: "highway",
|
|
641
|
+
isCasing: true,
|
|
642
|
+
minzoom: ZOOM.ROADS_BRIDGES_MIN,
|
|
643
|
+
}),
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// Highway fill (no minzoom in original)
|
|
647
|
+
layers.push(
|
|
648
|
+
createRoadLayer({
|
|
649
|
+
source,
|
|
650
|
+
style,
|
|
651
|
+
brunnel: "bridge",
|
|
652
|
+
category: "highway",
|
|
653
|
+
isCasing: false,
|
|
654
|
+
}),
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
return layers;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Creates pier layer (special road type)
|
|
662
|
+
*/
|
|
663
|
+
export function createPierLayer(
|
|
664
|
+
source: string,
|
|
665
|
+
style: Style,
|
|
666
|
+
): LayerSpecification {
|
|
667
|
+
return {
|
|
668
|
+
id: "roads_pier",
|
|
669
|
+
type: "line",
|
|
670
|
+
source,
|
|
671
|
+
"source-layer": "transportation",
|
|
672
|
+
filter: ["==", "subclass", "pier"],
|
|
673
|
+
paint: {
|
|
674
|
+
"line-color": style.pier,
|
|
675
|
+
"line-width": [
|
|
676
|
+
"interpolate",
|
|
677
|
+
["exponential", 1.6],
|
|
678
|
+
["zoom"],
|
|
679
|
+
12,
|
|
680
|
+
0,
|
|
681
|
+
12.5,
|
|
682
|
+
0.5,
|
|
683
|
+
20,
|
|
684
|
+
16,
|
|
685
|
+
],
|
|
686
|
+
},
|
|
687
|
+
};
|
|
688
|
+
}
|