Skip to content

Instantly share code, notes, and snippets.

@spingary
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spingary/43af2d27444f3ba4d6b0 to your computer and use it in GitHub Desktop.
Save spingary/43af2d27444f3ba4d6b0 to your computer and use it in GitHub Desktop.
Store Locator Javascript for Hubspot COS Hackathon 2
{% 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}}&amp;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