var app = app || {};
/**
* MapView
* @name app.MapView
* @class MapView
* @memberof app
*/
app.MapView = function() {
'use strict';
var self = this;
self.infoWindow = null;
self.currentLocation = null;
self.originalMapCenter = {lat: 36.1049534, lng: -115.1724043};
self.mapDiv = document.getElementById('map');
self.mapOptions = {
disableDefaultUI: true,
center: self.originalMapCenter,
zoom: 15,
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_TOP
}
};
self.preload = '<div class="preload">Loading...<div class="spin"></div></div>';
// Source: https://sites.google.com/site/gmapsdevelopment/
self.markerUrl = 'http://maps.google.com/mapfiles/ms/icons/';
self.markerColors = ['pink', 'blue', 'purple', 'green', 'yellow', 'red'];
self.bounds = new google.maps.LatLngBounds();
/**
* Displays a Google Map and adds resize event listener.
*
* @function app.MapView.init
* @memberof app.MapView
* @see {@link https://developers.google.com/maps/documentation/javascript/reference}
*/
self.initMap = function() {
// Create the map
self.map = new google.maps.Map(self.mapDiv, self.mapOptions);
// Create the info window that will be re-used by each marker
self.infoWindow = new google.maps.InfoWindow();
// Create the markers
self.createMarkers();
// Update center of the map on resize
google.maps.event.addDomListener(window, "resize", function() {
var center = self.map.getCenter();
google.maps.event.trigger(self.map, "resize");
self.map.setCenter(center);
});
}; // initMap
/**
* Creates map markers.
*
* @function app.MapView.createMarkers
* @memberof app.MapView
*/
self.createMarkers = function() {
var c = 0;
var hotel = {};
var allHotels = app.vm.getHotels();
var length = app.vm.getHotelsLength();
for (c; c < length; c++) {
hotel = allHotels[c];
// Marker color corresponds to diamond rating
hotel.color = self.markerColors[hotel.diamonds];
// Add hotel markers to the map
hotel.marker = new google.maps.Marker({
map: self.map,
position: hotel.location,
title: hotel.name,
animation: null,
visible: true,
icon: self.markerUrl + hotel.color + '.png'
}); // marker
// Extend the bounds
self.bounds.extend(new google.maps.LatLng(hotel.location));
// Setup the mark's infoWindow
self.setInfoWin(hotel);
} // for
// Adjust map to fit inside the marker bounds
self.map.fitBounds(self.bounds);
}; // createMarkers
/**
* Sets the animation and icon properties for the map marker.
*
* @function app.MapView.animateMarker
* @memberof app.MapView
*/
self.animateMarker = function(hotel) {
// Animate the marker
hotel.marker.setAnimation(google.maps.Animation.BOUNCE);
// Display the dot version of the marker
hotel.marker.icon = self.markerUrl + hotel.color + '-dot.png';
// Animate the marker for 2.1 seconds
setTimeout(function() {
hotel.marker.setAnimation(null);
hotel.marker.icon = self.markerUrl + hotel.color + '.png';
}, 2100);
}; // animateMarker
/**
* Gets the content or reads already set content for the infoWindow.
* Sets currentLocation, and creates a click event listener.
* Gets the hotel's recent tweets and inserts them into the page.
* Centers map on marker and pans map down on small screens.
*
* @function app.MapView.setInfoWin
* @memberof app.MapView
*/
self.setInfoWin = function(hotel) {
// Open the infoWindow when a marker is clicked
google.maps.event.addListener(hotel.marker, 'click', function() {
// Load Yelp and Twitter content
self.loadContent(hotel);
self.infoWindow.open(self.map, hotel.marker);
self.animateMarker(hotel);
self.currentLocation = hotel.location;
// Re-center the map on the marker that was clicked
self.map.setCenter(hotel.location);
// On small screens pan the map down 120px
if(window.screen.height > 400 && window.screen.width < 415) self.map.panBy(0, -120);
});
}; // setInfoWin
/**
* Make Yelp & Twitter API requests through a Promise
*
* @function app.MapView.loadContent
* @memberof app.MapView
*/
self.loadContent = function(hotel) {
var yelpParams = {
"hotel": hotel.id,
};
var twitterParams = {
"screen_name": hotel.twitter,
"count": 50
};
var yelpRequest;
var twitterRequest;
if(!hotel.content) {
// Show preload text inside the Info Window
self.infoWindow.setContent(self.preload);
// Send GET request to Yelp API
yelpRequest = getJSON('https://widgets.ws/yelp/api.php', {
method: 'GET',
apiquery: yelpParams,
})
.then(function (json) {
hotel.review = self.getYelpTemplate(hotel.name,
hotel.diamonds,
json[0].image_url,
json[1].reviews[0].text,
json[1].reviews[0].url);
self.infoWindow.setContent(hotel.review);
hotel.content = true;
return Promise.resolve('Yelp API Success');
})
.catch(function (error) {
hotel.content = null;
self.infoWindow.setContent('Error retrieving Yelp data.<br>Please try again.');
// Ref: https://medium.com/datafire-io/es6-promises-patterns-and-anti-patterns-bbb21a5d0918
return Promise.reject(new Error("Yelp API: " + error.status + " " + error.statusText));
});
} else
self.infoWindow.setContent(hotel.review);
if(!hotel.tweets) {
// Send GET request to Twitter API
twitterRequest = getJSON('https://widgets.ws/twitter/api.php', {
method: 'GET',
apiquery: twitterParams,
})
.then(function (json) {
hotel.tweets = self.getTweets(hotel, json);
self.displayTweets(hotel.tweets);
return Promise.resolve('Twitter API Success');
})
.catch(function (error) {
var url = 'https://twitter.com/' + hotel.twitter;
var msg = '<li><a href="' + url + '" target="_blank">Failed to load recent tweets for @';
msg += hotel.twitter + '. Click here to view tweets on twitter.com.</a></li>';
hotel.tweets = null;
self.displayTweets(msg);
return Promise.reject(new Error("Twitter API: " + error.status + " " + error.statusText));
});
} else
self.displayTweets(hotel.tweets);
// Track when all the API requests are complete using Promise.all and catch any errors
// Ref: http://adampaxton.com/handling-multiple-javascript-promises-even-if-some-fail/
Promise.all([yelpRequest, twitterRequest])
.then(function (res) {
if(window.console) console.log('GET request results', res);
})
.catch(function (err) {
if(window.console) console.error('GET request failed with', err);
});
}; // loadContent
/**
* Matches the icon to diamond rating and formats html for the hotel image and review snippet.
*
* @function app.MapView.getYelpTemplate
* @memberof app.MapView
* @returns {string} - HTML containing hotel name, diamond rating, image, and review.
*/
self.getYelpTemplate = function(name, diamonds, image, review, url) {
var i = 0;
var d = app.vm.getRatings();
var dlength = d.length;
var template = '';
var icon = '';
// Match the diamond rating to the icon text
for(i; i < dlength; i++) {
if(d[i].ratingValue === diamonds) {
icon = d[i].icon;
break;
}
}
template = '<h4>' + name + '</h4>';
template += '<i class="diamonds small">' + icon + '</i>';
template += '<div class="gm-info-container">';
template += ' <div class="gm-info-image"><img src="' + image + '" alt="' + name + '"></div>';
template += ' <div class="gm-info-text">';
template += '<img src="images/yelp_reviews.png" alt="Yelp Reviews"><br>';
template += review + ' <a href="' + url + '">read more</a>';
template += ' </div>';
template += '</div>';
return template;
}; // getYelpTemplate
/**
* Sends a GET request to api.php which accesses the Twitter API and returns JSON data.
*
* @function app.MapView.getTweets
* @memberof app.MapView
* @return {object} - JSON of the user's timeline
*/
self.getTweets = function(hotel, response) {
var tweets = '';
var length = response.length;
var t = 0;
var txt = '';
var img = '';
var id = '';
var url = 'https://twitter.com/' + hotel.twitter + '/status/';
// Limit to 5 tweets
if (length > 5) length = 5;
for(t; t < length; t++) {
id = response[t].id_str;
txt = response[t].text;
img = response[t].user.profile_image_url;
tweets += '<li class="tweet">';
tweets += '<a href="' + url + id + '" title="@' + hotel.twitter + '" target="_blank">';
tweets += '<img src="' + img + '" alt="@' + hotel.twitter + '"> ';
tweets += txt + '</a>';
tweets += '</li>';
} // for
return tweets;
}; // getTweets
/**
* Adds tweets inside the header above the map
*
* @function app.MapView.displayTweets
* @memberof app.MapView
*/
self.displayTweets = function(tweets) {
app.vm.showTicker(true);
app.vm.hotelTweets(tweets);
}; // displayTweets
}; // MapView