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

Last change on this file since 32798 was 32798, checked in by ak19, 5 years ago

Map Scripts Editor transformed into a class

File size: 20.6 KB
Line 
1
2
3function MapEditor(id) {
4 this.id = id;
5 this.shiftKeyPressed = false;
6 this.beingDragged = false;
7 this.allowDeselect = true;
8 this.colors = ['#1E90FF', '#FF1493', '#4B0082', '#32CD32', '#FF8C00', '#000000'];
9 this.selectedColor;
10 this.colorButtons = {};
11 this.thicknessValue = 1;
12 this.opacityValue = 0.4;
13 this.overlays = [];
14 this.selectedShapes = [];
15 this.listenersArray = [];
16 this.mapsArray = [];
17 this.drawingManager;
18 this.selectedShape;
19 this.map = null;
20 this.counter = 0;
21 this.branchNum = 1;
22 this.mouseState = "up";
23 this.thicknessRangeListener = this.thicknessValue; // ????
24 this.resizable = false;
25 this.dontResize = false;
26 this.polyOptions = {
27 fillColor: '#CA4A2F',
28 strokeWeight: this.thicknessValue,
29 fillOpacity: this.opacityValue,
30 editable: true,
31 geodesic: false,
32 draggable: true
33 };
34 this.mapEditorHistory = new MapEditorHistory(this);
35}
36
37MapEditor.prototype.initMapEditorControls = function () {
38 var that = this;
39 console.log(this.id);
40
41 var draggableCB = document.querySelector("input[name=draggableCB]");
42 draggableCB.addEventListener('change', function () {
43 if (this.checked) {
44 for (var i = 0; i < that.overlays.length; i++) {
45 console.log("checked");
46 that.overlays[i].draggable = false;
47 that.polyOptions.draggable = false;
48 }
49 } else {
50 for (var i = 0; i < that.overlays.length; i++) {
51 console.log("not checked");
52 that.overlays[i].draggable = true;
53 that.polyOptions.draggable = true;
54 }
55 }
56 });
57
58
59 //Update thickness
60 var thicknessSlider = document.getElementById("thicknessRange" + "-" + this.id);
61 var thicknessSliderOutput = document.getElementById("thicknessRangeVal" + "-" + this.id);
62 thicknessSliderOutput.innerHTML = thicknessSlider.value / 20;
63
64 thicknessSlider.oninput = function () {
65 that.shapeSpecsChangeMD();
66 thicknessSliderOutput.innerHTML = this.value / 20;
67 that.thicknessValue = this.value / 20;
68 that.polyOptions.strokeWeight = that.thicknessValue;
69 that.setSelectedThickness(that.thicknessValue);
70
71 }
72 //Update opacity
73 var opacitySlider = document.getElementById("colourOpacity" + "-" + this.id);
74 var opacitySliderOutput = document.getElementById("opacityRangeVal" + "-" + this.id);
75 opacitySliderOutput.innerHTML = Math.round(opacitySlider.value) / 100;
76
77 opacitySlider.oninput = function () {
78 that.shapeSpecsChangeMD();
79 opacitySliderOutput.innerHTML = "% " + this.value;
80 that.opacityValue = this.value / 100;
81 that.polyOptions.fillOpacity = that.opacityValue;
82 that.setSelectedOpacity(that.opacityValue);
83 }
84
85 document.getElementById("color-palette1" + "-" + this.id).addEventListener("mousedown", function() { that.shapeSpecsChangeMD() });
86 document.getElementById("thicknessRange" + "-" + this.id).addEventListener("mouseup", function () { that.shapeSpecsChangeMU() });
87 document.getElementById("colourOpacity" + "-" + this.id).addEventListener("mouseup", function() { that.shapeSpecsChangeMU() } );
88 document.onmousemove = function (ev) {
89 //How can I know the state of mouse from here
90 if (that.mouseState == 'down') {
91 //console.log('mouse down state')
92 }
93 if (that.mouseState == 'up') {
94 //console.log('mouse up state')
95 }
96 }
97
98 document.onmousedown = function (ev) {
99 that.mouseState = "down";
100 // console.log('Down State you can now start dragging');
101 //do not write any code here in this function
102 }
103
104 document.onmouseup = function (ev) {
105 that.mouseState = "up";
106 // console.log('up state you cannot drag now because you are not holding your mouse')
107 //do not write any code here in this function
108 }
109}
110
111MapEditor.prototype.settingThePath = function () {
112 var that = this;
113 this.listenersArray = []
114 this.counter = 0;
115 this.branchNum = 1;
116
117 for (var i = 0; i < this.selectedShapes.length * 2; i++) {
118 for (var j = 1; j < 6; j++) {
119 var path = "//*[@id='map-" + this.id + "']/div/div/div[1]/div[3]/div/div[3]/div[" + this.branchNum + "]/div[" + j + "]/div";
120 this.listenersArray[this.counter] = this.getElementByXpath(path);
121 if (this.listenersArray[this.counter] !== (undefined || null)) {
122 this.listenersArray[this.counter].addEventListener("mousemove", function () {
123 that.resizable = true;
124 that.shapeResize();
125 });
126 this.listenersArray[this.counter].addEventListener("mouseout", function () {
127 if (this.mouseDown) {
128 that.resizable = true;
129 that.shapeResize();
130 }
131 });
132 }
133 this.counter++;
134 }
135 this.branchNum++;
136 }
137}
138
139MapEditor.prototype.shapeResize = function () {
140 if (this.mouseState == "down") {
141 if (this.selectedShapes.length > 0) {
142 if (this.resizable) {
143 if (this.dontResize == false) {
144 this.mapEditorHistory.historyOverlayPush();
145 }
146
147 }
148 }
149 }
150}
151
152MapEditor.prototype.shapeSpecsChangeMD = function () {
153 console.log(this.selectedShapes);
154
155 if (this.selectedShapes.length > 0) {
156 this.mapEditorHistory.historyOverlayPush();
157 }
158}
159
160MapEditor.prototype.shapeSpecsChangeMU = function () {
161 if (this.selectedShapes.length > 0) {
162 this.mapEditorHistory.presentOverlayPush();
163 }
164}
165
166MapEditor.prototype.makeColorButton = function (color) {
167 var that = this;
168
169 var button = document.createElement('span');
170 button.className = 'color-buttons1';
171 button.style.backgroundColor = color;
172 google.maps.event.addDomListener(button, 'click', function () {
173 that.selectColor(color);
174 that.setSelectedShapeColor(color);
175 that.shapeSpecsChangeMU();
176 });
177 return button;
178}
179
180MapEditor.prototype.buildColorPalette = function () {
181 var colorPalette = document.getElementById("color-palette1" + "-" + this.id);
182 for (var i = 0; i < this.colors.length; ++i) {
183 var currColor = this.colors[i];
184 var colorButton = this.makeColorButton(currColor);
185 colorPalette.appendChild(colorButton);
186 this.colorButtons[currColor] = colorButton;
187 }
188 this.selectColor(this.colors[0]);
189};
190
191MapEditor.prototype.selectColor = function (color) {
192 this.selectedColor = color;
193 for (var i = 0; i < this.colors.length; ++i) {
194 var currColor = this.colors[i];
195 this.colorButtons[currColor].style.border = currColor == color ? '2px solid #789' : '2px solid #fff';
196 }
197
198 // Retrieves the current options from the drawing manager and replaces the
199 // stroke or fill color as appropriate.
200 var polylineOptions = this.drawingManager.get('polylineOptions');
201 polylineOptions.strokeColor = color;
202 this.drawingManager.set('polylineOptions', polylineOptions);
203
204 var rectangleOptions = this.drawingManager.get('rectangleOptions');
205 rectangleOptions.fillColor = color;
206 this.drawingManager.set('rectangleOptions', rectangleOptions);
207
208 var circleOptions = this.drawingManager.get('circleOptions');
209 circleOptions.fillColor = color;
210 this.drawingManager.set('circleOptions', circleOptions);
211
212 var polygonOptions = this.drawingManager.get('polygonOptions');
213 polygonOptions.fillColor = color;
214 this.drawingManager.set('polygonOptions', polygonOptions);
215}
216
217MapEditor.prototype.initMapEditor = function () {
218 var that = this;
219
220 this.map = new google.maps.Map(document.getElementById("map-" + this.id), {
221 center: {
222 lat: -37.7891,
223 lng: 175.3180
224 },
225 zoom: 14,
226 mapId: this.id,
227 });
228 this.mapsArray.push(this.map);
229 // Add a style-selector control to the map.
230 var styleControl = document.getElementById('style-selector-control' + "-" + this.id);
231 this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(styleControl);
232
233 // Set the map's style to the initial value of the selector.
234 var styleSelector = document.getElementById('style-selector' + "-" + this.id);
235 //console.log(styleSelector);
236 //map = google.maps.Map(document.getElementById('map' +"-"+ this.id));
237 this.map.setOptions({
238 styles: styles[styleSelector.value]
239
240 });
241
242 // Apply new JSON when the user selects a different style.
243 styleSelector.addEventListener('change', function () {
244 that.map.setOptions({
245 styles: styles[styleSelector.value]
246 });
247 });
248
249 this.drawingManager = new google.maps.drawing.DrawingManager({
250 drawingMode: google.maps.drawing.OverlayType.RECTANGLE,
251 drawingControl: true,
252 drawingControlOptions: {
253 position: google.maps.ControlPosition.TOP_CENTER,
254 drawingModes: ['marker', 'circle', 'polygon', 'polyline', 'rectangle']
255 },
256 markerOptions: {
257 draggable: true
258 },
259 circleOptions: this.polyOptions,
260 polylineOptions: this.polyOptions,
261 polygonOptions: this.polyOptions,
262 rectangleOptions: this.polyOptions,
263 });
264
265 this.drawingManager.setMap(this.map);
266
267 google.maps.event.addListener(this.drawingManager, "drawingmode_changed", function () {
268 if (that.shiftKeyPressed != true && that.drawingManager.drawingMode !== null) {
269 that.deselectAll();
270 }
271 that.settingThePath();
272
273 })
274
275 // store reference to added overlay
276 google.maps.event.addListener(this.drawingManager, 'overlaycomplete', function (e) {
277
278 that.allowDeselect = true;
279 that.mapEditorHistory.historyOverlayPush();
280 that.overlays.push(e.overlay); // store reference to added overlay
281 var newShape = e.overlay;
282 newShape.type = e.type;
283 that.mapEditorHistory.presentOverlayPush();
284
285 if (e.type !== google.maps.drawing.OverlayType.MARKER) {
286 that.addShapeListeners(newShape, e);
287 that.setSelection(newShape, e);
288 } else {
289 that.addMarkerListeners(newShape, e);
290 that.setSelection(newShape, e);
291 }
292
293 });
294
295 //Clears selection if clicked on the map when shift is not presseed
296 google.maps.event.addListener(this.map, 'click', function (e) {
297 var c = document.body.childNodes;
298 if (e.target && e.target.matches("a.classA")) {
299 console.log("Anchor element clicked!");
300 }
301 if (that.shiftKeyPressed == false) {
302 that.clearSelection();
303 that.selectedShape = null;
304 }
305 });
306
307 google.maps.event.addListener(this.map, 'mousedown', function (e) {
308 that.dontResize = true;
309 });
310
311 google.maps.event.addListener(this.map, 'mouseup', function (e) {
312 that.dontResize = false;
313 });
314
315 //Keyboard shortcuts
316 var mapAndControls = document.getElementById("map-and-controls-" + this.id);
317 mapAndControls.addEventListener('keydown', function () {
318 if (event.code == 'KeyY' && (event.ctrlKey || event.metaKey) ||
319 (event.code == 'KeyZ' && event.code == 'ShiftLeft' && (event.ctrlKey || event.metaKey))) {
320 that.mapEditorHistory.redo();
321 }
322 if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
323 if (that.shiftKeyPressed == false) {
324 that.mapEditorHistory.undo();
325 }
326 }
327 if (event.code == 'KeyA' && (event.ctrlKey || event.metaKey)) {
328 event.preventDefault();
329 that.drawingManager.setDrawingMode(null);
330 that.selectAll();
331
332 }
333 if (event.code == 'KeyD' && (event.ctrlKey || event.metaKey)) {
334 event.preventDefault();
335 that.deselectAll();
336 }
337 if (event.code == 'Digit0' || event.code == 'Numpad0' || event.code == 'Backquote') {
338
339 that.drawingManager.setDrawingMode(null);
340 } else if (event.code == 'Digit1') {
341 that.drawingManager.setDrawingMode('marker');
342 } else if (event.code == 'Digit2') {
343 that.drawingManager.setDrawingMode('circle');
344 } else if (event.code == 'Digit3') {
345 that.drawingManager.setDrawingMode('polygon');
346 } else if (event.code == 'Digit4') {
347 that.drawingManager.setDrawingMode('polyline');
348 } else if (event.code == 'Digit5') {
349 that.drawingManager.setDrawingMode('rectangle');
350 } else if (event.code == 'KeyQ') {
351 that.printHistory();
352 }
353 // console.log(event.code);
354 });
355
356 /*
357 var mapHtml = document.getElementById("map-" + this.id);
358 var controlHtml = document.getElementById("ControlPanel-" + this.id);
359 controlHtml.addEventListener('click', function () {
360 console.log("*** ControlPanel clicked");
361 mapHtml.focus()
362 });
363 */
364
365 //Sets shift as pressed
366 mapAndControls.addEventListener('keydown', function () {
367 if (event.code == 'ShiftLeft' || event.code == 'ShiftRight') {
368 that.shiftKeyPressed = true;
369
370 }
371
372 });
373
374 //Sets shift as unpressed
375 mapAndControls.addEventListener('keyup', function () {
376 if (event.code == 'ShiftLeft' || event.code == 'ShiftRight') {
377 that.shiftKeyPressed = false;
378 }
379
380 });
381
382 this.buildColorPalette();
383}
384
385//Deletes a vertex if clicked on it
386MapEditor.prototype.vertexAndPolyDel = function (e, newShape) {
387 var vertex = e.vertex;
388 if (e.vertex !== undefined) {
389 if (newShape.type === google.maps.drawing.OverlayType.POLYGON) {
390 var path = newShape.getPaths().getAt(e.path);
391 path.removeAt(e.vertex);
392 if (path.length < 3) {
393 newShape.setMap(null);
394 }
395 }
396 if (newShape.type === google.maps.drawing.OverlayType.POLYLINE) {
397 var path = newShape.getPath();
398 path.removeAt(e.vertex);
399 if (path.length < 2) {
400 newShape.setMap(null);
401 }
402 }
403 }
404}
405
406MapEditor.prototype.addMarkerListeners = function (newShape, e) {
407 var that = this;
408 //cLICK EVENT IF A MARKER IS CREATED
409 google.maps.event.addListener(newShape, 'click', function (e) {
410 that.setSelection(newShape, e);
411 });
412
413 google.maps.event.addListener(newShape, 'dragstart', function (e) {
414 that.beingDragged = true;
415 that.mapEditorHistory.historyOverlayPush();
416
417 });
418
419 google.maps.event.addListener(newShape, 'dragend', function () {
420 that.beingDragged = false;
421 that.mapEditorHistory.presentOverlayPush();
422 that.allowDeselect = false;
423 });
424}
425
426MapEditor.prototype.addShapeListeners = function (newShape, e) {
427 var that = this;
428 // Add an event listener that selects the newly-drawn shape when the user
429 // mouses down on it.
430 google.maps.event.addListener(newShape, 'click', function (e) {
431
432 that.vertexAndPolyDel(e, newShape);
433
434 });
435
436 google.maps.event.addListener(newShape, 'dragstart', function (e) {
437 that.allowDeselect = false;
438 that.mapEditorHistory.historyOverlayPush();
439 });
440
441 google.maps.event.addListener(newShape, 'dragend', function () {
442 that.beingDragged = false;
443 that.mapEditorHistory.presentOverlayPush();
444 that.settingThePath();
445
446 that.allowDeselect = false;
447 that.setSelection(newShape, e);
448 });
449
450 //Store information after the event ends
451 google.maps.event.addListener(newShape, 'bounds_changed', function (e) {
452 if (that.beingDragged == false) {
453 that.mapEditorHistory.presentOverlayPush();
454 }
455 });
456
457 //Add an event listener to select a shape if the mouse hovers over it
458 google.maps.event.addListener(newShape, 'mousedown', function (e) {
459 if (e.target && e.target.matches("a.classA")) {
460 console.log("Anchor element clicked!");
461 }
462 if (e.vertex !== undefined || e.edge !== undefined) {
463 that.mapEditorHistory.historyOverlayPush()
464 }
465 if (that.drawingManager.drawingMode == null) {
466 that.setSelection(newShape, e);
467 }
468 });
469
470 google.maps.event.addListener(newShape, 'mouseup', function (e) {
471 if (e.vertex !== undefined || e.edge !== undefined) {
472 that.mapEditorHistory.presentOverlayPush()
473 } else {
474 //that.setSelection(newShape, e);
475 }
476
477 });
478}
479MapEditor.prototype.clearSelection = function () {
480 if (this.selectedShape) {
481 if (this.selectedShape.type !== 'marker') {
482 this.selectedShape.setEditable(false);
483 if (this.shiftKeyPressed == false) {
484 for (var i = 0; i < this.selectedShapes.length; i++) {
485 this.selectedShapes[i].setEditable(false);
486 }
487 this.selectedShapes = [];
488 }
489 }
490 this.selectedShape = null;
491 }
492}
493
494//Set selection for the selected overlay
495MapEditor.prototype.setSelection = function (shape, e) {
496 //var that = this;
497 if (shape.type !== 'marker') {
498 if (this.shiftKeyPressed == false) {
499 if (e !== null) {
500 if (e.vertex == undefined) {
501 if (e.edge == undefined) {
502 this.clearSelection();
503 shape.setEditable(true);
504 }
505 }
506 }
507 }
508 if (this.selectedShapes.includes(shape)) {
509 if (e !== null) {
510 if (e.vertex == undefined) {
511 if (e.edge == undefined) {
512 this.allowDeselect = true;
513 this.removeFromSelectedShapes(shape);
514 }
515 }
516 }
517 } else {
518 this.allowDeselect = false;
519 shape.setEditable(true);
520 this.selectedShapes.push(shape);
521 }
522
523 //Send the values to be updated
524 var thi = shape.strokeWeight;
525 var opa = shape.fillOpacity;
526 var fCol = shape.fillColor;
527 var sCol = shape.strokeColor;
528 this.updateMenuValues(thi, opa, fCol, sCol);
529
530 } else if (shape.type == 'marker') {
531 this.clearSelection();
532 }
533 this.selectedShape = shape;
534 this.settingThePath();
535}
536
537MapEditor.prototype.removeFromSelectedShapes = function (shape) {
538 if (this.selectedShapes.includes(shape)) {
539 if (this.allowDeselect) {
540 const index = this.selectedShapes.indexOf(shape);
541 this.selectedShapes.splice(index, 1);
542 shape.setEditable(false);
543 }
544 this.allowDeselect = true;
545 }
546}
547
548//Set selected thickness
549MapEditor.prototype.setSelectedThickness = function (sWeight) {
550 if (this.selectedShapes.length > 0) {
551 for (var i = 0; i < this.selectedShapes.length; i++) {
552 this.selectedShapes[i].set('strokeWeight', sWeight);
553 }
554 }
555}
556
557//Set selected opacity
558MapEditor.prototype.setSelectedOpacity = function (fOpacity) {
559
560 if (this.selectedShapes.length > 0) {
561 for (var i = 0; i < this.selectedShapes.length; i++) {
562 this.selectedShapes[i].set('fillOpacity', fOpacity);
563 }
564 }
565}
566
567//set selected fill colour
568MapEditor.prototype.setSelectedShapeColor = function (color) {
569 if (this.selectedShapes.length > 0) {
570 for (var i = 0; i < this.selectedShapes.length; i++) {
571 this.selectedShapes[i].set('fillColor', color);
572 this.selectedShapes[i].set('strokeColor', color);
573 }
574 }
575}
576
577MapEditor.prototype.getElementByXpath = function (path) {
578 return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
579}
580
581MapEditor.prototype.updateMenuValues = function (thi, opa, fCol, sCol) {
582 //Update thickness slider and value on the settings menu
583 var thicknessSliderOutput = document.getElementById("thicknessRangeVal" + "-" + this.id);
584 thicknessSliderOutput.innerHTML = thi;
585 document.getElementById("thicknessRange" + "-" + this.id).value = thi * 20;
586
587 //Update the opacity slider and value on the settings menu
588 var opacitySliderOutput = document.getElementById("opacityRangeVal" + "-" + this.id);
589 opacitySliderOutput.innerHTML = "% " + opa * 100;
590 document.getElementById("colourOpacity" + "-" + this.id).value = opa * 100;
591
592 if (this.drawingManager.drawingMode == null) {
593 this.selectColor(fCol);
594 }
595}
596MapEditor.prototype.selectAll = function () {
597 this.shiftKeyPressed = true;
598 var e = new Object();
599 e.vertex = undefined;
600 this.selectedShapes = [];
601 for (var i = 0; i < this.overlays.length; i++) {
602 this.setSelection(this.overlays[i], e);
603 }
604 this.shiftKeyPressed = false;
605}
606MapEditor.prototype.deselectAll = function () {
607 for (var i = 0; i < this.selectedShapes.length; i++) {
608 this.selectedShapes[i].setEditable(false);
609 }
610 this.selectedShapes = [];
611}
612
613MapEditor.prototype.printHistory = function () {
614 //console.log("prev", this.mapEditorHistory.prevOverlays);
615 //console.log("present ", this.mapEditorHistory.presentOverlays);
616 //console.log("undone ", this.mapEditorHistory.undoneOverlays);
617 //console.log(this.selectedShapes);
618 console.log(this.overlays);
619
620 var json_overlays = ShapesUtil.overlayToJSON(this.overlays);
621
622 console.log("JSON overlay:\n" + JSON.stringify(json_overlays));
623
624}
625
626MapEditor.LOAD = function (json_str) {
627
628 var map_editor = Object.values(gsmap_store)[0]
629
630 var new_overlays = ShapesUtil.JSONToOverlays(json_str);
631
632 for (var i=0; i<map_editor.overlays.length; i++) {
633 map_editor.overlays[i].setMap(null);
634 }
635
636 map_editor.overlays = new_overlays;
637
638 for (var i=0; i<map_editor.overlays.length; i++) {
639 map_editor.overlays[i].setMap(map_editor.map);
640 }
641
642}
643
644MapEditor.prototype.deleteSelectedShapes = function () {
645 //console.log("this fires");
646 this.mapEditorHistory.historyOverlayPush();
647 for (var i = 0; i < this.selectedShapes.length; i++) {
648 this.selectedShapes[i].setMap(null);
649
650 if (this.overlays.includes(this.selectedShapes[i])) {
651 const index = this.overlays.indexOf(this.selectedShapes[i]);
652 this.overlays.splice(index, 1);
653 this.selectedShapes[i].setEditable(false);
654 }
655 }
656 this.selectedShapes = [];
657 //console.log("this fires");
658 this.mapEditorHistory.presentOverlayPush();
659}
660
661MapEditor.prototype.draggableState = function () {
662
663 var draggableCB = document.querySelector("input[name=draggableCB]");
664 draggableCB.addEventListener('change', function () {
665 if (this.checked) {
666 this.overlays.draggable = false;
667 } else {
668 this.overlays.draggable = false;
669 }
670 });
671}
672
673MapEditor.prototype.deleteAllShapes = function () {
674 //console.log("deleteAllShape() this.id = " + this.id);
675 this.mapEditorHistory.historyOverlayPush();
676 for (var i = 0; i < this.overlays.length; i++) {
677 this.overlays[i].setMap(null);
678 }
679 this.overlays = [];
680 this.mapEditorHistory.presentOverlayPush();
681}
Note: See TracBrowser for help on using the repository browser.