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

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