@sapui5/sap.ui.vbm 1.129.0 → 1.131.0
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/package.json +1 -1
- package/src/sap/ui/vbm/.library +1 -1
- package/src/sap/ui/vbm/Adapter.js +53 -2
- package/src/sap/ui/vbm/Adapter3D.js +1 -1
- package/src/sap/ui/vbm/VBI.js +43 -36
- package/src/sap/ui/vbm/VBIRenderer.js +7 -1
- package/src/sap/ui/vbm/Viewport.js +1 -1
- package/src/sap/ui/vbm/adapter3d/ColladaBounds.js +1 -1
- package/src/sap/ui/vbm/adapter3d/DragDropHandler.js +1 -1
- package/src/sap/ui/vbm/adapter3d/ModelHandler.js +1 -1
- package/src/sap/ui/vbm/adapter3d/ObjectFactory.js +1 -1
- package/src/sap/ui/vbm/adapter3d/PolygonHandler.js +1 -1
- package/src/sap/ui/vbm/adapter3d/RectangleTracker.js +1 -1
- package/src/sap/ui/vbm/adapter3d/SceneBuilder.js +1 -1
- package/src/sap/ui/vbm/adapter3d/VBIJSONParser.js +1 -1
- package/src/sap/ui/vbm/library.js +2 -2
- package/src/sap/ui/vbm/themes/base/img/Pin_images.json +33 -1
- package/src/sap/ui/vbm/vector/MapRenderer.js +872 -0
- package/src/sap/ui/vbm/vector/PayloadGenerator.js +130 -0
- package/src/sap/ui/vbm/vector/VBITransformer.js +897 -0
- package/src/sap/ui/vbm/vector/VectorUtils.js +146 -0
- package/src/sap/ui/vbm/vector/thirdparty/MaplibreStyles.js +723 -0
- package/src/sap/ui/vbm/vector/thirdparty/maplibre.css +682 -0
- package/src/sap/ui/vbm/vector/thirdparty/maplibregl.js +37950 -0
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
sap.ui.define([
|
|
4
|
+
"../lib/sapvbi",
|
|
5
|
+
"../VBIRenderer",
|
|
6
|
+
"./VectorUtils",
|
|
7
|
+
"./thirdparty/MaplibreStyles",
|
|
8
|
+
"./PayloadGenerator",
|
|
9
|
+
"./thirdparty/maplibregl",
|
|
10
|
+
"./VBITransformer"
|
|
11
|
+
], function (vb, VBIRenderer, VectorUtils, MaplibreStyles, PayloadGenerator) {
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
VBI.MapRenderer = {};
|
|
15
|
+
var map_container = "";
|
|
16
|
+
let isDragging = false;
|
|
17
|
+
let startY;
|
|
18
|
+
let startYpx;
|
|
19
|
+
let mapInitialZoom;
|
|
20
|
+
const scrollline_Length = 94 - 18;
|
|
21
|
+
const DRAG_THRESHOLD = 5;
|
|
22
|
+
let isDrawing = false;
|
|
23
|
+
let isCtrlPressed = false;
|
|
24
|
+
let lassoPoints = [];
|
|
25
|
+
var bounds = [];
|
|
26
|
+
let existingLines = [];
|
|
27
|
+
let predefinedMarkers = [];
|
|
28
|
+
let line = {};
|
|
29
|
+
let allMarkers = [];
|
|
30
|
+
let lineDrag = false;
|
|
31
|
+
let validDrop = false;
|
|
32
|
+
let start = null;
|
|
33
|
+
let current = null;
|
|
34
|
+
let isSelecting = false;
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
VBI.MapRenderer.setAdapter = (adapter) => {
|
|
38
|
+
this._adapter = adapter;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this._payloadGenerator = new PayloadGenerator(this._adapter);
|
|
42
|
+
// Process the GeoJSON spots and its properties
|
|
43
|
+
VBI.MapRenderer._processGeoSpot = (source, data) => {
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Process the GeoJSON routes/links and its properties
|
|
48
|
+
VBI.MapRenderer._processGeoRoutes = (source, data) => {
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
VBI.MapRenderer.renderMap = () => {
|
|
53
|
+
|
|
54
|
+
let geoJSON = VBI.VBITransformer.getTransformedJSON();
|
|
55
|
+
|
|
56
|
+
map_container = VBIRenderer.getId();
|
|
57
|
+
|
|
58
|
+
var styleSheet = document.createElement("style");
|
|
59
|
+
|
|
60
|
+
styleSheet.textContent = MaplibreStyles.loadStyles();
|
|
61
|
+
document.head.appendChild(styleSheet);
|
|
62
|
+
|
|
63
|
+
const map = VectorUtils.createMap(geoJSON, map_container);
|
|
64
|
+
|
|
65
|
+
class SAPMapNavControl {
|
|
66
|
+
onAdd(map) {
|
|
67
|
+
this.map = map;
|
|
68
|
+
// Create main container
|
|
69
|
+
this._container = document.createElement('div');
|
|
70
|
+
this._container.id = '__xmlview1--vbi-vbi-nav';
|
|
71
|
+
this._container.className = 'vbi-nav my-custom-control';
|
|
72
|
+
this._container.setAttribute('role', 'Navigation');
|
|
73
|
+
this._container.setAttribute('tabindex', '-1');
|
|
74
|
+
this._container.style.opacity = '0.5';
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
this._container.addEventListener('mouseover', function () {
|
|
78
|
+
this.style.opacity = '1';
|
|
79
|
+
this.style.boxShadow = '0 0 25px rgba(255, 0, 0, 0.8)';
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
this._container.addEventListener('mouseout', function () {
|
|
83
|
+
this.style.opacity = '0.5';
|
|
84
|
+
this.style.boxShadow = 'none';
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Create scroll area container
|
|
88
|
+
var scrollArea = document.createElement('div');
|
|
89
|
+
scrollArea.id = '__xmlview1--vbi-vbi-scrollarea';
|
|
90
|
+
scrollArea.className = 'vbi-scrollarea';
|
|
91
|
+
scrollArea.setAttribute('role', 'Slider');
|
|
92
|
+
scrollArea.setAttribute('tabindex', '0');
|
|
93
|
+
|
|
94
|
+
// Create scroll line upper ending div
|
|
95
|
+
var scrollLineUpperEnding = document.createElement('div');
|
|
96
|
+
scrollLineUpperEnding.id = '__xmlview1--vbi-vbi-scrolllineupperending';
|
|
97
|
+
scrollLineUpperEnding.className = 'vbi-scrolllineupperending';
|
|
98
|
+
scrollLineUpperEnding.setAttribute('role', 'Img');
|
|
99
|
+
scrollLineUpperEnding.setAttribute('tabindex', '-1');
|
|
100
|
+
scrollLineUpperEnding.style.cursor = 'pointer';
|
|
101
|
+
scrollLineUpperEnding.style.position = 'absolute';
|
|
102
|
+
scrollLineUpperEnding.top = '20px';
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
// Create scroll line div
|
|
106
|
+
var scrollLine = document.createElement('div');
|
|
107
|
+
scrollLine.id = '__xmlview1--vbi-vbi-scrollline';
|
|
108
|
+
scrollLine.className = 'vbi-scrollline';
|
|
109
|
+
scrollLine.setAttribute('role', 'Img');
|
|
110
|
+
scrollLine.setAttribute('tabindex', '-1');
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
// Create scroll line lower ending div
|
|
114
|
+
var scrollLineLowerEnding = document.createElement('div');
|
|
115
|
+
scrollLineLowerEnding.id = '__xmlview1--vbi-vbi-scrolllinelowerending';
|
|
116
|
+
scrollLineLowerEnding.className = 'vbi-scrolllinelowerending';
|
|
117
|
+
scrollLineLowerEnding.setAttribute('role', 'Img');
|
|
118
|
+
scrollLineLowerEnding.setAttribute('tabindex', '-1');
|
|
119
|
+
scrollLineLowerEnding.style.cursor = 'pointer';
|
|
120
|
+
scrollLineLowerEnding.style.position = 'absolute';
|
|
121
|
+
scrollLineLowerEnding.style.top = '100px';
|
|
122
|
+
|
|
123
|
+
// Create scroll point div
|
|
124
|
+
var scrollPoint = document.createElement('div');
|
|
125
|
+
scrollPoint.id = '__xmlview1--vbi-vbi-scrollpoint';
|
|
126
|
+
scrollPoint.className = 'vbi-scrollpoint';
|
|
127
|
+
scrollPoint.setAttribute('role', 'Button');
|
|
128
|
+
scrollPoint.setAttribute('aria-label', 'NAVCTL_TITLE_ZOOM');
|
|
129
|
+
scrollPoint.setAttribute('tabindex', '0');
|
|
130
|
+
scrollPoint.setAttribute('title', 'NAVCTL_TITLE_ZOOM');
|
|
131
|
+
scrollPoint.style.top = '4.43911px';
|
|
132
|
+
startYpx = 4.43911;
|
|
133
|
+
|
|
134
|
+
// Append scroll line elements to scroll area
|
|
135
|
+
scrollArea.appendChild(scrollLineUpperEnding);
|
|
136
|
+
scrollArea.appendChild(scrollLine);
|
|
137
|
+
scrollArea.appendChild(scrollLineLowerEnding);
|
|
138
|
+
scrollArea.appendChild(scrollPoint);
|
|
139
|
+
// Append scroll area to main container
|
|
140
|
+
this._container.appendChild(scrollArea);
|
|
141
|
+
|
|
142
|
+
// Create cursor div
|
|
143
|
+
var cursor = document.createElement('div');
|
|
144
|
+
cursor.id = '__xmlview1--vbi-vbi-cursor';
|
|
145
|
+
cursor.className = 'vbi-cursor';
|
|
146
|
+
cursor.setAttribute('role', 'Presentation');
|
|
147
|
+
cursor.setAttribute('tabindex', '-1');
|
|
148
|
+
// cursor.style.backgroundPosition = '-5px 305px';
|
|
149
|
+
|
|
150
|
+
// Append cursor to main container
|
|
151
|
+
this._container.appendChild(cursor);
|
|
152
|
+
|
|
153
|
+
// Create cursor grip container
|
|
154
|
+
var cursorGrip = document.createElement('div');
|
|
155
|
+
cursorGrip.id = '__xmlview1--vbi-vbi-cursor-grip';
|
|
156
|
+
cursorGrip.className = 'vbi-cursor-grip';
|
|
157
|
+
cursorGrip.setAttribute('role', 'Img');
|
|
158
|
+
cursorGrip.setAttribute('tabindex', '-1');
|
|
159
|
+
|
|
160
|
+
// Create cursor middle container
|
|
161
|
+
var cursorMiddle = document.createElement('div');
|
|
162
|
+
cursorMiddle.id = '__xmlview1--vbi-vbi-cursor-middle';
|
|
163
|
+
cursorMiddle.className = 'vbi-cursor-middle';
|
|
164
|
+
cursorMiddle.setAttribute('role', 'Img');
|
|
165
|
+
cursorMiddle.setAttribute('tabindex', '0');
|
|
166
|
+
|
|
167
|
+
// Create cursor left div
|
|
168
|
+
var cursorLeft = document.createElement('div');
|
|
169
|
+
cursorLeft.id = '__xmlview1--vbi-vbi-cursor-left';
|
|
170
|
+
cursorLeft.className = 'vbi-cursor-left';
|
|
171
|
+
cursorLeft.setAttribute('role', 'Button');
|
|
172
|
+
cursorLeft.setAttribute('aria-label', 'NAVCTL_TITLE_MOVE_LEFT');
|
|
173
|
+
cursorLeft.setAttribute('tabindex', '2');
|
|
174
|
+
cursorLeft.setAttribute('title', 'NAVCTL_TITLE_MOVE_LEFT');
|
|
175
|
+
// cursorLeft.style.backgroundPosition = '-134px 228px';
|
|
176
|
+
|
|
177
|
+
// Create cursor right div
|
|
178
|
+
var cursorRight = document.createElement('div');
|
|
179
|
+
cursorRight.id = '__xmlview1--vbi-vbi-cursor-right';
|
|
180
|
+
cursorRight.className = 'vbi-cursor-right';
|
|
181
|
+
cursorRight.setAttribute('role', 'Button');
|
|
182
|
+
cursorRight.setAttribute('aria-label', 'NAVCTL_TITLE_MOVE_RIGHT');
|
|
183
|
+
cursorRight.setAttribute('tabindex', '4');
|
|
184
|
+
cursorRight.setAttribute('title', 'NAVCTL_TITLE_MOVE_RIGHT');
|
|
185
|
+
|
|
186
|
+
// Create cursor top div
|
|
187
|
+
var cursorTop = document.createElement('div');
|
|
188
|
+
cursorTop.id = '__xmlview1--vbi-vbi-cursor-top';
|
|
189
|
+
cursorTop.className = 'vbi-cursor-top';
|
|
190
|
+
cursorTop.setAttribute('role', 'Button');
|
|
191
|
+
cursorTop.setAttribute('aria-label', 'NAVCTL_TITLE_MOVE_UP');
|
|
192
|
+
cursorTop.setAttribute('tabindex', '1');
|
|
193
|
+
cursorTop.setAttribute('title', 'NAVCTL_TITLE_MOVE_UP');
|
|
194
|
+
// cursorTop.style.backgroundPosition = '-82px 228px';
|
|
195
|
+
|
|
196
|
+
// Create cursor down div
|
|
197
|
+
var cursorDown = document.createElement('div');
|
|
198
|
+
cursorDown.id = '__xmlview1--vbi-vbi-cursor-down';
|
|
199
|
+
cursorDown.className = 'vbi-cursor-down';
|
|
200
|
+
cursorDown.setAttribute('role', 'Button');
|
|
201
|
+
cursorDown.setAttribute('aria-label', 'NAVCTL_TITLE_MOVE_DOWN');
|
|
202
|
+
cursorDown.setAttribute('tabindex', '5');
|
|
203
|
+
cursorDown.setAttribute('title', 'NAVCTL_TITLE_MOVE_DOWN');
|
|
204
|
+
|
|
205
|
+
// Create cursor reset div
|
|
206
|
+
var cursorReset = document.createElement('div');
|
|
207
|
+
cursorReset.id = '__xmlview1--vbi-vbi-cursor-reset';
|
|
208
|
+
cursorReset.className = 'vbi-cursor-reset';
|
|
209
|
+
cursorReset.setAttribute('role', 'Button');
|
|
210
|
+
cursorReset.setAttribute('aria-label', 'NAVCTL_TITLE_MOVE');
|
|
211
|
+
cursorReset.setAttribute('tabindex', '3');
|
|
212
|
+
cursorReset.setAttribute('title', 'NAVCTL_TITLE_MOVE');
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
// Append cursor buttons to cursor middle container
|
|
217
|
+
cursorMiddle.appendChild(cursorLeft);
|
|
218
|
+
cursorMiddle.appendChild(cursorRight);
|
|
219
|
+
cursorMiddle.appendChild(cursorTop);
|
|
220
|
+
cursorMiddle.appendChild(cursorDown);
|
|
221
|
+
cursorMiddle.appendChild(cursorReset);
|
|
222
|
+
|
|
223
|
+
cursorTop.addEventListener('click', function () {
|
|
224
|
+
map.panBy([0, -100]); // Move map up
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
cursorDown.addEventListener('click', function () {
|
|
228
|
+
map.panBy([0, 100]); // Move map down
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
cursorLeft.addEventListener('click', function () {
|
|
232
|
+
map.panBy([-100, 0]); // Move map left
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
cursorRight.addEventListener('click', function () {
|
|
236
|
+
map.panBy([100, 0]); // Move map right
|
|
237
|
+
});
|
|
238
|
+
cursorReset.addEventListener('click', function () {
|
|
239
|
+
map.setCenter([0, 0]); // Reset map
|
|
240
|
+
map.setZoom(0);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
// Function to handle mouse movement during dragging
|
|
246
|
+
function onMouseMove(event) {
|
|
247
|
+
if (!isDragging) return;
|
|
248
|
+
|
|
249
|
+
const currentY = event.clientY;
|
|
250
|
+
const deltaY = currentY - startY; // Calculate the difference in Y movement
|
|
251
|
+
|
|
252
|
+
// Get the current position of the scroll point
|
|
253
|
+
let newTop = parseInt(scrollPoint.style.top || "0px") + deltaY;
|
|
254
|
+
|
|
255
|
+
// Get the boundaries of the scroll line
|
|
256
|
+
const upperBoundary = 0;
|
|
257
|
+
const lowerBoundary = scrollLine.offsetHeight - scrollPoint.offsetHeight; // Full scroll range
|
|
258
|
+
|
|
259
|
+
// Enforce the boundaries
|
|
260
|
+
newTop = Math.max(upperBoundary, Math.min(newTop, lowerBoundary));
|
|
261
|
+
|
|
262
|
+
// Update the scroll point position to match mouse drag
|
|
263
|
+
scrollPoint.style.top = `${newTop}px`;
|
|
264
|
+
|
|
265
|
+
// Calculate zoom level based on the position of the scroll point
|
|
266
|
+
const zoomRange = map.getMaxZoom() - map.getMinZoom();
|
|
267
|
+
const scrollPositionRatio = (newTop - upperBoundary) / (lowerBoundary - upperBoundary);
|
|
268
|
+
const newZoom = map.getMinZoom() + scrollPositionRatio * zoomRange;
|
|
269
|
+
|
|
270
|
+
// Apply the zoom to the map
|
|
271
|
+
map.setZoom(newZoom);
|
|
272
|
+
|
|
273
|
+
// Reset `startY` to current Y position after each drag movement
|
|
274
|
+
startY = currentY;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Function to update scroll line position based on the map's zoom level
|
|
278
|
+
function updateScrollLinePosition() {
|
|
279
|
+
const zoomLevel = map.getZoom();
|
|
280
|
+
|
|
281
|
+
// Define boundaries
|
|
282
|
+
const upperBoundary = 0;
|
|
283
|
+
const lowerBoundary = scrollLine.offsetHeight - scrollPoint.offsetHeight;
|
|
284
|
+
|
|
285
|
+
// Calculate the maximum scrollable height
|
|
286
|
+
const maxScrollHeight = lowerBoundary - upperBoundary;
|
|
287
|
+
|
|
288
|
+
const minZoom = map.getMinZoom();
|
|
289
|
+
const maxZoom = map.getMaxZoom();
|
|
290
|
+
|
|
291
|
+
// Calculate the new scroll position based on the zoom level
|
|
292
|
+
const scrollPosition = ((zoomLevel - minZoom) / (maxZoom - minZoom)) * maxScrollHeight;
|
|
293
|
+
|
|
294
|
+
// Update the scroll point's position
|
|
295
|
+
scrollPoint.style.top = `${upperBoundary + scrollPosition}px`;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Attach event listeners to update the scroll line position on zoom and move
|
|
299
|
+
map.on('zoom', updateScrollLinePosition);
|
|
300
|
+
map.on('move', updateScrollLinePosition);
|
|
301
|
+
|
|
302
|
+
// Initialize the scroll line position when the map loads
|
|
303
|
+
updateScrollLinePosition();
|
|
304
|
+
|
|
305
|
+
// Event listeners for drag functionality
|
|
306
|
+
scrollPoint.addEventListener('mousedown', (event) => {
|
|
307
|
+
isDragging = true;
|
|
308
|
+
startY = event.clientY;
|
|
309
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
310
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Function to stop dragging
|
|
314
|
+
function onMouseUp() {
|
|
315
|
+
isDragging = false;
|
|
316
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
317
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Attach the onMouseUp event listener globally
|
|
321
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
322
|
+
|
|
323
|
+
// Append cursor middle to cursor grip
|
|
324
|
+
cursorGrip.appendChild(cursorMiddle);
|
|
325
|
+
|
|
326
|
+
// Append cursor grip to main container
|
|
327
|
+
this._container.appendChild(cursorGrip);
|
|
328
|
+
|
|
329
|
+
// Append main container to the map if available
|
|
330
|
+
if (map && map.getContainer()) {
|
|
331
|
+
map.getContainer().appendChild(this._container);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Return the main container
|
|
335
|
+
return this._container;
|
|
336
|
+
}
|
|
337
|
+
onRemove() {
|
|
338
|
+
this._container.parentNode.removeChild(this._container);
|
|
339
|
+
this.map = undefined;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
map.on('load', () => {
|
|
343
|
+
// Custom attribution/copyright control
|
|
344
|
+
map.addControl(new maplibregl.AttributionControl({
|
|
345
|
+
customAttribution: '<span>' + geoJSON[0].copyright + '</span>',
|
|
346
|
+
compact: false
|
|
347
|
+
})
|
|
348
|
+
);
|
|
349
|
+
// Scale control in mi,km or nm
|
|
350
|
+
map.addControl(new maplibregl.ScaleControl({
|
|
351
|
+
maxWidth: 80,
|
|
352
|
+
unit: geoJSON[0].scaleType
|
|
353
|
+
}));
|
|
354
|
+
|
|
355
|
+
// Parsing GeoJSON for each type of object
|
|
356
|
+
map.addSource('geojson-source', {
|
|
357
|
+
'type': 'geojson',
|
|
358
|
+
'data': geoJSON[1]
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
map.addControl(new SAPMapNavControl(), 'top-left');
|
|
363
|
+
// First layer for the border (wider line)
|
|
364
|
+
map.addLayer({
|
|
365
|
+
'id': 'geojson-source-route-border',
|
|
366
|
+
'type': 'line',
|
|
367
|
+
'source': 'geojson-source',
|
|
368
|
+
'layout': {
|
|
369
|
+
'line-join': 'round',
|
|
370
|
+
'line-cap': 'butt'
|
|
371
|
+
},
|
|
372
|
+
'paint': {
|
|
373
|
+
'line-color': ['get', 'BorderColor'],
|
|
374
|
+
'line-width': ['get', 'BorderWidth'] // Slightly wider for border effect
|
|
375
|
+
},
|
|
376
|
+
'filter': ['==', '$type', 'LineString']
|
|
377
|
+
});
|
|
378
|
+
map.addLayer({
|
|
379
|
+
'id': 'geojson-source-route',
|
|
380
|
+
'type': 'line',
|
|
381
|
+
'source': 'geojson-source',
|
|
382
|
+
'layout': {
|
|
383
|
+
'line-join': 'round',
|
|
384
|
+
'line-cap': 'butt'
|
|
385
|
+
},
|
|
386
|
+
'paint': {
|
|
387
|
+
'line-color': ['get', 'Color'],
|
|
388
|
+
'line-width': ['get', 'LineWidth']
|
|
389
|
+
},
|
|
390
|
+
'filter': ['==', '$type', 'LineString']
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Create a popup, but don't add it to the map yet.
|
|
394
|
+
const popup = new maplibregl.Popup({
|
|
395
|
+
closeButton: false,
|
|
396
|
+
closeOnClick: false
|
|
397
|
+
});
|
|
398
|
+
// add markers to map only for Points
|
|
399
|
+
bounds = [];
|
|
400
|
+
geoJSON[1].features.forEach((marker) => {
|
|
401
|
+
let markerCoordinates = marker.geometry.coordinates;
|
|
402
|
+
if (marker.geometry.type === 'Point') {
|
|
403
|
+
// create a DOM element for the marker (parent div)
|
|
404
|
+
const el = VectorUtils.createSpotElement(marker);
|
|
405
|
+
|
|
406
|
+
// Create child element for the SAP icon (icon overlay)
|
|
407
|
+
const child_el = VectorUtils.createIconElement(marker.properties.Icon);
|
|
408
|
+
|
|
409
|
+
// Append the icon inside the marker
|
|
410
|
+
el.appendChild(child_el);
|
|
411
|
+
// add marker to map
|
|
412
|
+
let spot = new maplibregl.Marker({
|
|
413
|
+
element: el,
|
|
414
|
+
draggable: true
|
|
415
|
+
}).setLngLat(marker.geometry.coordinates)
|
|
416
|
+
.on('dragend', onDragEnd)
|
|
417
|
+
.addTo(map);
|
|
418
|
+
let originalpos = spot.getLngLat();
|
|
419
|
+
allMarkers.push(spot);
|
|
420
|
+
|
|
421
|
+
function onDragEnd() {
|
|
422
|
+
const lngLat = spot.getLngLat();
|
|
423
|
+
if (lngLat !== 0) {
|
|
424
|
+
spot.setLngLat(originalpos);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Function to return a promise that resolves when the map is clicked
|
|
428
|
+
function getClickCoordinates() {
|
|
429
|
+
return new Promise((resolve) => {
|
|
430
|
+
map.once('click', function (e) {
|
|
431
|
+
resolve(e.lngLat); // Resolve with the clicked coordinates
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
el.addEventListener('mouseenter', () => {
|
|
437
|
+
//Check if a line is dragged here
|
|
438
|
+
if (lineDrag) {
|
|
439
|
+
validDrop = true;
|
|
440
|
+
el.style.cursor = 'copy';
|
|
441
|
+
} else {
|
|
442
|
+
// Change the cursor style as a UI indicator
|
|
443
|
+
el.style.cursor = 'pointer';
|
|
444
|
+
popup.setLngLat(marker.geometry.coordinates).setHTML(marker.properties.ToolTip).addTo(map);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
});
|
|
448
|
+
async function triggerPayloadSpot(e, event) {
|
|
449
|
+
let clickCoordinates = null;
|
|
450
|
+
if (event === 'DETAIL_REQUEST') {
|
|
451
|
+
// First, wait for the map click and get the coordinates
|
|
452
|
+
clickCoordinates = await getClickCoordinates();
|
|
453
|
+
} else {
|
|
454
|
+
clickCoordinates = { lng: marker.geometry.coordinates[0], lat: marker.geometry.coordinates[1] };
|
|
455
|
+
}
|
|
456
|
+
marker.properties.x = e.layerX;
|
|
457
|
+
marker.properties.y = e.layerY;
|
|
458
|
+
PayloadGenerator.objectClick('Spot', event, marker, clickCoordinates);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
el.addEventListener('click', (e) => {
|
|
462
|
+
//Trigger payload
|
|
463
|
+
triggerPayloadSpot(e, 'DETAIL_REQUEST');
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
el.addEventListener('contextmenu', (e) => {
|
|
467
|
+
//Trigger payload
|
|
468
|
+
triggerPayloadSpot(e, 'CONTEXT_MENU_REQUEST');
|
|
469
|
+
var dropdown = marker.properties.menu;
|
|
470
|
+
var i, y;
|
|
471
|
+
var openDropdown = [];
|
|
472
|
+
for (i = 0; i < dropdown.MenuItem.length; i++) {
|
|
473
|
+
openDropdown[i] = dropdown.MenuItem[i].text + "<br>";
|
|
474
|
+
}
|
|
475
|
+
// document.getElementById("openDropdown[0]").innerHTML = "dsa";
|
|
476
|
+
// }
|
|
477
|
+
// const e2 = document.createElement('div');
|
|
478
|
+
// e2.className = 'contextmenu';
|
|
479
|
+
// Initialize the menu
|
|
480
|
+
const menuElement = document.getElementById('menu');
|
|
481
|
+
var dropdownContent = VectorUtils.createDropdownMenu(marker.properties.menu);
|
|
482
|
+
// menuElement.appendChild(dropdownContent);
|
|
483
|
+
popup.setLngLat(marker.geometry.coordinates).setHTML(dropdownContent.innerHTML).addTo(map);
|
|
484
|
+
// Prevent popup from closing when hovering inside
|
|
485
|
+
popup._container.addEventListener('mouseenter', () => {
|
|
486
|
+
// // This keeps the popup open
|
|
487
|
+
popup.setLngLat(marker.geometry.coordinates).addTo(map);
|
|
488
|
+
// console.log(`Clicked on: ${item.text}`);
|
|
489
|
+
});
|
|
490
|
+
// Attach event listeners for interactivity after the popup opens
|
|
491
|
+
popup.on('open', () => {
|
|
492
|
+
const popupElement = popup.getElement();
|
|
493
|
+
const menuContainer = popupElement.querySelector('.dropdown-content');
|
|
494
|
+
|
|
495
|
+
// Toggle dropdown visibility
|
|
496
|
+
popupElement.addEventListener('click', (event) => {
|
|
497
|
+
event.stopPropagation();
|
|
498
|
+
menuContainer.style.display = menuContainer.style.display === 'block' ? 'none' : 'block';
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Hide menu when clicking outside
|
|
502
|
+
// document.addEventListener('click', () => {
|
|
503
|
+
// menuContainer.style.display = 'none';
|
|
504
|
+
// });
|
|
505
|
+
|
|
506
|
+
// Handle submenu toggling
|
|
507
|
+
popupElement.querySelectorAll('li').forEach(li => {
|
|
508
|
+
const submenu = li.querySelector('ul');
|
|
509
|
+
|
|
510
|
+
li.addEventListener('click', (event) => {
|
|
511
|
+
event.stopPropagation();
|
|
512
|
+
|
|
513
|
+
if (submenu) {
|
|
514
|
+
submenu.style.display = submenu.style.display === 'block' ? 'none' : 'block'; // Keep submenu open when hovered
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (submenu) {
|
|
518
|
+
submenu.addEventListener('click', () => {
|
|
519
|
+
submenu.style.display = submenu.style.display === 'block' ? 'none' : 'block'; // Keep submenu open when hovered
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
submenu.addEventListener('mouseleave', () => {
|
|
523
|
+
submenu.style.display = submenu.style.display === 'block' ? 'none' : 'block'; // Hide submenu when mouse leaves
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
el.addEventListener('mouseleave', () => {
|
|
535
|
+
map.getCanvas().style.cursor = '';
|
|
536
|
+
popup.remove();
|
|
537
|
+
validDrop = false;
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Check if the coordinates already exist in predefinedMarkers
|
|
541
|
+
let exists = predefinedMarkers.some(
|
|
542
|
+
(coords) => coords[0] === markerCoordinates[0] && coords[1] === markerCoordinates[1]
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
// If it doesn't exist, push the new coordinates
|
|
546
|
+
if (!exists) {
|
|
547
|
+
predefinedMarkers.push(markerCoordinates);
|
|
548
|
+
}
|
|
549
|
+
} else if (marker.geometry.type == "LineString") {
|
|
550
|
+
line.id = "line_" + marker.id;
|
|
551
|
+
line.coordinates = marker.geometry.coordinates;
|
|
552
|
+
existingLines.push(line);
|
|
553
|
+
}
|
|
554
|
+
if (marker.geometry.type == "LineString") {
|
|
555
|
+
markerCoordinates.forEach((line) => {
|
|
556
|
+
let exists = bounds.some(
|
|
557
|
+
(coords) => coords[0] === line[0] && coords[1] === line[1]
|
|
558
|
+
);
|
|
559
|
+
//If it doesn't exist, push the new coordinates
|
|
560
|
+
if (!exists) {
|
|
561
|
+
bounds.push(line);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
} else {
|
|
565
|
+
// Check if the coordinates already exist in predefinedMarkers
|
|
566
|
+
let exists = bounds.some(
|
|
567
|
+
(coords) => coords[0] === markerCoordinates[0] && coords[1] === markerCoordinates[1]
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// If it doesn't exist, push the new coordinates
|
|
571
|
+
if (!exists) {
|
|
572
|
+
bounds.push(markerCoordinates);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
//Focus the map into the features
|
|
579
|
+
var zoombounds = bounds.reduce((zoombounds, coord) => {
|
|
580
|
+
return zoombounds.extend(coord);
|
|
581
|
+
}, new maplibregl.LngLatBounds(bounds[0], bounds[0]));
|
|
582
|
+
|
|
583
|
+
map.fitBounds(zoombounds, {
|
|
584
|
+
padding: 150
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
// Change mouse cursor when hovering over the line
|
|
590
|
+
map.on('mouseenter', 'geojson-source-route', function () {
|
|
591
|
+
map.getCanvas().style.cursor = 'pointer';
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Revert mouse cursor back when not hovering
|
|
595
|
+
map.on('mouseleave', 'geojson-source-route', function () {
|
|
596
|
+
map.getCanvas().style.cursor = '';
|
|
597
|
+
});
|
|
598
|
+
map.on('click', 'geojson-source-route', function (e) {
|
|
599
|
+
//Trigger payload
|
|
600
|
+
triggerPayloadRoute(e, 'DETAIL_REQUEST');
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
map.on('contextmenu', 'geojson-source-route', function (e) {
|
|
604
|
+
//Trigger payload
|
|
605
|
+
triggerPayloadRoute(e, 'CONTEXT_MENU_REQUEST');
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
function triggerPayloadRoute(e, event) {
|
|
609
|
+
const coordinates = e.lngLat;
|
|
610
|
+
// Get the GeoJSON properties of the clicked line feature
|
|
611
|
+
var route = e.features[0];
|
|
612
|
+
route.properties.x = e.point.x;
|
|
613
|
+
route.properties.y = e.point.y;
|
|
614
|
+
|
|
615
|
+
PayloadGenerator.objectClick('Link', event, route, coordinates);
|
|
616
|
+
}
|
|
617
|
+
function onUp(e) {
|
|
618
|
+
const coords = e.lngLat;
|
|
619
|
+
|
|
620
|
+
if (validDrop) {
|
|
621
|
+
// Perform action for valid drop
|
|
622
|
+
console.log('Dropped on valid target');
|
|
623
|
+
} else {
|
|
624
|
+
// Perform action for invalid drop
|
|
625
|
+
console.log('Invalid drop');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Reset cursor and remove event listeners
|
|
629
|
+
map.getCanvas().style.cursor = '';
|
|
630
|
+
map.off('mousemove', onMove);
|
|
631
|
+
map.off('touchmove', onMove);
|
|
632
|
+
lineDrag = false;
|
|
633
|
+
validDrop = false;
|
|
634
|
+
}
|
|
635
|
+
map.on('mousedown', 'geojson-source-route', (e) => {
|
|
636
|
+
// Check if the left mouse button is clicked (button === 0)
|
|
637
|
+
if (e.originalEvent.button === 0) {
|
|
638
|
+
// Prevent the default map drag behavior.
|
|
639
|
+
e.preventDefault();
|
|
640
|
+
lineDrag = true;
|
|
641
|
+
|
|
642
|
+
// Add move and up event listeners
|
|
643
|
+
map.on('mousemove', onMove);
|
|
644
|
+
map.once('mouseup', onUp);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
function onMove(e) {
|
|
649
|
+
const features = map.queryRenderedFeatures(e.point, {
|
|
650
|
+
layers: ['geojson-source-route']
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
if (features.length || validDrop) {
|
|
654
|
+
map.getCanvas().style.cursor = 'copy';
|
|
655
|
+
|
|
656
|
+
} else {
|
|
657
|
+
// If not over a valid feature, show the "not-allowed" cursor
|
|
658
|
+
map.getCanvas().style.cursor = 'not-allowed';
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// https://docs.mapbox.com/mapbox-gl-js/api/map/#map#flyto
|
|
663
|
+
map.on('contextmenu', (e) => {
|
|
664
|
+
// The event object (e) contains information like the
|
|
665
|
+
// coordinates of the point on the map that was clicked.
|
|
666
|
+
// FireAction
|
|
667
|
+
console.log('A contextmenu event has occurred at ' + e.lngLat);
|
|
668
|
+
//to be removed and replaced dynamically from file
|
|
669
|
+
// map.flyTo({
|
|
670
|
+
// center: [e.lngLat.lat, e.lngLat.lng],
|
|
671
|
+
// zoom: 5,
|
|
672
|
+
// speed: 5
|
|
673
|
+
// });
|
|
674
|
+
})
|
|
675
|
+
//VBI.VBITransformer.clearTransformedJSON();
|
|
676
|
+
|
|
677
|
+
document.addEventListener('keydown', function (event) {
|
|
678
|
+
switch (event.code) {
|
|
679
|
+
case 'Plus': // Zoom in when '+' is pressed
|
|
680
|
+
map.zoomIn();
|
|
681
|
+
break;
|
|
682
|
+
case 'Minus': // Zoom out when '-' is pressed
|
|
683
|
+
map.zoomOut();
|
|
684
|
+
break;
|
|
685
|
+
case 'ArrowUp': // Pan up when the up arrow key is pressed
|
|
686
|
+
map.panBy([0, -100]);
|
|
687
|
+
break;
|
|
688
|
+
case 'ArrowDown': // Pan down when the down arrow key is pressed
|
|
689
|
+
map.panBy([0, 100]);
|
|
690
|
+
break;
|
|
691
|
+
case 'ArrowLeft': // Pan left when the left arrow key is pressed
|
|
692
|
+
map.panBy([-100, 0]);
|
|
693
|
+
break;
|
|
694
|
+
case 'ArrowRight': // Pan right when the right arrow key is pressed
|
|
695
|
+
map.panBy([100, 0]);
|
|
696
|
+
break;
|
|
697
|
+
case 'KeyR': // Reset map to initial view when 'r' is pressed
|
|
698
|
+
map.setCenter([0, 0]);
|
|
699
|
+
map.setZoom(2);
|
|
700
|
+
break;
|
|
701
|
+
default:
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
const box = document.createElement('div');
|
|
707
|
+
box.className = 'zoom-box';
|
|
708
|
+
//box.className = 'selection-box'
|
|
709
|
+
document.body.appendChild(box);
|
|
710
|
+
const mapContainer = document.getElementById('map');
|
|
711
|
+
const boxes = document.getElementById('selection-box');
|
|
712
|
+
window.addEventListener('keydown', (e) => {
|
|
713
|
+
if (e.code === 'ControlLeft') {
|
|
714
|
+
isCtrlPressed = true;
|
|
715
|
+
map.getCanvas().style.cursor = 'crosshair';
|
|
716
|
+
lassoPoints = [];
|
|
717
|
+
}
|
|
718
|
+
if (e.code === 'ShiftLeft') {
|
|
719
|
+
map.getCanvas().style.cursor = 'crosshair';
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
window.addEventListener('keyup', (e) => {
|
|
724
|
+
if (e.code === 'ControlLeft') {
|
|
725
|
+
isCtrlPressed = false;
|
|
726
|
+
if (lassoPoints.length > 2) {
|
|
727
|
+
completeLasso();
|
|
728
|
+
}
|
|
729
|
+
map.getCanvas().style.cursor = '';
|
|
730
|
+
}
|
|
731
|
+
if (e.code === 'ShiftLeft') {
|
|
732
|
+
map.getCanvas().style.cursor = '';
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
map.on('mousedown', (e) => {
|
|
736
|
+
if (isCtrlPressed) {
|
|
737
|
+
const clickedPoint = [e.lngLat.lng, e.lngLat.lat];
|
|
738
|
+
lassoPoints.push(clickedPoint);
|
|
739
|
+
isDrawing = true;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
else if (e.originalEvent.shiftKey) {
|
|
743
|
+
isDrawing = true;
|
|
744
|
+
start = e.point;
|
|
745
|
+
box.style.display = 'block';
|
|
746
|
+
box.style.left = `${e.point.x}px`;
|
|
747
|
+
box.style.top = `${e.point.y}px`;
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
map.on('mousemove', (e) => {
|
|
751
|
+
if (isCtrlPressed) {
|
|
752
|
+
const movingPoint = [e.lngLat.lng, e.lngLat.lat];
|
|
753
|
+
lassoPoints.push(movingPoint);
|
|
754
|
+
drawLassoLine();
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
else if (e.originalEvent.shiftKey) {
|
|
758
|
+
current = e.point;
|
|
759
|
+
const minX = Math.min(start.x, current.x);
|
|
760
|
+
const minY = Math.min(start.y, current.y);
|
|
761
|
+
const width = Math.abs(start.x - current.x);
|
|
762
|
+
const height = Math.abs(start.y - current.y);
|
|
763
|
+
box.style.left = `${minX}px`;
|
|
764
|
+
box.style.top = `${minY}px`;
|
|
765
|
+
box.style.width = `${width}px`;
|
|
766
|
+
box.style.height = `${height}px`;
|
|
767
|
+
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
map.on('mouseup', (e) => {
|
|
772
|
+
if (isCtrlPressed) {
|
|
773
|
+
// Complete Lasso Selection
|
|
774
|
+
isDrawing = false;
|
|
775
|
+
if (lassoPoints.length > 2) {
|
|
776
|
+
lassoPoints.push(lassoPoints[0]);
|
|
777
|
+
completeLasso();
|
|
778
|
+
}
|
|
779
|
+
} else if (e.originalEvent.shiftKey) {
|
|
780
|
+
isDrawing = false;
|
|
781
|
+
box.style.display = 'none';
|
|
782
|
+
box.style.width = '0px';
|
|
783
|
+
box.style.height = '0px';
|
|
784
|
+
const bounds = [
|
|
785
|
+
map.unproject([Math.min(start.x, current.x), Math.min(start.y, current.y)]),
|
|
786
|
+
map.unproject([Math.max(start.x, current.x), Math.max(start.y, current.y)])
|
|
787
|
+
];
|
|
788
|
+
console.log("Rectangular Zoom Bounds: ", bounds);
|
|
789
|
+
map.fitBounds(bounds, {
|
|
790
|
+
padding: 20
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
);
|
|
795
|
+
function drawLassoLine() {
|
|
796
|
+
if (map.getSource('lasso-line')) {
|
|
797
|
+
map.getSource('lasso-line').setData({
|
|
798
|
+
'type': 'LineString',
|
|
799
|
+
'coordinates': lassoPoints
|
|
800
|
+
});
|
|
801
|
+
} else {
|
|
802
|
+
map.addSource('lasso-line', {
|
|
803
|
+
'type': 'geojson',
|
|
804
|
+
'data': {
|
|
805
|
+
'type': 'LineString',
|
|
806
|
+
'coordinates': lassoPoints
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
map.addLayer({
|
|
810
|
+
'id': 'lasso-line-layer',
|
|
811
|
+
'type': 'line',
|
|
812
|
+
'source': 'lasso-line',
|
|
813
|
+
'paint': {
|
|
814
|
+
'line-color': '#000000',
|
|
815
|
+
'line-width': 2,
|
|
816
|
+
'line-dasharray': [2, 2]
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function completeLasso() {
|
|
823
|
+
if (map.getSource('lasso-polygon')) {
|
|
824
|
+
map.getSource('lasso-polygon').setData({
|
|
825
|
+
'type': 'Polygon',
|
|
826
|
+
'coordinates': [lassoPoints]
|
|
827
|
+
});
|
|
828
|
+
} else {
|
|
829
|
+
map.addSource('lasso-polygon', {
|
|
830
|
+
'type': 'geojson',
|
|
831
|
+
'data': {
|
|
832
|
+
'type': 'Polygon',
|
|
833
|
+
'coordinates': [lassoPoints]
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
map.addLayer({
|
|
837
|
+
'id': 'lasso-polygon-layer',
|
|
838
|
+
'type': 'fill',
|
|
839
|
+
'source': 'lasso-polygon',
|
|
840
|
+
'paint': {
|
|
841
|
+
'fill-color': '#088',
|
|
842
|
+
'fill-opacity': 0.5
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Remove lasso line and polygon after the selection is completed
|
|
848
|
+
setTimeout(() => {
|
|
849
|
+
map.removeLayer('lasso-line-layer');
|
|
850
|
+
map.removeSource('lasso-line');
|
|
851
|
+
map.removeLayer('lasso-polygon-layer');
|
|
852
|
+
map.removeSource('lasso-polygon');
|
|
853
|
+
lassoPoints = [];
|
|
854
|
+
}, 1000);
|
|
855
|
+
map.getCanvas().style.cursor = ''; // Reset cursor after lasso is completed
|
|
856
|
+
}
|
|
857
|
+
map.on('click', () => {
|
|
858
|
+
if (isDrawing) {
|
|
859
|
+
clearSelectionBox();
|
|
860
|
+
isDrawing = false;
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
// Function to clear selection box
|
|
864
|
+
function clearSelectionBox() {
|
|
865
|
+
box.style.display = 'none';
|
|
866
|
+
box.style.width = '0px';
|
|
867
|
+
box.style.height = '0px';
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
});
|
|
872
|
+
|