@tileflow/core 0.1.0-alpha.33 → 0.1.0-alpha.35
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 +14 -9
- package/THIRD_PARTY_NOTICES.md +100 -6
- package/dist/browser.d.ts +687 -162
- package/dist/browser.js +9188 -4321
- package/dist/build.d.ts +16 -4
- package/dist/build.js +1753 -525
- package/dist/capture.js +1 -0
- package/dist/config-reference.json +3144 -928
- package/dist/{icon-composition-CSnN2-Xt.d.ts → icon-composition-DSjIKmrK.d.ts} +279 -6
- package/dist/index.d.ts +302 -12
- package/dist/index.js +3237 -566
- package/dist/{manifest-types-E7m23eXL.d.ts → manifest-types-Bzxon3dx.d.ts} +68 -8
- package/dist/manifest.d.ts +2 -2
- package/dist/manifest.js +80 -2
- package/dist/native-profile.js +1 -0
- package/dist/native.d.ts +13 -3
- package/dist/native.js +714 -318
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +124 -6
- package/docs/application-tile-reading.md +3 -0
- package/docs/authoring-model.md +6 -1
- package/docs/buildings-3d.md +237 -84
- package/docs/compiled-style-performance.md +14 -3
- package/docs/data-is-separate-from-design.md +137 -5
- package/docs/native-artifact-profile.md +5 -0
- package/docs/native-resource-urls.md +5 -3
- package/docs/street-lights.md +32 -5
- package/docs/theme-transitions-and-blends.md +50 -0
- package/docs/trees-3d.md +270 -0
- package/package.json +4 -3
package/dist/build.js
CHANGED
|
@@ -45,6 +45,25 @@ function compileTileflowSky(options) {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// src/buildings-3d-design.ts
|
|
49
|
+
var tileflowBuildingsMetadataKey = "tileflow:buildings";
|
|
50
|
+
var tileflowDefaultBuildings3DDesign = Object.freeze({
|
|
51
|
+
source: "tileflow",
|
|
52
|
+
layers: Object.freeze({ building: "building", places: "poi" }),
|
|
53
|
+
color: "#d8d0c0",
|
|
54
|
+
edges: 0,
|
|
55
|
+
lighting: "style",
|
|
56
|
+
colorVariation: 0,
|
|
57
|
+
verticalGradient: true,
|
|
58
|
+
nightLight: 0,
|
|
59
|
+
windows: false,
|
|
60
|
+
shadows: false,
|
|
61
|
+
occlusion: false
|
|
62
|
+
});
|
|
63
|
+
function tileflowBuildingsMetadata(design) {
|
|
64
|
+
return { version: 1, ...design };
|
|
65
|
+
}
|
|
66
|
+
|
|
48
67
|
// src/data/world-generation.ts
|
|
49
68
|
var tileflowWorldGeneration = "v1";
|
|
50
69
|
|
|
@@ -135,6 +154,7 @@ var canonicalFields = {
|
|
|
135
154
|
markings: "markings",
|
|
136
155
|
minHeight: "min_height",
|
|
137
156
|
minZoom: "min_zoom",
|
|
157
|
+
mode: "mode",
|
|
138
158
|
mtbScale: "mtb_scale",
|
|
139
159
|
name: "name",
|
|
140
160
|
nameEnglish: "name:en",
|
|
@@ -635,7 +655,16 @@ var tileflowBathymetrySourceId = "tileflow-bathymetry";
|
|
|
635
655
|
var tileflowBathymetryDemSourceId = "tileflow-bathymetry-dem";
|
|
636
656
|
var tileflowNauticalSourceId = "tileflow-nautical";
|
|
637
657
|
var tileflowBathymetryV1Schema = Object.freeze({
|
|
638
|
-
fields: Object.freeze({
|
|
658
|
+
fields: Object.freeze({
|
|
659
|
+
class: "class",
|
|
660
|
+
depth: "depth",
|
|
661
|
+
id: "id",
|
|
662
|
+
maxZoom: "max_zoom",
|
|
663
|
+
minDepth: "min_depth",
|
|
664
|
+
minZoom: "min_zoom",
|
|
665
|
+
name: "name",
|
|
666
|
+
sortKey: "sort_key"
|
|
667
|
+
}),
|
|
639
668
|
layer: "bathymetry",
|
|
640
669
|
layers: Object.freeze({
|
|
641
670
|
bands: "bathymetry",
|
|
@@ -700,6 +729,7 @@ var tileflowNauticalV1Schema = Object.freeze({
|
|
|
700
729
|
product: "nautical-v1",
|
|
701
730
|
schemaVersion: 1
|
|
702
731
|
});
|
|
732
|
+
var tileflowBathymetryNameLayerLimits = Object.freeze({ maxZoomRanges: 128 });
|
|
703
733
|
function resolveMarine(marine, apiBaseUrl = "https://api.tileflow.dev") {
|
|
704
734
|
if (marine === void 0) return void 0;
|
|
705
735
|
if (typeof marine === "string") {
|
|
@@ -739,6 +769,7 @@ function resolveBathymetry(input, apiBaseUrl) {
|
|
|
739
769
|
...advanced?.contours === void 0 ? {} : { contours: advanced.contours },
|
|
740
770
|
display,
|
|
741
771
|
...advanced?.labels === void 0 ? {} : { labels: advanced.labels },
|
|
772
|
+
...advanced?.vectorLayers === void 0 ? {} : { vectorLayers: cloneJson(advanced.vectorLayers) },
|
|
742
773
|
...reliefVisible ? { relief: resolveBathymetryRelief(reliefConfig ?? {}, apiBaseUrl) } : {},
|
|
743
774
|
...usesVector ? {
|
|
744
775
|
vector: resolveMarineSource({
|
|
@@ -850,98 +881,6 @@ function cloneJson(value) {
|
|
|
850
881
|
return JSON.parse(JSON.stringify(value));
|
|
851
882
|
}
|
|
852
883
|
|
|
853
|
-
// src/cartography/contributions.ts
|
|
854
|
-
var tileflowLayerSlots = [
|
|
855
|
-
"background",
|
|
856
|
-
"land",
|
|
857
|
-
"terrain",
|
|
858
|
-
"hydro",
|
|
859
|
-
"building-areas",
|
|
860
|
-
"transport-areas",
|
|
861
|
-
"transport-tunnel-shadow",
|
|
862
|
-
"transport-tunnel-casing",
|
|
863
|
-
"transport-tunnel-fill",
|
|
864
|
-
"transport-pedestrian-areas",
|
|
865
|
-
"aeroways",
|
|
866
|
-
"transport-surface-shadow",
|
|
867
|
-
"transport-surface-casing",
|
|
868
|
-
"transport-surface-fill",
|
|
869
|
-
"transport-bridge-shadow",
|
|
870
|
-
"transport-bridge-casing",
|
|
871
|
-
"transport-bridge-fill",
|
|
872
|
-
"transport-symbols",
|
|
873
|
-
"boundaries",
|
|
874
|
-
"buildings",
|
|
875
|
-
"vegetation",
|
|
876
|
-
"symbols"
|
|
877
|
-
];
|
|
878
|
-
var tileflowLayerBands = [
|
|
879
|
-
"land",
|
|
880
|
-
"relief",
|
|
881
|
-
"water",
|
|
882
|
-
"roads",
|
|
883
|
-
"boundaries",
|
|
884
|
-
"buildings",
|
|
885
|
-
"vegetation",
|
|
886
|
-
"labels"
|
|
887
|
-
];
|
|
888
|
-
var bandSlots = {
|
|
889
|
-
land: ["background", "land"],
|
|
890
|
-
relief: ["terrain", "terrain"],
|
|
891
|
-
water: ["hydro", "hydro"],
|
|
892
|
-
roads: ["transport-areas", "transport-symbols"],
|
|
893
|
-
boundaries: ["boundaries", "boundaries"],
|
|
894
|
-
buildings: ["buildings", "buildings"],
|
|
895
|
-
vegetation: ["vegetation", "vegetation"],
|
|
896
|
-
labels: ["symbols", "symbols"]
|
|
897
|
-
};
|
|
898
|
-
var tileflowBandPlacements = tileflowLayerBands.flatMap(
|
|
899
|
-
(band) => [`below-${band}`, `above-${band}`]
|
|
900
|
-
);
|
|
901
|
-
function tileflowBandPlacementSlot(placement) {
|
|
902
|
-
const [side, band] = splitBandPlacement(placement);
|
|
903
|
-
return bandSlots[band][side === "below" ? 0 : 1];
|
|
904
|
-
}
|
|
905
|
-
function tileflowBandPlacementIndex(slotRanks, placement) {
|
|
906
|
-
const [side, band] = splitBandPlacement(placement);
|
|
907
|
-
const [first, last] = bandSlots[band];
|
|
908
|
-
const threshold = side === "below" ? tileflowLayerSlots.indexOf(first) : tileflowLayerSlots.indexOf(last) + 1;
|
|
909
|
-
const index = slotRanks.findIndex((rank) => rank !== void 0 && rank >= threshold);
|
|
910
|
-
return index < 0 ? slotRanks.length : index;
|
|
911
|
-
}
|
|
912
|
-
function splitBandPlacement(placement) {
|
|
913
|
-
const separator = placement.indexOf("-");
|
|
914
|
-
return [
|
|
915
|
-
placement.slice(0, separator),
|
|
916
|
-
placement.slice(separator + 1)
|
|
917
|
-
];
|
|
918
|
-
}
|
|
919
|
-
var tileflowSemanticTargetPattern = /^[a-z][a-z0-9-]*(?:\.[A-Za-z0-9_-]+)*$/u;
|
|
920
|
-
var tileflowRenderStackOperationNamePattern = /^[a-z][A-Za-z0-9_-]*$/u;
|
|
921
|
-
var tileflowCompilerMetadataKeys = Object.freeze({
|
|
922
|
-
owner: "tileflow:compiler-owner",
|
|
923
|
-
slot: "tileflow:compiler-slot",
|
|
924
|
-
target: "tileflow:compiler-target"
|
|
925
|
-
});
|
|
926
|
-
|
|
927
|
-
// src/modules/addresses/index.ts
|
|
928
|
-
function addresses(options = {}) {
|
|
929
|
-
return { type: "addresses", ...cloneJson2(options) };
|
|
930
|
-
}
|
|
931
|
-
function cloneJson2(value) {
|
|
932
|
-
return JSON.parse(JSON.stringify(value));
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
// src/cartography/context.ts
|
|
936
|
-
function typographyTextStyle(typography) {
|
|
937
|
-
return {
|
|
938
|
-
font: typography.font,
|
|
939
|
-
...typography.fallbacks ? { fallbacks: typography.fallbacks } : {},
|
|
940
|
-
...typography.letterSpacing === void 0 ? {} : { letterSpacing: typography.letterSpacing },
|
|
941
|
-
...typography.transform === void 0 ? {} : { transform: typography.transform }
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
|
|
945
884
|
// src/cartography/layer-style.ts
|
|
946
885
|
import { Color as Color2 } from "@maplibre/maplibre-gl-style-spec";
|
|
947
886
|
|
|
@@ -997,20 +936,20 @@ function createTileflowLineBackgroundFontStack(source, metrics = {}) {
|
|
|
997
936
|
return stack;
|
|
998
937
|
}
|
|
999
938
|
function parseTileflowLineBackgroundFontStack(stack) {
|
|
1000
|
-
const
|
|
1001
|
-
if (!
|
|
939
|
+
const match3 = STACK_PATTERN.exec(stack);
|
|
940
|
+
if (!match3 || stack.length > MAX_STACK_LENGTH || !SOURCE_PATTERN.test(match3[1]))
|
|
1002
941
|
return void 0;
|
|
1003
942
|
const metrics = {
|
|
1004
|
-
letterSpacing: Number(
|
|
1005
|
-
lineHeight: Number(
|
|
1006
|
-
padding: Number(
|
|
943
|
+
letterSpacing: Number(match3[2]) / 1e3,
|
|
944
|
+
lineHeight: Number(match3[3]) / 1e3,
|
|
945
|
+
padding: Number(match3[4]) / 1e3
|
|
1007
946
|
};
|
|
1008
947
|
try {
|
|
1009
948
|
const normalized = normalizeTileflowLineBackgroundMetrics(metrics);
|
|
1010
|
-
if (`lines-v1-t${thousandths(normalized.letterSpacing)}-l${thousandths(normalized.lineHeight)}-p${thousandths(normalized.padding)}` !== stack.slice(
|
|
949
|
+
if (`lines-v1-t${thousandths(normalized.letterSpacing)}-l${thousandths(normalized.lineHeight)}-p${thousandths(normalized.padding)}` !== stack.slice(match3[1].length + 1)) {
|
|
1011
950
|
return void 0;
|
|
1012
951
|
}
|
|
1013
|
-
return { metrics: normalized, source:
|
|
952
|
+
return { metrics: normalized, source: match3[1] };
|
|
1014
953
|
} catch {
|
|
1015
954
|
return void 0;
|
|
1016
955
|
}
|
|
@@ -1169,11 +1108,11 @@ var zoom = {
|
|
|
1169
1108
|
};
|
|
1170
1109
|
function expression(value) {
|
|
1171
1110
|
validateExpressionArray(value, "expression");
|
|
1172
|
-
return { kind: "expression", value:
|
|
1111
|
+
return { kind: "expression", value: cloneJson2(value) };
|
|
1173
1112
|
}
|
|
1174
1113
|
function toMapLibreStyleValue(value) {
|
|
1175
1114
|
if (isTileflowExpression(value)) {
|
|
1176
|
-
return
|
|
1115
|
+
return cloneJson2(value.value);
|
|
1177
1116
|
}
|
|
1178
1117
|
if (isTileflowZoomValue(value)) {
|
|
1179
1118
|
if (value.interpolation === "step") {
|
|
@@ -1181,8 +1120,8 @@ function toMapLibreStyleValue(value) {
|
|
|
1181
1120
|
return [
|
|
1182
1121
|
"step",
|
|
1183
1122
|
["zoom"],
|
|
1184
|
-
|
|
1185
|
-
...rest.flatMap(([stop, stopValue]) => [stop,
|
|
1123
|
+
cloneJson2(firstValue),
|
|
1124
|
+
...rest.flatMap(([stop, stopValue]) => [stop, cloneJson2(stopValue)])
|
|
1186
1125
|
];
|
|
1187
1126
|
}
|
|
1188
1127
|
const interpolation = value.interpolation === "exponential" ? ["exponential", value.base] : [value.interpolation];
|
|
@@ -1190,13 +1129,13 @@ function toMapLibreStyleValue(value) {
|
|
|
1190
1129
|
"interpolate",
|
|
1191
1130
|
interpolation,
|
|
1192
1131
|
["zoom"],
|
|
1193
|
-
...value.stops.flatMap(([stop, stopValue]) => [stop,
|
|
1132
|
+
...value.stops.flatMap(([stop, stopValue]) => [stop, cloneJson2(stopValue)])
|
|
1194
1133
|
];
|
|
1195
1134
|
}
|
|
1196
1135
|
if (isTileflowThemeValueNode(value)) {
|
|
1197
1136
|
throw new Error("Tileflow theme values must be resolved before MapLibre style compilation.");
|
|
1198
1137
|
}
|
|
1199
|
-
return
|
|
1138
|
+
return cloneJson2(value);
|
|
1200
1139
|
}
|
|
1201
1140
|
function isTileflowExpression(value) {
|
|
1202
1141
|
return isRecord(value) && value.kind === "expression" && Array.isArray(value.value);
|
|
@@ -1233,7 +1172,7 @@ function createZoomValue(interpolation, stops, base) {
|
|
|
1233
1172
|
throw new Error("Tileflow zoom stops must be strictly increasing.");
|
|
1234
1173
|
}
|
|
1235
1174
|
previous = stop;
|
|
1236
|
-
return [stop,
|
|
1175
|
+
return [stop, cloneJson2(value)];
|
|
1237
1176
|
});
|
|
1238
1177
|
return {
|
|
1239
1178
|
kind: "zoom",
|
|
@@ -1249,9 +1188,9 @@ function validateExpressionArray(value, name) {
|
|
|
1249
1188
|
if (!isMapLibreExpressionOperator(value[0])) {
|
|
1250
1189
|
throw new Error(`Unknown MapLibre expression operator: ${value[0]}`);
|
|
1251
1190
|
}
|
|
1252
|
-
|
|
1191
|
+
cloneJson2(value);
|
|
1253
1192
|
}
|
|
1254
|
-
function
|
|
1193
|
+
function cloneJson2(value) {
|
|
1255
1194
|
const serialized = JSON.stringify(value);
|
|
1256
1195
|
if (serialized === void 0) {
|
|
1257
1196
|
throw new Error("Tileflow style values must be JSON-serializable.");
|
|
@@ -1571,30 +1510,30 @@ function asRecord(value) {
|
|
|
1571
1510
|
|
|
1572
1511
|
// src/cartography/merge.ts
|
|
1573
1512
|
function mergeTileflowDesign(base, ...overlays) {
|
|
1574
|
-
let resolved =
|
|
1513
|
+
let resolved = cloneJson3(base);
|
|
1575
1514
|
for (const overlay of overlays) {
|
|
1576
1515
|
resolved = mergeValue(resolved, overlay);
|
|
1577
1516
|
}
|
|
1578
1517
|
return resolved;
|
|
1579
1518
|
}
|
|
1580
1519
|
function mergeValue(base, overlay) {
|
|
1581
|
-
if (overlay === void 0) return
|
|
1520
|
+
if (overlay === void 0) return cloneJson3(base);
|
|
1582
1521
|
if (Array.isArray(overlay) || isTileflowExpression(overlay) || isTileflowThemeValueNode(overlay) || isTileflowZoomValue(overlay) || !isRecord2(overlay)) {
|
|
1583
|
-
return
|
|
1522
|
+
return cloneJson3(overlay);
|
|
1584
1523
|
}
|
|
1585
1524
|
const baseRecord = isRecord2(base) ? base : {};
|
|
1586
1525
|
const result = {};
|
|
1587
1526
|
for (const key of /* @__PURE__ */ new Set([...Object.keys(baseRecord), ...Object.keys(overlay)])) {
|
|
1588
1527
|
const overlayValue = overlay[key];
|
|
1589
1528
|
if (overlayValue === void 0) {
|
|
1590
|
-
if (key in baseRecord) result[key] =
|
|
1529
|
+
if (key in baseRecord) result[key] = cloneJson3(baseRecord[key]);
|
|
1591
1530
|
continue;
|
|
1592
1531
|
}
|
|
1593
1532
|
result[key] = mergeValue(baseRecord[key], overlayValue);
|
|
1594
1533
|
}
|
|
1595
1534
|
return result;
|
|
1596
1535
|
}
|
|
1597
|
-
function
|
|
1536
|
+
function cloneJson3(value) {
|
|
1598
1537
|
if (value === void 0) return value;
|
|
1599
1538
|
return JSON.parse(JSON.stringify(value));
|
|
1600
1539
|
}
|
|
@@ -1602,6 +1541,306 @@ function isRecord2(value) {
|
|
|
1602
1541
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1603
1542
|
}
|
|
1604
1543
|
|
|
1544
|
+
// src/trees-3d.ts
|
|
1545
|
+
var tileflowWorldTreeFields = Object.freeze({
|
|
1546
|
+
height: "height",
|
|
1547
|
+
diameterCrown: "diameter_crown",
|
|
1548
|
+
circumference: "circumference",
|
|
1549
|
+
genus: "genus",
|
|
1550
|
+
species: "species",
|
|
1551
|
+
leafType: "leaf_type",
|
|
1552
|
+
taxon: "taxon",
|
|
1553
|
+
canopyRank: "rank",
|
|
1554
|
+
canopyClearance: "clearance_px_z15",
|
|
1555
|
+
canopyCover: "cover_pct",
|
|
1556
|
+
canopyHeight: "height_m"
|
|
1557
|
+
});
|
|
1558
|
+
var tileflowDefaultUnknownTreeForms = Object.freeze({
|
|
1559
|
+
round: 1,
|
|
1560
|
+
open: 1,
|
|
1561
|
+
tall: 1
|
|
1562
|
+
});
|
|
1563
|
+
var broadleaves = Object.freeze({
|
|
1564
|
+
...Object.fromEntries(
|
|
1565
|
+
[
|
|
1566
|
+
"acacia",
|
|
1567
|
+
"albizia",
|
|
1568
|
+
"arbutus",
|
|
1569
|
+
"bursera",
|
|
1570
|
+
"ceratonia",
|
|
1571
|
+
"delonix",
|
|
1572
|
+
"ficus",
|
|
1573
|
+
"gleditsia",
|
|
1574
|
+
"jacaranda",
|
|
1575
|
+
"olea",
|
|
1576
|
+
"quercus",
|
|
1577
|
+
"robinia",
|
|
1578
|
+
"schinus",
|
|
1579
|
+
"sophora",
|
|
1580
|
+
"styphnolobium",
|
|
1581
|
+
"tamarix"
|
|
1582
|
+
].map((genus) => [genus, "open"])
|
|
1583
|
+
),
|
|
1584
|
+
...Object.fromEntries(
|
|
1585
|
+
[
|
|
1586
|
+
"betula",
|
|
1587
|
+
"celtis",
|
|
1588
|
+
"fraxinus",
|
|
1589
|
+
"ginkgo",
|
|
1590
|
+
"liquidambar",
|
|
1591
|
+
"liriodendron",
|
|
1592
|
+
"magnolia",
|
|
1593
|
+
"platanus",
|
|
1594
|
+
"populus",
|
|
1595
|
+
"pyrus",
|
|
1596
|
+
"ulmus",
|
|
1597
|
+
"zelkova"
|
|
1598
|
+
].map((genus) => [genus, "tall"])
|
|
1599
|
+
),
|
|
1600
|
+
...Object.fromEntries(
|
|
1601
|
+
[
|
|
1602
|
+
"acer",
|
|
1603
|
+
"aesculus",
|
|
1604
|
+
"carpinus",
|
|
1605
|
+
"castanea",
|
|
1606
|
+
"catalpa",
|
|
1607
|
+
"cercis",
|
|
1608
|
+
"citrus",
|
|
1609
|
+
"fagus",
|
|
1610
|
+
"lagerstroemia",
|
|
1611
|
+
"malus",
|
|
1612
|
+
"melia",
|
|
1613
|
+
"morus",
|
|
1614
|
+
"prunus",
|
|
1615
|
+
"sorbus",
|
|
1616
|
+
"tilia"
|
|
1617
|
+
].map((genus) => [genus, "round"])
|
|
1618
|
+
)
|
|
1619
|
+
});
|
|
1620
|
+
var tileflowTreeModelIdPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
1621
|
+
var tileflowVegetationMetadataKey = "tileflow:vegetation";
|
|
1622
|
+
function tileflowVegetationMetadata(vegetation2) {
|
|
1623
|
+
return { version: 1, ...vegetation2 };
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
// src/modules/vegetation/compiler.ts
|
|
1627
|
+
function compileVegetation(request, context) {
|
|
1628
|
+
const minZoom = request?.flat?.minZoom ?? 16;
|
|
1629
|
+
const mode = request?.mode ?? "3d";
|
|
1630
|
+
const config = mergeTileflowDesign(
|
|
1631
|
+
{
|
|
1632
|
+
type: "vegetation",
|
|
1633
|
+
enabled: true,
|
|
1634
|
+
flat: {
|
|
1635
|
+
color: context.colors.landcover.wood,
|
|
1636
|
+
minZoom,
|
|
1637
|
+
opacity: mode === "3d" ? 0.82 : 0.9,
|
|
1638
|
+
pitchAlignment: "map",
|
|
1639
|
+
pitchScale: "map",
|
|
1640
|
+
radius: minZoom < 24 ? zoom.linear([
|
|
1641
|
+
[minZoom, 2.2],
|
|
1642
|
+
[minZoom < 20 ? 20 : 24, 8]
|
|
1643
|
+
]) : 2.2,
|
|
1644
|
+
strokeColor: context.colors.park,
|
|
1645
|
+
strokeOpacity: 0.55,
|
|
1646
|
+
strokeWidth: 0.8
|
|
1647
|
+
},
|
|
1648
|
+
mode,
|
|
1649
|
+
threeDimensional: {
|
|
1650
|
+
barkColor: context.colors.vegetation.tree.bark,
|
|
1651
|
+
broadleafColors: context.colors.vegetation.tree.broadleaf,
|
|
1652
|
+
coniferColors: context.colors.vegetation.tree.conifer,
|
|
1653
|
+
palmColors: context.colors.vegetation.tree.palm,
|
|
1654
|
+
crownScale: 1,
|
|
1655
|
+
heightScale: 1
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
request
|
|
1659
|
+
);
|
|
1660
|
+
if (config.enabled === false || !context.data.schema.layers.tree) return [];
|
|
1661
|
+
const resolvedMode = config.mode ?? "3d";
|
|
1662
|
+
return [
|
|
1663
|
+
{
|
|
1664
|
+
kind: "layer",
|
|
1665
|
+
layer: applyCircleStyle(
|
|
1666
|
+
{
|
|
1667
|
+
id: "tileflow-vegetation-trees",
|
|
1668
|
+
type: "circle",
|
|
1669
|
+
source: context.data.sourceId,
|
|
1670
|
+
"source-layer": context.data.schema.layers.tree,
|
|
1671
|
+
// The layer also holds rows of trees as lines; a circle on each vertex would misdraw them.
|
|
1672
|
+
filter: ["==", ["geometry-type"], "Point"],
|
|
1673
|
+
metadata: {
|
|
1674
|
+
"tileflow:vegetation-mode": resolvedMode,
|
|
1675
|
+
...resolvedMode === "3d" ? { "tileflow:vegetation-fallback": "flat-circle" } : {}
|
|
1676
|
+
}
|
|
1677
|
+
},
|
|
1678
|
+
config.flat ?? {}
|
|
1679
|
+
),
|
|
1680
|
+
localOrder: 1,
|
|
1681
|
+
owner: "vegetation",
|
|
1682
|
+
slot: "vegetation",
|
|
1683
|
+
target: "vegetation.trees"
|
|
1684
|
+
}
|
|
1685
|
+
];
|
|
1686
|
+
}
|
|
1687
|
+
function tileflowVegetationDescription(request, context) {
|
|
1688
|
+
const { schema } = context.data;
|
|
1689
|
+
if (request?.enabled === false || request?.mode === "flat" || !schema.layers.tree)
|
|
1690
|
+
return void 0;
|
|
1691
|
+
const tree = context.colors.vegetation.tree;
|
|
1692
|
+
const style = request?.threeDimensional ?? {};
|
|
1693
|
+
const colours = (value, fallback) => Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string") ? value : [...fallback];
|
|
1694
|
+
const number = (value) => {
|
|
1695
|
+
const resolved = value === void 0 ? void 0 : toMapLibreStyleValue(value);
|
|
1696
|
+
return typeof resolved === "number" && resolved > 0 ? resolved : 1;
|
|
1697
|
+
};
|
|
1698
|
+
const field2 = (name, fallback) => schema.fields[name] ?? fallback;
|
|
1699
|
+
return {
|
|
1700
|
+
source: context.data.sourceId,
|
|
1701
|
+
layers: {
|
|
1702
|
+
tree: schema.layers.tree,
|
|
1703
|
+
...schema.layers.canopy ? { canopy: schema.layers.canopy } : {}
|
|
1704
|
+
},
|
|
1705
|
+
fields: {
|
|
1706
|
+
...tileflowWorldTreeFields,
|
|
1707
|
+
height: field2("height", tileflowWorldTreeFields.height),
|
|
1708
|
+
diameterCrown: field2("diameterCrown", tileflowWorldTreeFields.diameterCrown),
|
|
1709
|
+
genus: field2("genus", tileflowWorldTreeFields.genus),
|
|
1710
|
+
species: field2("species", tileflowWorldTreeFields.species),
|
|
1711
|
+
leafType: field2("leafType", tileflowWorldTreeFields.leafType),
|
|
1712
|
+
canopyRank: field2("canopyRank", tileflowWorldTreeFields.canopyRank),
|
|
1713
|
+
canopyClearance: field2("canopyClearanceAtZoom15", tileflowWorldTreeFields.canopyClearance),
|
|
1714
|
+
canopyCover: field2("canopyCoverPercent", tileflowWorldTreeFields.canopyCover)
|
|
1715
|
+
},
|
|
1716
|
+
colors: {
|
|
1717
|
+
bark: typeof style.barkColor === "string" ? style.barkColor : tree.bark,
|
|
1718
|
+
broadleaf: colours(style.broadleafColors, tree.broadleaf),
|
|
1719
|
+
conifer: colours(style.coniferColors, tree.conifer),
|
|
1720
|
+
palm: colours(style.palmColors, tree.palm)
|
|
1721
|
+
},
|
|
1722
|
+
heightScale: number(style.heightScale),
|
|
1723
|
+
crownScale: number(style.crownScale),
|
|
1724
|
+
forms: Object.fromEntries(
|
|
1725
|
+
Object.entries(style.forms ?? {}).map(([form, own]) => [
|
|
1726
|
+
form,
|
|
1727
|
+
{
|
|
1728
|
+
heightScale: number(own?.heightScale),
|
|
1729
|
+
crownScale: number(own?.crownScale),
|
|
1730
|
+
...own?.models?.length ? { models: [...own.models] } : {}
|
|
1731
|
+
}
|
|
1732
|
+
])
|
|
1733
|
+
),
|
|
1734
|
+
// Filled by the compiler from the map's prepared models.
|
|
1735
|
+
models: {},
|
|
1736
|
+
finish: style.finish ?? "faceted",
|
|
1737
|
+
edges: (() => {
|
|
1738
|
+
const edges = toMapLibreStyleValue(style.edges ?? 0);
|
|
1739
|
+
return typeof edges === "number" ? edges : 0;
|
|
1740
|
+
})(),
|
|
1741
|
+
...(() => {
|
|
1742
|
+
const edgeColor = style.edgeColor === void 0 ? void 0 : toMapLibreStyleValue(style.edgeColor);
|
|
1743
|
+
return typeof edgeColor === "string" ? { edgeColor } : {};
|
|
1744
|
+
})(),
|
|
1745
|
+
unknownForms: style.unknownForms ?? tileflowDefaultUnknownTreeForms,
|
|
1746
|
+
regions: style.regions ?? [],
|
|
1747
|
+
// Filled by the compiler once the style's layers are final.
|
|
1748
|
+
flatLayers: []
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// src/cartography/contributions.ts
|
|
1753
|
+
var tileflowLayerSlots = [
|
|
1754
|
+
"background",
|
|
1755
|
+
"land",
|
|
1756
|
+
"terrain",
|
|
1757
|
+
"hydro",
|
|
1758
|
+
"building-areas",
|
|
1759
|
+
"transport-areas",
|
|
1760
|
+
"transport-tunnel-shadow",
|
|
1761
|
+
"transport-tunnel-casing",
|
|
1762
|
+
"transport-tunnel-fill",
|
|
1763
|
+
"transport-pedestrian-areas",
|
|
1764
|
+
"aeroways",
|
|
1765
|
+
"transport-surface-shadow",
|
|
1766
|
+
"transport-surface-casing",
|
|
1767
|
+
"transport-surface-fill",
|
|
1768
|
+
"transport-bridge-shadow",
|
|
1769
|
+
"transport-bridge-casing",
|
|
1770
|
+
"transport-bridge-fill",
|
|
1771
|
+
"transport-symbols",
|
|
1772
|
+
"boundaries",
|
|
1773
|
+
"buildings",
|
|
1774
|
+
"vegetation",
|
|
1775
|
+
"symbols"
|
|
1776
|
+
];
|
|
1777
|
+
var tileflowLayerBands = [
|
|
1778
|
+
"land",
|
|
1779
|
+
"relief",
|
|
1780
|
+
"water",
|
|
1781
|
+
"roads",
|
|
1782
|
+
"boundaries",
|
|
1783
|
+
"buildings",
|
|
1784
|
+
"vegetation",
|
|
1785
|
+
"labels"
|
|
1786
|
+
];
|
|
1787
|
+
var bandSlots = {
|
|
1788
|
+
land: ["background", "land"],
|
|
1789
|
+
relief: ["terrain", "terrain"],
|
|
1790
|
+
water: ["hydro", "hydro"],
|
|
1791
|
+
roads: ["transport-areas", "transport-symbols"],
|
|
1792
|
+
boundaries: ["boundaries", "boundaries"],
|
|
1793
|
+
buildings: ["buildings", "buildings"],
|
|
1794
|
+
vegetation: ["vegetation", "vegetation"],
|
|
1795
|
+
labels: ["symbols", "symbols"]
|
|
1796
|
+
};
|
|
1797
|
+
var tileflowBandPlacements = tileflowLayerBands.flatMap(
|
|
1798
|
+
(band) => [`below-${band}`, `above-${band}`]
|
|
1799
|
+
);
|
|
1800
|
+
function tileflowBandPlacementSlot(placement) {
|
|
1801
|
+
const [side, band] = splitBandPlacement(placement);
|
|
1802
|
+
return bandSlots[band][side === "below" ? 0 : 1];
|
|
1803
|
+
}
|
|
1804
|
+
function tileflowBandPlacementIndex(slotRanks, placement) {
|
|
1805
|
+
const [side, band] = splitBandPlacement(placement);
|
|
1806
|
+
const [first, last] = bandSlots[band];
|
|
1807
|
+
const threshold = side === "below" ? tileflowLayerSlots.indexOf(first) : tileflowLayerSlots.indexOf(last) + 1;
|
|
1808
|
+
const index = slotRanks.findIndex((rank) => rank !== void 0 && rank >= threshold);
|
|
1809
|
+
return index < 0 ? slotRanks.length : index;
|
|
1810
|
+
}
|
|
1811
|
+
function splitBandPlacement(placement) {
|
|
1812
|
+
const separator = placement.indexOf("-");
|
|
1813
|
+
return [
|
|
1814
|
+
placement.slice(0, separator),
|
|
1815
|
+
placement.slice(separator + 1)
|
|
1816
|
+
];
|
|
1817
|
+
}
|
|
1818
|
+
var tileflowSemanticTargetPattern = /^[a-z][a-z0-9-]*(?:\.[A-Za-z0-9_-]+)*$/u;
|
|
1819
|
+
var tileflowRenderStackOperationNamePattern = /^[a-z][A-Za-z0-9_-]*$/u;
|
|
1820
|
+
var tileflowCompilerMetadataKeys = Object.freeze({
|
|
1821
|
+
owner: "tileflow:compiler-owner",
|
|
1822
|
+
slot: "tileflow:compiler-slot",
|
|
1823
|
+
target: "tileflow:compiler-target"
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
// src/modules/addresses/index.ts
|
|
1827
|
+
function addresses(options = {}) {
|
|
1828
|
+
return { type: "addresses", ...cloneJson4(options) };
|
|
1829
|
+
}
|
|
1830
|
+
function cloneJson4(value) {
|
|
1831
|
+
return JSON.parse(JSON.stringify(value));
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// src/cartography/context.ts
|
|
1835
|
+
function typographyTextStyle(typography) {
|
|
1836
|
+
return {
|
|
1837
|
+
font: typography.font,
|
|
1838
|
+
...typography.fallbacks ? { fallbacks: typography.fallbacks } : {},
|
|
1839
|
+
...typography.letterSpacing === void 0 ? {} : { letterSpacing: typography.letterSpacing },
|
|
1840
|
+
...typography.transform === void 0 ? {} : { transform: typography.transform }
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1605
1844
|
// src/modules/addresses/compiler.ts
|
|
1606
1845
|
function compileAddresses(request, context) {
|
|
1607
1846
|
if (request?.enabled === false) return [];
|
|
@@ -2068,7 +2307,21 @@ function buildingColorExpression(context) {
|
|
|
2068
2307
|
colors.destination,
|
|
2069
2308
|
["==", ["coalesce", ["get", fields.buildingTone], ""], "commercial"],
|
|
2070
2309
|
colors.commercial,
|
|
2071
|
-
|
|
2310
|
+
// Without a tone, World's use class: housing, shops and offices, public buildings and works
|
|
2311
|
+
// each take their theme colour; a shed, a garage or an unknown use the generic one.
|
|
2312
|
+
[
|
|
2313
|
+
"match",
|
|
2314
|
+
["coalesce", ["get", fields.class], ""],
|
|
2315
|
+
"residential",
|
|
2316
|
+
colors.residential,
|
|
2317
|
+
"commercial",
|
|
2318
|
+
colors.commercial,
|
|
2319
|
+
["civic", "education", "entertainment", "medical", "military", "religious", "transportation"],
|
|
2320
|
+
colors.civic,
|
|
2321
|
+
["agricultural", "industrial", "service"],
|
|
2322
|
+
colors.industrial,
|
|
2323
|
+
colors.generic
|
|
2324
|
+
]
|
|
2072
2325
|
];
|
|
2073
2326
|
}
|
|
2074
2327
|
function buildingVisibilityFilter() {
|
|
@@ -2332,6 +2585,9 @@ function cloneJson9(value) {
|
|
|
2332
2585
|
function labelField(language, context) {
|
|
2333
2586
|
return expression(labelFieldExpression(language, context));
|
|
2334
2587
|
}
|
|
2588
|
+
function labelNameFields(language, context) {
|
|
2589
|
+
return labelFieldExpression(language, context).slice(1).map((entry) => entry[1]);
|
|
2590
|
+
}
|
|
2335
2591
|
function labelFieldExpression(language, context) {
|
|
2336
2592
|
const fields = context.data.schema.fields;
|
|
2337
2593
|
if (language === "local") {
|
|
@@ -3189,12 +3445,12 @@ function compileLand(request, context) {
|
|
|
3189
3445
|
if (name === "recreation") continue;
|
|
3190
3446
|
appendLanduse(name, classes);
|
|
3191
3447
|
}
|
|
3192
|
-
for (const [name,
|
|
3448
|
+
for (const [name, match3] of landcoverClasses) {
|
|
3193
3449
|
const style = config.landcover?.[name];
|
|
3194
3450
|
if (!style) continue;
|
|
3195
3451
|
const protectedSource = name === "protected";
|
|
3196
3452
|
const sourceLayer = protectedSource ? schema.layers.park : schema.layers.landcover;
|
|
3197
|
-
const filter = protectedSource && schema.semantics.parkLayer === "protected-only" ? void 0 : landcoverFilter(classField, subclassField,
|
|
3453
|
+
const filter = protectedSource && schema.semantics.parkLayer === "protected-only" ? void 0 : landcoverFilter(classField, subclassField, match3);
|
|
3198
3454
|
for (const area of createAreaLayers(
|
|
3199
3455
|
{
|
|
3200
3456
|
id: `tileflow-landcover-${name}`,
|
|
@@ -3250,11 +3506,11 @@ function compileLand(request, context) {
|
|
|
3250
3506
|
function classFilter2(field2, classes) {
|
|
3251
3507
|
return ["match", ["get", field2], classes, true, false];
|
|
3252
3508
|
}
|
|
3253
|
-
function landcoverFilter(classField, subclassField,
|
|
3254
|
-
const filter = classFilter2(classField,
|
|
3255
|
-
if (
|
|
3256
|
-
if (
|
|
3257
|
-
return ["all", filter, ["!", classFilter2(subclassField,
|
|
3509
|
+
function landcoverFilter(classField, subclassField, match3) {
|
|
3510
|
+
const filter = classFilter2(classField, match3.class);
|
|
3511
|
+
if (match3.subclass) return ["all", filter, classFilter2(subclassField, match3.subclass)];
|
|
3512
|
+
if (match3.excludeSubclass) {
|
|
3513
|
+
return ["all", filter, ["!", classFilter2(subclassField, match3.excludeSubclass)]];
|
|
3258
3514
|
}
|
|
3259
3515
|
return filter;
|
|
3260
3516
|
}
|
|
@@ -3963,149 +4219,557 @@ var tileflowPoiImageRoles = Object.freeze({
|
|
|
3963
4219
|
transport: { fallback: "major-transit", token: "poi.transport" },
|
|
3964
4220
|
"visitor-amenity": { fallback: "services", token: "poi.visitor-amenity" }
|
|
3965
4221
|
});
|
|
4222
|
+
var tileflowPoiIconOnlyTypes = Object.freeze([
|
|
4223
|
+
"parking",
|
|
4224
|
+
"parking_garage",
|
|
4225
|
+
"parking_lot",
|
|
4226
|
+
"public_restroom"
|
|
4227
|
+
]);
|
|
3966
4228
|
function poi(options = {}) {
|
|
3967
4229
|
return { type: "poi", ...cloneJson13(options) };
|
|
3968
4230
|
}
|
|
3969
|
-
function resolvePoi(request) {
|
|
3970
|
-
return {
|
|
3971
|
-
categories: [...new Set(request?.categories ?? tileflowPoiCategories)],
|
|
3972
|
-
color: request?.color ?? "uniform",
|
|
3973
|
-
density: request?.density ?? 3,
|
|
3974
|
-
icons: request?.icons ?? true,
|
|
3975
|
-
labels: request?.labels ?? true,
|
|
3976
|
-
minZoom: request?.minZoom ?? 0,
|
|
3977
|
-
placement: {
|
|
3978
|
-
coupleIconAndLabel: request?.placement?.coupleIconAndLabel ?? false,
|
|
3979
|
-
|
|
3980
|
-
|
|
4231
|
+
function resolvePoi(request) {
|
|
4232
|
+
return {
|
|
4233
|
+
categories: [...new Set(request?.categories ?? tileflowPoiCategories)],
|
|
4234
|
+
color: request?.color ?? "uniform",
|
|
4235
|
+
density: request?.density ?? 3,
|
|
4236
|
+
icons: request?.icons ?? true,
|
|
4237
|
+
labels: request?.labels ?? true,
|
|
4238
|
+
minZoom: request?.minZoom ?? 0,
|
|
4239
|
+
placement: {
|
|
4240
|
+
coupleIconAndLabel: request?.placement?.coupleIconAndLabel ?? false,
|
|
4241
|
+
iconOnlyTypes: [...request?.placement?.iconOnlyTypes ?? tileflowPoiIconOnlyTypes],
|
|
4242
|
+
iconPadding: request?.placement?.iconPadding ?? 2,
|
|
4243
|
+
order: request?.placement?.order ?? "importance",
|
|
4244
|
+
...request?.placement?.prominentRank === void 0 ? {} : { prominentRank: request.placement.prominentRank },
|
|
4245
|
+
textPadding: request?.placement?.textPadding ?? 2
|
|
4246
|
+
}
|
|
4247
|
+
};
|
|
4248
|
+
}
|
|
4249
|
+
function cloneJson13(value) {
|
|
4250
|
+
return JSON.parse(JSON.stringify(value));
|
|
4251
|
+
}
|
|
4252
|
+
|
|
4253
|
+
// src/modules/poi/placement.ts
|
|
4254
|
+
var tileflowPoiFeatureVaryingProperties = Object.freeze({
|
|
4255
|
+
circle: Object.freeze({
|
|
4256
|
+
"circle-blur": 0,
|
|
4257
|
+
"circle-color": "#000000",
|
|
4258
|
+
"circle-opacity": 1,
|
|
4259
|
+
"circle-radius": 5,
|
|
4260
|
+
"circle-sort-key": void 0,
|
|
4261
|
+
"circle-stroke-color": "#000000",
|
|
4262
|
+
"circle-stroke-opacity": 1,
|
|
4263
|
+
"circle-stroke-width": 0
|
|
4264
|
+
}),
|
|
4265
|
+
symbol: Object.freeze({
|
|
4266
|
+
"icon-anchor": "center",
|
|
4267
|
+
"icon-color": "#000000",
|
|
4268
|
+
"icon-halo-blur": 0,
|
|
4269
|
+
"icon-halo-color": "rgba(0, 0, 0, 0)",
|
|
4270
|
+
"icon-halo-width": 0,
|
|
4271
|
+
// An empty image draws no icon, so a category without one stays text-only.
|
|
4272
|
+
"icon-image": "",
|
|
4273
|
+
"icon-offset": [0, 0],
|
|
4274
|
+
"icon-opacity": 1,
|
|
4275
|
+
"icon-padding": [2],
|
|
4276
|
+
"icon-rotate": 0,
|
|
4277
|
+
"icon-size": 1,
|
|
4278
|
+
"symbol-sort-key": void 0,
|
|
4279
|
+
"text-anchor": "center",
|
|
4280
|
+
"text-color": "#000000",
|
|
4281
|
+
"text-field": "",
|
|
4282
|
+
// MapLibre can vary `text-font` per feature, but Tileflow prepares glyphs for a static font
|
|
4283
|
+
// stack, so the font stays a layer-wide property.
|
|
4284
|
+
"text-halo-blur": 0,
|
|
4285
|
+
"text-halo-color": "rgba(0, 0, 0, 0)",
|
|
4286
|
+
"text-halo-width": 0,
|
|
4287
|
+
"text-justify": "center",
|
|
4288
|
+
"text-letter-spacing": 0,
|
|
4289
|
+
"text-max-width": 10,
|
|
4290
|
+
"text-offset": [0, 0],
|
|
4291
|
+
"text-opacity": 1,
|
|
4292
|
+
"text-radial-offset": 0,
|
|
4293
|
+
"text-rotate": 0,
|
|
4294
|
+
"text-size": 16,
|
|
4295
|
+
"text-transform": "none",
|
|
4296
|
+
"text-variable-anchor-offset": void 0
|
|
4297
|
+
})
|
|
4298
|
+
});
|
|
4299
|
+
var tileflowPoiLayerPropertyDefaults = Object.freeze({
|
|
4300
|
+
"circle-pitch-alignment": "viewport",
|
|
4301
|
+
"circle-pitch-scale": "map",
|
|
4302
|
+
"circle-translate": [0, 0],
|
|
4303
|
+
"circle-translate-anchor": "map",
|
|
4304
|
+
"icon-allow-overlap": false,
|
|
4305
|
+
"icon-ignore-placement": false,
|
|
4306
|
+
"icon-keep-upright": false,
|
|
4307
|
+
"icon-optional": false,
|
|
4308
|
+
"icon-pitch-alignment": "auto",
|
|
4309
|
+
"icon-rotation-alignment": "auto",
|
|
4310
|
+
"icon-text-fit": "none",
|
|
4311
|
+
"icon-text-fit-padding": [0, 0, 0, 0],
|
|
4312
|
+
"symbol-avoid-edges": false,
|
|
4313
|
+
"symbol-placement": "point",
|
|
4314
|
+
"symbol-spacing": 250,
|
|
4315
|
+
"symbol-z-order": "auto",
|
|
4316
|
+
"text-allow-overlap": false,
|
|
4317
|
+
"text-ignore-placement": false,
|
|
4318
|
+
"text-keep-upright": true,
|
|
4319
|
+
"text-line-height": 1.2,
|
|
4320
|
+
"text-max-angle": 45,
|
|
4321
|
+
"text-optional": false,
|
|
4322
|
+
"text-padding": 2,
|
|
4323
|
+
"text-pitch-alignment": "auto",
|
|
4324
|
+
"text-rotation-alignment": "auto",
|
|
4325
|
+
visibility: "visible"
|
|
4326
|
+
});
|
|
4327
|
+
var TileflowPoiPlacementError = class extends Error {
|
|
4328
|
+
code = "TILEFLOW_POI_PLACEMENT_CONFLICT";
|
|
4329
|
+
constructor(message) {
|
|
4330
|
+
super(message);
|
|
4331
|
+
this.name = "TileflowPoiPlacementError";
|
|
4332
|
+
}
|
|
4333
|
+
};
|
|
4334
|
+
function mergePoiCategoryLayers(entries, options) {
|
|
4335
|
+
const [first] = entries;
|
|
4336
|
+
if (!first) throw new TileflowPoiPlacementError("A POI placement layer needs a category.");
|
|
4337
|
+
const kind = first.layer.type === "circle" ? "circle" : "symbol";
|
|
4338
|
+
const varying = tileflowPoiFeatureVaryingProperties[kind];
|
|
4339
|
+
const categories = entries.map(({ category }) => category);
|
|
4340
|
+
for (const property of ["type", "source", "source-layer", "minzoom", "maxzoom"]) {
|
|
4341
|
+
requireShared(entries, property, (layer) => layer[property]);
|
|
4342
|
+
}
|
|
4343
|
+
const result = {
|
|
4344
|
+
...first.layer,
|
|
4345
|
+
id: options.id,
|
|
4346
|
+
filter: options.filter
|
|
4347
|
+
};
|
|
4348
|
+
for (const part of ["layout", "paint"]) {
|
|
4349
|
+
const records = entries.map(({ layer }) => asRecord2(layer[part]));
|
|
4350
|
+
const properties2 = [...new Set(records.flatMap((record3) => Object.keys(record3)))].sort();
|
|
4351
|
+
const merged = {};
|
|
4352
|
+
for (const property of properties2) {
|
|
4353
|
+
const fallback = Object.hasOwn(varying, property) ? varying[property] : tileflowPoiLayerPropertyDefaults[property];
|
|
4354
|
+
const values = records.map(
|
|
4355
|
+
(record3) => Object.hasOwn(record3, property) ? record3[property] : fallback
|
|
4356
|
+
);
|
|
4357
|
+
if (values.every((value) => sameJson(value, values[0]))) {
|
|
4358
|
+
if (values[0] !== void 0) merged[property] = values[0];
|
|
4359
|
+
continue;
|
|
4360
|
+
}
|
|
4361
|
+
if (!Object.hasOwn(varying, property)) {
|
|
4362
|
+
throw conflict(entries, property, (layer) => asRecord2(layer[part])[property]);
|
|
4363
|
+
}
|
|
4364
|
+
if (values.some((value) => value === void 0)) {
|
|
4365
|
+
throw new TileflowPoiPlacementError(
|
|
4366
|
+
`POI categories ${categories.join(", ")} set ${property} for only some categories, and MapLibre has no default to fill in for the rest. Set it for every category.`
|
|
4367
|
+
);
|
|
4368
|
+
}
|
|
4369
|
+
merged[property] = matchByCategory(
|
|
4370
|
+
property,
|
|
4371
|
+
categories.map((category, index) => [category, values[index]]),
|
|
4372
|
+
["get", options.categoryField]
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4375
|
+
if (Object.keys(merged).length) result[part] = merged;
|
|
4376
|
+
else delete result[part];
|
|
4377
|
+
}
|
|
4378
|
+
return result;
|
|
4379
|
+
}
|
|
4380
|
+
function requireShared(entries, property, read) {
|
|
4381
|
+
const value = read(entries[0].layer);
|
|
4382
|
+
if (entries.every(({ layer }) => sameJson(read(layer), value))) return;
|
|
4383
|
+
throw conflict(entries, property, read);
|
|
4384
|
+
}
|
|
4385
|
+
function conflict(entries, property, read) {
|
|
4386
|
+
const described = entries.map(({ category, layer }) => `${category}: ${JSON.stringify(read(layer)) ?? "unset"}`).join("; ");
|
|
4387
|
+
return new TileflowPoiPlacementError(
|
|
4388
|
+
`POI categories need different ${property} values (${described}), but MapLibre keeps ${property} constant within one layer. Give them the same ${property}, or set placement.order to 'categories' to place each category in its own layer.`
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
function matchByCategory(property, values, input) {
|
|
4392
|
+
const curves = values.map(([, value]) => zoomCurve(value));
|
|
4393
|
+
const present = curves.filter((curve) => curve !== void 0);
|
|
4394
|
+
if (present.length === 0) return match(input, values);
|
|
4395
|
+
const reference = present[0];
|
|
4396
|
+
for (const curve of present) {
|
|
4397
|
+
if (curve.kind !== reference.kind || curve.kind === "interpolate" && reference.kind === "interpolate" && (curve.operator !== reference.operator || !sameJson(curve.interpolation, reference.interpolation))) {
|
|
4398
|
+
throw new TileflowPoiPlacementError(
|
|
4399
|
+
`POI categories use different kinds of zoom curve for ${property}. Use one kind of curve (linear, the same exponential base, or step) for every category, or set placement.order to 'categories'.`
|
|
4400
|
+
);
|
|
3981
4401
|
}
|
|
3982
|
-
}
|
|
4402
|
+
}
|
|
4403
|
+
const stops = [...new Set(present.flatMap((curve) => curve.stops.map(([zoom3]) => zoom3)))].sort(
|
|
4404
|
+
(left, right) => left - right
|
|
4405
|
+
);
|
|
4406
|
+
const at = (zoom3) => match(
|
|
4407
|
+
input,
|
|
4408
|
+
values.map(([category, value], index) => [
|
|
4409
|
+
category,
|
|
4410
|
+
curves[index] ? evaluateCurve(property, curves[index], zoom3) : value
|
|
4411
|
+
])
|
|
4412
|
+
);
|
|
4413
|
+
if (reference.kind === "step") {
|
|
4414
|
+
const base = match(
|
|
4415
|
+
input,
|
|
4416
|
+
values.map(([category, value], index) => {
|
|
4417
|
+
const curve = curves[index];
|
|
4418
|
+
return [category, curve?.kind === "step" ? curve.base : value];
|
|
4419
|
+
})
|
|
4420
|
+
);
|
|
4421
|
+
return ["step", ["zoom"], base, ...stops.flatMap((zoom3) => [zoom3, at(zoom3)])];
|
|
4422
|
+
}
|
|
4423
|
+
return [
|
|
4424
|
+
reference.operator,
|
|
4425
|
+
reference.interpolation,
|
|
4426
|
+
["zoom"],
|
|
4427
|
+
...stops.flatMap((zoom3) => [zoom3, at(zoom3)])
|
|
4428
|
+
];
|
|
3983
4429
|
}
|
|
3984
|
-
function
|
|
3985
|
-
|
|
4430
|
+
function match(input, values) {
|
|
4431
|
+
const groups = [];
|
|
4432
|
+
for (const [category, value] of values) {
|
|
4433
|
+
const group = groups.find((candidate) => sameJson(candidate.value, value));
|
|
4434
|
+
if (group) group.categories.push(category);
|
|
4435
|
+
else groups.push({ categories: [category], value });
|
|
4436
|
+
}
|
|
4437
|
+
if (groups.length === 1) return groups[0].value;
|
|
4438
|
+
const fallback = groups.reduce(
|
|
4439
|
+
(largest, group) => group.categories.length > largest.categories.length ? group : largest
|
|
4440
|
+
);
|
|
4441
|
+
return [
|
|
4442
|
+
"match",
|
|
4443
|
+
input,
|
|
4444
|
+
...groups.filter((group) => group !== fallback).flatMap((group) => [
|
|
4445
|
+
group.categories.length === 1 ? group.categories[0] : group.categories,
|
|
4446
|
+
expressionValue(group.value)
|
|
4447
|
+
]),
|
|
4448
|
+
expressionValue(fallback.value)
|
|
4449
|
+
];
|
|
4450
|
+
}
|
|
4451
|
+
function zoomCurve(value) {
|
|
4452
|
+
if (!Array.isArray(value)) return void 0;
|
|
4453
|
+
const [operator] = value;
|
|
4454
|
+
if ((operator === "interpolate" || operator === "interpolate-hcl" || operator === "interpolate-lab") && isZoomInput3(value[2])) {
|
|
4455
|
+
return {
|
|
4456
|
+
kind: "interpolate",
|
|
4457
|
+
operator,
|
|
4458
|
+
interpolation: value[1],
|
|
4459
|
+
stops: pairs(value.slice(3))
|
|
4460
|
+
};
|
|
4461
|
+
}
|
|
4462
|
+
if (operator === "step" && isZoomInput3(value[1])) {
|
|
4463
|
+
return { kind: "step", base: value[2], stops: pairs(value.slice(3)) };
|
|
4464
|
+
}
|
|
4465
|
+
return void 0;
|
|
4466
|
+
}
|
|
4467
|
+
function evaluateCurve(property, curve, zoom3) {
|
|
4468
|
+
const { stops } = curve;
|
|
4469
|
+
if (curve.kind === "step") {
|
|
4470
|
+
let value2 = curve.base;
|
|
4471
|
+
for (const [stop, output] of stops) if (stop <= zoom3) value2 = output;
|
|
4472
|
+
return value2;
|
|
4473
|
+
}
|
|
4474
|
+
const exact = stops.find(([stop]) => stop === zoom3);
|
|
4475
|
+
if (exact) return exact[1];
|
|
4476
|
+
if (zoom3 < stops[0][0]) return stops[0][1];
|
|
4477
|
+
if (zoom3 > stops.at(-1)[0]) return stops.at(-1)[1];
|
|
4478
|
+
const upperIndex = stops.findIndex(([stop]) => stop > zoom3);
|
|
4479
|
+
const [lowerZoom, lower] = stops[upperIndex - 1];
|
|
4480
|
+
const [upperZoom, upper] = stops[upperIndex];
|
|
4481
|
+
const t = interpolationFactor(curve.interpolation, zoom3, lowerZoom, upperZoom);
|
|
4482
|
+
const value = interpolateOutput(lower, upper, t);
|
|
4483
|
+
if (value === void 0) {
|
|
4484
|
+
throw new TileflowPoiPlacementError(
|
|
4485
|
+
`POI categories interpolate ${property} between values Tileflow cannot evaluate at zoom ${zoom3}. Give every category the same zoom stops for ${property}, or set placement.order to 'categories'.`
|
|
4486
|
+
);
|
|
4487
|
+
}
|
|
4488
|
+
return value;
|
|
4489
|
+
}
|
|
4490
|
+
function interpolationFactor(interpolation, zoom3, lower, upper) {
|
|
4491
|
+
const progress = zoom3 - lower;
|
|
4492
|
+
const range2 = upper - lower;
|
|
4493
|
+
if (Array.isArray(interpolation) && interpolation[0] === "exponential") {
|
|
4494
|
+
const base = Number(interpolation[1]);
|
|
4495
|
+
if (base !== 1) return (base ** progress - 1) / (base ** range2 - 1);
|
|
4496
|
+
}
|
|
4497
|
+
return progress / range2;
|
|
4498
|
+
}
|
|
4499
|
+
function interpolateOutput(lower, upper, t) {
|
|
4500
|
+
if (typeof lower === "number" && typeof upper === "number") {
|
|
4501
|
+
return roundOutput(lower + (upper - lower) * t);
|
|
4502
|
+
}
|
|
4503
|
+
const lowerArray = numericArray(lower);
|
|
4504
|
+
const upperArray = numericArray(upper);
|
|
4505
|
+
if (lowerArray && upperArray && lowerArray.length === upperArray.length) {
|
|
4506
|
+
return [
|
|
4507
|
+
"literal",
|
|
4508
|
+
lowerArray.map((value, index) => roundOutput(value + (upperArray[index] - value) * t))
|
|
4509
|
+
];
|
|
4510
|
+
}
|
|
4511
|
+
if (isNumericOutput(lower) && isNumericOutput(upper)) {
|
|
4512
|
+
return ["+", lower, ["*", roundOutput(t), ["-", upper, lower]]];
|
|
4513
|
+
}
|
|
4514
|
+
return void 0;
|
|
4515
|
+
}
|
|
4516
|
+
function isNumericOutput(value) {
|
|
4517
|
+
if (typeof value === "number") return true;
|
|
4518
|
+
if (!Array.isArray(value) || typeof value[0] !== "string") return false;
|
|
4519
|
+
return isMapLibreExpressionOperator(value[0]) && !["literal", "array"].includes(value[0]);
|
|
4520
|
+
}
|
|
4521
|
+
function numericArray(value) {
|
|
4522
|
+
const array = Array.isArray(value) && value[0] === "literal" && Array.isArray(value[1]) ? value[1] : value;
|
|
4523
|
+
return Array.isArray(array) && array.every((entry) => typeof entry === "number") ? array : void 0;
|
|
4524
|
+
}
|
|
4525
|
+
function roundOutput(value) {
|
|
4526
|
+
return Math.round(value * 1e6) / 1e6;
|
|
4527
|
+
}
|
|
4528
|
+
function expressionValue(value) {
|
|
4529
|
+
if (!Array.isArray(value)) return value;
|
|
4530
|
+
if (typeof value[0] === "string" && isMapLibreExpressionOperator(value[0])) return value;
|
|
4531
|
+
return ["literal", value];
|
|
4532
|
+
}
|
|
4533
|
+
function pairs(values) {
|
|
4534
|
+
const result = [];
|
|
4535
|
+
for (let index = 0; index + 1 < values.length; index += 2) {
|
|
4536
|
+
result.push([values[index], values[index + 1]]);
|
|
4537
|
+
}
|
|
4538
|
+
return result;
|
|
4539
|
+
}
|
|
4540
|
+
function isZoomInput3(value) {
|
|
4541
|
+
return Array.isArray(value) && value.length === 1 && value[0] === "zoom";
|
|
4542
|
+
}
|
|
4543
|
+
function sameJson(left, right) {
|
|
4544
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
4545
|
+
}
|
|
4546
|
+
function asRecord2(value) {
|
|
4547
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3986
4548
|
}
|
|
3987
4549
|
|
|
3988
4550
|
// src/modules/poi/compiler.ts
|
|
4551
|
+
var representationOrder = {
|
|
4552
|
+
marker: 0,
|
|
4553
|
+
combined: 1,
|
|
4554
|
+
icon: 1,
|
|
4555
|
+
label: 2
|
|
4556
|
+
};
|
|
3989
4557
|
function compilePoi(request, context, language = "auto") {
|
|
3990
4558
|
if (request?.enabled === false) return [];
|
|
3991
4559
|
const semantics = resolvePoi(request);
|
|
3992
|
-
const
|
|
4560
|
+
const selection2 = createPoiSelection(semantics, context, language);
|
|
4561
|
+
const parts = semantics.categories.flatMap(
|
|
4562
|
+
(category) => compileCategory(category, request, semantics, context, language, selection2)
|
|
4563
|
+
);
|
|
4564
|
+
if (semantics.placement.order === "categories") {
|
|
4565
|
+
return parts.map((part) => {
|
|
4566
|
+
const rank = semantics.categories.length - 1 - semantics.categories.indexOf(part.category);
|
|
4567
|
+
const suffix = part.representation === "combined" ? "" : `.${part.representation}`;
|
|
4568
|
+
return poiContribution(
|
|
4569
|
+
`${part.category}${suffix}`,
|
|
4570
|
+
rank * 4 + representationOrder[part.representation],
|
|
4571
|
+
{
|
|
4572
|
+
...part.layer,
|
|
4573
|
+
id: `tileflow-poi-${part.category}${suffix.replace(".", "-")}`,
|
|
4574
|
+
filter: selection2.filter([part.category], part.representation)
|
|
4575
|
+
}
|
|
4576
|
+
);
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4579
|
+
const { prominentRank } = semantics.placement;
|
|
4580
|
+
const filterRank = numericPoiField(context.data.schema.fields.poiFilterRank, 6);
|
|
4581
|
+
return ["marker", "combined", "icon", "label"].flatMap((representation) => {
|
|
4582
|
+
const entries = parts.filter((part) => part.representation === representation);
|
|
4583
|
+
if (entries.length === 0) return [];
|
|
4584
|
+
const suffix = representation === "combined" ? "" : `.${representation}`;
|
|
4585
|
+
const filter = selection2.filter(
|
|
4586
|
+
entries.map(({ category }) => category),
|
|
4587
|
+
representation
|
|
4588
|
+
);
|
|
4589
|
+
const layer = mergePoiCategoryLayers(entries, {
|
|
4590
|
+
categoryField: context.data.schema.fields.poiCategory,
|
|
4591
|
+
filter,
|
|
4592
|
+
id: `tileflow-poi${suffix.replace(".", "-")}`
|
|
4593
|
+
});
|
|
4594
|
+
if (prominentRank === void 0 || representation === "marker") {
|
|
4595
|
+
return [poiContribution(suffix.slice(1), representationOrder[representation], layer)];
|
|
4596
|
+
}
|
|
4597
|
+
return [
|
|
4598
|
+
poiContribution(suffix.slice(1), representationOrder[representation], {
|
|
4599
|
+
...layer,
|
|
4600
|
+
filter: [...filter, [">", filterRank, prominentRank]]
|
|
4601
|
+
}),
|
|
4602
|
+
poiContribution(`prominent${suffix}`, 400 + representationOrder[representation], {
|
|
4603
|
+
...layer,
|
|
4604
|
+
id: `tileflow-poi-prominent${suffix.replace(".", "-")}`,
|
|
4605
|
+
filter: [...filter, ["<=", filterRank, prominentRank]]
|
|
4606
|
+
})
|
|
4607
|
+
];
|
|
4608
|
+
});
|
|
4609
|
+
}
|
|
4610
|
+
function compileCategory(category, request, semantics, context, language, selection2) {
|
|
3993
4611
|
const { sourceId: source, schema } = context.data;
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4612
|
+
const coupled = semantics.placement.coupleIconAndLabel;
|
|
4613
|
+
const categoryColor = semantics.color === "category" ? context.colors.poi[category] ?? context.colors.poi.label : context.colors.poi.label;
|
|
4614
|
+
const defaults4 = {
|
|
4615
|
+
icon: {
|
|
4616
|
+
optional: !coupled,
|
|
4617
|
+
padding: semantics.placement.iconPadding,
|
|
4618
|
+
size: semantics.minZoom < 17 ? zoom.linear([
|
|
4619
|
+
[semantics.minZoom, 0.85],
|
|
4620
|
+
[17, 1]
|
|
4621
|
+
]) : 1
|
|
4622
|
+
},
|
|
4623
|
+
text: poiTextStyle(context, {
|
|
4624
|
+
color: categoryColor,
|
|
4625
|
+
field: labelField(language, context),
|
|
4626
|
+
// A coupled POI is its pictogram and its name: it is placed only when both fit.
|
|
4627
|
+
optional: !coupled,
|
|
4628
|
+
padding: semantics.placement.textPadding,
|
|
4629
|
+
size: semantics.minZoom < 17 ? zoom.linear([
|
|
4630
|
+
[semantics.minZoom, 10],
|
|
4631
|
+
[17, 12]
|
|
4632
|
+
]) : 12
|
|
4633
|
+
})
|
|
4634
|
+
};
|
|
4635
|
+
let style = mergeTileflowDesign(defaults4, request?.styles?.[category] ?? {});
|
|
4636
|
+
const markerStyle = style.marker ? resolveMarkerStyle(style) : void 0;
|
|
4637
|
+
const hidden = style.visible === false;
|
|
4638
|
+
const showText = !hidden && semantics.labels && style.text.visible !== false;
|
|
4639
|
+
const showIcon = !hidden && semantics.icons && style.icon.visible !== false;
|
|
4640
|
+
style = {
|
|
4641
|
+
...withoutVisibility(style),
|
|
4642
|
+
icon: withoutVisibility(style.icon),
|
|
4643
|
+
text: withoutVisibility(style.text)
|
|
4644
|
+
};
|
|
4645
|
+
if (showIcon && style.icon.image === void 0) {
|
|
4646
|
+
style = {
|
|
4647
|
+
...style,
|
|
4000
4648
|
icon: {
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
[semantics.minZoom, 0.85],
|
|
4005
|
-
[17, 1]
|
|
4006
|
-
]) : 1
|
|
4007
|
-
},
|
|
4008
|
-
text: poiTextStyle(context, {
|
|
4009
|
-
color: categoryColor,
|
|
4010
|
-
field: labelField(language, context),
|
|
4011
|
-
padding: semantics.placement.textPadding,
|
|
4012
|
-
size: semantics.minZoom < 17 ? zoom.linear([
|
|
4013
|
-
[semantics.minZoom, 10],
|
|
4014
|
-
[17, 12]
|
|
4015
|
-
]) : 12
|
|
4016
|
-
})
|
|
4649
|
+
...style.icon,
|
|
4650
|
+
image: resolvePoiImage(category, context, schema.fields.poiIcon)
|
|
4651
|
+
}
|
|
4017
4652
|
};
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
const
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
density: categoryDensity,
|
|
4038
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4039
|
-
id: `tileflow-poi-${category}-marker`,
|
|
4040
|
-
minZoom: semantics.minZoom,
|
|
4041
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4042
|
-
source,
|
|
4043
|
-
sourceLayer: schema.layers.poi
|
|
4044
|
-
});
|
|
4045
|
-
const markerLayer = applyCircleStyle(
|
|
4653
|
+
}
|
|
4654
|
+
style = withPoiTextClearance(style, showText && showIcon);
|
|
4655
|
+
const symbolStyle2 = withoutMarker2(style);
|
|
4656
|
+
const base = () => ({
|
|
4657
|
+
id: `tileflow-poi-${category}`,
|
|
4658
|
+
type: "symbol",
|
|
4659
|
+
source,
|
|
4660
|
+
"source-layer": schema.layers.poi,
|
|
4661
|
+
minzoom: semantics.minZoom,
|
|
4662
|
+
layout: { "symbol-sort-key": poiSortKey(schema.fields.poiFilterRank, schema.fields.poiSizeRank) }
|
|
4663
|
+
});
|
|
4664
|
+
const parts = [];
|
|
4665
|
+
selection2.register(category, { icon: showIcon, text: showText });
|
|
4666
|
+
if (!hidden && markerStyle && markerStyle.visible !== false) {
|
|
4667
|
+
const markerBase = base();
|
|
4668
|
+
parts.push({
|
|
4669
|
+
category,
|
|
4670
|
+
representation: "marker",
|
|
4671
|
+
layer: applyCircleStyle(
|
|
4046
4672
|
{
|
|
4047
|
-
...
|
|
4673
|
+
...markerBase,
|
|
4048
4674
|
type: "circle",
|
|
4049
4675
|
layout: {
|
|
4050
4676
|
"circle-sort-key": poiSortKey(schema.fields.poiFilterRank, schema.fields.poiSizeRank)
|
|
4051
4677
|
}
|
|
4052
4678
|
},
|
|
4053
4679
|
markerStyle
|
|
4054
|
-
)
|
|
4055
|
-
|
|
4056
|
-
}
|
|
4057
|
-
if (semantics.placement.coupleIconAndLabel && showText && showIcon) {
|
|
4058
|
-
let layer = createPoiLayer({
|
|
4059
|
-
category,
|
|
4060
|
-
categoryField: schema.fields.poiCategory,
|
|
4061
|
-
density: categoryDensity,
|
|
4062
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4063
|
-
id: `tileflow-poi-${category}`,
|
|
4064
|
-
minZoom: semantics.minZoom,
|
|
4065
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4066
|
-
source,
|
|
4067
|
-
sourceLayer: schema.layers.poi
|
|
4068
|
-
});
|
|
4069
|
-
layer = applySymbolStyle(layer, symbolStyle2);
|
|
4070
|
-
result.push(poiContribution(category, index * 4 + 1, layer));
|
|
4071
|
-
continue;
|
|
4072
|
-
}
|
|
4073
|
-
if (showIcon) {
|
|
4074
|
-
const layer = applySymbolStyle(
|
|
4075
|
-
createPoiLayer({
|
|
4076
|
-
category,
|
|
4077
|
-
categoryField: schema.fields.poiCategory,
|
|
4078
|
-
density: categoryDensity,
|
|
4079
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4080
|
-
id: `tileflow-poi-${category}-icon`,
|
|
4081
|
-
minZoom: semantics.minZoom,
|
|
4082
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4083
|
-
source,
|
|
4084
|
-
sourceLayer: schema.layers.poi
|
|
4085
|
-
}),
|
|
4086
|
-
{ ...symbolStyle2, text: void 0 }
|
|
4087
|
-
);
|
|
4088
|
-
result.push(poiContribution(`${category}.icon`, index * 4 + 1, layer));
|
|
4089
|
-
}
|
|
4090
|
-
if (showText) {
|
|
4091
|
-
const layer = applySymbolStyle(
|
|
4092
|
-
createPoiLayer({
|
|
4093
|
-
category,
|
|
4094
|
-
categoryField: schema.fields.poiCategory,
|
|
4095
|
-
density: categoryDensity,
|
|
4096
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4097
|
-
id: `tileflow-poi-${category}-label`,
|
|
4098
|
-
minZoom: semantics.minZoom,
|
|
4099
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4100
|
-
source,
|
|
4101
|
-
sourceLayer: schema.layers.poi
|
|
4102
|
-
}),
|
|
4103
|
-
{ ...symbolStyle2, icon: void 0 }
|
|
4104
|
-
);
|
|
4105
|
-
result.push(poiContribution(`${category}.label`, index * 4 + 2, layer));
|
|
4106
|
-
}
|
|
4680
|
+
)
|
|
4681
|
+
});
|
|
4107
4682
|
}
|
|
4108
|
-
|
|
4683
|
+
const combined = coupled && (semantics.placement.order === "importance" ? semantics.icons && semantics.labels && (showIcon || showText) : showIcon && showText);
|
|
4684
|
+
if (combined) {
|
|
4685
|
+
const combinedStyle = {
|
|
4686
|
+
...symbolStyle2,
|
|
4687
|
+
icon: showIcon ? symbolStyle2.icon : { image: "" },
|
|
4688
|
+
text: showText ? { ...symbolStyle2.text, field: selection2.textField(symbolStyle2.text.field) } : { field: "" }
|
|
4689
|
+
};
|
|
4690
|
+
parts.push({
|
|
4691
|
+
category,
|
|
4692
|
+
representation: "combined",
|
|
4693
|
+
layer: applySymbolStyle(base(), combinedStyle)
|
|
4694
|
+
});
|
|
4695
|
+
return parts;
|
|
4696
|
+
}
|
|
4697
|
+
if (showIcon) {
|
|
4698
|
+
parts.push({
|
|
4699
|
+
category,
|
|
4700
|
+
representation: "icon",
|
|
4701
|
+
layer: applySymbolStyle(base(), { ...symbolStyle2, text: void 0 })
|
|
4702
|
+
});
|
|
4703
|
+
}
|
|
4704
|
+
if (showText) {
|
|
4705
|
+
parts.push({
|
|
4706
|
+
category,
|
|
4707
|
+
representation: "label",
|
|
4708
|
+
layer: applySymbolStyle(base(), { ...symbolStyle2, icon: void 0 })
|
|
4709
|
+
});
|
|
4710
|
+
}
|
|
4711
|
+
return parts;
|
|
4712
|
+
}
|
|
4713
|
+
function createPoiSelection(semantics, context, language) {
|
|
4714
|
+
const { fields } = context.data.schema;
|
|
4715
|
+
const shown = /* @__PURE__ */ new Map();
|
|
4716
|
+
const iconOnlyTypes = [...new Set(semantics.placement.iconOnlyTypes)];
|
|
4717
|
+
const iconOnly = () => iconOnlyTypes.length ? ["match", ["get", fields.poiType], iconOnlyTypes, true, false] : ["literal", false];
|
|
4718
|
+
const inCategories = (categories) => categories.length === 1 ? ["==", ["get", fields.poiCategory], categories[0]] : ["match", ["get", fields.poiCategory], [...categories], true, false];
|
|
4719
|
+
const named = () => [
|
|
4720
|
+
"any",
|
|
4721
|
+
...labelNameFields(language, context).map((field2) => ["has", field2])
|
|
4722
|
+
];
|
|
4723
|
+
return {
|
|
4724
|
+
register(category, parts) {
|
|
4725
|
+
shown.set(category, parts);
|
|
4726
|
+
},
|
|
4727
|
+
textField(field2) {
|
|
4728
|
+
if (!iconOnlyTypes.length || field2 === void 0) return field2;
|
|
4729
|
+
return expression([
|
|
4730
|
+
"match",
|
|
4731
|
+
["get", fields.poiType],
|
|
4732
|
+
iconOnlyTypes,
|
|
4733
|
+
"",
|
|
4734
|
+
fieldValue(field2)
|
|
4735
|
+
]);
|
|
4736
|
+
},
|
|
4737
|
+
filter(categories, representation) {
|
|
4738
|
+
const filterRank = numericPoiField(fields.poiFilterRank, 6);
|
|
4739
|
+
const sizeRank = numericPoiField(fields.poiSizeRank, 17);
|
|
4740
|
+
const result = [
|
|
4741
|
+
"all",
|
|
4742
|
+
inCategories(categories),
|
|
4743
|
+
["has", fields.poiFilterRank],
|
|
4744
|
+
[">=", filterRank, 0],
|
|
4745
|
+
["<=", filterRank, poiRankThreshold(semantics.density)],
|
|
4746
|
+
["has", fields.poiSizeRank],
|
|
4747
|
+
[">=", sizeRank, 0],
|
|
4748
|
+
["<=", sizeRank, 16]
|
|
4749
|
+
];
|
|
4750
|
+
if (!semantics.icons || !semantics.labels) return result;
|
|
4751
|
+
const textless = categories.filter((category) => !shown.get(category)?.text);
|
|
4752
|
+
const iconless = categories.filter((category) => !shown.get(category)?.icon);
|
|
4753
|
+
if (representation === "label") {
|
|
4754
|
+
if (iconless.length === categories.length || !iconOnlyTypes.length) return result;
|
|
4755
|
+
const keep = ["!", iconOnly()];
|
|
4756
|
+
return [...result, iconless.length ? ["any", inCategories(iconless), keep] : keep];
|
|
4757
|
+
}
|
|
4758
|
+
if (textless.length === categories.length) return result;
|
|
4759
|
+
return [
|
|
4760
|
+
...result,
|
|
4761
|
+
[
|
|
4762
|
+
"any",
|
|
4763
|
+
named(),
|
|
4764
|
+
...iconOnlyTypes.length ? [iconOnly()] : [],
|
|
4765
|
+
...textless.length ? [inCategories(textless)] : []
|
|
4766
|
+
]
|
|
4767
|
+
];
|
|
4768
|
+
}
|
|
4769
|
+
};
|
|
4770
|
+
}
|
|
4771
|
+
function fieldValue(field2) {
|
|
4772
|
+
return typeof field2 === "object" && field2 !== null && "kind" in field2 && field2.kind === "expression" ? field2.value : field2;
|
|
4109
4773
|
}
|
|
4110
4774
|
function resolvePoiImage(category, context, iconField) {
|
|
4111
4775
|
const role = `poi.${category}`;
|
|
@@ -4128,28 +4792,6 @@ function resolveMarkerStyle(style) {
|
|
|
4128
4792
|
style.marker
|
|
4129
4793
|
);
|
|
4130
4794
|
}
|
|
4131
|
-
function createPoiLayer(options) {
|
|
4132
|
-
const filterRank = numericPoiField(options.filterRankField, 6);
|
|
4133
|
-
const sizeRank = numericPoiField(options.sizeRankField, 17);
|
|
4134
|
-
return {
|
|
4135
|
-
id: options.id,
|
|
4136
|
-
type: "symbol",
|
|
4137
|
-
source: options.source,
|
|
4138
|
-
"source-layer": options.sourceLayer,
|
|
4139
|
-
minzoom: options.minZoom,
|
|
4140
|
-
filter: [
|
|
4141
|
-
"all",
|
|
4142
|
-
["==", ["get", options.categoryField], options.category],
|
|
4143
|
-
["has", options.filterRankField],
|
|
4144
|
-
[">=", filterRank, 0],
|
|
4145
|
-
["<=", filterRank, poiRankThreshold(options.density)],
|
|
4146
|
-
["has", options.sizeRankField],
|
|
4147
|
-
[">=", sizeRank, 0],
|
|
4148
|
-
["<=", sizeRank, 16]
|
|
4149
|
-
],
|
|
4150
|
-
layout: { "symbol-sort-key": poiSortKey(options.filterRankField, options.sizeRankField) }
|
|
4151
|
-
};
|
|
4152
|
-
}
|
|
4153
4795
|
function poiRankThreshold(density) {
|
|
4154
4796
|
return ["+", ["step", ["zoom"], 0, 16, 1, 17, 2], density];
|
|
4155
4797
|
}
|
|
@@ -4166,7 +4808,7 @@ function poiContribution(target, localOrder, layer) {
|
|
|
4166
4808
|
localOrder: 1e3 + localOrder,
|
|
4167
4809
|
owner: "poi",
|
|
4168
4810
|
slot: "symbols",
|
|
4169
|
-
target: `poi.${target}`
|
|
4811
|
+
target: target ? `poi.${target}` : "poi"
|
|
4170
4812
|
};
|
|
4171
4813
|
}
|
|
4172
4814
|
function poiTextStyle(context, overrides) {
|
|
@@ -4176,8 +4818,7 @@ function poiTextStyle(context, overrides) {
|
|
|
4176
4818
|
color: context.colors.poi.label,
|
|
4177
4819
|
...typographyTextStyle(context.typography.poi),
|
|
4178
4820
|
haloColor: context.colors.poi.halo,
|
|
4179
|
-
haloWidth: 1
|
|
4180
|
-
optional: true
|
|
4821
|
+
haloWidth: 1
|
|
4181
4822
|
},
|
|
4182
4823
|
overrides
|
|
4183
4824
|
);
|
|
@@ -4200,6 +4841,10 @@ function withoutMarker2(style) {
|
|
|
4200
4841
|
delete result.marker;
|
|
4201
4842
|
return result;
|
|
4202
4843
|
}
|
|
4844
|
+
function withoutVisibility(value) {
|
|
4845
|
+
const { visible: _visible, ...rest } = value;
|
|
4846
|
+
return rest;
|
|
4847
|
+
}
|
|
4203
4848
|
|
|
4204
4849
|
// src/portable-identity-rules.ts
|
|
4205
4850
|
var tileflowPortableIdMaximumLength = 64;
|
|
@@ -4211,6 +4856,56 @@ function isTileflowThemeName(value) {
|
|
|
4211
4856
|
return isTileflowPortableId(value) && value !== "system";
|
|
4212
4857
|
}
|
|
4213
4858
|
|
|
4859
|
+
// src/time-of-day.ts
|
|
4860
|
+
var tileflowTimesOfDay = ["day", "dawn", "dusk", "night"];
|
|
4861
|
+
function isTileflowTimeOfDay(value) {
|
|
4862
|
+
return typeof value === "string" && tileflowTimesOfDay.includes(value);
|
|
4863
|
+
}
|
|
4864
|
+
function validateTileflowTimeOfDayVariants(variants, themes) {
|
|
4865
|
+
const issues = [];
|
|
4866
|
+
const owners = /* @__PURE__ */ new Map();
|
|
4867
|
+
const families = Object.entries(variants);
|
|
4868
|
+
for (const [family, moments] of families) {
|
|
4869
|
+
if (!isTileflowThemeName(family) || !Object.hasOwn(themes, family)) {
|
|
4870
|
+
issues.push({ path: [family], message: "Time-of-day family must name an existing theme" });
|
|
4871
|
+
}
|
|
4872
|
+
if (!Object.values(moments).includes(family)) {
|
|
4873
|
+
issues.push({ path: [family], message: "A family must include its own theme in its presets" });
|
|
4874
|
+
}
|
|
4875
|
+
for (const [moment, name] of Object.entries(moments)) {
|
|
4876
|
+
if (name === void 0) continue;
|
|
4877
|
+
if (!isTileflowTimeOfDay(moment) || !isTileflowThemeName(name) || !Object.hasOwn(themes, name)) {
|
|
4878
|
+
issues.push({
|
|
4879
|
+
path: [family, moment],
|
|
4880
|
+
message: "Expected a supported moment and an existing theme"
|
|
4881
|
+
});
|
|
4882
|
+
}
|
|
4883
|
+
const owner = owners.get(name);
|
|
4884
|
+
if (owner !== void 0 && owner !== family) {
|
|
4885
|
+
issues.push({
|
|
4886
|
+
path: [family, moment],
|
|
4887
|
+
message: `Theme "${name}" already belongs to family "${owner}"`
|
|
4888
|
+
});
|
|
4889
|
+
}
|
|
4890
|
+
owners.set(name, family);
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
return issues;
|
|
4894
|
+
}
|
|
4895
|
+
function resolveTileflowTimeOfDayTheme(variants, theme, timeOfDay) {
|
|
4896
|
+
if (timeOfDay === void 0 || variants === void 0) return theme;
|
|
4897
|
+
if (!isTileflowTimeOfDay(timeOfDay)) throw new TypeError("Expected day, dawn, dusk, or night");
|
|
4898
|
+
const family = Object.hasOwn(variants, theme) ? variants[theme] : Object.values(variants).find((moments) => Object.values(moments).includes(theme));
|
|
4899
|
+
if (!family) return theme;
|
|
4900
|
+
const result = family[timeOfDay];
|
|
4901
|
+
if (result === void 0) {
|
|
4902
|
+
throw new Error(
|
|
4903
|
+
`Theme "${theme}" does not offer timeOfDay="${timeOfDay}". Available: ${Object.keys(family).join(", ")}.`
|
|
4904
|
+
);
|
|
4905
|
+
}
|
|
4906
|
+
return result;
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4214
4909
|
// src/sun.ts
|
|
4215
4910
|
var tileflowSunMetadataKey = "tileflow:sun";
|
|
4216
4911
|
var tileflowDefaultSunPreset = Object.freeze({
|
|
@@ -4433,7 +5128,7 @@ function resolveThemeValues(value, theme, path = "value") {
|
|
|
4433
5128
|
if (errors.length > 0) throw new TileflowThemeAuditError(errors);
|
|
4434
5129
|
return resolved;
|
|
4435
5130
|
}
|
|
4436
|
-
function resolveThemeSelection(map, requested) {
|
|
5131
|
+
function resolveThemeSelection(map, requested, timeOfDay) {
|
|
4437
5132
|
const name = requested ?? map.defaultTheme;
|
|
4438
5133
|
if (name === "system") {
|
|
4439
5134
|
throw new Error(
|
|
@@ -4450,7 +5145,8 @@ function resolveThemeSelection(map, requested) {
|
|
|
4450
5145
|
const available = Object.keys(map.themes).sort().join(", ") || "<none>";
|
|
4451
5146
|
throw new Error(`Unknown Tileflow theme "${name}"; available themes: ${available}.`);
|
|
4452
5147
|
}
|
|
4453
|
-
|
|
5148
|
+
const resolvedName = resolveTileflowTimeOfDayTheme(map.timeOfDay, name, timeOfDay);
|
|
5149
|
+
return { name: resolvedName, theme: map.themes[resolvedName] };
|
|
4454
5150
|
}
|
|
4455
5151
|
function auditTileflowThemeValues(value, path = "value", context = inferAuditContext(path)) {
|
|
4456
5152
|
const diagnostics = [];
|
|
@@ -5757,7 +6453,8 @@ function resolveColors(overrides = {}, defaults4 = defaultColors, moduleOverride
|
|
|
5757
6453
|
resolved.landcover.grass,
|
|
5758
6454
|
resolved.landcover.meadow
|
|
5759
6455
|
],
|
|
5760
|
-
conifer: [resolved.landcover.protected, resolved.landcover.scrub, resolved.landcover.wood]
|
|
6456
|
+
conifer: [resolved.landcover.protected, resolved.landcover.scrub, resolved.landcover.wood],
|
|
6457
|
+
palm: [resolved.landcover.urbanPark, resolved.landcover.grass, resolved.landcover.meadow]
|
|
5761
6458
|
}
|
|
5762
6459
|
}
|
|
5763
6460
|
};
|
|
@@ -5924,6 +6621,11 @@ function resolveThemeColors(theme) {
|
|
|
5924
6621
|
optionalColor("vegetation.tree.conifer.a", colors.vegetation.tree.conifer[0]),
|
|
5925
6622
|
optionalColor("vegetation.tree.conifer.b", colors.vegetation.tree.conifer[1]),
|
|
5926
6623
|
optionalColor("vegetation.tree.conifer.c", colors.vegetation.tree.conifer[2])
|
|
6624
|
+
],
|
|
6625
|
+
palm: [
|
|
6626
|
+
optionalColor("vegetation.tree.palm.a", colors.vegetation.tree.palm[0]),
|
|
6627
|
+
optionalColor("vegetation.tree.palm.b", colors.vegetation.tree.palm[1]),
|
|
6628
|
+
optionalColor("vegetation.tree.palm.c", colors.vegetation.tree.palm[2])
|
|
5927
6629
|
]
|
|
5928
6630
|
}
|
|
5929
6631
|
}
|
|
@@ -6513,9 +7215,10 @@ function compileRoundabouts(request, context, contributions) {
|
|
|
6513
7215
|
contributions.push({
|
|
6514
7216
|
kind: "layer",
|
|
6515
7217
|
layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-casing" }, config.casing),
|
|
6516
|
-
localOrder:
|
|
7218
|
+
localOrder: 900,
|
|
6517
7219
|
owner: "roads",
|
|
6518
|
-
|
|
7220
|
+
// Approach fills must cover the circular casing where the roads meet.
|
|
7221
|
+
slot: "transport-surface-casing",
|
|
6519
7222
|
target: "roads.roundabouts.casing"
|
|
6520
7223
|
});
|
|
6521
7224
|
}
|
|
@@ -6523,9 +7226,9 @@ function compileRoundabouts(request, context, contributions) {
|
|
|
6523
7226
|
contributions.push({
|
|
6524
7227
|
kind: "layer",
|
|
6525
7228
|
layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-fill" }, config.fill),
|
|
6526
|
-
localOrder:
|
|
7229
|
+
localOrder: 900,
|
|
6527
7230
|
owner: "roads",
|
|
6528
|
-
slot: "transport-
|
|
7231
|
+
slot: "transport-surface-fill",
|
|
6529
7232
|
target: "roads.roundabouts.fill"
|
|
6530
7233
|
});
|
|
6531
7234
|
}
|
|
@@ -6590,7 +7293,7 @@ var circularRoadBorderTotalWidth = 1;
|
|
|
6590
7293
|
function circularRoadInnerRadius(fields, casing) {
|
|
6591
7294
|
const values = circularRoadValues(fields);
|
|
6592
7295
|
const stops = [];
|
|
6593
|
-
for (let level = 15; level <=
|
|
7296
|
+
for (let level = 15; level <= 24; level += 1) {
|
|
6594
7297
|
const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
|
|
6595
7298
|
const physicalInnerRadius = [
|
|
6596
7299
|
"*",
|
|
@@ -6607,13 +7310,13 @@ function circularRoadInnerRadius(fields, casing) {
|
|
|
6607
7310
|
casing ? ["-", innerRadius, circularRoadBorderTotalWidth / 2] : innerRadius
|
|
6608
7311
|
]);
|
|
6609
7312
|
}
|
|
6610
|
-
return ["interpolate", ["
|
|
7313
|
+
return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
|
|
6611
7314
|
}
|
|
6612
7315
|
function circularRoadStrokeWidth(fields, casing) {
|
|
6613
7316
|
const values = circularRoadValues(fields);
|
|
6614
7317
|
const baseWidth = circularRoadBaseWidth(fields.class);
|
|
6615
7318
|
const stops = [];
|
|
6616
|
-
for (let level = 15; level <=
|
|
7319
|
+
for (let level = 15; level <= 24; level += 1) {
|
|
6617
7320
|
const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
|
|
6618
7321
|
const physicalWidth = [
|
|
6619
7322
|
"*",
|
|
@@ -6628,7 +7331,7 @@ function circularRoadStrokeWidth(fields, casing) {
|
|
|
6628
7331
|
casing ? ["+", fallbackWidth, circularRoadBorderTotalWidth] : fallbackWidth
|
|
6629
7332
|
]);
|
|
6630
7333
|
}
|
|
6631
|
-
return ["interpolate", ["
|
|
7334
|
+
return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
|
|
6632
7335
|
}
|
|
6633
7336
|
function circularRoadBaseWidth(classField) {
|
|
6634
7337
|
return [
|
|
@@ -6792,6 +7495,10 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
|
|
|
6792
7495
|
return value === void 0 ? [] : [{ condition, resolve: () => expressionOutput(value) }];
|
|
6793
7496
|
});
|
|
6794
7497
|
if (branches.length > 0) {
|
|
7498
|
+
if (property === "dash" && isSolidRoadDash(result[property] ?? treatmentPaintDefaults.dash) && branches.every(({ resolve }) => isSolidRoadDash(resolve()))) {
|
|
7499
|
+
delete result[property];
|
|
7500
|
+
continue;
|
|
7501
|
+
}
|
|
6795
7502
|
result[property] = conditionalStyleValue(
|
|
6796
7503
|
result[property],
|
|
6797
7504
|
branches,
|
|
@@ -6808,9 +7515,21 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
|
|
|
6808
7515
|
widthScales,
|
|
6809
7516
|
treatmentPaintDefaults.width
|
|
6810
7517
|
);
|
|
7518
|
+
if (result.gapWidth !== void 0 && result.gapWidth !== 0) {
|
|
7519
|
+
result.gapWidth = conditionalWidthScaleValue(
|
|
7520
|
+
result.gapWidth,
|
|
7521
|
+
widthScales,
|
|
7522
|
+
treatmentPaintDefaults.gapWidth
|
|
7523
|
+
);
|
|
7524
|
+
}
|
|
6811
7525
|
}
|
|
6812
7526
|
return result;
|
|
6813
7527
|
}
|
|
7528
|
+
function isSolidRoadDash(value) {
|
|
7529
|
+
const output = expressionOutput(value);
|
|
7530
|
+
const dash = Array.isArray(output) && output[0] === "literal" ? output[1] : output;
|
|
7531
|
+
return Array.isArray(dash) && dash.length === 2 && dash[0] === 1 && dash[1] === 0;
|
|
7532
|
+
}
|
|
6814
7533
|
function roadTreatmentPhaseConditions(treatments, structure, phase) {
|
|
6815
7534
|
return treatments.flatMap(
|
|
6816
7535
|
({ condition, style }) => style[structure]?.[phase] === void 0 ? [] : [condition]
|
|
@@ -6895,10 +7614,10 @@ function isExpressionOutput(value) {
|
|
|
6895
7614
|
}
|
|
6896
7615
|
function rewriteZoomOutputs(value, rewrite) {
|
|
6897
7616
|
if (!Array.isArray(value)) return rewrite(value);
|
|
6898
|
-
if (value[0] === "interpolate" &&
|
|
7617
|
+
if (value[0] === "interpolate" && isZoomInput4(value[2])) {
|
|
6899
7618
|
return value.map((entry, index) => index >= 4 && index % 2 === 0 ? rewrite(entry) : entry);
|
|
6900
7619
|
}
|
|
6901
|
-
if (value[0] === "step" &&
|
|
7620
|
+
if (value[0] === "step" && isZoomInput4(value[1])) {
|
|
6902
7621
|
return value.map(
|
|
6903
7622
|
(entry, index) => index === 2 || index >= 4 && index % 2 === 0 ? rewrite(entry) : entry
|
|
6904
7623
|
);
|
|
@@ -6908,7 +7627,7 @@ function rewriteZoomOutputs(value, rewrite) {
|
|
|
6908
7627
|
function expressionOutput(value) {
|
|
6909
7628
|
return Array.isArray(value) && typeof value[0] !== "string" ? ["literal", value] : value;
|
|
6910
7629
|
}
|
|
6911
|
-
function
|
|
7630
|
+
function isZoomInput4(value) {
|
|
6912
7631
|
return Array.isArray(value) && value.length === 1 && value[0] === "zoom";
|
|
6913
7632
|
}
|
|
6914
7633
|
function restrictedAccessFilter(field2) {
|
|
@@ -7243,105 +7962,35 @@ function railHatchingStyle(color2, opacity) {
|
|
|
7243
7962
|
};
|
|
7244
7963
|
}
|
|
7245
7964
|
function serviceRailStyle(color2, opacity) {
|
|
7246
|
-
return {
|
|
7247
|
-
color: color2,
|
|
7248
|
-
minZoom: 12,
|
|
7249
|
-
opacity,
|
|
7250
|
-
width: zoom.linear([
|
|
7251
|
-
[12, 0.35],
|
|
7252
|
-
[16, 1.4]
|
|
7253
|
-
])
|
|
7254
|
-
};
|
|
7255
|
-
}
|
|
7256
|
-
function structureFilter2(field2, structure) {
|
|
7257
|
-
return structure === "surface" ? ["match", ["get", field2], ["tunnel", "bridge"], false, true] : ["==", ["get", field2], structure];
|
|
7258
|
-
}
|
|
7259
|
-
function modalFilter(classField, subclassField, modes) {
|
|
7260
|
-
return [
|
|
7261
|
-
"any",
|
|
7262
|
-
["match", ["get", classField], modes, true, false],
|
|
7263
|
-
["match", ["get", subclassField], modes, true, false]
|
|
7264
|
-
];
|
|
7265
|
-
}
|
|
7266
|
-
|
|
7267
|
-
// src/modules/vegetation/index.ts
|
|
7268
|
-
function vegetation(options = {}) {
|
|
7269
|
-
return { type: "vegetation", ...cloneJson16(options) };
|
|
7270
|
-
}
|
|
7271
|
-
function cloneJson16(value) {
|
|
7272
|
-
return JSON.parse(JSON.stringify(value));
|
|
7273
|
-
}
|
|
7274
|
-
|
|
7275
|
-
// src/modules/vegetation/compiler.ts
|
|
7276
|
-
function compileVegetation(request, context) {
|
|
7277
|
-
const minZoom = request?.flat?.minZoom ?? 16;
|
|
7278
|
-
const mode = request?.mode ?? "3d";
|
|
7279
|
-
const config = mergeTileflowDesign(
|
|
7280
|
-
{
|
|
7281
|
-
type: "vegetation",
|
|
7282
|
-
enabled: true,
|
|
7283
|
-
flat: {
|
|
7284
|
-
color: context.colors.landcover.wood,
|
|
7285
|
-
minZoom,
|
|
7286
|
-
opacity: mode === "3d" ? 0.82 : 0.9,
|
|
7287
|
-
pitchAlignment: "map",
|
|
7288
|
-
pitchScale: "map",
|
|
7289
|
-
radius: minZoom < 24 ? zoom.linear([
|
|
7290
|
-
[minZoom, 2.2],
|
|
7291
|
-
[minZoom < 20 ? 20 : 24, 8]
|
|
7292
|
-
]) : 2.2,
|
|
7293
|
-
strokeColor: context.colors.park,
|
|
7294
|
-
strokeOpacity: 0.55,
|
|
7295
|
-
strokeWidth: 0.8
|
|
7296
|
-
},
|
|
7297
|
-
mode,
|
|
7298
|
-
threeDimensional: {
|
|
7299
|
-
barkColor: context.colors.vegetation.tree.bark,
|
|
7300
|
-
broadleafColors: context.colors.vegetation.tree.broadleaf,
|
|
7301
|
-
coniferColors: context.colors.vegetation.tree.conifer,
|
|
7302
|
-
crownScale: 1,
|
|
7303
|
-
heightScale: 1
|
|
7304
|
-
}
|
|
7305
|
-
},
|
|
7306
|
-
request
|
|
7307
|
-
);
|
|
7308
|
-
if (config.enabled === false || !context.data.schema.layers.tree) return [];
|
|
7309
|
-
const resolvedMode = config.mode ?? "3d";
|
|
7310
|
-
const threeDimensional = config.threeDimensional;
|
|
7965
|
+
return {
|
|
7966
|
+
color: color2,
|
|
7967
|
+
minZoom: 12,
|
|
7968
|
+
opacity,
|
|
7969
|
+
width: zoom.linear([
|
|
7970
|
+
[12, 0.35],
|
|
7971
|
+
[16, 1.4]
|
|
7972
|
+
])
|
|
7973
|
+
};
|
|
7974
|
+
}
|
|
7975
|
+
function structureFilter2(field2, structure) {
|
|
7976
|
+
return structure === "surface" ? ["match", ["get", field2], ["tunnel", "bridge"], false, true] : ["==", ["get", field2], structure];
|
|
7977
|
+
}
|
|
7978
|
+
function modalFilter(classField, subclassField, modes) {
|
|
7311
7979
|
return [
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
{
|
|
7316
|
-
id: "tileflow-vegetation-trees",
|
|
7317
|
-
type: "circle",
|
|
7318
|
-
source: context.data.sourceId,
|
|
7319
|
-
"source-layer": context.data.schema.layers.tree,
|
|
7320
|
-
metadata: {
|
|
7321
|
-
"tileflow:vegetation-mode": resolvedMode,
|
|
7322
|
-
...resolvedMode === "3d" ? { "tileflow:vegetation-fallback": "flat-circle" } : {},
|
|
7323
|
-
"tileflow:tree-bark-color": threeDimensional.barkColor,
|
|
7324
|
-
"tileflow:tree-broadleaf-colors": threeDimensional.broadleafColors,
|
|
7325
|
-
"tileflow:tree-conifer-colors": threeDimensional.coniferColors,
|
|
7326
|
-
"tileflow:tree-crown-field": context.data.schema.fields.diameterCrown,
|
|
7327
|
-
"tileflow:tree-crown-scale": threeDimensional.crownScale,
|
|
7328
|
-
"tileflow:tree-genus-field": context.data.schema.fields.genus,
|
|
7329
|
-
"tileflow:tree-height-field": context.data.schema.fields.height,
|
|
7330
|
-
"tileflow:tree-height-scale": threeDimensional.heightScale,
|
|
7331
|
-
"tileflow:tree-leaf-type-field": context.data.schema.fields.leafType,
|
|
7332
|
-
"tileflow:tree-species-field": context.data.schema.fields.species
|
|
7333
|
-
}
|
|
7334
|
-
},
|
|
7335
|
-
config.flat ?? {}
|
|
7336
|
-
),
|
|
7337
|
-
localOrder: 1,
|
|
7338
|
-
owner: "vegetation",
|
|
7339
|
-
slot: "vegetation",
|
|
7340
|
-
target: "vegetation.trees"
|
|
7341
|
-
}
|
|
7980
|
+
"any",
|
|
7981
|
+
["match", ["get", classField], modes, true, false],
|
|
7982
|
+
["match", ["get", subclassField], modes, true, false]
|
|
7342
7983
|
];
|
|
7343
7984
|
}
|
|
7344
7985
|
|
|
7986
|
+
// src/modules/vegetation/index.ts
|
|
7987
|
+
function vegetation(options = {}) {
|
|
7988
|
+
return { type: "vegetation", ...cloneJson16(options) };
|
|
7989
|
+
}
|
|
7990
|
+
function cloneJson16(value) {
|
|
7991
|
+
return JSON.parse(JSON.stringify(value));
|
|
7992
|
+
}
|
|
7993
|
+
|
|
7345
7994
|
// src/modules/water/index.ts
|
|
7346
7995
|
function water(options = {}) {
|
|
7347
7996
|
return { type: "water", ...cloneJson17(options) };
|
|
@@ -7357,7 +8006,7 @@ var waterwayClasses = {
|
|
|
7357
8006
|
river: ["river"],
|
|
7358
8007
|
stream: ["stream"]
|
|
7359
8008
|
};
|
|
7360
|
-
function compileWater(request, context) {
|
|
8009
|
+
function compileWater(request, context, language = "auto") {
|
|
7361
8010
|
const config = mergeTileflowDesign(
|
|
7362
8011
|
{
|
|
7363
8012
|
type: "water",
|
|
@@ -7509,8 +8158,11 @@ function compileWater(request, context) {
|
|
|
7509
8158
|
appendBathymetryRelief(contributions, bathymetryProduct.relief, context);
|
|
7510
8159
|
}
|
|
7511
8160
|
const productContours = bathymetryProduct?.contours;
|
|
8161
|
+
const nativeContours = sidecarBathymetry && bathymetryProduct?.vectorLayers?.contours === true;
|
|
8162
|
+
const contourLayer = nativeContours ? tileflowBathymetryV1Schema.layers.contours : bathymetryLayer;
|
|
8163
|
+
const contourDepthField = nativeContours ? tileflowBathymetryV1Schema.fields.depth : bathymetryDepthField;
|
|
7512
8164
|
const contourRequest = productContours === false ? void 0 : productContours === void 0 ? request?.bathymetryContours : mergeTileflowDesign(productContours, request?.bathymetryContours);
|
|
7513
|
-
if (contourRequest !== void 0 &&
|
|
8165
|
+
if (contourRequest !== void 0 && contourLayer && contourDepthField) {
|
|
7514
8166
|
const bathymetryContours = mergeTileflowDesign(
|
|
7515
8167
|
{
|
|
7516
8168
|
color: context.colors.hydro.label,
|
|
@@ -7533,12 +8185,12 @@ function compileWater(request, context) {
|
|
|
7533
8185
|
id: "tileflow-bathymetry-contours",
|
|
7534
8186
|
type: "line",
|
|
7535
8187
|
source: bathymetrySource,
|
|
7536
|
-
"source-layer":
|
|
8188
|
+
"source-layer": contourLayer,
|
|
7537
8189
|
filter: [
|
|
7538
8190
|
"all",
|
|
7539
|
-
["==", ["geometry-type"], "Polygon"],
|
|
7540
|
-
["has",
|
|
7541
|
-
["<", ["to-number", ["get",
|
|
8191
|
+
["==", ["geometry-type"], nativeContours ? "LineString" : "Polygon"],
|
|
8192
|
+
["has", contourDepthField],
|
|
8193
|
+
["<", ["to-number", ["get", contourDepthField], 0], 0]
|
|
7542
8194
|
]
|
|
7543
8195
|
},
|
|
7544
8196
|
bathymetryContours
|
|
@@ -7552,19 +8204,19 @@ function compileWater(request, context) {
|
|
|
7552
8204
|
}
|
|
7553
8205
|
const productLabels = bathymetryProduct?.labels;
|
|
7554
8206
|
const labelRequest = productLabels === false ? void 0 : productLabels === void 0 ? request?.bathymetryLabels : mergeTileflowDesign(productLabels, request?.bathymetryLabels);
|
|
7555
|
-
if (labelRequest !== void 0 &&
|
|
8207
|
+
if (labelRequest !== void 0 && contourLayer && contourDepthField) {
|
|
7556
8208
|
const bathymetryLabels = mergeTileflowDesign(
|
|
7557
8209
|
{
|
|
7558
8210
|
maxZoom: 10,
|
|
7559
8211
|
minZoom: 3,
|
|
7560
|
-
placement: "point",
|
|
8212
|
+
placement: nativeContours ? "line" : "point",
|
|
7561
8213
|
priority: 5,
|
|
7562
8214
|
text: {
|
|
7563
8215
|
allowOverlap: false,
|
|
7564
8216
|
color: context.colors.hydro.label,
|
|
7565
8217
|
field: expression([
|
|
7566
8218
|
"to-string",
|
|
7567
|
-
["abs", ["to-number", ["get",
|
|
8219
|
+
["abs", ["to-number", ["get", contourDepthField], 0]]
|
|
7568
8220
|
]),
|
|
7569
8221
|
...typographyTextStyle(context.typography.water),
|
|
7570
8222
|
haloColor: context.colors.hydro.water,
|
|
@@ -7585,8 +8237,13 @@ function compileWater(request, context) {
|
|
|
7585
8237
|
id: "tileflow-bathymetry-labels",
|
|
7586
8238
|
type: "symbol",
|
|
7587
8239
|
source: bathymetrySource,
|
|
7588
|
-
"source-layer":
|
|
7589
|
-
filter: [
|
|
8240
|
+
"source-layer": contourLayer,
|
|
8241
|
+
filter: [
|
|
8242
|
+
"all",
|
|
8243
|
+
["==", ["geometry-type"], nativeContours ? "LineString" : "Polygon"],
|
|
8244
|
+
["has", contourDepthField],
|
|
8245
|
+
...nativeContours ? [["<", ["to-number", ["get", contourDepthField], 0], 0]] : []
|
|
8246
|
+
]
|
|
7590
8247
|
},
|
|
7591
8248
|
bathymetryLabels
|
|
7592
8249
|
),
|
|
@@ -7597,6 +8254,37 @@ function compileWater(request, context) {
|
|
|
7597
8254
|
});
|
|
7598
8255
|
}
|
|
7599
8256
|
}
|
|
8257
|
+
if (sidecarBathymetry) {
|
|
8258
|
+
const { layers: marineLayers } = tileflowBathymetryV1Schema;
|
|
8259
|
+
const landforms2 = bathymetryProduct?.vectorLayers?.landforms;
|
|
8260
|
+
const waterNames = bathymetryProduct?.vectorLayers?.waterNames;
|
|
8261
|
+
if (landforms2) {
|
|
8262
|
+
appendBathymetryNames(contributions, {
|
|
8263
|
+
availability: landforms2,
|
|
8264
|
+
context,
|
|
8265
|
+
language,
|
|
8266
|
+
localOrder: -300,
|
|
8267
|
+
source: sidecarBathymetry.sourceId,
|
|
8268
|
+
sourceLayer: marineLayers.landforms,
|
|
8269
|
+
style: config.bathymetryLandforms,
|
|
8270
|
+
target: "water.bathymetryLandforms",
|
|
8271
|
+
id: "tileflow-bathymetry-landforms"
|
|
8272
|
+
});
|
|
8273
|
+
}
|
|
8274
|
+
if (waterNames) {
|
|
8275
|
+
appendBathymetryNames(contributions, {
|
|
8276
|
+
availability: waterNames,
|
|
8277
|
+
context,
|
|
8278
|
+
language,
|
|
8279
|
+
localOrder: -150,
|
|
8280
|
+
source: sidecarBathymetry.sourceId,
|
|
8281
|
+
sourceLayer: marineLayers.waterNames,
|
|
8282
|
+
style: config.bathymetryWaterNames,
|
|
8283
|
+
target: "water.bathymetryWaterNames",
|
|
8284
|
+
id: "tileflow-bathymetry-water-names"
|
|
8285
|
+
});
|
|
8286
|
+
}
|
|
8287
|
+
}
|
|
7600
8288
|
let localOrder = 10;
|
|
7601
8289
|
for (const [name, classes] of Object.entries(waterwayClasses)) {
|
|
7602
8290
|
const style = config.waterways?.[name];
|
|
@@ -7660,6 +8348,99 @@ function compileWater(request, context) {
|
|
|
7660
8348
|
}
|
|
7661
8349
|
return contributions;
|
|
7662
8350
|
}
|
|
8351
|
+
function appendBathymetryNames(contributions, options) {
|
|
8352
|
+
const { context, language } = options;
|
|
8353
|
+
const { fields } = tileflowBathymetryV1Schema;
|
|
8354
|
+
const localName = ["to-string", ["coalesce", ["get", fields.name], ""]];
|
|
8355
|
+
const name = language === "auto" || language === "local" ? localName : [
|
|
8356
|
+
"case",
|
|
8357
|
+
["!=", ["to-string", ["coalesce", ["get", `name:${language}`], ""]], ""],
|
|
8358
|
+
["to-string", ["get", `name:${language}`]],
|
|
8359
|
+
localName
|
|
8360
|
+
];
|
|
8361
|
+
const style = mergeTileflowDesign(
|
|
8362
|
+
{
|
|
8363
|
+
minZoom: 0,
|
|
8364
|
+
placement: "point",
|
|
8365
|
+
priority: expression(["to-number", ["get", fields.sortKey], 0]),
|
|
8366
|
+
priorityOrder: "lower-first",
|
|
8367
|
+
text: {
|
|
8368
|
+
...typographyTextStyle(context.typography.water),
|
|
8369
|
+
allowOverlap: false,
|
|
8370
|
+
ignorePlacement: false,
|
|
8371
|
+
color: context.colors.hydro.label,
|
|
8372
|
+
field: expression(name),
|
|
8373
|
+
haloColor: context.colors.hydro.water,
|
|
8374
|
+
haloWidth: 1,
|
|
8375
|
+
optional: false,
|
|
8376
|
+
padding: 12,
|
|
8377
|
+
size: 11
|
|
8378
|
+
}
|
|
8379
|
+
},
|
|
8380
|
+
options.style
|
|
8381
|
+
);
|
|
8382
|
+
if (style.visible === false || style.text?.visible === false) return;
|
|
8383
|
+
const layer = applySymbolStyle(
|
|
8384
|
+
{
|
|
8385
|
+
id: options.id,
|
|
8386
|
+
type: "symbol",
|
|
8387
|
+
source: options.source,
|
|
8388
|
+
"source-layer": options.sourceLayer,
|
|
8389
|
+
filter: [
|
|
8390
|
+
"all",
|
|
8391
|
+
["match", ["geometry-type"], ["Point", "LineString", "Polygon"], true, false],
|
|
8392
|
+
["!=", name, ""]
|
|
8393
|
+
]
|
|
8394
|
+
},
|
|
8395
|
+
style
|
|
8396
|
+
);
|
|
8397
|
+
const sourceMinimum = ["to-number", ["coalesce", ["get", fields.minZoom], 0], 0];
|
|
8398
|
+
const sourceMaximum = ["to-number", ["coalesce", ["get", fields.maxZoom], 24], 24];
|
|
8399
|
+
const baseFilter = layer.filter;
|
|
8400
|
+
const append = (result, target, order = 0) => {
|
|
8401
|
+
contributions.push({
|
|
8402
|
+
kind: "layer",
|
|
8403
|
+
layer: result,
|
|
8404
|
+
localOrder: options.localOrder + order,
|
|
8405
|
+
owner: "water",
|
|
8406
|
+
slot: "symbols",
|
|
8407
|
+
target
|
|
8408
|
+
});
|
|
8409
|
+
};
|
|
8410
|
+
if (options.availability === true) {
|
|
8411
|
+
append(
|
|
8412
|
+
{
|
|
8413
|
+
...layer,
|
|
8414
|
+
filter: [...baseFilter, [">=", ["zoom"], sourceMinimum], ["<", ["zoom"], sourceMaximum]]
|
|
8415
|
+
},
|
|
8416
|
+
options.target
|
|
8417
|
+
);
|
|
8418
|
+
return;
|
|
8419
|
+
}
|
|
8420
|
+
const ranges = [...options.availability.zoomRanges].sort(
|
|
8421
|
+
(left, right) => left.minZoom - right.minZoom || left.maxZoom - right.maxZoom
|
|
8422
|
+
);
|
|
8423
|
+
for (const [index, range2] of ranges.entries()) {
|
|
8424
|
+
const minzoom = Math.max(Number(layer.minzoom ?? 0), range2.minZoom);
|
|
8425
|
+
const maxzoom = Math.min(Number(layer.maxzoom ?? 24), range2.maxZoom);
|
|
8426
|
+
if (minzoom >= maxzoom) continue;
|
|
8427
|
+
append(
|
|
8428
|
+
{
|
|
8429
|
+
...layer,
|
|
8430
|
+
id: `${options.id}-cohort-${index}`,
|
|
8431
|
+
minzoom,
|
|
8432
|
+
maxzoom,
|
|
8433
|
+
filter: [
|
|
8434
|
+
...baseFilter,
|
|
8435
|
+
["==", sourceMinimum, range2.minZoom],
|
|
8436
|
+
["==", sourceMaximum, range2.maxZoom]
|
|
8437
|
+
]
|
|
8438
|
+
},
|
|
8439
|
+
`${options.target}.cohort${index}`,
|
|
8440
|
+
index
|
|
8441
|
+
);
|
|
8442
|
+
}
|
|
8443
|
+
}
|
|
7663
8444
|
function appendBathymetryRelief(contributions, relief, context) {
|
|
7664
8445
|
const { sourceId, style } = relief;
|
|
7665
8446
|
const opacity = resolvedNumber(style.opacity, 0.22, "bathymetry relief opacity");
|
|
@@ -7868,12 +8649,6 @@ var tileflowSemanticDomainRegistry = Object.freeze([
|
|
|
7868
8649
|
dependencies: {},
|
|
7869
8650
|
name: "land"
|
|
7870
8651
|
}),
|
|
7871
|
-
defineDomain({
|
|
7872
|
-
compile: ({ context, module }) => compileWater(module, context),
|
|
7873
|
-
defaultModule: water(),
|
|
7874
|
-
dependencies: {},
|
|
7875
|
-
name: "water"
|
|
7876
|
-
}),
|
|
7877
8652
|
defineDomain({
|
|
7878
8653
|
compile: ({ context, module }) => compileNautical(module, context),
|
|
7879
8654
|
defaultModule: nautical(),
|
|
@@ -7962,6 +8737,12 @@ var tileflowSemanticDomainRegistry = Object.freeze([
|
|
|
7962
8737
|
provides: ["language"],
|
|
7963
8738
|
resolveServices: ({ module }) => ({ language: resolveLabels(module).language })
|
|
7964
8739
|
}),
|
|
8740
|
+
defineDomain({
|
|
8741
|
+
compile: ({ context, dependencies, module }) => compileWater(module, context, dependencies.service("language")),
|
|
8742
|
+
defaultModule: water(),
|
|
8743
|
+
dependencies: { services: ["language"] },
|
|
8744
|
+
name: "water"
|
|
8745
|
+
}),
|
|
7965
8746
|
defineDomain({
|
|
7966
8747
|
compile: ({ context, dependencies, module }) => compileLandforms(module, dependencies.service("language"), context),
|
|
7967
8748
|
defaultModule: landforms(),
|
|
@@ -8080,7 +8861,7 @@ function createTileflowCompilerProvenance(owner, slot, target) {
|
|
|
8080
8861
|
return [{ operations: [], owner, slot, target }];
|
|
8081
8862
|
}
|
|
8082
8863
|
function readTileflowCompilerProvenance(layer) {
|
|
8083
|
-
const metadata =
|
|
8864
|
+
const metadata = asRecord3(layer.metadata);
|
|
8084
8865
|
const raw = metadata[tileflowCompilerProvenanceMetadataKey];
|
|
8085
8866
|
if (Array.isArray(raw)) {
|
|
8086
8867
|
const parsed = raw.flatMap((value) => {
|
|
@@ -8108,7 +8889,7 @@ function createTileflowStyleInspection(map, theme, layers) {
|
|
|
8108
8889
|
};
|
|
8109
8890
|
}
|
|
8110
8891
|
function parseContribution(value) {
|
|
8111
|
-
const input =
|
|
8892
|
+
const input = asRecord3(value);
|
|
8112
8893
|
const owner = requireLayerDomain(input.owner);
|
|
8113
8894
|
const slot = requireLayerSlot(input.slot);
|
|
8114
8895
|
const target = input.target;
|
|
@@ -8122,7 +8903,7 @@ function parseContribution(value) {
|
|
|
8122
8903
|
return { operations, owner, slot, target };
|
|
8123
8904
|
}
|
|
8124
8905
|
function parseRenderOperation(value) {
|
|
8125
|
-
const input =
|
|
8906
|
+
const input = asRecord3(value);
|
|
8126
8907
|
const owner = requireLayerDomain(input.owner);
|
|
8127
8908
|
const target = input.target;
|
|
8128
8909
|
if (input.kind !== "pass" && input.kind !== "refinement" || !owner || typeof target !== "string" || !tileflowSemanticTargetPattern.test(target)) {
|
|
@@ -8136,7 +8917,7 @@ function requireLayerDomain(value) {
|
|
|
8136
8917
|
function requireLayerSlot(value) {
|
|
8137
8918
|
return typeof value === "string" && tileflowLayerSlots.includes(value) ? value : void 0;
|
|
8138
8919
|
}
|
|
8139
|
-
function
|
|
8920
|
+
function asRecord3(value) {
|
|
8140
8921
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8141
8922
|
}
|
|
8142
8923
|
|
|
@@ -8183,6 +8964,7 @@ var classicManifestSchemaOperations = {
|
|
|
8183
8964
|
return z3.enum(values);
|
|
8184
8965
|
},
|
|
8185
8966
|
literal: (value) => z3.literal(value),
|
|
8967
|
+
union: (left, right) => z3.union([classic(left), classic(right)]),
|
|
8186
8968
|
tuplePair(left, right) {
|
|
8187
8969
|
return z3.tuple([classic(left), classic(right)]);
|
|
8188
8970
|
},
|
|
@@ -8505,7 +9287,7 @@ function not(value) {
|
|
|
8505
9287
|
function has(reference) {
|
|
8506
9288
|
return make(["has", reference]);
|
|
8507
9289
|
}
|
|
8508
|
-
function
|
|
9290
|
+
function match2(input, branches, fallback) {
|
|
8509
9291
|
validateBranchCount(branches.length, "expr.match");
|
|
8510
9292
|
validateMatchLabels(branches);
|
|
8511
9293
|
return make([
|
|
@@ -8603,7 +9385,7 @@ function limitError(message) {
|
|
|
8603
9385
|
return new Error(site ? `${message} Called at ${site}.` : message);
|
|
8604
9386
|
}
|
|
8605
9387
|
function authoringCallSite(stack) {
|
|
8606
|
-
const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((
|
|
9388
|
+
const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((match3) => match3 !== null).map(([, file, line, column]) => ({ file: file.replace(/^file:\/\//, ""), line, column }));
|
|
8607
9389
|
const own = locations[0]?.file;
|
|
8608
9390
|
const site = locations.find(({ file }) => file !== own && !file.startsWith("node:"));
|
|
8609
9391
|
return site ? `${site.file}:${site.line}:${site.column}` : void 0;
|
|
@@ -8988,7 +9770,7 @@ var expr = Object.freeze({
|
|
|
8988
9770
|
literal,
|
|
8989
9771
|
lt: (left, right) => compare("<", left, right),
|
|
8990
9772
|
lte: (left, right) => compare("<=", left, right),
|
|
8991
|
-
match,
|
|
9773
|
+
match: match2,
|
|
8992
9774
|
max: maximum,
|
|
8993
9775
|
min: minimum,
|
|
8994
9776
|
modulo,
|
|
@@ -9012,6 +9794,12 @@ var tileflowSemanticFieldNames = Object.freeze(
|
|
|
9012
9794
|
var tileflowSemanticLayerNames = Object.freeze(
|
|
9013
9795
|
Object.keys(completeSemanticDataContract.layers).sort(compareCodeUnits5)
|
|
9014
9796
|
);
|
|
9797
|
+
var auxiliaryFieldBindings = Object.freeze({
|
|
9798
|
+
bathymetryContourDepth: tileflowBathymetryV1Schema.fields.depth
|
|
9799
|
+
});
|
|
9800
|
+
var tileflowSemanticExpressionFieldNames = Object.freeze(
|
|
9801
|
+
[...tileflowSemanticFieldNames, ...Object.keys(auxiliaryFieldBindings)].sort(compareCodeUnits5)
|
|
9802
|
+
);
|
|
9015
9803
|
function field(name) {
|
|
9016
9804
|
return Object.freeze({ kind: "tileflow-data-field", name });
|
|
9017
9805
|
}
|
|
@@ -9043,6 +9831,9 @@ function bindSemanticReferences(value, data) {
|
|
|
9043
9831
|
}
|
|
9044
9832
|
function bindSemanticValue(value, schema, sourceId) {
|
|
9045
9833
|
if (isDataFieldReference2(value)) {
|
|
9834
|
+
if (Object.hasOwn(auxiliaryFieldBindings, value.name)) {
|
|
9835
|
+
return auxiliaryFieldBindings[value.name];
|
|
9836
|
+
}
|
|
9046
9837
|
const binding = schema.fields[value.name];
|
|
9047
9838
|
if (!binding) throw new Error(`Tileflow data schema does not provide field ${value.name}.`);
|
|
9048
9839
|
return binding;
|
|
@@ -9247,72 +10038,77 @@ function emitLayer(family, resolvePhysicalId) {
|
|
|
9247
10038
|
function physicalLayerIdForSemanticKey(semanticKey) {
|
|
9248
10039
|
const exact = exactPhysicalLayerIds[semanticKey];
|
|
9249
10040
|
if (exact) return exact;
|
|
9250
|
-
let
|
|
10041
|
+
let match3 = /^([A-Za-z0-9_-]+)\.render\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(
|
|
9251
10042
|
semanticKey
|
|
9252
10043
|
);
|
|
9253
|
-
if (
|
|
9254
|
-
|
|
10044
|
+
if (match3) return `tileflow-${match3[1]}-render-${match3[2].replaceAll(".", "-")}`;
|
|
10045
|
+
match3 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch)$/u.exec(
|
|
9255
10046
|
semanticKey
|
|
9256
10047
|
);
|
|
9257
|
-
if (
|
|
9258
|
-
|
|
10048
|
+
if (match3) return `tileflow-road-${match3[2]}-${match3[1]}-${match3[3]}`;
|
|
10049
|
+
match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill)$/u.exec(
|
|
9259
10050
|
semanticKey
|
|
9260
10051
|
);
|
|
9261
|
-
if (
|
|
9262
|
-
|
|
9263
|
-
if (
|
|
9264
|
-
|
|
9265
|
-
if (
|
|
9266
|
-
const base =
|
|
9267
|
-
return
|
|
9268
|
-
}
|
|
9269
|
-
|
|
9270
|
-
if (
|
|
9271
|
-
const base = `tileflow-${
|
|
9272
|
-
return
|
|
9273
|
-
}
|
|
9274
|
-
|
|
9275
|
-
if (
|
|
9276
|
-
return
|
|
9277
|
-
}
|
|
9278
|
-
|
|
9279
|
-
if (
|
|
9280
|
-
|
|
9281
|
-
if (
|
|
9282
|
-
const base = `tileflow-water${
|
|
9283
|
-
return
|
|
9284
|
-
}
|
|
9285
|
-
|
|
9286
|
-
if (
|
|
9287
|
-
|
|
9288
|
-
if (
|
|
9289
|
-
const base =
|
|
9290
|
-
return
|
|
9291
|
-
}
|
|
9292
|
-
|
|
9293
|
-
if (
|
|
9294
|
-
|
|
9295
|
-
if (
|
|
9296
|
-
|
|
9297
|
-
if (
|
|
9298
|
-
|
|
9299
|
-
if (
|
|
9300
|
-
|
|
9301
|
-
if (
|
|
9302
|
-
|
|
9303
|
-
if (
|
|
9304
|
-
|
|
9305
|
-
if (
|
|
9306
|
-
|
|
9307
|
-
if (
|
|
9308
|
-
|
|
9309
|
-
if (
|
|
9310
|
-
|
|
9311
|
-
if (
|
|
9312
|
-
|
|
9313
|
-
if (
|
|
9314
|
-
|
|
9315
|
-
if (
|
|
10052
|
+
if (match3) return `tileflow-road-${match3[1]}-highzoom-${match3[2]}-${match3[3]}`;
|
|
10053
|
+
match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.hatch$/u.exec(semanticKey);
|
|
10054
|
+
if (match3) return `tileflow-road-${match3[1]}-hatch`;
|
|
10055
|
+
match3 = /^roads\.areas\.(road|pedestrian|pier)\.(fill|outline)$/u.exec(semanticKey);
|
|
10056
|
+
if (match3) {
|
|
10057
|
+
const base = match3[1] === "road" ? "tileflow-road-area" : `tileflow-road-${match3[1]}-area`;
|
|
10058
|
+
return match3[2] === "fill" ? base : `${base}-outline`;
|
|
10059
|
+
}
|
|
10060
|
+
match3 = /^land\.(landcover|landuse)\.([^.]+)\.(fill|outline)$/u.exec(semanticKey);
|
|
10061
|
+
if (match3) {
|
|
10062
|
+
const base = `tileflow-${match3[1]}-${match3[2]}`;
|
|
10063
|
+
return match3[3] === "fill" ? base : `${base}-outline`;
|
|
10064
|
+
}
|
|
10065
|
+
match3 = /^land\.compatibility\.legacyPark\.(fill|outline)$/u.exec(semanticKey);
|
|
10066
|
+
if (match3) {
|
|
10067
|
+
return match3[1] === "fill" ? "tileflow-landcover-legacy-park" : "tileflow-landcover-legacy-park-outline";
|
|
10068
|
+
}
|
|
10069
|
+
match3 = /^land\.cohorts\.(landcover|landuse)(?:\.cohort(\d+))?$/u.exec(semanticKey);
|
|
10070
|
+
if (match3) return `tileflow-${match3[1]}${match3[2] === void 0 ? "" : `-${match3[2]}`}`;
|
|
10071
|
+
match3 = /^water\.(intermittent\.)?bodies\.(fill|outline)$/u.exec(semanticKey);
|
|
10072
|
+
if (match3) {
|
|
10073
|
+
const base = `tileflow-water${match3[1] ? "-intermittent" : ""}`;
|
|
10074
|
+
return match3[2] === "fill" ? base : `${base}-outline`;
|
|
10075
|
+
}
|
|
10076
|
+
match3 = /^water\.(intermittent\.)?waterways\.([^.]+)$/u.exec(semanticKey);
|
|
10077
|
+
if (match3) return `tileflow-waterway-${match3[2]}${match3[1] ? "-intermittent" : ""}`;
|
|
10078
|
+
match3 = /^buildings\.(businessCorridor|flat)\.(fill|outline)$/u.exec(semanticKey);
|
|
10079
|
+
if (match3) {
|
|
10080
|
+
const base = match3[1] === "businessCorridor" ? "tileflow-business-corridor" : "tileflow-buildings-fill";
|
|
10081
|
+
return match3[2] === "fill" ? base : `${base}-outline`;
|
|
10082
|
+
}
|
|
10083
|
+
match3 = /^aeroways\.area\.(fill|outline)$/u.exec(semanticKey);
|
|
10084
|
+
if (match3) return match3[1] === "fill" ? "tileflow-aeroway-area" : "tileflow-aeroway-area-outline";
|
|
10085
|
+
match3 = /^aeroways\.(taxiway|runway)\.(shadow|casing|fill)$/u.exec(semanticKey);
|
|
10086
|
+
if (match3) return `tileflow-aeroway-${match3[1]}-${match3[2]}`;
|
|
10087
|
+
match3 = /^transit\.([A-Za-z0-9_-]+)(?:\.(tunnel|surface|bridge))?$/u.exec(semanticKey);
|
|
10088
|
+
if (match3) return `tileflow-transit-${match3[1]}${match3[2] ? `-${match3[2]}` : ""}`;
|
|
10089
|
+
match3 = /^boundaries\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
|
|
10090
|
+
if (match3) return `tileflow-boundary-${match3[1].replaceAll(".", "-")}`;
|
|
10091
|
+
match3 = /^labels\.places\.([^.]+)$/u.exec(semanticKey);
|
|
10092
|
+
if (match3) return `tileflow-label-place-${match3[1]}`;
|
|
10093
|
+
match3 = /^labels\.roads\.([^.]+)$/u.exec(semanticKey);
|
|
10094
|
+
if (match3) return `tileflow-label-road-${match3[1]}`;
|
|
10095
|
+
match3 = /^labels\.shields\.([^.]+)$/u.exec(semanticKey);
|
|
10096
|
+
if (match3) return `tileflow-label-road-shield-${match3[1]}`;
|
|
10097
|
+
match3 = /^labels\.water\.([^.]+)$/u.exec(semanticKey);
|
|
10098
|
+
if (match3) return `tileflow-label-water-${match3[1]}`;
|
|
10099
|
+
match3 = /^labels\.cohorts\.roads\.(major|local)$/u.exec(semanticKey);
|
|
10100
|
+
if (match3) return `tileflow-label-road-${match3[1]}`;
|
|
10101
|
+
match3 = /^labels\.cohorts\.roads\.cohort(\d+)$/u.exec(semanticKey);
|
|
10102
|
+
if (match3) return `tileflow-label-road-cohort-${match3[1]}`;
|
|
10103
|
+
match3 = /^landforms\.classes\.([^.]+)$/u.exec(semanticKey);
|
|
10104
|
+
if (match3) return `tileflow-landform-${match3[1]}`;
|
|
10105
|
+
match3 = /^water\.(bathymetryLandforms|bathymetryWaterNames)\.cohort(\d+)$/u.exec(semanticKey);
|
|
10106
|
+
if (match3) {
|
|
10107
|
+
const base = match3[1] === "bathymetryLandforms" ? "landforms" : "water-names";
|
|
10108
|
+
return `tileflow-bathymetry-${base}-cohort-${match3[2]}`;
|
|
10109
|
+
}
|
|
10110
|
+
match3 = /^poi\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
|
|
10111
|
+
if (match3) return `tileflow-poi-${match3[1].replaceAll(".", "-")}`;
|
|
9316
10112
|
const nautical2 = nauticalPhysicalLayerId(semanticKey);
|
|
9317
10113
|
if (nautical2) return nautical2;
|
|
9318
10114
|
throw new TileflowDomainIRError(
|
|
@@ -9329,6 +10125,7 @@ var exactPhysicalLayerIds = Object.freeze({
|
|
|
9329
10125
|
"labels.junctions": "tileflow-label-road-junction",
|
|
9330
10126
|
"land.background": "tileflow-background",
|
|
9331
10127
|
"land.globalLandcover": "tileflow-global-landcover",
|
|
10128
|
+
poi: "tileflow-poi",
|
|
9332
10129
|
"landforms.classes": "tileflow-landforms",
|
|
9333
10130
|
"roads.crossings": "tileflow-road-crossing",
|
|
9334
10131
|
"roads.oneWayMarkers": "tileflow-road-oneway",
|
|
@@ -9345,6 +10142,8 @@ var exactPhysicalLayerIds = Object.freeze({
|
|
|
9345
10142
|
"water.bathymetry": "tileflow-bathymetry",
|
|
9346
10143
|
"water.bathymetryContours": "tileflow-bathymetry-contours",
|
|
9347
10144
|
"water.bathymetryLabels": "tileflow-bathymetry-labels",
|
|
10145
|
+
"water.bathymetryLandforms": "tileflow-bathymetry-landforms",
|
|
10146
|
+
"water.bathymetryWaterNames": "tileflow-bathymetry-water-names",
|
|
9348
10147
|
"water.bathymetryRelief.color": "tileflow-bathymetry-color-relief",
|
|
9349
10148
|
"water.bathymetryRelief.hillshade": "tileflow-bathymetry-relief"
|
|
9350
10149
|
});
|
|
@@ -9369,15 +10168,15 @@ var nauticalPhysicalBases = Object.freeze({
|
|
|
9369
10168
|
function nauticalPhysicalLayerId(semanticKey) {
|
|
9370
10169
|
const direct = nauticalPhysicalBases[semanticKey];
|
|
9371
10170
|
if (direct) return direct;
|
|
9372
|
-
const
|
|
9373
|
-
if (!
|
|
9374
|
-
const base = nauticalPhysicalBases[
|
|
10171
|
+
const match3 = /^(nautical\.[A-Za-z0-9_.-]+)\.(fill|outline|marker|symbol)$/u.exec(semanticKey);
|
|
10172
|
+
if (!match3) return void 0;
|
|
10173
|
+
const base = nauticalPhysicalBases[match3[1]];
|
|
9375
10174
|
if (!base) return void 0;
|
|
9376
|
-
if (
|
|
9377
|
-
return `${base}-${
|
|
10175
|
+
if (match3[2] === "fill" || match3[2] === "symbol") return base;
|
|
10176
|
+
return `${base}-${match3[2]}`;
|
|
9378
10177
|
}
|
|
9379
10178
|
function publicMetadata(value) {
|
|
9380
|
-
const metadata = { ...
|
|
10179
|
+
const metadata = { ...asRecord4(value) };
|
|
9381
10180
|
delete metadata[tileflowCompilerProvenanceMetadataKey];
|
|
9382
10181
|
for (const key of Object.values(tileflowCompilerMetadataKeys)) delete metadata[key];
|
|
9383
10182
|
return Object.keys(metadata).length > 0 ? cloneJson20(metadata) : void 0;
|
|
@@ -9424,7 +10223,7 @@ function isSemanticSourceReference(value) {
|
|
|
9424
10223
|
function cloneJson20(value) {
|
|
9425
10224
|
return JSON.parse(JSON.stringify(value));
|
|
9426
10225
|
}
|
|
9427
|
-
function
|
|
10226
|
+
function asRecord4(value) {
|
|
9428
10227
|
return isRecord5(value) ? value : {};
|
|
9429
10228
|
}
|
|
9430
10229
|
function isRecord5(value) {
|
|
@@ -9898,8 +10697,8 @@ function applyRendererStyle(layer, renderer, style) {
|
|
|
9898
10697
|
if (!visibilityGroup) return result;
|
|
9899
10698
|
return {
|
|
9900
10699
|
...result,
|
|
9901
|
-
layout: { ...
|
|
9902
|
-
metadata: { ...
|
|
10700
|
+
layout: { ...asRecord5(result.layout), visibility: "none" },
|
|
10701
|
+
metadata: { ...asRecord5(result.metadata), "tileflow:3d-toggle": visibilityGroup }
|
|
9903
10702
|
};
|
|
9904
10703
|
}
|
|
9905
10704
|
function lowerSelector(selector, data) {
|
|
@@ -10381,7 +11180,7 @@ function compareCodeUnits6(left, right) {
|
|
|
10381
11180
|
function cloneJson21(value) {
|
|
10382
11181
|
return JSON.parse(JSON.stringify(value));
|
|
10383
11182
|
}
|
|
10384
|
-
function
|
|
11183
|
+
function asRecord5(value) {
|
|
10385
11184
|
return isRecord6(value) ? value : {};
|
|
10386
11185
|
}
|
|
10387
11186
|
function isRecord6(value) {
|
|
@@ -10579,6 +11378,19 @@ function isLoopbackHostname(hostname) {
|
|
|
10579
11378
|
return normalized === "localhost" || normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/u.test(normalized);
|
|
10580
11379
|
}
|
|
10581
11380
|
|
|
11381
|
+
// src/time-of-day-schema.ts
|
|
11382
|
+
function createTileflowTimeOfDaySchema(operations, themeName) {
|
|
11383
|
+
return operations.record(
|
|
11384
|
+
themeName,
|
|
11385
|
+
operations.object({
|
|
11386
|
+
day: operations.optional(themeName),
|
|
11387
|
+
dawn: operations.optional(themeName),
|
|
11388
|
+
dusk: operations.optional(themeName),
|
|
11389
|
+
night: operations.optional(themeName)
|
|
11390
|
+
})
|
|
11391
|
+
);
|
|
11392
|
+
}
|
|
11393
|
+
|
|
10582
11394
|
// src/resolved-map-schema.ts
|
|
10583
11395
|
var TileflowResolvedMapValidationError = class extends Error {
|
|
10584
11396
|
code = "CONFIG_INVALID";
|
|
@@ -10726,7 +11538,7 @@ function validateExpressionFieldNames(value, context, path) {
|
|
|
10726
11538
|
}
|
|
10727
11539
|
if (!value || typeof value !== "object") return;
|
|
10728
11540
|
const candidate = value;
|
|
10729
|
-
if (candidate.kind === "tileflow-data-field" && (typeof candidate.name !== "string" || !
|
|
11541
|
+
if (candidate.kind === "tileflow-data-field" && (typeof candidate.name !== "string" || !tileflowSemanticExpressionFieldNames.some((name) => name === candidate.name))) {
|
|
10730
11542
|
context.addIssue({
|
|
10731
11543
|
code: "custom",
|
|
10732
11544
|
message: "Expected a registered semantic field name.",
|
|
@@ -10880,12 +11692,12 @@ var hexColorSchema = z5.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a
|
|
|
10880
11692
|
message: "Expected a hex color like #F6F7F3 or #F6F7F3FF"
|
|
10881
11693
|
});
|
|
10882
11694
|
var rgbColorSchema = z5.string().refine((value) => {
|
|
10883
|
-
const
|
|
11695
|
+
const match3 = value.match(
|
|
10884
11696
|
/^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)(?:\s*,\s*(\d+(?:\.\d+)?))?\s*\)$/iu
|
|
10885
11697
|
);
|
|
10886
|
-
if (!
|
|
10887
|
-
const channels =
|
|
10888
|
-
const alpha2 = Number(
|
|
11698
|
+
if (!match3) return false;
|
|
11699
|
+
const channels = match3.slice(1, 4).map(Number);
|
|
11700
|
+
const alpha2 = Number(match3[4] ?? 1);
|
|
10889
11701
|
return channels.every((channel) => channel >= 0 && channel <= 255) && alpha2 >= 0 && alpha2 <= 1;
|
|
10890
11702
|
}, "Expected a Tileflow hex, rgb(), or rgba() color");
|
|
10891
11703
|
var terrainColorLiteralSchema = z5.union([hexColorSchema, rgbColorSchema]);
|
|
@@ -11162,9 +11974,7 @@ var symbolStyleSchema = z5.object({
|
|
|
11162
11974
|
text: textStyleSchema.optional()
|
|
11163
11975
|
}).strict();
|
|
11164
11976
|
var markerSymbolStyleSchema = symbolStyleSchema.extend({ marker: circleStyleSchema.optional() }).strict();
|
|
11165
|
-
var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).
|
|
11166
|
-
density: z5.union([z5.literal(1), z5.literal(2), z5.literal(3), z5.literal(4), z5.literal(5)]).optional()
|
|
11167
|
-
}).strict();
|
|
11977
|
+
var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).strict();
|
|
11168
11978
|
var renderScalarSchema = z5.union([z5.boolean(), z5.number().finite(), z5.string()]);
|
|
11169
11979
|
var renderTargetSchema = z5.string().regex(tileflowSemanticTargetPattern, "Expected a semantic target");
|
|
11170
11980
|
var renderStackOperationNameSchema = z5.string().regex(
|
|
@@ -11397,6 +12207,8 @@ var waterModuleSchema = z5.object({
|
|
|
11397
12207
|
bathymetry: fillStyleSchema.optional(),
|
|
11398
12208
|
bathymetryContours: lineStyleSchema.optional(),
|
|
11399
12209
|
bathymetryLabels: symbolStyleSchema.optional(),
|
|
12210
|
+
bathymetryLandforms: symbolStyleSchema.optional(),
|
|
12211
|
+
bathymetryWaterNames: symbolStyleSchema.optional(),
|
|
11400
12212
|
bodies: areaStyleSchema.optional(),
|
|
11401
12213
|
enabled: z5.boolean().optional(),
|
|
11402
12214
|
intermittent: z5.object({ bodies: areaStyleSchema.optional(), waterways: lineStyleSchema.optional() }).strict().optional(),
|
|
@@ -11408,6 +12220,17 @@ var waterModuleSchema = z5.object({
|
|
|
11408
12220
|
stream: lineStyleSchema.optional()
|
|
11409
12221
|
}).strict().optional()
|
|
11410
12222
|
}).strict();
|
|
12223
|
+
function boundedThemeNumberSchema(min, max) {
|
|
12224
|
+
return z5.union([
|
|
12225
|
+
z5.number().finite().min(min).max(max),
|
|
12226
|
+
themeNumberReferenceSchema,
|
|
12227
|
+
z5.object({
|
|
12228
|
+
kind: z5.literal("theme-fixed"),
|
|
12229
|
+
reason: z5.string().trim().min(1),
|
|
12230
|
+
value: z5.number().finite().min(min).max(max)
|
|
12231
|
+
}).strict()
|
|
12232
|
+
]);
|
|
12233
|
+
}
|
|
11411
12234
|
var buildingsModuleSchema = z5.object({
|
|
11412
12235
|
type: z5.literal("buildings"),
|
|
11413
12236
|
businessCorridor: areaStyleSchema.optional(),
|
|
@@ -11415,7 +12238,46 @@ var buildingsModuleSchema = z5.object({
|
|
|
11415
12238
|
extrusion: extrusionStyleSchema.optional(),
|
|
11416
12239
|
flat: areaStyleSchema.optional(),
|
|
11417
12240
|
mode: z5.enum(["3d", "flat"]).optional(),
|
|
11418
|
-
renderStack: renderStackSchema.optional()
|
|
12241
|
+
renderStack: renderStackSchema.optional(),
|
|
12242
|
+
threeDimensional: z5.object({
|
|
12243
|
+
lighting: z5.enum(["style", "sun"]).optional(),
|
|
12244
|
+
colorVariation: boundedThemeNumberSchema(0, 1).optional(),
|
|
12245
|
+
edges: boundedThemeNumberSchema(0, 1).optional(),
|
|
12246
|
+
edgeColor: themeColorValueSchema.optional(),
|
|
12247
|
+
nightLight: boundedThemeNumberSchema(0, 2).optional(),
|
|
12248
|
+
occlusion: z5.boolean().optional(),
|
|
12249
|
+
shadows: z5.boolean().optional(),
|
|
12250
|
+
windows: z5.boolean().optional(),
|
|
12251
|
+
models: z5.array(
|
|
12252
|
+
z5.object({
|
|
12253
|
+
model: z5.string().max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/u),
|
|
12254
|
+
at: z5.tuple([z5.number().min(-180).max(180), z5.number().min(-85).max(85)]),
|
|
12255
|
+
heading: z5.number().finite().optional(),
|
|
12256
|
+
url: z5.url().max(2048).refine((value) => new URL(value).protocol === "https:", {
|
|
12257
|
+
message: "A model served elsewhere has an HTTPS address."
|
|
12258
|
+
}).optional()
|
|
12259
|
+
}).strict()
|
|
12260
|
+
).max(256).optional(),
|
|
12261
|
+
modelColors: z5.object({
|
|
12262
|
+
surface: themeColorValueSchema.optional(),
|
|
12263
|
+
secondary: themeColorValueSchema.optional(),
|
|
12264
|
+
glass: themeColorValueSchema.optional(),
|
|
12265
|
+
accent: themeColorValueSchema.optional(),
|
|
12266
|
+
roof: themeColorValueSchema.optional()
|
|
12267
|
+
}).strict().optional(),
|
|
12268
|
+
landmarks: z5.union([
|
|
12269
|
+
z5.boolean(),
|
|
12270
|
+
z5.object({
|
|
12271
|
+
url: z5.url().max(2048).refine(
|
|
12272
|
+
(value) => {
|
|
12273
|
+
const url = new URL(value);
|
|
12274
|
+
return url.protocol === "https:" || url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
12275
|
+
},
|
|
12276
|
+
{ message: "A landmarks tileset has an HTTPS address, or a local one." }
|
|
12277
|
+
)
|
|
12278
|
+
}).strict()
|
|
12279
|
+
]).optional()
|
|
12280
|
+
}).strict().optional()
|
|
11419
12281
|
}).strict();
|
|
11420
12282
|
var addressesModuleSchema = z5.object({
|
|
11421
12283
|
type: z5.literal("addresses"),
|
|
@@ -11528,6 +12390,12 @@ var roadsModuleSchema = z5.object({
|
|
|
11528
12390
|
pattern: fillStyleSchema.optional(),
|
|
11529
12391
|
surface: fillStyleSchema.optional()
|
|
11530
12392
|
}).strict().optional(),
|
|
12393
|
+
streetLights: z5.object({
|
|
12394
|
+
color: themeColorValueSchema.optional(),
|
|
12395
|
+
enabled: z5.boolean().optional(),
|
|
12396
|
+
estimate: z5.enum(["lit", "streets", "none"]).optional(),
|
|
12397
|
+
intensity: boundedThemeNumberSchema(0, 2).optional()
|
|
12398
|
+
}).strict().optional(),
|
|
11531
12399
|
structures: roadStructureMapSchema.optional(),
|
|
11532
12400
|
weight: z5.enum(["thin", "regular", "bold"]).optional(),
|
|
11533
12401
|
widthScale: z5.partialRecord(roadClassSchema, themeNumberValueSchema).optional()
|
|
@@ -11587,7 +12455,10 @@ var poiModuleSchema = z5.object({
|
|
|
11587
12455
|
minZoom: zoomNumberSchema.optional(),
|
|
11588
12456
|
placement: z5.object({
|
|
11589
12457
|
coupleIconAndLabel: z5.boolean().optional(),
|
|
12458
|
+
iconOnlyTypes: z5.array(z5.string().regex(/^[a-z0-9]+(?:_[a-z0-9]+)*$/u, "Expected a World POI type")).max(64).optional(),
|
|
11590
12459
|
iconPadding: z5.number().finite().min(0).optional(),
|
|
12460
|
+
order: z5.enum(["categories", "importance"]).optional(),
|
|
12461
|
+
prominentRank: z5.number().int().min(0).max(5).optional(),
|
|
11591
12462
|
textPadding: z5.number().finite().min(0).optional()
|
|
11592
12463
|
}).strict().optional(),
|
|
11593
12464
|
renderStack: renderStackSchema.optional(),
|
|
@@ -11616,6 +12487,16 @@ var nauticalModuleSchema = z5.object({
|
|
|
11616
12487
|
wreckAreas: areaStyleSchema.optional(),
|
|
11617
12488
|
wrecks: markerSymbolStyleSchema.optional()
|
|
11618
12489
|
}).strict();
|
|
12490
|
+
var treeFormMixSchema = z5.object({
|
|
12491
|
+
round: z5.number().finite().min(0).optional(),
|
|
12492
|
+
open: z5.number().finite().min(0).optional(),
|
|
12493
|
+
tall: z5.number().finite().min(0).optional(),
|
|
12494
|
+
conifer: z5.number().finite().min(0).optional(),
|
|
12495
|
+
columnar: z5.number().finite().min(0).optional(),
|
|
12496
|
+
palm: z5.number().finite().min(0).optional()
|
|
12497
|
+
}).strict().refine((mix2) => Object.values(mix2).some((weight) => (weight ?? 0) > 0), {
|
|
12498
|
+
message: "Expected at least one tree form with a weight above 0"
|
|
12499
|
+
});
|
|
11619
12500
|
var modulesSchema = z5.object({
|
|
11620
12501
|
addresses: addressesModuleSchema.optional(),
|
|
11621
12502
|
aeroways: aerowaysModuleSchema.optional(),
|
|
@@ -11632,12 +12513,47 @@ var modulesSchema = z5.object({
|
|
|
11632
12513
|
type: z5.literal("vegetation"),
|
|
11633
12514
|
enabled: z5.boolean().optional(),
|
|
11634
12515
|
flat: circleStyleSchema.optional(),
|
|
11635
|
-
mode: z5.enum(["3d", "flat"]).optional(),
|
|
12516
|
+
mode: z5.enum(["3d", "flat", "auto"]).optional(),
|
|
12517
|
+
fallback: z5.enum(["flat", "none"]).optional(),
|
|
12518
|
+
visible: z5.boolean().optional(),
|
|
11636
12519
|
renderStack: renderStackSchema.optional(),
|
|
11637
12520
|
threeDimensional: z5.object({
|
|
11638
12521
|
barkColor: themeColorValueSchema.optional(),
|
|
11639
12522
|
broadleafColors: z5.array(themeColorValueSchema).min(1).max(8).optional(),
|
|
11640
12523
|
coniferColors: z5.array(themeColorValueSchema).min(1).max(8).optional(),
|
|
12524
|
+
palmColors: z5.array(themeColorValueSchema).min(1).max(8).optional(),
|
|
12525
|
+
finish: z5.enum(["faceted", "smooth", "toon"]).optional(),
|
|
12526
|
+
edges: boundedThemeNumberSchema(0, 1).optional(),
|
|
12527
|
+
edgeColor: themeColorValueSchema.optional(),
|
|
12528
|
+
forms: z5.partialRecord(
|
|
12529
|
+
z5.enum(["round", "open", "tall", "conifer", "columnar", "palm"]),
|
|
12530
|
+
z5.object({
|
|
12531
|
+
crownScale: boundedThemeNumberSchema(0.1, 10).optional(),
|
|
12532
|
+
heightScale: boundedThemeNumberSchema(0.1, 10).optional(),
|
|
12533
|
+
models: z5.array(
|
|
12534
|
+
z5.string().max(64).regex(
|
|
12535
|
+
tileflowTreeModelIdPattern,
|
|
12536
|
+
"Expected a model id: its .glb file name in lowercase letters, digits and hyphens"
|
|
12537
|
+
)
|
|
12538
|
+
).min(1).max(4).refine((ids) => new Set(ids).size === ids.length, {
|
|
12539
|
+
message: "Expected each model once"
|
|
12540
|
+
}).optional()
|
|
12541
|
+
}).strict()
|
|
12542
|
+
).optional(),
|
|
12543
|
+
unknownForms: treeFormMixSchema.optional(),
|
|
12544
|
+
regions: z5.array(
|
|
12545
|
+
z5.object({
|
|
12546
|
+
bounds: z5.tuple([
|
|
12547
|
+
z5.number().finite().min(-180).max(180),
|
|
12548
|
+
z5.number().finite().min(-90).max(90),
|
|
12549
|
+
z5.number().finite().min(-180).max(180),
|
|
12550
|
+
z5.number().finite().min(-90).max(90)
|
|
12551
|
+
]).refine(([, south, , north]) => south <= north, {
|
|
12552
|
+
message: "Expected bounds as [west, south, east, north] with south below north"
|
|
12553
|
+
}),
|
|
12554
|
+
unknownForms: treeFormMixSchema
|
|
12555
|
+
}).strict()
|
|
12556
|
+
).max(16).optional(),
|
|
11641
12557
|
crownScale: z5.union([
|
|
11642
12558
|
z5.number().finite().positive().max(10),
|
|
11643
12559
|
themeNumberReferenceSchema,
|
|
@@ -11736,6 +12652,7 @@ var fieldBindingsSchema = z5.object({
|
|
|
11736
12652
|
markings: z5.string().trim().min(1),
|
|
11737
12653
|
minHeight: z5.string().trim().min(1),
|
|
11738
12654
|
minZoom: z5.string().trim().min(1),
|
|
12655
|
+
mode: z5.string().trim().min(1),
|
|
11739
12656
|
mtbScale: z5.string().trim().min(1),
|
|
11740
12657
|
name: z5.string().trim().min(1),
|
|
11741
12658
|
nameEnglish: z5.string().trim().min(1),
|
|
@@ -11839,6 +12756,32 @@ var bathymetryReliefSchema = z5.object({
|
|
|
11839
12756
|
});
|
|
11840
12757
|
}
|
|
11841
12758
|
});
|
|
12759
|
+
var bathymetryNameLayerSchema = z5.union([
|
|
12760
|
+
z5.boolean(),
|
|
12761
|
+
z5.object({
|
|
12762
|
+
zoomRanges: z5.array(z5.object({ minZoom: zoomNumberSchema, maxZoom: zoomNumberSchema }).strict()).min(1).max(tileflowBathymetryNameLayerLimits.maxZoomRanges).superRefine((ranges, context) => {
|
|
12763
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12764
|
+
for (const [index, range2] of ranges.entries()) {
|
|
12765
|
+
if (range2.minZoom >= range2.maxZoom) {
|
|
12766
|
+
context.addIssue({
|
|
12767
|
+
code: "custom",
|
|
12768
|
+
message: "Expected minZoom < maxZoom",
|
|
12769
|
+
path: [index, "maxZoom"]
|
|
12770
|
+
});
|
|
12771
|
+
}
|
|
12772
|
+
const key = `${range2.minZoom}/${range2.maxZoom}`;
|
|
12773
|
+
if (seen.has(key)) {
|
|
12774
|
+
context.addIssue({
|
|
12775
|
+
code: "custom",
|
|
12776
|
+
message: "Expected unique nominal zoom ranges",
|
|
12777
|
+
path: [index]
|
|
12778
|
+
});
|
|
12779
|
+
}
|
|
12780
|
+
seen.add(key);
|
|
12781
|
+
}
|
|
12782
|
+
})
|
|
12783
|
+
}).strict()
|
|
12784
|
+
]);
|
|
11842
12785
|
var bathymetryConfigSchema = z5.object({
|
|
11843
12786
|
...marineSourceSchema.shape,
|
|
11844
12787
|
bands: z5.union([z5.literal(false), fillStyleSchema]).optional(),
|
|
@@ -11846,7 +12789,12 @@ var bathymetryConfigSchema = z5.object({
|
|
|
11846
12789
|
display: z5.enum(["bands", "relief", "hybrid"]).optional(),
|
|
11847
12790
|
labels: z5.union([z5.literal(false), symbolStyleSchema]).optional(),
|
|
11848
12791
|
relief: z5.union([z5.literal(false), bathymetryReliefSchema]).optional(),
|
|
11849
|
-
type: z5.literal("bathymetry")
|
|
12792
|
+
type: z5.literal("bathymetry"),
|
|
12793
|
+
vectorLayers: z5.object({
|
|
12794
|
+
contours: z5.boolean().optional(),
|
|
12795
|
+
landforms: bathymetryNameLayerSchema.optional(),
|
|
12796
|
+
waterNames: bathymetryNameLayerSchema.optional()
|
|
12797
|
+
}).strict().optional()
|
|
11850
12798
|
}).strict();
|
|
11851
12799
|
var marineSchema = z5.union([
|
|
11852
12800
|
z5.enum(["none", "bathymetry", "nautical", "chart"]),
|
|
@@ -11970,6 +12918,7 @@ var iconDirectoriesSchema = z5.array(
|
|
|
11970
12918
|
}
|
|
11971
12919
|
});
|
|
11972
12920
|
var fontDirectoriesSchema = z5.array(assetDirectorySchema).max(16);
|
|
12921
|
+
var modelDirectoriesSchema = z5.array(assetDirectorySchema).max(16);
|
|
11973
12922
|
var fontStacksSchema = z5.array(
|
|
11974
12923
|
z5.string().min(1).max(200).refine(
|
|
11975
12924
|
(value) => value === value.trim() && value === value.normalize("NFC") && !/[\p{Cc}\\/]/u.test(value),
|
|
@@ -12191,6 +13140,7 @@ var resolvedTileflowMapSchema = z5.object({
|
|
|
12191
13140
|
icons: iconDirectoriesSchema.optional(),
|
|
12192
13141
|
id: tileflowMapIdSchema,
|
|
12193
13142
|
marine: marineSchema.optional(),
|
|
13143
|
+
models: modelDirectoriesSchema.optional(),
|
|
12194
13144
|
modules: modulesSchema.optional(),
|
|
12195
13145
|
name: z5.string().trim().min(1),
|
|
12196
13146
|
overlays: overlaysSchema.optional(),
|
|
@@ -12199,6 +13149,10 @@ var resolvedTileflowMapSchema = z5.object({
|
|
|
12199
13149
|
systemThemes: systemThemesSchema.optional(),
|
|
12200
13150
|
terrain: terrainSchema.optional(),
|
|
12201
13151
|
themes: themesSchema,
|
|
13152
|
+
timeOfDay: createTileflowTimeOfDaySchema(
|
|
13153
|
+
classicManifestSchemaOperations,
|
|
13154
|
+
tileflowThemeNameSchema
|
|
13155
|
+
).optional(),
|
|
12202
13156
|
version: z5.number().int().positive(),
|
|
12203
13157
|
view: viewSchema.optional()
|
|
12204
13158
|
}).strict().superRefine((map, context) => {
|
|
@@ -12223,6 +13177,15 @@ var resolvedTileflowMapSchema = z5.object({
|
|
|
12223
13177
|
path: ["defaultTheme"]
|
|
12224
13178
|
});
|
|
12225
13179
|
}
|
|
13180
|
+
if (map.timeOfDay) {
|
|
13181
|
+
for (const issue of validateTileflowTimeOfDayVariants(map.timeOfDay, map.themes)) {
|
|
13182
|
+
context.addIssue({
|
|
13183
|
+
code: "custom",
|
|
13184
|
+
message: issue.message,
|
|
13185
|
+
path: ["timeOfDay", ...issue.path]
|
|
13186
|
+
});
|
|
13187
|
+
}
|
|
13188
|
+
}
|
|
12226
13189
|
const themeEntries = Object.entries(map.themes).sort(
|
|
12227
13190
|
([left], [right]) => left < right ? -1 : left > right ? 1 : 0
|
|
12228
13191
|
);
|
|
@@ -12445,6 +13408,23 @@ function tileflowRouteMetadata(inks) {
|
|
|
12445
13408
|
return Object.freeze({ version: 1, ...inks });
|
|
12446
13409
|
}
|
|
12447
13410
|
|
|
13411
|
+
// src/street-lights.ts
|
|
13412
|
+
var tileflowStreetLightsMetadataKey = "tileflow:street-lights";
|
|
13413
|
+
var tileflowDefaultStreetLightsDesign = Object.freeze({
|
|
13414
|
+
source: "tileflow",
|
|
13415
|
+
layers: Object.freeze({
|
|
13416
|
+
streetFurniture: "street_furniture",
|
|
13417
|
+
transportation: "transportation",
|
|
13418
|
+
sidewalk: "sidewalk"
|
|
13419
|
+
}),
|
|
13420
|
+
estimate: "lit",
|
|
13421
|
+
color: "#ffcf8f",
|
|
13422
|
+
intensity: 1
|
|
13423
|
+
});
|
|
13424
|
+
function tileflowStreetLightsMetadata(design) {
|
|
13425
|
+
return { version: 1, ...design };
|
|
13426
|
+
}
|
|
13427
|
+
|
|
12448
13428
|
// src/terrain/index.ts
|
|
12449
13429
|
function resolveTerrain(terrain, apiBaseUrl) {
|
|
12450
13430
|
if (!terrain || terrain === "none") return void 0;
|
|
@@ -12623,7 +13603,7 @@ function terrainContribution(target, localOrder, layer) {
|
|
|
12623
13603
|
};
|
|
12624
13604
|
}
|
|
12625
13605
|
function applyLayerRange2(layer, range2) {
|
|
12626
|
-
const layout = { ...
|
|
13606
|
+
const layout = { ...asRecord6(layer.layout) };
|
|
12627
13607
|
if (range2.visible !== void 0) layout.visibility = range2.visible ? "visible" : "none";
|
|
12628
13608
|
return {
|
|
12629
13609
|
...layer,
|
|
@@ -12632,10 +13612,13 @@ function applyLayerRange2(layer, range2) {
|
|
|
12632
13612
|
...Object.keys(layout).length === 0 ? {} : { layout }
|
|
12633
13613
|
};
|
|
12634
13614
|
}
|
|
12635
|
-
function
|
|
13615
|
+
function asRecord6(value) {
|
|
12636
13616
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12637
13617
|
}
|
|
12638
13618
|
|
|
13619
|
+
// src/vegetation-display.ts
|
|
13620
|
+
var tileflowVegetationDisplayMetadataKey = "tileflow:vegetation-display";
|
|
13621
|
+
|
|
12639
13622
|
// src/cartography/compilation-report.ts
|
|
12640
13623
|
var tileflowCompilationReportSchemaVersion = 1;
|
|
12641
13624
|
var tileflowCompilationPhases = Object.freeze([
|
|
@@ -13007,14 +13990,16 @@ function defaultPaint(image, key, names, appearances, ids) {
|
|
|
13007
13990
|
|
|
13008
13991
|
// src/cartography/interaction-manifest.ts
|
|
13009
13992
|
var tileflowInteractionManifestMetadataKey = "tileflow:interaction-manifest";
|
|
13010
|
-
var tileflowInteractionManifestVersion =
|
|
13993
|
+
var tileflowInteractionManifestVersion = 3;
|
|
13011
13994
|
function createTileflowInteractionManifest(layers, fields) {
|
|
13012
13995
|
const poiLayers = layers.flatMap((layer, priority) => {
|
|
13013
13996
|
const id2 = typeof layer.id === "string" ? layer.id : void 0;
|
|
13014
13997
|
const source = typeof layer.source === "string" ? layer.source : void 0;
|
|
13015
13998
|
const sourceLayer = typeof layer["source-layer"] === "string" ? layer["source-layer"] : void 0;
|
|
13016
13999
|
const target = semanticTarget(layer);
|
|
13017
|
-
if (!id2 || !source || !sourceLayer || !target?.startsWith("poi."))
|
|
14000
|
+
if (!id2 || !source || !sourceLayer || target !== "poi" && !target?.startsWith("poi.")) {
|
|
14001
|
+
return [];
|
|
14002
|
+
}
|
|
13018
14003
|
const parsed = parsePoiTarget(target);
|
|
13019
14004
|
if (!parsed) return [];
|
|
13020
14005
|
return [
|
|
@@ -13062,7 +14047,7 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
|
|
|
13062
14047
|
);
|
|
13063
14048
|
}
|
|
13064
14049
|
for (const layer of poiLayers) {
|
|
13065
|
-
if (!
|
|
14050
|
+
if (!isSafeArtifactName(layer.layerId) || !isSafeArtifactName(layer.source) || !isSafeArtifactName(layer.sourceLayer)) {
|
|
13066
14051
|
throw new Error("Tileflow interaction manifest contains an invalid physical POI lookup.");
|
|
13067
14052
|
}
|
|
13068
14053
|
const finalized = layersById.get(layer.layerId);
|
|
@@ -13085,15 +14070,16 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
|
|
|
13085
14070
|
}
|
|
13086
14071
|
function parsePoiTarget(target) {
|
|
13087
14072
|
const segments = target.split(".");
|
|
13088
|
-
if (segments[0] !== "poi" || segments.length
|
|
13089
|
-
const
|
|
13090
|
-
if (
|
|
13091
|
-
|
|
13092
|
-
if (
|
|
13093
|
-
if (
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
14073
|
+
if (segments[0] !== "poi" || segments.length > 3) return void 0;
|
|
14074
|
+
const [, first, second] = segments;
|
|
14075
|
+
if (first === void 0) return { representation: "combined" };
|
|
14076
|
+
if (segments.length === 2 && isRepresentationPart(first)) return { representation: first };
|
|
14077
|
+
if (first !== "prominent" && !isTileflowPoiCategory(first)) return void 0;
|
|
14078
|
+
if (second === void 0) return { representation: "combined" };
|
|
14079
|
+
return isRepresentationPart(second) ? { representation: second } : void 0;
|
|
14080
|
+
}
|
|
14081
|
+
function isRepresentationPart(value) {
|
|
14082
|
+
return value === "icon" || value === "label" || value === "marker";
|
|
13097
14083
|
}
|
|
13098
14084
|
function isTileflowPoiCategory(value) {
|
|
13099
14085
|
return typeof value === "string" && tileflowPoiCategories.includes(value);
|
|
@@ -13827,7 +14813,7 @@ function conditionalExpression(entries, fallback) {
|
|
|
13827
14813
|
];
|
|
13828
14814
|
}
|
|
13829
14815
|
const classMatches = entries.map(({ condition }) => splitClassMatch(condition));
|
|
13830
|
-
if (classMatches.every((
|
|
14816
|
+
if (classMatches.every((match3) => match3 !== void 0) && allEqual(classMatches.map((match3) => match3?.field)) && allEqual(classMatches.map((match3) => match3?.remainder)) && classMatchLabelsAreDisjoint(classMatches.map((match3) => match3.labels))) {
|
|
13831
14817
|
return [
|
|
13832
14818
|
"match",
|
|
13833
14819
|
["get", classMatches[0].field],
|
|
@@ -13991,6 +14977,114 @@ function stableSerialize(value) {
|
|
|
13991
14977
|
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableSerialize(entry)}`).join(",")}}`;
|
|
13992
14978
|
}
|
|
13993
14979
|
|
|
14980
|
+
// src/cartography/scene-3d-metadata.ts
|
|
14981
|
+
var colourSources = [
|
|
14982
|
+
["tileflow-buildings-render-extrusion", "fill-extrusion-color"],
|
|
14983
|
+
["tileflow-buildings-3d", "fill-extrusion-color"],
|
|
14984
|
+
["tileflow-buildings-fill", "fill-color"]
|
|
14985
|
+
];
|
|
14986
|
+
function tileflowBuildings3DDesignOf(module, context, layers, buildingModels, tileflowLandmarks) {
|
|
14987
|
+
const config = isRecord8(module) ? module : {};
|
|
14988
|
+
if (config.enabled === false) return void 0;
|
|
14989
|
+
const style = config.threeDimensional ?? {};
|
|
14990
|
+
let color2;
|
|
14991
|
+
let verticalGradient = true;
|
|
14992
|
+
for (const [id2, property] of colourSources) {
|
|
14993
|
+
const value = layers.find((layer) => layer.id === id2)?.paint?.[property];
|
|
14994
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
14995
|
+
color2 = value;
|
|
14996
|
+
verticalGradient = layers.find((layer) => layer.id === id2)?.paint?.["fill-extrusion-vertical-gradient"] !== false;
|
|
14997
|
+
break;
|
|
14998
|
+
}
|
|
14999
|
+
}
|
|
15000
|
+
const number = (value, fallback) => {
|
|
15001
|
+
const resolved = value === void 0 ? void 0 : toMapLibreStyleValue(value);
|
|
15002
|
+
return typeof resolved === "number" ? resolved : fallback;
|
|
15003
|
+
};
|
|
15004
|
+
const edgeColor = style.edgeColor === void 0 ? void 0 : toMapLibreStyleValue(style.edgeColor);
|
|
15005
|
+
return {
|
|
15006
|
+
source: context.data.sourceId,
|
|
15007
|
+
layers: {
|
|
15008
|
+
building: context.data.schema.layers.building,
|
|
15009
|
+
...context.data.schema.layers.poi ? { places: context.data.schema.layers.poi } : {}
|
|
15010
|
+
},
|
|
15011
|
+
color: color2 ?? context.colors.buildings.generic,
|
|
15012
|
+
lighting: style.lighting === "sun" ? "sun" : "style",
|
|
15013
|
+
colorVariation: number(style.colorVariation, 0),
|
|
15014
|
+
verticalGradient,
|
|
15015
|
+
edges: number(style.edges, 0),
|
|
15016
|
+
...typeof edgeColor === "string" ? { edgeColor } : {},
|
|
15017
|
+
nightLight: number(style.nightLight, 0),
|
|
15018
|
+
windows: style.windows === true,
|
|
15019
|
+
shadows: style.shadows === true,
|
|
15020
|
+
occlusion: style.occlusion === true,
|
|
15021
|
+
...placedModels(style.models, buildingModels),
|
|
15022
|
+
...modelColours(style.modelColors),
|
|
15023
|
+
...landmarksOf(style.landmarks, tileflowLandmarks)
|
|
15024
|
+
};
|
|
15025
|
+
}
|
|
15026
|
+
function landmarksOf(value, tileflowLandmarks) {
|
|
15027
|
+
if (value === false) return {};
|
|
15028
|
+
if (isRecord8(value) && typeof value.url === "string") return { landmarks: { url: value.url } };
|
|
15029
|
+
return tileflowLandmarks ? { landmarks: { url: tileflowLandmarks } } : {};
|
|
15030
|
+
}
|
|
15031
|
+
function placedModels(value, served) {
|
|
15032
|
+
if (!Array.isArray(value) || value.length === 0) return {};
|
|
15033
|
+
const placements = value;
|
|
15034
|
+
const missing = [
|
|
15035
|
+
...new Set(
|
|
15036
|
+
placements.filter((entry) => !entry.url).map((entry) => entry.model).filter((id2) => !served?.[id2])
|
|
15037
|
+
)
|
|
15038
|
+
].sort();
|
|
15039
|
+
if (missing.length > 0)
|
|
15040
|
+
throw new Error(
|
|
15041
|
+
`The buildings module places missing 3D models: ${missing.join(", ")}. Add ${missing.map((id2) => `${id2}.glb`).join(
|
|
15042
|
+
", "
|
|
15043
|
+
)} to a map.models directory, with materials named surface, secondary, glass, accent or roof, and run the Node build so the directories are prepared.`
|
|
15044
|
+
);
|
|
15045
|
+
return {
|
|
15046
|
+
models: placements.map((entry) => ({
|
|
15047
|
+
model: entry.model,
|
|
15048
|
+
url: entry.url ?? served[entry.model],
|
|
15049
|
+
at: [entry.at[0], entry.at[1]],
|
|
15050
|
+
heading: ((entry.heading ?? 0) % 360 + 360) % 360
|
|
15051
|
+
}))
|
|
15052
|
+
};
|
|
15053
|
+
}
|
|
15054
|
+
function modelColours(value) {
|
|
15055
|
+
if (!isRecord8(value)) return {};
|
|
15056
|
+
const colours = {};
|
|
15057
|
+
for (const [part, colour] of Object.entries(value)) {
|
|
15058
|
+
const resolved = colour === void 0 ? void 0 : toMapLibreStyleValue(colour);
|
|
15059
|
+
if (typeof resolved === "string") colours[part] = resolved;
|
|
15060
|
+
}
|
|
15061
|
+
return Object.keys(colours).length > 0 ? { modelColors: colours } : {};
|
|
15062
|
+
}
|
|
15063
|
+
function tileflowStreetLightsDesignOf(module, context) {
|
|
15064
|
+
const config = isRecord8(module) ? module : {};
|
|
15065
|
+
const layers = context.data.schema.layers;
|
|
15066
|
+
const style = config.streetLights ?? {};
|
|
15067
|
+
if (config.enabled === false || style.enabled === false || !layers.streetFurniture)
|
|
15068
|
+
return void 0;
|
|
15069
|
+
const color2 = style.color === void 0 ? void 0 : toMapLibreStyleValue(style.color);
|
|
15070
|
+
const intensity = style.intensity === void 0 ? void 0 : toMapLibreStyleValue(style.intensity);
|
|
15071
|
+
const estimate = style.estimate;
|
|
15072
|
+
return {
|
|
15073
|
+
source: context.data.sourceId,
|
|
15074
|
+
layers: {
|
|
15075
|
+
streetFurniture: layers.streetFurniture,
|
|
15076
|
+
transportation: layers.road,
|
|
15077
|
+
...layers.sidewalk ? { sidewalk: layers.sidewalk } : {}
|
|
15078
|
+
},
|
|
15079
|
+
estimate: estimate === "streets" || estimate === "none" || estimate === "lit" ? estimate : "lit",
|
|
15080
|
+
color: typeof color2 === "string" ? color2 : tileflowDefaultStreetLightsDesign.color,
|
|
15081
|
+
intensity: typeof intensity === "number" ? intensity : 1
|
|
15082
|
+
};
|
|
15083
|
+
}
|
|
15084
|
+
function isRecord8(value) {
|
|
15085
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15086
|
+
}
|
|
15087
|
+
|
|
13994
15088
|
// src/cartography/semantic-compiler.ts
|
|
13995
15089
|
var tileflowSemanticCompilerIdentity = Object.freeze({
|
|
13996
15090
|
name: "tileflow-semantic",
|
|
@@ -14021,7 +15115,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14021
15115
|
suggestion,
|
|
14022
15116
|
...target ? { target } : {}
|
|
14023
15117
|
}));
|
|
14024
|
-
const selected = runCompilationPhase(
|
|
15118
|
+
const selected = runCompilationPhase(
|
|
15119
|
+
"theme",
|
|
15120
|
+
() => resolveThemeSelection(input, options.theme, options.timeOfDay)
|
|
15121
|
+
);
|
|
14025
15122
|
const resolvedTheme = runCompilationPhase("theme", () => resolveTileflowTheme(selected.theme));
|
|
14026
15123
|
const { overlays, themes: _themes, ...themeableConfig } = input;
|
|
14027
15124
|
const resolvedThemeConfig = runCompilationPhase(
|
|
@@ -14127,8 +15224,19 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14127
15224
|
"domains",
|
|
14128
15225
|
() => compileSemanticDomains(modules, context)
|
|
14129
15226
|
);
|
|
15227
|
+
const vegetation3D = runCompilationPhase(
|
|
15228
|
+
"domains",
|
|
15229
|
+
() => withPreparedTreeModels(
|
|
15230
|
+
tileflowVegetationDescription(
|
|
15231
|
+
modules.vegetation,
|
|
15232
|
+
context
|
|
15233
|
+
),
|
|
15234
|
+
config,
|
|
15235
|
+
options.preparedAssets
|
|
15236
|
+
)
|
|
15237
|
+
);
|
|
14130
15238
|
const renderStackModules = Object.values(modules).filter(
|
|
14131
|
-
(module) =>
|
|
15239
|
+
(module) => isRecord9(module) && module.enabled !== false && "renderStack" in module && isRecord9(module.renderStack)
|
|
14132
15240
|
);
|
|
14133
15241
|
const renderOperations = runCompilationPhase(
|
|
14134
15242
|
"render-stack",
|
|
@@ -14288,6 +15396,17 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14288
15396
|
() => createTileflowOverlayPlacementManifest(plannedLayers)
|
|
14289
15397
|
);
|
|
14290
15398
|
const layers = runCompilationPhase("finalization", () => finalizeTileflowLayers(plannedLayers));
|
|
15399
|
+
const buildings3D = tileflowBuildings3DDesignOf(
|
|
15400
|
+
modules.buildings,
|
|
15401
|
+
context,
|
|
15402
|
+
layers,
|
|
15403
|
+
options.preparedAssets?.buildingModels,
|
|
15404
|
+
data.kind === "tileflow-world" ? `${apiBaseUrl}/landmarks/tiles.json` : void 0
|
|
15405
|
+
);
|
|
15406
|
+
const streetLights = tileflowStreetLightsDesignOf(
|
|
15407
|
+
modules.roads,
|
|
15408
|
+
context
|
|
15409
|
+
);
|
|
14291
15410
|
runCompilationPhase(
|
|
14292
15411
|
"finalization",
|
|
14293
15412
|
() => assertTileflowInteractionManifestLayers(interactionManifest, layers)
|
|
@@ -14335,6 +15454,24 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14335
15454
|
layers
|
|
14336
15455
|
})
|
|
14337
15456
|
);
|
|
15457
|
+
const flatVegetationLayers = layers.filter((layer) => {
|
|
15458
|
+
const metadata = layer.metadata;
|
|
15459
|
+
return metadata?.["tileflow:vegetation-mode"] !== void 0 || metadata?.["tileflow:domain"] === "vegetation";
|
|
15460
|
+
});
|
|
15461
|
+
const vegetationDisplay = flatVegetationLayers.length || vegetation3D ? {
|
|
15462
|
+
version: 1,
|
|
15463
|
+
mode: modules.vegetation?.mode ?? "3d",
|
|
15464
|
+
fallback: modules.vegetation?.fallback ?? "flat",
|
|
15465
|
+
visible: modules.vegetation?.visible ?? true,
|
|
15466
|
+
flatLayers: flatVegetationLayers.map((layer) => ({
|
|
15467
|
+
id: String(layer.id),
|
|
15468
|
+
visible: layer.layout?.visibility !== "none"
|
|
15469
|
+
}))
|
|
15470
|
+
} : void 0;
|
|
15471
|
+
if (vegetationDisplay && (!vegetationDisplay.visible || vegetationDisplay.mode === "3d" && vegetationDisplay.fallback === "none")) {
|
|
15472
|
+
for (const layer of flatVegetationLayers)
|
|
15473
|
+
layer.layout = { ...layer.layout, visibility: "none" };
|
|
15474
|
+
}
|
|
14338
15475
|
const atmosphere = resolveTileflowAtmosphere(config.atmosphere);
|
|
14339
15476
|
const style = {
|
|
14340
15477
|
...atmosphere ? { sky: compileTileflowSky(atmosphere) } : {},
|
|
@@ -14360,13 +15497,31 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14360
15497
|
"tileflow:colorScheme": resolvedTheme.colorScheme,
|
|
14361
15498
|
[tileflowRouteMetadataKey]: tileflowRouteMetadata(resolveTileflowRouteInks(resolvedTheme)),
|
|
14362
15499
|
...resolvedTheme.sun ? { [tileflowSunMetadataKey]: tileflowSunMetadata(resolvedTheme.sun) } : {},
|
|
15500
|
+
...buildings3D ? {
|
|
15501
|
+
[tileflowBuildingsMetadataKey]: tileflowBuildingsMetadata(
|
|
15502
|
+
bindSemanticReferences(buildings3D, semanticData)
|
|
15503
|
+
)
|
|
15504
|
+
} : {},
|
|
15505
|
+
...streetLights ? {
|
|
15506
|
+
[tileflowStreetLightsMetadataKey]: tileflowStreetLightsMetadata(
|
|
15507
|
+
bindSemanticReferences(streetLights, semanticData)
|
|
15508
|
+
)
|
|
15509
|
+
} : {},
|
|
15510
|
+
...vegetation3D ? {
|
|
15511
|
+
[tileflowVegetationMetadataKey]: tileflowVegetationMetadata({
|
|
15512
|
+
...bindSemanticReferences(vegetation3D, semanticData),
|
|
15513
|
+
// The layers that draw the trees flat: the module's own and its render passes.
|
|
15514
|
+
flatLayers: flatVegetationLayers.map((layer) => String(layer.id))
|
|
15515
|
+
})
|
|
15516
|
+
} : {},
|
|
15517
|
+
...vegetationDisplay ? { [tileflowVegetationDisplayMetadataKey]: vegetationDisplay } : {},
|
|
14363
15518
|
"tileflow:data": data.identity,
|
|
14364
15519
|
"tileflow:sources": sourceIdentities,
|
|
14365
15520
|
...Object.keys(loweredOverlays.identities).length > 0 ? { "tileflow:overlays": loweredOverlays.identities } : {},
|
|
14366
15521
|
"tileflow:sourceRequirements": sourceRequirements,
|
|
14367
15522
|
...interactionManifest ? { [tileflowInteractionManifestMetadataKey]: interactionManifest } : {},
|
|
14368
15523
|
[tileflowOverlayPlacementManifestMetadataKey]: overlayPlacementManifest,
|
|
14369
|
-
"tileflow:modules": Object.entries(modules).filter(([, module]) => !
|
|
15524
|
+
"tileflow:modules": Object.entries(modules).filter(([, module]) => !isRecord9(module) || module.enabled !== false).map(([name]) => name).sort(),
|
|
14370
15525
|
...config.view ? { "tileflow:view": config.view } : {}
|
|
14371
15526
|
}
|
|
14372
15527
|
};
|
|
@@ -14418,7 +15573,7 @@ function finalizeTileflowLayers(input) {
|
|
|
14418
15573
|
if (typeof minimum2 === "number" && typeof maximum2 === "number" && minimum2 > maximum2) {
|
|
14419
15574
|
throw new Error(`Compiled Tileflow layer ${id2} requires minzoom <= maxzoom.`);
|
|
14420
15575
|
}
|
|
14421
|
-
const metadata =
|
|
15576
|
+
const metadata = isRecord9(layer.metadata) ? { ...layer.metadata } : void 0;
|
|
14422
15577
|
if (metadata) {
|
|
14423
15578
|
const owner = metadata[tileflowCompilerMetadataKeys.owner];
|
|
14424
15579
|
delete metadata[tileflowCompilerProvenanceMetadataKey];
|
|
@@ -14452,13 +15607,32 @@ function assertMapLibreStyle(style, mapId) {
|
|
|
14452
15607
|
}
|
|
14453
15608
|
);
|
|
14454
15609
|
}
|
|
14455
|
-
function
|
|
15610
|
+
function isRecord9(value) {
|
|
14456
15611
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
14457
15612
|
}
|
|
14458
15613
|
function resolveGlyphs(config) {
|
|
14459
15614
|
if (config.fonts !== void 0) return void 0;
|
|
14460
15615
|
return config.glyphs?.url;
|
|
14461
15616
|
}
|
|
15617
|
+
function withPreparedTreeModels(vegetation2, config, prepared) {
|
|
15618
|
+
if (!vegetation2) return void 0;
|
|
15619
|
+
const referenced = [
|
|
15620
|
+
...new Set(Object.values(vegetation2.forms).flatMap((form) => form?.models ?? []))
|
|
15621
|
+
].sort();
|
|
15622
|
+
if (referenced.length === 0) return vegetation2;
|
|
15623
|
+
const available = prepared?.models ?? {};
|
|
15624
|
+
const missing = referenced.filter((id2) => !Object.hasOwn(available, id2));
|
|
15625
|
+
if (missing.length > 0) {
|
|
15626
|
+
const authoring = config.models?.length ? `Add ${missing.map((id2) => `${id2}.glb`).join(", ")} to a map.models directory, or run the Node build so the directories are prepared.` : "Declare map.models with directories containing those .glb files.";
|
|
15627
|
+
throw new Error(
|
|
15628
|
+
`Tileflow map "${config.id}" draws missing 3D models: ${missing.join(", ")}. ${authoring}`
|
|
15629
|
+
);
|
|
15630
|
+
}
|
|
15631
|
+
return {
|
|
15632
|
+
...vegetation2,
|
|
15633
|
+
models: Object.fromEntries(referenced.map((id2) => [id2, available[id2]]))
|
|
15634
|
+
};
|
|
15635
|
+
}
|
|
14462
15636
|
function assertPreparedIconReferences(style, config, prepared) {
|
|
14463
15637
|
const references = collectStyleImageReferences(style);
|
|
14464
15638
|
if (references.size === 0) return;
|
|
@@ -14473,8 +15647,8 @@ function assertPreparedIconReferences(style, config, prepared) {
|
|
|
14473
15647
|
function collectStyleImageReferences(style) {
|
|
14474
15648
|
const result = /* @__PURE__ */ new Set();
|
|
14475
15649
|
for (const layer of style.layers) {
|
|
14476
|
-
const layout =
|
|
14477
|
-
const paint =
|
|
15650
|
+
const layout = isRecord9(layer.layout) ? layer.layout : {};
|
|
15651
|
+
const paint = isRecord9(layer.paint) ? layer.paint : {};
|
|
14478
15652
|
const layerId = typeof layer.id === "string" ? layer.id : "<unknown>";
|
|
14479
15653
|
for (const [property, value] of [
|
|
14480
15654
|
["icon-image", layout["icon-image"]],
|
|
@@ -14563,7 +15737,7 @@ function assertGlyphFontStacks(style, config) {
|
|
|
14563
15737
|
const declared = new Set(config.glyphs.fontStacks);
|
|
14564
15738
|
const missing = /* @__PURE__ */ new Set();
|
|
14565
15739
|
for (const layer of style.layers) {
|
|
14566
|
-
const layout =
|
|
15740
|
+
const layout = isRecord9(layer.layout) ? layer.layout : void 0;
|
|
14567
15741
|
const font = layout?.["text-font"];
|
|
14568
15742
|
if (!Array.isArray(font) || !font.every((entry) => typeof entry === "string")) continue;
|
|
14569
15743
|
const stack = font.join(",");
|
|
@@ -14579,7 +15753,7 @@ function assertGlyphFontStacks(style, config) {
|
|
|
14579
15753
|
function assertTextAssets(style, config) {
|
|
14580
15754
|
const textLayers = [];
|
|
14581
15755
|
for (const layer of style.layers) {
|
|
14582
|
-
const layout =
|
|
15756
|
+
const layout = isRecord9(layer.layout) ? layer.layout : void 0;
|
|
14583
15757
|
if (layout?.["text-field"] === void 0) continue;
|
|
14584
15758
|
textLayers.push(typeof layer.id === "string" ? layer.id : "<unknown>");
|
|
14585
15759
|
const font = layout["text-font"];
|
|
@@ -14592,7 +15766,7 @@ function assertTextAssets(style, config) {
|
|
|
14592
15766
|
if (textLayers.length === 0) return;
|
|
14593
15767
|
if (config.fonts !== void 0) {
|
|
14594
15768
|
const backed = style.layers.find((layer) => {
|
|
14595
|
-
const font =
|
|
15769
|
+
const font = isRecord9(layer.layout) ? layer.layout["text-font"] : void 0;
|
|
14596
15770
|
return Array.isArray(font) && font.length === 1 && typeof font[0] === "string" && parseTileflowLineBackgroundFontStack(font[0]) !== void 0;
|
|
14597
15771
|
});
|
|
14598
15772
|
if (backed) {
|
|
@@ -14618,7 +15792,7 @@ function runCompilationPhase(phase, operation) {
|
|
|
14618
15792
|
}
|
|
14619
15793
|
}
|
|
14620
15794
|
function withCompilationPhase(error, phase) {
|
|
14621
|
-
const record3 =
|
|
15795
|
+
const record3 = isRecord9(error) ? error : {};
|
|
14622
15796
|
if (typeof record3.phase === "string") return error;
|
|
14623
15797
|
if (error instanceof Error && Object.isExtensible(error)) {
|
|
14624
15798
|
Object.defineProperty(error, "phase", { configurable: true, enumerable: true, value: phase });
|
|
@@ -14721,12 +15895,24 @@ function createTileflowRuntimeManifestSchema(primitives, operations, identities
|
|
|
14721
15895
|
})
|
|
14722
15896
|
),
|
|
14723
15897
|
themes: operations.record(tileflowThemeNameSchema2, manifestThemeSchema),
|
|
15898
|
+
timeOfDay: operations.optional(
|
|
15899
|
+
createTileflowTimeOfDaySchema(operations, tileflowThemeNameSchema2)
|
|
15900
|
+
),
|
|
14724
15901
|
usageMode: operations.optional(operations.literal("session")),
|
|
14725
15902
|
view: operations.optional(viewSchema3),
|
|
14726
15903
|
worldGeneration: operations.optional(operations.literal("v1"))
|
|
14727
15904
|
}),
|
|
14728
15905
|
(entry, context) => {
|
|
14729
15906
|
const names = Object.keys(entry.themes);
|
|
15907
|
+
if (entry.timeOfDay) {
|
|
15908
|
+
for (const issue of validateTileflowTimeOfDayVariants(entry.timeOfDay, entry.themes)) {
|
|
15909
|
+
context.addIssue({
|
|
15910
|
+
code: "custom",
|
|
15911
|
+
message: issue.message,
|
|
15912
|
+
path: ["timeOfDay", ...issue.path]
|
|
15913
|
+
});
|
|
15914
|
+
}
|
|
15915
|
+
}
|
|
14730
15916
|
if (names.length === 0) {
|
|
14731
15917
|
context.addIssue({
|
|
14732
15918
|
code: "custom",
|
|
@@ -14780,10 +15966,23 @@ function createTileflowRuntimeManifestSchema(primitives, operations, identities
|
|
|
14780
15966
|
operations.object({
|
|
14781
15967
|
apiUrl: operations.optional(apiOriginSchema),
|
|
14782
15968
|
maps: operations.record(tileflowPortableIdSchema2, manifestMapSchema),
|
|
14783
|
-
version: operations.
|
|
15969
|
+
version: operations.union(
|
|
15970
|
+
operations.literal(tileflowRuntimeManifestVersion),
|
|
15971
|
+
operations.literal(2)
|
|
15972
|
+
)
|
|
14784
15973
|
}),
|
|
14785
15974
|
(manifest, context) => {
|
|
14786
15975
|
const mapCount = Object.keys(manifest.maps).length;
|
|
15976
|
+
if (manifest.version === 1) {
|
|
15977
|
+
for (const [name, map] of Object.entries(manifest.maps)) {
|
|
15978
|
+
if (map.timeOfDay !== void 0)
|
|
15979
|
+
context.addIssue({
|
|
15980
|
+
code: "custom",
|
|
15981
|
+
message: "timeOfDay requires manifest version 2",
|
|
15982
|
+
path: ["maps", name, "timeOfDay"]
|
|
15983
|
+
});
|
|
15984
|
+
}
|
|
15985
|
+
}
|
|
14787
15986
|
if (mapCount === 0) {
|
|
14788
15987
|
context.addIssue({ code: "custom", message: "Expected at least one map", path: ["maps"] });
|
|
14789
15988
|
}
|
|
@@ -15178,6 +16377,7 @@ var tileflowMapMergeStrategies = {
|
|
|
15178
16377
|
icons: "icons",
|
|
15179
16378
|
id: "identity",
|
|
15180
16379
|
marine: "atomic",
|
|
16380
|
+
models: "atomic",
|
|
15181
16381
|
modules: "modules",
|
|
15182
16382
|
name: "identity",
|
|
15183
16383
|
overlays: "keyed-resources",
|
|
@@ -15188,6 +16388,7 @@ var tileflowMapMergeStrategies = {
|
|
|
15188
16388
|
systemThemes: "atomic",
|
|
15189
16389
|
terrain: "atomic",
|
|
15190
16390
|
themes: "atomic",
|
|
16391
|
+
timeOfDay: "atomic",
|
|
15191
16392
|
version: "identity",
|
|
15192
16393
|
view: "deep"
|
|
15193
16394
|
};
|
|
@@ -15202,7 +16403,10 @@ function resolveMap(map, options = {}) {
|
|
|
15202
16403
|
for (let index = lineage.length - 1; index >= 0; index -= 1) {
|
|
15203
16404
|
const current = lineage[index];
|
|
15204
16405
|
const currentId = current.id;
|
|
15205
|
-
if (current.themes !== void 0)
|
|
16406
|
+
if (current.themes !== void 0) {
|
|
16407
|
+
delete design.systemThemes;
|
|
16408
|
+
delete design.timeOfDay;
|
|
16409
|
+
}
|
|
15206
16410
|
for (const key of Object.keys(current)) {
|
|
15207
16411
|
const value = current[key];
|
|
15208
16412
|
const strategy = tileflowMapMergeStrategies[key];
|
|
@@ -15523,11 +16727,11 @@ function cloneDesign(value) {
|
|
|
15523
16727
|
function describeMap(value) {
|
|
15524
16728
|
return typeof value.id === "string" && value.id ? value.id : "<anonymous>";
|
|
15525
16729
|
}
|
|
15526
|
-
function
|
|
16730
|
+
function isRecord10(value) {
|
|
15527
16731
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
15528
16732
|
}
|
|
15529
16733
|
function isPlainRecord4(value) {
|
|
15530
|
-
if (!
|
|
16734
|
+
if (!isRecord10(value)) return false;
|
|
15531
16735
|
const prototype = Object.getPrototypeOf(value);
|
|
15532
16736
|
return prototype === Object.prototype || prototype === null;
|
|
15533
16737
|
}
|
|
@@ -15980,6 +17184,7 @@ async function createTileflowMapBuildManifest(maps, options = {}) {
|
|
|
15980
17184
|
semanticCompiler: { ...tileflowSemanticCompilerIdentity },
|
|
15981
17185
|
sourceAssets,
|
|
15982
17186
|
...map.systemThemes ? { systemThemes: { ...map.systemThemes } } : {},
|
|
17187
|
+
...map.timeOfDay && Object.keys(map.timeOfDay).length ? { timeOfDay: map.timeOfDay } : {},
|
|
15983
17188
|
themes
|
|
15984
17189
|
}
|
|
15985
17190
|
];
|
|
@@ -16045,6 +17250,7 @@ async function hashTileflowMapRevision(input, sourceAssets) {
|
|
|
16045
17250
|
const {
|
|
16046
17251
|
fonts: _fonts,
|
|
16047
17252
|
icons: _icons,
|
|
17253
|
+
models: _models,
|
|
16048
17254
|
id: _id,
|
|
16049
17255
|
name: _name,
|
|
16050
17256
|
version: _version,
|
|
@@ -16140,10 +17346,26 @@ function normalizeSourceAssets(input) {
|
|
|
16140
17346
|
if (new Set(fonts.map(fontIdentity)).size !== fonts.length) {
|
|
16141
17347
|
throw new Error("Effective Tileflow font source identities must have unique faces.");
|
|
16142
17348
|
}
|
|
17349
|
+
const models = [...input.models ?? []].map((model) => {
|
|
17350
|
+
assertSha256(model.sha256, `model ${model.id}`);
|
|
17351
|
+
if (model.level !== "near" && model.level !== "mid" && model.level !== "far")
|
|
17352
|
+
throw new Error(`Tileflow model ${model.id} is near, mid or far.`);
|
|
17353
|
+
return { id: model.id, level: model.level, sha256: model.sha256 };
|
|
17354
|
+
}).sort(
|
|
17355
|
+
(left, right) => compareCodeUnits8(`${left.id}\0${left.level}`, `${right.id}\0${right.level}`)
|
|
17356
|
+
);
|
|
17357
|
+
if (new Set(models.map((model) => `${model.id}\0${model.level}`)).size !== models.length) {
|
|
17358
|
+
throw new Error("Effective Tileflow model source identities must be unique.");
|
|
17359
|
+
}
|
|
16143
17360
|
const iconComposition = input.iconComposition === void 0 ? void 0 : parseTileflowIconComposition(input.iconComposition);
|
|
16144
17361
|
if (icons.some((icon) => icon.kind === "rendered-icon") && !iconComposition)
|
|
16145
17362
|
throw new Error("Rendered icon identities require an explicit composition receipt");
|
|
16146
|
-
return {
|
|
17363
|
+
return {
|
|
17364
|
+
fonts,
|
|
17365
|
+
icons,
|
|
17366
|
+
...iconComposition ? { iconComposition } : {},
|
|
17367
|
+
...models.length > 0 ? { models } : {}
|
|
17368
|
+
};
|
|
16147
17369
|
}
|
|
16148
17370
|
function fontIdentity(font) {
|
|
16149
17371
|
return `${font.family}\0${font.style}\0${font.weight}`;
|
|
@@ -24909,7 +26131,7 @@ function createNativeUrlPolicy(parse) {
|
|
|
24909
26131
|
const resourcePath = resolved.href.slice(resolved.origin.length);
|
|
24910
26132
|
const suffix = resourcePath.replace(
|
|
24911
26133
|
new RegExp(`${prefix}(\\d+)__`, "gu"),
|
|
24912
|
-
(
|
|
26134
|
+
(match3, index) => placeholders[Number(index)] ?? match3
|
|
24913
26135
|
);
|
|
24914
26136
|
const result = resolved.origin + suffix;
|
|
24915
26137
|
assertUrlText(result, "resourceUrl");
|
|
@@ -24927,8 +26149,8 @@ function createNativeUrlPolicy(parse) {
|
|
|
24927
26149
|
if (value === void 0) return void 0;
|
|
24928
26150
|
try {
|
|
24929
26151
|
assertUrlText(value, "developmentOrigin");
|
|
24930
|
-
const
|
|
24931
|
-
if (!
|
|
26152
|
+
const match3 = /^(http:\/\/[^/?#]+)\/?$/iu.exec(value);
|
|
26153
|
+
if (!match3 || /[{}@*]/u.test(value)) throw new Error();
|
|
24932
26154
|
const url = parseUrl(value, "developmentOrigin");
|
|
24933
26155
|
if (url.protocol !== "http:" || url.pathname !== "/" || url.search || url.hash || url.hostname.includes("*")) {
|
|
24934
26156
|
throw new Error();
|
|
@@ -25339,11 +26561,11 @@ function parserIssuePointer(key, style) {
|
|
|
25339
26561
|
let path = "";
|
|
25340
26562
|
while (rest) {
|
|
25341
26563
|
if (Array.isArray(value)) {
|
|
25342
|
-
const
|
|
25343
|
-
if (!
|
|
25344
|
-
path = nativePointer(path,
|
|
25345
|
-
value = value[Number(
|
|
25346
|
-
rest = rest.slice(
|
|
26564
|
+
const match3 = /^\[(\d+)\]/u.exec(rest);
|
|
26565
|
+
if (!match3 || Number(match3[1]) >= value.length) return path;
|
|
26566
|
+
path = nativePointer(path, match3[1]);
|
|
26567
|
+
value = value[Number(match3[1])];
|
|
26568
|
+
rest = rest.slice(match3[0].length).replace(/^\./u, "");
|
|
25347
26569
|
} else if (record2(value)) {
|
|
25348
26570
|
const matches = Object.keys(value).filter(
|
|
25349
26571
|
(name2) => rest === name2 || rest.startsWith(`${name2}.`) || rest.startsWith(`${name2}[`)
|
|
@@ -25436,7 +26658,11 @@ var mapBuildSchema = z15.object({
|
|
|
25436
26658
|
semanticCompiler: z15.object({ name: z15.literal("tileflow-semantic"), version: z15.literal(1) }).strict(),
|
|
25437
26659
|
sourceAssets: sourceAssetsSchema,
|
|
25438
26660
|
systemThemes: z15.object({ dark: tileflowThemeNameSchema, light: tileflowThemeNameSchema }).strict().optional(),
|
|
25439
|
-
themes: z15.record(tileflowThemeNameSchema, themeBuildSchema)
|
|
26661
|
+
themes: z15.record(tileflowThemeNameSchema, themeBuildSchema),
|
|
26662
|
+
timeOfDay: createTileflowTimeOfDaySchema(
|
|
26663
|
+
classicManifestSchemaOperations,
|
|
26664
|
+
tileflowThemeNameSchema
|
|
26665
|
+
).optional()
|
|
25440
26666
|
}).strict();
|
|
25441
26667
|
var buildManifestSchema = z15.object({
|
|
25442
26668
|
schemaVersion: z15.literal(1),
|
|
@@ -25498,6 +26724,8 @@ var tileflowRendererDeploymentArtifactSchema = z15.object({
|
|
|
25498
26724
|
const themes = Object.keys(map.themes).sort();
|
|
25499
26725
|
if (!themes.length || themes.length > tileflowRendererDeploymentLimits.maximumThemes || !equal(themes, Object.keys(family.styles).sort()) || !themes.includes(map.defaultTheme) || map.lineage[0]?.id !== artifact.mapId || map.lineage[0]?.mapVersion !== map.mapVersion || Boolean(map.sourceAssets.iconComposition) !== (map.mapRevisionSchemaVersion === 2))
|
|
25500
26726
|
fail();
|
|
26727
|
+
if (map.timeOfDay && validateTileflowTimeOfDayVariants(map.timeOfDay, map.themes).length)
|
|
26728
|
+
fail();
|
|
25501
26729
|
for (const scheme of ["light", "dark"]) {
|
|
25502
26730
|
if (map.systemThemes && map.themes[map.systemThemes[scheme]]?.colorScheme !== scheme)
|
|
25503
26731
|
fail();
|
|
@@ -25613,7 +26841,7 @@ var artifactName = z15.string().min(1).max(256).refine(
|
|
|
25613
26841
|
})
|
|
25614
26842
|
);
|
|
25615
26843
|
var semanticSchema = z15.object({
|
|
25616
|
-
version: z15.literal(
|
|
26844
|
+
version: z15.literal(3),
|
|
25617
26845
|
domains: z15.object({
|
|
25618
26846
|
poi: z15.object({
|
|
25619
26847
|
deduplication: z15.object({
|
|
@@ -25645,7 +26873,6 @@ var semanticSchema = z15.object({
|
|
|
25645
26873
|
layers: z15.array(
|
|
25646
26874
|
z15.object({
|
|
25647
26875
|
anchor: z15.literal("pointer-coordinate"),
|
|
25648
|
-
category: z15.enum(tileflowPoiCategories),
|
|
25649
26876
|
layerId: artifactName,
|
|
25650
26877
|
priority: z15.number().int().min(0).max(4095),
|
|
25651
26878
|
representation: z15.enum(["combined", "icon", "label", "marker"]),
|
|
@@ -25817,6 +27044,7 @@ function createManifest(catalog, options = {}) {
|
|
|
25817
27044
|
defaultTheme: resolved.defaultTheme,
|
|
25818
27045
|
...resolved.systemThemes ? { systemThemes: resolved.systemThemes } : {},
|
|
25819
27046
|
themes,
|
|
27047
|
+
...options.manifestVersion !== 1 && resolved.timeOfDay && Object.keys(resolved.timeOfDay).length ? { timeOfDay: resolved.timeOfDay } : {},
|
|
25820
27048
|
...resolved.view ? { view: resolved.view } : {}
|
|
25821
27049
|
}
|
|
25822
27050
|
];
|
|
@@ -25824,7 +27052,7 @@ function createManifest(catalog, options = {}) {
|
|
|
25824
27052
|
);
|
|
25825
27053
|
const manifest = {
|
|
25826
27054
|
maps,
|
|
25827
|
-
version: tileflowRuntimeManifestVersion
|
|
27055
|
+
version: options.manifestVersion ?? (Object.values(maps).some((map) => map.timeOfDay) ? 2 : tileflowRuntimeManifestVersion)
|
|
25828
27056
|
};
|
|
25829
27057
|
return parseTileflowRuntimeManifest(manifest);
|
|
25830
27058
|
}
|