source: main/trunk/greenstone3/web/interfaces/default/js/map-scripts-editor.js@ 33150

Last change on this file since 33150 was 33150, checked in by wy59, 5 years ago

Removing the line that would hide any marker that's been clicked. It served no actual purpose as it didn't delete the marker, but just hid it. Not sure what Zeddy intended with this, maybe it was as experimental and as temporary as his making the markers on the map (not map-editor) editable/draggable?

File size: 30.0 KB
Line 
1// Global autocomplete labels list: one list for all the map editors' shape labels in a page
2// We use the global labels hashmap to more efficiently ensure uniqueness of labels in our autocomplete list
3var global_autocompleteLabelsList = [];
4var global_labels_hashmap = {};
5
6function MapEditor(id) {
7 // TODO: investigate const, see https://www.w3schools.com/js/js_const.asp and check it will work on older browsers,
8 // https://stackoverflow.com/questions/4271566/how-do-i-know-which-version-of-javascript-im-using
9 this.MAX_THICKNESS = 5.0;
10 this.MIN_THICKNESS = 0.0;
11 this.MAX_OPACITY = 100.00;
12 this.MIN_OPACITY = 0.00;
13
14 // WORK-IN-PROGRESS FEATURE: label on Map (to be changed to a label associated with each shape later)
15 // Also uncomment import of label-overlay-class.js in document.xsl
16 //this.labelOverlay = null;
17
18
19 this.id = id;
20 this.shiftKeyPressed = false;
21 this.beingDragged = false;
22 this.allowDeselect = true;
23 this.colors = ['#1E90FF', '#FF1493', '#4B0082', '#32CD32', '#FF8C00', '#000000'];
24 this.selectedColor;
25 this.colorButtons = {};
26 this.thicknessValue = 1;
27 this.opacityValue = 40;
28 this.overlays = [];
29 this.selectedShapes = [];
30 this.listenersArray = [];
31 this.mapsArray = [];
32 this.drawingManager;
33 this.selectedShape;
34 this.savedOverlays = null;
35 this.map = null;
36 this.counter = 0;
37 this.branchNum = 1;
38 this.mouseState = "up";
39 this.thicknessRangeListener = this.thicknessValue; // ????
40 this.resizable = false;
41 this.dontResize = false;
42
43 this.shapeOptions = {
44 suppressUndo: true,
45 fillColor: '#CA4A2F',
46 strokeWeight: this.thicknessValue,
47 fillOpacity: this.opacityValue / 100,
48 editable: true,
49 geodesic: false,
50 draggable: true,
51 description: ""
52 };
53 this.mapEditorHistory = new MapEditorHistory(this);
54}
55
56//draggable checkbox control
57MapEditor.prototype.initMapEditorControls = function () {
58 var that = this;
59
60 var draggableCB = document.getElementById("draggableCB-"+ this.id);
61 draggableCB.addEventListener('change', function () {
62 if (this.checked) {
63 for (var i = 0; i < that.overlays.length; i++) {
64 that.overlays[i].draggable = false;
65 that.shapeOptions.draggable = false;
66 }
67 } else {
68 for (var i = 0; i < that.overlays.length; i++) {
69 that.overlays[i].draggable = true;
70 that.shapeOptions.draggable = true;
71 }
72 }
73 });
74
75
76 //Update thickness
77 var thicknessSliderOutput = document.getElementById("thicknessRangeVal" + "-" + this.id);
78 var thicknessSlider = document.getElementById("thicknessRange" + "-" + this.id);
79 var thicknessValue = ((thicknessSlider.value / 20) * 100) / 100;
80 thicknessSliderOutput.value = thicknessValue.toFixed(2);
81
82 thicknessSlider.oninput = function () {
83 that.shapeSpecsChangeMD();
84 var thicknessVal = ((this.value / 20) * 100) / 100;
85 thicknessSliderOutput.value = thicknessVal.toFixed(2);
86 that.thicknessValue = this.value / 20;
87 that.shapeOptions.strokeWeight = that.thicknessValue;
88 that.setSelectedThickness(that.thicknessValue);
89 }
90
91 thicknessSliderOutput.oninput = function () {
92 that.shapeSpecsChangeMD(); // TODO: DO WE NEED THIS LINE? (LINE COPIED & PASTED FROM ABOVE)
93 if(this.value > that.MAX_THICKNESS) this.value = that.MAX_THICKNESS;
94 if(this.value < that.MIN_THICKNESS) this.value = that.MIN_THICKNESS;
95 var thicknessVal = this.value * 20;
96 thicknessSlider.value = thicknessVal.toFixed(2);
97 that.thicknessValue = this.value;
98 that.shapeOptions.strokeWeight = that.thicknessValue;
99 that.setSelectedThickness(that.thicknessValue);
100 }
101 //Update opacity
102 // TODO: https://stackoverflow.com/questions/469357/html-text-input-allow-only-numeric-input?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
103 var opacitySlider = document.getElementById("colourOpacity" + "-" + this.id);
104 var opacitySliderOutput = document.getElementById("opacityRangeVal" + "-" + this.id);
105
106 opacitySlider.oninput = function () {
107 that.shapeSpecsChangeMD();
108 opacitySliderOutput.value = this.value;
109 that.opacityValue = this.value / 100;
110 that.shapeOptions.fillOpacity = that.opacityValue;
111 that.setSelectedOpacity(that.opacityValue);
112 }
113 opacitySliderOutput.oninput = function () {
114 that.shapeSpecsChangeOnInput();
115 if(this.value > that.MAX_OPACITY) this.value = that.MAX_OPACITY;
116 if(this.value < that.MIN_OPACITY) this.value = that.MIN_OPACITY;
117 opacitySlider.value = this.value;
118 that.opacityValue = this.value / 100;
119 that.shapeOptions.fillOpacity = that.opacityValue;
120 that.setSelectedOpacity(that.opacityValue);
121 }
122
123 var descriptionInput = document.getElementById("description" + "-" + this.id);
124 // don't use oninput, use onchange, because with autocomplete a newly entered or pasted value
125 // doesn't always get stored properly when using oninput.
126 descriptionInput.onchange = function () {
127 that.shapeSpecsChangeOnInput(); // takes care of history (undo/redo)
128 var description = this.value;
129 that.shapeOptions.description = description;
130 that.setSelectedDescription(that.shapeOptions.description);
131 }
132
133 // Also add a COMPLETED description (i.e. when description input box loses focus)
134 // to the autocomplete list of descriptions/labels
135 descriptionInput.onblur = function () {
136 var description = this.value;
137 that.addToAutocompleteLabelsList(description);
138 }
139
140 // TODO: Do we need these listeners, when we already have onInput methods above? Test.
141 document.getElementById("color-palette1" + "-" + this.id).addEventListener("mousedown", function() { that.shapeSpecsChangeMD() });
142 document.getElementById("thicknessRange" + "-" + this.id).addEventListener("mouseup", function () { that.shapeSpecsChangeMU() });
143 document.getElementById("colourOpacity" + "-" + this.id).addEventListener("mouseup", function () { that.shapeSpecsChangeMU() });
144 //document.getElementById("description" + "-" + this.id).addEventListener("keypress", function () { that.shapeSpecsChangeOnInput() });
145
146 document.onmousedown = function (ev) {
147 that.mouseState = "down";
148 // console.log('Down State you can now start dragging');
149 //do not write any code here in this function
150 }
151
152 document.onmouseup = function (ev) {
153 that.mouseState = "up";
154 // console.log('up state you cannot drag now because you are not holding your mouse')
155 //do not write any code here in this function
156 }
157
158
159 //prompts the user to save the changes before reloading/leaving the page
160 window.onbeforeunload = function (e) {
161 var currentOverlays = JSON.stringify(ShapesUtil.overlayToJSON(that.overlays));
162 var enableMessage = currentOverlays !== that.savedOverlays;
163 var message = "Changes are not saved. Are you sure you want to leave?";
164
165
166 // Comment out following section in entirety -- from "e = e || window.event" to end of "if(e)" -- if
167 // you don't want to see the popup about changes that haven't been saved yet
168 e = e || window.event;
169 // For IE and Firefox
170 if (e) {
171
172 if(enableMessage){
173 if(currentOverlays !== "[]") {
174 alert(message);
175 e.returnValue = message;
176
177 // For Safari
178 return message;
179 }
180 }
181 }
182 }
183}
184
185// Ensure only unique labels are added to our autocomplete list
186MapEditor.prototype.addToAutocompleteLabelsList = function (newLabel) {
187
188 if(typeof(newLabel) === 'undefined') { return; }
189
190 // We use a hashmap to more efficiently ensure uniqueness of labels in our array
191 // https://stackoverflow.com/questions/11040472/how-to-check-if-object-property-exists-with-a-variable-holding-the-property-name
192 if (newLabel !== "" && !global_labels_hashmap.hasOwnProperty(newLabel)) { // label is not empty and unique, so
193 // add to hashmap now
194 global_labels_hashmap[newLabel] = 1;
195 // add to autocomplete list and sort alphabetically
196 global_autocompleteLabelsList.push(newLabel);
197 global_autocompleteLabelsList.sort();
198 }
199}
200
201MapEditor.prototype.settingThePath = function () {
202 var that = this;
203 this.listenersArray = []
204 this.counter = 0;
205 this.branchNum = 1;
206
207 for (var i = 0; i < this.selectedShapes.length * 2; i++) {
208 for (var j = 1; j < 6; j++) {
209 var path = "//*[@id='map-" + this.id + "']/div/div/div[1]/div[3]/div/div[3]/div[" + this.branchNum + "]/div[" + j + "]/div";
210 this.listenersArray[this.counter] = this.getElementByXpath(path);
211 if (this.listenersArray[this.counter] !== (undefined || null)) {
212 this.listenersArray[this.counter].addEventListener("mousemove", function () {
213 that.resizable = true;
214 that.shapeResize();
215 });
216 this.listenersArray[this.counter].addEventListener("mouseout", function () {
217 if (this.mouseDown) {
218 that.resizable = true;
219 that.shapeResize();
220
221 }
222 });
223 }
224 this.counter++;
225 }
226 this.branchNum++;
227 }
228}
229
230MapEditor.prototype.shapeResize = function () {
231 if (this.mouseState == "down") {
232 if (this.selectedShapes.length > 0) {
233 if (this.resizable) {
234 if (this.dontResize == false) {
235 this.mapEditorHistory.historyOverlayPush();
236 }
237
238 }
239 }
240 }
241}
242
243MapEditor.prototype.shapeSpecsChangeMD = function () {
244 if (this.selectedShapes.length > 0) {
245 this.mapEditorHistory.historyOverlayPush();
246 }
247}
248
249MapEditor.prototype.shapeSpecsChangeMU = function () {
250 if (this.selectedShapes.length > 0) {
251 this.mapEditorHistory.presentOverlayPush();
252 }
253}
254
255MapEditor.prototype.shapeSpecsChangeOnInput = function () {
256 if (this.selectedShapes.length > 0) {
257 this.mapEditorHistory.presentOverlayPush();
258 }
259}
260
261MapEditor.prototype.makeColorButton = function (color) {
262 var that = this;
263
264 var button = document.createElement('span');
265 button.className = 'color-buttons1';
266 button.style.backgroundColor = color;
267 google.maps.event.addDomListener(button, 'click', function () {
268 that.selectColor(color);
269 that.setSelectedShapeColor(color);
270 that.shapeSpecsChangeMU();
271 });
272 return button;
273}
274
275MapEditor.prototype.buildColorPalette = function () {
276 var colorPalette = document.getElementById("color-palette1" + "-" + this.id);
277 for (var i = 0; i < this.colors.length; ++i) {
278 var currColor = this.colors[i];
279 var colorButton = this.makeColorButton(currColor);
280 colorPalette.appendChild(colorButton);
281 this.colorButtons[currColor] = colorButton;
282 }
283 this.selectColor(this.colors[0]);
284};
285
286MapEditor.prototype.selectColor = function (color) {
287 this.selectedColor = color;
288 for (var i = 0; i < this.colors.length; ++i) {
289 var currColor = this.colors[i];
290 this.colorButtons[currColor].style.border = currColor == color ? '2px solid #789' : '2px solid #fff';
291 }
292
293 // Retrieves the current options from the drawing manager and replaces the
294 // stroke or fill color as appropriate.
295 var polylineOptions = this.drawingManager.get('polylineOptions');
296 polylineOptions.strokeColor = color;
297 this.drawingManager.set('polylineOptions', polylineOptions);
298
299 var rectangleOptions = this.drawingManager.get('rectangleOptions');
300 rectangleOptions.fillColor = color;
301 this.drawingManager.set('rectangleOptions', rectangleOptions);
302
303 var circleOptions = this.drawingManager.get('circleOptions');
304 circleOptions.fillColor = color;
305 this.drawingManager.set('circleOptions', circleOptions);
306
307 var polygonOptions = this.drawingManager.get('polygonOptions');
308 polygonOptions.fillColor = color;
309 this.drawingManager.set('polygonOptions', polygonOptions);
310}
311
312MapEditor.prototype.initMapEditor = function () {
313 var that = this;
314
315 this.map = new google.maps.Map(document.getElementById("map-" + this.id), {
316 center: {
317 lat: -37.7891,
318 lng: 175.3180
319 },
320 zoom: 14,
321 mapId: this.id,
322 });
323
324 // WORK-IN-PROGRESS FEATURE: label on Map (to be changed to a label associated with each shape later)
325 // let's associate a label with the map (for now, later associate labels for each shape)
326 //this.labelOverlay = new LabelOverlay(this.map);
327
328 this.mapsArray.push(this.map);
329 // Add a style-selector control to the map.
330 var styleControl = document.getElementById('style-selector-control' + "-" + this.id);
331 this.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(styleControl);
332
333 /*
334 // Set the map's style to the initial value of the selector.
335 var styleSelector = document.getElementById('style-selector' + "-" + this.id);
336 //console.log(styleSelector);
337 //map = google.maps.Map(document.getElementById('map' +"-"+ this.id));
338 this.map.setOptions({
339 styles: styles[styleSelector.value]
340
341 });
342
343 // Apply new JSON when the user selects a different style.
344 styleSelector.addEventListener('change', function () {
345 that.map.setOptions({
346 styles: styles[styleSelector.value]
347 });
348 });
349 */
350
351 this.drawingManager = new google.maps.drawing.DrawingManager({
352 //drawingMode: google.maps.drawing.OverlayType.RECTANGLE,
353 drawingControl: true,
354 drawingControlOptions: {
355 position: google.maps.ControlPosition.TOP_CENTER,
356 drawingModes: ['marker', 'circle', 'polygon', 'polyline', 'rectangle']
357 },
358 markerOptions: {
359 draggable: true
360 },
361 circleOptions: this.shapeOptions,
362 polylineOptions: this.shapeOptions,
363 polygonOptions: this.shapeOptions,
364 rectangleOptions: this.shapeOptions,
365 });
366
367 this.drawingManager.setMap(this.map);
368
369 google.maps.event.addListener(this.drawingManager, "drawingmode_changed", function () {
370 if (that.shiftKeyPressed != true && that.drawingManager.drawingMode !== null) {
371 that.deselectAll();
372 }
373 that.settingThePath();
374
375 })
376
377 // store reference to added overlay
378 google.maps.event.addListener(this.drawingManager, 'overlaycomplete', function (e) {
379 that.allowDeselect = true;
380 that.mapEditorHistory.historyOverlayPush();
381 that.overlays.push(e.overlay); // store reference to added overlay
382 var newShape = e.overlay;
383 newShape.type = e.type;
384 that.mapEditorHistory.presentOverlayPush();
385
386 if (e.type !== google.maps.drawing.OverlayType.MARKER) {
387 that.addShapeListeners(newShape, e);
388 that.setSelection(newShape, e);
389 } else {
390 that.addMarkerListeners(newShape, e);
391 that.setSelection(newShape, e);
392 }
393 });
394
395 //Clears selection if clicked on the map when shift is not presseed
396 google.maps.event.addListener(this.map, 'click', function (e) {
397 var c = document.body.childNodes;
398 if (e.target && e.target.matches("a.classA")) {
399 console.log("Anchor element clicked!");
400 }
401 if (that.shiftKeyPressed == false) {
402 that.clearSelection();
403 that.selectedShape = null;
404 }
405 });
406
407 google.maps.event.addListener(this.map, 'mousedown', function (e) {
408 that.dontResize = true;
409 });
410
411 google.maps.event.addListener(this.map, 'mouseup', function (e) {
412 that.dontResize = false;
413 });
414
415 //Keyboard shortcuts
416 var mapAndControls = document.getElementById("map-and-controls-" + this.id);
417 var thicknessField = document.getElementById ("thicknessRangeVal-" + this.id);
418 var opacityField = document.getElementById ("opacityRangeVal-" + this.id);
419 var openMapFunction = function() {
420 //Sets shift as unpressed
421 mapAndControls.addEventListener('keyup', function (event) {
422 if (event.keyCode == '16') {
423 that.shiftKeyPressed = false;
424 }
425 });
426
427 mapAndControls.addEventListener('keydown', function (event) {
428
429 // https://stackoverflow.com/questions/2220196/how-to-decode-character-pressed-from-jquerys-keydowns-event-handler
430 var keyCode = String.fromCharCode(event.which);
431 //console.log("Key pressed: " + keyCode);
432
433 //disable keyboard shortcut within the number input field
434 var activeElement = $(document.activeElement);
435 if(activeElement.attr('type') == 'number' || activeElement.attr('type') == 'text'){
436 //console.log('number detected')
437 return;
438 }
439 //Sets shift as pressed
440 if (event.keyCode == '16') {
441 that.shiftKeyPressed = true;
442 }
443 else if (keyCode == 'Y' && (event.ctrlKey || event.metaKey)) {
444 that.mapEditorHistory.redo();
445 }
446 else if (keyCode == 'Z' && (event.ctrlKey || event.metaKey) ) {
447 if (that.shiftKeyPressed == false) {
448 that.mapEditorHistory.undo();
449 }
450 }
451 else if (keyCode == 'A' && (event.ctrlKey || event.metaKey)) {
452 event.preventDefault();
453 that.drawingManager.setDrawingMode(null);
454 that.selectAll();
455 }
456 else if (keyCode == 'D' && (event.ctrlKey || event.metaKey)) {
457 event.preventDefault();
458 that.deselectAll();
459 }
460
461 else if (keyCode == '0' || keyCode == 'À' || (keyCode == 'G'&& (event.ctrlKey || event.metaKey))) {
462 event.preventDefault();
463 that.drawingManager.setDrawingMode(null);
464 } else if (keyCode == '1') {
465 that.drawingManager.setDrawingMode('marker');
466 } else if (keyCode == '2') {
467 that.drawingManager.setDrawingMode('circle');
468 } else if (keyCode == '3') {
469 that.drawingManager.setDrawingMode('polygon');
470 } else if (keyCode == '4') {
471 that.drawingManager.setDrawingMode('polyline');
472 } else if (keyCode == '5') {
473 that.drawingManager.setDrawingMode('rectangle');
474 }
475
476 //else if (keyCode == 'S') {
477 // that.saveToArchives();
478 //}
479 else if (keyCode == 'Q') { // for debugging information, press Q (easy to hit key)
480 that.printHistory();
481 }
482 else if (keyCode == '.') {
483 that.deleteSelectedShapes();
484 }
485 // console.log(keyCode);
486 });
487 };
488
489 openMapFunction();
490
491 this.buildColorPalette();
492
493
494 var collection = gs.cgiParams.c;
495 var site_name = gs.xsltParams.site_name;
496 var nodeID = this.id; // documentID, hopefully contains section ID too
497 var metaname = gps_metadata_name;
498
499 // collection, site, documentID, metadataName, metadataPosition, responseFunction
500 gs.functions.getArchivesMetadata(collection, site_name, nodeID, metaname, 0, function(responseText){
501 // responseText is of type GSMetadata
502
503 // called when data has been retrieved from archives
504 var JSONString = responseText.getValue();
505 if(JSONString !== "")
506 {
507 that.LOAD(JSONString, nodeID);
508 that.savedOverlays = JSONString;
509 }
510 }
511 ); // responseFunctions are now in the setMeta calls
512}
513
514//Deletes a vertex if clicked on it
515MapEditor.prototype.vertexAndPolyDel = function (e, newShape) {
516 var vertex = e.vertex;
517 if (e.vertex !== undefined) {
518 if (newShape.type === google.maps.drawing.OverlayType.POLYGON) {
519 var path = newShape.getPaths().getAt(e.path);
520 path.removeAt(e.vertex);
521 if (path.length < 3) {
522 newShape.setMap(null);
523 }
524 }
525 if (newShape.type === google.maps.drawing.OverlayType.POLYLINE) {
526 var path = newShape.getPath();
527 path.removeAt(e.vertex);
528 if (path.length < 2) {
529 newShape.setMap(null);
530 }
531 }
532 }
533}
534
535MapEditor.prototype.addMarkerListeners = function (newShape, e) {
536 var that = this;
537 //Click event if a marker is created
538 google.maps.event.addListener(newShape, 'click', function (e) {
539 if(that.shiftKeyPressed){
540
541 } else {
542 that.mapEditorHistory.historyOverlayPush();
543 //newShape.setMap(null);
544 that.mapEditorHistory.presentOverlayPush();
545 }
546
547 });
548
549 google.maps.event.addListener(newShape, 'dragstart', function (e) {
550 that.beingDragged = true;
551 that.mapEditorHistory.historyOverlayPush();
552
553 });
554
555 google.maps.event.addListener(newShape, 'dragend', function () {
556 that.beingDragged = false;
557 that.mapEditorHistory.presentOverlayPush();
558 that.allowDeselect = false;
559 });
560}
561
562MapEditor.prototype.addShapeListeners = function (newShape, e) {
563 var that = this;
564 // Add an event listener that selects the newly-drawn shape when the user
565 // mouses down on it.
566 google.maps.event.addListener(newShape, 'click', function (e) {
567 that.vertexAndPolyDel(e, newShape);
568 });
569
570 google.maps.event.addListener(newShape, 'dragstart', function (e) {
571 that.allowDeselect = false;
572 that.mapEditorHistory.historyOverlayPush();
573 });
574
575 google.maps.event.addListener(newShape, 'dragend', function () {
576 that.beingDragged = false;
577 that.mapEditorHistory.presentOverlayPush();
578 that.settingThePath();
579
580 that.allowDeselect = false;
581 that.setSelection(newShape, e);
582 });
583
584 //Store information after the event ends
585 google.maps.event.addListener(newShape, 'bounds_changed', function (e) {
586 if (that.beingDragged == false) {
587 that.mapEditorHistory.presentOverlayPush();
588 }
589 });
590
591 //Add an event listener to select a shape if the mouse hovers over it
592 google.maps.event.addListener(newShape, 'mousedown', function (e) {
593 if (e.target && e.target.matches("a.classA")) {
594 console.log("Anchor element clicked!");
595 }
596 if (e.vertex !== undefined || e.edge !== undefined) {
597 that.mapEditorHistory.historyOverlayPush()
598 }
599 if (that.drawingManager.drawingMode == null) {
600 that.setSelection(newShape, e);
601 }
602 });
603
604 google.maps.event.addListener(newShape, 'mouseup', function (e) {
605 if (e.vertex !== undefined || e.edge !== undefined) {
606 that.mapEditorHistory.presentOverlayPush()
607 } else {
608 //that.setSelection(newShape, e);
609 }
610
611 });
612}
613MapEditor.prototype.clearSelection = function () {
614 if (this.selectedShape) {
615 if (this.shiftKeyPressed == false) {
616 for (var i = 0; i < this.selectedShapes.length; i++) {
617 if(this.selectedShapes[i].type !== 'marker') {
618 this.selectedShapes[i].setEditable(false);
619 }
620 }
621 this.selectedShapes = [];
622 }
623 this.selectedShape = null;
624 }
625}
626
627//Set selection for the selected overlay
628MapEditor.prototype.setSelection = function (shape, e) {
629 //var that = this;
630 if (shape.type !== 'marker') {
631 if (this.shiftKeyPressed == false) {
632 if (e !== null) {
633 if (e.vertex == undefined) {
634 if (e.edge == undefined) {
635 this.clearSelection();
636 shape.setEditable(true);
637 }
638 }
639 }
640 }
641 if (this.selectedShapes.includes(shape)) {
642 if (e !== null) {
643 if (e.vertex == undefined) {
644 if (e.edge == undefined) {
645 this.allowDeselect = true;
646 this.removeFromSelectedShapes(shape);
647 }
648 }
649 }
650 } else {
651 this.allowDeselect = false;
652 shape.setEditable(true);
653 this.selectedShapes.push(shape);
654 }
655
656 //Send the values to be updated
657 var thi = shape.strokeWeight;
658 var opa = shape.fillOpacity;
659 var fCol = shape.fillColor;
660 var sCol = shape.strokeColor;
661 var description = shape.description;
662 this.updateMenuValues(thi, opa, fCol, sCol, description);
663
664 } else if (shape.type == 'marker') {
665 this.allowDeselect = false;
666 this.selectedShapes.push(shape);
667 }
668 this.selectedShape = shape;
669 this.settingThePath();
670}
671
672MapEditor.prototype.removeFromSelectedShapes = function (shape) {
673 if (this.selectedShapes.includes(shape)) {
674 if (this.allowDeselect) {
675 const index = this.selectedShapes.indexOf(shape);
676 this.selectedShapes.splice(index, 1);
677 shape.setEditable(false);
678 }
679 this.allowDeselect = true;
680 }
681}
682
683//Set selected label
684MapEditor.prototype.setSelectedDescription = function (label) {
685 if (this.selectedShapes.length > 0) {
686 for (var i = 0; i < this.selectedShapes.length; i++) {
687 this.selectedShapes[i].set('description', label); //SAME: this.selectedShapes[i].description = label;
688 }
689 }
690}
691
692//Set selected thickness
693MapEditor.prototype.setSelectedThickness = function (sWeight) {
694 if (this.selectedShapes.length > 0) {
695 for (var i = 0; i < this.selectedShapes.length; i++) {
696 this.selectedShapes[i].set('strokeWeight', sWeight);
697 }
698 }
699}
700
701//Set selected opacity
702MapEditor.prototype.setSelectedOpacity = function (fOpacity) {
703
704 if (this.selectedShapes.length > 0) {
705 for (var i = 0; i < this.selectedShapes.length; i++) {
706 this.selectedShapes[i].set('fillOpacity', fOpacity);
707 }
708 }
709}
710
711//set selected fill colour
712MapEditor.prototype.setSelectedShapeColor = function (color) {
713 if (this.selectedShapes.length > 0) {
714 for (var i = 0; i < this.selectedShapes.length; i++) {
715 this.selectedShapes[i].set('fillColor', color);
716 this.selectedShapes[i].set('strokeColor', color);
717 }
718 }
719}
720
721MapEditor.prototype.getElementByXpath = function (path) {
722 return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
723}
724
725MapEditor.prototype.updateMenuValues = function (thi, opa, fCol, sCol, description) {
726 //Update thickness slider and value on the settings menu
727 var thicknessSliderOutput = document.getElementById("thicknessRangeVal" + "-" + this.id);
728 // update the thickness innerHTML's value to always have 2 decimal places, https://www.w3schools.com/js/js_number_methods.asp
729 thi = parseFloat(thi); //Ensure the thi is a number
730 thicknessSliderOutput.value = thi.toFixed(2);
731 document.getElementById("thicknessRange" + "-" + this.id).value = Math.round((thi * 20) * 100) / 100;
732
733 //Update the opacity slider and value on the settings menu
734 var opacitySliderOutput = document.getElementById("opacityRangeVal" + "-" + this.id);
735 opacitySliderOutput.value = opa * 100;
736 document.getElementById("colourOpacity" + "-" + this.id).value = opa * 100;
737
738 // Show the description in the description field
739 var descriptionInput = document.getElementById("description" + "-" + this.id);
740 descriptionInput.value = description;
741
742 if (this.drawingManager.drawingMode == null) {
743 this.selectColor(fCol);
744 }
745}
746MapEditor.prototype.selectAll = function () {
747 this.shiftKeyPressed = true;
748 var e = new Object();
749 e.vertex = undefined;
750 this.selectedShapes = [];
751 for (var i = 0; i < this.overlays.length; i++) {
752 this.setSelection(this.overlays[i], e);
753 }
754 this.shiftKeyPressed = false;
755}
756MapEditor.prototype.deselectAll = function () {
757 for (var i = 0; i < this.selectedShapes.length; i++) {
758 if (this.selectedShapes[i].type !== google.maps.drawing.OverlayType.MARKER) {
759 this.selectedShapes[i].setEditable(false);
760 }
761
762 }
763 this.selectedShapes = [];
764}
765
766// event handler for s being pressed *when map editor has the focus*
767// For saving and rebuilding, see map_scripts
768MapEditor.prototype.saveToArchives = function () {
769 var that = this;
770 console.log("Save pressed");
771
772 var json_overlays = JSON.stringify(ShapesUtil.overlayToJSON(this.overlays));
773 that.savedOverlays = json_overlays; // save the old version to compare with future changes
774 var collection = gs.cgiParams.c;
775 var site_name = gs.xsltParams.site_name;
776 var nodeID = this.id; // documentID, hopefully contains section ID too
777 var metaname = "GPS.mapOverlay";
778
779 // collection, site, documentID, metadataName, metadataPosition, metadataValue, prevMetadataValue, metamode, responseFunction
780 gs.functions.setArchivesMetadata(collection, site_name, nodeID, metaname, 0, json_overlays, null, "override", function(){
781 console.log("SAVED");
782 }
783 );
784}
785
786// TODO: When finished testing, can remove this debug function that just prints to console
787MapEditor.prototype.printHistory = function () {
788 console.log("prev", this.mapEditorHistory.prevOverlays);
789 console.log("present ", this.mapEditorHistory.presentOverlays);
790 console.log("undone ", this.mapEditorHistory.undoneOverlays);
791 console.log("@@@@ allShapes: ", this.overlays);
792 console.log("@@@@ selectedShapes: ", this.selectedShapes);
793}
794
795// to be called after reading back in stored JSON from archives meta
796MapEditor.prototype.LOAD = function (json_str, nodeID) {
797 this.mapEditorHistory.historyOverlayPush();
798
799 // This seems to convert the map_store object into an array and forces array index access, instead of convenient property access using nodeID
800 //Object.values(gsmap_store)[0]; // Always gets top level section's map-editor, not what we want.
801
802 // Get the map editor for the nodeID, as we're asked to load that editor
803 var map_editor = gsmap_store["map-"+nodeID];
804
805 var new_overlays = ShapesUtil.JSONToOverlays(json_str);
806 for (var i=0; i<map_editor.overlays.length; i++) {
807 map_editor.overlays[i].setMap(null);
808 }
809
810 map_editor.overlays = new_overlays;
811
812 for (var i=0; i<map_editor.overlays.length; i++) {
813 var shape = map_editor.overlays[i];
814
815 // set up the autocomplete list using saved labels/descriptions
816 map_editor.addToAutocompleteLabelsList(shape.description); // now efficiently ensures uniqueness of values using (hash)map
817
818 // make the shapes selectable on load:
819 if (ShapesUtil.overlayItemIsShape(shape)) {
820 map_editor.addShapeListeners(shape, null); // don't have an overlay event!
821 } else {
822 map_editor.addMarkerListeners(shape, null); // don't have an overlay event!
823 }
824 shape.setMap(map_editor.map);
825 }
826
827 this.mapEditorHistory.presentOverlayPush();
828}
829
830MapEditor.prototype.deleteSelectedShapes = function () {
831 if(this.selectedShapes.length !== 0) {
832 this.mapEditorHistory.historyOverlayPush();
833 for (var i = 0; i < this.selectedShapes.length; i++) {
834 this.selectedShapes[i].setMap(null);
835
836 if (this.overlays.includes(this.selectedShapes[i])) {
837 const index = this.overlays.indexOf(this.selectedShapes[i]);
838 this.overlays.splice(index, 1);
839// this.selectedShapes[i].setEditable(false);
840 }
841 }
842 this.selectedShapes = [];
843 this.mapEditorHistory.presentOverlayPush();
844 }
845}
846
847MapEditor.prototype.draggableState = function () {
848
849 var draggableCB = document.querySelector("input[name=draggableCB]");
850 draggableCB.addEventListener('change', function () {
851 if (this.checked) {
852 this.overlays.draggable = false;
853 } else {
854 this.overlays.draggable = false;
855 }
856 });
857}
858
859MapEditor.prototype.deleteAllShapes = function () {
860 if(this.overlays.length !== 0) {
861 //console.log("deleteAllShape() this.id = " + this.id);
862 this.mapEditorHistory.historyOverlayPush();
863 for (var i = 0; i < this.overlays.length; i++) {
864 this.overlays[i].setMap(null);
865 }
866 this.overlays = [];
867 this.mapEditorHistory.presentOverlayPush();
868 }
869}
870
871// Global function that uses jquery to set the autocomplete list's data source to whatever's in our global autocomplete labels array
872$(function setupAutocompleteLabelsList() {
873 // Overrides the default autocomplete filter function to
874 // search only from the beginning of the string
875 //resource: https://miroslavpopovic.com/posts/2012/06/jqueryui-autocomplete-filter-words-starting-with-term
876 $.ui.autocomplete.filter = function (array, term) {
877 var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
878 return $.grep(array, function (value) {
879 return matcher.test(value.label || value.value || value);
880 });
881 };
882
883 $(".description").autocomplete({
884 source: global_autocompleteLabelsList
885 });
886});
Note: See TracBrowser for help on using the repository browser.