@tomtom-org/maps-sdk 0.30.2 → 0.31.1
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/CHANGELOG.md +14 -0
- package/README.md +4 -3
- package/core/dist/core.cjs.js +19 -1
- package/core/dist/core.cjs.js.map +1 -1
- package/core/dist/core.cjs.min.js +1 -1
- package/core/dist/core.cjs.min.js.map +1 -1
- package/core/dist/core.es.js +1 -1
- package/core/dist/core.es.js.map +1 -1
- package/core/dist/index.d.ts +22 -7
- package/core/package.json +0 -8
- package/map/dist/THIRD_PARTY.txt +132 -5
- package/map/dist/index.d.ts +246 -147
- package/map/dist/map.cjs.js +261 -150
- package/map/dist/map.cjs.js.map +1 -1
- package/map/dist/map.cjs.min.js +1 -1
- package/map/dist/map.cjs.min.js.map +1 -1
- package/map/dist/map.es.js +1 -1
- package/map/dist/map.es.js.map +1 -1
- package/map/package.json +0 -8
- package/package.json +3 -13
- package/services/dist/index.d.ts +119 -106
- package/services/dist/services.cjs.js +51 -1
- package/services/dist/services.cjs.js.map +1 -1
- package/services/dist/services.cjs.min.js +1 -1
- package/services/dist/services.cjs.min.js.map +1 -1
- package/services/dist/services.es.js +1 -1
- package/services/dist/services.es.js.map +1 -1
- package/services/package.json +0 -8
- package/sdk-examples-collage.png +0 -0
- package/tomtom-logo-big.svg +0 -6
package/map/dist/map.cjs.js
CHANGED
|
@@ -2289,6 +2289,14 @@ class GeoJSONSourceWithLayers extends AddedSourceWithLayers {
|
|
|
2289
2289
|
clear() {
|
|
2290
2290
|
this.show(emptyFeatureCollection);
|
|
2291
2291
|
}
|
|
2292
|
+
findFeature(options) {
|
|
2293
|
+
if ("index" in options) {
|
|
2294
|
+
return this.shownFeatures.features[options.index];
|
|
2295
|
+
} else if ("id" in options) {
|
|
2296
|
+
return this.shownFeatures.features.find((f) => f.id === options.id);
|
|
2297
|
+
}
|
|
2298
|
+
return void 0;
|
|
2299
|
+
}
|
|
2292
2300
|
putEventState(options) {
|
|
2293
2301
|
const mode = options.mode ?? "put";
|
|
2294
2302
|
if (mode === "put") {
|
|
@@ -2298,7 +2306,7 @@ class GeoJSONSourceWithLayers extends AddedSourceWithLayers {
|
|
|
2298
2306
|
}
|
|
2299
2307
|
}
|
|
2300
2308
|
}
|
|
2301
|
-
const feature = this.
|
|
2309
|
+
const feature = this.findFeature(options);
|
|
2302
2310
|
if (feature) {
|
|
2303
2311
|
feature.properties = { ...feature.properties, eventState: options.state };
|
|
2304
2312
|
}
|
|
@@ -2307,7 +2315,7 @@ class GeoJSONSourceWithLayers extends AddedSourceWithLayers {
|
|
|
2307
2315
|
}
|
|
2308
2316
|
}
|
|
2309
2317
|
cleanEventState(options) {
|
|
2310
|
-
const feature = this.
|
|
2318
|
+
const feature = this.findFeature(options);
|
|
2311
2319
|
if (feature?.properties?.eventState) {
|
|
2312
2320
|
delete feature?.properties?.eventState;
|
|
2313
2321
|
if (options?.show !== false) {
|
|
@@ -2789,15 +2797,16 @@ const toMapDisplayPOICategory = (category) => (
|
|
|
2789
2797
|
// if it's one of the different categories between search and poi layer, use poi layer category
|
|
2790
2798
|
category in mapDisplayPoiCategoryMappings ? mapDisplayPoiCategoryMappings[category] : category.toLowerCase()
|
|
2791
2799
|
);
|
|
2800
|
+
const MAP_BOLD_FONT = "Noto-Bold";
|
|
2801
|
+
const MAP_MEDIUM_FONT = "Noto-Medium";
|
|
2802
|
+
const DEFAULT_TEXT_SIZE = ["interpolate", ["linear"], ["zoom"], 10, 14, 18, 16];
|
|
2803
|
+
const PIN_ICON_SIZE = ["interpolate", ["linear"], ["zoom"], 8, 0.6, 22, 0.8];
|
|
2804
|
+
const SELECTED_PIN_ICON_SIZE = ["interpolate", ["linear"], ["zoom"], 8, 0.8, 22, 1];
|
|
2792
2805
|
const isClickEventState = [
|
|
2793
2806
|
"in",
|
|
2794
2807
|
["get", "eventState"],
|
|
2795
2808
|
["literal", ["click", "contextmenu"]]
|
|
2796
2809
|
];
|
|
2797
|
-
const MAP_BOLD_FONT = "Noto-Bold";
|
|
2798
|
-
const MAP_MEDIUM_FONT = "Noto-Medium";
|
|
2799
|
-
const DEFAULT_TEXT_SIZE = ["interpolate", ["linear"], ["zoom"], 10, 14, 18, 16];
|
|
2800
|
-
const PIN_ICON_SIZE = ["interpolate", ["linear"], ["zoom"], 8, 0.6, 22, 0.8];
|
|
2801
2810
|
const TITLE = "title";
|
|
2802
2811
|
const ICON_ID = "iconID";
|
|
2803
2812
|
const pinIconBaseLayout = {
|
|
@@ -2817,7 +2826,8 @@ const pinTextBaseLayout = {
|
|
|
2817
2826
|
"text-field": ["get", TITLE],
|
|
2818
2827
|
"text-justify": "auto",
|
|
2819
2828
|
"text-variable-anchor": ["top", "left", "right"],
|
|
2820
|
-
|
|
2829
|
+
// NOTE: make sure to text against pins and waypoints, in a way that there's enough distance from the pin so the text doesn't disappear
|
|
2830
|
+
"text-variable-anchor-offset": ["top", [0, 0.7], "left", [1.4, -1.4], "right", [-1.4, -1.4]],
|
|
2821
2831
|
"text-size": DEFAULT_TEXT_SIZE,
|
|
2822
2832
|
"text-padding": 5
|
|
2823
2833
|
};
|
|
@@ -2849,8 +2859,7 @@ const selectedPlaceLayerSpec = {
|
|
|
2849
2859
|
filter: hasEventState,
|
|
2850
2860
|
layout: {
|
|
2851
2861
|
...pinLayerBaseSpec.layout,
|
|
2852
|
-
|
|
2853
|
-
"icon-size": ["interpolate", ["linear"], ["zoom"], 8, 0.8, 22, 1],
|
|
2862
|
+
"icon-size": SELECTED_PIN_ICON_SIZE,
|
|
2854
2863
|
"text-allow-overlap": true
|
|
2855
2864
|
},
|
|
2856
2865
|
paint: {
|
|
@@ -2858,30 +2867,27 @@ const selectedPlaceLayerSpec = {
|
|
|
2858
2867
|
"text-color": SELECTED_COLOR
|
|
2859
2868
|
}
|
|
2860
2869
|
};
|
|
2861
|
-
const
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
};
|
|
2865
|
-
const withConfig = (layerSpec, config, id) => {
|
|
2866
|
-
const textConfig = config?.textConfig;
|
|
2870
|
+
const withConfig = (layerSpec, config, layerName) => {
|
|
2871
|
+
const textConfig = config?.text;
|
|
2872
|
+
const customLayer = config?.layers?.[layerName];
|
|
2867
2873
|
return {
|
|
2868
2874
|
...layerSpec,
|
|
2869
|
-
id,
|
|
2870
2875
|
layout: {
|
|
2871
2876
|
...layerSpec.layout,
|
|
2872
|
-
...textConfig?.
|
|
2873
|
-
...textConfig?.
|
|
2874
|
-
...textConfig?.
|
|
2875
|
-
...textConfig?.
|
|
2876
|
-
"text-field": textConfig?.
|
|
2877
|
+
...textConfig?.size && { "text-size": textConfig.size },
|
|
2878
|
+
...textConfig?.font && { "text-font": textConfig.font },
|
|
2879
|
+
...textConfig?.offset && { "text-offset": textConfig.offset },
|
|
2880
|
+
...textConfig?.title && typeof textConfig?.title !== "function" && {
|
|
2881
|
+
"text-field": textConfig?.title
|
|
2877
2882
|
}
|
|
2878
2883
|
},
|
|
2879
2884
|
paint: {
|
|
2880
2885
|
...layerSpec.paint,
|
|
2881
|
-
...textConfig?.
|
|
2882
|
-
...textConfig?.
|
|
2883
|
-
...textConfig?.
|
|
2884
|
-
}
|
|
2886
|
+
...textConfig?.color && { "text-color": textConfig.color },
|
|
2887
|
+
...textConfig?.haloColor && { "text-halo-color": textConfig.haloColor },
|
|
2888
|
+
...textConfig?.haloWidth && { "text-halo-width": textConfig.haloWidth }
|
|
2889
|
+
},
|
|
2890
|
+
...customLayer
|
|
2885
2891
|
};
|
|
2886
2892
|
};
|
|
2887
2893
|
const getTextSizeSpec = (textSize) => {
|
|
@@ -2902,14 +2908,36 @@ const buildPoiLikeLayerSpec = (map) => {
|
|
|
2902
2908
|
}
|
|
2903
2909
|
};
|
|
2904
2910
|
};
|
|
2905
|
-
const buildPlacesLayerSpecs = (config,
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2911
|
+
const buildPlacesLayerSpecs = (config, map) => {
|
|
2912
|
+
let layerSpecTemplates;
|
|
2913
|
+
if (config?.theme === "base-map") {
|
|
2914
|
+
const poiLikeLayerSpec = buildPoiLikeLayerSpec(map);
|
|
2915
|
+
layerSpecTemplates = {
|
|
2916
|
+
main: poiLikeLayerSpec,
|
|
2917
|
+
selected: {
|
|
2918
|
+
...poiLikeLayerSpec,
|
|
2919
|
+
filter: hasEventState,
|
|
2920
|
+
layout: {
|
|
2921
|
+
...poiLikeLayerSpec.layout,
|
|
2922
|
+
"text-allow-overlap": true
|
|
2923
|
+
},
|
|
2924
|
+
paint: {
|
|
2925
|
+
...poiLikeLayerSpec.paint,
|
|
2926
|
+
"text-color": SELECTED_COLOR
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
};
|
|
2930
|
+
} else {
|
|
2931
|
+
layerSpecTemplates = {
|
|
2932
|
+
main: placesLayerSpec,
|
|
2933
|
+
selected: selectedPlaceLayerSpec
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
return {
|
|
2937
|
+
main: withConfig(layerSpecTemplates.main, config, "main"),
|
|
2938
|
+
selected: withConfig(layerSpecTemplates.selected, config, "selected"),
|
|
2939
|
+
...config?.layers?.additional
|
|
2940
|
+
};
|
|
2913
2941
|
};
|
|
2914
2942
|
const supportedPinSubcategories = /* @__PURE__ */ new Set([
|
|
2915
2943
|
7339002,
|
|
@@ -2966,9 +2994,9 @@ const toMapDisplayPin = (place) => {
|
|
|
2966
2994
|
return categoryID.toString().substring(0, 4);
|
|
2967
2995
|
};
|
|
2968
2996
|
const buildPlaceTitle = (place) => place.properties.poi?.name ?? place.properties.address.freeformAddress;
|
|
2969
|
-
const getIconIDForPlace = (place, config = {}
|
|
2970
|
-
const iconStyle = config.
|
|
2971
|
-
const customIcons = config.
|
|
2997
|
+
const getIconIDForPlace = (place, config = {}) => {
|
|
2998
|
+
const iconStyle = config.theme ?? "pin";
|
|
2999
|
+
const customIcons = config.icon?.customIcons;
|
|
2972
3000
|
const classificationCode = place.properties.poi?.classifications?.[0]?.code;
|
|
2973
3001
|
const matchingCustomIcon = customIcons?.find((customIcon) => customIcon.id === classificationCode);
|
|
2974
3002
|
if (matchingCustomIcon) {
|
|
@@ -2997,7 +3025,7 @@ const preparePlacesForDisplay = (placesInput, map, config = {}) => {
|
|
|
2997
3025
|
return {
|
|
2998
3026
|
...places,
|
|
2999
3027
|
features: places.features.map((place) => {
|
|
3000
|
-
const title = typeof config?.
|
|
3028
|
+
const title = typeof config?.text?.title === "function" ? config?.text?.title(place) : buildPlaceTitle(place);
|
|
3001
3029
|
const extraFeatureProps = config.extraFeatureProps ? Object.fromEntries(
|
|
3002
3030
|
Object.entries(config.extraFeatureProps).map(([prop, value]) => [
|
|
3003
3031
|
prop,
|
|
@@ -3015,9 +3043,7 @@ const preparePlacesForDisplay = (placesInput, map, config = {}) => {
|
|
|
3015
3043
|
id: place.id,
|
|
3016
3044
|
title,
|
|
3017
3045
|
iconID: getIconIDForPlace(place, config),
|
|
3018
|
-
...config?.
|
|
3019
|
-
category: getPOILayerCategoryForPlace(place)
|
|
3020
|
-
},
|
|
3046
|
+
...config?.theme === "base-map" && { category: getPOILayerCategoryForPlace(place) },
|
|
3021
3047
|
...extraFeatureProps
|
|
3022
3048
|
}
|
|
3023
3049
|
};
|
|
@@ -3049,15 +3075,28 @@ const _PlacesModule = class _PlacesModule extends AbstractMapModule {
|
|
|
3049
3075
|
this.sourceID = `${PLACES_SOURCE_PREFIX_ID}-${this.instanceIndex}`;
|
|
3050
3076
|
this.layerIDPrefix = `placesSymbols-${this.instanceIndex}`;
|
|
3051
3077
|
}
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3078
|
+
this.layerSpecs = this.buildLayerSpecs(config);
|
|
3079
|
+
return {
|
|
3080
|
+
places: new GeoJSONSourceWithLayers(this.mapLibreMap, this.sourceID, [
|
|
3081
|
+
this.layerSpecs.main,
|
|
3082
|
+
this.layerSpecs.selected
|
|
3083
|
+
])
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
buildLayerSpecs(config) {
|
|
3087
|
+
const layerSpecTemplates = buildPlacesLayerSpecs(config, this.mapLibreMap);
|
|
3088
|
+
return Object.fromEntries(
|
|
3089
|
+
Object.entries(layerSpecTemplates).map(([key, spec]) => [
|
|
3090
|
+
key,
|
|
3091
|
+
{ ...spec, id: `${this.layerIDPrefix}-${key}` }
|
|
3092
|
+
])
|
|
3093
|
+
);
|
|
3055
3094
|
}
|
|
3056
3095
|
/**
|
|
3057
3096
|
* @ignore
|
|
3058
3097
|
*/
|
|
3059
3098
|
_applyConfig(config) {
|
|
3060
|
-
if (config?.
|
|
3099
|
+
if (config?.theme || config?.icon || config?.text) {
|
|
3061
3100
|
this.updateLayersAndData(config);
|
|
3062
3101
|
} else if (config?.extraFeatureProps) {
|
|
3063
3102
|
this.updateData(config);
|
|
@@ -3073,6 +3112,35 @@ const _PlacesModule = class _PlacesModule extends AbstractMapModule {
|
|
|
3073
3112
|
this.config && this._applyConfig(this.config);
|
|
3074
3113
|
this.show(previousShownFeatures);
|
|
3075
3114
|
}
|
|
3115
|
+
/**
|
|
3116
|
+
* Updates the visual theme for displayed places.
|
|
3117
|
+
*
|
|
3118
|
+
* @param theme - The theme style to apply to place markers.
|
|
3119
|
+
*
|
|
3120
|
+
* @remarks
|
|
3121
|
+
* **Available Themes:**
|
|
3122
|
+
* - `pin`: Traditional teardrop-shaped map pins
|
|
3123
|
+
* - `circle`: Simple circular markers
|
|
3124
|
+
* - `base-map`: Mimics the map's built-in POI layer style with category icons
|
|
3125
|
+
*
|
|
3126
|
+
* Changes apply immediately to all currently shown places. Other configuration
|
|
3127
|
+
* properties (icon config, text config) remain unchanged.
|
|
3128
|
+
*
|
|
3129
|
+
* @example
|
|
3130
|
+
* ```typescript
|
|
3131
|
+
* // Switch to pin markers
|
|
3132
|
+
* places.applyTheme('pin');
|
|
3133
|
+
*
|
|
3134
|
+
* // Use simple circles
|
|
3135
|
+
* places.applyTheme('circle');
|
|
3136
|
+
*
|
|
3137
|
+
* // Match map's POI style (ideal to blend in)
|
|
3138
|
+
* places.applyTheme('base-map');
|
|
3139
|
+
* ```
|
|
3140
|
+
*/
|
|
3141
|
+
applyTheme(theme) {
|
|
3142
|
+
this.applyConfigPart({ theme });
|
|
3143
|
+
}
|
|
3076
3144
|
/**
|
|
3077
3145
|
* Updates the icon configuration for displayed places.
|
|
3078
3146
|
*
|
|
@@ -3086,21 +3154,14 @@ const _PlacesModule = class _PlacesModule extends AbstractMapModule {
|
|
|
3086
3154
|
* @example
|
|
3087
3155
|
* ```typescript
|
|
3088
3156
|
* places.applyIconConfig({
|
|
3089
|
-
* iconStyle: 'circle'
|
|
3090
|
-
* });
|
|
3091
|
-
*
|
|
3092
|
-
* // Add custom icons
|
|
3093
|
-
* places.applyIconConfig({
|
|
3094
3157
|
* customIcons: [
|
|
3095
|
-
* { category: 'RESTAURANT', image: '/icons/food.png' }
|
|
3158
|
+
* { category: 'RESTAURANT', id: 'restaurant-icon', image: '/icons/food.png' }
|
|
3096
3159
|
* ]
|
|
3097
3160
|
* });
|
|
3098
3161
|
* ```
|
|
3099
3162
|
*/
|
|
3100
3163
|
applyIconConfig(iconConfig) {
|
|
3101
|
-
|
|
3102
|
-
this.updateLayersAndData(config);
|
|
3103
|
-
this.config = config;
|
|
3164
|
+
this.applyConfigPart({ icon: iconConfig });
|
|
3104
3165
|
}
|
|
3105
3166
|
/**
|
|
3106
3167
|
* Updates the text/label configuration for displayed places.
|
|
@@ -3114,19 +3175,22 @@ const _PlacesModule = class _PlacesModule extends AbstractMapModule {
|
|
|
3114
3175
|
* ```typescript
|
|
3115
3176
|
* // Use function
|
|
3116
3177
|
* places.applyTextConfig({
|
|
3117
|
-
*
|
|
3178
|
+
* field: (place) => place.properties.poi?.name || 'Unknown'
|
|
3118
3179
|
* });
|
|
3119
3180
|
*
|
|
3120
3181
|
* // Use MapLibre expression
|
|
3121
3182
|
* places.applyTextConfig({
|
|
3122
|
-
*
|
|
3123
|
-
*
|
|
3124
|
-
*
|
|
3183
|
+
* field: ['get', 'title'],
|
|
3184
|
+
* size: 14,
|
|
3185
|
+
* color: '#333'
|
|
3125
3186
|
* });
|
|
3126
3187
|
* ```
|
|
3127
3188
|
*/
|
|
3128
3189
|
applyTextConfig(textConfig) {
|
|
3129
|
-
|
|
3190
|
+
this.applyConfigPart({ text: textConfig });
|
|
3191
|
+
}
|
|
3192
|
+
applyConfigPart(partialConfig) {
|
|
3193
|
+
const config = { ...this.config, ...partialConfig };
|
|
3130
3194
|
this.updateLayersAndData(config);
|
|
3131
3195
|
this.config = config;
|
|
3132
3196
|
}
|
|
@@ -3153,13 +3217,15 @@ const _PlacesModule = class _PlacesModule extends AbstractMapModule {
|
|
|
3153
3217
|
this.config = config;
|
|
3154
3218
|
}
|
|
3155
3219
|
updateLayersAndData(config) {
|
|
3156
|
-
for (const customIcon of config?.
|
|
3220
|
+
for (const customIcon of config?.icon?.customIcons ?? []) {
|
|
3157
3221
|
addImageIfNotExisting(this.mapLibreMap, customIcon.id, customIcon.image, {
|
|
3158
3222
|
pixelRatio: customIcon.pixelRatio ?? 2
|
|
3159
3223
|
});
|
|
3160
3224
|
}
|
|
3161
|
-
const newLayerSpecs =
|
|
3162
|
-
|
|
3225
|
+
const newLayerSpecs = this.buildLayerSpecs(config);
|
|
3226
|
+
const newLayerSpecsArray = [newLayerSpecs.main, newLayerSpecs.selected];
|
|
3227
|
+
const oldLayerSpecsArray = [this.layerSpecs.main, this.layerSpecs.selected];
|
|
3228
|
+
changeLayersProps(newLayerSpecsArray, oldLayerSpecsArray, this.mapLibreMap);
|
|
3163
3229
|
this.layerSpecs = newLayerSpecs;
|
|
3164
3230
|
this.updateData(config);
|
|
3165
3231
|
}
|
|
@@ -4213,7 +4279,7 @@ const buildGeometryLayerSpecs = (fillLayerId, outlineLayerId, config) => {
|
|
|
4213
4279
|
};
|
|
4214
4280
|
return [fillLayerSpec, outlineLayerSpec];
|
|
4215
4281
|
};
|
|
4216
|
-
const buildTitle = (feature, config) => {
|
|
4282
|
+
const buildTitle$1 = (feature, config) => {
|
|
4217
4283
|
if (config.textConfig?.textField) {
|
|
4218
4284
|
return config.textConfig.textField;
|
|
4219
4285
|
}
|
|
@@ -4251,7 +4317,7 @@ const buildGeometryTitleLayerSpec = (layerId, config) => {
|
|
|
4251
4317
|
const prepareGeometryForDisplay = (geometry, config = {}) => ({
|
|
4252
4318
|
...geometry,
|
|
4253
4319
|
features: geometry.features.map((feature, index) => {
|
|
4254
|
-
const title = feature.properties?.title ? feature.properties.title : buildTitle(feature, config);
|
|
4320
|
+
const title = feature.properties?.title ? feature.properties.title : buildTitle$1(feature, config);
|
|
4255
4321
|
const color = feature.properties?.color ? feature.properties.color : buildColor(config, index);
|
|
4256
4322
|
return { ...feature, properties: { ...feature.properties, title, color } };
|
|
4257
4323
|
})
|
|
@@ -4969,9 +5035,7 @@ const EXTRA_FOREGROUND_LINE_WIDTH = [
|
|
|
4969
5035
|
];
|
|
4970
5036
|
const routeIncidentsBGLine = {
|
|
4971
5037
|
type: "line",
|
|
4972
|
-
layout: {
|
|
4973
|
-
"line-join": "round"
|
|
4974
|
-
},
|
|
5038
|
+
layout: { "line-cap": "round" },
|
|
4975
5039
|
paint: {
|
|
4976
5040
|
"line-width": EXTRA_FOREGROUND_LINE_WIDTH,
|
|
4977
5041
|
"line-color": [
|
|
@@ -4991,9 +5055,7 @@ const routeIncidentsBGLine = {
|
|
|
4991
5055
|
const routeIncidentsDashedLine = {
|
|
4992
5056
|
type: "line",
|
|
4993
5057
|
filter: ["in", ["get", "magnitudeOfDelay"], ["literal", ["unknown", "indefinite"]]],
|
|
4994
|
-
layout: {
|
|
4995
|
-
"line-join": "round"
|
|
4996
|
-
},
|
|
5058
|
+
layout: { "line-join": "round" },
|
|
4997
5059
|
paint: {
|
|
4998
5060
|
"line-width": EXTRA_FOREGROUND_LINE_WIDTH,
|
|
4999
5061
|
"line-color": [
|
|
@@ -5007,28 +5069,6 @@ const routeIncidentsDashedLine = {
|
|
|
5007
5069
|
"line-dasharray": [1.5, 1]
|
|
5008
5070
|
}
|
|
5009
5071
|
};
|
|
5010
|
-
const routeIncidentsPatternLine = {
|
|
5011
|
-
type: "line",
|
|
5012
|
-
filter: ["in", ["get", "magnitudeOfDelay"], ["literal", ["minor", "moderate", "major"]]],
|
|
5013
|
-
layout: {
|
|
5014
|
-
"line-join": "round"
|
|
5015
|
-
},
|
|
5016
|
-
paint: {
|
|
5017
|
-
"line-width": EXTRA_FOREGROUND_LINE_WIDTH,
|
|
5018
|
-
"line-pattern": [
|
|
5019
|
-
"match",
|
|
5020
|
-
["get", "magnitudeOfDelay"],
|
|
5021
|
-
"minor",
|
|
5022
|
-
"traffic-incidents-minor-pattern",
|
|
5023
|
-
"moderate",
|
|
5024
|
-
"traffic-incidents-moderate-pattern",
|
|
5025
|
-
"major",
|
|
5026
|
-
"traffic-incidents-major-pattern",
|
|
5027
|
-
// other
|
|
5028
|
-
"traffic-incidents-no_delay-pattern"
|
|
5029
|
-
]
|
|
5030
|
-
}
|
|
5031
|
-
};
|
|
5032
5072
|
const magnitudeOfDelayTextColor = [
|
|
5033
5073
|
"match",
|
|
5034
5074
|
["get", "magnitudeOfDelay"],
|
|
@@ -5043,29 +5083,48 @@ const magnitudeOfDelayTextColor = [
|
|
|
5043
5083
|
// other
|
|
5044
5084
|
UNKNOWN_DELAY_COLOR
|
|
5045
5085
|
];
|
|
5046
|
-
const
|
|
5086
|
+
const routeIncidentsSymbolBase = {
|
|
5047
5087
|
filter: SELECTED_ROUTE_FILTER,
|
|
5048
5088
|
type: "symbol",
|
|
5049
5089
|
minzoom: 6,
|
|
5050
5090
|
layout: {
|
|
5051
5091
|
"symbol-placement": "point",
|
|
5052
5092
|
"symbol-avoid-edges": true,
|
|
5053
|
-
"icon-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5093
|
+
"icon-ignore-placement": true
|
|
5094
|
+
}
|
|
5095
|
+
};
|
|
5096
|
+
const routeIncidentsJamSymbol = {
|
|
5097
|
+
...routeIncidentsSymbolBase,
|
|
5098
|
+
filter: ["all", ["has", "jamIconID"], routeIncidentsSymbolBase.filter],
|
|
5099
|
+
layout: {
|
|
5100
|
+
...routeIncidentsSymbolBase.layout,
|
|
5101
|
+
"icon-image": ["get", "jamIconID"],
|
|
5102
|
+
"icon-anchor": "bottom-left",
|
|
5103
|
+
"text-anchor": "bottom-left",
|
|
5104
|
+
// Jam symbols have delay labels in them:
|
|
5057
5105
|
"text-field": ["get", "title"],
|
|
5058
5106
|
"text-font": [MAP_BOLD_FONT],
|
|
5059
|
-
"text-
|
|
5060
|
-
"text-
|
|
5061
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 6, 11, 10, 13]
|
|
5107
|
+
"text-offset": [3.9, -1.4],
|
|
5108
|
+
"text-size": 13
|
|
5062
5109
|
},
|
|
5063
5110
|
paint: {
|
|
5111
|
+
...routeIncidentsSymbolBase.paint,
|
|
5064
5112
|
"text-color": magnitudeOfDelayTextColor,
|
|
5065
5113
|
"text-halo-color": "#FFFFFF",
|
|
5066
5114
|
"text-halo-width": 1
|
|
5067
5115
|
}
|
|
5068
5116
|
};
|
|
5117
|
+
const routeIncidentsCauseSymbol = {
|
|
5118
|
+
...routeIncidentsSymbolBase,
|
|
5119
|
+
filter: ["all", ["has", "causeIconID"], routeIncidentsSymbolBase.filter],
|
|
5120
|
+
layout: {
|
|
5121
|
+
...routeIncidentsSymbolBase.layout,
|
|
5122
|
+
"icon-image": ["get", "causeIconID"],
|
|
5123
|
+
"icon-anchor": "bottom-right"
|
|
5124
|
+
// Cause symbols have no label in them.
|
|
5125
|
+
},
|
|
5126
|
+
paint: { ...routeIncidentsSymbolBase.paint }
|
|
5127
|
+
};
|
|
5069
5128
|
const routeTunnelsLine = {
|
|
5070
5129
|
filter: SELECTED_ROUTE_FILTER,
|
|
5071
5130
|
type: "line",
|
|
@@ -5290,27 +5349,26 @@ const buildRoutingLayers = (config = {}) => {
|
|
|
5290
5349
|
},
|
|
5291
5350
|
sections: {
|
|
5292
5351
|
incident: {
|
|
5293
|
-
|
|
5294
|
-
...
|
|
5352
|
+
routeIncidentJamSymbol: {
|
|
5353
|
+
...routeIncidentsJamSymbol,
|
|
5295
5354
|
beforeID: "routeChargingStopSymbol",
|
|
5296
|
-
...configSectionLayers?.incident?.
|
|
5355
|
+
...configSectionLayers?.incident?.routeIncidentJamSymbol
|
|
5356
|
+
},
|
|
5357
|
+
routeIncidentCauseSymbol: {
|
|
5358
|
+
...routeIncidentsCauseSymbol,
|
|
5359
|
+
beforeID: "routeChargingStopSymbol",
|
|
5360
|
+
...configSectionLayers?.incident?.routeIncidentCauseSymbol
|
|
5297
5361
|
},
|
|
5298
5362
|
routeIncidentBackgroundLine: {
|
|
5299
5363
|
...routeIncidentsBGLine,
|
|
5300
|
-
beforeID:
|
|
5364
|
+
beforeID: "routeIncidentDashedLine",
|
|
5301
5365
|
...configSectionLayers?.incident?.routeIncidentBackgroundLine
|
|
5302
5366
|
},
|
|
5303
5367
|
routeIncidentDashedLine: {
|
|
5304
5368
|
...routeIncidentsDashedLine,
|
|
5305
5369
|
beforeID: mapStyleLayerIDs.lowestLabel,
|
|
5306
5370
|
...configSectionLayers?.incident?.routeIncidentDashedLine
|
|
5307
|
-
}
|
|
5308
|
-
routeIncidentPatternLine: {
|
|
5309
|
-
...routeIncidentsPatternLine,
|
|
5310
|
-
beforeID: mapStyleLayerIDs.lowestLabel,
|
|
5311
|
-
...configSectionLayers?.incident?.routeIncidentPatternLine
|
|
5312
|
-
},
|
|
5313
|
-
...configLayers?.sections?.incident?.additional
|
|
5371
|
+
}
|
|
5314
5372
|
},
|
|
5315
5373
|
ferry: {
|
|
5316
5374
|
routeFerryLine: {
|
|
@@ -5320,7 +5378,7 @@ const buildRoutingLayers = (config = {}) => {
|
|
|
5320
5378
|
},
|
|
5321
5379
|
routeFerrySymbol: {
|
|
5322
5380
|
...routeFerriesSymbol,
|
|
5323
|
-
beforeID: "
|
|
5381
|
+
beforeID: "routeIncidentJamSymbol",
|
|
5324
5382
|
...configSectionLayers?.ferry?.routeFerrySymbol
|
|
5325
5383
|
},
|
|
5326
5384
|
...configSectionLayers?.ferry?.additional
|
|
@@ -5500,14 +5558,14 @@ const e = { commonBaseURL: "https://api.tomtom.com", apiKey: "", apiVersion: 1 }
|
|
|
5500
5558
|
};
|
|
5501
5559
|
t.instance = new t();
|
|
5502
5560
|
let r = t;
|
|
5503
|
-
const
|
|
5561
|
+
const F = (e2) => e2?.minutes ?? "min", L = (e2, t2) => {
|
|
5504
5562
|
if (e2) {
|
|
5505
5563
|
const a = Math.abs(e2) / 3600;
|
|
5506
5564
|
let o = Math.floor(a), i = Math.round(a % 1 * 60);
|
|
5507
5565
|
60 === i && (i = 0, o++);
|
|
5508
5566
|
const s = { ...r.instance.get().displayUnits?.time, ...t2 };
|
|
5509
|
-
if (o) return `${o} ${n = s, n?.hours ?? "hr"} ${i.toString().padStart(2, "0")} ${
|
|
5510
|
-
if (i) return `${i.toString()} ${
|
|
5567
|
+
if (o) return `${o} ${n = s, n?.hours ?? "hr"} ${i.toString().padStart(2, "0")} ${F(s)}`;
|
|
5568
|
+
if (i) return `${i.toString()} ${F(s)}`;
|
|
5511
5569
|
}
|
|
5512
5570
|
var n;
|
|
5513
5571
|
};
|
|
@@ -5547,7 +5605,7 @@ const toDisplayChargingStops = (routes, config) => {
|
|
|
5547
5605
|
iconID: getIconID(chargingStop, config),
|
|
5548
5606
|
title: formatTitle(chargingStop),
|
|
5549
5607
|
chargingPower: `${properties.chargingConnectionInfo?.chargingPowerInkW} kW`,
|
|
5550
|
-
chargingDuration:
|
|
5608
|
+
chargingDuration: L(
|
|
5551
5609
|
properties.chargingTimeInSeconds,
|
|
5552
5610
|
config?.displayUnits?.time
|
|
5553
5611
|
),
|
|
@@ -5560,42 +5618,71 @@ const toDisplayChargingStops = (routes, config) => {
|
|
|
5560
5618
|
}
|
|
5561
5619
|
return { type: "FeatureCollection", features: displayChargingStops };
|
|
5562
5620
|
};
|
|
5563
|
-
const
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
};
|
|
5570
|
-
const
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
if (!tecIconSuffix) {
|
|
5621
|
+
const hasJam = (sectionProps) => sectionProps.categories.includes("jam");
|
|
5622
|
+
const buildTitle = (sectionProps) => {
|
|
5623
|
+
if (hasJam(sectionProps)) {
|
|
5624
|
+
return core.formatDuration(sectionProps.delayInSeconds);
|
|
5625
|
+
}
|
|
5626
|
+
return void 0;
|
|
5627
|
+
};
|
|
5628
|
+
const toTrafficJamIconSuffix = (title) => {
|
|
5629
|
+
if (!title?.length) {
|
|
5630
|
+
return "collapsed";
|
|
5631
|
+
}
|
|
5632
|
+
if (title.length < 6) {
|
|
5633
|
+
return "small";
|
|
5634
|
+
}
|
|
5635
|
+
if (title.length < 8) {
|
|
5636
|
+
return "medium";
|
|
5637
|
+
}
|
|
5638
|
+
return "large";
|
|
5639
|
+
};
|
|
5640
|
+
const toJamIconID = (sectionProps, title) => {
|
|
5641
|
+
if (!hasJam(sectionProps)) {
|
|
5585
5642
|
return null;
|
|
5586
5643
|
}
|
|
5587
|
-
const
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5644
|
+
const magnitude = sectionProps.magnitudeOfDelay ?? "unknown";
|
|
5645
|
+
return `traffic-jam-${magnitude}-${toTrafficJamIconSuffix(title)}`;
|
|
5646
|
+
};
|
|
5647
|
+
const toCauseIconID = (sectionProps) => {
|
|
5648
|
+
const firstNonJamCategory = sectionProps.categories.find((category) => category !== "jam");
|
|
5649
|
+
switch (firstNonJamCategory) {
|
|
5650
|
+
case "accident":
|
|
5651
|
+
return "traffic-incidents-accident";
|
|
5652
|
+
case "roadworks":
|
|
5653
|
+
return "traffic-incidents-roadworks";
|
|
5654
|
+
case "road-closed":
|
|
5655
|
+
return "traffic-incidents-road_closed";
|
|
5656
|
+
case "danger":
|
|
5657
|
+
case "animals-on-road":
|
|
5658
|
+
return "traffic-incidents-danger";
|
|
5659
|
+
case "broken-down-vehicle":
|
|
5660
|
+
return "traffic-incidents-broken_down_vehicle";
|
|
5661
|
+
case "lane-closed":
|
|
5662
|
+
case "narrow-lanes":
|
|
5663
|
+
return "traffic-incidents-lane_closed";
|
|
5664
|
+
case "wind":
|
|
5665
|
+
return "traffic-incidents-wind";
|
|
5666
|
+
case "fog":
|
|
5667
|
+
return "traffic-incidents-fog";
|
|
5668
|
+
case "rain":
|
|
5669
|
+
return "traffic-incidents-rain";
|
|
5670
|
+
case "frost":
|
|
5671
|
+
return "traffic-incidents-frost";
|
|
5672
|
+
case "flooding":
|
|
5673
|
+
return "traffic-incidents-flooding";
|
|
5674
|
+
default:
|
|
5675
|
+
return null;
|
|
5676
|
+
}
|
|
5592
5677
|
};
|
|
5593
5678
|
const toDisplayTrafficSectionProps = (sectionProps) => {
|
|
5594
|
-
const title =
|
|
5595
|
-
const
|
|
5679
|
+
const title = buildTitle(sectionProps);
|
|
5680
|
+
const jamIconID = toJamIconID(sectionProps, title);
|
|
5681
|
+
const causeIconID = toCauseIconID(sectionProps);
|
|
5596
5682
|
return {
|
|
5597
5683
|
...sectionProps,
|
|
5598
|
-
...
|
|
5684
|
+
...jamIconID && { jamIconID },
|
|
5685
|
+
...causeIconID && { causeIconID },
|
|
5599
5686
|
...title && { title }
|
|
5600
5687
|
};
|
|
5601
5688
|
};
|
|
@@ -5974,11 +6061,12 @@ class RoutingModule extends AbstractMapModule {
|
|
|
5974
6061
|
const mergedConfig = routeModuleConfigWithDefaults(config);
|
|
5975
6062
|
if (this.config) {
|
|
5976
6063
|
const newLayersSpecs = createLayersSpecs(mergedConfig.layers);
|
|
5977
|
-
Object.keys(newLayersSpecs).forEach((
|
|
6064
|
+
Object.keys(newLayersSpecs).forEach((layersSpecID) => {
|
|
6065
|
+
const id = layersSpecID;
|
|
5978
6066
|
updateLayersAndSource(
|
|
5979
|
-
newLayersSpecs[
|
|
5980
|
-
this.layersSpecs[
|
|
5981
|
-
this.sourcesWithLayers[
|
|
6067
|
+
newLayersSpecs[id],
|
|
6068
|
+
this.layersSpecs[id],
|
|
6069
|
+
this.sourcesWithLayers[id],
|
|
5982
6070
|
this.mapLibreMap
|
|
5983
6071
|
);
|
|
5984
6072
|
});
|
|
@@ -6211,6 +6299,7 @@ class RoutingModule extends AbstractMapModule {
|
|
|
6211
6299
|
return mapStyleLayerIDs.lowestLabel;
|
|
6212
6300
|
}
|
|
6213
6301
|
}
|
|
6302
|
+
const version = "5.12.0";
|
|
6214
6303
|
const DEFAULT_PUBLISHED_STYLE = "standardLight";
|
|
6215
6304
|
const URL_PREFIX = "${baseURL}/maps/orbis/assets/styles/${version}/style.json?&apiVersion=1&key=${apiKey}";
|
|
6216
6305
|
const publishedStyleModulesValues = {
|
|
@@ -6260,7 +6349,7 @@ const baseMapStyleUrlTemplates = {
|
|
|
6260
6349
|
monoDark: baseMapStyleUrlTemplate("basic_mono-dark"),
|
|
6261
6350
|
satellite: baseMapStyleUrlTemplate("basic_street-satellite")
|
|
6262
6351
|
};
|
|
6263
|
-
const buildBaseMapStyleUrl = (publishedStyle, baseUrl, apiKey) => baseMapStyleUrlTemplates[publishedStyle?.id ?? DEFAULT_PUBLISHED_STYLE].replace("${baseURL}", baseUrl).replace("${version}", publishedStyle.version ?? "0
|
|
6352
|
+
const buildBaseMapStyleUrl = (publishedStyle, baseUrl, apiKey) => baseMapStyleUrlTemplates[publishedStyle?.id ?? DEFAULT_PUBLISHED_STYLE].replace("${baseURL}", baseUrl).replace("${version}", publishedStyle.version ?? "0.6.0-0").replace("${apiKey}", apiKey);
|
|
6264
6353
|
const withApiKey = (givenUrl, apiKey) => {
|
|
6265
6354
|
const url = new URL(givenUrl);
|
|
6266
6355
|
if (!url.searchParams.has("key")) {
|
|
@@ -6436,9 +6525,13 @@ class TomTomMap {
|
|
|
6436
6525
|
return this._params.style;
|
|
6437
6526
|
};
|
|
6438
6527
|
this._params = core.mergeFromGlobal(mapParams);
|
|
6528
|
+
this.ensureMapLibreCSSLoaded();
|
|
6439
6529
|
this.mapLibreMap = new maplibreGl.Map(buildMapOptions(mapLibreOptions, this._params));
|
|
6440
6530
|
this.mapLibreMap.once("styledata", () => this.handleStyleData(false));
|
|
6441
6531
|
this._eventsProxy = new EventsProxy(this.mapLibreMap, this._params?.eventsConfig);
|
|
6532
|
+
this.loadRTLTextPlugin();
|
|
6533
|
+
}
|
|
6534
|
+
loadRTLTextPlugin() {
|
|
6442
6535
|
setTimeout(() => {
|
|
6443
6536
|
if (!["deferred", "loaded"].includes(maplibreGl.getRTLTextPluginStatus())) {
|
|
6444
6537
|
maplibreGl.setRTLTextPlugin(
|
|
@@ -6448,6 +6541,24 @@ class TomTomMap {
|
|
|
6448
6541
|
}
|
|
6449
6542
|
});
|
|
6450
6543
|
}
|
|
6544
|
+
/**
|
|
6545
|
+
* Dynamically loads the MapLibre CSS stylesheet from CDN.
|
|
6546
|
+
*/
|
|
6547
|
+
ensureMapLibreCSSLoaded() {
|
|
6548
|
+
if (typeof document === "undefined") {
|
|
6549
|
+
return;
|
|
6550
|
+
}
|
|
6551
|
+
const existingLink = Array.from(document.querySelectorAll('link[rel="stylesheet"], style')).some(
|
|
6552
|
+
(element) => element.textContent?.includes("maplibre")
|
|
6553
|
+
);
|
|
6554
|
+
if (existingLink) {
|
|
6555
|
+
return;
|
|
6556
|
+
}
|
|
6557
|
+
const link = document.createElement("link");
|
|
6558
|
+
link.rel = "stylesheet";
|
|
6559
|
+
link.href = `https://unpkg.com/maplibre-gl@${version}/dist/maplibre-gl.css`;
|
|
6560
|
+
document.head.appendChild(link);
|
|
6561
|
+
}
|
|
6451
6562
|
_setLanguage(language) {
|
|
6452
6563
|
this._params = { ...this._params, language };
|
|
6453
6564
|
const mapLanguage = language?.includes("-") ? language.split("-")[0] : language;
|