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

Last change on this file since 33140 was 33140, checked in by wy59, 5 years ago
  1. Moved from plotting markers for each coord in doc.coords array to creating doc.mapOverlay from GPS.mapOverlay meta and converting each shape therein into Google Map Shapes/Overlays and storing these in the new doc.shapes array. 2. We now use Google Map InfoWindows to display label information for shapes/markers that have them. For now the labels are displayed/hidden on mouseover and mouseout. We can make them permanently displayed if necessary. 3. Lots more TODO questions added.
  • Property svn:executable set to *
File size: 33.7 KB
Line 
1//var newLat, newLng = 0;
2var _docList = new Array();
3_docList.ids = new Array();
4_docList.getDocByIndex = function(index)
5{
6 return _docList[_docList.ids[index]];
7};
8
9var _map;
10var _intervalHandle;
11var _baseURL = document.URL.substring(0, document.URL.indexOf("?") + 1);
12var _retrievedClassifiers = new Array();
13var _preventLoopingSingleMarker = false;
14var _searchRunning = false;
15var _nearbyDocs = new Array();
16var _scrollThroughDefault = true;
17
18function initializeMapScripts()
19{
20 modifyFunctions();
21 setUpMap();
22
23 var jsonNodeDiv = $("#jsonNodes");
24 if(jsonNodeDiv.length)
25 {
26 //console.log("@@@ JSON node div html: " + jsonNodeDiv.html());
27 var jsonNodes = eval(jsonNodeDiv.html());
28
29 if(jsonNodes && jsonNodes.length > 0)
30 {
31 for(var i = 0; i < jsonNodes.length; i++)
32 {
33 _docList[jsonNodes[i].nodeID] = jsonNodes[i];
34 _docList.ids.push(jsonNodes[i].nodeID);
35 createMarkers(jsonNodes[i], true);
36 }
37 updateMap();
38 }
39 else
40 {
41 //hiding the map
42 //$("#map_canvas").css({visibility:"hidden", height:"0px"});
43 $("#map_canvas").css({visibility:"hidden"}); // if you comment this out, add a log message saying "suppressing hiding map"
44 }
45 }
46
47 _docList.loopIndex = 0;
48
49 if(_docList.ids.length > 1)
50 {
51 var startStopCheckbox = $("<input>", {"type": "checkbox", "checked": _scrollThroughDefault, "id": "scrollCheckbox"});
52 startStopCheckbox.click(function()
53 {
54 // http://stackoverflow.com/questions/901712/how-to-check-if-a-checkbox-is-checked-in-jquery
55 // http://stackoverflow.com/questions/5270689/attrchecked-checked-does-not-work
56
57 if($('#scrollCheckbox').is(':checked')) // OR: if(document.getElementById('scrollCheckbox').checked)
58 {
59 if(_intervalHandle == null)
60 {
61 _intervalHandle = setInterval(loopThroughMarkers, 2000);
62 }
63 }
64 else
65 {
66 clearInterval(_intervalHandle);
67 _intervalHandle = null;
68 }
69 });
70
71 var label = $("<span>Scroll through places</span>");
72 var container = $("<div>", {"class": "ui-widget-header ui-corner-all", "style": "clear:right; float:right; padding:0px 5px 3px 0px;"});
73 container.append(startStopCheckbox);
74 container.append(label);
75
76 $(container).insertAfter("#map_canvas");
77
78 if (_scrollThroughDefault) {
79 _intervalHandle = setInterval(loopThroughMarkers, 2000);
80 }
81
82 }
83}
84
85function setUpMap()
86{
87 //alert("@@@@in map-scripts::setUpMap()");
88
89 var myOptions =
90 {
91 zoom: 2,
92 center: new google.maps.LatLng(0, 0),
93 mapTypeId: google.maps.MapTypeId.HYBRID
94 };
95 var $map_canvas = $("#map_canvas");
96
97 if ($map_canvas.length > 0) {
98 _map = new google.maps.Map($map_canvas[0], myOptions);
99 google.maps.event.addListener(_map, 'bounds_changed', performSearchForMarkers);
100 }
101}
102
103function performSearchForMarkers()
104{
105 if(_searchRunning)
106 {
107 return;
108 }
109
110
111
112 _searchRunning = true;
113
114 var bounds = _map.getBounds();
115
116 var neLat = bounds.getNorthEast().lat();
117 var neLng = bounds.getNorthEast().lng();
118 var swLat = bounds.getSouthWest().lat();
119 var swLng = bounds.getSouthWest().lng();
120
121 var latDistance = neLat - swLat;
122 var lngDistance = neLng - swLng;
123
124 //Check which increment to use for latitude (i.e. 0.001, 0.01, 0.1 or 1 degree increments)
125 var latDelta;
126 var latPrecision;
127 for(var i = 3; i >= 0; i--)
128 {
129 latDelta = (1 / Math.pow(10, i));
130 if((latDistance / latDelta) <= 5 || latDelta == 1)
131 {
132 latPrecision = i;
133 break;
134 }
135 }
136
137 //Check which increment to use for longitude (i.e. 0.001, 0.01, 0.1 or 1 degree increments)
138 var lngDelta;
139 for(var i = 3; i >= 0; i--)
140 {
141 lngDelta = (1 / Math.pow(10, i));
142 if((lngDistance / lngDelta) <= 5 || lngDelta == 1)
143 {
144 lngPrecision = i;
145 break;
146 }
147 }
148
149 if(latDelta == 0.1){latDelta = 1; latPrecision = 0; }
150 if(lngDelta == 0.1){lngDelta = 1; lngPrecision = 0; }
151
152 /*
153 var query = "";
154 for(var i = 0; i <= Math.floor(latDistance / latDelta) + 1; i++)
155 {
156 for(var j = 0; j <= Math.floor(lngDistance / lngDelta) + 1; j++)
157 {
158 //Some necessary variables
159 var newLat = neLat - (latDelta * i);
160 var newLatString = "" + newLat;
161 var newLatTrunc;
162 if(newLat < 0){newLatTrunc = Math.ceil(newLat);}
163 else{newLatTrunc = Math.floor(newLat);}
164
165 var newLng = neLng - (lngDelta * j);
166 var newLngString = "" + newLng;
167 var newLngTrunc;
168 if(newLng < 0){newLngTrunc = Math.ceil(newLng);}
169 else{newLngTrunc = Math.floor(newLng);}
170
171 //Construct query
172 query += "(";
173 query += "LA:" + coordToAbsDirected(newLatTrunc, "lat");
174 if(latDelta != 1)
175 {
176 query += "+AND+";
177 query += "LA:" + newLatString.substring(newLatString.indexOf(".") + 1, newLatString.indexOf(".") + latPrecision + 1);
178 }
179 query += "+AND+";
180 query += "LN:" + coordToAbsDirected(newLngTrunc, "lng");
181 if(lngDelta != 1)
182 {
183 query += "+AND+";
184 query += "LN:" + newLngString.substring(newLngString.indexOf(".") + 1, newLngString.indexOf(".") + lngPrecision + 1);
185 }
186 query += ")";
187
188 if(i != (Math.floor(latDistance / latDelta) + 1) || j != (Math.floor(lngDistance / lngDelta) + 1)){ query += "+OR+"; }
189 }
190 }
191 */
192 var query = "";
193 var iMax = Math.floor(latDistance / latDelta) + 1;
194 var jMax = Math.floor(lngDistance / lngDelta) + 1;;
195 for(var i = 0; i <= iMax; i++) //for(var i = 0; i <= Math.floor(latDistance / latDelta) + 1; i++)
196 {
197 for(var j = 0; j <= jMax; j++) //for(var j = 0; j <= Math.floor(lngDistance / lngDelta) + 1; j++)
198 {
199 //Some necessary variables
200 var newLat = neLat - (latDelta * i);
201 var newLatString = "" + newLat;
202 var newLatTrunc;
203 if(newLat < 0){newLatTrunc = Math.ceil(newLat);}
204 else{newLatTrunc = Math.floor(newLat);}
205
206 var newLng = neLng - (lngDelta * j);
207 var newLngString = "" + newLng;
208 var newLngTrunc;
209 if(newLng < 0){newLngTrunc = Math.ceil(newLng);}
210 else{newLngTrunc = Math.floor(newLng);}
211
212 //Construct query
213 query += "(";
214 query += "CS:\"" + coordToAbsDirected(newLatTrunc, "lat");
215 //query += "CS:\"" + coordToAbsDirected(newLatTrunc, "lat") + "\" \"" + coordToAbsDirected(newLngTrunc, "lng") + "\""; //query += "LA:" + coordToAbsDirected(newLatTrunc, "lat");
216 if(latDelta != 1)
217 {
218 query += newLatString.substring(newLatString.indexOf(".") + 1, newLatString.indexOf(".") + latPrecision + 1);
219 }
220 query += " ";
221 //query += "+AND+";
222
223 //query += "LN:" + coordToAbsDirected(newLngTrunc, "lng");
224 query += coordToAbsDirected(newLngTrunc, "lng");
225 if(lngDelta != 1)
226 {
227 query += newLngString.substring(newLngString.indexOf(".") + 1, newLngString.indexOf(".") + lngPrecision + 1);
228 }
229 query += "\"";
230 query += ")";
231
232 //if(i != (Math.floor(latDistance / latDelta) + 1) || j != (Math.floor(lngDistance / lngDelta) + 1)){ query += "+OR+"; }
233 if(i != iMax || j != jMax){ query += "+OR+"; }
234 }
235 }
236
237 // This works, why not from the double loop above?
238 //query = "(CS:\"" + coordToAbsDirected(newLatTrunc, "lat") + " " + coordToAbsDirected(newLngTrunc, "lng") + "\")";
239 //alert("@@@@in map-scripts::performSearchForMarkers() - query: " + query);
240
241 //var url = gs.xsltParams.library_name + "?a=q&s=RawQuery&rt=rd&c=" + gs.cgiParams.c + "&s1.rawquery=" + query + "&excerptid=jsonNodes";
242 var url = gs.xsltParams.library_name;
243 var data = "a=q&s=RawQuery&rt=rd&c=" + gs.cgiParams.c + "&s1.rawquery=" + query + "&excerptid=jsonNodes";
244 $.ajax({type:"POST", url:url, data:data})
245 .success(function(responseText)
246 {
247 //console.log("*** responseText (first 250) = " + responseText.substring(0,256));
248
249 if(responseText.search("id=\"jsonNodes") != -1)
250 {
251 var startIndex = responseText.indexOf(">");
252 var endIndex = responseText.indexOf("</");
253
254 //console.log("@@@@ performSearch, got response: " + responseText);
255
256 var jsonNodes = eval(responseText.substring(startIndex+1, endIndex));
257 if(jsonNodes && jsonNodes.length > 0)
258 {
259 for(var i = 0; i < jsonNodes.length; i++)
260 {
261 var doc = jsonNodes[i];
262
263 var found = false;
264 for(var j = 0; j < _docList.ids.length; j++){if(doc.nodeID == _docList.ids[j]){found = true; break;}}
265
266 if(!found)
267 {
268 _docList[doc.nodeID] = doc;
269 _docList.ids.push(doc.nodeID);
270
271 createMarkers(doc, false);
272 }
273 }
274 }
275 }
276 else
277 {
278 console.log("No JSON information received");
279 }
280
281 _searchRunning = false;
282 }).fail(function(responseText, textStatus, errorThrown) // fail() has replaced error(), http://api.jquery.com/jquery.ajax/
283 {
284 console.log("In map-scripts.performSearchForMarkers(): Got an error in ajax call");
285 _searchRunning = false;
286 });
287}
288
289function coordToAbsDirected(coord, type)
290{
291 var value = "" + coord;
292 if(coord < 0)
293 {
294 value = value.substring(1);
295 if(type == "lat")
296 {
297 value += "S";
298 }
299 else
300 {
301 value += "W";
302 }
303 }
304 else
305 {
306 if(type == "lat")
307 {
308 value += "N";
309 }
310 else
311 {
312 value += "E";
313 }
314 }
315
316 return value;
317}
318
319function updateMap()
320{
321 var markersOnMap = 0;
322 var bounds = new google.maps.LatLngBounds();
323 for(var i = 0; i < _docList.ids.length; i++)
324 {
325 var doc = _docList.getDocByIndex(i);
326 if(doc.parentCL && doc.parentCL.style.display == "none")
327 {
328 if(doc.shapes) {
329 for(var x = 0; x < doc.shapes.length; x++) {
330 doc.shapes[x].setVisible(false);
331 }
332 } else {
333 doc.marker.setVisible(false);
334 }
335 continue;
336 }
337 else
338 {
339 if(doc.shapes) {
340 for(var x = 0; x < doc.shapes.length; x++) {
341 doc.shapes[x].setVisible(true);
342 }
343 } else {
344 doc.marker.setVisible(true);
345 }
346 markersOnMap++; // TODO: what do we do with this when we have shapes. This variable may be connected with centring the map?
347 }
348
349
350 if(doc.coords) {
351 for(var x = 0; x < doc.coords.length; x++) {
352 var coord = doc.coords[x];
353 var coordInfo = getLatLngForCoord(doc.coords[x]);
354 bounds.extend(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
355 }
356 }
357 else {
358 bounds.extend(new google.maps.LatLng(doc.lat, doc.lng));
359 }
360 }
361
362 if(markersOnMap > 1)
363 {
364 _map.fitBounds(bounds);
365 } else if (markersOnMap == 1) {
366 // sometimes a single point bounds are too small for the map to display, so use center and zoom instead of fitbounds.
367 _map.setCenter(bounds.getCenter());
368 _map.setZoom(18); // arbitrary value that looked nice for my example
369 }
370}
371
372function getLatLngForCoord(coord) {
373
374 // https://stackoverflow.com/questions/2559318/how-to-check-for-an-undefined-or-null-variable-in-javascript
375 if(!coord) {
376 // some_variable is either null, undefined, 0, NaN, false, or an empty string
377 console.log("@@@@ In map-scripts::getLatLngForCoord(): no or invalid coord info");
378 return null;
379 }
380
381 // coord is of the form: "37S77 157E53"
382 // lat will be 37S77, lng 157E53.
383 var indexOfSpace = coord.indexOf(" ");
384 if(indexOfSpace === -1) {
385 console.log("@@@@ In map-scripts::getLatLngForCoord(): bad format for coord " + coord);
386 return null;
387 }
388 var latitude = coord.substring(0, indexOfSpace);
389 var longitude = coord.substring(indexOfSpace+1);
390 return {lat: latitude, lng: longitude}; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
391}
392
393function loopThroughMarkers()
394{
395 if(_docList.ids.length == 0)
396 {
397 return;
398 }
399
400 var visibleMarkers = new Array();
401 for(var i = 0; i < _docList.ids.length; i++)
402 {
403 var doc = _docList.getDocByIndex(i);
404 if(doc.marker.getVisible())
405 {
406 visibleMarkers.push(doc);
407 }
408 }
409
410 if(visibleMarkers.length < 2)
411 {
412 clearAllInfoBoxes();
413 return;
414 }
415
416 clearAllInfoBoxes();
417
418 var elem = null;
419 while(!elem)
420 {
421 if(_docList.loopIndex >= visibleMarkers.length)
422 {
423 _docList.loopIndex = 0;
424 }
425
426 var doc = visibleMarkers[_docList.loopIndex];
427 var elem = gs.jqGet("div" + doc.nodeID);
428 if(elem.length)
429 {
430 elem.css("background", "#BBFFBB");
431 setTimeout(function(){elem.css("background", "");}, 2000);
432 }
433 _docList.loopIndex++;
434 }
435 doc.marker.markerInfo.open(_map, doc.marker);
436}
437
438// Unused at present, called by draggableCreateMarker
439// Map used to have editable markers. Now editable markers are restricted to the map-editor.
440function attachDraggableClickHandler(marker, nodeID)
441{
442 google.maps.event.addListener(marker, 'click', function()
443 {
444 document.location.href = gs.xsltParams.library_name + "?a=d&ed=1&c=" + gs.cgiParams.c + "&d=" + nodeID + "&dt=hierarchy&p.a=b&p.sa=&p.s=ClassifierBrowse";
445
446 });
447
448 if (("docEdit" in gs.cgiParams) && (gs.cgiParams['docEdit'])) {
449 google.maps.event.addListener(marker, 'mouseup', function()
450 {
451 var lat = marker.getPosition().lat();
452 var lng = marker.getPosition().lng();
453 var collection = gs.cgiParams.c;
454 var site_name = gs.xsltParams.site_name;
455
456 if (nodeID == "") {
457 nodeID = gs.cgiParams.d;
458 }
459 console.log("GPS Click handler in collection:" + collection + " in site: " + site_name + " for Doc: " + nodeID + "(" + lat + "," + lng + ")");
460
461 var callbackFunction = function(){console.log("Completed saving metadata changes. You must rebuild the collection for the changes to take effect.");};
462
463 // set 5th parameter, metapos (metadata position) or 7th param prevMetaValue (previous metadata value) to non-null if you want metamode=override to work
464 // if neither of these 2 are set, then metamode is changed to 'accumulate' instead.
465 gs.functions.setArchivesMetadata(collection, site_name, nodeID, "Latitude", null, lat, null, "override", function(){callbackFunction();});
466 gs.functions.setArchivesMetadata(collection, site_name, nodeID, "Longitude", null, lng, null, "override", function(){callbackFunction();});
467 gs.functions.setArchivesMetadata(collection, site_name, nodeID, "Coordinate", null, lat + " " + lng, null, "override", function(){callbackFunction();});
468 console.log("NodeID: " + nodeID);
469 console.log("GPS Click handler in collection:" + collection + " in site: " + site_name + " for Doc: " + nodeID + "(" + lat + "," + lng + ")");
470 });
471 }
472}
473
474function focusDocument(id)
475{
476 var doc = _docList[id];
477 if(doc)
478 {
479 clearInterval(_intervalHandle);
480 _intervalHandle = null;
481 if(doc.coords) {
482 for(var x = 0; x < doc.coords.length; x++) {
483 var coord = doc.coords[x];
484 var coordInfo = getLatLngForCoord(doc.coords[x]);
485 _map.panTo(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
486 }
487 } else {
488 _map.panTo(new google.maps.LatLng(doc.lat, doc.lng));
489 }
490 clearAllInfoBoxes();
491 doc.marker.markerInfo.open(_map, doc.marker);
492 var scrollCheckbox = $("#scrollCheckbox");
493 if(scrollCheckbox.checked)
494 {
495 scrollCheckbox.checked = false;
496 }
497 }
498}
499
500function clearAllInfoBoxes()
501{
502 for(var i = 0; i < _docList.ids.length; i++)
503 {
504 var doc = _docList.getDocByIndex(i);
505 doc.marker.markerInfo.close();
506 }
507}
508
509function createMarkers(doc, mainMarker) {
510 if(doc.mapoverlay) {
511 //console.log("Have shapes: " + doc.mapoverlay.toString());
512 createShapes(doc, mainMarker);
513 } else { // backwards compatible to deal with Lat and Lng meta stored for doc
514 pos = new google.maps.LatLng(doc.lat,doc.lng);
515 createMarker(doc, pos, mainMarker);
516 }
517}
518
519function addInfoMarker(doc, shape) {
520
521 if(!shape.description) {
522 //console.log("@@@@ " + shape.type.toString() + " had no description/label");
523 return;
524 }
525
526 // else add an InfoWindow for this shape using the label (shape.description)
527
528 // https://developers.google.com/maps/documentation/javascript/infowindows
529 // An InfoWindow's "position contains the LatLng at which this info window is anchored.
530 // Note: An InfoWindow may be attached either to a Marker object (in which case its position is based on the marker's location)
531 // or on the map itself at a specified LatLng. Opening an info window on a marker will automatically update the position."
532 var infoWindow = new google.maps.InfoWindow({content:shape.description}); // NOTE: if not setting content or position properties
533 // inside this constructor, need to call setContent/setPosition to set them
534
535 if(shape.type === google.maps.drawing.OverlayType.MARKER) {
536 var marker = shape;
537 //marker.addListener('mouseover', function() {
538 infoWindow.open(_map, marker);
539 //});
540 attachClickHandler(marker, doc.nodeID); // do what the original code used to do here
541 }
542 else {
543 var coord = ShapesUtil.getLabelCoordinate(shape);
544 console.log("Coord for " + shape.type.toString() + " is " + coord.toString());
545 infoWindow.setPosition(coord);
546 shape.addListener('mouseover', function() {
547 infoWindow.open(_map);
548 });
549 shape.addListener('mouseout', function() {
550 infoWindow.close();
551 });
552 attachClickHandler(shape, doc.nodeID); // as above
553 }
554}
555
556// This function will create Google Shapes/Overlays and markers out of a given doc JSONNode's doc.mapOverlay
557// (doc.mapOverlay shapes are stored as an array of JSON) and store the shapes/overlays in the doc.shapes array.
558// Note: doc.coords are just an array of all the coordinates in a doc, not indicating to which shapes they belong.
559// They're only **for searching** - for seaching which coords (hence docs) are in a map.
560// Param mainMarker: if set to true, marker is red. If false, marker is blue
561function createShapes(doc, mainMarker)
562{
563 // for doc.shapes: don't store JSON anymore, convert them to google Shapes overlays and store them instead
564 doc.shapes = [];
565 for (var i=0; i<doc.mapoverlay.length; i++) {
566 var shape = ShapesUtil.JSONToShape(doc.mapoverlay[i]);
567 doc.shapes[i] = shape;
568 shape.setMap(_map);
569 shape["title"] = doc.title;
570
571 // Unset editable and draggable properties of shape
572 // And for markers, which are initialised to clickable besides, undo the clickability
573 // and set them
574 if(shape.type === google.maps.drawing.OverlayType.MARKER) {
575 var marker = shape;
576 // mainMarkers should be red
577 if(!mainMarker) {
578 marker["icon"] = "interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png";
579 }
580 marker.clickable = false; // only markers
581 }
582
583 shape.editable = false;
584 shape.draggable = false;
585
586
587
588 // doc[i]'s label = doc.shapes[i].description
589 addInfoMarker(doc, shape);
590 }
591
592 var docElement = gs.jqGet("div" + doc.nodeID);
593 var parent;
594 if(docElement)
595 {
596 parent = docElement.parentNode;
597 }
598
599 while(parent && parent.nodeName != "BODY")
600 {
601 if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
602 {
603 doc.parentCL = parent;
604 break;
605 }
606
607 parent = parent.parentNode;
608 }
609}
610
611// This method is only for backwards compatibility: for those collections with docs that only have Lat and Lng meta
612// and no GPS.mapOverlay (and hence Coordinate) meta.
613// Param mainMarker: if set to true, marker is red. If false, marker is blue
614function createMarker(doc, pos, mainMarker)
615{
616 var marker;
617 if(mainMarker)
618 {
619 marker = new google.maps.Marker
620 ({
621 position: pos,
622 title:doc.title,
623 map:_map
624 });
625 }
626 else
627 {
628 marker = new google.maps.Marker
629 ({
630 position: pos,
631 title:doc.title,
632 map:_map,
633 icon:"interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png"
634 });
635 }
636
637 var docElement = gs.jqGet("div" + doc.nodeID);
638 var parent;
639 if(docElement)
640 {
641 parent = docElement.parentNode;
642 }
643
644 while(parent && parent.nodeName != "BODY")
645 {
646 if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
647 {
648 doc.parentCL = parent;
649 break;
650 }
651
652 parent = parent.parentNode;
653 }
654
655 var info = new google.maps.InfoWindow({content:doc.title});
656 marker.markerInfo = info;
657 doc.marker = marker;
658 attachClickHandler(marker, doc.nodeID);
659}
660
661// TODO: with the following, it seems that clicking on shape expands the entire document
662// Should it be that clicking on a shape should expand the doc section that contains that shape meta?
663function attachClickHandler(shapeOrMarker, nodeID)
664{
665 google.maps.event.addListener(shapeOrMarker, 'click', function()
666 {
667 document.location.href = gs.xsltParams.library_name + "?a=d&ed=1&c=" + gs.cgiParams.c + "&d=" + nodeID + "&dt=hierarchy&p.a=b&p.sa=&p.s=ClassifierBrowse";
668 });
669}
670
671// TODO:
672// Version of createMarker function containing Zeddy's modifications (pre-mapeditor?) to make markers
673// on the public *map* (not on map-editor) draggable/editable and to save these edits/rebuild with them.
674// Do we want to continue supporting editing on the main map? I thought we weren't going to and that editing
675// was exclusive to the map-editor, with the public map only displaying the saved features?
676function draggableCreateMarker(doc, pos, mainMarker)
677{
678 var docEdit = (("docEdit" in gs.cgiParams) && (gs.cgiParams['docEdit']));
679 //var draggable_val = (docEdit) ? true : false;
680
681 // When user logs out, the very first page they're returned to has logout set
682 // If the user logged out when leaving docEdit on, then the very first page has docEdit=1 AND logout.
683 // In that case, don't allow editing. Subsequent pages in logged out mode have neither logout nor docEdit=1 set.
684 var loggedOutVar = ("logout" in gs.cgiParams);
685
686 // Don't allow dragging if either 1. docEdit not on OR 2. logout is in the cgiParams
687 var draggable_val = (!docEdit || loggedOutVar) ? false : true;
688
689 var marker;
690 if(mainMarker)
691 {
692 marker = new google.maps.Marker
693 ({
694 position: pos,
695 title:doc.title,
696 map:_map,
697 draggable: draggable_val
698 });
699 }
700 else
701 {
702 marker = new google.maps.Marker
703 ({
704 position: pos,
705 title:doc.title,
706 map:_map,
707 icon:"interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png",
708 draggable: draggable_val
709 });
710 }
711
712 var docElement = gs.jqGet("div" + doc.nodeID);
713 var parent;
714 if(docElement)
715 {
716 parent = docElement.parentNode;
717 }
718
719 while(parent && parent.nodeName != "BODY")
720 {
721 if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
722 {
723 doc.parentCL = parent;
724 break;
725 }
726
727 parent = parent.parentNode;
728 }
729
730 var info = new google.maps.InfoWindow({content:doc.title});
731 marker.markerInfo = info;
732 doc.marker = marker;
733 attachDraggableClickHandler(marker, doc.nodeID);
734
735 ////////////////////////////////////////////////////// TEST
736
737 newLat = marker.getPosition().lat();
738 newLng = marker.getPosition().lng();
739 //console.log("Latitude " + newLat);
740 //console.log("Longitude " + newLng);
741 //NewLatLng(newLat, newLng);
742
743// // Define the LatLng coordinates for the polygon's path.
744// var triangleCoords = [
745// {lat: 18.774, lng: -80.190},
746// {lat: 18.466, lng: -64.600},
747// {lat: 32.321, lng: -64.757},
748// {lat: 32.300, lng: -80.190},
749// {lat: 28.300, lng: -90.190}
750// ];
751//
752// // Construct the polygon.
753// var bermudaTriangle = new google.maps.Polygon({
754// paths: triangleCoords,
755// strokeColor: '#FF0000',
756// strokeOpacity: 0.8,
757// strokeWeight: 2,
758// fillColor: '#FF0000',
759// fillOpacity: 0.35
760// });
761// bermudaTriangle.setMap(map);
762}
763
764function NewLatLng(lat, lng)
765{
766 console.log("Latitude " + lat);
767 console.log("Longitude " + lng);
768}
769
770function getSubClassifier(sectionID)
771{
772 var url = gs.xsltParams.library_name + "?a=b&rt=s&s=ClassifierBrowse&c=" + gs.cgiParams.c + "&cl=" + sectionID + "&excerptid=jsonNodes";
773 $.ajax(url)
774 .success(function(responseText)
775 {
776 var startIndex = responseText.indexOf(">");
777 var endIndex = responseText.indexOf("</");
778
779 var jsonNodes = eval(responseText.substring(startIndex+1, endIndex));
780 if(jsonNodes && jsonNodes.length > 0)
781 {
782 for(var i = 0; i < jsonNodes.length; i++)
783 {
784 var doc = jsonNodes[i];
785 _docList[doc.nodeID] = doc;
786 _docList.ids.push(doc.nodeID);
787
788 createMarkers(doc, false);
789 }
790
791 $("#map_canvas").css({"visibility": "visible", "height": ""});
792 }
793
794 updateMap();
795 })
796 .error(function()
797 {
798 console.log("Error getting subclassifiers");
799 return;
800 });
801}
802
803function performDistanceSearchWithCoordinates(id, coord, degrees)
804{
805 var coordInfo = getLatLngForCoord(coord);
806 if(!coordInfo) {
807 console.log("@@@ ERROR in map-scripts::performDistanceSearchWithCoordinates: coordInfo is null");
808 }
809 performDistanceSearch(id, coordInfo.lat, coordInfo.lng, degrees);
810}
811
812function performDistanceSearch(id, lat, lng, degrees)
813{
814 if(parseFloat(lat) > 180 || parseFloat(lat) < -180 || parseFloat(lng) > 180 || parseFloat(lat) < -180)
815 {
816 console.log("Latitude or longitude incorrectly formatted");
817 return;
818 }
819
820 if(lat.indexOf(".") == -1 || lng.indexOf(".") == -1 || (lat.indexOf(".") + 3) >= lat.length || (lng.indexOf(".") + 3) >= lng.length)
821 {
822 console.log("Latitude or longitude does not have the required precision for a distance search");
823 return;
824 }
825
826 var query = "";
827 for(var i = 0; i < degrees * 2; i++)
828 {
829 for (var j = 0; j < degrees * 2; j++)
830 {
831 var latDelta = (i - degrees) * 0.01;
832 var lngDelta = (j - degrees) * 0.01;
833
834 query += "(" + getDistanceQueryString(lat, latDelta, 2, "LA", ["N","S"]);
835 query += "+AND+";
836 query += getDistanceQueryString(lng, lngDelta, 2, "LN", ["E","W"]) + ")";
837
838 if(i != ((degrees * 2) - 1) || j != ((degrees * 2) - 1)){ query += "+OR+"; }
839 }
840 }
841
842 var inlineTemplate = '\
843 <xsl:template match="/" priority="5">\
844 <table id="nearbyDocs">\
845 <tr>\
846 <th><a href="javascript:sortByDistance();">Distance</a></th><th><a href="javascript:sortAlphabetically();">Document</a></th>\
847 </tr>\
848 <xsl:apply-templates select="//documentNode"/>\
849 </table>\
850 </xsl:template>\
851 \
852 <xsl:template match="documentNode" priority="5">\
853 <xsl:if test="@nodeID !=\''+id+'\'">\
854 <tr>\
855 <td>___<gsf:metadata name="Latitude"/>______<gsf:metadata name="Longitude"/>___</td>\
856 <td><gsf:link title="'+gs.text.doc.nearby_doc_tooltip+'" type="document"><gsf:metadata name="Title"/></gsf:link></td>\
857 </tr>\
858 </xsl:if>\
859 </xsl:template>';
860
861 var url = gs.xsltParams.library_name + "?a=q&s=RawQuery&rt=rd&c=" + gs.cgiParams.c + "&s1.rawquery=" + query + "&excerptid=nearbyDocs&ilt=" + inlineTemplate.replace(/ /, "%20");
862 $.ajax(url)
863 .success(function(response)
864 {
865 response = response.replace(/<img src="[^"]*map_marker.png"[^>]*>/g, "");
866
867 var nearbyDocsArray = new Array();
868
869 var lats = new Array();
870 var lngs = new Array();
871 var matches = response.match(/___(-?[0-9\.]*)___/g);
872 for(var i = 0; i < matches.length; i += 2)
873 {
874 var matchLatFloat = parseFloat(matches[i].replace("___", ""));
875 var matchLngFloat = parseFloat(matches[i+1].replace("___", ""));
876
877 lats.push(matchLatFloat);
878 lngs.push(matchLngFloat);
879 var distance = Math.sqrt(Math.pow(matchLatFloat - parseFloat(lat), 2) + Math.pow(matchLngFloat - parseFloat(lng), 2)) * (40000.0/360.0);
880 var distanceString = "" + distance;
881 distanceString = distanceString.substring(0, 6);
882 response = response.replace(matches[i] + matches[i+1], distanceString);
883 }
884
885 var index = 0;
886 var i = 0;
887 while(true)
888 {
889 var distanceStart = response.indexOf("<td>", index);
890 if(distanceStart == -1)
891 {
892 break;
893 }
894 var distanceEnd = response.indexOf("</td>", distanceStart);
895
896 var docLinkStart = response.indexOf("<td>", distanceEnd);
897 var docLinkEnd = response.indexOf("</td>", docLinkStart);
898
899 var dist = response.substring(distanceStart + 4, distanceEnd);
900 var docLink = response.substring(docLinkStart + 4, docLinkEnd);
901
902 _nearbyDocs.push({title:docLink, distance:dist, lat:lats[i], lng:lngs[i++]});
903
904 index = docLinkEnd;
905 }
906
907 sortByDistance(lat,lng);
908
909 var toggle = $("#nearbyDocumentsToggle");
910 toggle.attr("src", gs.imageURLs.collapse);
911 gs.functions.makeToggle(toggle, $("#nearbyDocuments"));
912 });
913}
914
915var map_centering_timeout = null;
916function recenterMapF(lat, lng)
917{
918 return function() {
919 _map.setCenter(new google.maps.LatLng(lat, lng));
920 }
921}
922function recenterMap(lat, lng)
923{
924
925 _map.setCenter(new google.maps.LatLng(lat, lng));
926
927}
928function sortByDistance(base_lat,base_lng)
929{
930 var sortedTable = '<table id="nearbyDocs" onmouseleave="clearTimeout(map_centering_timeout); recenterMap('+base_lat+','+base_lng+');"><tr><th><a href="javascript:;">Distance</a></th><th><a href="javascript:sortAlphabetically('+base_lat+', '+base_lng+');">Document</a></th></tr>';
931 _nearbyDocs.sort(function(a, b){return (a.distance - b.distance);});
932 for(var i = 0; i < _nearbyDocs.length; i++)
933 {
934
935 sortedTable += "<tr><td>" + prettifyDistance(_nearbyDocs[i].distance) + '</td><td onmouseover="clearTimeout(map_centering_timeout); map_centering_timeout = setTimeout(recenterMapF(' + _nearbyDocs[i].lat + ',' + _nearbyDocs[i].lng + '), 900)" >' + _nearbyDocs[i].title + "</td></tr>";
936 }
937 sortedTable += "</table>";
938
939 $("#nearbyDocuments").html(sortedTable);
940}
941function prettifyDistance(distance) {
942
943 var new_distance;
944 if (distance < 1) {
945 new_distance = (distance * 1000);
946 // Round to nearest whole number - don't need to show points of metres..
947 new_distance = Math.round(new_distance);
948 new_distance += " m";
949 }
950 else {
951 new_distance = distance +" km";
952
953 }
954 return new_distance;
955}
956
957
958
959function sortAlphabetically(base_lat, base_lng)
960{
961 var sortedTable = '<table id="nearbyDocs" onmouseleave="clearTimeout(map_centering_timeout); recenterMap('+base_lat+','+base_lng+');"><tr><th><a href="javascript:sortByDistance('+base_lat+', '+base_lng+');">Distance</a></th><th><a href="javascript:;">Document</a></th></tr>';
962 _nearbyDocs.sort(function(a, b)
963 {
964 var firstTitleStartIndex = a.title.indexOf(">");
965 var firstTitleEndIndex = a.title.indexOf("<", firstTitleStartIndex);
966 var firstTitle = a.title.substring(firstTitleStartIndex + 1, firstTitleEndIndex);
967 var secondTitleStartIndex = b.title.indexOf(">");
968 var secondTitleEndIndex = b.title.indexOf("<", secondTitleStartIndex);
969 var secondTitle = b.title.substring(secondTitleStartIndex + 1, secondTitleEndIndex);
970 return ((firstTitle.toLowerCase() == secondTitle.toLowerCase()) ? 0 : ((firstTitle.toLowerCase() > secondTitle.toLowerCase()) ? 1 : -1));
971 });
972 for(var i = 0; i < _nearbyDocs.length; i++)
973 {
974 sortedTable += "<tr><td>" + _nearbyDocs[i].distance + '</td><td onmouseover="clearTimeout(map_centering_timeout); map_centering_timeout = setTimeout(recenterMapF(' + _nearbyDocs[i].lat + ',' + _nearbyDocs[i].lng + '), 900)">' + _nearbyDocs[i].title + "</td></tr>";
975 }
976 sortedTable += "</table>";
977
978 $("#nearbyDocuments").html(sortedTable);
979}
980
981function getDistanceQueryString(currentCoord, delta, precision, indexName, dirs)
982{
983 var query = "";
984 var coordFloat = parseFloat(currentCoord);
985
986 var newCoord = "" + (coordFloat + delta);
987 var beforeDec = newCoord.substring(0, newCoord.indexOf("."));
988
989 var dir = dirs[0];
990 if(coordFloat < 0)
991 {
992 dir = dirs[1];
993 beforeDec = beforeDec.substring(1);
994 }
995 beforeDec += dir;
996
997 var afterDec = newCoord.substring(newCoord.indexOf(".") + 1, newCoord.indexOf(".") + (precision) + 1);
998
999 return indexName + ":" + beforeDec + "+AND+" + indexName + ":" + afterDec;
1000}
1001
1002function modifyFunctions()
1003{
1004 // This function "overrides" toggleSection in both classifier_scripts.js and document_scripts.js
1005 // However, classifier_scripts.js::toggleSection() only took one parameter, sectionID, whereas
1006 // document_scripts.js::toggleSection() took 3 params (sectionID, callback, tocDisabled).
1007 // So to be compatible with both, need map-scripts::toggleSection() here to support all 3 in that order.
1008 toggleSection = function(sectionID, callback, tocDisabled)
1009 {
1010 _basicToggleSection(sectionID, callback, tocDisabled);
1011
1012 var section = gs.jqGet("div" + sectionID);
1013 var sectionToggle = gs.jqGet("toggle" + sectionID);
1014
1015 if(sectionToggle == undefined)
1016 {
1017 return;
1018 }
1019
1020 // Test if 'section' exists.
1021 // ==> Because we're using jQuery to do this we need to test the length of the object returned
1022 // http://stackoverflow.com/questions/920236/how-can-i-detect-if-a-selector-returns-null
1023 if(section.length !== 0)
1024 {
1025 if(isExpanded(sectionID))
1026 {
1027 section.css("display", "none");
1028 sectionToggle.attr("src", gs.imageURLs.expand);
1029
1030 if(openClassifiers[sectionID].length !== 0) //if(openClassifiers[sectionID] != undefined)
1031 {
1032 delete openClassifiers[sectionID];
1033 }
1034 }
1035 else
1036 {
1037 section.css("display", "block");
1038 sectionToggle.attr("src", gs.imageURLs.collapse);
1039 openClassifiers[sectionID] = true;
1040 }
1041 updateOpenClassifiers();
1042 updateMap();
1043 }
1044 else
1045 {
1046 httpRequest(sectionID);
1047 }
1048
1049 }
1050
1051 httpRequest = function(sectionID)
1052 {
1053 if(!inProgress[sectionID])
1054 {
1055 inProgress[sectionID] = true;
1056
1057 var sectionToggle = gs.jqGet("toggle" + sectionID);
1058 sectionToggle.attr("src", gs.imageURLs.loading);
1059
1060 var url = gs.xsltParams.library_name + "/collection/" + gs.cgiParams.c + "/browse/" + sectionID.replace(/\./g, "/") + "?excerptid=div" + sectionID;
1061
1062 if(gs.cgiParams.berrybasket == "on")
1063 {
1064 url = url + "&berrybasket=on";
1065 }
1066
1067 if(url.indexOf("#") != -1)
1068 {
1069 url = url.substring(0, url.indexOf("#"));
1070 }
1071
1072 $.ajax(url)
1073 .success(function(responseText)
1074 {
1075 var newDiv = $("<div>");
1076 var sibling = gs.jqGet("title" + sectionID);
1077 sibling.after(newDiv);
1078
1079 newDiv.html(responseText);
1080 sectionToggle.attr("src", gs.imageURLs.collapse);
1081 openClassifiers[sectionID] = true;
1082
1083 if(gs.cgiParams.berrybasket == "on")
1084 {
1085 checkout();
1086 }
1087 /*else if(gs.cgiParams.documentbasket == "on") // TODO: copied from classifier_scripts.js - should this else block be included here (and happen when mapEnabled) or not?
1088 {
1089 dmcheckout();
1090 }*/
1091 updateOpenClassifiers();
1092 getSubClassifier(sectionID);
1093 })
1094 .error(function()
1095 {
1096 sectionToggle.attr("src", gs.imageURLs.expand);
1097 })
1098 .complete(function()
1099 {
1100 inProgress[sectionID] = false;
1101 busy = false;
1102 });
1103 }
1104 }
1105}
Note: See TracBrowser for help on using the repository browser.