Created
June 14, 2017 19:28
-
-
Save llakewood/41812981ce38311c08dcecb4ee5b683e to your computer and use it in GitHub Desktop.
Google Maps JavaScript (Beer Finder)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint browser: true */ | |
/*global $, jQuery, alert, console, gcMap:true */ | |
var console = console || { log: function() { 'use strict'; } }; // jshint ignore:line | |
var APIKEY = 'AIzaSyCjOhYTFNQIGg2mIITJITOPc1WI6OSXTdM'; | |
window.gcMap = window.gcMap || {}; | |
(function($) { | |
// all Javascript code goes here | |
'use strict'; | |
$.App = function () { | |
return { | |
init : function () { | |
try { | |
//On init, place user at brewery/HQ until geolocate is accepted, or location is searched | |
var init = true; | |
gcMap.App().geocode(jQuery('#sf_hq_address').val(), init); | |
jQuery('#sf_map_search_my_location').click(function(){ | |
gcMap.App().geolocate(init); | |
}); | |
jQuery('#sf_map_search_button').click(function(){ | |
gcMap.App().toggleAlert(); | |
gcMap.App().geocode(jQuery('#sf_map_seach_location').val(), false); | |
}); | |
jQuery('#sf_map_seach_location').keypress(function(e) { | |
if(e.which == 13) { | |
gcMap.App().geocode(jQuery('#sf_map_seach_location').val(), false); | |
} | |
}); | |
} catch(err) { | |
console.log('Map did not load: ' + err); | |
} | |
}, | |
/* gcMap.App().geolocate(); | |
* Checks for HTML5 capabilities, fallback to Google Geolocation */ | |
geolocate : function(init) { | |
//Set Brewer/HQ Location | |
gcMap.App().geocode(jQuery('#sf_hq_address').val(), init); | |
//Perform a location lookup | |
var sf_location = jQuery('#sf_map_seach_location'); | |
if ("geolocation" in navigator) { | |
//If HTML5 GeoLocation | |
navigator.geolocation.getCurrentPosition(function(position) { | |
sf_location.val([position.coords.latitude, position.coords.longitude]); | |
gcMap.App().geocode(sf_location.val()); | |
}); | |
} else { | |
var url = 'https://www.googleapis.com/geolocation/v1/geolocate?key='+APIKEY; | |
var jqxhr = jQuery.get( url , function(data) { | |
sf_location.val(data); | |
gcMap.App().geocode(sf_location.val()); | |
}); | |
} | |
}, | |
/* gcMap.App().geocode(); | |
* Uses Google Geolcode service to translate address to geocorodinates */ | |
geocode : function(sf_location, init = false) { | |
if(!init) { | |
gcMap.App().animateOut(); | |
} | |
switch(typeof sf_location) { | |
case 'object': | |
gcMap.App().wp_prepDom(sf_location.results[0].formatted_address); | |
break; | |
case 'string': | |
sf_location = sf_location.split(' '); | |
sf_location = sf_location.join('+'); | |
try { | |
var url = 'https://maps.googleapis.com/maps/api/geocode/json?address='+sf_location+'&key='+APIKEY; | |
var jqxhr = jQuery.get( url, function(data) { | |
if(init === true) { | |
gcMap.App().updateOriginLocation(data, init); | |
return; | |
} | |
var address = data.results[0].formatted_address; | |
var addressParts = data.results[0].address_components; | |
gcMap.App().wp_prepDom([address, addressParts]); | |
}); | |
} | |
catch(e) { | |
gcMap.App().toggleAlert(); | |
} | |
break; | |
} | |
}, | |
toggleAlert: function () { | |
jQuery("#productFinder #sf_filters .alert").toggleClass('alert--hide').toggleClass('alert--show'); | |
}, | |
/* gcMap.App().wp_prepDom(); | |
Communicates with spirit_finder.php to build window.productFinder | |
*/ | |
wp_prepDom :function (data) { | |
var vars = { | |
'action': 'prepDomAction', | |
'location': data | |
}; | |
jQuery.post(ajaxurl, vars, function(data) { | |
try { | |
jQuery("#productFinder #sf_filters .alert").addClass('alert--hide').removeClass('alert--show'); | |
data = data.replace(']}{"0":[',','); | |
var jsonLocations = jQuery.parseJSON(data), | |
lcboTemp = jsonLocations['loc'], | |
vendorTemp = jsonLocations['0'], | |
objTemp = { | |
'loc': jQuery.extend([], lcboTemp, vendorTemp) | |
}; | |
window.productFinder = objTemp; | |
gcMap.App().updateOriginLocation(objTemp); | |
} | |
catch(e) { | |
gcMap.App().toggleAlert(); | |
} | |
}); | |
}, | |
/* gcMap.App().animateOut(); | |
* Distract the user while operations are carried out */ | |
animateOut : function() { | |
jQuery('#sf_cover_up').addClass('do'); | |
var info_cards = document.getElementById('sf_info_cards'); | |
while(info_cards.firstChild) { | |
info_cards.removeChild(info_cards.firstChild); | |
} | |
}, | |
/* gcMap.App().animateIn(); | |
* Update map and tiles and filters */ | |
animateIn : function() { | |
jQuery('#sf_cover_up').removeClass('do'); | |
}, | |
/* gcMap.App().updateOriginLocation(); | |
* Send Callback data to clear and redraw */ | |
updateOriginLocation :function (locationsByDistance, init = false) { | |
var origin = ( init ? '#sf_hq_address' : '#sf_map_seach_location' ); | |
origin = jQuery(origin).val(); | |
var url = 'https://maps.googleapis.com/maps/api/geocode/json?address='+origin+'&key='+APIKEY; | |
var jqxhr = jQuery.get( url, function(data) { | |
if( init ) { | |
gcMap.App().drawCards(locationsByDistance, init); | |
} | |
gcMap.App().drawMap( | |
data.results[0].geometry.location.lat, | |
data.results[0].geometry.location.lng, | |
init | |
); | |
}); | |
}, | |
/* gcMap.App().drawMap(); | |
* Draws a map, set styles, trigger marker placement */ | |
drawMap : function(gcLat, gcLng, init = false) { | |
var mapDiv, | |
draggableScrollable = false, | |
map, | |
zoomLevel = jQuery(document).width() >= 1200 ? 14 : 12; | |
draggableScrollable = jQuery(document).width() > 1024 ? true : false; | |
mapDiv = document.getElementById('sf_map'); | |
map = new google.maps.Map(mapDiv, { | |
draggable: draggableScrollable, | |
scrollwheel: draggableScrollable, | |
center: {lat: gcLat, lng: gcLng}, | |
mapTypeControl: false, | |
streetViewControl: false | |
}); | |
//Make it pretty | |
gcMap.App().setStyles(map); | |
//call createLocations, pass HQ coords if init is true | |
(init ? gcMap.App().createLocations(map, gcLat, gcLng) : gcMap.App().createLocations(map)); | |
}, | |
/* | |
gcMap.App().createLocations(); | |
is Init (based on gcLang truthy)? - Load HQ location | |
else - Use window.location to calculate distances by origin, | |
build new window.locSorted object to build location card and marker | |
called in drawMap, recieves map object and geolocated origin | |
*/ | |
createLocations : function (map, gcLat = false, gcLng = false) { | |
window.productFinder.locSorted = {}; | |
window.productFinder.locSorted.loc = {}; | |
//Set map bounds | |
var bounds = new google.maps.LatLngBounds(); | |
var finishUp = false; | |
//If non-init, loop from window object, else show HQ | |
if(!gcLat) { | |
var locations = window.productFinder.loc, | |
locationCount = Object.keys(locations).length, | |
limit = 100, | |
newSortArr = []; | |
//Distance Matrix errors OVER_LIMIT at 100 queries | |
if(locationCount >= 100) { | |
locations = locations.slice(0, limit); | |
locationCount = 100; | |
} | |
var seachAddress = jQuery('#sf_map_seach_location').val(); | |
var origin = ( seachAddress ? seachAddress : jQuery("#sf_hq_address").val() ); | |
//Loop through locations array, process and sort via distance matrix | |
jQuery.each(locations, function( index, location ) { | |
var destination = new google.maps.LatLng(location.latitude, location.longitude), | |
_id = location._id, | |
locDist, | |
locId; | |
// Distance Calculations | |
// Two functions: | |
// 1. populate array with distance from orgin values | |
// 2. doMarker for sortedArray items | |
var matrixResponse = calculateDistances([origin],[destination]) | |
.done(function(response) { | |
var origins = response.originAddresses; | |
for (var i = 0; i < origins.length; i++) { | |
var results = response.rows[i].elements; | |
for (var j = 0; j < results.length; j++) { | |
if(response.rows[0].elements[0].status === "OK") { | |
newSortArr.push([ | |
index, | |
response.rows[0].elements[0].distance.value | |
]); | |
} else { | |
newSortArr.push([index, 0]); | |
} | |
} | |
} | |
}) | |
.done(function(response) { | |
// 2. doMarker() on distace sorted array | |
if(locationCount === index + 1) { | |
var sorted = newSortArr.sort(function(a, b) { | |
return a[1] - b[1]; | |
}); | |
//Sort array, make new window object | |
jQuery.each(sorted, function( i, distance ) { | |
locDist = sorted[i][1]; | |
locId = sorted[i][0]; | |
if(0 < parseInt(locDist,10)) { | |
window.productFinder.locSorted.loc[i] = locations[locId]; | |
} | |
}); | |
var sliced = window.productFinder.locSorted.loc; | |
//Draw the cards based on this sorted object | |
gcMap.App().drawCards(sliced, false); | |
//Sort array, put distance in object, doMarker() | |
jQuery.each(sliced, function( i, distance ) { | |
locDist = sorted[i][1]; | |
locId = sorted[i][0]; | |
locations[locId].distance_in_meters = locDist; | |
gcMap.App().doMarker( | |
map, | |
bounds, | |
locations[locId].latitude, | |
locations[locId].longitude, | |
locations[locId], | |
i | |
); | |
} | |
); | |
//Fit map to all markers | |
map.fitBounds(bounds); | |
google.maps.event.addListener( | |
map, | |
'click', | |
map.fitBounds(bounds) | |
); | |
} | |
}); | |
gcMap.App().animateIn(); | |
}); | |
function calculateDistances(origins, destinations) { | |
var service = new google.maps.DistanceMatrixService(); | |
var d = jQuery.Deferred(); | |
service.getDistanceMatrix({ | |
origins: origins, | |
destinations: destinations, | |
travelMode: google.maps.TravelMode.DRIVING, | |
unitSystem: google.maps.UnitSystem.METRIC, | |
avoidHighways: false, | |
avoidTolls: true | |
}, | |
function(response, status){ | |
if (status != google.maps.DistanceMatrixStatus.OK) { | |
d.reject(status); | |
} else { | |
d.resolve(response); | |
} | |
}); | |
return d.promise(); | |
} | |
} else { | |
var hq = { | |
'address' : jQuery("#sf_hq_address").val(), | |
'hours' : jQuery("#sf_hq_hours").val(), | |
'phone' : jQuery("#sf_hq_phone").val(), | |
'name' : jQuery("#sf_brewer").val(), | |
'type' : 'brewer', | |
'_id' : 'brewer' | |
}; | |
//marker(hq.lat, hq.lng, hq); | |
gcMap.App().doMarker(map, bounds, gcLat, gcLng, hq); | |
//center and zoom out | |
var latLng = new google.maps.LatLng(gcLat, gcLng); | |
map.setCenter(latLng); | |
map.setZoom(8); | |
} | |
}, | |
/* gcMap.App().drawCards(); | |
* Draw the cards - called from createLocation() */ | |
drawCards : function(locations, init = false) { | |
if(!init) { | |
locations = (locations.loc ? locations.loc : locations); | |
var cardMarkup; | |
jQuery.each(locations, function( i, value ) { | |
cardMarkup = '<div id="marker_'+value._id+'" class="location item '+ value.type + (i === '0' ? ' active' : '') + '" data-type="'+ value.type +'">'; | |
cardMarkup += '<span class="icon '+value.type+'"></span>'; | |
cardMarkup += '<div class="cont">'; | |
cardMarkup += '<h3>'+value.name+'</h3>'; | |
cardMarkup += '<p class="address"> '+ value.address +', ' + value.city + '</p>'; | |
cardMarkup += '<ul class="bullet">'; | |
if(jQuery('#sf_map_seach_location').val() !== undefined) { cardMarkup += '<li class="directions active"><span></span></li>';} | |
if(value.telephone !== undefined) { cardMarkup += '<li class="phone"><span></span></li>';} | |
if(gcMap.App().hours(value) !== undefined) { cardMarkup += '<li class="hours"><span></span></li>';} | |
if(value.url !== undefined) { cardMarkup += '<li class="url"><span></span></li>';} | |
cardMarkup += '</ul>'; | |
cardMarkup += '<ul class="text">'; | |
if(jQuery('#sf_map_seach_location').val() !== undefined) { cardMarkup += '<li class="directions active"><a class="button directions" href="https://www.google.ca/maps/dir/'+ jQuery('#sf_map_seach_location').val() +'/'+ value.address +'+'+ value.city +'/">Get Directions</a></li>';} | |
if(value.telephone !== undefined) { cardMarkup += '<li class="phone fa"><p><a href="tel:' + value.telephone + '"> ' + value.telephone + '</a></p></li>';} | |
if(gcMap.App().hours(value) !== undefined) { cardMarkup += '<li class="hours fa"><p>' + gcMap.App().hours(value) + '</p></li>';} | |
if(value.url !== undefined) { cardMarkup += '<li class="url" title=""><p>' + value.url + '</p></li>'; } | |
cardMarkup += '</ul>'; | |
cardMarkup += '</div>'; | |
cardMarkup += '</div>'; | |
// cardMarkup += '<p><span>Distance:</span> ' + parseFloat(value.distance_in_meters/1000).toFixed(1) + 'km</p>'; | |
jQuery("#sf_info_cards").append(cardMarkup); | |
}); | |
jQuery('ul.bullet li').click(function() { | |
jQuery('ul.bullet li, ul.text li').removeClass('active'); | |
var this_node = jQuery(this); | |
var the_parent = this_node.parent().parent().parent().attr('id'); | |
var classes = this_node.attr("class"); | |
this_node.addClass('active'); | |
jQuery('#' + the_parent +' ul li.'+ classes).addClass('active'); | |
}); | |
} else { | |
var value = { | |
'name' : jQuery('#sf_brewer').val(), | |
'address' : jQuery('#sf_hq_address').val(), | |
'telephone' : jQuery('#sf_hq_phone').val(), | |
'hours' : jQuery('#sf_hq_hours').val() | |
} | |
cardMarkup = '<div id="marker_brewer" class="location item brewer" data-type="brewer">'; | |
cardMarkup += '<h3>'+value.name+'</h3>'; | |
cardMarkup += '<ul>'; | |
cardMarkup += '<li><span class="icon brewer"></span></li>'; | |
cardMarkup += '<li class="address"><span></span><p> '+ value.address + '</p></li>'; | |
cardMarkup += '<li class="hours"><span></span><p> '+ value.hours + '</p></li>'; | |
cardMarkup += '<li class="phone"><span></span><p> <a href="tel:' + value.telephone + '"> ' + value.telephone + '</a></p></li>'; | |
cardMarkup += '</ul>'; | |
cardMarkup += '</div>'; | |
gcMap.App().animateIn(); | |
jQuery("#sf_info_cards").append(cardMarkup); | |
gcMap.App().animateIn(); | |
} | |
}, | |
//Markup and bindings for EACH marker, looped below | |
doMarker : function(map, bounds, gcLat, gcLng, value, i = false) { | |
var url, | |
image = {}, | |
myLatLng, | |
marker, | |
iconPath = '/wp-content/plugins/spirit-finder/images/icons/', | |
content, | |
infoCardByMarkerId; | |
var markerCardLinkFn; | |
switch(value.type) { | |
case 'brewer': | |
image.url = iconPath + value.type + '-pin-active.png'; | |
break; | |
default: | |
image.url = iconPath + value.type + '-pin.png'; | |
} | |
myLatLng = new google.maps.LatLng(gcLat, gcLng); | |
marker = new google.maps.Marker({ | |
animation: google.maps.Animation.DROP, | |
position: myLatLng, | |
map: map, | |
title: value.name, | |
icon: image, | |
metadata: {type: value.type, id: value._id} | |
}); | |
if(i === '0') { | |
marker.setZIndex(1000); | |
marker.setIcon(iconPath + value.type + '-pin-active.png'); | |
} | |
bounds.extend(myLatLng); | |
//Not init/brewer - create info window s | |
if(value._id !== 'brewer') { | |
content = '<div id="content"><h1 id="firstHeading" class="firstHeading">' + value.name + '</h1></div>'; | |
/** | |
Marker / Card interactions | |
//card click: calls openWindowFn | |
//marker touch/click: calls openWindowFn, scroll cards | |
*/ | |
markerCardLinkFn = function() { | |
if(typeof window.productFinder.tempMarker == "object") { | |
window.productFinder.tempMarker.setZIndex(1); | |
window.productFinder.tempMarker.setIcon('/wp-content/plugins/spirit-finder/images/icons/' + window.productFinder.tempMarker.metadata.type + '-pin.png'); | |
window.productFinder.tempMarker.setZIndex(1); | |
} | |
window.productFinder.tempMarker = marker; | |
jQuery('#sf_info_cards .location').removeClass('active'); | |
jQuery('#sf_info_cards #marker_' + value._id + '.location').addClass('active'); | |
} | |
infoCardByMarkerId = jQuery('#sf_info_cards #marker_' + value._id); | |
/** Action: marker click | |
// - Calls openWindowFn() | |
// - Sets active marker | |
// - Scrolls to card | |
*/ | |
google.maps.event.addListener(marker, 'click', function() { | |
markerCardLinkFn(); | |
marker.setZIndex(100); | |
marker.setIcon('/wp-content/plugins/spirit-finder/images/icons/' + marker.metadata.type + '-pin-active.png'); | |
marker.setZIndex(1000); | |
jQuery('#sf_info_cards').animate({ | |
scrollTop: jQuery("#marker_" + marker.metadata.id).offset().top | |
}, 365); | |
}); | |
/** Action: card click | |
// - Calls openWindowFn() | |
// - change icon to active state */ | |
infoCardByMarkerId.click(function() { | |
markerCardLinkFn(); | |
marker.setZIndex(100); | |
marker.setIcon('/wp-content/plugins/spirit-finder/images/icons/' + marker.metadata.type + '-pin-active.png'); | |
marker.setZIndex(1000); | |
}); | |
} | |
}, | |
hours : function(l) { | |
var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; | |
var hours = {}, | |
open, | |
close, | |
display = "Open today: "; | |
var d = new Date(), | |
now = days[d.getDay()], | |
hour, | |
mins, | |
h24, | |
h12, | |
time, | |
ampm; | |
switch(l.type) { | |
case 'beer': | |
break; | |
case 'lcbo': | |
switch(now) { | |
case "sunday": | |
hours.open = l.sunday_open; | |
hours.close = l.sunday_close; | |
break; | |
case "monday": | |
hours.open = l.monday_open; | |
hours.close = l.monday_close; | |
break; | |
case "tuesday": | |
hours.open = l.tuesday_open; | |
hours.close = l.tuesday_close; | |
break; | |
case "wednesday": | |
hours.open = l.wednesday_open; | |
hours.close = l.wednesday_close; | |
break; | |
case "thursday": | |
hours.open = l.thursday_open; | |
hours.close = l.thursday_close; | |
break; | |
case "friday": | |
hours.open = l.friday_open; | |
hours.close = l.friday_close; | |
break; | |
case "saturday": | |
hours.open = l.saturday_open; | |
hours.close = l.saturday_close; | |
break; | |
break; | |
} | |
function msmTo24time(msm) { | |
hour = msm / 60; | |
mins = msm % 60; | |
return [hour, mins]; | |
} | |
function msmTo12time(msm) { | |
time = msmTo24time(msm); | |
h24 = time[0]; | |
h12 = (0 == h24 ? 12 : (h24 > 12 ? (h24 - 10) - 2 : h24)); | |
ampm = (h24 >= 12 ? 'PM' : 'AM'); | |
if(h12 % 1 != 0) { | |
h12 = Math.trunc(h12); | |
} | |
if(time[1] === 0) { | |
time[1] = "00"; | |
} | |
return [h12 +':'+ time[1] +''+ ampm]; | |
} | |
open = msmTo12time(hours.open); | |
close = msmTo12time(hours.close); | |
display += open + '-' + close ; | |
return display; | |
break; | |
} | |
}, | |
setStyles : function(map) { | |
map.set('styles', [ | |
{ | |
stylers: [ | |
{ color: '#F5F5F5' } | |
] | |
}, { | |
featureType: "administrative", | |
elementType: 'labels', | |
stylers: [ | |
{ color: '#142B4C' }, | |
{ weight: 0.5 }, | |
] | |
}, { | |
featureType: 'road', | |
elementType: 'geometry', | |
stylers: [ | |
{ color: '#C3C6C9' }, | |
{ weight: 0.1 } | |
] | |
}, { | |
featureType: 'road.highway', | |
elementType: 'labels', | |
stylers: [ | |
{ "visibility": "off" }, | |
] | |
}, { | |
featureType: "road.highway", | |
elementType: "geometry", | |
stylers: [ | |
{ color: '#A7A9AC' }, | |
{ visibility: "on" } | |
] | |
}, { | |
featureType: "road.arterial", | |
elementType: "labels", | |
stylers: [ | |
{ visibility: "on" } | |
] | |
}, { | |
featureType: "road.local", | |
elementType: "labels", | |
stylers: [ | |
{ visibility: "off" } | |
] | |
}, { | |
featureType: "transit.line", | |
elementType: "geometry", | |
stylers: [ | |
{ "color": "#A7A9AC" }, | |
{ weight: 0.45 } | |
] | |
}, { | |
featureType: "poi", | |
elementType: "labels", | |
stylers: [ | |
{ visibility: "off" } | |
] | |
}, { | |
featureType: "administrative.neighborhood", | |
elementType: "labels", | |
stylers: [ | |
{ "visibility": "off" } | |
] | |
}, { | |
featureType: 'transit.station', | |
elementType: 'all', | |
stylers: [ | |
{ visibility: 'off' } | |
] | |
}, { | |
featureType: 'road', | |
elementType: 'labels', | |
stylers: [ | |
{ color: '#58595B' } | |
] | |
}, { | |
featureType: 'road', | |
elementType: 'labels.icon', | |
stylers: [ | |
{ visibility: 'off' } | |
] | |
}, { | |
featureType: 'road', | |
elementType: 'labels.text.stroke', | |
stylers: [ | |
{ color: '#fff' }, | |
{ weight: 2 } | |
] | |
}, { | |
featureType: 'water', | |
stylers: [ | |
{ color: '#D1D3D4' } | |
] | |
}, { | |
featureType: 'poi', | |
elementType: 'geometry', | |
stylers: [ | |
{ visibility: 'off' } | |
] | |
} | |
]); | |
} | |
}; | |
}; | |
})(gcMap); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment