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

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