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

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

Some improvements t

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