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

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

Lower opacity for other documents that are nearby. Discovered broken code: Locations classifier in ImagesGPS no longer displays a map.

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