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

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

Bugfix to recently introduced bug: when there are bookshelves, suddenly the 33168 revision commit didn't display the map any more. This broke it for ImagesGPS' classifier display but also for our sectioned collection's classifier display. We still have issues with our classifier not showing all the correct maps and their bounds, but at least, the map shows again when a bookshelf has been opened.

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