@mapcreator/sdk 0.0.8 → 0.0.9
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/dist/{HighlightManager.d.ts → esm/HighlightManager.d.ts} +2 -2
- package/dist/esm/HighlightManager.js +203 -0
- package/dist/{MCMap.d.ts → esm/MCMap.d.ts} +1 -1
- package/dist/esm/MCMap.js +254 -0
- package/dist/{PopupManager.d.ts → esm/PopupManager.d.ts} +4 -4
- package/dist/esm/PopupManager.js +297 -0
- package/dist/{Registry.d.ts → esm/Registry.d.ts} +3 -3
- package/dist/esm/Registry.js +74 -0
- package/dist/{adornments → esm/adornments}/categoricalLegend.d.ts +1 -1
- package/dist/esm/adornments/categoricalLegend.js +141 -0
- package/dist/{adornments → esm/adornments}/connectedLegend.d.ts +2 -2
- package/dist/esm/adornments/connectedLegend.js +393 -0
- package/dist/{adornments → esm/adornments}/customAdornment.d.ts +1 -1
- package/dist/esm/adornments/customAdornment.js +29 -0
- package/dist/{adornments → esm/adornments}/heading.d.ts +1 -1
- package/dist/esm/adornments/heading.js +71 -0
- package/dist/esm/adornments/insetMap.d.ts +3 -0
- package/dist/esm/adornments/insetMap.js +351 -0
- package/dist/{adornments → esm/adornments}/manualLegend.d.ts +1 -1
- package/dist/esm/adornments/manualLegend.js +15 -0
- package/dist/esm/adornments/northArrow.d.ts +3 -0
- package/dist/esm/adornments/northArrow.js +24 -0
- package/dist/esm/adornments/scalebar.d.ts +3 -0
- package/dist/esm/adornments/scalebar.js +176 -0
- package/dist/{constants → esm/constants}/index.d.ts +2 -2
- package/dist/esm/constants/index.js +53 -0
- package/dist/esm/controls/controls.js +7 -0
- package/dist/{controls → esm/controls}/fullscreenControls.d.ts +1 -1
- package/dist/esm/controls/fullscreenControls.js +29 -0
- package/dist/{controls → esm/controls}/geocoderControl.d.ts +1 -1
- package/dist/esm/controls/geocoderControl.js +202 -0
- package/dist/{controls → esm/controls}/geolocationControls.d.ts +1 -1
- package/dist/esm/controls/geolocationControls.js +65 -0
- package/dist/esm/controls/refreshMapControls.d.ts +3 -0
- package/dist/esm/controls/refreshMapControls.js +26 -0
- package/dist/esm/controls/webControls.d.ts +4 -0
- package/dist/esm/controls/webControls.js +40 -0
- package/dist/{controls → esm/controls}/zoomControls.d.ts +1 -1
- package/dist/esm/controls/zoomControls.js +23 -0
- package/dist/esm/i18n.js +21 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/locales/da_DK/strings.json +7 -0
- package/dist/esm/locales/de_DE/strings.json +7 -0
- package/dist/esm/locales/en_GB/strings.json +7 -0
- package/dist/esm/locales/es_ES/strings.json +7 -0
- package/dist/esm/locales/fr_FR/strings.json +7 -0
- package/dist/esm/locales/it_IT/strings.json +7 -0
- package/dist/esm/locales/nl_NL/strings.json +7 -0
- package/dist/esm/models/area.d.ts +5 -0
- package/dist/esm/models/area.js +165 -0
- package/dist/esm/models/circle.d.ts +5 -0
- package/dist/esm/models/circle.js +110 -0
- package/dist/esm/models/dot.d.ts +3 -0
- package/dist/esm/models/dot.js +42 -0
- package/dist/esm/models/line.d.ts +4 -0
- package/dist/esm/models/line.js +117 -0
- package/dist/esm/models/marker.d.ts +5 -0
- package/dist/esm/models/marker.js +179 -0
- package/dist/esm/models/polygon.d.ts +5 -0
- package/dist/esm/models/polygon.js +80 -0
- package/dist/{renderAdornments.d.ts → esm/renderAdornments.d.ts} +3 -3
- package/dist/esm/renderAdornments.js +129 -0
- package/dist/esm/types/geometry.js +1 -0
- package/dist/{types → esm/types}/index.d.ts +1 -1
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/jobObject.js +1 -0
- package/dist/{types → esm/types}/mapstyle.d.ts +6 -2
- package/dist/esm/types/mapstyle.js +1 -0
- package/dist/esm/utils/browser.js +6 -0
- package/dist/{utils → esm/utils}/choropleth.d.ts +3 -3
- package/dist/esm/utils/choropleth.js +110 -0
- package/dist/esm/utils/fullscreen.js +40 -0
- package/dist/{utils → esm/utils}/geolocation.d.ts +1 -1
- package/dist/esm/utils/geolocation.js +93 -0
- package/dist/{utils → esm/utils}/graphhopper.d.ts +1 -1
- package/dist/esm/utils/graphhopper.js +41 -0
- package/dist/{utils → esm/utils}/helpers.d.ts +2 -2
- package/dist/esm/utils/helpers.js +116 -0
- package/dist/{utils → esm/utils}/language.d.ts +1 -1
- package/dist/esm/utils/language.js +170 -0
- package/dist/{utils → esm/utils}/models.d.ts +4 -4
- package/dist/esm/utils/models.js +103 -0
- package/dist/{utils → esm/utils}/overlays.d.ts +1 -1
- package/dist/esm/utils/overlays.js +87 -0
- package/dist/esm/utils/scalebar.js +52 -0
- package/dist/{utils → esm/utils}/svgHelpers.d.ts +4 -3
- package/dist/esm/utils/svgHelpers.js +1512 -0
- package/dist/{utils → esm/utils}/template.d.ts +2 -2
- package/dist/esm/utils/template.js +120 -0
- package/dist/{utils → esm/utils}/youtube.d.ts +1 -1
- package/dist/esm/utils/youtube.js +64 -0
- package/dist/favicon-32x32.png +0 -0
- package/dist/mapcreator-sdk.umd.cjs +3 -3
- package/dist/report.html +4950 -0
- package/package.json +7 -7
- package/dist/adornments/insetMap.d.ts +0 -3
- package/dist/adornments/northArrow.d.ts +0 -3
- package/dist/adornments/scalebar.d.ts +0 -3
- package/dist/controls/refreshMapControls.d.ts +0 -3
- package/dist/controls/webControls.d.ts +0 -4
- package/dist/index.d.ts +0 -3
- package/dist/locales/da_DK/strings.json.d.ts +0 -10
- package/dist/locales/de_DE/strings.json.d.ts +0 -10
- package/dist/locales/en_GB/strings.json.d.ts +0 -10
- package/dist/locales/es_ES/strings.json.d.ts +0 -10
- package/dist/locales/fr_FR/strings.json.d.ts +0 -10
- package/dist/locales/it_IT/strings.json.d.ts +0 -10
- package/dist/locales/nl_NL/strings.json.d.ts +0 -10
- package/dist/mapcreator-sdk.js +0 -39590
- package/dist/models/area.d.ts +0 -5
- package/dist/models/circle.d.ts +0 -5
- package/dist/models/dot.d.ts +0 -3
- package/dist/models/line.d.ts +0 -4
- package/dist/models/marker.d.ts +0 -5
- package/dist/models/polygon.d.ts +0 -5
- /package/dist/{controls → esm/controls}/controls.d.ts +0 -0
- /package/dist/{i18n.d.ts → esm/i18n.d.ts} +0 -0
- /package/dist/{types → esm/types}/geometry.d.ts +0 -0
- /package/dist/{types → esm/types}/jobObject.d.ts +0 -0
- /package/dist/{utils → esm/utils}/browser.d.ts +0 -0
- /package/dist/{utils → esm/utils}/fullscreen.d.ts +0 -0
- /package/dist/{utils → esm/utils}/scalebar.d.ts +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import searchIcon from '@/images/search.svg?raw';
|
|
2
|
+
import closeIcon from '@/images/close.svg?raw';
|
|
3
|
+
import { GraphHopperGeocoderService } from '@/utils/graphhopper';
|
|
4
|
+
import { t } from '@/i18n';
|
|
5
|
+
export class GeocoderControl {
|
|
6
|
+
map;
|
|
7
|
+
mapContainer;
|
|
8
|
+
container;
|
|
9
|
+
control;
|
|
10
|
+
input;
|
|
11
|
+
dropdown;
|
|
12
|
+
inputWrapper;
|
|
13
|
+
button;
|
|
14
|
+
isOpen = false;
|
|
15
|
+
geocoder = new GraphHopperGeocoderService();
|
|
16
|
+
suggestions = [];
|
|
17
|
+
items = [];
|
|
18
|
+
index = 0;
|
|
19
|
+
debounce;
|
|
20
|
+
constructor(map) {
|
|
21
|
+
this.map = map;
|
|
22
|
+
this.container = document.createElement('div');
|
|
23
|
+
this.control = document.createElement('div');
|
|
24
|
+
this.input = document.createElement('input');
|
|
25
|
+
this.dropdown = document.createElement('div');
|
|
26
|
+
this.inputWrapper = document.createElement('div');
|
|
27
|
+
this.button = document.createElement('button');
|
|
28
|
+
this.mapContainer = this.map.getContainer();
|
|
29
|
+
}
|
|
30
|
+
init() {
|
|
31
|
+
this.container.className = 'geocoder-container';
|
|
32
|
+
this.control.className = 'geocoder-control';
|
|
33
|
+
this.input.className = 'geocoder-input';
|
|
34
|
+
this.dropdown.className = 'geocoder-dropdown';
|
|
35
|
+
this.inputWrapper.className = 'geocoder-input-wrapper';
|
|
36
|
+
this.button.className = 'control-button';
|
|
37
|
+
this.input.type = 'text';
|
|
38
|
+
this.input.placeholder = t('search');
|
|
39
|
+
this.button.innerHTML = searchIcon;
|
|
40
|
+
const clearBtn = document.createElement('button');
|
|
41
|
+
clearBtn.className = 'geocoder-clear';
|
|
42
|
+
clearBtn.innerHTML = closeIcon;
|
|
43
|
+
const scrollWrapper = document.createElement('div');
|
|
44
|
+
scrollWrapper.className = 'geocoder-scrollwrapper';
|
|
45
|
+
scrollWrapper.append(this.dropdown);
|
|
46
|
+
this.inputWrapper.append(this.input, clearBtn);
|
|
47
|
+
this.control.append(this.button, this.inputWrapper, scrollWrapper);
|
|
48
|
+
clearBtn.addEventListener('click', () => this.clearAll());
|
|
49
|
+
this.button.addEventListener('click', () => this.toggle());
|
|
50
|
+
this.input.addEventListener('input', () => this.onInput());
|
|
51
|
+
this.input.addEventListener('keydown', e => this.onKeyDown(e));
|
|
52
|
+
this.dropdown.addEventListener('mousemove', e => this.onMouseMove(e));
|
|
53
|
+
this.mapContainer.addEventListener('mousedown', e => this.clickOutside(e));
|
|
54
|
+
window.addEventListener('resize', () => this.setMaxSizes());
|
|
55
|
+
this.setMaxSizes();
|
|
56
|
+
this.updateVisibility();
|
|
57
|
+
this.container.append(this.control);
|
|
58
|
+
return this.container;
|
|
59
|
+
}
|
|
60
|
+
clickOutside(e) {
|
|
61
|
+
if (e.target instanceof Node && !this.control.contains(e.target)) {
|
|
62
|
+
this.hide();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
setMaxSizes() {
|
|
66
|
+
const { width, height } = this.mapContainer.getBoundingClientRect();
|
|
67
|
+
this.control.style.maxWidth = `${width - 40}px`;
|
|
68
|
+
this.dropdown.style.maxHeight = `${Math.min(310, height - 63)}px`;
|
|
69
|
+
}
|
|
70
|
+
toggle() {
|
|
71
|
+
this.isOpen = !this.isOpen;
|
|
72
|
+
this.button.classList.toggle('open');
|
|
73
|
+
this.updateVisibility();
|
|
74
|
+
if (this.isOpen) {
|
|
75
|
+
this.input.focus();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
hide() {
|
|
79
|
+
if (!this.isOpen) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.isOpen = false;
|
|
83
|
+
this.button.classList.remove('open');
|
|
84
|
+
this.updateVisibility();
|
|
85
|
+
}
|
|
86
|
+
clearDropdown() {
|
|
87
|
+
this.suggestions = [];
|
|
88
|
+
this.items = [];
|
|
89
|
+
this.dropdown.innerHTML = '';
|
|
90
|
+
}
|
|
91
|
+
clearAll() {
|
|
92
|
+
this.input.value = '';
|
|
93
|
+
this.clearDropdown();
|
|
94
|
+
}
|
|
95
|
+
updateVisibility() {
|
|
96
|
+
const show = this.isOpen;
|
|
97
|
+
this.inputWrapper.style.display = show ? 'flex' : 'none';
|
|
98
|
+
if (!show) {
|
|
99
|
+
this.clearAll();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
onInput() {
|
|
103
|
+
const query = this.input.value.trim();
|
|
104
|
+
if (this.debounce) {
|
|
105
|
+
clearTimeout(this.debounce);
|
|
106
|
+
}
|
|
107
|
+
if (query.length < 2) {
|
|
108
|
+
this.dropdown.innerHTML = '';
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.debounce = window.setTimeout(async () => {
|
|
112
|
+
this.suggestions = await this.geocoder.getLocationInBounds(query, this.map.getCenter(), 20);
|
|
113
|
+
this.items = [];
|
|
114
|
+
this.renderSuggestions();
|
|
115
|
+
}, 200);
|
|
116
|
+
}
|
|
117
|
+
renderSuggestions() {
|
|
118
|
+
this.dropdown.innerHTML = '';
|
|
119
|
+
this.items = [];
|
|
120
|
+
this.index = 0;
|
|
121
|
+
this.suggestions.forEach(suggestion => {
|
|
122
|
+
const el = document.createElement('div');
|
|
123
|
+
const title = document.createElement('div');
|
|
124
|
+
const subtitle = document.createElement('div');
|
|
125
|
+
el.className = 'geocoder-suggestion';
|
|
126
|
+
title.className = 'title';
|
|
127
|
+
subtitle.className = 'subtitle';
|
|
128
|
+
title.textContent = suggestion.labelTitle;
|
|
129
|
+
subtitle.textContent = suggestion.subtitle;
|
|
130
|
+
el.append(title, subtitle);
|
|
131
|
+
el.addEventListener('mousedown', e => {
|
|
132
|
+
e.stopPropagation();
|
|
133
|
+
this.goToSelection(suggestion);
|
|
134
|
+
});
|
|
135
|
+
this.dropdown.appendChild(el);
|
|
136
|
+
this.items.push({ data: suggestion, el });
|
|
137
|
+
});
|
|
138
|
+
this.updateHighlight();
|
|
139
|
+
}
|
|
140
|
+
updateHighlight() {
|
|
141
|
+
this.items.forEach((item, index) => {
|
|
142
|
+
item.el.classList.toggle('highlight', index === this.index);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
onKeyDown(e) {
|
|
146
|
+
if (e.key === 'ArrowUp') {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
this.index--;
|
|
149
|
+
if (this.index < 0) {
|
|
150
|
+
this.index = this.items.length - 1;
|
|
151
|
+
}
|
|
152
|
+
this.adjustScroll();
|
|
153
|
+
}
|
|
154
|
+
else if (e.key === 'ArrowDown') {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
this.index++;
|
|
157
|
+
if (this.index > this.items.length - 1) {
|
|
158
|
+
this.index = 0;
|
|
159
|
+
}
|
|
160
|
+
this.adjustScroll();
|
|
161
|
+
}
|
|
162
|
+
else if (e.key === 'Enter') {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
const item = this.items[this.index];
|
|
165
|
+
if (item) {
|
|
166
|
+
this.goToSelection(item.data);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (e.key === 'Escape') {
|
|
170
|
+
e.preventDefault();
|
|
171
|
+
this.hide();
|
|
172
|
+
}
|
|
173
|
+
this.updateHighlight();
|
|
174
|
+
}
|
|
175
|
+
onMouseMove(e) {
|
|
176
|
+
const el = e.target.closest('.geocoder-suggestion');
|
|
177
|
+
this.index = this.items.findIndex(item => item.el === el);
|
|
178
|
+
this.updateHighlight();
|
|
179
|
+
}
|
|
180
|
+
goToSelection(suggestion) {
|
|
181
|
+
if (suggestion.bbox) {
|
|
182
|
+
this.map.fitBounds(suggestion.bbox, { duration: 0, animate: false });
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
this.map.jumpTo({ center: suggestion.position, zoom: 16 });
|
|
186
|
+
}
|
|
187
|
+
this.input.value = suggestion.labelTitle;
|
|
188
|
+
this.clearDropdown();
|
|
189
|
+
}
|
|
190
|
+
adjustScroll() {
|
|
191
|
+
const item = this.items[this.index].el;
|
|
192
|
+
const dropdown = this.dropdown;
|
|
193
|
+
const dropdownBox = dropdown.getBoundingClientRect();
|
|
194
|
+
const itemBox = item.getBoundingClientRect();
|
|
195
|
+
if (itemBox.bottom > dropdownBox.bottom) {
|
|
196
|
+
dropdown.scrollTop += itemBox.bottom - dropdownBox.bottom;
|
|
197
|
+
}
|
|
198
|
+
else if (itemBox.top < dropdownBox.top) {
|
|
199
|
+
dropdown.scrollTop += itemBox.top - dropdownBox.top;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Map } from '@mapcreator/maplibre-gl';
|
|
1
|
+
import type { Map } from '@mapcreator/maplibre-gl';
|
|
2
2
|
export declare function useGeolocationButton(map: Map): HTMLElement;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import geolocationIcon from '@/images/geolocation.svg?raw';
|
|
2
|
+
import locatingIcon from '@/images/locating.svg?raw';
|
|
3
|
+
import { useButtonControl } from '@/controls/controls';
|
|
4
|
+
import { initLayersAndSources, showNotification, addLocationDot, createCircle, } from '@/utils/geolocation';
|
|
5
|
+
export function useGeolocationButton(map) {
|
|
6
|
+
let isLocating = false;
|
|
7
|
+
const updateIcons = (locating) => {
|
|
8
|
+
const button = document.querySelector('.geolocation-button');
|
|
9
|
+
const geoIcon = button?.querySelector('.geolocation-icon');
|
|
10
|
+
const locatingIconElem = button?.querySelector('.locating-icon');
|
|
11
|
+
if (geoIcon && locatingIconElem) {
|
|
12
|
+
geoIcon.classList.toggle('active', !locating);
|
|
13
|
+
locatingIconElem.classList.toggle('active', locating);
|
|
14
|
+
}
|
|
15
|
+
isLocating = locating;
|
|
16
|
+
};
|
|
17
|
+
const handleSuccess = (position) => {
|
|
18
|
+
const { longitude, latitude, accuracy } = position.coords;
|
|
19
|
+
const center = [longitude, latitude];
|
|
20
|
+
if (map.easeTo) {
|
|
21
|
+
map.easeTo({ center, zoom: 19, duration: 1000 });
|
|
22
|
+
}
|
|
23
|
+
else if (map.setCenter) {
|
|
24
|
+
map.setCenter(center);
|
|
25
|
+
}
|
|
26
|
+
const circleSource = map.getSource('location-circle');
|
|
27
|
+
if (circleSource) {
|
|
28
|
+
circleSource.setData(createCircle(longitude, latitude, accuracy / 2));
|
|
29
|
+
}
|
|
30
|
+
addLocationDot(map, longitude, latitude);
|
|
31
|
+
map.once('moveend', () => updateIcons(false));
|
|
32
|
+
};
|
|
33
|
+
const handleError = (error) => {
|
|
34
|
+
console.error('Geolocation error:', error);
|
|
35
|
+
updateIcons(false);
|
|
36
|
+
};
|
|
37
|
+
const onClick = () => {
|
|
38
|
+
if (isLocating) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!map.getSource('location-circle')) {
|
|
42
|
+
initLayersAndSources(map);
|
|
43
|
+
}
|
|
44
|
+
updateIcons(true);
|
|
45
|
+
if (!navigator.geolocation) {
|
|
46
|
+
showNotification();
|
|
47
|
+
updateIcons(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
navigator.geolocation.getCurrentPosition(handleSuccess, handleError, {
|
|
51
|
+
maximumAge: 60000,
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const control = {
|
|
56
|
+
type: 'button',
|
|
57
|
+
className: 'control-button geolocation-button',
|
|
58
|
+
content: `
|
|
59
|
+
<div class="location-icon geolocation-icon active">${geolocationIcon}</div>
|
|
60
|
+
<div class="location-icon locating-icon">${locatingIcon}</div>
|
|
61
|
+
`,
|
|
62
|
+
onClick,
|
|
63
|
+
};
|
|
64
|
+
return useButtonControl(control);
|
|
65
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import refreshIcon from '@/images/refresh.svg?raw';
|
|
2
|
+
import { useButtonControl } from '@/controls/controls';
|
|
3
|
+
export function useRefreshButton(map, initialPosition) {
|
|
4
|
+
const onClick = () => {
|
|
5
|
+
const container = map.getContainer();
|
|
6
|
+
let zoomCorrection = 0;
|
|
7
|
+
// Adjust map's zoom level to preserve viewport regardless of map size
|
|
8
|
+
if (container.clientWidth > 0 && container.clientHeight > 0) {
|
|
9
|
+
const scale = Math.min(container.clientWidth / initialPosition.width, container.clientHeight / initialPosition.height);
|
|
10
|
+
zoomCorrection = Math.log(scale) / Math.LN2;
|
|
11
|
+
}
|
|
12
|
+
map.easeTo({
|
|
13
|
+
center: initialPosition.center,
|
|
14
|
+
zoom: initialPosition.zoom - initialPosition.detailLevel + zoomCorrection,
|
|
15
|
+
pitch: initialPosition.pitch,
|
|
16
|
+
bearing: initialPosition.rotation,
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const control = {
|
|
20
|
+
type: 'button',
|
|
21
|
+
className: 'control-button refresh-button',
|
|
22
|
+
content: refreshIcon,
|
|
23
|
+
onClick,
|
|
24
|
+
};
|
|
25
|
+
return useButtonControl(control);
|
|
26
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { JobObjectWebControls } from '@/types/jobObject';
|
|
2
|
+
import type { InitialPositionInfo } from '@/types';
|
|
3
|
+
import type { Map } from '@mapcreator/maplibre-gl';
|
|
4
|
+
export declare function useWebControls(webControls: JobObjectWebControls, map: Map, initialPosition: InitialPositionInfo): HTMLElement;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isMobile } from '@/utils/browser';
|
|
2
|
+
import { useZoomInButton, useZoomOutButton } from '@/controls/zoomControls';
|
|
3
|
+
import { useFullScreenButton } from '@/controls/fullscreenControls';
|
|
4
|
+
import { useGeolocationButton } from '@/controls/geolocationControls';
|
|
5
|
+
import { useRefreshButton } from '@/controls/refreshMapControls';
|
|
6
|
+
import { GeocoderControl } from '@/controls/geocoderControl';
|
|
7
|
+
export function useWebControls(webControls, map, initialPosition) {
|
|
8
|
+
const controlContainer = document.createElement('div');
|
|
9
|
+
controlContainer.classList.add('web-control', 'adornment');
|
|
10
|
+
const expandedButtons = webControls.buttons.flatMap(btn => btn === 'zoom' ? ['zoomIn', 'zoomOut'] : btn);
|
|
11
|
+
const finalButtons = isMobile()
|
|
12
|
+
? expandedButtons.filter(btn => btn !== 'zoomIn' && btn !== 'zoomOut')
|
|
13
|
+
: expandedButtons;
|
|
14
|
+
finalButtons.forEach(btn => {
|
|
15
|
+
let buttonElem;
|
|
16
|
+
if (btn === 'zoomIn') {
|
|
17
|
+
buttonElem = useZoomInButton(map);
|
|
18
|
+
}
|
|
19
|
+
else if (btn === 'zoomOut') {
|
|
20
|
+
buttonElem = useZoomOutButton(map);
|
|
21
|
+
}
|
|
22
|
+
else if (btn === 'fullscreen') {
|
|
23
|
+
buttonElem = useFullScreenButton(map);
|
|
24
|
+
}
|
|
25
|
+
else if (btn === 'geolocation') {
|
|
26
|
+
buttonElem = useGeolocationButton(map);
|
|
27
|
+
}
|
|
28
|
+
else if (btn === 'refresh') {
|
|
29
|
+
buttonElem = useRefreshButton(map, initialPosition);
|
|
30
|
+
}
|
|
31
|
+
else if (btn === 'search') {
|
|
32
|
+
buttonElem = new GeocoderControl(map).init();
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
controlContainer.appendChild(buttonElem);
|
|
38
|
+
});
|
|
39
|
+
return controlContainer;
|
|
40
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import zoomInIcon from '@/images/plus.svg?raw';
|
|
2
|
+
import zoomOutIcon from '@/images/minus.svg?raw';
|
|
3
|
+
import { useButtonControl } from '@/controls/controls';
|
|
4
|
+
export function useZoomInButton(map) {
|
|
5
|
+
const onClick = () => map.zoomIn();
|
|
6
|
+
const control = {
|
|
7
|
+
type: 'button',
|
|
8
|
+
className: 'control-button zoom-in-button',
|
|
9
|
+
content: zoomInIcon,
|
|
10
|
+
onClick,
|
|
11
|
+
};
|
|
12
|
+
return useButtonControl(control);
|
|
13
|
+
}
|
|
14
|
+
export function useZoomOutButton(map) {
|
|
15
|
+
const onClick = () => map.zoomOut();
|
|
16
|
+
const control = {
|
|
17
|
+
type: 'button',
|
|
18
|
+
className: 'control-button zoom-out-button',
|
|
19
|
+
content: zoomOutIcon,
|
|
20
|
+
onClick,
|
|
21
|
+
};
|
|
22
|
+
return useButtonControl(control);
|
|
23
|
+
}
|
package/dist/esm/i18n.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable import/extensions */
|
|
2
|
+
import da_DK from '@/locales/da_DK/strings.json';
|
|
3
|
+
import de_DE from '@/locales/de_DE/strings.json';
|
|
4
|
+
import en_GB from '@/locales/en_GB/strings.json';
|
|
5
|
+
import es_ES from '@/locales/es_ES/strings.json';
|
|
6
|
+
import fr_FR from '@/locales/fr_FR/strings.json';
|
|
7
|
+
import it_IT from '@/locales/it_IT/strings.json';
|
|
8
|
+
import nl_NL from '@/locales/nl_NL/strings.json';
|
|
9
|
+
/* eslint-enable import/extensions */
|
|
10
|
+
const locales = { da_DK, de_DE, en_GB, es_ES, fr_FR, it_IT, nl_NL };
|
|
11
|
+
function selectBestLocale() {
|
|
12
|
+
const lang = navigator.language.replace('-', '_');
|
|
13
|
+
const availableLocales = Object.keys(locales);
|
|
14
|
+
return (availableLocales.find(x => x === lang) ??
|
|
15
|
+
availableLocales.find(x => x.split('_')[0] === lang.split('_')[0]) ??
|
|
16
|
+
'en_GB');
|
|
17
|
+
}
|
|
18
|
+
export const locale = selectBestLocale();
|
|
19
|
+
export function t(key) {
|
|
20
|
+
return locales[locale][key] ?? key;
|
|
21
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Suche",
|
|
3
|
+
"videoAlert": "Das Video ist in der veröffentlichten Karte sichtbar.",
|
|
4
|
+
"mobileHelpText": "Verwenden Sie zwei Finger um die Karte zu bewegen",
|
|
5
|
+
"windowsHelpText": "Verwenden Sie Strg + Scroll um in der Karte zu zoomen",
|
|
6
|
+
"macHelpText": "Verwenden Sie ⌘ + Scroll um in der Karte zu zoomen"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Buscar",
|
|
3
|
+
"videoAlert": "The video will only work when you publish the map",
|
|
4
|
+
"mobileHelpText": "Use dos dedos para mover el mapa",
|
|
5
|
+
"windowsHelpText": "Use Ctrl + desplazamiento para hacer zoom en el mapa",
|
|
6
|
+
"macHelpText": "Use ⌘ + desplazamiento para hacer zoom en el mapa"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Rechercher",
|
|
3
|
+
"videoAlert": "Votre vidéo sera diffusée sur la carte publiée",
|
|
4
|
+
"mobileHelpText": "Utilisez deux doigts pour déplacer la carte",
|
|
5
|
+
"windowsHelpText": "Utilisez Ctrl + défilement pour zoomer sur la carte",
|
|
6
|
+
"macHelpText": "Utilisez ⌘ + défilement pour zoomer sur la carte"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Cercare",
|
|
3
|
+
"videoAlert": "The video will only work when you publish the map",
|
|
4
|
+
"mobileHelpText": "Usa due dita per muovere la mappa",
|
|
5
|
+
"windowsHelpText": "Usa Ctrl + Scroll per ingrandire la mappa",
|
|
6
|
+
"macHelpText": "Usa ⌘ + Scroll per ingrandire la mappa"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Zoeken",
|
|
3
|
+
"videoAlert": "The video will only work when you publish the map",
|
|
4
|
+
"mobileHelpText": "Gebruik twee vingers om de kaart te bewegen",
|
|
5
|
+
"windowsHelpText": "Gebruik Ctrl + Scroll om de kaart te zoomen",
|
|
6
|
+
"macHelpText": "Gebruik ⌘ + Scroll om de kaart te zoomen"
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SvgCache } from '@/utils/svgHelpers';
|
|
2
|
+
import type { JobObjectAreaGroup } from '@/types/jobObject';
|
|
3
|
+
import type { Map as MapLibre } from '@mapcreator/maplibre-gl';
|
|
4
|
+
import type { Svgs } from '@/types';
|
|
5
|
+
export declare function addAreaGroup(map: MapLibre, group: JobObjectAreaGroup, beforeId: string, svgs: Svgs, svgCache: SvgCache, vectorUrl: string, accessToken: string): void;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { getAreaLayerId, getAreaSourceId } from '@/utils/models';
|
|
2
|
+
import { getColorValue, SvgCache } from '@/utils/svgHelpers';
|
|
3
|
+
import { getColorGenerator } from '@/utils/choropleth';
|
|
4
|
+
export function addAreaGroup(map, group, beforeId, svgs, svgCache, vectorUrl, accessToken) {
|
|
5
|
+
const colorGenerator = getColorGenerator(group);
|
|
6
|
+
const sources = new Map();
|
|
7
|
+
const layers = new Map();
|
|
8
|
+
for (const area of group.models) {
|
|
9
|
+
// MC-2870 The registry ensures the featureId is not undefined
|
|
10
|
+
const featureId = area.featureId;
|
|
11
|
+
const groupId = group.id;
|
|
12
|
+
const featureIds = [];
|
|
13
|
+
const sourceId = getAreaSourceId(area);
|
|
14
|
+
const layerId = getAreaLayerId(groupId, area);
|
|
15
|
+
const data = layers.get(layerId) ?? {
|
|
16
|
+
model: area,
|
|
17
|
+
featureIds,
|
|
18
|
+
modelIdToFillColor: {},
|
|
19
|
+
modelIdToFillPattern: {},
|
|
20
|
+
modelIdToOutlineColor: {},
|
|
21
|
+
modelIdToOutlineWidth: {},
|
|
22
|
+
};
|
|
23
|
+
if (area.visible ?? true) {
|
|
24
|
+
data.featureIds.push(featureId);
|
|
25
|
+
const patternKey = area.fillPattern !== undefined
|
|
26
|
+
? svgCache.getMapLibreImageKey(svgs[area.fillPattern], 2 * window.devicePixelRatio)
|
|
27
|
+
: null;
|
|
28
|
+
data.modelIdToFillColor[featureId] =
|
|
29
|
+
group.fillColor || area.fillColor
|
|
30
|
+
? getColorValue(area.dataBindings ?? {}, area.fillColor, group.fillColor, colorGenerator, group.choropleth?.unmatchedColor)
|
|
31
|
+
: '#000000';
|
|
32
|
+
data.modelIdToFillPattern[featureId] = patternKey;
|
|
33
|
+
data.modelIdToOutlineColor[featureId] =
|
|
34
|
+
group.outlineColor || area.outlineColor
|
|
35
|
+
? getColorValue(area.dataBindings ?? {}, area.outlineColor, group.outlineColor)
|
|
36
|
+
: '#000000';
|
|
37
|
+
data.modelIdToOutlineWidth[featureId] = area.outlineWidth ?? 0.5;
|
|
38
|
+
}
|
|
39
|
+
sources.set(sourceId, area);
|
|
40
|
+
layers.set(layerId, data);
|
|
41
|
+
}
|
|
42
|
+
for (const id of sources.keys()) {
|
|
43
|
+
if (map.getSource(id)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
map.addSource(id, {
|
|
47
|
+
type: 'vector',
|
|
48
|
+
url: `${vectorUrl}${sources.get(id).vectorUrl}?access_token=${accessToken}`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const id of layers.keys()) {
|
|
52
|
+
const { model } = layers.get(id);
|
|
53
|
+
const { sourceLayerId } = model;
|
|
54
|
+
const sourceId = getAreaSourceId(model);
|
|
55
|
+
map.addLayer({
|
|
56
|
+
id,
|
|
57
|
+
'type': 'fill',
|
|
58
|
+
'source': sourceId,
|
|
59
|
+
'source-layer': sourceLayerId,
|
|
60
|
+
'filter': ['literal', false],
|
|
61
|
+
'metadata': {
|
|
62
|
+
'mc-model-type': 'area',
|
|
63
|
+
'mc-model-id-prefix': model.vectorUrl,
|
|
64
|
+
'mc-group-id': group.id,
|
|
65
|
+
},
|
|
66
|
+
'paint': {
|
|
67
|
+
'fill-color': '#ffffff',
|
|
68
|
+
'fill-outline-color': '#000000',
|
|
69
|
+
'fill-antialias': false,
|
|
70
|
+
},
|
|
71
|
+
}, beforeId);
|
|
72
|
+
map.addLayer({
|
|
73
|
+
'id': `${id}-pattern`,
|
|
74
|
+
'type': 'fill',
|
|
75
|
+
'source': sourceId,
|
|
76
|
+
'source-layer': sourceLayerId,
|
|
77
|
+
'filter': ['literal', false],
|
|
78
|
+
'metadata': {
|
|
79
|
+
'mc-model-type': 'area',
|
|
80
|
+
'mc-model-id-prefix': model.vectorUrl,
|
|
81
|
+
'mc-group-id': group.id,
|
|
82
|
+
},
|
|
83
|
+
'paint': {
|
|
84
|
+
'fill-pattern': ['get', 'fill-pattern'],
|
|
85
|
+
},
|
|
86
|
+
'layout': {
|
|
87
|
+
visibility: 'visible',
|
|
88
|
+
},
|
|
89
|
+
}, beforeId);
|
|
90
|
+
map.addLayer({
|
|
91
|
+
'id': `${id}-outline`,
|
|
92
|
+
'type': 'line',
|
|
93
|
+
'source': sourceId,
|
|
94
|
+
'source-layer': sourceLayerId,
|
|
95
|
+
'filter': ['literal', false],
|
|
96
|
+
'metadata': {
|
|
97
|
+
'mc-model-type': 'area',
|
|
98
|
+
'mc-model-id-prefix': model.vectorUrl,
|
|
99
|
+
'mc-group-id': group.id,
|
|
100
|
+
},
|
|
101
|
+
'paint': {
|
|
102
|
+
'line-color': '#000000',
|
|
103
|
+
'line-width': 0.5,
|
|
104
|
+
},
|
|
105
|
+
}, beforeId);
|
|
106
|
+
}
|
|
107
|
+
layers.forEach((data, layerId) => {
|
|
108
|
+
const { featureIds, modelIdToFillColor, modelIdToFillPattern, modelIdToOutlineColor, modelIdToOutlineWidth, } = data;
|
|
109
|
+
map.setFilter(layerId, ['in', 'id', ...featureIds]);
|
|
110
|
+
map.setFilter(`${layerId}-outline`, ['in', 'id', ...featureIds]);
|
|
111
|
+
map.setPaintProperty(layerId, 'fill-color', [
|
|
112
|
+
'get',
|
|
113
|
+
[
|
|
114
|
+
'case',
|
|
115
|
+
['==', ['typeof', ['get', 'id']], 'number'],
|
|
116
|
+
['to-string', ['get', 'id']],
|
|
117
|
+
['get', 'id'],
|
|
118
|
+
],
|
|
119
|
+
['literal', modelIdToFillColor],
|
|
120
|
+
]);
|
|
121
|
+
map.setPaintProperty(`${layerId}-outline`, 'line-color', [
|
|
122
|
+
'get',
|
|
123
|
+
[
|
|
124
|
+
'case',
|
|
125
|
+
['==', ['typeof', ['get', 'id']], 'number'],
|
|
126
|
+
['to-string', ['get', 'id']],
|
|
127
|
+
['get', 'id'],
|
|
128
|
+
],
|
|
129
|
+
['literal', modelIdToOutlineColor],
|
|
130
|
+
]);
|
|
131
|
+
map.setPaintProperty(`${layerId}-outline`, 'line-width', [
|
|
132
|
+
'get',
|
|
133
|
+
[
|
|
134
|
+
'case',
|
|
135
|
+
['==', ['typeof', ['get', 'id']], 'number'],
|
|
136
|
+
['to-string', ['get', 'id']],
|
|
137
|
+
['get', 'id'],
|
|
138
|
+
],
|
|
139
|
+
['literal', modelIdToOutlineWidth],
|
|
140
|
+
]);
|
|
141
|
+
map.setFilter(`${layerId}-pattern`, [
|
|
142
|
+
'to-boolean',
|
|
143
|
+
[
|
|
144
|
+
'get',
|
|
145
|
+
[
|
|
146
|
+
'case',
|
|
147
|
+
['==', ['typeof', ['get', 'id']], 'number'],
|
|
148
|
+
['to-string', ['get', 'id']],
|
|
149
|
+
['get', 'id'],
|
|
150
|
+
],
|
|
151
|
+
['literal', modelIdToFillPattern],
|
|
152
|
+
],
|
|
153
|
+
]);
|
|
154
|
+
map.setPaintProperty(`${layerId}-pattern`, 'fill-pattern', [
|
|
155
|
+
'get',
|
|
156
|
+
[
|
|
157
|
+
'case',
|
|
158
|
+
['==', ['typeof', ['get', 'id']], 'number'],
|
|
159
|
+
['to-string', ['get', 'id']],
|
|
160
|
+
['get', 'id'],
|
|
161
|
+
],
|
|
162
|
+
['literal', modelIdToFillPattern],
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SvgCache } from '@/utils/svgHelpers';
|
|
2
|
+
import type { JobObjectCircleGroup } from '@/types/jobObject';
|
|
3
|
+
import type { Svgs } from '@/types';
|
|
4
|
+
import type { Map } from '@mapcreator/maplibre-gl';
|
|
5
|
+
export declare function addCircleGroup(map: Map, group: JobObjectCircleGroup, beforeId: string, svgs: Svgs, svgCache: SvgCache): void;
|