@tileflow/core 0.1.0-alpha.7 → 0.1.0-alpha.8
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 +56 -3
- package/dist/index.d.ts +401 -3
- package/dist/index.js +877 -321
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,203 +1,13 @@
|
|
|
1
1
|
// src/basemaps/osm.ts
|
|
2
|
+
var defaultOsmBrightSprite = "https://openmaptiles.github.io/osm-bright-gl-style/sprite";
|
|
2
3
|
function osm(options = {}) {
|
|
3
4
|
return {
|
|
4
5
|
type: "osm",
|
|
6
|
+
sprite: defaultOsmBrightSprite,
|
|
5
7
|
...options
|
|
6
8
|
};
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
// src/modules/roads/index.ts
|
|
10
|
-
function roads(options = {}) {
|
|
11
|
-
return {
|
|
12
|
-
type: "roads",
|
|
13
|
-
preset: options.preset ?? "modern",
|
|
14
|
-
...options.density ? { density: options.density } : {}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function resolveRoads(legacyRoads, moduleConfig, fallback) {
|
|
18
|
-
if (!moduleConfig) {
|
|
19
|
-
return legacyRoads ?? fallback;
|
|
20
|
-
}
|
|
21
|
-
if (moduleConfig.preset === "minimal" || moduleConfig.density === "clean") {
|
|
22
|
-
return "soft";
|
|
23
|
-
}
|
|
24
|
-
if (moduleConfig.density === "dense") {
|
|
25
|
-
return "detailed";
|
|
26
|
-
}
|
|
27
|
-
return "standard";
|
|
28
|
-
}
|
|
29
|
-
function roadLayers(source, sourceLayer, colors, roadsMode) {
|
|
30
|
-
if (roadsMode === "hidden") {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
const opacity = roadsMode === "soft" ? 0.72 : roadsMode === "standard" ? 0.84 : 0.96;
|
|
34
|
-
const casingOpacity = roadsMode === "detailed" ? 0.3 : 0.16;
|
|
35
|
-
const majorRoadFilter = classFilter(["motorway", "trunk", "primary", "secondary"]);
|
|
36
|
-
const ferryFilter = classFilter(["ferry"]);
|
|
37
|
-
const pathFilter = classFilter(["path", "track"]);
|
|
38
|
-
const railFilter = classFilter(["rail", "transit"]);
|
|
39
|
-
const minorRoadFilter = [
|
|
40
|
-
"all",
|
|
41
|
-
["!", majorRoadFilter],
|
|
42
|
-
["!", ferryFilter],
|
|
43
|
-
["!", pathFilter],
|
|
44
|
-
["!", railFilter]
|
|
45
|
-
];
|
|
46
|
-
const nonTunnelRoadFilter = ["!=", ["get", "brunnel"], "tunnel"];
|
|
47
|
-
const roadClassColor = roadClassColorExpression(colors);
|
|
48
|
-
return [
|
|
49
|
-
{
|
|
50
|
-
id: "roads-tunnels-casing",
|
|
51
|
-
type: "line",
|
|
52
|
-
source,
|
|
53
|
-
"source-layer": sourceLayer,
|
|
54
|
-
minzoom: 10,
|
|
55
|
-
filter: ["==", ["get", "brunnel"], "tunnel"],
|
|
56
|
-
paint: {
|
|
57
|
-
"line-color": colors.roads.tunnel,
|
|
58
|
-
"line-dasharray": [0.6, 0.8],
|
|
59
|
-
"line-opacity": 0.28,
|
|
60
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.5, 14, 1.7, 16, 3.8]
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
id: "roads-tunnels",
|
|
65
|
-
type: "line",
|
|
66
|
-
source,
|
|
67
|
-
"source-layer": sourceLayer,
|
|
68
|
-
minzoom: 10,
|
|
69
|
-
filter: ["==", ["get", "brunnel"], "tunnel"],
|
|
70
|
-
paint: {
|
|
71
|
-
"line-color": roadClassColor,
|
|
72
|
-
"line-dasharray": [0.6, 0.8],
|
|
73
|
-
"line-opacity": 0.2,
|
|
74
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.25, 14, 1, 16, 2.4]
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
id: "roads-casing",
|
|
79
|
-
type: "line",
|
|
80
|
-
source,
|
|
81
|
-
"source-layer": sourceLayer,
|
|
82
|
-
minzoom: 6,
|
|
83
|
-
filter: nonTunnelRoadFilter,
|
|
84
|
-
paint: {
|
|
85
|
-
"line-color": colors.roads.casing,
|
|
86
|
-
"line-opacity": casingOpacity,
|
|
87
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 6, 0.4, 12, 1.2, 16, 4]
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
id: "roads-ferry",
|
|
92
|
-
type: "line",
|
|
93
|
-
source,
|
|
94
|
-
"source-layer": sourceLayer,
|
|
95
|
-
minzoom: 5,
|
|
96
|
-
filter: ["all", nonTunnelRoadFilter, ferryFilter],
|
|
97
|
-
paint: {
|
|
98
|
-
"line-color": colors.roads.ferry,
|
|
99
|
-
"line-dasharray": [1.2, 1.1],
|
|
100
|
-
"line-opacity": opacity * 0.8,
|
|
101
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 5, 0.25, 12, 0.8, 16, 2.6]
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
id: "roads-paths",
|
|
106
|
-
type: "line",
|
|
107
|
-
source,
|
|
108
|
-
"source-layer": sourceLayer,
|
|
109
|
-
minzoom: 10,
|
|
110
|
-
filter: ["all", nonTunnelRoadFilter, pathFilter],
|
|
111
|
-
paint: {
|
|
112
|
-
"line-color": colors.roads.path,
|
|
113
|
-
"line-dasharray": [0.7, 0.7],
|
|
114
|
-
"line-opacity": opacity * 0.68,
|
|
115
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.25, 14, 0.8, 16, 2.2]
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: "roads-rail",
|
|
120
|
-
type: "line",
|
|
121
|
-
source,
|
|
122
|
-
"source-layer": sourceLayer,
|
|
123
|
-
minzoom: 7,
|
|
124
|
-
filter: ["all", nonTunnelRoadFilter, railFilter],
|
|
125
|
-
paint: {
|
|
126
|
-
"line-color": colors.roads.rail,
|
|
127
|
-
"line-opacity": opacity * 0.58,
|
|
128
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 7, 0.35, 12, 0.9, 16, 2.4]
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
id: "roads-minor",
|
|
133
|
-
type: "line",
|
|
134
|
-
source,
|
|
135
|
-
"source-layer": sourceLayer,
|
|
136
|
-
minzoom: 6,
|
|
137
|
-
filter: ["all", nonTunnelRoadFilter, minorRoadFilter],
|
|
138
|
-
paint: {
|
|
139
|
-
"line-color": colors.roads.minor,
|
|
140
|
-
"line-opacity": opacity * 0.88,
|
|
141
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 6, 0.2, 12, 0.8, 16, 3]
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
id: "roads-major",
|
|
146
|
-
type: "line",
|
|
147
|
-
source,
|
|
148
|
-
"source-layer": sourceLayer,
|
|
149
|
-
minzoom: 5,
|
|
150
|
-
filter: ["all", nonTunnelRoadFilter, majorRoadFilter],
|
|
151
|
-
paint: {
|
|
152
|
-
"line-color": roadClassColor,
|
|
153
|
-
"line-opacity": opacity,
|
|
154
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 5, 0.35, 12, 1.2, 16, 4]
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
id: "roads-bridges",
|
|
159
|
-
type: "line",
|
|
160
|
-
source,
|
|
161
|
-
"source-layer": sourceLayer,
|
|
162
|
-
minzoom: 10,
|
|
163
|
-
filter: ["==", ["get", "brunnel"], "bridge"],
|
|
164
|
-
paint: {
|
|
165
|
-
"line-color": colors.roads.bridge,
|
|
166
|
-
"line-opacity": opacity,
|
|
167
|
-
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.45, 14, 1.6, 16, 4.4]
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
];
|
|
171
|
-
}
|
|
172
|
-
function classFilter(classes) {
|
|
173
|
-
return ["match", ["get", "class"], classes, true, false];
|
|
174
|
-
}
|
|
175
|
-
function roadClassColorExpression(colors) {
|
|
176
|
-
return [
|
|
177
|
-
"match",
|
|
178
|
-
["get", "class"],
|
|
179
|
-
"motorway",
|
|
180
|
-
colors.roads.motorway,
|
|
181
|
-
"trunk",
|
|
182
|
-
colors.roads.trunk,
|
|
183
|
-
"primary",
|
|
184
|
-
colors.roads.primary,
|
|
185
|
-
"secondary",
|
|
186
|
-
colors.roads.secondary,
|
|
187
|
-
"rail",
|
|
188
|
-
colors.roads.rail,
|
|
189
|
-
"transit",
|
|
190
|
-
colors.roads.rail,
|
|
191
|
-
"ferry",
|
|
192
|
-
colors.roads.ferry,
|
|
193
|
-
"path",
|
|
194
|
-
colors.roads.path,
|
|
195
|
-
"track",
|
|
196
|
-
colors.roads.path,
|
|
197
|
-
colors.roads.minor
|
|
198
|
-
];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
11
|
// src/themes/index.ts
|
|
202
12
|
var defaultColors = {
|
|
203
13
|
background: "#F6F7F3",
|
|
@@ -366,12 +176,27 @@ function resolveColors(overrides = {}, defaults = defaultColors, moduleOverrides
|
|
|
366
176
|
country: base.text,
|
|
367
177
|
halo: base.textHalo,
|
|
368
178
|
muted: base.textMuted,
|
|
179
|
+
neighborhood: base.textMuted,
|
|
369
180
|
poi: base.textMuted,
|
|
370
181
|
primary: base.text,
|
|
371
182
|
road: base.textMuted,
|
|
372
183
|
settlement: base.text,
|
|
373
184
|
water: mix(base.water, base.text, 0.42)
|
|
374
185
|
};
|
|
186
|
+
const poiDefaults = {
|
|
187
|
+
coffee: mix(base.textMuted, base.roadMajor, 0.24),
|
|
188
|
+
culture: mix(base.textMuted, base.text, 0.18),
|
|
189
|
+
education: mix(base.textMuted, base.water, 0.18),
|
|
190
|
+
food: mix(base.textMuted, base.roadMajor, 0.34),
|
|
191
|
+
halo: labelDefaults.halo,
|
|
192
|
+
health: mix(base.textMuted, "#D45E5E", 0.22),
|
|
193
|
+
icon: labelDefaults.poi,
|
|
194
|
+
label: labelDefaults.poi,
|
|
195
|
+
lodging: mix(base.textMuted, base.water, 0.24),
|
|
196
|
+
services: labelDefaults.poi,
|
|
197
|
+
shopping: mix(base.textMuted, base.park, 0.2),
|
|
198
|
+
transit: labelDefaults.road
|
|
199
|
+
};
|
|
375
200
|
const landuseDefaults = {
|
|
376
201
|
cemetery: mix(base.park, base.land, 0.35),
|
|
377
202
|
civic: mix(base.land, base.textMuted, 0.08),
|
|
@@ -422,6 +247,7 @@ function resolveColors(overrides = {}, defaults = defaultColors, moduleOverrides
|
|
|
422
247
|
landuse: mapColorRecord(
|
|
423
248
|
resolveGroup(landuseDefaults, defaultModules.landuse, overrideModules.landuse)
|
|
424
249
|
),
|
|
250
|
+
poi: mapColorRecord(resolveGroup(poiDefaults, defaultModules.poi, overrideModules.poi)),
|
|
425
251
|
roads: mapColorRecord(resolveGroup(roadDefaults, defaultModules.roads, overrideModules.roads))
|
|
426
252
|
};
|
|
427
253
|
}
|
|
@@ -575,6 +401,7 @@ function stripLegacyModuleColors(colors) {
|
|
|
575
401
|
labels: _labels,
|
|
576
402
|
landcover: _landcover,
|
|
577
403
|
landuse: _landuse,
|
|
404
|
+
poi: _poi,
|
|
578
405
|
roads: _roads,
|
|
579
406
|
...baseColors
|
|
580
407
|
} = colors;
|
|
@@ -591,6 +418,7 @@ function extractLegacyModuleColors(colors) {
|
|
|
591
418
|
...colors.labels ? { labels: colors.labels } : {},
|
|
592
419
|
...colors.landcover ? { landcover: colors.landcover } : {},
|
|
593
420
|
...colors.landuse ? { landuse: colors.landuse } : {},
|
|
421
|
+
...colors.poi ? { poi: colors.poi } : {},
|
|
594
422
|
...colors.roads ? { roads: colors.roads } : {}
|
|
595
423
|
};
|
|
596
424
|
}
|
|
@@ -602,6 +430,7 @@ function mergeThemeModules(defaults = {}, overrides = {}) {
|
|
|
602
430
|
...mergeThemeModuleGroup("labels", defaults, overrides),
|
|
603
431
|
...mergeThemeModuleGroup("landcover", defaults, overrides),
|
|
604
432
|
...mergeThemeModuleGroup("landuse", defaults, overrides),
|
|
433
|
+
...mergeThemeModuleGroup("poi", defaults, overrides),
|
|
605
434
|
...mergeThemeModuleGroup("roads", defaults, overrides)
|
|
606
435
|
};
|
|
607
436
|
}
|
|
@@ -685,6 +514,437 @@ function rgbToHex(r, g, b) {
|
|
|
685
514
|
return `#${[r, g, b].map((value) => value.toString(16).padStart(2, "0")).join("")}`;
|
|
686
515
|
}
|
|
687
516
|
|
|
517
|
+
// src/modules/labels/index.ts
|
|
518
|
+
function labels(options = {}) {
|
|
519
|
+
return {
|
|
520
|
+
type: "labels",
|
|
521
|
+
...options.language ? { language: options.language } : {},
|
|
522
|
+
...options.places ? { places: options.places } : {},
|
|
523
|
+
...options.preset ? { preset: options.preset } : {},
|
|
524
|
+
...options.roads ? { roads: options.roads } : {},
|
|
525
|
+
...options.water ? { water: options.water } : {}
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
function resolveLabels(legacyLabels, moduleConfig, fallback) {
|
|
529
|
+
const mode = moduleConfig?.preset ?? legacyLabels ?? fallback;
|
|
530
|
+
const density = labelDensityFromMode(mode);
|
|
531
|
+
return {
|
|
532
|
+
language: moduleConfig?.language ?? "auto",
|
|
533
|
+
mode,
|
|
534
|
+
places: moduleConfig?.places ?? density,
|
|
535
|
+
roads: moduleConfig?.roads ?? density,
|
|
536
|
+
water: moduleConfig?.water ?? density
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function labelLayers(source, sourceLayer, colors, labelsConfig, typography) {
|
|
540
|
+
if (labelsConfig.mode === "none" || labelsConfig.places === "none") {
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
543
|
+
const maxRank = labelsConfig.places === "minimal" ? 3 : labelsConfig.places === "balanced" ? 7 : 12;
|
|
544
|
+
return [
|
|
545
|
+
{
|
|
546
|
+
id: "place-labels",
|
|
547
|
+
type: "symbol",
|
|
548
|
+
source,
|
|
549
|
+
"source-layer": sourceLayer,
|
|
550
|
+
minzoom: 3,
|
|
551
|
+
filter: ["<=", ["coalesce", ["get", "rank"], 10], maxRank],
|
|
552
|
+
layout: {
|
|
553
|
+
"text-field": labelTextField(labelsConfig.language),
|
|
554
|
+
"text-font": textFont(typography),
|
|
555
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], 3, 10, 8, 13, 14, 17],
|
|
556
|
+
"text-letter-spacing": 0,
|
|
557
|
+
"text-padding": 4
|
|
558
|
+
},
|
|
559
|
+
paint: {
|
|
560
|
+
"text-color": colors.labels.primary,
|
|
561
|
+
"text-halo-color": colors.labels.halo,
|
|
562
|
+
"text-halo-width": 1.2
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
function labelDensityFromMode(mode) {
|
|
568
|
+
if (mode === "none") return "none";
|
|
569
|
+
if (mode === "essential") return "minimal";
|
|
570
|
+
if (mode === "full") return "detailed";
|
|
571
|
+
return "balanced";
|
|
572
|
+
}
|
|
573
|
+
function labelTextField(language) {
|
|
574
|
+
if (language === "local") {
|
|
575
|
+
return ["coalesce", ["get", "name"], ["get", "name:latin"], ["get", "name:en"]];
|
|
576
|
+
}
|
|
577
|
+
if (language === "auto") {
|
|
578
|
+
return ["coalesce", ["get", "name:latin"], ["get", "name"], ["get", "name:en"]];
|
|
579
|
+
}
|
|
580
|
+
return ["coalesce", ["get", `name:${language}`], ["get", "name:latin"], ["get", "name"]];
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/modules/poi/index.ts
|
|
584
|
+
var defaultPoiMinZoom = {
|
|
585
|
+
none: 24,
|
|
586
|
+
minimal: 15,
|
|
587
|
+
balanced: 13,
|
|
588
|
+
full: 11
|
|
589
|
+
};
|
|
590
|
+
function poi(options = {}) {
|
|
591
|
+
return {
|
|
592
|
+
type: "poi",
|
|
593
|
+
...options.categories ? { categories: options.categories } : {},
|
|
594
|
+
...options.icons !== void 0 ? { icons: options.icons } : {},
|
|
595
|
+
...options.labels ? { labels: options.labels } : {},
|
|
596
|
+
...options.minZoom !== void 0 ? { minZoom: options.minZoom } : {},
|
|
597
|
+
...options.preset ? { preset: options.preset } : {}
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
function resolvePoi(legacyPoi, moduleConfig, fallback) {
|
|
601
|
+
const mode = moduleConfig?.preset ?? legacyPoi ?? fallback;
|
|
602
|
+
return {
|
|
603
|
+
categories: moduleConfig?.categories,
|
|
604
|
+
icons: moduleConfig?.icons ?? (mode === "none" ? false : "essential"),
|
|
605
|
+
labels: moduleConfig?.labels ?? poiLabelsFromMode(mode),
|
|
606
|
+
minZoom: moduleConfig?.minZoom ?? defaultPoiMinZoom[mode],
|
|
607
|
+
mode
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function poiLayers(source, sourceLayer, colors, poiConfig, typography, customIconSpriteId2, customIconMapping) {
|
|
611
|
+
if (poiConfig.mode === "none") {
|
|
612
|
+
return [];
|
|
613
|
+
}
|
|
614
|
+
const layout = {
|
|
615
|
+
"text-field": labelTextField("auto"),
|
|
616
|
+
"text-font": textFont(typography),
|
|
617
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], poiConfig.minZoom, 10, 17, 12],
|
|
618
|
+
"text-letter-spacing": 0,
|
|
619
|
+
"text-padding": 2
|
|
620
|
+
};
|
|
621
|
+
if (poiConfig.labels === "none") {
|
|
622
|
+
delete layout["text-field"];
|
|
623
|
+
}
|
|
624
|
+
if (poiConfig.icons) {
|
|
625
|
+
layout["icon-image"] = poiIconImageExpression(customIconSpriteId2, customIconMapping);
|
|
626
|
+
layout["icon-optional"] = true;
|
|
627
|
+
layout["icon-padding"] = 2;
|
|
628
|
+
layout["icon-size"] = ["interpolate", ["linear"], ["zoom"], poiConfig.minZoom, 0.85, 17, 1];
|
|
629
|
+
layout["text-anchor"] = "top";
|
|
630
|
+
layout["text-offset"] = [0, 0.75];
|
|
631
|
+
}
|
|
632
|
+
return [
|
|
633
|
+
{
|
|
634
|
+
id: "poi-labels",
|
|
635
|
+
type: "symbol",
|
|
636
|
+
source,
|
|
637
|
+
"source-layer": sourceLayer,
|
|
638
|
+
minzoom: poiConfig.minZoom,
|
|
639
|
+
...poiConfig.categories ? { filter: poiCategoryFilter(poiConfig.categories) } : {},
|
|
640
|
+
layout,
|
|
641
|
+
paint: {
|
|
642
|
+
"text-color": colors.poi.label,
|
|
643
|
+
"text-halo-color": colors.poi.halo ?? alpha(colors.background, 0.78),
|
|
644
|
+
"text-halo-width": 1
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
];
|
|
648
|
+
}
|
|
649
|
+
function poiLabelsFromMode(mode) {
|
|
650
|
+
if (mode === "none") return "none";
|
|
651
|
+
if (mode === "minimal") return "minimal";
|
|
652
|
+
if (mode === "full") return "full";
|
|
653
|
+
return "balanced";
|
|
654
|
+
}
|
|
655
|
+
function poiCategoryFilter(categories) {
|
|
656
|
+
return ["in", "class", ...categories.flatMap((category) => poiCategoryClasses(category))];
|
|
657
|
+
}
|
|
658
|
+
function poiIconImageExpression(customIconSpriteId2, customIconMapping = {}) {
|
|
659
|
+
const matchParts = [];
|
|
660
|
+
for (const [className, iconName] of Object.entries(poiClassIconNames)) {
|
|
661
|
+
matchParts.push(
|
|
662
|
+
className,
|
|
663
|
+
poiIconImageFallback(iconName, customIconSpriteId2, customIconMapping)
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
return [
|
|
667
|
+
"match",
|
|
668
|
+
["get", "class"],
|
|
669
|
+
...matchParts,
|
|
670
|
+
poiIconImageFallback("default", customIconSpriteId2, customIconMapping)
|
|
671
|
+
];
|
|
672
|
+
}
|
|
673
|
+
function poiCategoryClasses(category) {
|
|
674
|
+
return poiCategoryClassNames[category] ?? [category];
|
|
675
|
+
}
|
|
676
|
+
function poiIconImageFallback(iconName, customIconSpriteId2, customIconMapping) {
|
|
677
|
+
const osmBrightIcon = `${osmBrightIconNameForSemanticIcon(iconName)}_11`;
|
|
678
|
+
const customIconName = customIconMapping[iconName] ?? iconName;
|
|
679
|
+
if (!customIconSpriteId2) {
|
|
680
|
+
return ["coalesce", ["image", customIconName], ["image", osmBrightIcon]];
|
|
681
|
+
}
|
|
682
|
+
return [
|
|
683
|
+
"coalesce",
|
|
684
|
+
["image", `${customIconSpriteId2}:${customIconName}`],
|
|
685
|
+
["image", osmBrightIcon]
|
|
686
|
+
];
|
|
687
|
+
}
|
|
688
|
+
function osmBrightIconNameForSemanticIcon(iconName) {
|
|
689
|
+
return semanticToOsmBrightIconName[iconName] ?? "marker";
|
|
690
|
+
}
|
|
691
|
+
var poiCategoryClassNames = {
|
|
692
|
+
coffee: ["cafe"],
|
|
693
|
+
culture: ["museum", "gallery", "theatre", "cinema", "library", "attraction"],
|
|
694
|
+
education: ["school", "college", "university"],
|
|
695
|
+
food: ["restaurant", "fast_food", "bar", "pub", "biergarten"],
|
|
696
|
+
health: ["hospital", "pharmacy", "doctors", "dentist"],
|
|
697
|
+
lodging: ["hotel", "motel", "hostel", "guest_house"],
|
|
698
|
+
services: ["bank", "post", "toilet", "police", "fire_station", "town_hall"],
|
|
699
|
+
shopping: ["shop", "mall", "supermarket", "marketplace"],
|
|
700
|
+
transit: ["railway", "station", "bus", "bus_stop", "subway", "tram"]
|
|
701
|
+
};
|
|
702
|
+
var poiClassIconNames = {
|
|
703
|
+
attraction: "culture",
|
|
704
|
+
bank: "services",
|
|
705
|
+
bar: "food",
|
|
706
|
+
biergarten: "food",
|
|
707
|
+
bus: "transit",
|
|
708
|
+
bus_stop: "transit",
|
|
709
|
+
cafe: "coffee",
|
|
710
|
+
cinema: "culture",
|
|
711
|
+
college: "education",
|
|
712
|
+
dentist: "health",
|
|
713
|
+
doctors: "health",
|
|
714
|
+
fast_food: "food",
|
|
715
|
+
fire_station: "services",
|
|
716
|
+
gallery: "culture",
|
|
717
|
+
guest_house: "lodging",
|
|
718
|
+
hospital: "health",
|
|
719
|
+
hostel: "lodging",
|
|
720
|
+
hotel: "lodging",
|
|
721
|
+
library: "culture",
|
|
722
|
+
mall: "shopping",
|
|
723
|
+
marketplace: "shopping",
|
|
724
|
+
motel: "lodging",
|
|
725
|
+
museum: "culture",
|
|
726
|
+
pharmacy: "health",
|
|
727
|
+
police: "services",
|
|
728
|
+
post: "services",
|
|
729
|
+
pub: "food",
|
|
730
|
+
railway: "transit",
|
|
731
|
+
restaurant: "food",
|
|
732
|
+
school: "education",
|
|
733
|
+
shop: "shopping",
|
|
734
|
+
station: "transit",
|
|
735
|
+
subway: "transit",
|
|
736
|
+
supermarket: "shopping",
|
|
737
|
+
theatre: "culture",
|
|
738
|
+
toilet: "services",
|
|
739
|
+
town_hall: "services",
|
|
740
|
+
tram: "transit",
|
|
741
|
+
university: "education"
|
|
742
|
+
};
|
|
743
|
+
var semanticToOsmBrightIconName = {
|
|
744
|
+
coffee: "cafe",
|
|
745
|
+
culture: "museum",
|
|
746
|
+
default: "marker",
|
|
747
|
+
education: "school",
|
|
748
|
+
food: "restaurant",
|
|
749
|
+
health: "hospital",
|
|
750
|
+
lodging: "lodging",
|
|
751
|
+
services: "marker",
|
|
752
|
+
shopping: "shop",
|
|
753
|
+
transit: "railway"
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
// src/modules/roads/index.ts
|
|
757
|
+
function roads(options = {}) {
|
|
758
|
+
return {
|
|
759
|
+
type: "roads",
|
|
760
|
+
preset: options.preset ?? "modern",
|
|
761
|
+
...options.density ? { density: options.density } : {}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function resolveRoads(legacyRoads, moduleConfig, fallback) {
|
|
765
|
+
if (!moduleConfig) {
|
|
766
|
+
return legacyRoads ?? fallback;
|
|
767
|
+
}
|
|
768
|
+
if (moduleConfig.preset === "minimal" || moduleConfig.density === "clean") {
|
|
769
|
+
return "soft";
|
|
770
|
+
}
|
|
771
|
+
if (moduleConfig.density === "dense") {
|
|
772
|
+
return "detailed";
|
|
773
|
+
}
|
|
774
|
+
return "standard";
|
|
775
|
+
}
|
|
776
|
+
function roadLayers(source, sourceLayer, colors, roadsMode) {
|
|
777
|
+
if (roadsMode === "hidden") {
|
|
778
|
+
return [];
|
|
779
|
+
}
|
|
780
|
+
const opacity = roadsMode === "soft" ? 0.72 : roadsMode === "standard" ? 0.84 : 0.96;
|
|
781
|
+
const casingOpacity = roadsMode === "detailed" ? 0.3 : 0.16;
|
|
782
|
+
const majorRoadFilter = classFilter(["motorway", "trunk", "primary", "secondary"]);
|
|
783
|
+
const ferryFilter = classFilter(["ferry"]);
|
|
784
|
+
const pathFilter = classFilter(["path", "track"]);
|
|
785
|
+
const railFilter = classFilter(["rail", "transit"]);
|
|
786
|
+
const minorRoadFilter = [
|
|
787
|
+
"all",
|
|
788
|
+
["!", majorRoadFilter],
|
|
789
|
+
["!", ferryFilter],
|
|
790
|
+
["!", pathFilter],
|
|
791
|
+
["!", railFilter]
|
|
792
|
+
];
|
|
793
|
+
const nonTunnelRoadFilter = ["!=", ["get", "brunnel"], "tunnel"];
|
|
794
|
+
const roadClassColor = roadClassColorExpression(colors);
|
|
795
|
+
return [
|
|
796
|
+
{
|
|
797
|
+
id: "roads-tunnels-casing",
|
|
798
|
+
type: "line",
|
|
799
|
+
source,
|
|
800
|
+
"source-layer": sourceLayer,
|
|
801
|
+
minzoom: 10,
|
|
802
|
+
filter: ["==", ["get", "brunnel"], "tunnel"],
|
|
803
|
+
paint: {
|
|
804
|
+
"line-color": colors.roads.tunnel,
|
|
805
|
+
"line-dasharray": [0.6, 0.8],
|
|
806
|
+
"line-opacity": 0.28,
|
|
807
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.5, 14, 1.7, 16, 3.8]
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
id: "roads-tunnels",
|
|
812
|
+
type: "line",
|
|
813
|
+
source,
|
|
814
|
+
"source-layer": sourceLayer,
|
|
815
|
+
minzoom: 10,
|
|
816
|
+
filter: ["==", ["get", "brunnel"], "tunnel"],
|
|
817
|
+
paint: {
|
|
818
|
+
"line-color": roadClassColor,
|
|
819
|
+
"line-dasharray": [0.6, 0.8],
|
|
820
|
+
"line-opacity": 0.2,
|
|
821
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.25, 14, 1, 16, 2.4]
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
id: "roads-casing",
|
|
826
|
+
type: "line",
|
|
827
|
+
source,
|
|
828
|
+
"source-layer": sourceLayer,
|
|
829
|
+
minzoom: 6,
|
|
830
|
+
filter: nonTunnelRoadFilter,
|
|
831
|
+
paint: {
|
|
832
|
+
"line-color": colors.roads.casing,
|
|
833
|
+
"line-opacity": casingOpacity,
|
|
834
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 6, 0.4, 12, 1.2, 16, 4]
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
id: "roads-ferry",
|
|
839
|
+
type: "line",
|
|
840
|
+
source,
|
|
841
|
+
"source-layer": sourceLayer,
|
|
842
|
+
minzoom: 5,
|
|
843
|
+
filter: ["all", nonTunnelRoadFilter, ferryFilter],
|
|
844
|
+
paint: {
|
|
845
|
+
"line-color": colors.roads.ferry,
|
|
846
|
+
"line-dasharray": [1.2, 1.1],
|
|
847
|
+
"line-opacity": opacity * 0.8,
|
|
848
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 5, 0.25, 12, 0.8, 16, 2.6]
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
id: "roads-paths",
|
|
853
|
+
type: "line",
|
|
854
|
+
source,
|
|
855
|
+
"source-layer": sourceLayer,
|
|
856
|
+
minzoom: 10,
|
|
857
|
+
filter: ["all", nonTunnelRoadFilter, pathFilter],
|
|
858
|
+
paint: {
|
|
859
|
+
"line-color": colors.roads.path,
|
|
860
|
+
"line-dasharray": [0.7, 0.7],
|
|
861
|
+
"line-opacity": opacity * 0.68,
|
|
862
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.25, 14, 0.8, 16, 2.2]
|
|
863
|
+
}
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
id: "roads-rail",
|
|
867
|
+
type: "line",
|
|
868
|
+
source,
|
|
869
|
+
"source-layer": sourceLayer,
|
|
870
|
+
minzoom: 7,
|
|
871
|
+
filter: ["all", nonTunnelRoadFilter, railFilter],
|
|
872
|
+
paint: {
|
|
873
|
+
"line-color": colors.roads.rail,
|
|
874
|
+
"line-opacity": opacity * 0.58,
|
|
875
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 7, 0.35, 12, 0.9, 16, 2.4]
|
|
876
|
+
}
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
id: "roads-minor",
|
|
880
|
+
type: "line",
|
|
881
|
+
source,
|
|
882
|
+
"source-layer": sourceLayer,
|
|
883
|
+
minzoom: 6,
|
|
884
|
+
filter: ["all", nonTunnelRoadFilter, minorRoadFilter],
|
|
885
|
+
paint: {
|
|
886
|
+
"line-color": colors.roads.minor,
|
|
887
|
+
"line-opacity": opacity * 0.88,
|
|
888
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 6, 0.2, 12, 0.8, 16, 3]
|
|
889
|
+
}
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
id: "roads-major",
|
|
893
|
+
type: "line",
|
|
894
|
+
source,
|
|
895
|
+
"source-layer": sourceLayer,
|
|
896
|
+
minzoom: 5,
|
|
897
|
+
filter: ["all", nonTunnelRoadFilter, majorRoadFilter],
|
|
898
|
+
paint: {
|
|
899
|
+
"line-color": roadClassColor,
|
|
900
|
+
"line-opacity": opacity,
|
|
901
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 5, 0.35, 12, 1.2, 16, 4]
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
id: "roads-bridges",
|
|
906
|
+
type: "line",
|
|
907
|
+
source,
|
|
908
|
+
"source-layer": sourceLayer,
|
|
909
|
+
minzoom: 10,
|
|
910
|
+
filter: ["==", ["get", "brunnel"], "bridge"],
|
|
911
|
+
paint: {
|
|
912
|
+
"line-color": colors.roads.bridge,
|
|
913
|
+
"line-opacity": opacity,
|
|
914
|
+
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.45, 14, 1.6, 16, 4.4]
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
];
|
|
918
|
+
}
|
|
919
|
+
function classFilter(classes) {
|
|
920
|
+
return ["match", ["get", "class"], classes, true, false];
|
|
921
|
+
}
|
|
922
|
+
function roadClassColorExpression(colors) {
|
|
923
|
+
return [
|
|
924
|
+
"match",
|
|
925
|
+
["get", "class"],
|
|
926
|
+
"motorway",
|
|
927
|
+
colors.roads.motorway,
|
|
928
|
+
"trunk",
|
|
929
|
+
colors.roads.trunk,
|
|
930
|
+
"primary",
|
|
931
|
+
colors.roads.primary,
|
|
932
|
+
"secondary",
|
|
933
|
+
colors.roads.secondary,
|
|
934
|
+
"rail",
|
|
935
|
+
colors.roads.rail,
|
|
936
|
+
"transit",
|
|
937
|
+
colors.roads.rail,
|
|
938
|
+
"ferry",
|
|
939
|
+
colors.roads.ferry,
|
|
940
|
+
"path",
|
|
941
|
+
colors.roads.path,
|
|
942
|
+
"track",
|
|
943
|
+
colors.roads.path,
|
|
944
|
+
colors.roads.minor
|
|
945
|
+
];
|
|
946
|
+
}
|
|
947
|
+
|
|
688
948
|
// src/basemaps/osm/layers.ts
|
|
689
949
|
function openMapTilesLayers(source, sourceLayers, colors, options) {
|
|
690
950
|
return [
|
|
@@ -696,13 +956,27 @@ function openMapTilesLayers(source, sourceLayers, colors, options) {
|
|
|
696
956
|
}
|
|
697
957
|
},
|
|
698
958
|
fillLayer("landuse", source, sourceLayers.landuse, colors.landuse.residential, 0.42),
|
|
699
|
-
fillLayer(
|
|
959
|
+
fillLayer(
|
|
960
|
+
"parks",
|
|
961
|
+
source,
|
|
962
|
+
sourceLayers.park,
|
|
963
|
+
colors.landcover.park,
|
|
964
|
+
parkOpacity(options.density)
|
|
965
|
+
),
|
|
700
966
|
fillLayer("water", source, sourceLayers.water, colors.hydro.water, 1),
|
|
701
967
|
...buildingLayers(source, sourceLayers.building, colors, options.density, options.buildings),
|
|
702
968
|
...roadLayers(source, sourceLayers.road, colors, options.roads),
|
|
703
969
|
...boundaryLayers(source, sourceLayers.boundary, colors),
|
|
704
970
|
...labelLayers(source, sourceLayers.place, colors, options.labels, options.typography),
|
|
705
|
-
...poiLayers(
|
|
971
|
+
...poiLayers(
|
|
972
|
+
source,
|
|
973
|
+
sourceLayers.poi,
|
|
974
|
+
colors,
|
|
975
|
+
options.poi,
|
|
976
|
+
options.typography,
|
|
977
|
+
options.customIconSpriteId,
|
|
978
|
+
options.customIconMapping
|
|
979
|
+
)
|
|
706
980
|
];
|
|
707
981
|
}
|
|
708
982
|
function fillLayer(id, source, sourceLayer, color, opacity) {
|
|
@@ -818,61 +1092,6 @@ function boundaryLayers(source, sourceLayer, colors) {
|
|
|
818
1092
|
}
|
|
819
1093
|
];
|
|
820
1094
|
}
|
|
821
|
-
function labelLayers(source, sourceLayer, colors, labels, typography) {
|
|
822
|
-
if (labels === "none") {
|
|
823
|
-
return [];
|
|
824
|
-
}
|
|
825
|
-
const maxRank = labels === "essential" ? 3 : labels === "balanced" ? 7 : 12;
|
|
826
|
-
return [
|
|
827
|
-
{
|
|
828
|
-
id: "place-labels",
|
|
829
|
-
type: "symbol",
|
|
830
|
-
source,
|
|
831
|
-
"source-layer": sourceLayer,
|
|
832
|
-
minzoom: 3,
|
|
833
|
-
filter: ["<=", ["coalesce", ["get", "rank"], 10], maxRank],
|
|
834
|
-
layout: {
|
|
835
|
-
"text-field": ["coalesce", ["get", "name:en"], ["get", "name"]],
|
|
836
|
-
"text-font": textFont(typography),
|
|
837
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 3, 10, 8, 13, 14, 17],
|
|
838
|
-
"text-letter-spacing": 0,
|
|
839
|
-
"text-padding": 4
|
|
840
|
-
},
|
|
841
|
-
paint: {
|
|
842
|
-
"text-color": colors.labels.primary,
|
|
843
|
-
"text-halo-color": colors.labels.halo,
|
|
844
|
-
"text-halo-width": 1.2
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
];
|
|
848
|
-
}
|
|
849
|
-
function poiLayers(source, sourceLayer, colors, poi, typography) {
|
|
850
|
-
if (poi === "none") {
|
|
851
|
-
return [];
|
|
852
|
-
}
|
|
853
|
-
const minzoom = poi === "minimal" ? 15 : poi === "balanced" ? 13 : 11;
|
|
854
|
-
return [
|
|
855
|
-
{
|
|
856
|
-
id: "poi-labels",
|
|
857
|
-
type: "symbol",
|
|
858
|
-
source,
|
|
859
|
-
"source-layer": sourceLayer,
|
|
860
|
-
minzoom,
|
|
861
|
-
layout: {
|
|
862
|
-
"text-field": ["coalesce", ["get", "name:en"], ["get", "name"]],
|
|
863
|
-
"text-font": textFont(typography),
|
|
864
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], minzoom, 10, 17, 12],
|
|
865
|
-
"text-letter-spacing": 0,
|
|
866
|
-
"text-padding": 2
|
|
867
|
-
},
|
|
868
|
-
paint: {
|
|
869
|
-
"text-color": colors.labels.poi,
|
|
870
|
-
"text-halo-color": alpha(colors.background, 0.78),
|
|
871
|
-
"text-halo-width": 1
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
];
|
|
875
|
-
}
|
|
876
1095
|
function parkOpacity(density) {
|
|
877
1096
|
return density === "clean" ? 0.64 : density === "balanced" ? 0.78 : 0.9;
|
|
878
1097
|
}
|
|
@@ -983,6 +1202,7 @@ var colorConfigSchema = z.object({
|
|
|
983
1202
|
"country",
|
|
984
1203
|
"halo",
|
|
985
1204
|
"muted",
|
|
1205
|
+
"neighborhood",
|
|
986
1206
|
"poi",
|
|
987
1207
|
"primary",
|
|
988
1208
|
"road",
|
|
@@ -997,6 +1217,20 @@ var colorConfigSchema = z.object({
|
|
|
997
1217
|
"industrial",
|
|
998
1218
|
"residential"
|
|
999
1219
|
]).optional(),
|
|
1220
|
+
poi: colorGroupSchema([
|
|
1221
|
+
"coffee",
|
|
1222
|
+
"culture",
|
|
1223
|
+
"education",
|
|
1224
|
+
"food",
|
|
1225
|
+
"halo",
|
|
1226
|
+
"health",
|
|
1227
|
+
"icon",
|
|
1228
|
+
"label",
|
|
1229
|
+
"lodging",
|
|
1230
|
+
"services",
|
|
1231
|
+
"shopping",
|
|
1232
|
+
"transit"
|
|
1233
|
+
]).optional(),
|
|
1000
1234
|
roads: colorGroupSchema([
|
|
1001
1235
|
"bridge",
|
|
1002
1236
|
"casing",
|
|
@@ -1019,6 +1253,7 @@ var themeModulesSchema = z.object({
|
|
|
1019
1253
|
"country",
|
|
1020
1254
|
"halo",
|
|
1021
1255
|
"muted",
|
|
1256
|
+
"neighborhood",
|
|
1022
1257
|
"poi",
|
|
1023
1258
|
"primary",
|
|
1024
1259
|
"road",
|
|
@@ -1033,6 +1268,20 @@ var themeModulesSchema = z.object({
|
|
|
1033
1268
|
"industrial",
|
|
1034
1269
|
"residential"
|
|
1035
1270
|
]).optional(),
|
|
1271
|
+
poi: colorGroupSchema([
|
|
1272
|
+
"coffee",
|
|
1273
|
+
"culture",
|
|
1274
|
+
"education",
|
|
1275
|
+
"food",
|
|
1276
|
+
"halo",
|
|
1277
|
+
"health",
|
|
1278
|
+
"icon",
|
|
1279
|
+
"label",
|
|
1280
|
+
"lodging",
|
|
1281
|
+
"services",
|
|
1282
|
+
"shopping",
|
|
1283
|
+
"transit"
|
|
1284
|
+
]).optional(),
|
|
1036
1285
|
roads: colorGroupSchema([
|
|
1037
1286
|
"bridge",
|
|
1038
1287
|
"casing",
|
|
@@ -1103,12 +1352,43 @@ var roadsModuleSchema = z.object({
|
|
|
1103
1352
|
density: z.enum(["clean", "balanced", "dense"]).optional(),
|
|
1104
1353
|
preset: z.enum(["modern", "minimal"]).optional()
|
|
1105
1354
|
}).strict();
|
|
1355
|
+
var labelDensitySchema = z.enum(["none", "minimal", "balanced", "detailed"]);
|
|
1356
|
+
var labelsModuleSchema = z.object({
|
|
1357
|
+
type: z.literal("labels"),
|
|
1358
|
+
language: z.string().trim().min(1).optional(),
|
|
1359
|
+
places: labelDensitySchema.optional(),
|
|
1360
|
+
preset: z.enum(["none", "essential", "balanced", "full"]).optional(),
|
|
1361
|
+
roads: labelDensitySchema.optional(),
|
|
1362
|
+
water: labelDensitySchema.optional()
|
|
1363
|
+
}).strict();
|
|
1364
|
+
var poiModuleSchema = z.object({
|
|
1365
|
+
type: z.literal("poi"),
|
|
1366
|
+
categories: z.array(identifierSchema).optional(),
|
|
1367
|
+
icons: z.union([z.boolean(), z.enum(["essential", "full"])]).optional(),
|
|
1368
|
+
labels: z.enum(["none", "minimal", "balanced", "full"]).optional(),
|
|
1369
|
+
minZoom: z.number().finite().min(0).max(24).optional(),
|
|
1370
|
+
preset: z.enum(["none", "minimal", "balanced", "full"]).optional()
|
|
1371
|
+
}).strict();
|
|
1106
1372
|
var styleOverrideModuleSchema = z.object({
|
|
1107
1373
|
type: z.literal("styleOverride"),
|
|
1108
1374
|
layers: z.record(z.string(), styleLayerOverrideSchema).optional(),
|
|
1109
1375
|
removeLayers: z.array(z.string().min(1)).optional()
|
|
1110
1376
|
}).strict();
|
|
1111
|
-
var moduleSchema = z.discriminatedUnion("type", [
|
|
1377
|
+
var moduleSchema = z.discriminatedUnion("type", [
|
|
1378
|
+
labelsModuleSchema,
|
|
1379
|
+
poiModuleSchema,
|
|
1380
|
+
roadsModuleSchema,
|
|
1381
|
+
styleOverrideModuleSchema
|
|
1382
|
+
]);
|
|
1383
|
+
var iconSetSchema = z.union([
|
|
1384
|
+
z.string().trim().min(1),
|
|
1385
|
+
z.object({
|
|
1386
|
+
extends: z.string().trim().min(1).optional(),
|
|
1387
|
+
mapping: z.record(identifierSchema, z.string().trim().min(1)).optional(),
|
|
1388
|
+
source: z.string().trim().min(1).optional(),
|
|
1389
|
+
sprite: z.string().trim().min(1).optional()
|
|
1390
|
+
}).strict()
|
|
1391
|
+
]);
|
|
1112
1392
|
var viewSchema = z.object({
|
|
1113
1393
|
bearing: z.number().finite().min(-180).max(180).optional(),
|
|
1114
1394
|
center: z.tuple([z.number().finite(), z.number().finite()]).refine(([lng, lat]) => lng >= -180 && lng <= 180 && lat >= -90 && lat <= 90, {
|
|
@@ -1148,6 +1428,7 @@ var tileflowMapSchema = z.object({
|
|
|
1148
1428
|
buildings: z.enum(["hidden", "flat", "3d"]).optional(),
|
|
1149
1429
|
terrain: z.union([z.enum(["none", "hillshade", "3d"]), terrainConfigSchema]).optional(),
|
|
1150
1430
|
glyphs: z.string().min(1).optional(),
|
|
1431
|
+
icons: iconSetSchema.optional(),
|
|
1151
1432
|
sprite: z.string().min(1).optional(),
|
|
1152
1433
|
tiles: tilesSchema.optional(),
|
|
1153
1434
|
view: viewSchema.optional(),
|
|
@@ -1161,6 +1442,7 @@ var tilesetConfigSchema = z.object({
|
|
|
1161
1442
|
sourceLayers: sourceLayersSchema.optional()
|
|
1162
1443
|
}).strict();
|
|
1163
1444
|
var tileflowProjectSchema = z.object({
|
|
1445
|
+
icons: z.record(identifierSchema, iconSetSchema).optional(),
|
|
1164
1446
|
themes: z.record(identifierSchema, themeConfigSchema).optional(),
|
|
1165
1447
|
tilesets: z.record(identifierSchema, tilesetConfigSchema).optional(),
|
|
1166
1448
|
maps: z.record(identifierSchema, configSchema).refine((maps) => {
|
|
@@ -1229,10 +1511,11 @@ function isProjectConfigLike(input) {
|
|
|
1229
1511
|
function validateProjectThemeReferences(project) {
|
|
1230
1512
|
const themeNames = new Set(Object.keys(project.themes ?? {}));
|
|
1231
1513
|
const themeMessages = validateThemeExtends(project.themes, themeNames);
|
|
1514
|
+
const iconMessages = validateProjectIconReferences(project);
|
|
1232
1515
|
const mapMessages = Object.entries(project.maps).flatMap(
|
|
1233
1516
|
([mapName, mapConfig]) => validateMapThemeReference(mapConfig, themeNames, `maps.${mapName}.theme`)
|
|
1234
1517
|
);
|
|
1235
|
-
return [...themeMessages, ...mapMessages];
|
|
1518
|
+
return [...themeMessages, ...iconMessages, ...mapMessages];
|
|
1236
1519
|
}
|
|
1237
1520
|
function validateMapThemeReference(config, themeNames, path) {
|
|
1238
1521
|
if (!config.theme) {
|
|
@@ -1297,6 +1580,242 @@ function findThemeCycle(themeName, themes, path) {
|
|
|
1297
1580
|
}
|
|
1298
1581
|
return findThemeCycle(nextThemeName, themes, [...path, themeName]);
|
|
1299
1582
|
}
|
|
1583
|
+
function validateProjectIconReferences(project) {
|
|
1584
|
+
const messages = [];
|
|
1585
|
+
const iconSets = project.icons ?? {};
|
|
1586
|
+
for (const [iconSetName, iconSet] of Object.entries(iconSets)) {
|
|
1587
|
+
const extendedName = iconSetReference(iconSet);
|
|
1588
|
+
if (extendedName && !iconSets[extendedName]) {
|
|
1589
|
+
messages.push({
|
|
1590
|
+
level: "error",
|
|
1591
|
+
path: iconSetExtendsPath(`icons.${iconSetName}`, iconSet),
|
|
1592
|
+
message: `Unknown Tileflow icon set "${extendedName}"`
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
for (const iconSetName of Object.keys(iconSets)) {
|
|
1597
|
+
const cycle = findIconSetCycle(iconSetName, iconSets, []);
|
|
1598
|
+
if (cycle) {
|
|
1599
|
+
messages.push({
|
|
1600
|
+
level: "error",
|
|
1601
|
+
path: iconSetExtendsPath(`icons.${iconSetName}`, iconSets[iconSetName]),
|
|
1602
|
+
message: `Circular Tileflow icon set extends: ${cycle.join(" -> ")}`
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
for (const [mapName, mapConfig] of Object.entries(project.maps)) {
|
|
1607
|
+
if (!isIconSetObject(mapConfig.icons) || !mapConfig.icons.extends) {
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
if (!iconSets[mapConfig.icons.extends]) {
|
|
1611
|
+
messages.push({
|
|
1612
|
+
level: "error",
|
|
1613
|
+
path: `maps.${mapName}.icons.extends`,
|
|
1614
|
+
message: `Unknown Tileflow icon set "${mapConfig.icons.extends}"`
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
return messages;
|
|
1619
|
+
}
|
|
1620
|
+
function findIconSetCycle(iconSetName, iconSets, path) {
|
|
1621
|
+
if (path.includes(iconSetName)) {
|
|
1622
|
+
return [...path, iconSetName];
|
|
1623
|
+
}
|
|
1624
|
+
const nextIconSetName = iconSetReference(iconSets?.[iconSetName]);
|
|
1625
|
+
if (!nextIconSetName || !iconSets?.[nextIconSetName]) {
|
|
1626
|
+
return void 0;
|
|
1627
|
+
}
|
|
1628
|
+
return findIconSetCycle(nextIconSetName, iconSets, [...path, iconSetName]);
|
|
1629
|
+
}
|
|
1630
|
+
function iconSetReference(iconSet) {
|
|
1631
|
+
if (typeof iconSet === "string") {
|
|
1632
|
+
return iconSet;
|
|
1633
|
+
}
|
|
1634
|
+
return isIconSetObject(iconSet) ? iconSet.extends : void 0;
|
|
1635
|
+
}
|
|
1636
|
+
function iconSetExtendsPath(basePath, iconSet) {
|
|
1637
|
+
return isIconSetObject(iconSet) ? `${basePath}.extends` : basePath;
|
|
1638
|
+
}
|
|
1639
|
+
function isIconSetObject(value) {
|
|
1640
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// src/terrain/index.ts
|
|
1644
|
+
function resolveTerrain(terrain, tileBaseUrl) {
|
|
1645
|
+
if (!terrain || terrain === "none") {
|
|
1646
|
+
return void 0;
|
|
1647
|
+
}
|
|
1648
|
+
const terrainConfig = typeof terrain === "string" ? { mode: terrain } : terrain;
|
|
1649
|
+
const mode = terrainConfig.mode ?? "hillshade";
|
|
1650
|
+
if (mode === "none") {
|
|
1651
|
+
return void 0;
|
|
1652
|
+
}
|
|
1653
|
+
const sourceId = terrainConfig.sourceId ?? "tileflow-terrain";
|
|
1654
|
+
const tileset = terrainConfig.tileset ?? "terrain";
|
|
1655
|
+
const url = terrainConfig.url ?? `${tileBaseUrl}/tiles/${tileset}/tiles.json`;
|
|
1656
|
+
const encoding = terrainConfig.encoding ?? "terrarium";
|
|
1657
|
+
return {
|
|
1658
|
+
exaggeration: terrainConfig.exaggeration ?? 1.2,
|
|
1659
|
+
mode,
|
|
1660
|
+
sourceId,
|
|
1661
|
+
source: {
|
|
1662
|
+
...terrainConfig.attribution ? { attribution: terrainConfig.attribution } : {},
|
|
1663
|
+
encoding,
|
|
1664
|
+
type: "raster-dem",
|
|
1665
|
+
url
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
function withTerrainLayers(layers, terrain) {
|
|
1670
|
+
const hillshadeLayer = {
|
|
1671
|
+
id: "terrain-hillshade",
|
|
1672
|
+
type: "hillshade",
|
|
1673
|
+
source: terrain.sourceId,
|
|
1674
|
+
maxzoom: 15,
|
|
1675
|
+
paint: {
|
|
1676
|
+
"hillshade-accent-color": "rgba(255, 255, 255, 0.18)",
|
|
1677
|
+
"hillshade-exaggeration": terrain.mode === "3d" ? 0.24 : 0.42,
|
|
1678
|
+
"hillshade-highlight-color": "rgba(255, 255, 255, 0.28)",
|
|
1679
|
+
"hillshade-shadow-color": "rgba(38, 44, 50, 0.34)"
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
const insertionIndex = layers.findIndex((layer) => layer.id === "water");
|
|
1683
|
+
if (insertionIndex === -1) {
|
|
1684
|
+
return [hillshadeLayer, ...layers];
|
|
1685
|
+
}
|
|
1686
|
+
return [
|
|
1687
|
+
...layers.slice(0, insertionIndex + 1),
|
|
1688
|
+
hillshadeLayer,
|
|
1689
|
+
...layers.slice(insertionIndex + 1)
|
|
1690
|
+
];
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
// src/templates/osm-bright/controls.ts
|
|
1694
|
+
function applyOsmBrightControls(layers, options) {
|
|
1695
|
+
return layers.map((layer) => {
|
|
1696
|
+
const id = stringValue(layer.id);
|
|
1697
|
+
const sourceLayer = stringValue(layer["source-layer"]);
|
|
1698
|
+
const type = stringValue(layer.type);
|
|
1699
|
+
if (type !== "symbol") {
|
|
1700
|
+
return layer;
|
|
1701
|
+
}
|
|
1702
|
+
if (isPoiLayer(id, sourceLayer)) {
|
|
1703
|
+
return applyPoiLayerControls(
|
|
1704
|
+
layer,
|
|
1705
|
+
options.poi,
|
|
1706
|
+
options.customIconSpriteId,
|
|
1707
|
+
options.customIconMapping
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
if (isLabelLayer(id, sourceLayer)) {
|
|
1711
|
+
return applyLabelLayerControls(layer, options.labels);
|
|
1712
|
+
}
|
|
1713
|
+
return layer;
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
function applyLabelLayerControls(layer, labels2) {
|
|
1717
|
+
const id = stringValue(layer.id);
|
|
1718
|
+
const sourceLayer = stringValue(layer["source-layer"]);
|
|
1719
|
+
const group = labelGroup(id, sourceLayer);
|
|
1720
|
+
const density = labelGroupDensity(labels2, group);
|
|
1721
|
+
if (labels2.mode === "none" || density === "none") {
|
|
1722
|
+
return setLayerVisibility(layer, "none");
|
|
1723
|
+
}
|
|
1724
|
+
const nextLayer = setLayerVisibility(layer, "visible");
|
|
1725
|
+
const layout = isRecord3(nextLayer.layout) ? { ...nextLayer.layout } : {};
|
|
1726
|
+
if ("text-field" in layout && !isHighwayShieldLayer(id)) {
|
|
1727
|
+
layout["text-field"] = labelTextField(labels2.language);
|
|
1728
|
+
}
|
|
1729
|
+
if (density === "minimal") {
|
|
1730
|
+
nextLayer.minzoom = Math.max(numberValue(nextLayer.minzoom) ?? 0, minimalMinZoom(group));
|
|
1731
|
+
}
|
|
1732
|
+
if (density === "detailed") {
|
|
1733
|
+
const currentMinZoom = numberValue(nextLayer.minzoom);
|
|
1734
|
+
if (currentMinZoom !== void 0) {
|
|
1735
|
+
nextLayer.minzoom = Math.max(0, currentMinZoom - 1);
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
nextLayer.layout = layout;
|
|
1739
|
+
return nextLayer;
|
|
1740
|
+
}
|
|
1741
|
+
function applyPoiLayerControls(layer, poi2, customIconSpriteId2, customIconMapping) {
|
|
1742
|
+
if (poi2.mode === "none") {
|
|
1743
|
+
return setLayerVisibility(layer, "none");
|
|
1744
|
+
}
|
|
1745
|
+
const nextLayer = setLayerVisibility(layer, "visible");
|
|
1746
|
+
const layout = isRecord3(nextLayer.layout) ? { ...nextLayer.layout } : {};
|
|
1747
|
+
nextLayer.minzoom = Math.max(numberValue(nextLayer.minzoom) ?? 0, poi2.minZoom);
|
|
1748
|
+
if (poi2.categories && sourceLayerValue(nextLayer) === "poi") {
|
|
1749
|
+
nextLayer.filter = combineFilters(nextLayer.filter, poiCategoryFilter(poi2.categories));
|
|
1750
|
+
}
|
|
1751
|
+
if (poi2.labels === "none") {
|
|
1752
|
+
delete layout["text-field"];
|
|
1753
|
+
} else if ("text-field" in layout) {
|
|
1754
|
+
layout["text-field"] = labelTextField("auto");
|
|
1755
|
+
}
|
|
1756
|
+
if (poi2.icons === false) {
|
|
1757
|
+
delete layout["icon-image"];
|
|
1758
|
+
} else if ("icon-image" in layout || customIconSpriteId2) {
|
|
1759
|
+
layout["icon-image"] = poiIconImageExpression(customIconSpriteId2, customIconMapping);
|
|
1760
|
+
layout["icon-optional"] = true;
|
|
1761
|
+
}
|
|
1762
|
+
nextLayer.layout = layout;
|
|
1763
|
+
return nextLayer;
|
|
1764
|
+
}
|
|
1765
|
+
function labelGroupDensity(labels2, group) {
|
|
1766
|
+
if (group === "roads") return labels2.roads;
|
|
1767
|
+
if (group === "water") return labels2.water;
|
|
1768
|
+
return labels2.places;
|
|
1769
|
+
}
|
|
1770
|
+
function labelGroup(id, sourceLayer) {
|
|
1771
|
+
if (sourceLayer === "transportation_name" || id.includes("highway-name") || id.includes("highway-shield")) {
|
|
1772
|
+
return "roads";
|
|
1773
|
+
}
|
|
1774
|
+
if (sourceLayer === "water_name" || sourceLayer === "waterway" || id.includes("water-name")) {
|
|
1775
|
+
return "water";
|
|
1776
|
+
}
|
|
1777
|
+
return "places";
|
|
1778
|
+
}
|
|
1779
|
+
function minimalMinZoom(group) {
|
|
1780
|
+
if (group === "roads") return 13;
|
|
1781
|
+
if (group === "water") return 5;
|
|
1782
|
+
return 4;
|
|
1783
|
+
}
|
|
1784
|
+
function isLabelLayer(id, sourceLayer) {
|
|
1785
|
+
return sourceLayer === "place" || sourceLayer === "transportation_name" || sourceLayer === "water_name" || sourceLayer === "waterway" || id.includes("highway-name") || id.includes("highway-shield") || id.includes("water-name");
|
|
1786
|
+
}
|
|
1787
|
+
function isPoiLayer(id, sourceLayer) {
|
|
1788
|
+
return sourceLayer === "poi" || id.startsWith("poi-");
|
|
1789
|
+
}
|
|
1790
|
+
function isHighwayShieldLayer(id) {
|
|
1791
|
+
return id.includes("highway-shield");
|
|
1792
|
+
}
|
|
1793
|
+
function setLayerVisibility(layer, visibility) {
|
|
1794
|
+
const layout = isRecord3(layer.layout) ? { ...layer.layout } : {};
|
|
1795
|
+
layout.visibility = visibility;
|
|
1796
|
+
return {
|
|
1797
|
+
...layer,
|
|
1798
|
+
layout
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
function combineFilters(first, second) {
|
|
1802
|
+
if (!first) {
|
|
1803
|
+
return second;
|
|
1804
|
+
}
|
|
1805
|
+
return ["all", first, second];
|
|
1806
|
+
}
|
|
1807
|
+
function sourceLayerValue(layer) {
|
|
1808
|
+
return stringValue(layer["source-layer"]);
|
|
1809
|
+
}
|
|
1810
|
+
function stringValue(value) {
|
|
1811
|
+
return typeof value === "string" ? value : "";
|
|
1812
|
+
}
|
|
1813
|
+
function numberValue(value) {
|
|
1814
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1815
|
+
}
|
|
1816
|
+
function isRecord3(value) {
|
|
1817
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1818
|
+
}
|
|
1300
1819
|
|
|
1301
1820
|
// src/templates/osm-bright/style.json
|
|
1302
1821
|
var style_default = {
|
|
@@ -3860,68 +4379,18 @@ var style_default = {
|
|
|
3860
4379
|
id: "bright"
|
|
3861
4380
|
};
|
|
3862
4381
|
|
|
3863
|
-
// src/terrain/index.ts
|
|
3864
|
-
function resolveTerrain(terrain, tileBaseUrl) {
|
|
3865
|
-
if (!terrain || terrain === "none") {
|
|
3866
|
-
return void 0;
|
|
3867
|
-
}
|
|
3868
|
-
const terrainConfig = typeof terrain === "string" ? { mode: terrain } : terrain;
|
|
3869
|
-
const mode = terrainConfig.mode ?? "hillshade";
|
|
3870
|
-
if (mode === "none") {
|
|
3871
|
-
return void 0;
|
|
3872
|
-
}
|
|
3873
|
-
const sourceId = terrainConfig.sourceId ?? "tileflow-terrain";
|
|
3874
|
-
const tileset = terrainConfig.tileset ?? "terrain";
|
|
3875
|
-
const url = terrainConfig.url ?? `${tileBaseUrl}/tiles/${tileset}/tiles.json`;
|
|
3876
|
-
const encoding = terrainConfig.encoding ?? "terrarium";
|
|
3877
|
-
return {
|
|
3878
|
-
exaggeration: terrainConfig.exaggeration ?? 1.2,
|
|
3879
|
-
mode,
|
|
3880
|
-
sourceId,
|
|
3881
|
-
source: {
|
|
3882
|
-
...terrainConfig.attribution ? { attribution: terrainConfig.attribution } : {},
|
|
3883
|
-
encoding,
|
|
3884
|
-
type: "raster-dem",
|
|
3885
|
-
url
|
|
3886
|
-
}
|
|
3887
|
-
};
|
|
3888
|
-
}
|
|
3889
|
-
function withTerrainLayers(layers, terrain) {
|
|
3890
|
-
const hillshadeLayer = {
|
|
3891
|
-
id: "terrain-hillshade",
|
|
3892
|
-
type: "hillshade",
|
|
3893
|
-
source: terrain.sourceId,
|
|
3894
|
-
maxzoom: 15,
|
|
3895
|
-
paint: {
|
|
3896
|
-
"hillshade-accent-color": "rgba(255, 255, 255, 0.18)",
|
|
3897
|
-
"hillshade-exaggeration": terrain.mode === "3d" ? 0.24 : 0.42,
|
|
3898
|
-
"hillshade-highlight-color": "rgba(255, 255, 255, 0.28)",
|
|
3899
|
-
"hillshade-shadow-color": "rgba(38, 44, 50, 0.34)"
|
|
3900
|
-
}
|
|
3901
|
-
};
|
|
3902
|
-
const insertionIndex = layers.findIndex((layer) => layer.id === "water");
|
|
3903
|
-
if (insertionIndex === -1) {
|
|
3904
|
-
return [hillshadeLayer, ...layers];
|
|
3905
|
-
}
|
|
3906
|
-
return [
|
|
3907
|
-
...layers.slice(0, insertionIndex + 1),
|
|
3908
|
-
hillshadeLayer,
|
|
3909
|
-
...layers.slice(insertionIndex + 1)
|
|
3910
|
-
];
|
|
3911
|
-
}
|
|
3912
|
-
|
|
3913
4382
|
// src/templates/osm-bright/theme.ts
|
|
3914
4383
|
function applyOsmBrightTheme(layers, colors, theme, typography) {
|
|
3915
4384
|
if (!theme.custom && theme.name === "light") {
|
|
3916
4385
|
return layers;
|
|
3917
4386
|
}
|
|
3918
4387
|
return layers.map((layer) => {
|
|
3919
|
-
const type =
|
|
3920
|
-
const sourceLayer =
|
|
3921
|
-
const id =
|
|
4388
|
+
const type = stringValue2(layer.type);
|
|
4389
|
+
const sourceLayer = stringValue2(layer["source-layer"]);
|
|
4390
|
+
const id = stringValue2(layer.id);
|
|
3922
4391
|
const nextLayer = { ...layer };
|
|
3923
|
-
const paint =
|
|
3924
|
-
const layout =
|
|
4392
|
+
const paint = isRecord4(layer.paint) ? { ...layer.paint } : {};
|
|
4393
|
+
const layout = isRecord4(layer.layout) ? { ...layer.layout } : {};
|
|
3925
4394
|
let paintChanged = false;
|
|
3926
4395
|
let layoutChanged = false;
|
|
3927
4396
|
if (type === "background" && hasBaseColor(theme, ["background", "canvas"])) {
|
|
@@ -4032,6 +4501,9 @@ function osmBrightTextColor(id, sourceLayer, colors, theme) {
|
|
|
4032
4501
|
return shouldThemeLabelColor(theme, "road") ? colors.labels.road : void 0;
|
|
4033
4502
|
}
|
|
4034
4503
|
if (sourceLayer === "poi" || id.includes("poi")) {
|
|
4504
|
+
if (hasNestedModuleColor(theme, "poi", "label")) {
|
|
4505
|
+
return colors.poi.label;
|
|
4506
|
+
}
|
|
4035
4507
|
return shouldThemeLabelColor(theme, "poi") ? colors.labels.poi : void 0;
|
|
4036
4508
|
}
|
|
4037
4509
|
if (id.includes("country")) {
|
|
@@ -4167,10 +4639,10 @@ function hasNestedModuleColor(theme, group, key) {
|
|
|
4167
4639
|
}
|
|
4168
4640
|
return typeof value[key] === "string";
|
|
4169
4641
|
}
|
|
4170
|
-
function
|
|
4642
|
+
function isRecord4(value) {
|
|
4171
4643
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
4172
4644
|
}
|
|
4173
|
-
function
|
|
4645
|
+
function stringValue2(value) {
|
|
4174
4646
|
return typeof value === "string" ? value : "";
|
|
4175
4647
|
}
|
|
4176
4648
|
|
|
@@ -4184,7 +4656,13 @@ function createOsmBrightStyle(options) {
|
|
|
4184
4656
|
options.theme,
|
|
4185
4657
|
options.typography
|
|
4186
4658
|
);
|
|
4187
|
-
const
|
|
4659
|
+
const controlledLayers = applyOsmBrightControls(themedLayers, {
|
|
4660
|
+
customIconMapping: options.customIconMapping,
|
|
4661
|
+
customIconSpriteId: options.customIconSpriteId,
|
|
4662
|
+
labels: options.labelsModule,
|
|
4663
|
+
poi: options.poiModule
|
|
4664
|
+
});
|
|
4665
|
+
const resolvedLayers = options.terrain ? withTerrainLayers(controlledLayers, options.terrain) : controlledLayers;
|
|
4188
4666
|
return {
|
|
4189
4667
|
...template,
|
|
4190
4668
|
name: options.name,
|
|
@@ -4246,6 +4724,7 @@ var defaultConfig = {
|
|
|
4246
4724
|
};
|
|
4247
4725
|
var defaultTileBaseUrl = "https://api.tileflow.dev";
|
|
4248
4726
|
var defaultTileset = "world";
|
|
4727
|
+
var customIconSpriteId = "tileflow";
|
|
4249
4728
|
function createStyle(input = {}, options = {}) {
|
|
4250
4729
|
const parsed = configSchema.safeParse(input);
|
|
4251
4730
|
if (!parsed.success) {
|
|
@@ -4278,9 +4757,21 @@ function createStyle(input = {}, options = {}) {
|
|
|
4278
4757
|
const roadModule = config.modules?.find(
|
|
4279
4758
|
(moduleConfig) => moduleConfig.type === "roads"
|
|
4280
4759
|
);
|
|
4760
|
+
const labelsModule = config.modules?.find(
|
|
4761
|
+
(moduleConfig) => moduleConfig.type === "labels"
|
|
4762
|
+
);
|
|
4763
|
+
const poiModule = config.modules?.find(
|
|
4764
|
+
(moduleConfig) => moduleConfig.type === "poi"
|
|
4765
|
+
);
|
|
4281
4766
|
const roads2 = resolveRoads(config.roads, roadModule, theme.preset.roads ?? defaultConfig.roads);
|
|
4282
|
-
const
|
|
4283
|
-
|
|
4767
|
+
const resolvedLabels = resolveLabels(
|
|
4768
|
+
config.labels,
|
|
4769
|
+
labelsModule,
|
|
4770
|
+
theme.preset.labels ?? defaultConfig.labels
|
|
4771
|
+
);
|
|
4772
|
+
const resolvedPoi = resolvePoi(config.poi, poiModule, theme.preset.poi ?? defaultConfig.poi);
|
|
4773
|
+
const labels2 = resolvedLabels.mode;
|
|
4774
|
+
const poi2 = resolvedPoi.mode;
|
|
4284
4775
|
const buildings = config.buildings ?? "flat";
|
|
4285
4776
|
const colors = resolveColors(config.colors, theme.colors, {}, theme.modules);
|
|
4286
4777
|
const sourceId = config.tiles?.sourceId ?? basemap.sourceId ?? "tileflow";
|
|
@@ -4290,7 +4781,10 @@ function createStyle(input = {}, options = {}) {
|
|
|
4290
4781
|
const typography = resolveTypography(config.typography, theme.typography);
|
|
4291
4782
|
const terrain = resolveTerrain(config.terrain, tileBaseUrl);
|
|
4292
4783
|
const glyphs = config.glyphs ?? basemap.glyphs ?? `${tileBaseUrl}/fonts/{fontstack}/{range}.pbf`;
|
|
4293
|
-
const
|
|
4784
|
+
const iconSet = resolveIconSet(config.icons, options.iconSets);
|
|
4785
|
+
const iconSprite = iconSet?.sprite;
|
|
4786
|
+
const sprite = config.sprite ?? resolveSprite(basemap.sprite, iconSprite);
|
|
4787
|
+
const customIconSpriteName = Array.isArray(sprite) && iconSprite ? customIconSpriteId : void 0;
|
|
4294
4788
|
const attribution = config.tiles?.attribution ?? basemap.attribution ?? "\xA9 OpenMapTiles \xA9 OpenStreetMap contributors";
|
|
4295
4789
|
const metadata = {
|
|
4296
4790
|
"tileflow:basemap": basemap.type,
|
|
@@ -4298,8 +4792,15 @@ function createStyle(input = {}, options = {}) {
|
|
|
4298
4792
|
"tileflow:themeMode": theme.mode,
|
|
4299
4793
|
"tileflow:density": density,
|
|
4300
4794
|
"tileflow:roads": roads2,
|
|
4301
|
-
"tileflow:labels":
|
|
4302
|
-
"tileflow:
|
|
4795
|
+
"tileflow:labels": labels2,
|
|
4796
|
+
"tileflow:labelsModule": labelsModule,
|
|
4797
|
+
"tileflow:poi": poi2,
|
|
4798
|
+
"tileflow:poiModule": poiModule,
|
|
4799
|
+
"tileflow:icons": iconSet ? {
|
|
4800
|
+
customSpriteId: customIconSpriteName,
|
|
4801
|
+
mapping: iconSet.mapping,
|
|
4802
|
+
sprite: iconSprite
|
|
4803
|
+
} : void 0,
|
|
4303
4804
|
"tileflow:buildings": buildings,
|
|
4304
4805
|
"tileflow:modules": config.modules?.map((moduleConfig) => moduleConfig.type) ?? [],
|
|
4305
4806
|
"tileflow:themeModules": Object.keys(theme.moduleOverrides),
|
|
@@ -4327,7 +4828,13 @@ function createStyle(input = {}, options = {}) {
|
|
|
4327
4828
|
terrain,
|
|
4328
4829
|
theme,
|
|
4329
4830
|
tilesUrl,
|
|
4330
|
-
typography
|
|
4831
|
+
typography,
|
|
4832
|
+
labels: labels2,
|
|
4833
|
+
labelsModule: resolvedLabels,
|
|
4834
|
+
poi: poi2,
|
|
4835
|
+
poiModule: resolvedPoi,
|
|
4836
|
+
customIconMapping: iconSet?.mapping,
|
|
4837
|
+
customIconSpriteId: customIconSpriteName
|
|
4331
4838
|
});
|
|
4332
4839
|
return {
|
|
4333
4840
|
...style2,
|
|
@@ -4345,10 +4852,12 @@ function createStyle(input = {}, options = {}) {
|
|
|
4345
4852
|
const layers = openMapTilesLayers(sourceId, sourceLayers, colors, {
|
|
4346
4853
|
buildings,
|
|
4347
4854
|
density,
|
|
4348
|
-
labels,
|
|
4349
|
-
poi,
|
|
4855
|
+
labels: resolvedLabels,
|
|
4856
|
+
poi: resolvedPoi,
|
|
4350
4857
|
roads: roads2,
|
|
4351
|
-
typography
|
|
4858
|
+
typography,
|
|
4859
|
+
customIconMapping: iconSet?.mapping,
|
|
4860
|
+
customIconSpriteId: customIconSpriteName
|
|
4352
4861
|
});
|
|
4353
4862
|
const terrainLayers = terrain ? withTerrainLayers(layers, terrain) : layers;
|
|
4354
4863
|
const resolvedLayers = applyStyleOverrides(terrainLayers, styleOverrideModules);
|
|
@@ -4408,6 +4917,7 @@ function createStyleFromProject(projectConfig, mapName, options = {}) {
|
|
|
4408
4917
|
},
|
|
4409
4918
|
{
|
|
4410
4919
|
...options,
|
|
4920
|
+
iconSets: projectConfig.icons,
|
|
4411
4921
|
themes: projectConfig.themes,
|
|
4412
4922
|
tileset: resolvedTileset
|
|
4413
4923
|
}
|
|
@@ -4440,7 +4950,9 @@ function resolveSourceLayers(mapLayers, tilesetLayers) {
|
|
|
4440
4950
|
}
|
|
4441
4951
|
function shouldUseOsmBrightTemplate(config, basemap, theme) {
|
|
4442
4952
|
const templateTheme = theme.custom || theme.name === "light" || theme.name === "dark";
|
|
4443
|
-
return basemap.type === "osm" && templateTheme && !hasEffectiveColorOverrides(config.colors) && !config.typography && !config.density && !config.roads && !config.
|
|
4953
|
+
return basemap.type === "osm" && templateTheme && !hasEffectiveColorOverrides(config.colors) && !config.typography && !config.density && !config.roads && !config.buildings && !config.modules?.some(
|
|
4954
|
+
(moduleConfig) => moduleConfig.type !== "styleOverride" && moduleConfig.type !== "labels" && moduleConfig.type !== "poi"
|
|
4955
|
+
) && !basemap.sourceLayers && !config.tiles?.sourceLayers;
|
|
4444
4956
|
}
|
|
4445
4957
|
function hasEffectiveColorOverrides(colors) {
|
|
4446
4958
|
if (!colors) {
|
|
@@ -4450,13 +4962,13 @@ function hasEffectiveColorOverrides(colors) {
|
|
|
4450
4962
|
if (key === "accent" || value === void 0) {
|
|
4451
4963
|
return false;
|
|
4452
4964
|
}
|
|
4453
|
-
if (
|
|
4965
|
+
if (isRecord5(value)) {
|
|
4454
4966
|
return Object.values(value).some((nestedValue) => typeof nestedValue === "string");
|
|
4455
4967
|
}
|
|
4456
4968
|
return typeof value === "string";
|
|
4457
4969
|
});
|
|
4458
4970
|
}
|
|
4459
|
-
function
|
|
4971
|
+
function isRecord5(value) {
|
|
4460
4972
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
4461
4973
|
}
|
|
4462
4974
|
function normalizeBaseUrl(value) {
|
|
@@ -4468,6 +4980,48 @@ function normalizeStyleBaseUrl(value) {
|
|
|
4468
4980
|
function normalizeUrl(value) {
|
|
4469
4981
|
return value.replace(/\/+$/, "");
|
|
4470
4982
|
}
|
|
4983
|
+
function resolveIconSet(icons, iconSets, path = []) {
|
|
4984
|
+
if (!icons) {
|
|
4985
|
+
return void 0;
|
|
4986
|
+
}
|
|
4987
|
+
if (typeof icons === "string") {
|
|
4988
|
+
const referenced = iconSets?.[icons];
|
|
4989
|
+
if (referenced) {
|
|
4990
|
+
if (path.includes(icons)) {
|
|
4991
|
+
throw new Error(`Circular Tileflow icon set extends: ${[...path, icons].join(" -> ")}`);
|
|
4992
|
+
}
|
|
4993
|
+
return resolveIconSet(referenced, iconSets, [...path, icons]);
|
|
4994
|
+
}
|
|
4995
|
+
if (isSpriteReference(icons)) {
|
|
4996
|
+
return { sprite: icons };
|
|
4997
|
+
}
|
|
4998
|
+
return { source: icons };
|
|
4999
|
+
}
|
|
5000
|
+
const extended = icons.extends ? resolveIconSet(icons.extends, iconSets, path) : void 0;
|
|
5001
|
+
return {
|
|
5002
|
+
...extended,
|
|
5003
|
+
...icons,
|
|
5004
|
+
mapping: {
|
|
5005
|
+
...extended?.mapping,
|
|
5006
|
+
...icons.mapping
|
|
5007
|
+
}
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
5010
|
+
function resolveSprite(basemapSprite, iconSprite) {
|
|
5011
|
+
if (!basemapSprite) {
|
|
5012
|
+
return iconSprite;
|
|
5013
|
+
}
|
|
5014
|
+
if (!iconSprite || iconSprite === basemapSprite) {
|
|
5015
|
+
return basemapSprite;
|
|
5016
|
+
}
|
|
5017
|
+
return [
|
|
5018
|
+
{ id: "default", url: basemapSprite },
|
|
5019
|
+
{ id: customIconSpriteId, url: iconSprite }
|
|
5020
|
+
];
|
|
5021
|
+
}
|
|
5022
|
+
function isSpriteReference(value) {
|
|
5023
|
+
return value.startsWith("http://") || value.startsWith("https://") || value.startsWith("/") || value.startsWith("data:");
|
|
5024
|
+
}
|
|
4471
5025
|
|
|
4472
5026
|
// src/config.ts
|
|
4473
5027
|
function defineTileflow(config) {
|
|
@@ -4480,9 +5034,11 @@ export {
|
|
|
4480
5034
|
createStyleFromProject,
|
|
4481
5035
|
defineTileflow,
|
|
4482
5036
|
getDefaultColors2 as getDefaultColors,
|
|
5037
|
+
labels,
|
|
4483
5038
|
osm,
|
|
4484
5039
|
parseTileflowMap,
|
|
4485
5040
|
parseTileflowProject,
|
|
5041
|
+
poi,
|
|
4486
5042
|
roads,
|
|
4487
5043
|
styleOverride,
|
|
4488
5044
|
tileflowMapSchema,
|