get city name, address using latitude and longitude in appcelerator - google-maps

I have a doubt in the mentioned Title. I can get current latitude and longitude. But when i am using reverse geoCoding to convert to corresponding city name or address, nothing shows. Does anybody have any idea about this ?. Here is my code
Titanium.Geolocation.getCurrentPosition(function(e) {
if (!e.success || e.error) {
alert('Could not find the device location');
return;
} else {
longitude = e.coords.longitude;
latitude = e.coords.latitude;
Titanium.Geolocation.reverseGeocoder(latitude, longitude, function(e) {
if (e.success) {
var places = e.places;
if (places && places.length) {
driverCity = places[0].city;
// Current city
driverState = places[0].address;
// Current State
annotation.title = e.places[0].displayAddress;
// Whole address
// Ti.API.info("\nReverse Geocode address == " + JSON.stringify(places));
} else {
// address = "No address found";
}
}
});
}
});

I would suggest firstly using different variables for your return parameters in the functions and use negative conditions to reduce indentation:
Titanium.Geolocation.getCurrentPosition(function(position) {
if (!position.success || position.error) {
alert('Could not find the device location');
return;
}
longitude = position.coords.longitude; // -88.0747875
latitude = position.coords.latitude; // 41.801141
Titanium.Geolocation.reverseGeocoder(latitude, longitude, function(result) {
if (!result.success || !result.places || result.places.length == 0) {
alert('Could not find any places.');
return;
}
var places = result.places;
Ti.API.info("\nReverse Geocode address == " + JSON.stringify(places));
driverCity = places[0].city;
// Current city
driverState = places[0].address;
// Current State
annotation.title = places[0].displayAddress;
// Whole address
// Ti.API.info("\nReverse Geocode address == " + JSON.stringify(places));
});
});
Then see what is being returned from your calls.

Related

Google geocode with address returns one result

Geocoder with an existing address as a parameter returns only the street_address as a result. Why? The address is valid. It has been tested at https://google-developers.appspot.com/maps/documentation/utils/geocoder/
My call:
checkAddress(street, strNo, post_code, area, function (results) {
if (results) {
$.each(results, function (i, address) {
if (address.types[0] == "street_address") {
itemStreetNo = address.address_components[0].long_name;
itemStreet = address.address_components[1].long_name;
}
if (address.types[0] == "route") {
itemStreet = address.address_components[0].long_name;
}
if (address.types[0] == "postal_code") {
itemPostalCode = address.address_components[0].long_name;
}
if (address.types[0] == "country") {
itemCountry = address.address_components[0].long_name;
}
if (address.types[0] == "locality") {
itemRegion = address.address_components[0].long_name;
}
}
});
My function is:
function checkAddress(address, number, zipcode, area, callback) {
var geocoder = new google.maps.Geocoder;
var addr = address + ' ' + number + ' ' + zipcode + ' ' + area;
geocoder.geocode({ 'address': addr }, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[0]) {
callback(results);
}
else {
callback(null);
}
}
else {
callback(null);
}
});
}
You only search in 1 component (address.address_components[0]), so you only get 1 result.
address.address_components[0] contains a component, for example "route". Then address.address_components[1] contains another component, for example "locality", then address.address_components[2] ... As far as I remember the order of the components is random.
So what you need, is to iterate. For every component you check the type, that lets you know where the value is supposed to go.
I wrote a function for a different Stack Overflow question that does this iteration, that goes "fishing" for whatever component.
See if it works for you; let me know.
Google API Address Components

Which API method provides the drawing of a city's boundaries?

Using Google Maps' API v3, how can I geocode a city name, and have a map returned with the outline of the result? usually this is a political entity with strict boundaries, like a city, municipality, etc.
Which API method should be used?
There isn't any API (at present) that provides that data.
Enhancement request
I think you will need Tiger/Line files as referenced in this answer. You can use the data to generate polygons. Use Geocoder.geocode to search for city names. Here's a promise based function that I use:
function locateAddress(address) {
var deferred = $q.defer();
if(!address) { $q.resolve(null); return; }
var geocoder = new google.maps.Geocoder();
var a = address;
if(_.isObject(a)) {
a = (a.line1 || '') + ' ' + (a.city || '') + ' ' + (a.state || '') + ' ' + (a.zip || '');
}
geocoder.geocode({ 'address' : a}, function(results, status) {
if(status === 'ZERO_RESULTS') {
deferred.resolve(null);
return;
}
var c = results[0].geometry.location;
deferred.resolve({latitude: c.lat(), longitude: c.lng()});
}, function(err) {
deferred.reject(err);
});
return deferred.promise;
}

GMap Api geocoder.getLatLng (address) function , Doesn't work good when call it within loop

I'm trying this recursion function to find LatLng of 2088 diffrent addresses and replay me with only about 180 results . although all addresses are valid on google maps website .
function test(i)
{
if(i >= jsArray.length){return;}
var geocoder = new GClientGeocoder();
geocoder.getLatLng(jsArray[i], function (current) {
return function(point) {
if (!point) {
data.push("null");
//nulls.push(myindex);
} else {
data.push(point);
//alert("done");
}
test(i+1,jsArray);
}
}(i));
}
test(0);
i have developed this recursive function but it's need about 30 mins till get good results ,
function test2(i)
{
geocoder.getLocations(jsArray[i], function (current) {
return function(response) {
if (!response || response.Status.code != 200) {
//alert(address + " not found");
//test(i,jsArray);
// data.push("null");
//nulls.push(myindex);
test2(i);
} else {
var len = response.Placemark[0];
point2 = new GLatLng(
len.Point.coordinates[1],
len.Point.coordinates[0]
);
data[i] = point2;
}
}
}(i));
}
for(i =0 ; i<=jsArray.length; i++)
{
if(i==jsArray.length){
alert(data.length);
/// $("#maintable").show(100) ;
/// $("#loading").hide(100) ;
}else{
test2(i);
}
}
i still need expert one to help me :) :D
The geocoder is asynchronous (which makes using it in loops problematic) and subject to a quota and rate limits. It is not intended for displaying lots of known addresses on a map, it is intended for user entered data.
You really should geocode your points off line, save the resulting coordinates and use those coordinates to display markers on your map.
If you are using it in a loop, you shouldn't use the getLatLng method, you should use the getLocations method, which contains a status code that will let you know why it is failing (G_GEO_TOO_MANY_QUERIES
= 620, would mean you could throttle your requests and potentially get a useful result)
// jsArray is array of addresses . the length of this array is 2087 element, all addresses got from google maps .
function MYFunction(i)
{
geocoder.getLocations(jsArray[i], function (current) {
return function(response) {
if (!response || response.Status.code != 200) {
test2(i); // recursive calling
} else {
var len = response.Placemark[0];
point2 = new GLatLng(
len.Point.coordinates[1],
len.Point.coordinates[0]
);
data[i] = point2;
}
}
}(i));
} /// end of y Function
//// loop for each address and pass it to MyFunction function and start recursive function .
for(i =0 ; i<=jsArray.length; i++)
{
MYFunction(i);
}

Country name from latitude and longitude

This question may look familiar: I have the latitude and longitude of a place. I need to get the name of country. I know I have to use reverse geo coding for this. But my problem is that sometimes it returns the short form of the area or country (for example US for United State or CA for California). Is there any way that I can get the full name of the country? I can't perform a match operation by this short forms with my prestored country database.
I have already gone through this, this. But it's not much help for my problem.
The geocoder response usually returns several results which include street corners, intersections, counties, and other alternate representation names. I found that results[0] is the best description.
The trick is searching for "country" in the results. Then the long_name can be retrieved.
Click on the map
function getCountry(latLng) {
geocoder.geocode( {'latLng': latLng},
function(results, status) {
if(status == google.maps.GeocoderStatus.OK) {
if(results[0]) {
for(var i = 0; i < results[0].address_components.length; i++) {
if(results[0].address_components[i].types[0] == "country") {
alert(results[0].address_components[i].long_name);
}
}
}
else {
alert("No results");
}
}
else {
alert("Status: " + status);
}
}
);
}
The JSON array normally includes both long_name and short_name. You should be able to extract both...
Here is an JSON/XML parser that works for both google street maps and open street maps.
(the only problem is that it requires a JSON or XML object as the "reply" its tested on version 3 google and 0.6 open street maps and it works good)
NOTE: it returns an object location.lat or location.lon you can also have it return whatever other field you want.
JSON.parse(text) // where text is the reply from google or open street maps
XML.parse(text) // you can make your own to convert the reply to XML or use regex to parse it. If someone has a regex version to parse the text reply that may also be helpful.
// Parser(ajax reply object, google/open, json/xml);
// takes the reply from google maps or open street maps and creates an object with location[lat/lon]
function Parser(reply, provider, type) {
var location = {};
if(reply != null) {
if(provider == "google") { // Google Street Maps
switch(type) {
case "xml":
location["lat"] = reply.getElementsByTagName("lat")[0].textContent;
location["lon"] = reply.getElementsByTagName("lng")[0].textContent;
break;
default: // json
location["lat"] = reply.results[0].geometry.location.lat;
location["lon"] = reply.results[0].geometry.location.lng;
}
}
else { // Open Street Maps
switch(type) {
case "xml":
location["lat"] = reply.getElementsByTagName("place")[0].getAttribute("lat");
location["lon"] = reply.getElementsByTagName("place")[0].getAttribute("lon");
break;
default: // json
location["lat"] = reply[0].lat;
location["lon"] = reply[0].lon;
}
}
}
return location;
}
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
$.post("https://maps.googleapis.com/maps/api/geocode/json?latlng=" + position.coords.latitude + "," + position.coords.longitude + "&sensor=false", function (result) {
for (var i = 0; i < result['results'][0]['address_components'].length; i++) {
if (result['results'][0]['address_components'][i]['types'][0] == "country") {
alert(result['results'][0]['address_components'][i]['long_name']);
}
}
});
});
}
}
getLocation();

Retrieving Postal Code with Google Maps Javascript API V3 Reverse Geocode

I'm trying to submit a query using the postal code to my DB whenever the googlemaps viewport center changes. I know that this can be done with reverse geocoding with something like:
google.maps.event.addListener(map, 'center_changed', function(){
newCenter();
});
...
function newCenter(){
var newc = map.getCenter();
geocoder.geocode({'latLng': newc}, function(results, status){
if (status == google.maps.GeocoderStatus.OK) {
var newzip = results[0].address_components['postal_code'];
}
});
};
Of course, this code doesn't actually work. So I was wondering how I would need to change this in order to extract the postal code from the results array.
Thanks
What I've realized so far is that in most cases the ZIPCODE is always the last value inside each returned address, so, if you want to retrieve the very first zipcode (this is my case), you can use the following approach:
var address = results[0].address_components;
var zipcode = address[address.length - 1].long_name;
You can do this pretty easily using the underscore.js libraray: http://documentcloud.github.com/underscore/#find
_.find(results[0].address_components, function (ac) { return ac.types[0] == 'postal_code' }).short_name
Using JQuery?
var searchAddressComponents = results[0].address_components,
searchPostalCode="";
$.each(searchAddressComponents, function(){
if(this.types[0]=="postal_code"){
searchPostalCode=this.short_name;
}
});
short_name or long_name will work above
the "searchPostalCode" var will contain the postal (zip?) code IF
and only IF you get one from the Google Maps API.
Sometimes you DO NOT get a "postal_code" in return for your query.
Alright, so I got it. The solution is a little uglier than I'd like, and I probably don't need the last for loop, but here's the code for anyone else who needs to extract crap from address_components[]. This is inside the geocoder callback function
// make sure to initialize i
for(i=0; i < results.length; i++){
for(var j=0;j < results[i].address_components.length; j++){
for(var k=0; k < results[i].address_components[j].types.length; k++){
if(results[i].address_components[j].types[k] == "postal_code"){
zipcode = results[i].address_components[j].short_name;
}
}
}
}
$.each(results[0].address_components,function(index,value){
if(value.types[0] === "postal_code"){
$('#postal_code').val(value.long_name);
}
});
You can also use JavaScript .find method which is similar to underscore _.find method but it is native and require no extra dependency.
const zip_code = results[0].address_components.find(addr => addr.types[0] === "postal_code").short_name;
This takes only two for loops. The "results" array gets updated once we found the first "type" to be "postal_code".
It then updates the original array with the newly found array set and loops again.
var i, j,
result, types;
// Loop through the Geocoder result set. Note that the results
// array will change as this loop can self iterate.
for (i = 0; i < results.length; i++) {
result = results[i];
types = result.types;
for (j = 0; j < types.length; j++) {
if (types[j] === 'postal_code') {
// If we haven't found the "long_name" property,
// then we need to take this object and iterate through
// it again by setting it to our master loops array and
// setting the index to -1
if (result.long_name === undefined) {
results = result.address_components;
i = -1;
}
// We've found it!
else {
postcode = result.long_name;
}
break;
}
}
}
You can also use this code, this function will help to get zip on button click or onblur or keyup or keydown.
Just pass the address to this function.
use google api with valid key and sensor option removed as it doesn't required now.
function callZipAPI(addSearchZip)
{
var geocoder = new google.maps.Geocoder();
var zipCode = null;
geocoder.geocode({ 'address': addSearchZip }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//var latitude = results[0].geometry.location.lat();
//var longitude = results[0].geometry.location.lng();
var addressComponent = results[0].address_components;
for (var x = 0 ; x < addressComponent.length; x++) {
var chk = addressComponent[x];
if (chk.types[0] == 'postal_code') {
zipCode = chk.long_name;
}
}
if (zipCode) {
alert(zipCode);
}
else {
alert('No result found!!');
}
} else {
alert('Enter proper address!!');
}
});
}
I use this code to get "Postal code" and "locality", but you can use it to get any other field just changing the value of type:
JAVASCRIPT
var address = results[0].address_components;
var zipcode = '';
var locality = '';
for (var i = 0; i < address.length; i++) {
if (address[i].types.includes("postal_code")){ zipcode = address[i].short_name; }
if (address[i].types.includes("locality")){ locality = address[i].short_name; }
}
I think rather than depending on the index it better checks address type key inside the component. I solved this issue by using a switch case.
var address = '';
var pin = '';
var country = '';
var state = '';
var city = '';
var streetNumber = '';
var route ='';
var place = autocomplete.getPlace();
for (var i = 0; i < place.address_components.length; i++) {
var component = place.address_components[i];
var addressType = component.types[0];
switch (addressType) {
case 'street_number':
streetNumber = component.long_name;
break;
case 'route':
route = component.short_name;
break;
case 'locality':
city = component.long_name;
break;
case 'administrative_area_level_1':
state = component.long_name;
break;
case 'postal_code':
pin = component.long_name;
break;
case 'country':
country = component.long_name;
break;
}
}
places.getDetails( request_details, function(results_details, status){
// Check if the Service is OK
if (status == google.maps.places.PlacesServiceStatus.OK) {
places_postal = results_details.address_components
places_phone = results_details.formatted_phone_number
places_phone_int = results_details.international_phone_number
places_format_address = results_details.formatted_address
places_google_url = results_details.url
places_website = results_details.website
places_rating = results_details.rating
for (var i = 0; i < places_postal.length; i++ ) {
if (places_postal[i].types == "postal_code"){
console.log(places_postal[i].long_name)
}
}
}
});
This seems to work very well for me, this is with the new Google Maps API V3. If this helps anyone, write a comment, i'm writing my script as we speak... so it might change.
Using JSONPath, it's easily done with one line of code:
var zip = $.results[0].address_components[?(#.types=="postal_code")].long_name;
In PHP I use this code. Almost in every conditions it works.
$zip = $data["results"][3]["address_components"];
$zip = $index[0]["short_name"];
Romaine M. — thanks! If you just need to find the postal code in the first returned result from Google, you can do just 2 loops:
for(var j=0;j < results[0].address_components.length; j++){
for(var k=0; k < results[0].address_components[j].types.length; k++){
if(results[0].address_components[j].types[k] == "postal_code"){
zipcode = results[0].address_components[j].long_name;
}
}
}
In a word, that's a lot of effort. At least with the v2 API, I could retrieve those details thusly:
var place = response.Placemark[0];
var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
myAddress = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName
myCity = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName
myState = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName
myZipCode = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.PostalCode.PostalCodeNumber
There has got to be a more elegant way to retrieve individual address_components without going through the looping jujitsu you just went through.
This simple code works for me
for (var i = 0; i < address.length; i++) {
alert(address[i].types);
if (address[i].types == "postal_code")
$('#postalCode').val(address[i].long_name);
if (address[i].types == "")
$('#country').val(address[i].short_name);
}
Using Jquery
You cant be sure in which location in the address_components array the postal code is stored. Sometimes in address_components.length - 1 > pincode may not be there. This is true in "Address to latlng" geocoding.
You can be sure that Postal code will contain a "postal_code" string. So best way is to check for that.
var postalObject = $.grep(results[0].address_components, function(n, i) {
if (n.types[0] == "postal_code") {
return n;
} else {
return null;
}
});
$scope.query.Pincode = postalObject[0].long_name;
return $http.get('//maps.googleapis.com/maps/api/geocode/json', {
params: {
address: val,
sensor: false
}
}).then(function (response) {
var model= response.data.results.map(function (item) {
// return item.address_components[0].short_name;
var short_name;
var st= $.each(item.address_components, function (value, key) {
if (key.types[0] == "postal_code") {
short_name= key.short_name;
}
});
return short_name;
});
return model;
});
//autocomplete is the text box where u will get the suggestions for an address.
autocomplete.addListener('place_changed', function () {
//Place will get the selected place geocode and returns with the address
//and marker information.
var place = autocomplete.getPlace();
//To select just the zip code of complete address from marker, below loop //will help to find. Instead of y.long_name you can also use y.short_name.
var zipCode = null;
for (var x = 0 ; x < place.address_components.length; x++) {
var y = place.address_components[x];
if (y.types[0] == 'postal_code') {
zipCode = y.long_name;
}
}
});
It seems that nowadays it's better to get it from the restful API, simply try:
https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=YOUR_KEY_HERE
Using an AJAX GET call works perfect!
Something like:
var your_api_key = "***";
var f_center_lat = 40.714224;
var f_center_lon = -73.961452;
$.ajax({ url: "https://maps.googleapis.com/maps/api/geocode/json?latlng="+f_center_lat+","+f_center_lon+"&key="+your_api_key,
method: "GET"
})
.done(function( res ) { if (debug) console.log("Ajax result:"); console.log(res);
var zipCode = null;
var addressComponent = res.results[0].address_components;
for (var x = 0 ; x < addressComponent.length; x++) {
var chk = addressComponent[x];
if (chk.types[0] == 'postal_code') {
zipCode = chk.long_name;
}
}
if (zipCode) {
//alert(zipCode);
$(current_map_form + " #postalcode").val(zipCode);
}
else {
//alert('No result found!!');
if (debug) console.log("Zip/postal code not found for this map location.")
}
})
.fail(function( jqXHR, textStatus ) {
console.log( "Request failed (get postal code via geocoder rest api). Msg: " + textStatus );
});
As I got it zip is the last or the one that before last.
That why this is my solution
const getZip = function (arr) {
return (arr[arr.length - 1].types[0] === 'postal_code') ? arr[arr.length - 1].long_name : arr[arr.length - 2].long_name;
};
const zip = getZip(place.address_components);
i think this is the most accurate solution:
zipCode: result.address_components.find(item => item.types[0] === 'postal_code').long_name;
Just search for postal_code in all types, and return when found.
const address_components = [{"long_name": "2b","short_name": "2b","types": ["street_number"]}, { "long_name": "Louis Schuermanstraat","short_name": "Louis Schuermanstraat", "types": ["route"]},{"long_name": "Gent","short_name": "Gent","types": ["locality","political" ]},{"long_name": "Oost-Vlaanderen","short_name": "OV","types": ["administrative_area_level_2","political"]},{"long_name": "Vlaanderen","short_name": "Vlaanderen","types": ["administrative_area_level_1","political"]},{"long_name": "België","short_name": "BE","types": ["country","political"]},{"long_name": "9040","short_name": "9040","types": ["postal_code"]}];
// address_components = results[0]address_components
console.log({
'object': getByGeoType(address_components),
'short_name': getByGeoType(address_components).short_name,
'long_name': getByGeoType(address_components).long_name,
'route': getByGeoType(address_components, ['route']).long_name,
'place': getByGeoType(address_components, ['locality', 'political']).long_name
});
function getByGeoType(components, type = ['postal_code']) {
let result = null;
$.each(components,
function() {
if (this.types.some(r => type.indexOf(r) >= 0)) {
result = this;
return false;
}
});
return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>