@mapcreator/sdk 0.0.9 → 0.0.11

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.
Files changed (121) hide show
  1. package/README.md +29 -0
  2. package/dist/{esm/HighlightManager.d.ts → HighlightManager.d.ts} +2 -2
  3. package/dist/{esm/MCMap.d.ts → MCMap.d.ts} +1 -1
  4. package/dist/{esm/PopupManager.d.ts → PopupManager.d.ts} +4 -4
  5. package/dist/{esm/Registry.d.ts → Registry.d.ts} +3 -3
  6. package/dist/{esm/adornments → adornments}/categoricalLegend.d.ts +1 -1
  7. package/dist/{esm/adornments → adornments}/connectedLegend.d.ts +2 -2
  8. package/dist/{esm/adornments → adornments}/customAdornment.d.ts +1 -1
  9. package/dist/{esm/adornments → adornments}/heading.d.ts +1 -1
  10. package/dist/adornments/insetMap.d.ts +3 -0
  11. package/dist/{esm/adornments → adornments}/manualLegend.d.ts +1 -1
  12. package/dist/adornments/northArrow.d.ts +3 -0
  13. package/dist/adornments/scalebar.d.ts +3 -0
  14. package/dist/{esm/constants → constants}/index.d.ts +2 -2
  15. package/dist/{esm/controls → controls}/fullscreenControls.d.ts +1 -1
  16. package/dist/{esm/controls → controls}/geocoderControl.d.ts +1 -1
  17. package/dist/{esm/controls → controls}/geolocationControls.d.ts +1 -1
  18. package/dist/controls/refreshMapControls.d.ts +3 -0
  19. package/dist/controls/webControls.d.ts +4 -0
  20. package/dist/{esm/controls → controls}/zoomControls.d.ts +1 -1
  21. package/dist/index.d.ts +3 -0
  22. package/dist/locales/da_DK/strings.json.d.ts +10 -0
  23. package/dist/locales/de_DE/strings.json.d.ts +10 -0
  24. package/dist/locales/en_GB/strings.json.d.ts +10 -0
  25. package/dist/locales/es_ES/strings.json.d.ts +10 -0
  26. package/dist/locales/fr_FR/strings.json.d.ts +10 -0
  27. package/dist/locales/it_IT/strings.json.d.ts +10 -0
  28. package/dist/locales/nl_NL/strings.json.d.ts +10 -0
  29. package/dist/mapcreator-sdk.js +39590 -0
  30. package/dist/models/area.d.ts +5 -0
  31. package/dist/models/circle.d.ts +5 -0
  32. package/dist/models/dot.d.ts +3 -0
  33. package/dist/models/line.d.ts +4 -0
  34. package/dist/models/marker.d.ts +5 -0
  35. package/dist/models/polygon.d.ts +5 -0
  36. package/dist/{esm/renderAdornments.d.ts → renderAdornments.d.ts} +3 -3
  37. package/dist/{esm/types → types}/index.d.ts +1 -1
  38. package/dist/{esm/types → types}/mapstyle.d.ts +2 -6
  39. package/dist/{esm/utils → utils}/choropleth.d.ts +3 -3
  40. package/dist/{esm/utils → utils}/geolocation.d.ts +1 -1
  41. package/dist/{esm/utils → utils}/graphhopper.d.ts +1 -1
  42. package/dist/{esm/utils → utils}/helpers.d.ts +2 -2
  43. package/dist/{esm/utils → utils}/language.d.ts +1 -1
  44. package/dist/{esm/utils → utils}/models.d.ts +4 -4
  45. package/dist/{esm/utils → utils}/overlays.d.ts +1 -1
  46. package/dist/{esm/utils → utils}/svgHelpers.d.ts +3 -4
  47. package/dist/{esm/utils → utils}/template.d.ts +2 -2
  48. package/dist/{esm/utils → utils}/youtube.d.ts +1 -1
  49. package/package.json +8 -6
  50. package/dist/esm/HighlightManager.js +0 -203
  51. package/dist/esm/MCMap.js +0 -254
  52. package/dist/esm/PopupManager.js +0 -297
  53. package/dist/esm/Registry.js +0 -74
  54. package/dist/esm/adornments/categoricalLegend.js +0 -141
  55. package/dist/esm/adornments/connectedLegend.js +0 -393
  56. package/dist/esm/adornments/customAdornment.js +0 -29
  57. package/dist/esm/adornments/heading.js +0 -71
  58. package/dist/esm/adornments/insetMap.d.ts +0 -3
  59. package/dist/esm/adornments/insetMap.js +0 -351
  60. package/dist/esm/adornments/manualLegend.js +0 -15
  61. package/dist/esm/adornments/northArrow.d.ts +0 -3
  62. package/dist/esm/adornments/northArrow.js +0 -24
  63. package/dist/esm/adornments/scalebar.d.ts +0 -3
  64. package/dist/esm/adornments/scalebar.js +0 -176
  65. package/dist/esm/constants/index.js +0 -53
  66. package/dist/esm/controls/controls.js +0 -7
  67. package/dist/esm/controls/fullscreenControls.js +0 -29
  68. package/dist/esm/controls/geocoderControl.js +0 -202
  69. package/dist/esm/controls/geolocationControls.js +0 -65
  70. package/dist/esm/controls/refreshMapControls.d.ts +0 -3
  71. package/dist/esm/controls/refreshMapControls.js +0 -26
  72. package/dist/esm/controls/webControls.d.ts +0 -4
  73. package/dist/esm/controls/webControls.js +0 -40
  74. package/dist/esm/controls/zoomControls.js +0 -23
  75. package/dist/esm/i18n.js +0 -21
  76. package/dist/esm/index.d.ts +0 -5
  77. package/dist/esm/index.js +0 -5
  78. package/dist/esm/locales/da_DK/strings.json +0 -7
  79. package/dist/esm/locales/de_DE/strings.json +0 -7
  80. package/dist/esm/locales/en_GB/strings.json +0 -7
  81. package/dist/esm/locales/es_ES/strings.json +0 -7
  82. package/dist/esm/locales/fr_FR/strings.json +0 -7
  83. package/dist/esm/locales/it_IT/strings.json +0 -7
  84. package/dist/esm/locales/nl_NL/strings.json +0 -7
  85. package/dist/esm/models/area.d.ts +0 -5
  86. package/dist/esm/models/area.js +0 -165
  87. package/dist/esm/models/circle.d.ts +0 -5
  88. package/dist/esm/models/circle.js +0 -110
  89. package/dist/esm/models/dot.d.ts +0 -3
  90. package/dist/esm/models/dot.js +0 -42
  91. package/dist/esm/models/line.d.ts +0 -4
  92. package/dist/esm/models/line.js +0 -117
  93. package/dist/esm/models/marker.d.ts +0 -5
  94. package/dist/esm/models/marker.js +0 -179
  95. package/dist/esm/models/polygon.d.ts +0 -5
  96. package/dist/esm/models/polygon.js +0 -80
  97. package/dist/esm/renderAdornments.js +0 -129
  98. package/dist/esm/types/geometry.js +0 -1
  99. package/dist/esm/types/index.js +0 -1
  100. package/dist/esm/types/jobObject.js +0 -1
  101. package/dist/esm/types/mapstyle.js +0 -1
  102. package/dist/esm/utils/browser.js +0 -6
  103. package/dist/esm/utils/choropleth.js +0 -110
  104. package/dist/esm/utils/fullscreen.js +0 -40
  105. package/dist/esm/utils/geolocation.js +0 -93
  106. package/dist/esm/utils/graphhopper.js +0 -41
  107. package/dist/esm/utils/helpers.js +0 -116
  108. package/dist/esm/utils/language.js +0 -170
  109. package/dist/esm/utils/models.js +0 -103
  110. package/dist/esm/utils/overlays.js +0 -87
  111. package/dist/esm/utils/scalebar.js +0 -52
  112. package/dist/esm/utils/svgHelpers.js +0 -1512
  113. package/dist/esm/utils/template.js +0 -120
  114. package/dist/esm/utils/youtube.js +0 -64
  115. /package/dist/{esm/controls → controls}/controls.d.ts +0 -0
  116. /package/dist/{esm/i18n.d.ts → i18n.d.ts} +0 -0
  117. /package/dist/{esm/types → types}/geometry.d.ts +0 -0
  118. /package/dist/{esm/types → types}/jobObject.d.ts +0 -0
  119. /package/dist/{esm/utils → utils}/browser.d.ts +0 -0
  120. /package/dist/{esm/utils → utils}/fullscreen.d.ts +0 -0
  121. /package/dist/{esm/utils → utils}/scalebar.d.ts +0 -0
package/dist/esm/MCMap.js DELETED
@@ -1,254 +0,0 @@
1
- import { LanguageNotation, setLanguage, transformLanguageCode } from '@/utils/language';
2
- import { AttributionControl, Map as MapLibre } from '@mapcreator/maplibre-gl';
3
- import { useRenderAdornments } from '@/renderAdornments';
4
- import { addPolygonGroup } from '@/models/polygon';
5
- import { addCircleGroup } from '@/models/circle';
6
- import { addMarkerGroup } from '@/models/marker';
7
- import { loadOverlays } from '@/utils/overlays';
8
- import { PopupManager } from '@/PopupManager';
9
- import { unitConvert } from '@/utils/helpers';
10
- import { SvgCache } from '@/utils/svgHelpers';
11
- import { addLineGroup } from '@/models/line';
12
- import { addAreaGroup } from '@/models/area';
13
- import { addDotGroup } from '@/models/dot';
14
- import { defaultSky } from '@/constants';
15
- import { t } from '@/i18n';
16
- export class MCMap {
17
- map;
18
- constructor(map) {
19
- this.map = map;
20
- }
21
- }
22
- export async function initMap(options) {
23
- const { accessToken, mode = 'sdk', env = 'production' } = options;
24
- const vapiUrl = env === 'bleeding'
25
- ? 'https://vapi.bleeding.mc-cdn.io'
26
- : env === 'beta'
27
- ? 'https://vapi.beta.mc-cdn.io'
28
- : 'https://vapi.mc-cdn.io';
29
- const cdnUrl = env === 'bleeding'
30
- ? 'https://cdn.bleeding.mapcreator.io'
31
- : env === 'beta'
32
- ? 'https://cdn.beta.mapcreator.io'
33
- : 'https://cdn.mapcreator.io';
34
- const jobObject = typeof options.job === 'string'
35
- ? await loadJobObject(options.job, cdnUrl, accessToken)
36
- : options.job;
37
- await nonZeroWindowSize();
38
- const map = new MapLibre({
39
- container: options.container,
40
- attributionControl: false,
41
- style: null,
42
- maxBounds: [-Infinity, -90, Infinity, 90],
43
- maxPitch: 85,
44
- maxZoom: 22,
45
- locale: {
46
- 'CooperativeGesturesHandler.WindowsHelpText': t('windowsHelpText'),
47
- 'CooperativeGesturesHandler.MacHelpText': t('macHelpText'),
48
- 'CooperativeGesturesHandler.MobileHelpText': t('mobileHelpText'),
49
- },
50
- });
51
- const container = map.getContainer();
52
- container.classList.add('mc-map');
53
- const svgCache = new SvgCache(map);
54
- const popupManager = new PopupManager(map, mode);
55
- const { map: { language, zoom, pitch = 0, rotation = 0, center, hideBasemap, layerInfo = [], detailLevel = 0, projection = 'mercator', terrain = false, terrainExaggeration = 1, }, export: exportData, registry = {}, web, positionOffsets, title, } = jobObject;
56
- const { models = {}, slots = {}, svgs = {} } = registry;
57
- loadFontFaces(env, vapiUrl, accessToken);
58
- map.resize();
59
- if (mode === 'app') {
60
- document.title = title ? `${title} - Mapcreator` : 'Mapcreator';
61
- }
62
- map.setPitch(pitch);
63
- map.setBearing(rotation);
64
- const unit = exportData?.unit ?? 'pixel';
65
- const aspectBoxWidth = unitConvert(unit, 'pixel', exportData?.size?.[0] ?? 600);
66
- const aspectBoxHeight = unitConvert(unit, 'pixel', exportData?.size?.[1] ?? 400);
67
- let zoomCorrection = 0;
68
- // Adjust map's zoom level to preserve viewport regardless of map size
69
- if (container.clientWidth > 0 && container.clientHeight > 0) {
70
- const scale = Math.min(container.clientWidth / aspectBoxWidth, container.clientHeight / aspectBoxHeight);
71
- zoomCorrection = Math.log(scale) / Math.LN2;
72
- }
73
- map.setZoom(zoom - detailLevel + zoomCorrection);
74
- map.setCenter(center);
75
- map.setDetailLevel(detailLevel);
76
- map.setMinZoom(detailLevel);
77
- map.addControl(new AttributionControl({ compact: false }));
78
- if (mode === 'app') {
79
- map.cooperativeGestures.enable();
80
- }
81
- useRenderAdornments(jobObject, positionOffsets, map, {
82
- center,
83
- zoom,
84
- pitch,
85
- rotation,
86
- detailLevel,
87
- width: aspectBoxWidth,
88
- height: aspectBoxHeight,
89
- }, vapiUrl, cdnUrl, accessToken);
90
- popupManager.setJobObject(jobObject);
91
- if (web) {
92
- const { restrictMapMovement, popupPosition } = web;
93
- if (restrictMapMovement) {
94
- map.boxZoom.disable();
95
- map.doubleClickZoom.disable();
96
- map.dragPan.disable();
97
- map.dragRotate.disable();
98
- map.keyboard.disable();
99
- map.scrollZoom.disable();
100
- map.touchPitch.disable();
101
- map.touchZoomRotate.disable();
102
- }
103
- popupManager.setParams(popupPosition, transformLanguageCode(language, LanguageNotation.TWO), restrictMapMovement, center);
104
- }
105
- const mapstyle = await fetch(`${vapiUrl}/styles/${jobObject.meta.mapstyleSet}.json?access_token=${accessToken}`).then(response => response.json());
106
- map.setStyle(null);
107
- map.setStyle(mapstyle);
108
- await map.once('style.load');
109
- if (mode === 'app') {
110
- setCustomStyle(map.getStyle().metadata?.customCssFilePath, accessToken);
111
- }
112
- // Don't wait for overlays and models to set the language as maps on slow internet will otherwise not be translated immediately
113
- setLanguage(language, map);
114
- await loadOverlays(jobObject.meta.layers ?? [], map, vapiUrl, accessToken, mapstyle.metadata?.styleOverride);
115
- addModels(map, svgCache, models, slots, svgs, vapiUrl, accessToken);
116
- // Set the language again to translate the overlays and models
117
- setLanguage(language, map);
118
- popupManager.setPublication(mapstyle.metadata?.publication);
119
- popupManager.setpopupElements();
120
- popupManager.setHighlightManager();
121
- map.setProjection({ type: projection === 'globe' ? 'globe' : 'mercator' });
122
- setSky(map, projection);
123
- if (terrain) {
124
- initTerrain(map, vapiUrl, accessToken, terrainExaggeration);
125
- }
126
- setLayerVisibility(map, map.getStyle(), layerInfo, !hideBasemap);
127
- return new MCMap(map);
128
- }
129
- function loadJobObject(id, cdnUrl, accessToken) {
130
- return fetch(`${cdnUrl}/jobs/${id}.json?access_token=${accessToken}`).then(response => response.json());
131
- }
132
- function nonZeroWindowSize() {
133
- return new Promise(resolve => {
134
- const checkSize = () => {
135
- if (window.innerWidth > 0 && window.innerHeight > 0) {
136
- window.removeEventListener('resize', checkSize);
137
- resolve();
138
- }
139
- };
140
- window.addEventListener('resize', checkSize);
141
- checkSize();
142
- });
143
- }
144
- function setSky(map, projection) {
145
- const meta = map.getStyle().metadata ?? {};
146
- const backgroundColorFlat = meta['mc:background-color'] ?? '#f8f8f8';
147
- const backgroundColorGlobe = meta['mc:background-color-globe'] ?? '#000000';
148
- map.getContainer().style.backgroundColor =
149
- projection === 'globe' ? backgroundColorGlobe : backgroundColorFlat;
150
- map.setSky(map.getStyle().sky ?? defaultSky);
151
- map.setLight({ position: [1.15, 210, 45] });
152
- }
153
- function initTerrain(map, vapiUrl, accessToken, exaggeration) {
154
- map.addSource('mc-dem', {
155
- type: 'raster-dem',
156
- tiles: [`${vapiUrl}/dataset/jaxa_terrainrgb/{z}/{x}/{y}?access_token=${accessToken}`],
157
- attribution: '<a href="https://earth.jaxa.jp/en/data/policy" target="_blank">© AW3D30 (JAXA)</a>',
158
- minzoom: 0,
159
- maxzoom: 12,
160
- });
161
- map.setTerrain({ source: 'mc-dem', exaggeration });
162
- }
163
- function loadFontFaces(env, vapiUrl, accessToken) {
164
- const betaPrefix = env === 'beta' ? 'b-' : '';
165
- const href = `${vapiUrl}/stylesheets/ff-${betaPrefix}${accessToken}.css?access_token=${accessToken}`;
166
- const element = document.createElement('link');
167
- element.setAttribute('rel', 'stylesheet');
168
- element.setAttribute('href', href);
169
- element.setAttribute('type', 'text/css');
170
- // Inserting at the beginning of <head> to avoid redefining existing Roboto fonts
171
- // See https://mapcreator.atlassian.net/browse/MC-2702
172
- document.head.insertBefore(element, document.head.firstChild);
173
- }
174
- function setCustomStyle(styleOrURL, accessToken) {
175
- document.getElementById('custom-style')?.remove();
176
- if (!styleOrURL) {
177
- return;
178
- }
179
- let element;
180
- if (styleOrURL.startsWith('http')) {
181
- styleOrURL = `${styleOrURL}?access_token=${accessToken}`;
182
- element = document.createElement('link');
183
- element.setAttribute('rel', 'stylesheet');
184
- element.setAttribute('href', styleOrURL.replace(/https?:/, ''));
185
- }
186
- else {
187
- element = document.createElement('style');
188
- element.appendChild(document.createTextNode(styleOrURL));
189
- }
190
- element.setAttribute('id', 'custom-style');
191
- element.setAttribute('type', 'text/css');
192
- document.head.appendChild(element);
193
- }
194
- function setLayerVisibility(map, mapstyle, layers, showBasemap) {
195
- for (const layer of layers) {
196
- const existingLayer = mapstyle.layers.find(item => layer.id === item.id || layer.id.endsWith(` | ${item.id}`));
197
- if (existingLayer) {
198
- map.setLayoutProperty(existingLayer.id, 'visibility', layer.visibility && showBasemap ? 'visible' : 'none');
199
- }
200
- }
201
- }
202
- function addModels(map, svgCache, models, slots, svgs, vapiUrl, accessToken) {
203
- const { beforeNone = [], beforeNames = [], beforeBoundaries = [], beforeWaters = [] } = slots;
204
- beforeNone.forEach(item => {
205
- addModelsByType(map, svgCache, models, item, svgs, 'mc-before-none', vapiUrl, accessToken);
206
- });
207
- beforeNames.forEach(item => {
208
- addModelsByType(map, svgCache, models, item, svgs, 'mc-before-names', vapiUrl, accessToken);
209
- });
210
- beforeBoundaries.forEach(item => {
211
- addModelsByType(map, svgCache, models, item, svgs, 'mc-before-boundaries', vapiUrl, accessToken);
212
- });
213
- beforeWaters.forEach(item => {
214
- addModelsByType(map, svgCache, models, item, svgs, 'mc-before-waters', vapiUrl, accessToken);
215
- });
216
- }
217
- function addModelsByType(map, svgCache, models, item, svgs, beforeId, vapiUrl, accessToken) {
218
- if (item.type === 'marker') {
219
- const group = models.marker?.find(entry => entry.id === item.groupId);
220
- if (group) {
221
- addMarkerGroup(map, group, beforeId, svgs, svgCache);
222
- }
223
- }
224
- else if (item.type === 'polygon') {
225
- const group = models.polygon?.find(entry => entry.id === item.groupId);
226
- if (group) {
227
- addPolygonGroup(map, group, beforeId, svgs, svgCache);
228
- }
229
- }
230
- else if (item.type === 'circle') {
231
- const group = models.circle?.find(entry => entry.id === item.groupId);
232
- if (group) {
233
- addCircleGroup(map, group, beforeId, svgs, svgCache);
234
- }
235
- }
236
- else if (item.type === 'line') {
237
- const group = models.line?.find(entry => entry.id === item.groupId);
238
- if (group) {
239
- addLineGroup(map, group, beforeId, svgCache);
240
- }
241
- }
242
- else if (item.type === 'dot') {
243
- const group = models.dot?.find(entry => entry.id === item.groupId);
244
- if (group) {
245
- addDotGroup(map, group, beforeId);
246
- }
247
- }
248
- else if (item.type === 'area') {
249
- const group = models.area?.find(entry => entry.id === item.groupId);
250
- if (group) {
251
- addAreaGroup(map, group, beforeId, svgs, svgCache, vapiUrl, accessToken);
252
- }
253
- }
254
- }
@@ -1,297 +0,0 @@
1
- import { Popup, } from '@mapcreator/maplibre-gl';
2
- import { buildTemplate, closeButtonHtml, cycleButtonsHtml } from '@/utils/template';
3
- import { Registry } from '@/Registry';
4
- import { HighlightManager } from '@/HighlightManager';
5
- export class PopupManager {
6
- map;
7
- popupPosition = 'bottomLeft';
8
- mapContainer;
9
- popupContainer;
10
- feature;
11
- currentFeatureId;
12
- currentModelId;
13
- popupElements = [];
14
- language = 'en';
15
- promoteIdCache = new Map();
16
- publication;
17
- floatingPopup;
18
- registry;
19
- highlightManager;
20
- mode;
21
- restrictMapMovement;
22
- center;
23
- constructor(map, mode) {
24
- this.map = map;
25
- this.mode = mode;
26
- this.mapContainer = this.map.getContainer();
27
- this.popupContainer = document.createElement('div');
28
- this.popupContainer.classList.add('popup-container');
29
- this.map.on('mousemove', e => this.onMouseMove(e));
30
- this.map.on('click', e => this.onClick(e));
31
- }
32
- setJobObject(jobObject) {
33
- this.registry = new Registry(jobObject);
34
- }
35
- setParams(popupPosition, language, restrictMapMovement, center) {
36
- this.popupPosition = popupPosition;
37
- this.language = language;
38
- this.restrictMapMovement = restrictMapMovement;
39
- this.center = center;
40
- }
41
- setPublication(publication) {
42
- this.publication = publication;
43
- }
44
- setpopupElements() {
45
- this.popupElements = this.registry.getPopupElements();
46
- }
47
- setHighlightManager() {
48
- this.highlightManager = new HighlightManager(this.map, this.registry.getPopupElements());
49
- }
50
- onMouseMove(e) {
51
- this.feature = this.getInteractiveFeature(e);
52
- if (this.feature) {
53
- this.map.getCanvas().style.cursor = 'pointer';
54
- }
55
- else {
56
- this.map.getCanvas().style.cursor = '';
57
- }
58
- }
59
- onClick(e) {
60
- this.feature = this.getInteractiveFeature(e);
61
- this.currentModelId = this.feature?.properties?.id;
62
- if (this.feature &&
63
- (!this.mapContainer.contains(this.popupContainer) ||
64
- this.feature?.id !== this.currentFeatureId)) {
65
- this.addPopup(e);
66
- this.highlightManager?.highlight(this.getPopupElementFromFeature(this.feature));
67
- }
68
- else {
69
- this.hidePopup();
70
- this.highlightManager?.highlight(undefined);
71
- }
72
- }
73
- getPopupElementFromFeature(feature) {
74
- return this.popupElements.find(item => item.modelId === feature.properties.id);
75
- }
76
- getInteractiveFeature(e) {
77
- const features = this.map.queryRenderedFeatures(e.point);
78
- return features.find(feature => {
79
- // Overlay interactive feature
80
- if (Object.keys(feature.layer.metadata ?? {}).some(key => key.startsWith('mc-interactivity-template'))) {
81
- return true;
82
- }
83
- // User-created interactive feature
84
- const model = this.registry.getModel(feature);
85
- return !!(model?.popup ?? model?.popupMedia);
86
- });
87
- }
88
- addPopup(e) {
89
- if (!this.feature) {
90
- return;
91
- }
92
- this.floatingPopup?.remove();
93
- const toNumber = Number(this.feature.id);
94
- this.currentFeatureId = isNaN(toNumber) ? this.feature.id : toNumber;
95
- const template = this.getTemplate(this.feature);
96
- if (!template) {
97
- return;
98
- }
99
- if (this.popupPosition === 'mapElement') {
100
- if (this.feature.geometry.type === 'Point') {
101
- this.addFloatingPopup(template, this.feature.geometry.coordinates);
102
- }
103
- else {
104
- const { lng, lat } = this.map.unproject(e.point);
105
- this.addFloatingPopup(template, [lng, lat]);
106
- }
107
- return;
108
- }
109
- this.popupContainer.innerHTML = template;
110
- const currentPopup = this.popupElements.find(popup => popup.modelId === this.currentModelId);
111
- if (currentPopup) {
112
- this.addPopupControls();
113
- }
114
- this.mapContainer.appendChild(this.popupContainer);
115
- }
116
- addFloatingPopup(template, lngLat) {
117
- const anchor = this.restrictMapMovement ? this.getAnchor(lngLat) : undefined;
118
- this.floatingPopup = new Popup({
119
- maxWidth: 'none',
120
- closeButton: false,
121
- offset: 20,
122
- ...(anchor !== undefined && { anchor }),
123
- })
124
- .setLngLat(lngLat)
125
- .setHTML(template)
126
- .addTo(this.map);
127
- }
128
- getAnchor(lngLat) {
129
- const point = this.map.projectWithScaleCorrection(lngLat);
130
- const width = this.map.getContainer().clientWidth;
131
- const height = this.map.getContainer().clientHeight;
132
- let vertical;
133
- let horizontal;
134
- if (point.y < height * 0.33) {
135
- vertical = 'top';
136
- }
137
- else if (point.y > height * 0.66) {
138
- vertical = 'bottom';
139
- }
140
- else {
141
- vertical = 'center';
142
- }
143
- if (point.x < width * 0.33) {
144
- horizontal = 'left';
145
- }
146
- else if (point.x > width * 0.66) {
147
- horizontal = 'right';
148
- }
149
- else {
150
- horizontal = 'center';
151
- }
152
- if (vertical === 'center' && horizontal === 'center') {
153
- return 'bottom';
154
- }
155
- else if (vertical === 'center') {
156
- return horizontal;
157
- }
158
- else if (horizontal === 'center') {
159
- return vertical;
160
- }
161
- return `${vertical}-${horizontal}`;
162
- }
163
- hidePopup() {
164
- if (this.popupContainer) {
165
- this.popupContainer.remove();
166
- this.feature = undefined;
167
- this.currentFeatureId = undefined;
168
- }
169
- if (this.restrictMapMovement && this.center) {
170
- this.map.easeTo({ center: this.center });
171
- }
172
- }
173
- getTemplate(feature) {
174
- const { layer } = feature;
175
- let template;
176
- const model = this.registry.getModel(feature);
177
- const modelTemplate = model?.popup || model?.popupMedia;
178
- if (modelTemplate) {
179
- template = buildTemplate(model.popup, model.popupMedia, model.dataBindings ?? {}, this.mode);
180
- }
181
- else {
182
- const options = [];
183
- if (this.publication) {
184
- options.push(`:${this.publication}-${this.language}`);
185
- options.push(`:${this.publication}-:en`);
186
- }
187
- options.push(`:${this.language}`);
188
- options.push(`:en`);
189
- options.push('');
190
- for (const option of options) {
191
- const layerTemplate = layer.metadata?.[`mc-interactivity-template${option}`];
192
- if (layerTemplate) {
193
- template = this.fillDatalayerTemplate(feature, layerTemplate, option);
194
- break;
195
- }
196
- }
197
- if (template) {
198
- template = `
199
- <div class="popup-scroll-wrapper">
200
- <div class="mc-popup data-layer text-content">${template}</div>
201
- </div>
202
- `;
203
- }
204
- }
205
- return template;
206
- }
207
- htmlToElement(html) {
208
- const template = document.createElement('template');
209
- template.innerHTML = html.trim();
210
- return template.content.firstElementChild;
211
- }
212
- addPopupControls() {
213
- const closeButton = this.htmlToElement(closeButtonHtml);
214
- if (closeButton) {
215
- closeButton.addEventListener('click', () => {
216
- this.hidePopup();
217
- this.highlightManager.highlight(undefined);
218
- });
219
- this.popupContainer.appendChild(closeButton);
220
- }
221
- if (this.popupElements.length < 2) {
222
- return;
223
- }
224
- const cycleButtons = this.htmlToElement(cycleButtonsHtml);
225
- if (cycleButtons) {
226
- cycleButtons.querySelector('.prev')?.addEventListener('click', () => this.cyclePopups(false));
227
- cycleButtons.querySelector('.next')?.addEventListener('click', () => this.cyclePopups());
228
- this.popupContainer.appendChild(cycleButtons);
229
- }
230
- }
231
- fillDatalayerTemplate(feature, html, language) {
232
- const attr = 'data-mention-id';
233
- const dom = new DOMParser().parseFromString(html, 'text/html').body;
234
- for (const el of dom.querySelectorAll(`[${attr}]`)) {
235
- const value = this.getProperty(feature, el.getAttribute(attr), language);
236
- if (value !== undefined) {
237
- el.innerText = value;
238
- }
239
- }
240
- return dom.innerHTML;
241
- }
242
- getProperty(feature, name, language) {
243
- if (!name) {
244
- return undefined;
245
- }
246
- const options = name.endsWith(':en') ? [name.replace(':en', language), name] : [name];
247
- for (const option of options) {
248
- const property = feature.properties[option] ?? this.getVectorProperty(feature, option);
249
- if (property !== undefined) {
250
- return property;
251
- }
252
- }
253
- return undefined;
254
- }
255
- getVectorProperty(feature, name) {
256
- let promoteId = this.promoteIdCache.get(feature.source);
257
- if (promoteId === undefined) {
258
- promoteId = (this.map.getSource(feature.source)?.serialize().promoteId || 'id');
259
- this.promoteIdCache.set(feature.source, promoteId);
260
- }
261
- try {
262
- const id = feature.properties[promoteId];
263
- return feature.layer.metadata.properties[name][id];
264
- }
265
- catch (e) {
266
- return undefined;
267
- }
268
- }
269
- cyclePopups(forward = true) {
270
- const index = this.popupElements?.findIndex(model => model.modelId === this.currentModelId);
271
- if (index !== -1) {
272
- let nextIndex = 0;
273
- if (forward) {
274
- nextIndex = index === this.popupElements.length - 1 ? 0 : index + 1;
275
- }
276
- else {
277
- nextIndex = index === 0 ? this.popupElements.length - 1 : index - 1;
278
- }
279
- const next = this.popupElements?.[nextIndex];
280
- this.highlightManager.highlight(next);
281
- const template = buildTemplate(next.popup, next.popupMedia, next.dataBindings ?? {}, this.mode);
282
- const temp = this.popupContainer;
283
- this.popupContainer.remove();
284
- temp.innerHTML = template;
285
- this.mapContainer.appendChild(temp);
286
- this.currentModelId = next.modelId;
287
- this.addPopupControls();
288
- if (forward) {
289
- this.popupContainer.querySelector('.mc-popup-button.next')?.focus();
290
- }
291
- else {
292
- this.popupContainer.querySelector('.mc-popup-button.prev')?.focus();
293
- }
294
- this.currentFeatureId = undefined;
295
- }
296
- }
297
- }
@@ -1,74 +0,0 @@
1
- const allModelTypes = ['area', 'circle', 'dot', 'line', 'marker', 'polygon'];
2
- export class Registry {
3
- data;
4
- customGroupIds;
5
- constructor(jobObject) {
6
- this.data = {
7
- area: {},
8
- circle: {},
9
- dot: {},
10
- line: {},
11
- marker: {},
12
- polygon: {},
13
- };
14
- for (const modelType of allModelTypes) {
15
- for (const group of jobObject.registry?.models?.[modelType] ?? []) {
16
- this.data[modelType][group.id] = {};
17
- for (const model of group.models) {
18
- // MC-2870 Convert the old format area without multiple vector-source group support to the new format
19
- if (modelType === 'area') {
20
- const area = model;
21
- if (area.featureId === undefined) {
22
- area.featureId = Number(area.id);
23
- area.id = `${area.vectorUrl}-${area.id}`;
24
- }
25
- }
26
- this.data[modelType][group.id][model.id] = model;
27
- }
28
- }
29
- }
30
- const { beforeWaters = [], beforeBoundaries = [], beforeNames = [], beforeNone = [], } = jobObject.registry?.slots ?? {};
31
- this.customGroupIds = [...beforeWaters, ...beforeBoundaries, ...beforeNames, ...beforeNone].map(item => item.groupId);
32
- }
33
- getModel(feature) {
34
- let modelId = String(feature.properties?.id);
35
- const metadata = feature.layer.metadata;
36
- const groupId = metadata?.['mc-group-id'];
37
- const modelType = metadata?.['mc-model-type'];
38
- const prefix = metadata?.['mc-model-id-prefix'];
39
- if (prefix) {
40
- modelId = `${prefix}-${modelId}`;
41
- }
42
- if (groupId === undefined || modelId === undefined || modelType === undefined) {
43
- return undefined;
44
- }
45
- return this.data[modelType]?.[groupId]?.[modelId];
46
- }
47
- getPopupElements() {
48
- const result = [];
49
- const elementTypes = ['circle', 'dot', 'line', 'marker', 'polygon'];
50
- for (const groupId of this.customGroupIds) {
51
- for (const type of elementTypes) {
52
- const groupModels = this.data[type]?.[groupId];
53
- if (groupModels) {
54
- for (const [modelId, model] of Object.entries(groupModels)) {
55
- if (model.popup || model.popupMedia) {
56
- result.push({
57
- groupId,
58
- modelId,
59
- popup: model.popup,
60
- popupMedia: model.popupMedia,
61
- lngLat: model.lngLat,
62
- center: model.center,
63
- radius: model.radius,
64
- anchorPoints: model.anchorPoints,
65
- dataBindings: model.dataBindings,
66
- });
67
- }
68
- }
69
- }
70
- }
71
- }
72
- return result.reverse();
73
- }
74
- }