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

Last change on this file since 32607 was 32607, checked in by kjdon, 5 years ago

fixed a bug where the paris photos in gps tutorial wouldn't show up in document view. I think its something to do with the size of the bounds that we are trying to fit the map to. using a single point as bounds. works for hamilton gardens locations, but not paris. to do with availability of photos?? not sure. anyway, if we only have a single point on the map, center on that point and set zoom rather than fit bounds to that point. also tidied up a bit of code - can use bounds.extend with lat/long rather than trying to calculate sw/ne ourselves.

  • Property svn:executable set to *
File size: 18.5 KB
Line 
1var _docList = new Array();
2_docList.ids = new Array();
3_docList.getDocByIndex = function(index)
4{
5 return _docList[_docList.ids[index]];
6};
7
8var _map;
9var _intervalHandle;
10var _baseURL = document.URL.substring(0, document.URL.indexOf("?") + 1);
11var _retrievedClassifiers = new Array();
12var _preventLoopingSingleMarker = false;
13var _searchRunning = false;
14var _nearbyDocs = new Array();
15var _scrollThroughDefault = true;
16
17function initializeMapScripts()
18{
19 modifyFunctions();
20 setUpMap();
21
22 var jsonNodeDiv = $("#jsonNodes");
23 if(jsonNodeDiv.length)
24 {
25 var jsonNodes = eval(jsonNodeDiv.html());
26 if(jsonNodes && jsonNodes.length > 0)
27 {
28 for(var i = 0; i < jsonNodes.length; i++)
29 {
30 _docList[jsonNodes[i].nodeID] = jsonNodes[i];
31 _docList.ids.push(jsonNodes[i].nodeID);
32 createMarker(jsonNodes[i], true);
33 }
34 updateMap();
35 }
36 else
37 {
38 //$("#map_canvas").css({visibility:"hidden", height:"0px"});
39 $("#map_canvas").css({visibility:"hidden"});
40 }
41 }
42
43 _docList.loopIndex = 0;
44
45 if(_docList.ids.length > 1)
46 {
47 var startStopCheckbox = $("<input>", {"type": "checkbox", "checked": _scrollThroughDefault, "id": "scrollCheckbox"});
48 startStopCheckbox.click(function()
49 {
50 // http://stackoverflow.com/questions/901712/how-to-check-if-a-checkbox-is-checked-in-jquery
51 // http://stackoverflow.com/questions/5270689/attrchecked-checked-does-not-work
52
53 if($('#scrollCheckbox').is(':checked')) // OR: if(document.getElementById('scrollCheckbox').checked)
54 {
55 if(_intervalHandle == null)
56 {
57 _intervalHandle = setInterval(loopThroughMarkers, 2000);
58 }
59 }
60 else
61 {
62 clearInterval(_intervalHandle);
63 _intervalHandle = null;
64 }
65 });
66
67 var label = $("<span>Scroll through places</span>");
68 var container = $("<div>", {"class": "ui-widget-header ui-corner-all", "style": "clear:right; float:right; padding:0px 5px 3px 0px;"});
69 container.append(startStopCheckbox);
70 container.append(label);
71
72 $(container).insertAfter("#map_canvas");
73
74 if (_scrollThroughDefault) {
75 _intervalHandle = setInterval(loopThroughMarkers, 2000);
76 }
77
78 }
79}
80
81function setUpMap()
82{
83 var myOptions =
84 {
85 zoom: 2,
86 center: new google.maps.LatLng(0, 0),
87 mapTypeId: google.maps.MapTypeId.HYBRID
88 };
89 _map = new google.maps.Map($("#map_canvas")[0], myOptions);
90 google.maps.event.addListener(_map, 'bounds_changed', performSearchForMarkers);
91}
92
93function performSearchForMarkers()
94{
95 if(_searchRunning)
96 {
97 return;
98 }
99
100 _searchRunning = true;
101
102 var bounds = _map.getBounds();
103
104 var neLat = bounds.getNorthEast().lat();
105 var neLng = bounds.getNorthEast().lng();
106 var swLat = bounds.getSouthWest().lat();
107 var swLng = bounds.getSouthWest().lng();
108
109 var latDistance = neLat - swLat;
110 var lngDistance = neLng - swLng;
111
112 //Check which increment to use for latitude (i.e. 0.001, 0.01, 0.1 or 1 degree increments)
113 var latDelta;
114 var latPrecision;
115 for(var i = 3; i >= 0; i--)
116 {
117 latDelta = (1 / Math.pow(10, i));
118 if((latDistance / latDelta) <= 5 || latDelta == 1)
119 {
120 latPrecision = i;
121 break;
122 }
123 }
124
125 //Check which increment to use for longitude (i.e. 0.001, 0.01, 0.1 or 1 degree increments)
126 var lngDelta;
127 for(var i = 3; i >= 0; i--)
128 {
129 lngDelta = (1 / Math.pow(10, i));
130 if((lngDistance / lngDelta) <= 5 || lngDelta == 1)
131 {
132 lngPrecision = i;
133 break;
134 }
135 }
136
137 if(latDelta == 0.1){latDelta = 1; latPrecision = 0; }
138 if(lngDelta == 0.1){lngDelta = 1; lngPrecision = 0; }
139
140 var query = "";
141 for(var i = 0; i <= Math.floor(latDistance / latDelta) + 1; i++)
142 {
143 for(var j = 0; j <= Math.floor(lngDistance / lngDelta) + 1; j++)
144 {
145 //Some necessary variables
146 var newLat = neLat - (latDelta * i);
147 var newLatString = "" + newLat;
148 var newLatTrunc;
149 if(newLat < 0){newLatTrunc = Math.ceil(newLat);}
150 else{newLatTrunc = Math.floor(newLat);}
151
152 var newLng = neLng - (lngDelta * j);
153 var newLngString = "" + newLng;
154 var newLngTrunc;
155 if(newLng < 0){newLngTrunc = Math.ceil(newLng);}
156 else{newLngTrunc = Math.floor(newLng);}
157
158 //Construct query
159 query += "(";
160 query += "LA:" + coordToAbsDirected(newLatTrunc, "lat");
161 if(latDelta != 1)
162 {
163 query += "+AND+";
164 query += "LA:" + newLatString.substring(newLatString.indexOf(".") + 1, newLatString.indexOf(".") + latPrecision + 1);
165 }
166 query += "+AND+";
167 query += "LN:" + coordToAbsDirected(newLngTrunc, "lng");
168 if(lngDelta != 1)
169 {
170 query += "+AND+";
171 query += "LN:" + newLngString.substring(newLngString.indexOf(".") + 1, newLngString.indexOf(".") + lngPrecision + 1);
172 }
173 query += ")";
174
175 if(i != (Math.floor(latDistance / latDelta) + 1) || j != (Math.floor(lngDistance / lngDelta) + 1)){ query += "+OR+"; }
176 }
177 }
178
179 //var url = gs.xsltParams.library_name + "?a=q&s=RawQuery&rt=rd&c=" + gs.cgiParams.c + "&s1.rawquery=" + query + "&excerptid=jsonNodes";
180 var url = gs.xsltParams.library_name;
181 var data = "a=q&s=RawQuery&rt=rd&c=" + gs.cgiParams.c + "&s1.rawquery=" + query + "&excerptid=jsonNodes";
182 $.ajax({type:"POST", url:url, data:data})
183 .success(function(responseText)
184 {
185 //console.log("*** responseText (first 250) = " + responseText.substring(0,256));
186
187 if(responseText.search("id=\"jsonNodes") != -1)
188 {
189 var startIndex = responseText.indexOf(">");
190 var endIndex = responseText.indexOf("</");
191
192 var jsonNodes = eval(responseText.substring(startIndex+1, endIndex));
193 if(jsonNodes && jsonNodes.length > 0)
194 {
195 for(var i = 0; i < jsonNodes.length; i++)
196 {
197 var doc = jsonNodes[i];
198
199 var found = false;
200 for(var j = 0; j < _docList.ids.length; j++){if(doc.nodeID == _docList.ids[j]){found = true; break;}}
201
202 if(!found)
203 {
204 _docList[doc.nodeID] = doc;
205 _docList.ids.push(doc.nodeID);
206
207 createMarker(doc, false);
208 }
209 }
210 }
211 }
212 else
213 {
214 console.log("No JSON information received");
215 }
216
217 _searchRunning = false;
218 }).fail(function(responseText, textStatus, errorThrown) // fail() has replaced error(), http://api.jquery.com/jquery.ajax/
219 {
220 console.log("In map-scripts.performSearchForMarkers(): Got an error in ajax call");
221 _searchRunning = false;
222 });
223}
224
225function coordToAbsDirected(coord, type)
226{
227 var value = "" + coord;
228 if(coord < 0)
229 {
230 value = value.substring(1);
231 if(type == "lat")
232 {
233 value += "S";
234 }
235 else
236 {
237 value += "W";
238 }
239 }
240 else
241 {
242 if(type == "lat")
243 {
244 value += "N";
245 }
246 else
247 {
248 value += "E";
249 }
250 }
251
252 return value;
253}
254
255function updateMap()
256{
257 var markersOnMap = 0;
258 var bounds = new google.maps.LatLngBounds();
259 for(var i = 0; i < _docList.ids.length; i++)
260 {
261 var doc = _docList.getDocByIndex(i);
262 if(doc.parentCL && doc.parentCL.style.display == "none")
263 {
264 doc.marker.setVisible(false);
265 continue;
266 }
267 else
268 {
269 doc.marker.setVisible(true);
270 markersOnMap++;
271 }
272
273 bounds.extend(new google.maps.LatLng(doc.lat, doc.lng));
274 }
275
276 if(markersOnMap > 1)
277 {
278 _map.fitBounds(bounds);
279 } else if (markersOnMap == 1) {
280 // sometimes a single point bounds are too small for the map to display, so use center and zoom instead of fitbounds.
281 _map.setCenter(bounds.getCenter());
282 _map.setZoom(18); // arbitrary value that looked nice for my example
283 }
284}
285
286function loopThroughMarkers()
287{
288 if(_docList.ids.length == 0)
289 {
290 return;
291 }
292
293 var visibleMarkers = new Array();
294 for(var i = 0; i < _docList.ids.length; i++)
295 {
296 var doc = _docList.getDocByIndex(i);
297 if(doc.marker.getVisible())
298 {
299 visibleMarkers.push(doc);
300 }
301 }
302
303 if(visibleMarkers.length < 2)
304 {
305 clearAllInfoBoxes();
306 return;
307 }
308
309 clearAllInfoBoxes();
310
311 var elem = null;
312 while(!elem)
313 {
314 if(_docList.loopIndex >= visibleMarkers.length)
315 {
316 _docList.loopIndex = 0;
317 }
318
319 var doc = visibleMarkers[_docList.loopIndex];
320 var elem = gs.jqGet("div" + doc.nodeID);
321 if(elem.length)
322 {
323 elem.css("background", "#BBFFBB");
324 setTimeout(function(){elem.css("background", "");}, 2000);
325 }
326 _docList.loopIndex++;
327 }
328 doc.marker.markerInfo.open(_map, doc.marker);
329}
330
331function attachClickHandler(marker, nodeID)
332{
333 google.maps.event.addListener(marker, 'click', function()
334 {
335 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";
336 });
337}
338
339function focusDocument(id)
340{
341 var doc = _docList[id];
342 if(doc)
343 {
344 clearInterval(_intervalHandle);
345 _intervalHandle = null;
346 _map.panTo(new google.maps.LatLng(doc.lat, doc.lng));
347 clearAllInfoBoxes();
348 doc.marker.markerInfo.open(_map, doc.marker);
349 var scrollCheckbox = $("#scrollCheckbox");
350 if(scrollCheckbox.checked)
351 {
352 scrollCheckbox.checked = false;
353 }
354 }
355}
356
357function clearAllInfoBoxes()
358{
359 for(var i = 0; i < _docList.ids.length; i++)
360 {
361 var doc = _docList.getDocByIndex(i);
362 doc.marker.markerInfo.close();
363 }
364}
365
366function createMarker(doc, mainMarker)
367{
368 var pos = new google.maps.LatLng(doc.lat,doc.lng);
369 var marker
370 if(mainMarker)
371 {
372 marker = new google.maps.Marker
373 ({
374 position: pos,
375 title:doc.title,
376 map:_map
377 });
378 }
379 else
380 {
381 marker = new google.maps.Marker
382 ({
383 position: pos,
384 title:doc.title,
385 map:_map,
386 icon:"interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png"
387 });
388 }
389
390 var docElement = gs.jqGet("div" + doc.nodeID);
391 var parent;
392 if(docElement)
393 {
394 parent = docElement.parentNode;
395 }
396
397 while(parent && parent.nodeName != "BODY")
398 {
399 if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
400 {
401 doc.parentCL = parent;
402 break;
403 }
404
405 parent = parent.parentNode;
406 }
407
408 var info = new google.maps.InfoWindow({content:doc.title});
409 marker.markerInfo = info;
410 doc.marker = marker;
411 attachClickHandler(marker, doc.nodeID);
412}
413
414function getSubClassifier(sectionID)
415{
416 var url = gs.xsltParams.library_name + "?a=b&rt=s&s=ClassifierBrowse&c=" + gs.cgiParams.c + "&cl=" + sectionID + "&excerptid=jsonNodes";
417 $.ajax(url)
418 .success(function(responseText)
419 {
420 var startIndex = responseText.indexOf(">");
421 var endIndex = responseText.indexOf("</");
422
423 var jsonNodes = eval(responseText.substring(startIndex+1, endIndex));
424 if(jsonNodes && jsonNodes.length > 0)
425 {
426 for(var i = 0; i < jsonNodes.length; i++)
427 {
428 var doc = jsonNodes[i];
429 _docList[doc.nodeID] = doc;
430 _docList.ids.push(doc.nodeID);
431
432 createMarker(doc, false);
433 }
434
435 $("#map_canvas").css({"visibility": "visible", "height": ""});
436 }
437
438 updateMap();
439 })
440 .error(function()
441 {
442 console.log("Error getting subclassifiers");
443 return;
444 });
445}
446
447function performDistanceSearch(id, lat, lng, degrees)
448{
449 if(parseFloat(lat) > 180 || parseFloat(lat) < -180 || parseFloat(lng) > 180 || parseFloat(lat) < -180)
450 {
451 console.log("Latitude or longitude incorrectly formatted");
452 return;
453 }
454
455 if(lat.indexOf(".") == -1 || lng.indexOf(".") == -1 || (lat.indexOf(".") + 3) >= lat.length || (lng.indexOf(".") + 3) >= lng.length)
456 {
457 console.log("Latitude or longitude does not have the required precision for a distance search");
458 return;
459 }
460
461 var query = "";
462 for(var i = 0; i < degrees * 2; i++)
463 {
464 for (var j = 0; j < degrees * 2; j++)
465 {
466 var latDelta = (i - degrees) * 0.01;
467 var lngDelta = (j - degrees) * 0.01;
468
469 query += "(" + getDistanceQueryString(lat, latDelta, 2, "LA", ["N","S"]);
470 query += "+AND+";
471 query += getDistanceQueryString(lng, lngDelta, 2, "LN", ["E","W"]) + ")";
472
473 if(i != ((degrees * 2) - 1) || j != ((degrees * 2) - 1)){ query += "+OR+"; }
474 }
475 }
476
477 var inlineTemplate = '\
478 <xsl:template match="/" priority="5">\
479 <table id="nearbyDocs">\
480 <tr>\
481 <th><a href="javascript:sortByDistance();">Distance (km)</a></th><th><a href="javascript:sortAlphabetically();">Document</a></th>\
482 </tr>\
483 <xsl:apply-templates select="//documentNode"/>\
484 </table>\
485 </xsl:template>\
486 \
487 <xsl:template match="documentNode" priority="5">\
488 <tr>\
489 <td>___<gsf:metadata name="Latitude"/>______<gsf:metadata name="Longitude"/>___</td>\
490 <td><gsf:link type="document"><gsf:metadata name="Title"/></gsf:link></td>\
491 </tr>\
492 </xsl:template>';
493
494 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");
495 $.ajax(url)
496 .success(function(response)
497 {
498 response = response.replace(/<img src="[^"]*map_marker.png"[^>]*>/g, "");
499
500 var nearbyDocsArray = new Array();
501
502 var lats = new Array();
503 var lngs = new Array();
504
505 var matches = response.match(/___(-?[0-9\.]*)___/g);
506 for(var i = 0; i < matches.length; i += 2)
507 {
508 var matchLatFloat = parseFloat(matches[i].replace("___", ""));
509 var matchLngFloat = parseFloat(matches[i+1].replace("___", ""));
510
511 lats.push(matchLatFloat);
512 lngs.push(matchLngFloat);
513
514 var distance = Math.sqrt(Math.pow(matchLatFloat - parseFloat(lat), 2) + Math.pow(matchLngFloat - parseFloat(lng), 2)) * (40000.0/360.0);
515 var distanceString = "" + distance;
516 distanceString = distanceString.substring(0, 6);
517
518 response = response.replace(matches[i] + matches[i+1], distanceString);
519 }
520
521 var index = 0;
522 var i = 0;
523 while(true)
524 {
525 var distanceStart = response.indexOf("<td>", index);
526 if(distanceStart == -1)
527 {
528 break;
529 }
530 var distanceEnd = response.indexOf("</td>", distanceStart);
531
532 var docLinkStart = response.indexOf("<td>", distanceEnd);
533 var docLinkEnd = response.indexOf("</td>", docLinkStart);
534
535 var dist = response.substring(distanceStart + 4, distanceEnd);
536 var docLink = response.substring(docLinkStart + 4, docLinkEnd);
537
538 _nearbyDocs.push({title:docLink, distance:dist, lat:lats[i], lng:lngs[i++]});
539
540 index = docLinkEnd;
541 }
542
543 sortByDistance();
544
545 var toggle = $("#nearbyDocumentsToggle");
546 toggle.attr("src", gs.imageURLs.collapse);
547 gs.functions.makeToggle(toggle, $("#nearbyDocuments"));
548 });
549}
550
551function sortByDistance()
552{
553 var sortedTable = '<table id="nearbyDocs"><tr><th><a href="javascript:;">Distance (km)</a></th><th><a href="javascript:sortAlphabetically();">Document</a></th></tr>';
554 _nearbyDocs.sort(function(a, b){return (a.distance - b.distance);});
555 for(var i = 0; i < _nearbyDocs.length; i++)
556 {
557 sortedTable += "<tr><td>" + _nearbyDocs[i].distance + '</td><td onmouseover="_map.setCenter(new google.maps.LatLng(' + _nearbyDocs[i].lat + ',' + _nearbyDocs[i].lng + '))">' + _nearbyDocs[i].title + "</td></tr>";
558 }
559 sortedTable += "</table>";
560
561 $("#nearbyDocuments").html(sortedTable);
562}
563
564function sortAlphabetically()
565{
566 var sortedTable = '<table id="nearbyDocs"><tr><th><a href="javascript:sortByDistance();">Distance (km)</a></th><th><a href="javascript:;">Document</a></th></tr>';
567 _nearbyDocs.sort(function(a, b)
568 {
569 var firstTitleStartIndex = a.title.indexOf(">");
570 var firstTitleEndIndex = a.title.indexOf("<", firstTitleStartIndex);
571 var firstTitle = a.title.substring(firstTitleStartIndex + 1, firstTitleEndIndex);
572 var secondTitleStartIndex = b.title.indexOf(">");
573 var secondTitleEndIndex = b.title.indexOf("<", secondTitleStartIndex);
574 var secondTitle = b.title.substring(secondTitleStartIndex + 1, secondTitleEndIndex);
575 return ((firstTitle.toLowerCase() == secondTitle.toLowerCase()) ? 0 : ((firstTitle.toLowerCase() > secondTitle.toLowerCase()) ? 1 : -1));
576 });
577 for(var i = 0; i < _nearbyDocs.length; i++)
578 {
579 sortedTable += "<tr><td>" + _nearbyDocs[i].distance + '</td><td onmouseover="_map.setCenter(new google.maps.LatLng(' + _nearbyDocs[i].lat + ',' + _nearbyDocs[i].lng + '))">' + _nearbyDocs[i].title + "</td></tr>";
580 }
581 sortedTable += "</table>";
582
583 $("#nearbyDocuments").html(sortedTable);
584}
585
586function getDistanceQueryString(currentCoord, delta, precision, indexName, dirs)
587{
588 var query = "";
589 var coordFloat = parseFloat(currentCoord);
590
591 var newCoord = "" + (coordFloat + delta);
592 var beforeDec = newCoord.substring(0, newCoord.indexOf("."));
593
594 var dir = dirs[0];
595 if(coordFloat < 0)
596 {
597 dir = dirs[1];
598 beforeDec = beforeDec.substring(1);
599 }
600 beforeDec += dir;
601
602 var afterDec = newCoord.substring(newCoord.indexOf(".") + 1, newCoord.indexOf(".") + (precision) + 1);
603
604 return indexName + ":" + beforeDec + "+AND+" + indexName + ":" + afterDec;
605}
606
607function modifyFunctions()
608{
609 toggleSection = function(sectionID)
610 {
611 var section = gs.jqGet("div" + sectionID);
612 var sectionToggle = gs.jqGet("toggle" + sectionID);
613
614 if(sectionToggle == undefined)
615 {
616 return;
617 }
618
619 // Test if 'section' exists.
620 // ==> Because we're using jQuery to do this we need to test the length of the object returned
621 // http://stackoverflow.com/questions/920236/how-can-i-detect-if-a-selector-returns-null
622 if(section.length !== 0)
623 {
624 if(isExpanded(sectionID))
625 {
626 section.css("display", "none");
627 sectionToggle.attr("src", gs.imageURLs.expand);
628
629 if(openClassifiers[sectionID].length !== 0) //if(openClassifiers[sectionID] != undefined)
630 {
631 delete openClassifiers[sectionID];
632 }
633 }
634 else
635 {
636 section.css("display", "block");
637 sectionToggle.attr("src", gs.imageURLs.collapse);
638 openClassifiers[sectionID] = true;
639 }
640 updateOpenClassifiers();
641 updateMap();
642 }
643 else
644 {
645 httpRequest(sectionID);
646 }
647 }
648
649 httpRequest = function(sectionID)
650 {
651 if(!inProgress[sectionID])
652 {
653 inProgress[sectionID] = true;
654
655 var sectionToggle = gs.jqGet("toggle" + sectionID);
656 sectionToggle.attr("src", gs.imageURLs.loading);
657
658 var url = gs.xsltParams.library_name + "/collection/" + gs.cgiParams.c + "/browse/" + sectionID.replace(/\./g, "/") + "?excerptid=div" + sectionID;
659
660 if(gs.cgiParams.berrybasket == "on")
661 {
662 url = url + "&berrybasket=on";
663 }
664
665 if(url.indexOf("#") != -1)
666 {
667 url = url.substring(0, url.indexOf("#"));
668 }
669
670 $.ajax(url)
671 .success(function(responseText)
672 {
673 var newDiv = $("<div>");
674 var sibling = gs.jqGet("title" + sectionID);
675 sibling.after(newDiv);
676
677 newDiv.html(responseText);
678 sectionToggle.attr("src", gs.imageURLs.collapse);
679 openClassifiers[sectionID] = true;
680
681 if(gs.cgiParams.berrybasket == "on")
682 {
683 checkout();
684 }
685 updateOpenClassifiers();
686 getSubClassifier(sectionID);
687 })
688 .error(function()
689 {
690 sectionToggle.attr("src", gs.imageURLs.expand);
691 })
692 .complete(function()
693 {
694 inProgress[sectionID] = false;
695 busy = false;
696 });
697 }
698 }
699}
Note: See TracBrowser for help on using the repository browser.