source: other-projects/tipple-android/i-greenstone-server-files/greenstone/webapps/greenstone3/interfaces/default/js/map-scripts.js@ 26899

Last change on this file since 26899 was 26899, checked in by davidb, 11 years ago

Tipple reborn after Chris's Summer of Code 2013

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