Skip to content

Instantly share code, notes, and snippets.

@EthanGould
Created December 10, 2015 16:22
Show Gist options
  • Save EthanGould/b214aded9ac8d3152008 to your computer and use it in GitHub Desktop.
Save EthanGould/b214aded9ac8d3152008 to your computer and use it in GitHub Desktop.
// *
// * 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