@tileflow/core 0.1.0-alpha.34 → 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 +13 -11
- package/THIRD_PARTY_NOTICES.md +100 -6
- package/dist/browser.d.ts +218 -21
- package/dist/browser.js +3049 -822
- package/dist/build.d.ts +9 -5
- package/dist/build.js +1284 -443
- package/dist/capture.js +1 -0
- package/dist/config-reference.json +1500 -868
- package/dist/{icon-composition-DqoZWQuz.d.ts → icon-composition-DSjIKmrK.d.ts} +98 -12
- package/dist/index.d.ts +231 -12
- package/dist/index.js +2542 -566
- package/dist/{manifest-types-hmzy2bBX.d.ts → manifest-types-Bzxon3dx.d.ts} +49 -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/authoring-model.md +4 -0
- package/docs/buildings-3d.md +177 -28
- 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/theme-transitions-and-blends.md +50 -0
- package/docs/trees-3d.md +63 -4
- 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({
|
|
@@ -905,20 +936,20 @@ function createTileflowLineBackgroundFontStack(source, metrics = {}) {
|
|
|
905
936
|
return stack;
|
|
906
937
|
}
|
|
907
938
|
function parseTileflowLineBackgroundFontStack(stack) {
|
|
908
|
-
const
|
|
909
|
-
if (!
|
|
939
|
+
const match3 = STACK_PATTERN.exec(stack);
|
|
940
|
+
if (!match3 || stack.length > MAX_STACK_LENGTH || !SOURCE_PATTERN.test(match3[1]))
|
|
910
941
|
return void 0;
|
|
911
942
|
const metrics = {
|
|
912
|
-
letterSpacing: Number(
|
|
913
|
-
lineHeight: Number(
|
|
914
|
-
padding: Number(
|
|
943
|
+
letterSpacing: Number(match3[2]) / 1e3,
|
|
944
|
+
lineHeight: Number(match3[3]) / 1e3,
|
|
945
|
+
padding: Number(match3[4]) / 1e3
|
|
915
946
|
};
|
|
916
947
|
try {
|
|
917
948
|
const normalized = normalizeTileflowLineBackgroundMetrics(metrics);
|
|
918
|
-
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)) {
|
|
919
950
|
return void 0;
|
|
920
951
|
}
|
|
921
|
-
return { metrics: normalized, source:
|
|
952
|
+
return { metrics: normalized, source: match3[1] };
|
|
922
953
|
} catch {
|
|
923
954
|
return void 0;
|
|
924
955
|
}
|
|
@@ -1655,7 +1686,7 @@ function compileVegetation(request, context) {
|
|
|
1655
1686
|
}
|
|
1656
1687
|
function tileflowVegetationDescription(request, context) {
|
|
1657
1688
|
const { schema } = context.data;
|
|
1658
|
-
if (request?.enabled === false ||
|
|
1689
|
+
if (request?.enabled === false || request?.mode === "flat" || !schema.layers.tree)
|
|
1659
1690
|
return void 0;
|
|
1660
1691
|
const tree = context.colors.vegetation.tree;
|
|
1661
1692
|
const style = request?.threeDimensional ?? {};
|
|
@@ -1718,102 +1749,6 @@ function tileflowVegetationDescription(request, context) {
|
|
|
1718
1749
|
};
|
|
1719
1750
|
}
|
|
1720
1751
|
|
|
1721
|
-
// src/buildings-3d-design.ts
|
|
1722
|
-
var tileflowBuildingsMetadataKey = "tileflow:buildings";
|
|
1723
|
-
var tileflowDefaultBuildings3DDesign = Object.freeze({
|
|
1724
|
-
source: "tileflow",
|
|
1725
|
-
layers: Object.freeze({ building: "building", places: "poi" }),
|
|
1726
|
-
color: "#d8d0c0",
|
|
1727
|
-
edges: 1,
|
|
1728
|
-
nightLight: 1,
|
|
1729
|
-
windows: false,
|
|
1730
|
-
shadows: true,
|
|
1731
|
-
occlusion: true
|
|
1732
|
-
});
|
|
1733
|
-
function tileflowBuildingsMetadata(design) {
|
|
1734
|
-
return { version: 1, ...design };
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
// src/street-lights.ts
|
|
1738
|
-
var tileflowStreetLightsMetadataKey = "tileflow:street-lights";
|
|
1739
|
-
var tileflowDefaultStreetLightsDesign = Object.freeze({
|
|
1740
|
-
source: "tileflow",
|
|
1741
|
-
layers: Object.freeze({
|
|
1742
|
-
streetFurniture: "street_furniture",
|
|
1743
|
-
transportation: "transportation",
|
|
1744
|
-
sidewalk: "sidewalk"
|
|
1745
|
-
}),
|
|
1746
|
-
estimate: "lit",
|
|
1747
|
-
color: "#ffcf8f",
|
|
1748
|
-
intensity: 1
|
|
1749
|
-
});
|
|
1750
|
-
function tileflowStreetLightsMetadata(design) {
|
|
1751
|
-
return { version: 1, ...design };
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
// src/cartography/scene-3d-metadata.ts
|
|
1755
|
-
var colourSources = [
|
|
1756
|
-
["tileflow-buildings-render-extrusion", "fill-extrusion-color"],
|
|
1757
|
-
["tileflow-buildings-3d", "fill-extrusion-color"],
|
|
1758
|
-
["tileflow-buildings-fill", "fill-color"]
|
|
1759
|
-
];
|
|
1760
|
-
function tileflowBuildings3DDesignOf(module, context, layers) {
|
|
1761
|
-
const config = isRecord3(module) ? module : {};
|
|
1762
|
-
if (config.enabled === false) return void 0;
|
|
1763
|
-
const style = config.threeDimensional ?? {};
|
|
1764
|
-
let color2;
|
|
1765
|
-
for (const [id2, property] of colourSources) {
|
|
1766
|
-
const value = layers.find((layer) => layer.id === id2)?.paint?.[property];
|
|
1767
|
-
if (typeof value === "string" || Array.isArray(value)) {
|
|
1768
|
-
color2 = value;
|
|
1769
|
-
break;
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
const number = (value, fallback) => {
|
|
1773
|
-
const resolved = value === void 0 ? void 0 : toMapLibreStyleValue(value);
|
|
1774
|
-
return typeof resolved === "number" ? resolved : fallback;
|
|
1775
|
-
};
|
|
1776
|
-
const edgeColor = style.edgeColor === void 0 ? void 0 : toMapLibreStyleValue(style.edgeColor);
|
|
1777
|
-
return {
|
|
1778
|
-
source: context.data.sourceId,
|
|
1779
|
-
layers: {
|
|
1780
|
-
building: context.data.schema.layers.building,
|
|
1781
|
-
...context.data.schema.layers.poi ? { places: context.data.schema.layers.poi } : {}
|
|
1782
|
-
},
|
|
1783
|
-
color: color2 ?? context.colors.buildings.generic,
|
|
1784
|
-
edges: number(style.edges, 1),
|
|
1785
|
-
...typeof edgeColor === "string" ? { edgeColor } : {},
|
|
1786
|
-
nightLight: number(style.nightLight, 1),
|
|
1787
|
-
windows: style.windows === true,
|
|
1788
|
-
shadows: style.shadows !== false,
|
|
1789
|
-
occlusion: style.occlusion !== false
|
|
1790
|
-
};
|
|
1791
|
-
}
|
|
1792
|
-
function tileflowStreetLightsDesignOf(module, context) {
|
|
1793
|
-
const config = isRecord3(module) ? module : {};
|
|
1794
|
-
const layers = context.data.schema.layers;
|
|
1795
|
-
const style = config.streetLights ?? {};
|
|
1796
|
-
if (config.enabled === false || style.enabled === false || !layers.streetFurniture)
|
|
1797
|
-
return void 0;
|
|
1798
|
-
const color2 = style.color === void 0 ? void 0 : toMapLibreStyleValue(style.color);
|
|
1799
|
-
const intensity = style.intensity === void 0 ? void 0 : toMapLibreStyleValue(style.intensity);
|
|
1800
|
-
const estimate = style.estimate;
|
|
1801
|
-
return {
|
|
1802
|
-
source: context.data.sourceId,
|
|
1803
|
-
layers: {
|
|
1804
|
-
streetFurniture: layers.streetFurniture,
|
|
1805
|
-
transportation: layers.road,
|
|
1806
|
-
...layers.sidewalk ? { sidewalk: layers.sidewalk } : {}
|
|
1807
|
-
},
|
|
1808
|
-
estimate: estimate === "streets" || estimate === "none" || estimate === "lit" ? estimate : "lit",
|
|
1809
|
-
color: typeof color2 === "string" ? color2 : tileflowDefaultStreetLightsDesign.color,
|
|
1810
|
-
intensity: typeof intensity === "number" ? intensity : 1
|
|
1811
|
-
};
|
|
1812
|
-
}
|
|
1813
|
-
function isRecord3(value) {
|
|
1814
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
1752
|
// src/cartography/contributions.ts
|
|
1818
1753
|
var tileflowLayerSlots = [
|
|
1819
1754
|
"background",
|
|
@@ -2372,7 +2307,21 @@ function buildingColorExpression(context) {
|
|
|
2372
2307
|
colors.destination,
|
|
2373
2308
|
["==", ["coalesce", ["get", fields.buildingTone], ""], "commercial"],
|
|
2374
2309
|
colors.commercial,
|
|
2375
|
-
|
|
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
|
+
]
|
|
2376
2325
|
];
|
|
2377
2326
|
}
|
|
2378
2327
|
function buildingVisibilityFilter() {
|
|
@@ -2636,6 +2585,9 @@ function cloneJson9(value) {
|
|
|
2636
2585
|
function labelField(language, context) {
|
|
2637
2586
|
return expression(labelFieldExpression(language, context));
|
|
2638
2587
|
}
|
|
2588
|
+
function labelNameFields(language, context) {
|
|
2589
|
+
return labelFieldExpression(language, context).slice(1).map((entry) => entry[1]);
|
|
2590
|
+
}
|
|
2639
2591
|
function labelFieldExpression(language, context) {
|
|
2640
2592
|
const fields = context.data.schema.fields;
|
|
2641
2593
|
if (language === "local") {
|
|
@@ -3493,12 +3445,12 @@ function compileLand(request, context) {
|
|
|
3493
3445
|
if (name === "recreation") continue;
|
|
3494
3446
|
appendLanduse(name, classes);
|
|
3495
3447
|
}
|
|
3496
|
-
for (const [name,
|
|
3448
|
+
for (const [name, match3] of landcoverClasses) {
|
|
3497
3449
|
const style = config.landcover?.[name];
|
|
3498
3450
|
if (!style) continue;
|
|
3499
3451
|
const protectedSource = name === "protected";
|
|
3500
3452
|
const sourceLayer = protectedSource ? schema.layers.park : schema.layers.landcover;
|
|
3501
|
-
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);
|
|
3502
3454
|
for (const area of createAreaLayers(
|
|
3503
3455
|
{
|
|
3504
3456
|
id: `tileflow-landcover-${name}`,
|
|
@@ -3554,11 +3506,11 @@ function compileLand(request, context) {
|
|
|
3554
3506
|
function classFilter2(field2, classes) {
|
|
3555
3507
|
return ["match", ["get", field2], classes, true, false];
|
|
3556
3508
|
}
|
|
3557
|
-
function landcoverFilter(classField, subclassField,
|
|
3558
|
-
const filter = classFilter2(classField,
|
|
3559
|
-
if (
|
|
3560
|
-
if (
|
|
3561
|
-
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)]];
|
|
3562
3514
|
}
|
|
3563
3515
|
return filter;
|
|
3564
3516
|
}
|
|
@@ -4267,6 +4219,12 @@ var tileflowPoiImageRoles = Object.freeze({
|
|
|
4267
4219
|
transport: { fallback: "major-transit", token: "poi.transport" },
|
|
4268
4220
|
"visitor-amenity": { fallback: "services", token: "poi.visitor-amenity" }
|
|
4269
4221
|
});
|
|
4222
|
+
var tileflowPoiIconOnlyTypes = Object.freeze([
|
|
4223
|
+
"parking",
|
|
4224
|
+
"parking_garage",
|
|
4225
|
+
"parking_lot",
|
|
4226
|
+
"public_restroom"
|
|
4227
|
+
]);
|
|
4270
4228
|
function poi(options = {}) {
|
|
4271
4229
|
return { type: "poi", ...cloneJson13(options) };
|
|
4272
4230
|
}
|
|
@@ -4280,7 +4238,10 @@ function resolvePoi(request) {
|
|
|
4280
4238
|
minZoom: request?.minZoom ?? 0,
|
|
4281
4239
|
placement: {
|
|
4282
4240
|
coupleIconAndLabel: request?.placement?.coupleIconAndLabel ?? false,
|
|
4241
|
+
iconOnlyTypes: [...request?.placement?.iconOnlyTypes ?? tileflowPoiIconOnlyTypes],
|
|
4283
4242
|
iconPadding: request?.placement?.iconPadding ?? 2,
|
|
4243
|
+
order: request?.placement?.order ?? "importance",
|
|
4244
|
+
...request?.placement?.prominentRank === void 0 ? {} : { prominentRank: request.placement.prominentRank },
|
|
4284
4245
|
textPadding: request?.placement?.textPadding ?? 2
|
|
4285
4246
|
}
|
|
4286
4247
|
};
|
|
@@ -4289,127 +4250,526 @@ function cloneJson13(value) {
|
|
|
4289
4250
|
return JSON.parse(JSON.stringify(value));
|
|
4290
4251
|
}
|
|
4291
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
|
+
);
|
|
4401
|
+
}
|
|
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
|
+
];
|
|
4429
|
+
}
|
|
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 : {};
|
|
4548
|
+
}
|
|
4549
|
+
|
|
4292
4550
|
// src/modules/poi/compiler.ts
|
|
4551
|
+
var representationOrder = {
|
|
4552
|
+
marker: 0,
|
|
4553
|
+
combined: 1,
|
|
4554
|
+
icon: 1,
|
|
4555
|
+
label: 2
|
|
4556
|
+
};
|
|
4293
4557
|
function compilePoi(request, context, language = "auto") {
|
|
4294
4558
|
if (request?.enabled === false) return [];
|
|
4295
4559
|
const semantics = resolvePoi(request);
|
|
4296
|
-
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) {
|
|
4297
4611
|
const { sourceId: source, schema } = context.data;
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
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,
|
|
4304
4648
|
icon: {
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
[semantics.minZoom, 0.85],
|
|
4309
|
-
[17, 1]
|
|
4310
|
-
]) : 1
|
|
4311
|
-
},
|
|
4312
|
-
text: poiTextStyle(context, {
|
|
4313
|
-
color: categoryColor,
|
|
4314
|
-
field: labelField(language, context),
|
|
4315
|
-
padding: semantics.placement.textPadding,
|
|
4316
|
-
size: semantics.minZoom < 17 ? zoom.linear([
|
|
4317
|
-
[semantics.minZoom, 10],
|
|
4318
|
-
[17, 12]
|
|
4319
|
-
]) : 12
|
|
4320
|
-
})
|
|
4649
|
+
...style.icon,
|
|
4650
|
+
image: resolvePoiImage(category, context, schema.fields.poiIcon)
|
|
4651
|
+
}
|
|
4321
4652
|
};
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
const
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
density: categoryDensity,
|
|
4342
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4343
|
-
id: `tileflow-poi-${category}-marker`,
|
|
4344
|
-
minZoom: semantics.minZoom,
|
|
4345
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4346
|
-
source,
|
|
4347
|
-
sourceLayer: schema.layers.poi
|
|
4348
|
-
});
|
|
4349
|
-
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(
|
|
4350
4672
|
{
|
|
4351
|
-
...
|
|
4673
|
+
...markerBase,
|
|
4352
4674
|
type: "circle",
|
|
4353
4675
|
layout: {
|
|
4354
4676
|
"circle-sort-key": poiSortKey(schema.fields.poiFilterRank, schema.fields.poiSizeRank)
|
|
4355
4677
|
}
|
|
4356
4678
|
},
|
|
4357
4679
|
markerStyle
|
|
4358
|
-
)
|
|
4359
|
-
|
|
4360
|
-
}
|
|
4361
|
-
if (semantics.placement.coupleIconAndLabel && showText && showIcon) {
|
|
4362
|
-
let layer = createPoiLayer({
|
|
4363
|
-
category,
|
|
4364
|
-
categoryField: schema.fields.poiCategory,
|
|
4365
|
-
density: categoryDensity,
|
|
4366
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4367
|
-
id: `tileflow-poi-${category}`,
|
|
4368
|
-
minZoom: semantics.minZoom,
|
|
4369
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4370
|
-
source,
|
|
4371
|
-
sourceLayer: schema.layers.poi
|
|
4372
|
-
});
|
|
4373
|
-
layer = applySymbolStyle(layer, symbolStyle2);
|
|
4374
|
-
result.push(poiContribution(category, index * 4 + 1, layer));
|
|
4375
|
-
continue;
|
|
4376
|
-
}
|
|
4377
|
-
if (showIcon) {
|
|
4378
|
-
const layer = applySymbolStyle(
|
|
4379
|
-
createPoiLayer({
|
|
4380
|
-
category,
|
|
4381
|
-
categoryField: schema.fields.poiCategory,
|
|
4382
|
-
density: categoryDensity,
|
|
4383
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4384
|
-
id: `tileflow-poi-${category}-icon`,
|
|
4385
|
-
minZoom: semantics.minZoom,
|
|
4386
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4387
|
-
source,
|
|
4388
|
-
sourceLayer: schema.layers.poi
|
|
4389
|
-
}),
|
|
4390
|
-
{ ...symbolStyle2, text: void 0 }
|
|
4391
|
-
);
|
|
4392
|
-
result.push(poiContribution(`${category}.icon`, index * 4 + 1, layer));
|
|
4393
|
-
}
|
|
4394
|
-
if (showText) {
|
|
4395
|
-
const layer = applySymbolStyle(
|
|
4396
|
-
createPoiLayer({
|
|
4397
|
-
category,
|
|
4398
|
-
categoryField: schema.fields.poiCategory,
|
|
4399
|
-
density: categoryDensity,
|
|
4400
|
-
filterRankField: schema.fields.poiFilterRank,
|
|
4401
|
-
id: `tileflow-poi-${category}-label`,
|
|
4402
|
-
minZoom: semantics.minZoom,
|
|
4403
|
-
sizeRankField: schema.fields.poiSizeRank,
|
|
4404
|
-
source,
|
|
4405
|
-
sourceLayer: schema.layers.poi
|
|
4406
|
-
}),
|
|
4407
|
-
{ ...symbolStyle2, icon: void 0 }
|
|
4408
|
-
);
|
|
4409
|
-
result.push(poiContribution(`${category}.label`, index * 4 + 2, layer));
|
|
4410
|
-
}
|
|
4680
|
+
)
|
|
4681
|
+
});
|
|
4411
4682
|
}
|
|
4412
|
-
|
|
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;
|
|
4413
4773
|
}
|
|
4414
4774
|
function resolvePoiImage(category, context, iconField) {
|
|
4415
4775
|
const role = `poi.${category}`;
|
|
@@ -4432,28 +4792,6 @@ function resolveMarkerStyle(style) {
|
|
|
4432
4792
|
style.marker
|
|
4433
4793
|
);
|
|
4434
4794
|
}
|
|
4435
|
-
function createPoiLayer(options) {
|
|
4436
|
-
const filterRank = numericPoiField(options.filterRankField, 6);
|
|
4437
|
-
const sizeRank = numericPoiField(options.sizeRankField, 17);
|
|
4438
|
-
return {
|
|
4439
|
-
id: options.id,
|
|
4440
|
-
type: "symbol",
|
|
4441
|
-
source: options.source,
|
|
4442
|
-
"source-layer": options.sourceLayer,
|
|
4443
|
-
minzoom: options.minZoom,
|
|
4444
|
-
filter: [
|
|
4445
|
-
"all",
|
|
4446
|
-
["==", ["get", options.categoryField], options.category],
|
|
4447
|
-
["has", options.filterRankField],
|
|
4448
|
-
[">=", filterRank, 0],
|
|
4449
|
-
["<=", filterRank, poiRankThreshold(options.density)],
|
|
4450
|
-
["has", options.sizeRankField],
|
|
4451
|
-
[">=", sizeRank, 0],
|
|
4452
|
-
["<=", sizeRank, 16]
|
|
4453
|
-
],
|
|
4454
|
-
layout: { "symbol-sort-key": poiSortKey(options.filterRankField, options.sizeRankField) }
|
|
4455
|
-
};
|
|
4456
|
-
}
|
|
4457
4795
|
function poiRankThreshold(density) {
|
|
4458
4796
|
return ["+", ["step", ["zoom"], 0, 16, 1, 17, 2], density];
|
|
4459
4797
|
}
|
|
@@ -4470,7 +4808,7 @@ function poiContribution(target, localOrder, layer) {
|
|
|
4470
4808
|
localOrder: 1e3 + localOrder,
|
|
4471
4809
|
owner: "poi",
|
|
4472
4810
|
slot: "symbols",
|
|
4473
|
-
target: `poi.${target}`
|
|
4811
|
+
target: target ? `poi.${target}` : "poi"
|
|
4474
4812
|
};
|
|
4475
4813
|
}
|
|
4476
4814
|
function poiTextStyle(context, overrides) {
|
|
@@ -4480,8 +4818,7 @@ function poiTextStyle(context, overrides) {
|
|
|
4480
4818
|
color: context.colors.poi.label,
|
|
4481
4819
|
...typographyTextStyle(context.typography.poi),
|
|
4482
4820
|
haloColor: context.colors.poi.halo,
|
|
4483
|
-
haloWidth: 1
|
|
4484
|
-
optional: true
|
|
4821
|
+
haloWidth: 1
|
|
4485
4822
|
},
|
|
4486
4823
|
overrides
|
|
4487
4824
|
);
|
|
@@ -4499,22 +4836,76 @@ function withPoiTextClearance(style, besideIcon) {
|
|
|
4499
4836
|
}
|
|
4500
4837
|
};
|
|
4501
4838
|
}
|
|
4502
|
-
function withoutMarker2(style) {
|
|
4503
|
-
const result = { ...style };
|
|
4504
|
-
delete result.marker;
|
|
4839
|
+
function withoutMarker2(style) {
|
|
4840
|
+
const result = { ...style };
|
|
4841
|
+
delete result.marker;
|
|
4842
|
+
return result;
|
|
4843
|
+
}
|
|
4844
|
+
function withoutVisibility(value) {
|
|
4845
|
+
const { visible: _visible, ...rest } = value;
|
|
4846
|
+
return rest;
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4849
|
+
// src/portable-identity-rules.ts
|
|
4850
|
+
var tileflowPortableIdMaximumLength = 64;
|
|
4851
|
+
var tileflowPortableIdPattern = /^[a-z][a-z0-9-]{0,63}$/u;
|
|
4852
|
+
function isTileflowPortableId(value) {
|
|
4853
|
+
return typeof value === "string" && value.length <= tileflowPortableIdMaximumLength && tileflowPortableIdPattern.test(value) && !["constructor", "prototype"].includes(value) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(value);
|
|
4854
|
+
}
|
|
4855
|
+
function isTileflowThemeName(value) {
|
|
4856
|
+
return isTileflowPortableId(value) && value !== "system";
|
|
4857
|
+
}
|
|
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
|
+
}
|
|
4505
4906
|
return result;
|
|
4506
4907
|
}
|
|
4507
4908
|
|
|
4508
|
-
// src/portable-identity-rules.ts
|
|
4509
|
-
var tileflowPortableIdMaximumLength = 64;
|
|
4510
|
-
var tileflowPortableIdPattern = /^[a-z][a-z0-9-]{0,63}$/u;
|
|
4511
|
-
function isTileflowPortableId(value) {
|
|
4512
|
-
return typeof value === "string" && value.length <= tileflowPortableIdMaximumLength && tileflowPortableIdPattern.test(value) && !["constructor", "prototype"].includes(value) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(value);
|
|
4513
|
-
}
|
|
4514
|
-
function isTileflowThemeName(value) {
|
|
4515
|
-
return isTileflowPortableId(value) && value !== "system";
|
|
4516
|
-
}
|
|
4517
|
-
|
|
4518
4909
|
// src/sun.ts
|
|
4519
4910
|
var tileflowSunMetadataKey = "tileflow:sun";
|
|
4520
4911
|
var tileflowDefaultSunPreset = Object.freeze({
|
|
@@ -4737,7 +5128,7 @@ function resolveThemeValues(value, theme, path = "value") {
|
|
|
4737
5128
|
if (errors.length > 0) throw new TileflowThemeAuditError(errors);
|
|
4738
5129
|
return resolved;
|
|
4739
5130
|
}
|
|
4740
|
-
function resolveThemeSelection(map, requested) {
|
|
5131
|
+
function resolveThemeSelection(map, requested, timeOfDay) {
|
|
4741
5132
|
const name = requested ?? map.defaultTheme;
|
|
4742
5133
|
if (name === "system") {
|
|
4743
5134
|
throw new Error(
|
|
@@ -4754,7 +5145,8 @@ function resolveThemeSelection(map, requested) {
|
|
|
4754
5145
|
const available = Object.keys(map.themes).sort().join(", ") || "<none>";
|
|
4755
5146
|
throw new Error(`Unknown Tileflow theme "${name}"; available themes: ${available}.`);
|
|
4756
5147
|
}
|
|
4757
|
-
|
|
5148
|
+
const resolvedName = resolveTileflowTimeOfDayTheme(map.timeOfDay, name, timeOfDay);
|
|
5149
|
+
return { name: resolvedName, theme: map.themes[resolvedName] };
|
|
4758
5150
|
}
|
|
4759
5151
|
function auditTileflowThemeValues(value, path = "value", context = inferAuditContext(path)) {
|
|
4760
5152
|
const diagnostics = [];
|
|
@@ -4767,7 +5159,7 @@ function auditTileflowThemeValues(value, path = "value", context = inferAuditCon
|
|
|
4767
5159
|
return diagnostics.sort(compareAuditDiagnostics);
|
|
4768
5160
|
}
|
|
4769
5161
|
function auditTileflowMapThemeValues(map) {
|
|
4770
|
-
const modules =
|
|
5162
|
+
const modules = isRecord3(map.modules) ? map.modules : void 0;
|
|
4771
5163
|
const moduleDiagnostics = modules ? Object.keys(modules).sort(compareCodeUnits2).flatMap(
|
|
4772
5164
|
(owner) => auditTileflowThemeValues(modules[owner], `modules.${owner}`, {
|
|
4773
5165
|
owner,
|
|
@@ -4870,7 +5262,7 @@ function isThemePrimitiveForCategory(value, category) {
|
|
|
4870
5262
|
return category === "number" ? typeof value === "number" && Number.isFinite(value) || Array.isArray(value) && value.every((entry) => typeof entry === "number" && Number.isFinite(entry)) : typeof value === "string" && value.length > 0;
|
|
4871
5263
|
}
|
|
4872
5264
|
function isThemeValueCandidate(value) {
|
|
4873
|
-
return
|
|
5265
|
+
return isRecord3(value) && (value.kind === "theme-token" || value.kind === "theme-fixed" || value.kind === "theme-color");
|
|
4874
5266
|
}
|
|
4875
5267
|
function visitAuditableValue(value, path, category, state, intentRequired = false) {
|
|
4876
5268
|
if (isThemeStructuralPath(path)) category = void 0;
|
|
@@ -4886,7 +5278,7 @@ function visitAuditableValue(value, path, category, state, intentRequired = fals
|
|
|
4886
5278
|
visitAuditableArray(value, path, category, state, false, intentRequired);
|
|
4887
5279
|
return;
|
|
4888
5280
|
}
|
|
4889
|
-
if (!
|
|
5281
|
+
if (!isRecord3(value)) return;
|
|
4890
5282
|
if (value.kind === "expression" && Array.isArray(value.value)) {
|
|
4891
5283
|
visitAuditableArray(value.value, `${path}.value`, category, state, true, intentRequired);
|
|
4892
5284
|
return;
|
|
@@ -5201,7 +5593,7 @@ var ThemeValueResolver = class {
|
|
|
5201
5593
|
if (Array.isArray(value)) {
|
|
5202
5594
|
return value.map((entry, index) => this.resolveTree(entry, `${path}[${index}]`, category));
|
|
5203
5595
|
}
|
|
5204
|
-
if (!
|
|
5596
|
+
if (!isRecord3(value)) return value;
|
|
5205
5597
|
if (value.kind === "expression" && Array.isArray(value.value)) {
|
|
5206
5598
|
return {
|
|
5207
5599
|
...value,
|
|
@@ -5513,7 +5905,7 @@ function assertThemeLighting(value, path) {
|
|
|
5513
5905
|
}
|
|
5514
5906
|
}
|
|
5515
5907
|
function assertThemeCategoryValue(value, expectedCategory, path) {
|
|
5516
|
-
if (!
|
|
5908
|
+
if (!isRecord3(value)) {
|
|
5517
5909
|
assertTokenPrimitive(expectedCategory, value, path);
|
|
5518
5910
|
return;
|
|
5519
5911
|
}
|
|
@@ -5865,11 +6257,11 @@ function cloneJson14(value) {
|
|
|
5865
6257
|
if (serialized === void 0) throw new Error("Tileflow themes must be JSON-serializable.");
|
|
5866
6258
|
return JSON.parse(serialized);
|
|
5867
6259
|
}
|
|
5868
|
-
function
|
|
6260
|
+
function isRecord3(value) {
|
|
5869
6261
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
5870
6262
|
}
|
|
5871
6263
|
function isPlainRecord(value) {
|
|
5872
|
-
if (!
|
|
6264
|
+
if (!isRecord3(value)) return false;
|
|
5873
6265
|
const prototype = Object.getPrototypeOf(value);
|
|
5874
6266
|
return prototype === Object.prototype || prototype === null;
|
|
5875
6267
|
}
|
|
@@ -6823,9 +7215,10 @@ function compileRoundabouts(request, context, contributions) {
|
|
|
6823
7215
|
contributions.push({
|
|
6824
7216
|
kind: "layer",
|
|
6825
7217
|
layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-casing" }, config.casing),
|
|
6826
|
-
localOrder:
|
|
7218
|
+
localOrder: 900,
|
|
6827
7219
|
owner: "roads",
|
|
6828
|
-
|
|
7220
|
+
// Approach fills must cover the circular casing where the roads meet.
|
|
7221
|
+
slot: "transport-surface-casing",
|
|
6829
7222
|
target: "roads.roundabouts.casing"
|
|
6830
7223
|
});
|
|
6831
7224
|
}
|
|
@@ -6833,9 +7226,9 @@ function compileRoundabouts(request, context, contributions) {
|
|
|
6833
7226
|
contributions.push({
|
|
6834
7227
|
kind: "layer",
|
|
6835
7228
|
layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-fill" }, config.fill),
|
|
6836
|
-
localOrder:
|
|
7229
|
+
localOrder: 900,
|
|
6837
7230
|
owner: "roads",
|
|
6838
|
-
slot: "transport-
|
|
7231
|
+
slot: "transport-surface-fill",
|
|
6839
7232
|
target: "roads.roundabouts.fill"
|
|
6840
7233
|
});
|
|
6841
7234
|
}
|
|
@@ -6900,7 +7293,7 @@ var circularRoadBorderTotalWidth = 1;
|
|
|
6900
7293
|
function circularRoadInnerRadius(fields, casing) {
|
|
6901
7294
|
const values = circularRoadValues(fields);
|
|
6902
7295
|
const stops = [];
|
|
6903
|
-
for (let level = 15; level <=
|
|
7296
|
+
for (let level = 15; level <= 24; level += 1) {
|
|
6904
7297
|
const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
|
|
6905
7298
|
const physicalInnerRadius = [
|
|
6906
7299
|
"*",
|
|
@@ -6917,13 +7310,13 @@ function circularRoadInnerRadius(fields, casing) {
|
|
|
6917
7310
|
casing ? ["-", innerRadius, circularRoadBorderTotalWidth / 2] : innerRadius
|
|
6918
7311
|
]);
|
|
6919
7312
|
}
|
|
6920
|
-
return ["interpolate", ["
|
|
7313
|
+
return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
|
|
6921
7314
|
}
|
|
6922
7315
|
function circularRoadStrokeWidth(fields, casing) {
|
|
6923
7316
|
const values = circularRoadValues(fields);
|
|
6924
7317
|
const baseWidth = circularRoadBaseWidth(fields.class);
|
|
6925
7318
|
const stops = [];
|
|
6926
|
-
for (let level = 15; level <=
|
|
7319
|
+
for (let level = 15; level <= 24; level += 1) {
|
|
6927
7320
|
const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
|
|
6928
7321
|
const physicalWidth = [
|
|
6929
7322
|
"*",
|
|
@@ -6938,7 +7331,7 @@ function circularRoadStrokeWidth(fields, casing) {
|
|
|
6938
7331
|
casing ? ["+", fallbackWidth, circularRoadBorderTotalWidth] : fallbackWidth
|
|
6939
7332
|
]);
|
|
6940
7333
|
}
|
|
6941
|
-
return ["interpolate", ["
|
|
7334
|
+
return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
|
|
6942
7335
|
}
|
|
6943
7336
|
function circularRoadBaseWidth(classField) {
|
|
6944
7337
|
return [
|
|
@@ -7102,6 +7495,10 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
|
|
|
7102
7495
|
return value === void 0 ? [] : [{ condition, resolve: () => expressionOutput(value) }];
|
|
7103
7496
|
});
|
|
7104
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
|
+
}
|
|
7105
7502
|
result[property] = conditionalStyleValue(
|
|
7106
7503
|
result[property],
|
|
7107
7504
|
branches,
|
|
@@ -7118,9 +7515,21 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
|
|
|
7118
7515
|
widthScales,
|
|
7119
7516
|
treatmentPaintDefaults.width
|
|
7120
7517
|
);
|
|
7518
|
+
if (result.gapWidth !== void 0 && result.gapWidth !== 0) {
|
|
7519
|
+
result.gapWidth = conditionalWidthScaleValue(
|
|
7520
|
+
result.gapWidth,
|
|
7521
|
+
widthScales,
|
|
7522
|
+
treatmentPaintDefaults.gapWidth
|
|
7523
|
+
);
|
|
7524
|
+
}
|
|
7121
7525
|
}
|
|
7122
7526
|
return result;
|
|
7123
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
|
+
}
|
|
7124
7533
|
function roadTreatmentPhaseConditions(treatments, structure, phase) {
|
|
7125
7534
|
return treatments.flatMap(
|
|
7126
7535
|
({ condition, style }) => style[structure]?.[phase] === void 0 ? [] : [condition]
|
|
@@ -7205,10 +7614,10 @@ function isExpressionOutput(value) {
|
|
|
7205
7614
|
}
|
|
7206
7615
|
function rewriteZoomOutputs(value, rewrite) {
|
|
7207
7616
|
if (!Array.isArray(value)) return rewrite(value);
|
|
7208
|
-
if (value[0] === "interpolate" &&
|
|
7617
|
+
if (value[0] === "interpolate" && isZoomInput4(value[2])) {
|
|
7209
7618
|
return value.map((entry, index) => index >= 4 && index % 2 === 0 ? rewrite(entry) : entry);
|
|
7210
7619
|
}
|
|
7211
|
-
if (value[0] === "step" &&
|
|
7620
|
+
if (value[0] === "step" && isZoomInput4(value[1])) {
|
|
7212
7621
|
return value.map(
|
|
7213
7622
|
(entry, index) => index === 2 || index >= 4 && index % 2 === 0 ? rewrite(entry) : entry
|
|
7214
7623
|
);
|
|
@@ -7218,7 +7627,7 @@ function rewriteZoomOutputs(value, rewrite) {
|
|
|
7218
7627
|
function expressionOutput(value) {
|
|
7219
7628
|
return Array.isArray(value) && typeof value[0] !== "string" ? ["literal", value] : value;
|
|
7220
7629
|
}
|
|
7221
|
-
function
|
|
7630
|
+
function isZoomInput4(value) {
|
|
7222
7631
|
return Array.isArray(value) && value.length === 1 && value[0] === "zoom";
|
|
7223
7632
|
}
|
|
7224
7633
|
function restrictedAccessFilter(field2) {
|
|
@@ -7597,7 +8006,7 @@ var waterwayClasses = {
|
|
|
7597
8006
|
river: ["river"],
|
|
7598
8007
|
stream: ["stream"]
|
|
7599
8008
|
};
|
|
7600
|
-
function compileWater(request, context) {
|
|
8009
|
+
function compileWater(request, context, language = "auto") {
|
|
7601
8010
|
const config = mergeTileflowDesign(
|
|
7602
8011
|
{
|
|
7603
8012
|
type: "water",
|
|
@@ -7749,8 +8158,11 @@ function compileWater(request, context) {
|
|
|
7749
8158
|
appendBathymetryRelief(contributions, bathymetryProduct.relief, context);
|
|
7750
8159
|
}
|
|
7751
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;
|
|
7752
8164
|
const contourRequest = productContours === false ? void 0 : productContours === void 0 ? request?.bathymetryContours : mergeTileflowDesign(productContours, request?.bathymetryContours);
|
|
7753
|
-
if (contourRequest !== void 0 &&
|
|
8165
|
+
if (contourRequest !== void 0 && contourLayer && contourDepthField) {
|
|
7754
8166
|
const bathymetryContours = mergeTileflowDesign(
|
|
7755
8167
|
{
|
|
7756
8168
|
color: context.colors.hydro.label,
|
|
@@ -7773,12 +8185,12 @@ function compileWater(request, context) {
|
|
|
7773
8185
|
id: "tileflow-bathymetry-contours",
|
|
7774
8186
|
type: "line",
|
|
7775
8187
|
source: bathymetrySource,
|
|
7776
|
-
"source-layer":
|
|
8188
|
+
"source-layer": contourLayer,
|
|
7777
8189
|
filter: [
|
|
7778
8190
|
"all",
|
|
7779
|
-
["==", ["geometry-type"], "Polygon"],
|
|
7780
|
-
["has",
|
|
7781
|
-
["<", ["to-number", ["get",
|
|
8191
|
+
["==", ["geometry-type"], nativeContours ? "LineString" : "Polygon"],
|
|
8192
|
+
["has", contourDepthField],
|
|
8193
|
+
["<", ["to-number", ["get", contourDepthField], 0], 0]
|
|
7782
8194
|
]
|
|
7783
8195
|
},
|
|
7784
8196
|
bathymetryContours
|
|
@@ -7792,19 +8204,19 @@ function compileWater(request, context) {
|
|
|
7792
8204
|
}
|
|
7793
8205
|
const productLabels = bathymetryProduct?.labels;
|
|
7794
8206
|
const labelRequest = productLabels === false ? void 0 : productLabels === void 0 ? request?.bathymetryLabels : mergeTileflowDesign(productLabels, request?.bathymetryLabels);
|
|
7795
|
-
if (labelRequest !== void 0 &&
|
|
8207
|
+
if (labelRequest !== void 0 && contourLayer && contourDepthField) {
|
|
7796
8208
|
const bathymetryLabels = mergeTileflowDesign(
|
|
7797
8209
|
{
|
|
7798
8210
|
maxZoom: 10,
|
|
7799
8211
|
minZoom: 3,
|
|
7800
|
-
placement: "point",
|
|
8212
|
+
placement: nativeContours ? "line" : "point",
|
|
7801
8213
|
priority: 5,
|
|
7802
8214
|
text: {
|
|
7803
8215
|
allowOverlap: false,
|
|
7804
8216
|
color: context.colors.hydro.label,
|
|
7805
8217
|
field: expression([
|
|
7806
8218
|
"to-string",
|
|
7807
|
-
["abs", ["to-number", ["get",
|
|
8219
|
+
["abs", ["to-number", ["get", contourDepthField], 0]]
|
|
7808
8220
|
]),
|
|
7809
8221
|
...typographyTextStyle(context.typography.water),
|
|
7810
8222
|
haloColor: context.colors.hydro.water,
|
|
@@ -7825,8 +8237,13 @@ function compileWater(request, context) {
|
|
|
7825
8237
|
id: "tileflow-bathymetry-labels",
|
|
7826
8238
|
type: "symbol",
|
|
7827
8239
|
source: bathymetrySource,
|
|
7828
|
-
"source-layer":
|
|
7829
|
-
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
|
+
]
|
|
7830
8247
|
},
|
|
7831
8248
|
bathymetryLabels
|
|
7832
8249
|
),
|
|
@@ -7837,6 +8254,37 @@ function compileWater(request, context) {
|
|
|
7837
8254
|
});
|
|
7838
8255
|
}
|
|
7839
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
|
+
}
|
|
7840
8288
|
let localOrder = 10;
|
|
7841
8289
|
for (const [name, classes] of Object.entries(waterwayClasses)) {
|
|
7842
8290
|
const style = config.waterways?.[name];
|
|
@@ -7900,6 +8348,99 @@ function compileWater(request, context) {
|
|
|
7900
8348
|
}
|
|
7901
8349
|
return contributions;
|
|
7902
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
|
+
}
|
|
7903
8444
|
function appendBathymetryRelief(contributions, relief, context) {
|
|
7904
8445
|
const { sourceId, style } = relief;
|
|
7905
8446
|
const opacity = resolvedNumber(style.opacity, 0.22, "bathymetry relief opacity");
|
|
@@ -8108,12 +8649,6 @@ var tileflowSemanticDomainRegistry = Object.freeze([
|
|
|
8108
8649
|
dependencies: {},
|
|
8109
8650
|
name: "land"
|
|
8110
8651
|
}),
|
|
8111
|
-
defineDomain({
|
|
8112
|
-
compile: ({ context, module }) => compileWater(module, context),
|
|
8113
|
-
defaultModule: water(),
|
|
8114
|
-
dependencies: {},
|
|
8115
|
-
name: "water"
|
|
8116
|
-
}),
|
|
8117
8652
|
defineDomain({
|
|
8118
8653
|
compile: ({ context, module }) => compileNautical(module, context),
|
|
8119
8654
|
defaultModule: nautical(),
|
|
@@ -8202,6 +8737,12 @@ var tileflowSemanticDomainRegistry = Object.freeze([
|
|
|
8202
8737
|
provides: ["language"],
|
|
8203
8738
|
resolveServices: ({ module }) => ({ language: resolveLabels(module).language })
|
|
8204
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
|
+
}),
|
|
8205
8746
|
defineDomain({
|
|
8206
8747
|
compile: ({ context, dependencies, module }) => compileLandforms(module, dependencies.service("language"), context),
|
|
8207
8748
|
defaultModule: landforms(),
|
|
@@ -8320,7 +8861,7 @@ function createTileflowCompilerProvenance(owner, slot, target) {
|
|
|
8320
8861
|
return [{ operations: [], owner, slot, target }];
|
|
8321
8862
|
}
|
|
8322
8863
|
function readTileflowCompilerProvenance(layer) {
|
|
8323
|
-
const metadata =
|
|
8864
|
+
const metadata = asRecord3(layer.metadata);
|
|
8324
8865
|
const raw = metadata[tileflowCompilerProvenanceMetadataKey];
|
|
8325
8866
|
if (Array.isArray(raw)) {
|
|
8326
8867
|
const parsed = raw.flatMap((value) => {
|
|
@@ -8348,7 +8889,7 @@ function createTileflowStyleInspection(map, theme, layers) {
|
|
|
8348
8889
|
};
|
|
8349
8890
|
}
|
|
8350
8891
|
function parseContribution(value) {
|
|
8351
|
-
const input =
|
|
8892
|
+
const input = asRecord3(value);
|
|
8352
8893
|
const owner = requireLayerDomain(input.owner);
|
|
8353
8894
|
const slot = requireLayerSlot(input.slot);
|
|
8354
8895
|
const target = input.target;
|
|
@@ -8362,7 +8903,7 @@ function parseContribution(value) {
|
|
|
8362
8903
|
return { operations, owner, slot, target };
|
|
8363
8904
|
}
|
|
8364
8905
|
function parseRenderOperation(value) {
|
|
8365
|
-
const input =
|
|
8906
|
+
const input = asRecord3(value);
|
|
8366
8907
|
const owner = requireLayerDomain(input.owner);
|
|
8367
8908
|
const target = input.target;
|
|
8368
8909
|
if (input.kind !== "pass" && input.kind !== "refinement" || !owner || typeof target !== "string" || !tileflowSemanticTargetPattern.test(target)) {
|
|
@@ -8376,7 +8917,7 @@ function requireLayerDomain(value) {
|
|
|
8376
8917
|
function requireLayerSlot(value) {
|
|
8377
8918
|
return typeof value === "string" && tileflowLayerSlots.includes(value) ? value : void 0;
|
|
8378
8919
|
}
|
|
8379
|
-
function
|
|
8920
|
+
function asRecord3(value) {
|
|
8380
8921
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8381
8922
|
}
|
|
8382
8923
|
|
|
@@ -8423,6 +8964,7 @@ var classicManifestSchemaOperations = {
|
|
|
8423
8964
|
return z3.enum(values);
|
|
8424
8965
|
},
|
|
8425
8966
|
literal: (value) => z3.literal(value),
|
|
8967
|
+
union: (left, right) => z3.union([classic(left), classic(right)]),
|
|
8426
8968
|
tuplePair(left, right) {
|
|
8427
8969
|
return z3.tuple([classic(left), classic(right)]);
|
|
8428
8970
|
},
|
|
@@ -8745,7 +9287,7 @@ function not(value) {
|
|
|
8745
9287
|
function has(reference) {
|
|
8746
9288
|
return make(["has", reference]);
|
|
8747
9289
|
}
|
|
8748
|
-
function
|
|
9290
|
+
function match2(input, branches, fallback) {
|
|
8749
9291
|
validateBranchCount(branches.length, "expr.match");
|
|
8750
9292
|
validateMatchLabels(branches);
|
|
8751
9293
|
return make([
|
|
@@ -8843,7 +9385,7 @@ function limitError(message) {
|
|
|
8843
9385
|
return new Error(site ? `${message} Called at ${site}.` : message);
|
|
8844
9386
|
}
|
|
8845
9387
|
function authoringCallSite(stack) {
|
|
8846
|
-
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 }));
|
|
8847
9389
|
const own = locations[0]?.file;
|
|
8848
9390
|
const site = locations.find(({ file }) => file !== own && !file.startsWith("node:"));
|
|
8849
9391
|
return site ? `${site.file}:${site.line}:${site.column}` : void 0;
|
|
@@ -9228,7 +9770,7 @@ var expr = Object.freeze({
|
|
|
9228
9770
|
literal,
|
|
9229
9771
|
lt: (left, right) => compare("<", left, right),
|
|
9230
9772
|
lte: (left, right) => compare("<=", left, right),
|
|
9231
|
-
match,
|
|
9773
|
+
match: match2,
|
|
9232
9774
|
max: maximum,
|
|
9233
9775
|
min: minimum,
|
|
9234
9776
|
modulo,
|
|
@@ -9252,6 +9794,12 @@ var tileflowSemanticFieldNames = Object.freeze(
|
|
|
9252
9794
|
var tileflowSemanticLayerNames = Object.freeze(
|
|
9253
9795
|
Object.keys(completeSemanticDataContract.layers).sort(compareCodeUnits5)
|
|
9254
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
|
+
);
|
|
9255
9803
|
function field(name) {
|
|
9256
9804
|
return Object.freeze({ kind: "tileflow-data-field", name });
|
|
9257
9805
|
}
|
|
@@ -9283,6 +9831,9 @@ function bindSemanticReferences(value, data) {
|
|
|
9283
9831
|
}
|
|
9284
9832
|
function bindSemanticValue(value, schema, sourceId) {
|
|
9285
9833
|
if (isDataFieldReference2(value)) {
|
|
9834
|
+
if (Object.hasOwn(auxiliaryFieldBindings, value.name)) {
|
|
9835
|
+
return auxiliaryFieldBindings[value.name];
|
|
9836
|
+
}
|
|
9286
9837
|
const binding = schema.fields[value.name];
|
|
9287
9838
|
if (!binding) throw new Error(`Tileflow data schema does not provide field ${value.name}.`);
|
|
9288
9839
|
return binding;
|
|
@@ -9294,21 +9845,21 @@ function bindSemanticValue(value, schema, sourceId) {
|
|
|
9294
9845
|
}
|
|
9295
9846
|
if (isDataSourceReference(value)) return sourceId;
|
|
9296
9847
|
if (Array.isArray(value)) return value.map((item) => bindSemanticValue(item, schema, sourceId));
|
|
9297
|
-
if (!
|
|
9848
|
+
if (!isRecord4(value)) return value;
|
|
9298
9849
|
return Object.fromEntries(
|
|
9299
9850
|
Object.entries(value).map(([key, item]) => [key, bindSemanticValue(item, schema, sourceId)])
|
|
9300
9851
|
);
|
|
9301
9852
|
}
|
|
9302
9853
|
function isDataFieldReference2(value) {
|
|
9303
|
-
return
|
|
9854
|
+
return isRecord4(value) && value.kind === "tileflow-data-field" && typeof value.name === "string";
|
|
9304
9855
|
}
|
|
9305
9856
|
function isDataLayerReference(value) {
|
|
9306
|
-
return
|
|
9857
|
+
return isRecord4(value) && value.kind === "tileflow-data-layer" && typeof value.name === "string";
|
|
9307
9858
|
}
|
|
9308
9859
|
function isDataSourceReference(value) {
|
|
9309
|
-
return
|
|
9860
|
+
return isRecord4(value) && value.kind === "tileflow-data-source" && value.name === "primary";
|
|
9310
9861
|
}
|
|
9311
|
-
function
|
|
9862
|
+
function isRecord4(value) {
|
|
9312
9863
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
9313
9864
|
}
|
|
9314
9865
|
function compareCodeUnits5(left, right) {
|
|
@@ -9412,8 +9963,8 @@ function createTileflowLayerTemplateIR(layer, semanticKey) {
|
|
|
9412
9963
|
renderer: type,
|
|
9413
9964
|
...filter === void 0 ? {} : { selector: cloneJson20(filter) },
|
|
9414
9965
|
style: Object.freeze({
|
|
9415
|
-
...
|
|
9416
|
-
...
|
|
9966
|
+
...isRecord5(layout) ? { placement: Object.freeze(cloneJson20(layout)) } : {},
|
|
9967
|
+
...isRecord5(paint) ? { appearance: Object.freeze(cloneJson20(paint)) } : {}
|
|
9417
9968
|
})
|
|
9418
9969
|
});
|
|
9419
9970
|
}
|
|
@@ -9487,72 +10038,77 @@ function emitLayer(family, resolvePhysicalId) {
|
|
|
9487
10038
|
function physicalLayerIdForSemanticKey(semanticKey) {
|
|
9488
10039
|
const exact = exactPhysicalLayerIds[semanticKey];
|
|
9489
10040
|
if (exact) return exact;
|
|
9490
|
-
let
|
|
10041
|
+
let match3 = /^([A-Za-z0-9_-]+)\.render\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(
|
|
9491
10042
|
semanticKey
|
|
9492
10043
|
);
|
|
9493
|
-
if (
|
|
9494
|
-
|
|
10044
|
+
if (match3) return `tileflow-${match3[1]}-render-${match3[2].replaceAll(".", "-")}`;
|
|
10045
|
+
match3 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch)$/u.exec(
|
|
9495
10046
|
semanticKey
|
|
9496
10047
|
);
|
|
9497
|
-
if (
|
|
9498
|
-
|
|
10048
|
+
if (match3) return `tileflow-road-${match3[2]}-${match3[1]}-${match3[3]}`;
|
|
10049
|
+
match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill)$/u.exec(
|
|
9499
10050
|
semanticKey
|
|
9500
10051
|
);
|
|
9501
|
-
if (
|
|
9502
|
-
|
|
9503
|
-
if (
|
|
9504
|
-
|
|
9505
|
-
if (
|
|
9506
|
-
const base =
|
|
9507
|
-
return
|
|
9508
|
-
}
|
|
9509
|
-
|
|
9510
|
-
if (
|
|
9511
|
-
const base = `tileflow-${
|
|
9512
|
-
return
|
|
9513
|
-
}
|
|
9514
|
-
|
|
9515
|
-
if (
|
|
9516
|
-
return
|
|
9517
|
-
}
|
|
9518
|
-
|
|
9519
|
-
if (
|
|
9520
|
-
|
|
9521
|
-
if (
|
|
9522
|
-
const base = `tileflow-water${
|
|
9523
|
-
return
|
|
9524
|
-
}
|
|
9525
|
-
|
|
9526
|
-
if (
|
|
9527
|
-
|
|
9528
|
-
if (
|
|
9529
|
-
const base =
|
|
9530
|
-
return
|
|
9531
|
-
}
|
|
9532
|
-
|
|
9533
|
-
if (
|
|
9534
|
-
|
|
9535
|
-
if (
|
|
9536
|
-
|
|
9537
|
-
if (
|
|
9538
|
-
|
|
9539
|
-
if (
|
|
9540
|
-
|
|
9541
|
-
if (
|
|
9542
|
-
|
|
9543
|
-
if (
|
|
9544
|
-
|
|
9545
|
-
if (
|
|
9546
|
-
|
|
9547
|
-
if (
|
|
9548
|
-
|
|
9549
|
-
if (
|
|
9550
|
-
|
|
9551
|
-
if (
|
|
9552
|
-
|
|
9553
|
-
if (
|
|
9554
|
-
|
|
9555
|
-
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(".", "-")}`;
|
|
9556
10112
|
const nautical2 = nauticalPhysicalLayerId(semanticKey);
|
|
9557
10113
|
if (nautical2) return nautical2;
|
|
9558
10114
|
throw new TileflowDomainIRError(
|
|
@@ -9569,6 +10125,7 @@ var exactPhysicalLayerIds = Object.freeze({
|
|
|
9569
10125
|
"labels.junctions": "tileflow-label-road-junction",
|
|
9570
10126
|
"land.background": "tileflow-background",
|
|
9571
10127
|
"land.globalLandcover": "tileflow-global-landcover",
|
|
10128
|
+
poi: "tileflow-poi",
|
|
9572
10129
|
"landforms.classes": "tileflow-landforms",
|
|
9573
10130
|
"roads.crossings": "tileflow-road-crossing",
|
|
9574
10131
|
"roads.oneWayMarkers": "tileflow-road-oneway",
|
|
@@ -9585,6 +10142,8 @@ var exactPhysicalLayerIds = Object.freeze({
|
|
|
9585
10142
|
"water.bathymetry": "tileflow-bathymetry",
|
|
9586
10143
|
"water.bathymetryContours": "tileflow-bathymetry-contours",
|
|
9587
10144
|
"water.bathymetryLabels": "tileflow-bathymetry-labels",
|
|
10145
|
+
"water.bathymetryLandforms": "tileflow-bathymetry-landforms",
|
|
10146
|
+
"water.bathymetryWaterNames": "tileflow-bathymetry-water-names",
|
|
9588
10147
|
"water.bathymetryRelief.color": "tileflow-bathymetry-color-relief",
|
|
9589
10148
|
"water.bathymetryRelief.hillshade": "tileflow-bathymetry-relief"
|
|
9590
10149
|
});
|
|
@@ -9609,15 +10168,15 @@ var nauticalPhysicalBases = Object.freeze({
|
|
|
9609
10168
|
function nauticalPhysicalLayerId(semanticKey) {
|
|
9610
10169
|
const direct = nauticalPhysicalBases[semanticKey];
|
|
9611
10170
|
if (direct) return direct;
|
|
9612
|
-
const
|
|
9613
|
-
if (!
|
|
9614
|
-
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]];
|
|
9615
10174
|
if (!base) return void 0;
|
|
9616
|
-
if (
|
|
9617
|
-
return `${base}-${
|
|
10175
|
+
if (match3[2] === "fill" || match3[2] === "symbol") return base;
|
|
10176
|
+
return `${base}-${match3[2]}`;
|
|
9618
10177
|
}
|
|
9619
10178
|
function publicMetadata(value) {
|
|
9620
|
-
const metadata = { ...
|
|
10179
|
+
const metadata = { ...asRecord4(value) };
|
|
9621
10180
|
delete metadata[tileflowCompilerProvenanceMetadataKey];
|
|
9622
10181
|
for (const key of Object.values(tileflowCompilerMetadataKeys)) delete metadata[key];
|
|
9623
10182
|
return Object.keys(metadata).length > 0 ? cloneJson20(metadata) : void 0;
|
|
@@ -9653,21 +10212,21 @@ function visitReferences(value, counts, visited = /* @__PURE__ */ new WeakSet())
|
|
|
9653
10212
|
}
|
|
9654
10213
|
}
|
|
9655
10214
|
function isSemanticFieldReference(value) {
|
|
9656
|
-
return
|
|
10215
|
+
return isRecord5(value) && value.kind === "tileflow-data-field";
|
|
9657
10216
|
}
|
|
9658
10217
|
function isSemanticLayerReference(value) {
|
|
9659
|
-
return
|
|
10218
|
+
return isRecord5(value) && value.kind === "tileflow-data-layer";
|
|
9660
10219
|
}
|
|
9661
10220
|
function isSemanticSourceReference(value) {
|
|
9662
|
-
return
|
|
10221
|
+
return isRecord5(value) && value.kind === "tileflow-data-source";
|
|
9663
10222
|
}
|
|
9664
10223
|
function cloneJson20(value) {
|
|
9665
10224
|
return JSON.parse(JSON.stringify(value));
|
|
9666
10225
|
}
|
|
9667
|
-
function
|
|
9668
|
-
return
|
|
10226
|
+
function asRecord4(value) {
|
|
10227
|
+
return isRecord5(value) ? value : {};
|
|
9669
10228
|
}
|
|
9670
|
-
function
|
|
10229
|
+
function isRecord5(value) {
|
|
9671
10230
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
9672
10231
|
}
|
|
9673
10232
|
|
|
@@ -9719,7 +10278,7 @@ function validateTileflowRenderSelectorConstraints(input) {
|
|
|
9719
10278
|
};
|
|
9720
10279
|
while (pending.length > 0) {
|
|
9721
10280
|
const current = pending.pop();
|
|
9722
|
-
if (!
|
|
10281
|
+
if (!isRecord6(current.selector) || typeof current.selector.kind !== "string") {
|
|
9723
10282
|
addIssue(
|
|
9724
10283
|
"invalid-selector",
|
|
9725
10284
|
"a render selector must be a semantic selector node",
|
|
@@ -9780,7 +10339,7 @@ function validateTileflowRenderSelectorConstraints(input) {
|
|
|
9780
10339
|
}
|
|
9781
10340
|
for (const [index, branch] of current.selector.branches.entries()) {
|
|
9782
10341
|
const branchPath = [...branchesPath, index];
|
|
9783
|
-
if (!
|
|
10342
|
+
if (!isRecord6(branch)) {
|
|
9784
10343
|
addIssue("invalid-selector", "match selector branch must be an object", branchPath);
|
|
9785
10344
|
continue;
|
|
9786
10345
|
}
|
|
@@ -9811,14 +10370,14 @@ function validateTileflowRenderSelectorConstraints(input) {
|
|
|
9811
10370
|
for (let index = current.selector.stops.length - 1; index >= 0; index -= 1) {
|
|
9812
10371
|
const stop = current.selector.stops[index];
|
|
9813
10372
|
const stopPath = [...stopsPath, index];
|
|
9814
|
-
if (!
|
|
10373
|
+
if (!isRecord6(stop)) {
|
|
9815
10374
|
addIssue("invalid-selector", "step selector stop must be an object", stopPath);
|
|
9816
10375
|
continue;
|
|
9817
10376
|
}
|
|
9818
10377
|
pushChild(stop.selector, current.depth + 1, [...stopPath, "selector"]);
|
|
9819
10378
|
}
|
|
9820
10379
|
for (const [index, stop] of current.selector.stops.entries()) {
|
|
9821
|
-
if (!
|
|
10380
|
+
if (!isRecord6(stop)) continue;
|
|
9822
10381
|
const zoom3 = stop.zoom;
|
|
9823
10382
|
const zoomPath = [...stopsPath, index, "zoom"];
|
|
9824
10383
|
if (typeof zoom3 !== "number" || !Number.isFinite(zoom3) || zoom3 < 0 || zoom3 > 24) {
|
|
@@ -10138,12 +10697,12 @@ function applyRendererStyle(layer, renderer, style) {
|
|
|
10138
10697
|
if (!visibilityGroup) return result;
|
|
10139
10698
|
return {
|
|
10140
10699
|
...result,
|
|
10141
|
-
layout: { ...
|
|
10142
|
-
metadata: { ...
|
|
10700
|
+
layout: { ...asRecord5(result.layout), visibility: "none" },
|
|
10701
|
+
metadata: { ...asRecord5(result.metadata), "tileflow:3d-toggle": visibilityGroup }
|
|
10143
10702
|
};
|
|
10144
10703
|
}
|
|
10145
10704
|
function lowerSelector(selector, data) {
|
|
10146
|
-
if (!
|
|
10705
|
+
if (!isRecord6(selector) || typeof selector.kind !== "string") {
|
|
10147
10706
|
throw renderStackError(
|
|
10148
10707
|
"invalid-selector",
|
|
10149
10708
|
"A render selector must be a semantic selector node."
|
|
@@ -10346,7 +10905,7 @@ function requireRenderer(value) {
|
|
|
10346
10905
|
function requirePlacement(value) {
|
|
10347
10906
|
if (typeof value === "string") {
|
|
10348
10907
|
if (tileflowBandPlacements.includes(value)) return;
|
|
10349
|
-
} else if (
|
|
10908
|
+
} else if (isRecord6(value)) {
|
|
10350
10909
|
const keys = Object.keys(value);
|
|
10351
10910
|
if (keys.length === 1 && (keys[0] === "above" || keys[0] === "below")) {
|
|
10352
10911
|
requirePortableTarget(value[keys[0]], "render placement target");
|
|
@@ -10373,7 +10932,7 @@ function validateRefinementShape(operation) {
|
|
|
10373
10932
|
validateStyle(operation.renderer, operation.style);
|
|
10374
10933
|
}
|
|
10375
10934
|
function validateStyle(renderer, style) {
|
|
10376
|
-
if (!
|
|
10935
|
+
if (!isRecord6(style)) {
|
|
10377
10936
|
throw renderStackError(
|
|
10378
10937
|
"invalid-style",
|
|
10379
10938
|
`A ${renderer} render operation requires a style object.`
|
|
@@ -10475,7 +11034,7 @@ function normalizeRequirements(requirements) {
|
|
|
10475
11034
|
return [...requirements];
|
|
10476
11035
|
}
|
|
10477
11036
|
function requireRenderStackEntries(stack) {
|
|
10478
|
-
if (!
|
|
11037
|
+
if (!isRecord6(stack)) {
|
|
10479
11038
|
throw renderStackError("invalid-stack", "A render stack must be a named operation record.");
|
|
10480
11039
|
}
|
|
10481
11040
|
const entries = Object.entries(stack);
|
|
@@ -10621,10 +11180,10 @@ function compareCodeUnits6(left, right) {
|
|
|
10621
11180
|
function cloneJson21(value) {
|
|
10622
11181
|
return JSON.parse(JSON.stringify(value));
|
|
10623
11182
|
}
|
|
10624
|
-
function
|
|
10625
|
-
return
|
|
11183
|
+
function asRecord5(value) {
|
|
11184
|
+
return isRecord6(value) ? value : {};
|
|
10626
11185
|
}
|
|
10627
|
-
function
|
|
11186
|
+
function isRecord6(value) {
|
|
10628
11187
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
10629
11188
|
}
|
|
10630
11189
|
|
|
@@ -10819,6 +11378,19 @@ function isLoopbackHostname(hostname) {
|
|
|
10819
11378
|
return normalized === "localhost" || normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/u.test(normalized);
|
|
10820
11379
|
}
|
|
10821
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
|
+
|
|
10822
11394
|
// src/resolved-map-schema.ts
|
|
10823
11395
|
var TileflowResolvedMapValidationError = class extends Error {
|
|
10824
11396
|
code = "CONFIG_INVALID";
|
|
@@ -10966,7 +11538,7 @@ function validateExpressionFieldNames(value, context, path) {
|
|
|
10966
11538
|
}
|
|
10967
11539
|
if (!value || typeof value !== "object") return;
|
|
10968
11540
|
const candidate = value;
|
|
10969
|
-
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))) {
|
|
10970
11542
|
context.addIssue({
|
|
10971
11543
|
code: "custom",
|
|
10972
11544
|
message: "Expected a registered semantic field name.",
|
|
@@ -11120,12 +11692,12 @@ var hexColorSchema = z5.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a
|
|
|
11120
11692
|
message: "Expected a hex color like #F6F7F3 or #F6F7F3FF"
|
|
11121
11693
|
});
|
|
11122
11694
|
var rgbColorSchema = z5.string().refine((value) => {
|
|
11123
|
-
const
|
|
11695
|
+
const match3 = value.match(
|
|
11124
11696
|
/^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)(?:\s*,\s*(\d+(?:\.\d+)?))?\s*\)$/iu
|
|
11125
11697
|
);
|
|
11126
|
-
if (!
|
|
11127
|
-
const channels =
|
|
11128
|
-
const alpha2 = Number(
|
|
11698
|
+
if (!match3) return false;
|
|
11699
|
+
const channels = match3.slice(1, 4).map(Number);
|
|
11700
|
+
const alpha2 = Number(match3[4] ?? 1);
|
|
11129
11701
|
return channels.every((channel) => channel >= 0 && channel <= 255) && alpha2 >= 0 && alpha2 <= 1;
|
|
11130
11702
|
}, "Expected a Tileflow hex, rgb(), or rgba() color");
|
|
11131
11703
|
var terrainColorLiteralSchema = z5.union([hexColorSchema, rgbColorSchema]);
|
|
@@ -11402,9 +11974,7 @@ var symbolStyleSchema = z5.object({
|
|
|
11402
11974
|
text: textStyleSchema.optional()
|
|
11403
11975
|
}).strict();
|
|
11404
11976
|
var markerSymbolStyleSchema = symbolStyleSchema.extend({ marker: circleStyleSchema.optional() }).strict();
|
|
11405
|
-
var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).
|
|
11406
|
-
density: z5.union([z5.literal(1), z5.literal(2), z5.literal(3), z5.literal(4), z5.literal(5)]).optional()
|
|
11407
|
-
}).strict();
|
|
11977
|
+
var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).strict();
|
|
11408
11978
|
var renderScalarSchema = z5.union([z5.boolean(), z5.number().finite(), z5.string()]);
|
|
11409
11979
|
var renderTargetSchema = z5.string().regex(tileflowSemanticTargetPattern, "Expected a semantic target");
|
|
11410
11980
|
var renderStackOperationNameSchema = z5.string().regex(
|
|
@@ -11637,6 +12207,8 @@ var waterModuleSchema = z5.object({
|
|
|
11637
12207
|
bathymetry: fillStyleSchema.optional(),
|
|
11638
12208
|
bathymetryContours: lineStyleSchema.optional(),
|
|
11639
12209
|
bathymetryLabels: symbolStyleSchema.optional(),
|
|
12210
|
+
bathymetryLandforms: symbolStyleSchema.optional(),
|
|
12211
|
+
bathymetryWaterNames: symbolStyleSchema.optional(),
|
|
11640
12212
|
bodies: areaStyleSchema.optional(),
|
|
11641
12213
|
enabled: z5.boolean().optional(),
|
|
11642
12214
|
intermittent: z5.object({ bodies: areaStyleSchema.optional(), waterways: lineStyleSchema.optional() }).strict().optional(),
|
|
@@ -11668,12 +12240,43 @@ var buildingsModuleSchema = z5.object({
|
|
|
11668
12240
|
mode: z5.enum(["3d", "flat"]).optional(),
|
|
11669
12241
|
renderStack: renderStackSchema.optional(),
|
|
11670
12242
|
threeDimensional: z5.object({
|
|
12243
|
+
lighting: z5.enum(["style", "sun"]).optional(),
|
|
12244
|
+
colorVariation: boundedThemeNumberSchema(0, 1).optional(),
|
|
11671
12245
|
edges: boundedThemeNumberSchema(0, 1).optional(),
|
|
11672
12246
|
edgeColor: themeColorValueSchema.optional(),
|
|
11673
12247
|
nightLight: boundedThemeNumberSchema(0, 2).optional(),
|
|
11674
12248
|
occlusion: z5.boolean().optional(),
|
|
11675
12249
|
shadows: z5.boolean().optional(),
|
|
11676
|
-
windows: 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()
|
|
11677
12280
|
}).strict().optional()
|
|
11678
12281
|
}).strict();
|
|
11679
12282
|
var addressesModuleSchema = z5.object({
|
|
@@ -11852,7 +12455,10 @@ var poiModuleSchema = z5.object({
|
|
|
11852
12455
|
minZoom: zoomNumberSchema.optional(),
|
|
11853
12456
|
placement: z5.object({
|
|
11854
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(),
|
|
11855
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(),
|
|
11856
12462
|
textPadding: z5.number().finite().min(0).optional()
|
|
11857
12463
|
}).strict().optional(),
|
|
11858
12464
|
renderStack: renderStackSchema.optional(),
|
|
@@ -11907,7 +12513,9 @@ var modulesSchema = z5.object({
|
|
|
11907
12513
|
type: z5.literal("vegetation"),
|
|
11908
12514
|
enabled: z5.boolean().optional(),
|
|
11909
12515
|
flat: circleStyleSchema.optional(),
|
|
11910
|
-
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(),
|
|
11911
12519
|
renderStack: renderStackSchema.optional(),
|
|
11912
12520
|
threeDimensional: z5.object({
|
|
11913
12521
|
barkColor: themeColorValueSchema.optional(),
|
|
@@ -12044,6 +12652,7 @@ var fieldBindingsSchema = z5.object({
|
|
|
12044
12652
|
markings: z5.string().trim().min(1),
|
|
12045
12653
|
minHeight: z5.string().trim().min(1),
|
|
12046
12654
|
minZoom: z5.string().trim().min(1),
|
|
12655
|
+
mode: z5.string().trim().min(1),
|
|
12047
12656
|
mtbScale: z5.string().trim().min(1),
|
|
12048
12657
|
name: z5.string().trim().min(1),
|
|
12049
12658
|
nameEnglish: z5.string().trim().min(1),
|
|
@@ -12147,6 +12756,32 @@ var bathymetryReliefSchema = z5.object({
|
|
|
12147
12756
|
});
|
|
12148
12757
|
}
|
|
12149
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
|
+
]);
|
|
12150
12785
|
var bathymetryConfigSchema = z5.object({
|
|
12151
12786
|
...marineSourceSchema.shape,
|
|
12152
12787
|
bands: z5.union([z5.literal(false), fillStyleSchema]).optional(),
|
|
@@ -12154,7 +12789,12 @@ var bathymetryConfigSchema = z5.object({
|
|
|
12154
12789
|
display: z5.enum(["bands", "relief", "hybrid"]).optional(),
|
|
12155
12790
|
labels: z5.union([z5.literal(false), symbolStyleSchema]).optional(),
|
|
12156
12791
|
relief: z5.union([z5.literal(false), bathymetryReliefSchema]).optional(),
|
|
12157
|
-
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()
|
|
12158
12798
|
}).strict();
|
|
12159
12799
|
var marineSchema = z5.union([
|
|
12160
12800
|
z5.enum(["none", "bathymetry", "nautical", "chart"]),
|
|
@@ -12509,6 +13149,10 @@ var resolvedTileflowMapSchema = z5.object({
|
|
|
12509
13149
|
systemThemes: systemThemesSchema.optional(),
|
|
12510
13150
|
terrain: terrainSchema.optional(),
|
|
12511
13151
|
themes: themesSchema,
|
|
13152
|
+
timeOfDay: createTileflowTimeOfDaySchema(
|
|
13153
|
+
classicManifestSchemaOperations,
|
|
13154
|
+
tileflowThemeNameSchema
|
|
13155
|
+
).optional(),
|
|
12512
13156
|
version: z5.number().int().positive(),
|
|
12513
13157
|
view: viewSchema.optional()
|
|
12514
13158
|
}).strict().superRefine((map, context) => {
|
|
@@ -12533,6 +13177,15 @@ var resolvedTileflowMapSchema = z5.object({
|
|
|
12533
13177
|
path: ["defaultTheme"]
|
|
12534
13178
|
});
|
|
12535
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
|
+
}
|
|
12536
13189
|
const themeEntries = Object.entries(map.themes).sort(
|
|
12537
13190
|
([left], [right]) => left < right ? -1 : left > right ? 1 : 0
|
|
12538
13191
|
);
|
|
@@ -12755,6 +13408,23 @@ function tileflowRouteMetadata(inks) {
|
|
|
12755
13408
|
return Object.freeze({ version: 1, ...inks });
|
|
12756
13409
|
}
|
|
12757
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
|
+
|
|
12758
13428
|
// src/terrain/index.ts
|
|
12759
13429
|
function resolveTerrain(terrain, apiBaseUrl) {
|
|
12760
13430
|
if (!terrain || terrain === "none") return void 0;
|
|
@@ -12933,7 +13603,7 @@ function terrainContribution(target, localOrder, layer) {
|
|
|
12933
13603
|
};
|
|
12934
13604
|
}
|
|
12935
13605
|
function applyLayerRange2(layer, range2) {
|
|
12936
|
-
const layout = { ...
|
|
13606
|
+
const layout = { ...asRecord6(layer.layout) };
|
|
12937
13607
|
if (range2.visible !== void 0) layout.visibility = range2.visible ? "visible" : "none";
|
|
12938
13608
|
return {
|
|
12939
13609
|
...layer,
|
|
@@ -12942,10 +13612,13 @@ function applyLayerRange2(layer, range2) {
|
|
|
12942
13612
|
...Object.keys(layout).length === 0 ? {} : { layout }
|
|
12943
13613
|
};
|
|
12944
13614
|
}
|
|
12945
|
-
function
|
|
13615
|
+
function asRecord6(value) {
|
|
12946
13616
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12947
13617
|
}
|
|
12948
13618
|
|
|
13619
|
+
// src/vegetation-display.ts
|
|
13620
|
+
var tileflowVegetationDisplayMetadataKey = "tileflow:vegetation-display";
|
|
13621
|
+
|
|
12949
13622
|
// src/cartography/compilation-report.ts
|
|
12950
13623
|
var tileflowCompilationReportSchemaVersion = 1;
|
|
12951
13624
|
var tileflowCompilationPhases = Object.freeze([
|
|
@@ -13317,14 +13990,16 @@ function defaultPaint(image, key, names, appearances, ids) {
|
|
|
13317
13990
|
|
|
13318
13991
|
// src/cartography/interaction-manifest.ts
|
|
13319
13992
|
var tileflowInteractionManifestMetadataKey = "tileflow:interaction-manifest";
|
|
13320
|
-
var tileflowInteractionManifestVersion =
|
|
13993
|
+
var tileflowInteractionManifestVersion = 3;
|
|
13321
13994
|
function createTileflowInteractionManifest(layers, fields) {
|
|
13322
13995
|
const poiLayers = layers.flatMap((layer, priority) => {
|
|
13323
13996
|
const id2 = typeof layer.id === "string" ? layer.id : void 0;
|
|
13324
13997
|
const source = typeof layer.source === "string" ? layer.source : void 0;
|
|
13325
13998
|
const sourceLayer = typeof layer["source-layer"] === "string" ? layer["source-layer"] : void 0;
|
|
13326
13999
|
const target = semanticTarget(layer);
|
|
13327
|
-
if (!id2 || !source || !sourceLayer || !target?.startsWith("poi."))
|
|
14000
|
+
if (!id2 || !source || !sourceLayer || target !== "poi" && !target?.startsWith("poi.")) {
|
|
14001
|
+
return [];
|
|
14002
|
+
}
|
|
13328
14003
|
const parsed = parsePoiTarget(target);
|
|
13329
14004
|
if (!parsed) return [];
|
|
13330
14005
|
return [
|
|
@@ -13372,7 +14047,7 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
|
|
|
13372
14047
|
);
|
|
13373
14048
|
}
|
|
13374
14049
|
for (const layer of poiLayers) {
|
|
13375
|
-
if (!
|
|
14050
|
+
if (!isSafeArtifactName(layer.layerId) || !isSafeArtifactName(layer.source) || !isSafeArtifactName(layer.sourceLayer)) {
|
|
13376
14051
|
throw new Error("Tileflow interaction manifest contains an invalid physical POI lookup.");
|
|
13377
14052
|
}
|
|
13378
14053
|
const finalized = layersById.get(layer.layerId);
|
|
@@ -13395,25 +14070,26 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
|
|
|
13395
14070
|
}
|
|
13396
14071
|
function parsePoiTarget(target) {
|
|
13397
14072
|
const segments = target.split(".");
|
|
13398
|
-
if (segments[0] !== "poi" || segments.length
|
|
13399
|
-
const
|
|
13400
|
-
if (
|
|
13401
|
-
|
|
13402
|
-
if (
|
|
13403
|
-
if (
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
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";
|
|
13407
14083
|
}
|
|
13408
14084
|
function isTileflowPoiCategory(value) {
|
|
13409
14085
|
return typeof value === "string" && tileflowPoiCategories.includes(value);
|
|
13410
14086
|
}
|
|
13411
14087
|
function semanticTarget(layer) {
|
|
13412
|
-
if (!
|
|
14088
|
+
if (!isRecord7(layer.metadata)) return void 0;
|
|
13413
14089
|
const value = layer.metadata[tileflowCompilerMetadataKeys.target];
|
|
13414
14090
|
return typeof value === "string" ? value : void 0;
|
|
13415
14091
|
}
|
|
13416
|
-
function
|
|
14092
|
+
function isRecord7(value) {
|
|
13417
14093
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
13418
14094
|
}
|
|
13419
14095
|
function isSafeArtifactName(value) {
|
|
@@ -14137,7 +14813,7 @@ function conditionalExpression(entries, fallback) {
|
|
|
14137
14813
|
];
|
|
14138
14814
|
}
|
|
14139
14815
|
const classMatches = entries.map(({ condition }) => splitClassMatch(condition));
|
|
14140
|
-
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))) {
|
|
14141
14817
|
return [
|
|
14142
14818
|
"match",
|
|
14143
14819
|
["get", classMatches[0].field],
|
|
@@ -14301,6 +14977,114 @@ function stableSerialize(value) {
|
|
|
14301
14977
|
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableSerialize(entry)}`).join(",")}}`;
|
|
14302
14978
|
}
|
|
14303
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
|
+
|
|
14304
15088
|
// src/cartography/semantic-compiler.ts
|
|
14305
15089
|
var tileflowSemanticCompilerIdentity = Object.freeze({
|
|
14306
15090
|
name: "tileflow-semantic",
|
|
@@ -14331,7 +15115,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14331
15115
|
suggestion,
|
|
14332
15116
|
...target ? { target } : {}
|
|
14333
15117
|
}));
|
|
14334
|
-
const selected = runCompilationPhase(
|
|
15118
|
+
const selected = runCompilationPhase(
|
|
15119
|
+
"theme",
|
|
15120
|
+
() => resolveThemeSelection(input, options.theme, options.timeOfDay)
|
|
15121
|
+
);
|
|
14335
15122
|
const resolvedTheme = runCompilationPhase("theme", () => resolveTileflowTheme(selected.theme));
|
|
14336
15123
|
const { overlays, themes: _themes, ...themeableConfig } = input;
|
|
14337
15124
|
const resolvedThemeConfig = runCompilationPhase(
|
|
@@ -14612,7 +15399,9 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14612
15399
|
const buildings3D = tileflowBuildings3DDesignOf(
|
|
14613
15400
|
modules.buildings,
|
|
14614
15401
|
context,
|
|
14615
|
-
layers
|
|
15402
|
+
layers,
|
|
15403
|
+
options.preparedAssets?.buildingModels,
|
|
15404
|
+
data.kind === "tileflow-world" ? `${apiBaseUrl}/landmarks/tiles.json` : void 0
|
|
14616
15405
|
);
|
|
14617
15406
|
const streetLights = tileflowStreetLightsDesignOf(
|
|
14618
15407
|
modules.roads,
|
|
@@ -14665,6 +15454,24 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14665
15454
|
layers
|
|
14666
15455
|
})
|
|
14667
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
|
+
}
|
|
14668
15475
|
const atmosphere = resolveTileflowAtmosphere(config.atmosphere);
|
|
14669
15476
|
const style = {
|
|
14670
15477
|
...atmosphere ? { sky: compileTileflowSky(atmosphere) } : {},
|
|
@@ -14704,12 +15511,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
|
|
|
14704
15511
|
[tileflowVegetationMetadataKey]: tileflowVegetationMetadata({
|
|
14705
15512
|
...bindSemanticReferences(vegetation3D, semanticData),
|
|
14706
15513
|
// The layers that draw the trees flat: the module's own and its render passes.
|
|
14707
|
-
flatLayers:
|
|
14708
|
-
const metadata = layer.metadata;
|
|
14709
|
-
return metadata?.["tileflow:vegetation-mode"] !== void 0 || metadata?.["tileflow:domain"] === "vegetation";
|
|
14710
|
-
}).map((layer) => String(layer.id))
|
|
15514
|
+
flatLayers: flatVegetationLayers.map((layer) => String(layer.id))
|
|
14711
15515
|
})
|
|
14712
15516
|
} : {},
|
|
15517
|
+
...vegetationDisplay ? { [tileflowVegetationDisplayMetadataKey]: vegetationDisplay } : {},
|
|
14713
15518
|
"tileflow:data": data.identity,
|
|
14714
15519
|
"tileflow:sources": sourceIdentities,
|
|
14715
15520
|
...Object.keys(loweredOverlays.identities).length > 0 ? { "tileflow:overlays": loweredOverlays.identities } : {},
|
|
@@ -15090,12 +15895,24 @@ function createTileflowRuntimeManifestSchema(primitives, operations, identities
|
|
|
15090
15895
|
})
|
|
15091
15896
|
),
|
|
15092
15897
|
themes: operations.record(tileflowThemeNameSchema2, manifestThemeSchema),
|
|
15898
|
+
timeOfDay: operations.optional(
|
|
15899
|
+
createTileflowTimeOfDaySchema(operations, tileflowThemeNameSchema2)
|
|
15900
|
+
),
|
|
15093
15901
|
usageMode: operations.optional(operations.literal("session")),
|
|
15094
15902
|
view: operations.optional(viewSchema3),
|
|
15095
15903
|
worldGeneration: operations.optional(operations.literal("v1"))
|
|
15096
15904
|
}),
|
|
15097
15905
|
(entry, context) => {
|
|
15098
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
|
+
}
|
|
15099
15916
|
if (names.length === 0) {
|
|
15100
15917
|
context.addIssue({
|
|
15101
15918
|
code: "custom",
|
|
@@ -15149,10 +15966,23 @@ function createTileflowRuntimeManifestSchema(primitives, operations, identities
|
|
|
15149
15966
|
operations.object({
|
|
15150
15967
|
apiUrl: operations.optional(apiOriginSchema),
|
|
15151
15968
|
maps: operations.record(tileflowPortableIdSchema2, manifestMapSchema),
|
|
15152
|
-
version: operations.
|
|
15969
|
+
version: operations.union(
|
|
15970
|
+
operations.literal(tileflowRuntimeManifestVersion),
|
|
15971
|
+
operations.literal(2)
|
|
15972
|
+
)
|
|
15153
15973
|
}),
|
|
15154
15974
|
(manifest, context) => {
|
|
15155
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
|
+
}
|
|
15156
15986
|
if (mapCount === 0) {
|
|
15157
15987
|
context.addIssue({ code: "custom", message: "Expected at least one map", path: ["maps"] });
|
|
15158
15988
|
}
|
|
@@ -15558,6 +16388,7 @@ var tileflowMapMergeStrategies = {
|
|
|
15558
16388
|
systemThemes: "atomic",
|
|
15559
16389
|
terrain: "atomic",
|
|
15560
16390
|
themes: "atomic",
|
|
16391
|
+
timeOfDay: "atomic",
|
|
15561
16392
|
version: "identity",
|
|
15562
16393
|
view: "deep"
|
|
15563
16394
|
};
|
|
@@ -15572,7 +16403,10 @@ function resolveMap(map, options = {}) {
|
|
|
15572
16403
|
for (let index = lineage.length - 1; index >= 0; index -= 1) {
|
|
15573
16404
|
const current = lineage[index];
|
|
15574
16405
|
const currentId = current.id;
|
|
15575
|
-
if (current.themes !== void 0)
|
|
16406
|
+
if (current.themes !== void 0) {
|
|
16407
|
+
delete design.systemThemes;
|
|
16408
|
+
delete design.timeOfDay;
|
|
16409
|
+
}
|
|
15576
16410
|
for (const key of Object.keys(current)) {
|
|
15577
16411
|
const value = current[key];
|
|
15578
16412
|
const strategy = tileflowMapMergeStrategies[key];
|
|
@@ -16350,6 +17184,7 @@ async function createTileflowMapBuildManifest(maps, options = {}) {
|
|
|
16350
17184
|
semanticCompiler: { ...tileflowSemanticCompilerIdentity },
|
|
16351
17185
|
sourceAssets,
|
|
16352
17186
|
...map.systemThemes ? { systemThemes: { ...map.systemThemes } } : {},
|
|
17187
|
+
...map.timeOfDay && Object.keys(map.timeOfDay).length ? { timeOfDay: map.timeOfDay } : {},
|
|
16353
17188
|
themes
|
|
16354
17189
|
}
|
|
16355
17190
|
];
|
|
@@ -16513,8 +17348,8 @@ function normalizeSourceAssets(input) {
|
|
|
16513
17348
|
}
|
|
16514
17349
|
const models = [...input.models ?? []].map((model) => {
|
|
16515
17350
|
assertSha256(model.sha256, `model ${model.id}`);
|
|
16516
|
-
if (model.level !== "near" && model.level !== "far")
|
|
16517
|
-
throw new Error(`Tileflow model ${model.id} is near or far.`);
|
|
17351
|
+
if (model.level !== "near" && model.level !== "mid" && model.level !== "far")
|
|
17352
|
+
throw new Error(`Tileflow model ${model.id} is near, mid or far.`);
|
|
16518
17353
|
return { id: model.id, level: model.level, sha256: model.sha256 };
|
|
16519
17354
|
}).sort(
|
|
16520
17355
|
(left, right) => compareCodeUnits8(`${left.id}\0${left.level}`, `${right.id}\0${right.level}`)
|
|
@@ -25296,7 +26131,7 @@ function createNativeUrlPolicy(parse) {
|
|
|
25296
26131
|
const resourcePath = resolved.href.slice(resolved.origin.length);
|
|
25297
26132
|
const suffix = resourcePath.replace(
|
|
25298
26133
|
new RegExp(`${prefix}(\\d+)__`, "gu"),
|
|
25299
|
-
(
|
|
26134
|
+
(match3, index) => placeholders[Number(index)] ?? match3
|
|
25300
26135
|
);
|
|
25301
26136
|
const result = resolved.origin + suffix;
|
|
25302
26137
|
assertUrlText(result, "resourceUrl");
|
|
@@ -25314,8 +26149,8 @@ function createNativeUrlPolicy(parse) {
|
|
|
25314
26149
|
if (value === void 0) return void 0;
|
|
25315
26150
|
try {
|
|
25316
26151
|
assertUrlText(value, "developmentOrigin");
|
|
25317
|
-
const
|
|
25318
|
-
if (!
|
|
26152
|
+
const match3 = /^(http:\/\/[^/?#]+)\/?$/iu.exec(value);
|
|
26153
|
+
if (!match3 || /[{}@*]/u.test(value)) throw new Error();
|
|
25319
26154
|
const url = parseUrl(value, "developmentOrigin");
|
|
25320
26155
|
if (url.protocol !== "http:" || url.pathname !== "/" || url.search || url.hash || url.hostname.includes("*")) {
|
|
25321
26156
|
throw new Error();
|
|
@@ -25726,11 +26561,11 @@ function parserIssuePointer(key, style) {
|
|
|
25726
26561
|
let path = "";
|
|
25727
26562
|
while (rest) {
|
|
25728
26563
|
if (Array.isArray(value)) {
|
|
25729
|
-
const
|
|
25730
|
-
if (!
|
|
25731
|
-
path = nativePointer(path,
|
|
25732
|
-
value = value[Number(
|
|
25733
|
-
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, "");
|
|
25734
26569
|
} else if (record2(value)) {
|
|
25735
26570
|
const matches = Object.keys(value).filter(
|
|
25736
26571
|
(name2) => rest === name2 || rest.startsWith(`${name2}.`) || rest.startsWith(`${name2}[`)
|
|
@@ -25823,7 +26658,11 @@ var mapBuildSchema = z15.object({
|
|
|
25823
26658
|
semanticCompiler: z15.object({ name: z15.literal("tileflow-semantic"), version: z15.literal(1) }).strict(),
|
|
25824
26659
|
sourceAssets: sourceAssetsSchema,
|
|
25825
26660
|
systemThemes: z15.object({ dark: tileflowThemeNameSchema, light: tileflowThemeNameSchema }).strict().optional(),
|
|
25826
|
-
themes: z15.record(tileflowThemeNameSchema, themeBuildSchema)
|
|
26661
|
+
themes: z15.record(tileflowThemeNameSchema, themeBuildSchema),
|
|
26662
|
+
timeOfDay: createTileflowTimeOfDaySchema(
|
|
26663
|
+
classicManifestSchemaOperations,
|
|
26664
|
+
tileflowThemeNameSchema
|
|
26665
|
+
).optional()
|
|
25827
26666
|
}).strict();
|
|
25828
26667
|
var buildManifestSchema = z15.object({
|
|
25829
26668
|
schemaVersion: z15.literal(1),
|
|
@@ -25885,6 +26724,8 @@ var tileflowRendererDeploymentArtifactSchema = z15.object({
|
|
|
25885
26724
|
const themes = Object.keys(map.themes).sort();
|
|
25886
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))
|
|
25887
26726
|
fail();
|
|
26727
|
+
if (map.timeOfDay && validateTileflowTimeOfDayVariants(map.timeOfDay, map.themes).length)
|
|
26728
|
+
fail();
|
|
25888
26729
|
for (const scheme of ["light", "dark"]) {
|
|
25889
26730
|
if (map.systemThemes && map.themes[map.systemThemes[scheme]]?.colorScheme !== scheme)
|
|
25890
26731
|
fail();
|
|
@@ -26000,7 +26841,7 @@ var artifactName = z15.string().min(1).max(256).refine(
|
|
|
26000
26841
|
})
|
|
26001
26842
|
);
|
|
26002
26843
|
var semanticSchema = z15.object({
|
|
26003
|
-
version: z15.literal(
|
|
26844
|
+
version: z15.literal(3),
|
|
26004
26845
|
domains: z15.object({
|
|
26005
26846
|
poi: z15.object({
|
|
26006
26847
|
deduplication: z15.object({
|
|
@@ -26032,7 +26873,6 @@ var semanticSchema = z15.object({
|
|
|
26032
26873
|
layers: z15.array(
|
|
26033
26874
|
z15.object({
|
|
26034
26875
|
anchor: z15.literal("pointer-coordinate"),
|
|
26035
|
-
category: z15.enum(tileflowPoiCategories),
|
|
26036
26876
|
layerId: artifactName,
|
|
26037
26877
|
priority: z15.number().int().min(0).max(4095),
|
|
26038
26878
|
representation: z15.enum(["combined", "icon", "label", "marker"]),
|
|
@@ -26204,6 +27044,7 @@ function createManifest(catalog, options = {}) {
|
|
|
26204
27044
|
defaultTheme: resolved.defaultTheme,
|
|
26205
27045
|
...resolved.systemThemes ? { systemThemes: resolved.systemThemes } : {},
|
|
26206
27046
|
themes,
|
|
27047
|
+
...options.manifestVersion !== 1 && resolved.timeOfDay && Object.keys(resolved.timeOfDay).length ? { timeOfDay: resolved.timeOfDay } : {},
|
|
26207
27048
|
...resolved.view ? { view: resolved.view } : {}
|
|
26208
27049
|
}
|
|
26209
27050
|
];
|
|
@@ -26211,7 +27052,7 @@ function createManifest(catalog, options = {}) {
|
|
|
26211
27052
|
);
|
|
26212
27053
|
const manifest = {
|
|
26213
27054
|
maps,
|
|
26214
|
-
version: tileflowRuntimeManifestVersion
|
|
27055
|
+
version: options.manifestVersion ?? (Object.values(maps).some((map) => map.timeOfDay) ? 2 : tileflowRuntimeManifestVersion)
|
|
26215
27056
|
};
|
|
26216
27057
|
return parseTileflowRuntimeManifest(manifest);
|
|
26217
27058
|
}
|