@sapui5/sap.ui.vbm 1.131.0 → 1.133.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.
@@ -6,9 +6,13 @@ sap.ui.define([
6
6
  "./VectorUtils",
7
7
  "./thirdparty/MaplibreStyles",
8
8
  "./PayloadGenerator",
9
+ "./RectangularSelection",
10
+ "./LassoSelection",
11
+ "sap/ui/core/Lib",
12
+ //"../lib/sapscene",
9
13
  "./thirdparty/maplibregl",
10
14
  "./VBITransformer"
11
- ], function (vb, VBIRenderer, VectorUtils, MaplibreStyles, PayloadGenerator) {
15
+ ], function (vb, VBIRenderer, VectorUtils, MaplibreStyles, PayloadGenerator, RectangularSelection, LassoSelection, Lib) {
12
16
  'use strict';
13
17
 
14
18
  VBI.MapRenderer = {};
@@ -16,29 +20,21 @@ sap.ui.define([
16
20
  let isDragging = false;
17
21
  let startY;
18
22
  let startYpx;
19
- let mapInitialZoom;
20
- const scrollline_Length = 94 - 18;
21
- const DRAG_THRESHOLD = 5;
22
23
  let isDrawing = false;
23
24
  let isCtrlPressed = false;
24
25
  let lassoPoints = [];
25
26
  var bounds = [];
26
- let existingLines = [];
27
27
  let predefinedMarkers = [];
28
- let line = {};
29
28
  let allMarkers = [];
30
29
  let lineDrag = false;
31
30
  let validDrop = false;
32
- let start = null;
33
- let current = null;
34
- let isSelecting = false;
35
-
31
+ VBI.MapRenderer.name = undefined;
36
32
 
37
33
  VBI.MapRenderer.setAdapter = (adapter) => {
38
34
  this._adapter = adapter;
35
+ this._payloadGenerator = new PayloadGenerator(this._adapter);
39
36
  }
40
37
 
41
- this._payloadGenerator = new PayloadGenerator(this._adapter);
42
38
  // Process the GeoJSON spots and its properties
43
39
  VBI.MapRenderer._processGeoSpot = (source, data) => {
44
40
 
@@ -61,7 +57,16 @@ sap.ui.define([
61
57
  document.head.appendChild(styleSheet);
62
58
 
63
59
  const map = VectorUtils.createMap(geoJSON, map_container);
64
-
60
+ const canvas = map.getCanvasContainer();
61
+ const rectangularSelection = new RectangularSelection(map);
62
+ const lassoSelection = new LassoSelection(map);
63
+ // Set `true` to dispatch the event before other functions
64
+ // call it. This is necessary for disabling the default map
65
+ // dragging behaviour.
66
+ canvas.addEventListener('mousedown', (e) => rectangularSelection.mouseDown(e, this.Rpressed), true);
67
+ canvas.addEventListener('mousedown', (e) => lassoSelection.mouseDown(e, this.Apressed), true);
68
+ map.touchZoomRotate.enable();
69
+ this.map = map;
65
70
  class SAPMapNavControl {
66
71
  onAdd(map) {
67
72
  this.map = map;
@@ -73,6 +78,68 @@ sap.ui.define([
73
78
  this._container.setAttribute('tabindex', '-1');
74
79
  this._container.style.opacity = '0.5';
75
80
 
81
+ // ensures the library is loaded
82
+ Lib.load({ name: "sap.ui.vbm.i18n" });
83
+
84
+ // ResourceBundle can be retrieved
85
+ var oResourceBundle = Lib.getResourceBundleFor("sap.ui.vbm.i18n")
86
+
87
+ var sTooltipMoveLeft = oResourceBundle.getText("NAVCTL_TITLE_MOVE_LEFT");
88
+ var sTooltipMoveRight = oResourceBundle.getText("NAVCTL_TITLE_MOVE_RIGHT");
89
+ var sTooltipMoveUp = oResourceBundle.getText("NAVCTL_TITLE_MOVE_UP");
90
+ var sTooltipMoveDown = oResourceBundle.getText("NAVCTL_TITLE_MOVE_DOWN");
91
+ var sTooltipMove = oResourceBundle.getText("NAVCTL_TITLE_MOVE");
92
+ var sTooltipZoom = oResourceBundle.getText("NAVCTL_TITLE_ZOOM");
93
+
94
+
95
+ //Create cursor left div
96
+
97
+ var cursorLeft = document.createElement('div');
98
+ cursorLeft.id = '__xmlview1--vbi-vbi-cursor-left';
99
+ cursorLeft.className = 'vbi-cursor-left';
100
+ cursorLeft.setAttribute('role', sap.ui.core.AccessibleRole.Button);
101
+ cursorLeft.setAttribute('aria-label', sTooltipMoveLeft);
102
+ cursorLeft.setAttribute('tabindex', '2');
103
+ cursorLeft.setAttribute('title', sTooltipMoveLeft);
104
+
105
+ // Create cursor right div
106
+
107
+ var cursorRight = document.createElement('div');
108
+ cursorRight.id = '__xmlview1--vbi-vbi-cursor-right';
109
+ cursorRight.className = 'vbi-cursor-right';
110
+ cursorRight.setAttribute('role', 'Button');
111
+ cursorRight.setAttribute('aria-label', sTooltipMoveRight);
112
+ cursorRight.setAttribute('tabindex', '4');
113
+ cursorRight.setAttribute('title', sTooltipMoveRight);
114
+
115
+ // Create cursor top div
116
+
117
+ var cursorTop = document.createElement('div');
118
+ cursorTop.id = '__xmlview1--vbi-vbi-cursor-top';
119
+ cursorTop.className = 'vbi-cursor-top';
120
+ cursorTop.setAttribute('role', 'Button');
121
+ cursorTop.setAttribute('aria-label', sTooltipMoveUp);
122
+ cursorTop.setAttribute('tabindex', '1');
123
+ cursorTop.setAttribute('title', sTooltipMoveUp);
124
+
125
+ // Create cursor down div
126
+
127
+ var cursorDown = document.createElement('div');
128
+ cursorDown.id = '__xmlview1--vbi-vbi-cursor-down';
129
+ cursorDown.className = 'vbi-cursor-down';
130
+ cursorDown.setAttribute('role', 'Button');
131
+ cursorDown.setAttribute('aria-label', sTooltipMoveDown);
132
+ cursorDown.setAttribute('tabindex', '5');
133
+ cursorDown.setAttribute('title', sTooltipMoveDown);
134
+
135
+ // Create cursor reset div
136
+ var cursorReset = document.createElement('div');
137
+ cursorReset.id = '__xmlview1--vbi-vbi-cursor-reset';
138
+ cursorReset.className = 'vbi-cursor-reset';
139
+ cursorReset.setAttribute('role', 'Button');
140
+ cursorReset.setAttribute('aria-label', sTooltipMove);
141
+ cursorReset.setAttribute('tabindex', '3');
142
+ cursorReset.setAttribute('title', sTooltipMove);
76
143
 
77
144
  this._container.addEventListener('mouseover', function () {
78
145
  this.style.opacity = '1';
@@ -101,7 +168,6 @@ sap.ui.define([
101
168
  scrollLineUpperEnding.style.position = 'absolute';
102
169
  scrollLineUpperEnding.top = '20px';
103
170
 
104
-
105
171
  // Create scroll line div
106
172
  var scrollLine = document.createElement('div');
107
173
  scrollLine.id = '__xmlview1--vbi-vbi-scrollline';
@@ -109,7 +175,6 @@ sap.ui.define([
109
175
  scrollLine.setAttribute('role', 'Img');
110
176
  scrollLine.setAttribute('tabindex', '-1');
111
177
 
112
-
113
178
  // Create scroll line lower ending div
114
179
  var scrollLineLowerEnding = document.createElement('div');
115
180
  scrollLineLowerEnding.id = '__xmlview1--vbi-vbi-scrolllinelowerending';
@@ -118,16 +183,16 @@ sap.ui.define([
118
183
  scrollLineLowerEnding.setAttribute('tabindex', '-1');
119
184
  scrollLineLowerEnding.style.cursor = 'pointer';
120
185
  scrollLineLowerEnding.style.position = 'absolute';
121
- scrollLineLowerEnding.style.top = '100px';
186
+ scrollLineLowerEnding.style.top = '90px';
122
187
 
123
188
  // Create scroll point div
124
189
  var scrollPoint = document.createElement('div');
125
190
  scrollPoint.id = '__xmlview1--vbi-vbi-scrollpoint';
126
191
  scrollPoint.className = 'vbi-scrollpoint';
127
192
  scrollPoint.setAttribute('role', 'Button');
128
- scrollPoint.setAttribute('aria-label', 'NAVCTL_TITLE_ZOOM');
193
+ scrollPoint.setAttribute('aria-label', sTooltipZoom);
129
194
  scrollPoint.setAttribute('tabindex', '0');
130
- scrollPoint.setAttribute('title', 'NAVCTL_TITLE_ZOOM');
195
+ scrollPoint.setAttribute('title', sTooltipZoom);
131
196
  scrollPoint.style.top = '4.43911px';
132
197
  startYpx = 4.43911;
133
198
 
@@ -164,54 +229,6 @@ sap.ui.define([
164
229
  cursorMiddle.setAttribute('role', 'Img');
165
230
  cursorMiddle.setAttribute('tabindex', '0');
166
231
 
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
232
 
216
233
  // Append cursor buttons to cursor middle container
217
234
  cursorMiddle.appendChild(cursorLeft);
@@ -340,6 +357,10 @@ sap.ui.define([
340
357
  }
341
358
  }
342
359
  map.on('load', () => {
360
+
361
+ // Legend control
362
+ VBI.VBITransformer._createLegend(map_container);
363
+
343
364
  // Custom attribution/copyright control
344
365
  map.addControl(new maplibregl.AttributionControl({
345
366
  customAttribution: '<span>' + geoJSON[0].copyright + '</span>',
@@ -360,36 +381,7 @@ sap.ui.define([
360
381
 
361
382
 
362
383
  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
-
384
+ // map.addControl(new SAPMAPLgndControl(), 'top-right');
393
385
  // Create a popup, but don't add it to the map yet.
394
386
  const popup = new maplibregl.Popup({
395
387
  closeButton: false,
@@ -397,6 +389,7 @@ sap.ui.define([
397
389
  });
398
390
  // add markers to map only for Points
399
391
  bounds = [];
392
+ const pointFeatures = [];
400
393
  geoJSON[1].features.forEach((marker) => {
401
394
  let markerCoordinates = marker.geometry.coordinates;
402
395
  if (marker.geometry.type === 'Point') {
@@ -411,11 +404,13 @@ sap.ui.define([
411
404
  // add marker to map
412
405
  let spot = new maplibregl.Marker({
413
406
  element: el,
414
- draggable: true
407
+ draggable: true,
408
+ offset: [0, -25]
415
409
  }).setLngLat(marker.geometry.coordinates)
416
410
  .on('dragend', onDragEnd)
417
411
  .addTo(map);
418
412
  let originalpos = spot.getLngLat();
413
+ spot.customProperties = { Key: marker.properties.Key };
419
414
  allMarkers.push(spot);
420
415
 
421
416
  function onDragEnd() {
@@ -437,11 +432,19 @@ sap.ui.define([
437
432
  //Check if a line is dragged here
438
433
  if (lineDrag) {
439
434
  validDrop = true;
440
- el.style.cursor = 'copy';
435
+ if (!that.Apressed && !that.Rpressed) {
436
+ el.style.cursor = 'copy';
437
+ }
441
438
  } else {
442
439
  // 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);
440
+ if (!that.Apressed && !that.Rpressed) {
441
+ el.style.cursor = 'pointer';
442
+ }
443
+ if (that.Apressed || that.Rpressed) {
444
+ el.style.cursor = 'crosshair';
445
+ } else {
446
+ popup.setLngLat(marker.geometry.coordinates).setHTML(marker.properties.ToolTip).addTo(map);
447
+ }
445
448
  }
446
449
 
447
450
  });
@@ -453,8 +456,9 @@ sap.ui.define([
453
456
  } else {
454
457
  clickCoordinates = { lng: marker.geometry.coordinates[0], lat: marker.geometry.coordinates[1] };
455
458
  }
456
- marker.properties.x = e.layerX;
457
- marker.properties.y = e.layerY;
459
+ const xyobj = VectorUtils.GetEventVPCoordsObj(e, map_container);
460
+ marker.properties.x = xyobj.x;
461
+ marker.properties.y = xyobj.y;
458
462
  PayloadGenerator.objectClick('Spot', event, marker, clickCoordinates);
459
463
  };
460
464
 
@@ -466,73 +470,13 @@ sap.ui.define([
466
470
  el.addEventListener('contextmenu', (e) => {
467
471
  //Trigger payload
468
472
  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
473
  });
532
474
 
533
475
 
534
476
  el.addEventListener('mouseleave', () => {
535
- map.getCanvas().style.cursor = '';
477
+ if (!that.Apressed && !that.Rpressed) {
478
+ map.getCanvas().style.cursor = '';
479
+ }
536
480
  popup.remove();
537
481
  validDrop = false;
538
482
  });
@@ -547,10 +491,61 @@ sap.ui.define([
547
491
  predefinedMarkers.push(markerCoordinates);
548
492
  }
549
493
  } else if (marker.geometry.type == "LineString") {
550
- line.id = "line_" + marker.id;
551
- line.coordinates = marker.geometry.coordinates;
552
- existingLines.push(line);
494
+ const coords = marker.geometry.coordinates;
495
+ const startCoord = coords[0]; // First coordinate
496
+ const endCoord = coords[coords.length - 1]; // Last coordinate
497
+
498
+ // Calculate angle between the two points
499
+ const angle = VectorUtils.calculateBearing(startCoord, endCoord);
500
+
501
+ // Determine the arrow rotations
502
+ const normalizedStartRotation = VectorUtils.normalizeAngle(90 + angle); // Adjust for start arrow
503
+ const normalizedEndRotation = angle > 90 ? VectorUtils.normalizeAngle(270 + angle) : VectorUtils.normalizeAngle(90 - angle); // Adjust for end arrow
504
+
505
+ if (coords.length > 1) {
506
+ // Create start point
507
+ const startPoint = {
508
+ 'type': 'Feature',
509
+ 'geometry': {
510
+ 'type': 'Point',
511
+ 'coordinates': coords[0] // First coordinate
512
+ },
513
+ 'properties': {
514
+ 'Color': marker.properties.Color,
515
+ 'BorderColor': marker.properties.BorderColor,
516
+ 'arrowRotation': normalizedStartRotation,
517
+ 'size': 0.07 * parseFloat(marker.properties.LineWidth),
518
+ 'borderSize': 0.07 * (parseFloat(marker.properties.LineWidth) + 1)
519
+ }
520
+ };
521
+
522
+ // Create end point
523
+ const endPoint = {
524
+ 'type': 'Feature',
525
+ 'geometry': {
526
+ 'type': 'Point',
527
+ 'coordinates': coords[coords.length - 1] // Last coordinate
528
+ },
529
+ 'properties': {
530
+ 'Color': marker.properties.Color,
531
+ 'BorderColor': marker.properties.BorderColor,
532
+ 'arrowRotation': normalizedEndRotation,
533
+ 'size': 0.07 * parseFloat(marker.properties.LineWidth),
534
+ 'borderSize': 0.07 * (parseFloat(marker.properties.LineWidth) + 1)
535
+ }
536
+ };
537
+
538
+ // Add the points only if the arrow is supposed to be shown
539
+ if (marker.properties.StartStyle === '1') {
540
+ pointFeatures.push(startPoint);
541
+ }
542
+ if (marker.properties.EndStyle === '1') {
543
+ pointFeatures.push(endPoint);
544
+ }
545
+ }
553
546
  }
547
+
548
+ // Calculate bounds to Zoom
554
549
  if (marker.geometry.type == "LineString") {
555
550
  markerCoordinates.forEach((line) => {
556
551
  let exists = bounds.some(
@@ -583,40 +578,127 @@ sap.ui.define([
583
578
  map.fitBounds(zoombounds, {
584
579
  padding: 150
585
580
  });
586
- });
587
581
 
582
+ map.addLayer({
583
+ 'id': 'geojson-source-point',
584
+ 'type': 'circle',
585
+ 'source': 'geojson-source',
586
+ 'paint': {
587
+ 'circle-opacity': 0 // Hide points by making them fully transparent
588
+ },
589
+ 'filter': ['==', '$type', 'Point']
590
+ });
588
591
 
592
+ // First layer for the border (wider line)
593
+ map.addLayer({
594
+ 'id': 'geojson-source-route-border',
595
+ 'type': 'line',
596
+ 'source': 'geojson-source',
597
+ 'layout': {
598
+ 'line-join': 'round',
599
+ 'line-cap': 'butt'
600
+ },
601
+ 'paint': {
602
+ 'line-color': ['get', 'BorderColor'],
603
+ 'line-width': ['get', 'BorderWidth'] // Slightly wider for border effect
604
+ },
605
+ 'filter': ['==', '$type', 'LineString']
606
+ });
607
+ map.addLayer({
608
+ 'id': 'geojson-source-route',
609
+ 'type': 'line',
610
+ 'source': 'geojson-source',
611
+ 'layout': {
612
+ 'line-join': 'round',
613
+ 'line-cap': 'butt'
614
+ },
615
+ 'paint': {
616
+ 'line-color': ['get', 'Color'],
617
+ 'line-width': ['get', 'LineWidth']
618
+ },
619
+ 'filter': ['==', '$type', 'LineString']
620
+ });
621
+ // Create a new FeatureCollection for the points
622
+ const pointGeoJSON = {
623
+ 'type': 'FeatureCollection',
624
+ 'features': pointFeatures
625
+ };
626
+
627
+ // Add the GeoJSON source for the points to the map
628
+ map.addSource('line-end-points', {
629
+ 'type': 'geojson',
630
+ 'data': pointGeoJSON
631
+ });
632
+
633
+ VectorUtils.getArrowHead((image) => {
634
+ map.addImage('arrow-icon', image, { sdf: true });
635
+ // Add a layer to display the arrows borders at the start/end points
636
+ map.addLayer({
637
+ 'id': 'route-end-arrows-border',
638
+ 'type': 'symbol',
639
+ 'source': 'line-end-points',
640
+ 'layout': {
641
+ 'icon-image': 'arrow-icon', // base64 arrow icon
642
+ 'icon-size': ['get', 'borderSize'],
643
+ 'icon-allow-overlap': true,
644
+ 'icon-rotation-alignment': 'map',
645
+ 'icon-rotate': ['get', 'arrowRotation'] // Rotate based on calculated angle
646
+ },
647
+ 'paint': {
648
+ 'icon-color': ['get', 'BorderColor'] // Match the arrow color with the line color
649
+ }
650
+ });
651
+
652
+ // Add a layer to display the arrows at the start/end points
653
+ map.addLayer({
654
+ 'id': 'route-end-arrows',
655
+ 'type': 'symbol',
656
+ 'source': 'line-end-points',
657
+ 'layout': {
658
+ 'icon-image': 'arrow-icon', // Use your base64 arrow icon
659
+ 'icon-size': ['get', 'size'],
660
+ 'icon-allow-overlap': true,
661
+ 'icon-rotation-alignment': 'map',
662
+ 'icon-rotate': ['get', 'arrowRotation'] // Rotate based on calculated angle
663
+ },
664
+ 'paint': {
665
+ 'icon-color': ['get', 'Color'] // Match the arrow color with the line color
666
+ }
667
+ });
668
+ });
669
+
670
+ });
589
671
  // Change mouse cursor when hovering over the line
590
672
  map.on('mouseenter', 'geojson-source-route', function () {
591
- map.getCanvas().style.cursor = 'pointer';
673
+ if (!that.Apressed && !that.Rpressed) {
674
+ map.getCanvas().style.cursor = 'pointer';
675
+ }
592
676
  });
593
677
 
594
678
  // Revert mouse cursor back when not hovering
595
679
  map.on('mouseleave', 'geojson-source-route', function () {
596
- map.getCanvas().style.cursor = '';
680
+ if (!that.Apressed && !that.Rpressed) {
681
+ map.getCanvas().style.cursor = '';
682
+ }
597
683
  });
598
684
  map.on('click', 'geojson-source-route', function (e) {
599
685
  //Trigger payload
600
686
  triggerPayloadRoute(e, 'DETAIL_REQUEST');
601
687
  });
602
688
 
603
- map.on('contextmenu', 'geojson-source-route', function (e) {
604
- //Trigger payload
605
- triggerPayloadRoute(e, 'CONTEXT_MENU_REQUEST');
606
- });
607
-
608
689
  function triggerPayloadRoute(e, event) {
609
690
  const coordinates = e.lngLat;
610
691
  // Get the GeoJSON properties of the clicked line feature
692
+ const xyobj = VectorUtils.GetEventVPCoordsObj(e.originalEvent, map_container);
611
693
  var route = e.features[0];
612
- route.properties.x = e.point.x;
613
- route.properties.y = e.point.y;
694
+ route.properties.x = xyobj.x;
695
+ route.properties.y = xyobj.y;
614
696
 
615
697
  PayloadGenerator.objectClick('Link', event, route, coordinates);
616
698
  }
617
- function onUp(e) {
618
- const coords = e.lngLat;
619
699
 
700
+ function onUp(e) {
701
+ // To be done
620
702
  if (validDrop) {
621
703
  // Perform action for valid drop
622
704
  console.log('Dropped on valid target');
@@ -632,6 +714,7 @@ sap.ui.define([
632
714
  lineDrag = false;
633
715
  validDrop = false;
634
716
  }
717
+
635
718
  map.on('mousedown', 'geojson-source-route', (e) => {
636
719
  // Check if the left mouse button is clicked (button === 0)
637
720
  if (e.originalEvent.button === 0) {
@@ -650,222 +733,152 @@ sap.ui.define([
650
733
  layers: ['geojson-source-route']
651
734
  });
652
735
 
653
- if (features.length || validDrop) {
654
- map.getCanvas().style.cursor = 'copy';
736
+ if (!that.Apressed && !that.Rpressed) {
737
+ if (features.length || validDrop) {
738
+ map.getCanvas().style.cursor = 'copy';
655
739
 
656
- } else {
657
- // If not over a valid feature, show the "not-allowed" cursor
658
- map.getCanvas().style.cursor = 'not-allowed';
740
+ } else {
741
+ // If not over a valid feature, show the "not-allowed" cursor
742
+ map.getCanvas().style.cursor = 'not-allowed';
743
+ }
659
744
  }
660
745
  };
661
746
 
662
- // https://docs.mapbox.com/mapbox-gl-js/api/map/#map#flyto
663
747
  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
- });
748
+ // Check if the right-click happened on the 'geojson-source-route' layer
749
+ const features = map.queryRenderedFeatures(e.point, { layers: ['geojson-source-route'] });
705
750
 
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';
751
+ if (features.length > 0) {
752
+ e.features = features;
753
+ // The context menu is for the 'geojson-source-route' layer
754
+ triggerPayloadRoute(e, 'CONTEXT_MENU_REQUEST');
755
+ } else {
756
+ // The context menu is for the map
757
+ const coords = e.lngLat.lng + ";" + e.lngLat.lat + ";0.0";
758
+ const currentZoom = map.getZoom();
759
+ const center = map.getCenter();
760
+ const currentCenter = center.lng + ";" + center.lat;
761
+ const xyobj = VectorUtils.GetEventVPCoordsObj(e.originalEvent, map_container);
762
+ const screenX = xyobj.x;
763
+ const screenY = xyobj.y;
764
+ PayloadGenerator.onMapContextMenu(coords, currentZoom, currentCenter, screenX, screenY);
720
765
  }
721
766
  });
722
767
 
723
- window.addEventListener('keyup', (e) => {
724
- if (e.code === 'ControlLeft') {
725
- isCtrlPressed = false;
726
- if (lassoPoints.length > 2) {
727
- completeLasso();
768
+ var that = this;
769
+ map.on('idle', () => {
770
+ const container = map.getContainer();
771
+ container.addEventListener('keydown', function (event) {
772
+ switch (event.keyCode) {
773
+ case 72: // Reset map to initial view when 'h' is pressed
774
+ map.setCenter([0, 0]);
775
+ map.setZoom(2);
776
+ map.getCanvas().style.cursor = '';
777
+ break;
778
+ case 82:
779
+ if (!that.Rpressed) {
780
+ // Disable default box zooming.
781
+ that.Rpressed = true;
782
+ that.Apressed = false;
783
+ map.boxZoom.disable();
784
+ map.getCanvas().style.cursor = 'crosshair';
785
+ } else {
786
+ // Enable default box zooming.
787
+ that.Rpressed = false;
788
+ map.boxZoom.enable();
789
+ map.getCanvas().style.cursor = '';
790
+ }
791
+ break;
792
+ case 65:
793
+ if (!that.Apressed) {
794
+ // Disable default box zooming.
795
+ that.Apressed = true;
796
+ that.Rpressed = false;
797
+ map.boxZoom.disable();
798
+ map.getCanvas().style.cursor = 'crosshair';
799
+ } else {
800
+ // Enable default box zooming.
801
+ that.Apressed = false;
802
+ map.boxZoom.enable();
803
+ map.getCanvas().style.cursor = '';
804
+ }
805
+ break;
806
+ default:
807
+ break;
728
808
  }
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
- }
809
+ //Always trigger
810
+ PayloadGenerator.KeyboardHandler(event, VBI.MapRenderer.name);
811
+ });
812
+ })
756
813
 
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
814
 
768
- }
769
- });
815
+ }
816
+ VBI.MapRenderer.actionName = (obj) => {
817
+ const actions = Array.isArray(obj?.SAPVB?.Actions?.Set?.Action)
818
+ ? obj.SAPVB.Actions.Set.Action
819
+ : [obj?.SAPVB?.Actions?.Set?.Action].filter(Boolean);
820
+
821
+ const action = actions.find(act => act.refEvent === "KeyPress");
822
+ VBI.MapRenderer.name = action?.name ?? undefined;
823
+ };
824
+
825
+ VBI.MapRenderer.createPopup = (htmlContent, posArray) => {
826
+ let lngLat;
827
+ switch (posArray[0]) {
828
+ case "Spots":
829
+ // Find the spot with the specified key
830
+ const foundSpot = allMarkers.find(spot => spot.customProperties.Key === posArray[1]);
831
+ lngLat = foundSpot?.getLngLat();
832
+ break;
833
+ default:
834
+ }
770
835
 
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
- }
836
+ if (this.popup) {
837
+ //Remove existing popups
838
+ this.popup.remove();
793
839
  }
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
- });
840
+ // Create a Mapbox popup using the constructed HTML DOM
841
+ this.popup = new maplibregl.Popup({
842
+ closeButton: false,
843
+ offset: [19, 15]
844
+ }).setLngLat(lngLat)
845
+ .setDOMContent(htmlContent)
846
+ .addTo(this.map);
847
+ }
848
+
849
+ VBI.MapRenderer.closePopup = () => {
850
+ this.popup?.remove();
851
+ }
852
+ VBI.MapRenderer.setRefMapLayerStack = (style, header) => {
853
+ this.map.setStyle(style);
854
+ // Add the headers only for the specific types of requests
855
+ if (Object.keys(header).length != 0) {
856
+ // Use transformRequest to modify requests for specific maps
857
+ this.map.transformRequest = (url, resourceType) => {
858
+ return {
859
+ url: url,
860
+ headers: header // Add the header
861
+ };
819
862
  }
820
863
  }
864
+ }
821
865
 
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
- });
866
+ VBI.MapRenderer.createMenu = (Menu, data) => {
867
+ var contextMenuHandler = {};
868
+ contextMenuHandler.cnt = 0;
869
+ const xyparam = data.Params?.Param ? data.Params.Param : data.Param;
870
+ for (var i = 0; i < xyparam.length; ++i) {
871
+ if (xyparam[i].name === "x") {
872
+ contextMenuHandler.m_x = parseInt(xyparam[i]["#"], 10);
845
873
  }
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;
874
+ if (xyparam[i].name === "y") {
875
+ contextMenuHandler.m_y = parseInt(xyparam[i]["#"], 10);
876
+ }
877
+ if (xyparam[i].name === "scene") {
878
+ contextMenuHandler.m_scene = xyparam[i]["#"];
861
879
  }
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
880
  }
881
+ Menu.findMenuByID(data.refID).open(true, 0, "begin top", "begin top", this.map._container, "" + contextMenuHandler.m_x + " " + contextMenuHandler.m_y + "", "fit");
869
882
  }
870
883
 
871
884
  });