Last active
August 29, 2015 14:22
-
-
Save spingary/43af2d27444f3ba4d6b0 to your computer and use it in GitHub Desktop.
Store Locator Javascript for Hubspot COS Hackathon 2
This file contains 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
{% raw %} | |
<script id="infowindow-description-template" type="text/x-handlebars-template"> | |
<div class="loc-name">{{Name}}</div> | |
<div>{{StreetAddress}}</div> | |
<div>{{City}}{{#if State}},{{/if}} {{State}} {{Zip}}</div> | |
<div>{{Features-Products}}</div> | |
<div>{{Features-Service}}</div> | |
<div>{{Features-Stations}}</div> | |
<div>{{PhoneNumber}}</div> | |
</script> | |
<script id="location-list-description-template" type="text/x-handlebars-template"> | |
{{#each locations}} | |
<li data-markerid="{{markerid}}"> | |
<div class="list-label">{{marker_text}}</div> | |
<div class="list-details"> | |
<div class="list-content"> | |
<div class="loc-name">{{Name}}</div> | |
<div class="loc-addr">{{StreetAddress}}</div> | |
<div class="loc-addr3">{{City}}{{#if State}},{{/if}} {{State}} {{Zip}}</div> | |
<div class="loc-phone">{{PhoneNumber}}</div> | |
{{#if distance}}<div class="loc-dist">{{distance}} {{length}}</div> | |
<div class="loc-directions"><a href="https://maps.google.com/maps?saddr={{origin}}&daddr={{StreetAddress}} {{StreetLine2}} {{City}}, {{State}} {{Zip}}" target="_blank">Directions</a></div>{{/if}} | |
</div> | |
</div> | |
</li> | |
{{/each}} | |
</script> | |
{% endraw %} | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.0/handlebars.min.js"></script> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery-sheetrock/1.0.0/dist/sheetrock.min.js"></script> | |
<script> | |
// Asynchronously Load the map API | |
var script = document.createElement('script'); | |
script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&callback=initialize"; | |
document.body.appendChild(script); | |
var locationSpreadsheet = '{{ widget.spreadsheet_url }}'; | |
var region = '{{ widget.region|default(US,true) }}'; | |
var max_locations = {{ widget.max_locations }}; | |
var map; | |
var markers = []; | |
var info_window; | |
var info_windows = []; | |
var bounds; | |
var locations_template = Handlebars.compile($('#location-list-description-template').html()); | |
var infowindows_template = Handlebars.compile($('#infowindow-description-template').html()); | |
jQuery(document).ready(function($) { | |
var locations = []; | |
var origin = ''; | |
$('#map_form').submit(function(){ | |
resetMap(); | |
origin = $('#map_address').val(); | |
googleGeocodeAndGo(origin); | |
return false; | |
}) | |
}) | |
var initialize=function() { | |
var geocoder = new google.maps.Geocoder(); | |
var request = {'address': '{{ widget.default_location }}', 'region': region }; | |
var default_loc; var default_loc_ll; | |
geocoder.geocode(request, function (results, status) { | |
if (status === google.maps.GeocoderStatus.OK) { | |
var result = {}; | |
result.latitude = results[0].geometry.location.lat(); | |
result.longitude = results[0].geometry.location.lng(); | |
default_loc = new google.maps.LatLng(result.latitude, result.longitude); | |
default_loc_ll = result; | |
} else { | |
console.log('Unable to geocode default location!'); | |
default_loc = new google.maps.LatLng(37.7699298, -122.4469157); // San Fran | |
default_loc_ll = { latitude: result.longitude, longitude: -122.4469157}; | |
} | |
bounds = new google.maps.LatLngBounds(); | |
var mapOptions = { | |
zoom: 12, | |
center: default_loc, | |
mapTypeId: google.maps.MapTypeId.{{ widget.map_type }} | |
}; | |
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions); | |
info_window = new google.maps.InfoWindow(); | |
doSearch(default_loc_ll,'{{ widget.default_location }}'); | |
}) | |
} | |
var drawLocations = function(locations) { | |
// Loop through resulting locations | |
for (i in locations) { | |
// Create map info windows | |
locations[i].markerid = i; | |
locations[i].length = '{{ widget.map_unit }}'; | |
locations[i].marker_text = parseFloat(i) + 1; | |
var info_html =infowindows_template(locations[i]); | |
info_windows.push(info_html); | |
// Create map markers | |
var position = new google.maps.LatLng(parseFloat(locations[i].lat), parseFloat(locations[i].lng)); | |
var marker = new google.maps.Marker({ | |
position: position, | |
map: map, | |
{% if widget.marker_image.src %} | |
icon: '{{ widget.marker_image.src }}', | |
{% endif %} | |
}); | |
markers.push(marker); | |
// Adjust map bounds accordingly | |
bounds.extend(position); | |
// Set click event on markers to bring up info window | |
google.maps.event.addListener(marker, 'click', (function(marker, i) { | |
return function() { | |
info_window.setContent(info_windows[i]); | |
info_window.open(map, marker); | |
$('#map_list li').removeClass('list-focus'); | |
$('#map_list').find('[data-markerid="'+i+'"]').addClass('list-focus'); | |
} | |
})(marker, i)); | |
} | |
// Draw external list | |
var locations_obj = {locations: locations}; | |
var html = locations_template(locations_obj); | |
$('#map_list').html(html); | |
$('#map_list li').click(function(){ | |
var markerid = $(this).data('markerid'); | |
info_window.setContent(info_windows[markerid]); | |
info_window.open(map, markers[markerid]); | |
$('html,body').animate({ | |
scrollTop: $('.map_locator').offset().top | |
}, 1000); | |
$('#map_list li').removeClass('list-focus'); | |
$(this).addClass('list-focus'); | |
}); | |
map.fitBounds(bounds); | |
} | |
var doSearch = function(origin_ll,origin) { | |
// Query spreadsheet for locations within bounding box area | |
var q = "select * WHERE {{ widget.latitude_column_letter }} >= " + parseFloat(origin_ll.latitude - toDegrees(0.0253)) + " AND {{ widget.latitude_column_letter }} <= " + parseFloat(origin_ll.latitude + toDegrees(0.0253)) + | |
" AND {{ widget.longitude_column_letter }} >= " + parseFloat(origin_ll.longitude - toDegrees(0.0253)) + | |
" AND {{ widget.longitude_column_letter }} <= " + parseFloat(origin_ll.longitude + toDegrees(0.0253)); | |
sheetrock({ | |
url: locationSpreadsheet, | |
query: q, | |
fetchSize: 1000, | |
callback: function (error, options, response) { | |
var results = []; | |
if (error || response.rows.length <=1) | |
{ | |
$('#map_list').html('<div class="map_error">No results found!</div>'); | |
return; | |
} | |
// Loop through the returned locations and calcualate distance to origin using Haversine formula | |
for (i in response.rows) { | |
if (i==0) | |
continue; | |
var target = { latitude: response.rows[i].cells.lat, longitude: response.rows[i].cells.lng }; | |
var dist = haversine(origin_ll,target,{unit: '{{ widget.map_unit }}'}) | |
response.rows[i].cells.distance = parseFloat(dist.toFixed(2)); | |
response.rows[i].cells.origin = origin; | |
results.push(response.rows[i].cells); | |
} | |
// Sort results by distance | |
sortByDist(results); | |
// Truncate results to max_locaitons | |
results = results.slice(0, {{ widget.max_locations|default(20,true) }}); | |
// Render the results | |
drawLocations(results); | |
} | |
}); | |
} | |
var googleGeocodeAndGo = function(o) { | |
var geocoder = new google.maps.Geocoder(); | |
var request = {'address': o, 'region': region }; | |
geocoder.geocode(request, function (results, status) { | |
if (status === google.maps.GeocoderStatus.OK) { | |
var result = {}; | |
result.latitude = results[0].geometry.location.lat(); | |
result.longitude = results[0].geometry.location.lng(); | |
doSearch(result,request); | |
} else { | |
throw new Error('Geocode was not successful for the following reason: ' + status); | |
} | |
}); | |
} | |
var resetMap = function() { | |
$('#map_list').html(); | |
setAllMap(null); | |
markers=[]; | |
info_windows=[]; | |
bounds = new google.maps.LatLngBounds(); | |
} | |
// Sets the map on all markers in the array. | |
var setAllMap = function(map) { | |
for (var i = 0; i < markers.length; i++) { | |
markers[i].setMap(map); | |
} | |
} | |
var sortByDist = function (locations) { | |
locations.sort(function (a, b) { | |
return ((a.distance < b.distance) ? -1 : ((a.distance > b.distance) ? 1 : 0)); | |
}); | |
} | |
var toDegrees= function(angle) { | |
return angle * (180 / Math.PI); | |
} | |
var toRad = function(num) { | |
return num * Math.PI / 180 | |
} | |
/* Haversine code from https://github.com/niix/haversine */ | |
var haversine = function(start, end, options) { | |
var km = 6371 | |
var mile = 3960 | |
options = options || {} | |
var R = options.unit === 'mile' ? | |
mile : | |
km | |
var dLat = toRad(end.latitude - start.latitude) | |
var dLon = toRad(end.longitude - start.longitude) | |
var lat1 = toRad(start.latitude) | |
var lat2 = toRad(end.latitude) | |
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + | |
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2) | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)) | |
if (options.threshold) { | |
return options.threshold > (R * c) | |
} else { | |
return R * c | |
} | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment