// Google Map
var map;
// markers for map
var markers = [];
// info window
var info = new google.maps.InfoWindow();
// execute when the DOM is fully loaded
$(function() {
// styles for map
// https://developers.google.com/maps/documentation/javascript/styling
var styles = [
// hide Google's labels
{
featureType: "all",
elementType: "labels",
stylers: [
{visibility: "off"}
]
},
// hide roads
{
featureType: "road",
elementType: "geometry",
stylers: [
{visibility: "off"}
]
}
];
// options for map
// https://developers.google.com/maps/documentation/javascript/reference#MapOptions
var options = {
center: {lat: 37.4236, lng: -122.1619}, // Stanford, California
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP,
maxZoom: 14,
panControl: true,
styles: styles,
zoom: 13,
zoomControl: true
};
// get DOM node in which map will be instantiated
var canvas = $("#map-canvas").get(0); //E: where is this "map-canvas" from? E: Answer= from "map-canvas" element on DOM tree, .
// instantiate map E: var myMap = new google.maps.Map(...); <- Every Map has a Data object by default, so most of the time there is no need to construct one.
//E: For example: myMap.data.addGeoJson(...); OR myMap.data.setStyle(...);
map = new google.maps.Map(canvas, options);
// configure UI once Google Map is idle (i.e., loaded)
google.maps.event.addListenerOnce(map, "idle", configure);
});
//E: question, does this mean, that the functions below are already functional, since they are not asked to listen for idle as per the line of code above this line?
/**
* Adds marker for place to map.
*/
function addMarker(place)
{
//TODO //E: to look at addMarker documentation provided in Pset8
//Z: instantiate marker(look into google.maps.Marker)
var myLatlng = new google.maps.LatLng(parseFloat(place.latitude), parseFloat(place.longitude));
var marker = new google.maps.Marker({
position: myLatlng,
// title: place.place_name + ", " + place.admin_name1, //<-- title key in this object, marker add a tool tip when mouse over.
label: place.place_name + ", " + place.admin_name1,
icon: {
url: 'https://maps.google.com/mapfiles/kml/pal2/icon31.png',
labelOrigin: new google.maps.Point(11,40)
// origin: new google.maps.Point(0,0),
// anchor: new google.maps.Point(11,40)
}
//anchorPoint: new google.maps.MarkerOptions.Point(0,32)
});
//-------------
//marker.setMap(map); <-- testing/removed this (to put it back if test doens't work)
function setMapOnAll(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
markers = setMapOnAll;
console.log(markers);
//--------------
//Z: listen for clicks on marker(look into google.maps.event.addListener)
//E: Once click is recieved, get articles, remember markers so we can remove them later
marker.addListener('click', function(){
//Z: Get articles for place(Look into $.getJSON)
var ulist = '<div id="articleList"><ul>';
//Z: build list of links to articles
//E: Get article list(in the form of JSON) from /article?geo= , (JSON is an array of dicts with keys: values)
$.getJSON(Flask.url_for("articles"), {geo:place.postal_code})
.done(function(data, textStatus, jqXHR) {
//put each article into the "articleList"
// for (var key in object) <-- java script for loop
$.each(data, function(each,article){
$('<li><a href=' + article.link + ' target="_blank">' + article.title + '</a>'+'</li>').appendTo('#articleList');
});
'</ul>'; //<-- E: do we need a, + '</div>'?
});
//show window on marker, using content in ulist
showInfo(marker, ulist );
});
//Z: remember marker (to remove all markers from the map/delete them. look into google maps API)
}
/**
* Configures application.
*/
function configure()
{
// update UI after map has been dragged
google.maps.event.addListener(map, "dragend", function() {
// if info window isn't open
// http://stackoverflow.com/a/12410385
if (!info.getMap || !info.getMap())
{
update();
}
});
// update UI after zoom level changes
google.maps.event.addListener(map, "zoom_changed", function() {
update();
});
// configure typeahead E: set, "options", and "datasets".
//E: When initializing a typeahead, there are a number of options you can configure, highlight:, hint: , minlength: ect. (see options in - https://github.com/corejavascript/typeahead.js/blob/master/doc/jquery_typeahead.md#options)
$("#q").typeahead({
highlight: false,
minLength: 1
},
{
//E: A typeahead is composed of one or more datasets. When an end-user modifies the value of a typeahead, each dataset will attempt to render suggestions for the new value.
//E: see datasets in - https://github.com/corejavascript/typeahead.js/blob/master/doc/jquery_typeahead.md#options
display: function(suggestion) { return null; },
limit: 10,
source: search,
templates: {
suggestion: Handlebars.compile(
"<div>" +
"{{place_name}}, {{admin_name1}}, {{postal_code}}" +
"</div>"
)
}
});
// re-center map after place is selected from drop-down
$("#q").on("typeahead:selected", function(eventObject, suggestion, name) {
// set map's center
map.setCenter({lat: parseFloat(suggestion.latitude), lng: parseFloat(suggestion.longitude)});
// update UI
update();
});
// hide info window when text box has focus
$("#q").focus(function(eventData) {
info.close();
});
// re-enable ctrl- and right-clicking (and thus Inspect Element) on Google Map
// https://chrome.google.com/webstore/detail/allow-right-click/hompjdfbfmmmgflfjdlnkohcplmboaeo?hl=en
document.addEventListener("contextmenu", function(event) {
event.returnValue = true;
event.stopPropagation && event.stopPropagation();
event.cancelBubble && event.cancelBubble();
}, true);
// update UI
update();
// give focus to text box
$("#q").focus();
}
/**
* Removes markers from map.
*/
function removeMarkers()
{
//TODO
//V1_done on 26 Dec 2017, latest update copied from
// clearMarkers();
// markers = [];
//V2_remove marker from markers
// for (var i = 0, n = markers.length; i < n; i++)
// {
// markers[i].setMap(null);
// }
// // reset length to 0
// markers.length = 0;
}
/**
* Searches database for typeahead's suggestions.
*/
function search(query, syncResults, asyncResults) //E: have trouble understanding this
{
// get places matching query (asynchronously)
var parameters = {
q: query
};
$.getJSON(Flask.url_for("search"), parameters)
.done(function(data, textStatus, jqXHR) {
// call typeahead's callback with search results (i.e., places)
asyncResults(data);
})
.fail(function(jqXHR, textStatus, errorThrown) {
// log error to browser's console
console.log(errorThrown.toString());
// call typeahead's callback with no results
asyncResults([]);
});
}
/**
* Shows info window at marker with content.
*/
function showInfo(marker, content)
{
// start div
var div = "<div id='info'>";
if (typeof(content) == "undefined")
{
// http://www.ajaxload.info/
div += "<img alt='loading' src='/static/ajax-loader.gif'/>";
}
else
{
div += content;
}
// end div
div += "</div>";
// set info window's content
info.setContent(div);
// open info window (if not already open)
info.open(map, marker);
}
/**
* Updates UI's markers.
*/
function update() //E: trouble understanding this
{
// get map's bounds
var bounds = map.getBounds();
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
// get places within bounds (asynchronously)
var parameters = {
ne: ne.lat() + "," + ne.lng(),
q: $("#q").val(),
sw: sw.lat() + "," + sw.lng()
};
$.getJSON(Flask.url_for("update"), parameters)
.done(function(data, textStatus, jqXHR) {
// remove old markers from map
removeMarkers();
// add new markers to map
for (var i = 0; i < data.length; i++)
{
addMarker(data[i]);
}
})
.fail(function(jqXHR, textStatus, errorThrown) {
// log error to browser's console
console.log(errorThrown.toString());
});
};
[code edited away to avoid spoilers]