问题
I need a list of countries, states & cities based on a collection of lat/long values I have. I need to store this information in a manner that hierarchy is preserve and without duplicates (e.g. \"USA\" and \"United States\" and \"United States of America\" are the same country; I only want one instance of this country in my database).
Is this possible to do with Google Map API?
回答1:
What you are looking for is called reverse geocoding. Google provides a server-side reverse geocoding service through the Google Geocoding API, which you should be able to use for your project.
This is how a response to the following request would look like:
http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=false
Response:
{
"status": "OK",
"results": [ {
"types": [ "street_address" ],
"formatted_address": "275-291 Bedford Ave, Brooklyn, NY 11211, USA",
"address_components": [ {
"long_name": "275-291",
"short_name": "275-291",
"types": [ "street_number" ]
}, {
"long_name": "Bedford Ave",
"short_name": "Bedford Ave",
"types": [ "route" ]
}, {
"long_name": "New York",
"short_name": "New York",
"types": [ "locality", "political" ]
}, {
"long_name": "Brooklyn",
"short_name": "Brooklyn",
"types": [ "administrative_area_level_3", "political" ]
}, {
"long_name": "Kings",
"short_name": "Kings",
"types": [ "administrative_area_level_2", "political" ]
}, {
"long_name": "New York",
"short_name": "NY",
"types": [ "administrative_area_level_1", "political" ]
}, {
"long_name": "United States",
"short_name": "US",
"types": [ "country", "political" ]
}, {
"long_name": "11211",
"short_name": "11211",
"types": [ "postal_code" ]
} ],
"geometry": {
"location": {
"lat": 40.7142298,
"lng": -73.9614669
},
"location_type": "RANGE_INTERPOLATED",
"viewport": {
"southwest": {
"lat": 40.7110822,
"lng": -73.9646145
},
"northeast": {
"lat": 40.7173774,
"lng": -73.9583193
}
}
}
},
... Additional results[] ...
You can also opt to receive the response in xml instead of json, by simply substituting json for xml in the request URI:
http://maps.googleapis.com/maps/api/geocode/xml?latlng=40.714224,-73.961452&sensor=false
As far as I know, Google will also return the same name for address components, especially for high-level names like country names and city names. Nevertheless, keep in mind that while the results are very accurate for most applications, you could still find the occasional spelling mistake or ambiguous result.
回答2:
You have a basic answer here: Get city name using geolocation
But for what you are looking for, i'd recommend this way.
Only if you also need administrative_area_level_1,to store different things for Paris, Texas, US and Paris, Ile-de-France, France and provide a manual fallback:
--
There is a problem in Michal's way, in that it takes the first result, not a particular one. He uses results[0]. The way I see fit (I just modified his code) is to take ONLY the result whose type is "locality", which is always present, even in an eventual manual fallback in case the browser does not support geolocation.
His way: fetched results are different from using http://maps.googleapis.com/maps/api/geocode/json?address=bucharest&sensor=false than from using http://maps.googleapis.com/maps/api/geocode/json?latlng=44.42514,26.10540&sensor=false (searching by name / searching by lat&lng)
This way: same fetched results.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Reverse Geocoding</title>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var geocoder;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
}
//Get the latitude and the longitude;
function successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
codeLatLng(lat, lng)
}
function errorFunction(){
alert("Geocoder failed");
}
function initialize() {
geocoder = new google.maps.Geocoder();
}
function codeLatLng(lat, lng) {
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//console.log(results);
if (results[1]) {
var indice=0;
for (var j=0; j<results.length; j++)
{
if (results[j].types[0]=='locality')
{
indice=j;
break;
}
}
alert('The good number is: '+j);
console.log(results[j]);
for (var i=0; i<results[j].address_components.length; i++)
{
if (results[j].address_components[i].types[0] == "locality") {
//this is the object you are looking for City
city = results[j].address_components[i];
}
if (results[j].address_components[i].types[0] == "administrative_area_level_1") {
//this is the object you are looking for State
region = results[j].address_components[i];
}
if (results[j].address_components[i].types[0] == "country") {
//this is the object you are looking for
country = results[j].address_components[i];
}
}
//city data
alert(city.long_name + " || " + region.long_name + " || " + country.short_name)
} else {
alert("No results found");
}
//}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
</script>
</head>
<body onload="initialize()">
</body>
</html>
回答3:
I used this question as a starting point for my own solution. Thought it was appropriate to contribute my code back since its smaller than tabacitu's
Dependencies:
- underscore.js
- https://github.com/estebanav/javascript-mobile-desktop-geolocation
- <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
Code:
if(geoPosition.init()){
var foundLocation = function(city, state, country, lat, lon){
//do stuff with your location! any of the first 3 args may be null
console.log(arguments);
}
var geocoder = new google.maps.Geocoder();
geoPosition.getCurrentPosition(function(r){
var findResult = function(results, name){
var result = _.find(results, function(obj){
return obj.types[0] == name && obj.types[1] == "political";
});
return result ? result.short_name : null;
};
geocoder.geocode({'latLng': new google.maps.LatLng(r.coords.latitude, r.coords.longitude)}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length) {
results = results[0].address_components;
var city = findResult(results, "locality");
var state = findResult(results, "administrative_area_level_1");
var country = findResult(results, "country");
foundLocation(city, state, country, r.coords.latitude, r.coords.longitude);
} else {
foundLocation(null, null, null, r.coords.latitude, r.coords.longitude);
}
});
}, { enableHighAccuracy:false, maximumAge: 1000 * 60 * 1 });
}
回答4:
I found the GeoCoder javascript a little buggy when I included it in my jsp files.
You can also try this:
var lat = "43.7667855" ;
var long = "-79.2157321" ;
var url = "https://maps.googleapis.com/maps/api/geocode/json?latlng="
+lat+","+long+"&sensor=false";
$.get(url).success(function(data) {
var loc1 = data.results[0];
var county, city;
$.each(loc1, function(k1,v1) {
if (k1 == "address_components") {
for (var i = 0; i < v1.length; i++) {
for (k2 in v1[i]) {
if (k2 == "types") {
var types = v1[i][k2];
if (types[0] =="sublocality_level_1") {
county = v1[i].long_name;
//alert ("county: " + county);
}
if (types[0] =="locality") {
city = v1[i].long_name;
//alert ("city: " + city);
}
}
}
}
}
});
$('#city').html(city);
});
回答5:
I wrote this function that extracts what you are looking for based on the address_components returned from the gmaps API. This is the city (for example).
export const getAddressCity = (address, length) => {
const findType = type => type.types[0] === "locality"
const location = address.map(obj => obj)
const rr = location.filter(findType)[0]
return (
length === 'short'
? rr.short_name
: rr.long_name
)
}
Change locality to administrative_area_level_1 for the State etc.
In my js code I am using like so:
const location =`${getAddressCity(address_components, 'short')}, ${getAddressState(address_components, 'short')}`
Will return: Waltham, MA
回答6:
Just try this code this code work with me
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation.getCurrentPosition(posOptions).then(function (position) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
//console.log(lat +" "+long);
$http.get('https://maps.googleapis.com/maps/api/geocode/json?latlng=' + lat + ',' + long + '&key=your key here').success(function (output) {
//console.log( JSON.stringify(output.results[0]));
//console.log( JSON.stringify(output.results[0].address_components[4].short_name));
var results = output.results;
if (results[0]) {
//console.log("results.length= "+results.length);
//console.log("hi "+JSON.stringify(results[0],null,4));
for (var j = 0; j < results.length; j++){
//console.log("j= "+j);
//console.log(JSON.stringify(results[j],null,4));
for (var i = 0; i < results[j].address_components.length; i++){
if(results[j].address_components[i].types[0] == "country") {
//this is the object you are looking for
country = results[j].address_components[i];
}
}
}
console.log(country.long_name);
console.log(country.short_name);
} else {
alert("No results found");
console.log("No results found");
}
});
}, function (err) {
});
回答7:
I've created a small mapper function:
private getAddressParts(object): Object {
let address = {};
const address_components = object.address_components;
address_components.forEach(element => {
address[element.types[0]] = element.short_name;
});
return address;
}
It's a solution for Angular 4 but I think you'll get the idea.
Usage:
geocoder.geocode({ 'location' : latlng }, (results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
const address = {
formatted_address: results[0].formatted_address,
address_parts: this.getAddressParts(results[0])
};
(....)
}
This way the address object will be something like this:
address: {
address_parts: {
administrative_area_level_1: "NY",
administrative_area_level_2: "New York County",
country: "US",
locality: "New York",
neighborhood: "Lower Manhattan",
political: "Manhattan",
postal_code: "10038",
route: "Beekman St",
street_number: "90",
},
formatted_address: "90 Beekman St, New York, NY 10038, USA"
}
Hope it helps!
回答8:
<div id="location"></div>
<script>
window.onload = function () {
var startPos;
var geoOptions = {
maximumAge: 5 * 60 * 1000,
timeout: 10 * 1000,
enableHighAccuracy: true
}
var geoSuccess = function (position) {
startPos = position;
geocodeLatLng(startPos.coords.latitude, startPos.coords.longitude);
};
var geoError = function (error) {
console.log('Error occurred. Error code: ' + error.code);
// error.code can be:
// 0: unknown error
// 1: permission denied
// 2: position unavailable (error response from location provider)
// 3: timed out
};
navigator.geolocation.getCurrentPosition(geoSuccess, geoError, geoOptions);
};
function geocodeLatLng(lat, lng) {
var geocoder = new google.maps.Geocoder;
var latlng = {lat: parseFloat(lat), lng: parseFloat(lng)};
geocoder.geocode({'location': latlng}, function (results, status) {
if (status === 'OK') {
console.log(results)
if (results[0]) {
document.getElementById('location').innerHTML = results[0].formatted_address;
var street = "";
var city = "";
var state = "";
var country = "";
var zipcode = "";
for (var i = 0; i < results.length; i++) {
if (results[i].types[0] === "locality") {
city = results[i].address_components[0].long_name;
state = results[i].address_components[2].long_name;
}
if (results[i].types[0] === "postal_code" && zipcode == "") {
zipcode = results[i].address_components[0].long_name;
}
if (results[i].types[0] === "country") {
country = results[i].address_components[0].long_name;
}
if (results[i].types[0] === "route" && street == "") {
for (var j = 0; j < 4; j++) {
if (j == 0) {
street = results[i].address_components[j].long_name;
} else {
street += ", " + results[i].address_components[j].long_name;
}
}
}
if (results[i].types[0] === "street_address") {
for (var j = 0; j < 4; j++) {
if (j == 0) {
street = results[i].address_components[j].long_name;
} else {
street += ", " + results[i].address_components[j].long_name;
}
}
}
}
if (zipcode == "") {
if (typeof results[0].address_components[8] !== 'undefined') {
zipcode = results[0].address_components[8].long_name;
}
}
if (country == "") {
if (typeof results[0].address_components[7] !== 'undefined') {
country = results[0].address_components[7].long_name;
}
}
if (state == "") {
if (typeof results[0].address_components[6] !== 'undefined') {
state = results[0].address_components[6].long_name;
}
}
if (city == "") {
if (typeof results[0].address_components[5] !== 'undefined') {
city = results[0].address_components[5].long_name;
}
}
var address = {
"street": street,
"city": city,
"state": state,
"country": country,
"zipcode": zipcode,
};
document.getElementById('location').innerHTML = document.getElementById('location').innerHTML + "<br/>Street : " + address.street + "<br/>City : " + address.city + "<br/>State : " + address.state + "<br/>Country : " + address.country + "<br/>zipcode : " + address.zipcode;
console.log(address);
} else {
window.alert('No results found');
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY">
</script>
回答9:
@Szkíta Had a great solution by creating a function that gets the address parts in a named array. Here is a compiled solution for those who want to use plain JavaScript.
Function to convert results to the named array:
function getAddressParts(obj) {
var address = [];
obj.address_components.forEach( function(el) {
address[el.types[0]] = el.short_name;
});
return address;
} //getAddressParts()
Geocode the LAT/LNG values:
geocoder.geocode( { 'location' : latlng }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var addressParts = getAddressParts(results[0]);
// the city
var city = addressParts.locality;
// the state
var state = addressParts.administrative_area_level_1;
}
});
来源:https://stackoverflow.com/questions/4013606/google-maps-how-to-get-country-state-province-region-city-given-a-lat-long-va