Created
December 10, 2015 16:22
-
-
Save EthanGould/b214aded9ac8d3152008 to your computer and use it in GitHub Desktop.
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
// * | |
// * Cars Search | |
// * | |
if (typeof bdc === 'undefined') { bdc = {}; } | |
(function( $, _ ) { | |
'use strict'; | |
var module = {}; | |
/* | |
* set module variables | |
*/ | |
module.init = function() { | |
module.$form = $( '.js-cars-search-form' ); | |
module.$submit = $( '.js-cars-search-form__submit' ); | |
module.$freetext = $( '.js-cars-search-form__location' ); | |
module.$make = $( '.js-cars-search-form__select[name="make"]' ); | |
module.$radius = $( '.js-cars-search-form__select[name="radius"]' ); | |
module.$resultItem = $( '.js-cars-search-results__list-item' ); | |
module.$resultList = $( '.js-cars-search-results__list' ); | |
module.$clearFilter = $('.js-cars-search-results__clear-form'); | |
module.$viewMore = $( '.js-cars-search-results__more-results' ); | |
module.$footer = $( '.js-cars-search-results__footer' ); | |
module.$header = $( '.js-cars-search-results__header' ); | |
module.$resultCount = $( '.js-cars-search-results__count' ); | |
module.invalidClass = 'cars-search-form--invalid'; | |
module.noDistanceClass = 'cars-search-results__list--no-distance'; | |
module.resultSetIndex = 0; | |
module.resultSetCount = 9; | |
module.maxRadius = 500; | |
module.events(); | |
module.addDealerInfo(); | |
}; | |
/* | |
* assign actions to events | |
*/ | |
module.events = function() { | |
module.$form.on( 'submit', module.submitForm ); | |
module.$freetext.on( 'input propertychange', module.sanatizeForm ); | |
module.$make.on( 'change', module.sanatizeForm ); | |
module.$clearFilter.on( 'click', module.clearResults ); | |
module.$viewMore.on( 'click', module.viewMore ); | |
}; | |
/* | |
* handler for search form submissions | |
*/ | |
module.submitForm = function( event ) { | |
event.preventDefault(); | |
if ( module.validate( event ) ) { | |
module.setQuery(); | |
} else { | |
module.showError(); | |
} | |
}; | |
/* | |
* ensure form is filled out properly | |
* user must provide location OR car make | |
*/ | |
module.validate = function( event ) { | |
module.sanatizeForm(); | |
if ( module.$freetext.val() !== '' || module.$make.val() !== 'any' ) { | |
return true; | |
} else { | |
return false; | |
} | |
}; | |
/* | |
* reset form | |
*/ | |
module.sanatizeForm = function() { | |
module.$form.removeClass(module.invalidClass); | |
}; | |
/* | |
* append error message to form | |
*/ | |
module.showError = function() { | |
module.$form.addClass(module.invalidClass); | |
}; | |
/* | |
* get user's search query from form | |
*/ | |
module.setQuery = function() { | |
module.query = {}; | |
module.query.make = module.$make.val(); | |
module.query.radius = module.$radius.val(); | |
module.query.location = module.$freetext.val(); | |
// if present, get user location before parsing query | |
if ( module.query.location !== '' ) { | |
module.getUserLocation( module.query.location ); | |
} else { | |
module.parseQuery(); | |
} | |
}; | |
/* | |
* decide data format info for the query | |
*/ | |
module.parseQuery = function( userLocation ) { | |
var allDealers = allDealersVariable.data.slice(0), | |
userLongLat, | |
radius = module.query.radius, | |
make = module.query.make, | |
dealersWithProximity = [], | |
dealersWithMake = [], | |
dealersInRange = []; | |
module.matchedResults = allDealers || []; | |
module.resultSetIndex = 0; | |
// if present, get users searched x,y coordinates | |
if ( userLocation ) { | |
userLongLat = userLocation.features[0].geometry.coordinates; | |
} | |
// if combination of 'location' and 'radius' provided... | |
if ( userLongLat ) { | |
module.$resultList.removeClass( module.noDistanceClass ); | |
// sort all dealers by proximity | |
dealersWithProximity = module.setDealerProximity( allDealers, userLongLat ); | |
if ( radius !== 'any' ) { | |
// grab sorted dealers within specified radius | |
module.matchedResults = module.filterDistance( dealersWithProximity, radius ); | |
} else { | |
module.matchedResults = module.filterDistance( dealersWithProximity ); | |
} | |
} else { | |
// hide the dealership's 'distance away' flag (no relative user location) | |
module.$resultList.addClass( module.noDistanceClass ); | |
} | |
// filter results by make if neccessary | |
if ( make !== 'any' ) { | |
// grab dealers within radius with specified make | |
module.matchedResults = module.filterMake( module.matchedResults, make ); | |
} | |
module.showResults( true ); | |
}; | |
/* | |
* gets dealership proximity to users entered location | |
* formula from: http://www.htmlgoodies.com/beyond/javascript/calculate-the-distance-between-two-points-in-your-web-apps.html | |
*/ | |
module.setDealerProximity = function( dealerships, userLongLat ) { | |
_.forEach( dealerships, function( dealer ) { | |
if ( dealer.Latitude && dealer.Longitude ) { | |
var lon1 = userLongLat[0]; | |
var lat1 = userLongLat[1]; | |
var lon2 = dealer.Longitude; | |
var lat2 = dealer.Latitude; | |
var radlat1 = Math.PI * lat1/180; | |
var radlat2 = Math.PI * lat2/180; | |
var radlon1 = Math.PI * lon1/180; | |
var radlon2 = Math.PI * lon2/180; | |
var theta = lon1-lon2; | |
var radtheta = Math.PI * theta/180; | |
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); | |
dist = Math.acos(dist); | |
dist = dist * 180/Math.PI; | |
dist = dist * 60 * 1.1515; | |
dist = dist * 0.8684; | |
dealer.proximity = Math.floor( dist * 10 ) /10; | |
var unit = dealer.proximity === 1 ? ' mile' : ' miles'; | |
dealer.proximityString = dealer.proximity + unit; | |
} else { | |
dealer.proximity = 'no data'; | |
} | |
}); | |
return dealerships; | |
}; | |
/* | |
* Creates new 'fullAddress' node for use in template | |
*/ | |
module.addDealerInfo = function() { | |
_.forEach( allDealersVariable.data, function(d) { | |
d.fullAddress = d.address + ' ' + d.city + ', ' + d.state + ' ' + d.zip; | |
}); | |
}; | |
/* | |
* gets users X,Y coords from input | |
*/ | |
module.getUserLocation = function( location ) { | |
var base = 'https://api.mapbox.com/geocoding/v5/mapbox.places/', | |
proximity = '42.36,-71.06', // include X,Y center of Boston to refine results | |
query = encodeURI( location ), | |
token = 'pk.eyJ1IjoiYm9zdG9uZG90Y29tIiwiYSI6IldleklVdWsifQ._uUhid6lqMMFISKLnvE4Lw'; | |
$.get( base + query + '.json?proximity=' + proximity + '&access_token=' + token, module.parseQuery ); | |
}; | |
/* | |
* filters dealerships by make | |
*/ | |
module.filterMake = function( dealerships, make ) { | |
return _.filter( dealerships, { 'make': make } ); | |
}; | |
/* | |
* filters and sort dealerships by distance ASC | |
*/ | |
module.filterDistance = function( dealerships, radius ) { | |
// fallback to default if no radius provided | |
radius = radius || module.maxRadius; | |
var filteredResults = []; | |
// get dealers within range | |
_.forEach( dealerships, function(dealership) { | |
if ( dealership.proximity <= parseInt( radius, 10 ) ) { | |
filteredResults.push( dealership ); | |
} | |
}); | |
// sort dealers by asc proximity | |
filteredResults = filteredResults.sort(function(a, b) { | |
return a.proximity - b.proximity; | |
}); | |
return filteredResults; | |
}; | |
/* | |
* grabs next set of results | |
*/ | |
module.viewMore = function() { | |
module.resultSetIndex += module.resultSetCount; | |
module.showResults(); | |
}; | |
/* | |
* put dealerships into template form | |
*/ | |
module.showResults = function( newQuery ) { | |
_.templateSettings.variable = 'dealership'; | |
var resultSet = module.matchedResults.slice(module.resultSetIndex, module.resultSetIndex + module.resultSetCount), | |
template = _.template( $( 'script#cars-search-result__item-template' ).html() ), | |
resultsMarkup = ''; | |
// if this is a new query, clear old results, update new results count | |
if ( newQuery ) { | |
module.$resultList.empty(); | |
module.$resultCount.text('Results found ' + module.matchedResults.length ); | |
} | |
// build markup of each search result | |
for ( var i = 0; i < resultSet.length; i++ ) { | |
resultsMarkup += template( resultSet[i] ); | |
} | |
// appened markup to DOM | |
module.$resultList.append( resultsMarkup ); | |
module.$header.show(); | |
// conditionally show/hide 'view more' footer | |
if ( module.resultSetIndex + module.resultSetCount < module.matchedResults.length ) { | |
module.$footer.show(); | |
} else { | |
module.$footer.hide(); | |
} | |
}; | |
/* | |
* clears search results, reset form | |
*/ | |
module.clearResults = function() { | |
module.$resultList.empty(); | |
module.$footer.hide(); | |
module.$header.hide(); | |
module.$form[0].reset(); | |
}; | |
/* | |
* initialize if search form is present | |
*/ | |
$(document).ready( function() { | |
if ( $( '.cars-search' ).length ) { | |
module.init(); | |
} | |
}); | |
})( jQuery, _ ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment