I've made an algorithm/ function to get a user's region based on their GPS coordinates. It primarily looks for big cites and counties for the region and the state for the outer region eg. orange county, Texas.
This wasn't simple as GPS / maps isn't a perfect science. Sometimes I might only get a town and a country to work with. Other times I have 8 levels of their location from house number to country.
I've managed to do this really well, only returning unknown when they are in the ocean. But there are a lot of if
s and else if
s etc. and it would be nice to tidy it up a bit.
function getRegion(latitude, longitude){
return new Promise(function(resolve, reject){
geocoder.geocode({'latLng': new google.maps.LatLng(latitude, longitude)}, function (results, status) {
var region = 'Unknown'; //Set default reigion to unknown
var outterRegion; //Declare an outta reigion as some 'inner' regions have the same name
if (status == google.maps.GeocoderStatus.OK) {
var details = results[0].address_components; //Returns the users location
var gotOptimal = false; //If the optimal reigion name is there, dont search for it anymore
var backupRegion = null; //Look for a backup reigion name incase of eg. Utah, Utah. Changes to xcounty, Utah
for (var i = 0; i< details.length; i++) { //Each level of the users address from smallest (street), to largest (country)
var invalidAreaType = false; //I dont want someones reigion to be their country, postcode, or a route.
for (var j=0; j<details[i].types.length;j++) { //Each level has a type eg country, neibourhood etc
invalidAreaType = ((details[i].types[j] == 'country') || (details[i].types[j] == 'postal_code') || (details[i].types[j] == 'route'));
break;
}
if (!invalidAreaType){ //If the current level of the users location is a type we dont want, skip it
for (var j=0; j<details[i].types.length;j++) {
if (details[i].types[j] == 'administrative_area_level_2' && (!parseInt(details[i].long_name))) {
region = details[i].long_name; //This is the prime reigion, Big citys and countys
gotOptimal = true;
} else if (details[i].types[j] == 'administrative_area_level_1' && (!parseInt(details[i].long_name))) {
outterRegion = details[i].long_name; //Level 1 up from reigion, eg state
region = (!gotOptimal) ? details[i].long_name : region; //If optimal isnt found yet, save it for now
} else if (details[i].types[j] == 'political' && (!parseInt(details[i].long_name))) {
region = (!gotOptimal) ? details[i].long_name : region; //big else if statment from most optimal, to least
} else if (details[i].types[j] == 'postal_town' && (!parseInt(details[i].long_name))) {
region = (!gotOptimal) ? details[i].long_name : region;
backupRegion = (!gotOptimal) ? details[i].long_name : backupRegion;
} else if (details[i].types[j] == 'locality' && (!parseInt(details[i].long_name))) {
region = (!gotOptimal) ? details[i].long_name : region;
backupRegion = (!gotOptimal) ? details[i].long_name : backupRegion;
} else if (details[i].types[j] == 'sublocality' && (!parseInt(details[i].long_name))) {
region = (!gotOptimal) ? details[i].long_name : region;
backupRegion = (!gotOptimal) ? details[i].long_name : backupRegion;
} else if (details[i].types[j] == 'neighborhood' && (!parseInt(details[i].long_name))) {
region = (!gotOptimal) ? details[i].long_name : region;
backupRegion = (!gotOptimal) ? details[i].long_name : backupRegion;
}
}
}
}
//This is used for cases when very little info is returned or a number region eg. '3'
if (region == 'Unknown' && details.length > 1 && !invalidAreaType) {
region = details[Math.floor(details.length / 2)].long_name;
region = (parseInt(region)) ? details[Math.floor(details.length / 2) - 1].long_name : region;
region = (parseInt(region)) ? details[Math.floor(details.length / 2) + 1].long_name : region;
region = (parseInt(region)) ? 'Unknown' : region;
//Ive had number regions returned before, this is to rule it out as a reigion called '3' is too broad
}
//eg Utah, Utah --> change the region to a county or town
region = (region == outterRegion) ? backupRegion : region;
//Finalise and return
userLocation.region = region;
userLocation.outterRegion = outterRegion;
region = (outterRegion && (!parseInt(outterRegion))) ? region + ', ' + outterRegion : region;
}
resolve(region);
});
})
}
I've commented a lot of it to give you an idea of why its there. You can see why I would ideally like this to be a bit shorter. This uses the google maps API also.