How to Search for Addresses using Postal Codes - google-maps

I am using the google_maps_webservice package to fetch geocoding data from Google Maps Web Services.
I want to get the list of addresses, attached to a postal code.
Here's a small snippet of code that demonstrates that:
import 'package:google_maps_webservice/places.dart';
final _places =
GoogleMapsPlaces(apiKey: '<API-Key>');
void main() async {
// This is a valid British postal code.
final postalCode = 'WC2N 5DU';
final response = await _places.autocomplete(
postalCode,
components: [
Component(Component.postalCode, postalCode),
Component(Component.country, 'GB'),
],
location: Location(51.50721, -0.12827),
);
if (response.isOkay) {
for (Prediction prediction in response.predictions) {
print(prediction.description);
}
} else {
print(response.status);
}
}
I get an INVALID_REQUEST status message.
From the Google Maps Geocoding docs
"INVALID_REQUEST" generally indicates that the query (address, components or latlng) is missing.
The components, latlng arguments are passed to the API, but I need it to return the address, associated with the postal code.

Related

Flutter google maps and import polylines

I just start to learn more about dart and flutter and followed some tutorials. Now I have a start with a Google maps app and what i want to do is to import my own polylines.
Normally the polylines are generated automatically between the start and destination point but i want to change that:
This is the automatic standard:
List<LatLng> polylineCoordinates = [];
This is how I can manually change that.
List<LatLng> polylineCoordinates = [
LatLng (4.6546609, 52.2997741),
LatLng (4.6539206, 52.2998594),
LatLng (4.6522898, 52.3002268),
LatLng (4.651689, 52.3002793),
];
Now I dont want to manually add it in the code but I want to fill it from a file(json, csv)
What is best to do and how can I start.. Hope someone can help me.
Your question is more like "how to read data from json/csv into dart code".
Anyway, here's a standard way to do it:
Assuming that you have the values in a json file like the following:
{
[
{ 'lat':33.22222,
'long':20.25451
},
{ 'lat':30.89222,
'long':20.55551
}
]
}
Declare the json file in the pubspec.yaml
flutter:
assets:
- assets/sample.json
Write a function that parses the json
readJson() async {
final String assetFile = await rootBundle.loadString('assets/sample.json');
final data = await json.decode(assetFile);
return data;
}
Use that data for your desired logic
List<LatLng> polylineCoordinates = readJson().map((e)=>LatLng(e['lat'], e['long']).toList;

flutter batch http requests

I am trying to send multiple http request to the google maps api to get the time taken for a journey. With the code below:
getRouteCoordinates(LatLng sourceCords, LatLng destCords)async{
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=${sourceCords.latitude},${sourceCords.longitude}&destination=${destCords.latitude},${destCords.longitude}&key=$apiKey";
http.Response response = await http.get(url);
Map values = jsonDecode(response.body);
}
So I decide to use this package
[ batching_future ] , but I cant seem to understand how I can use this package to make it work.
I want to do this batch request with destination inputs like
var inputs = [
LatLng(43.721160, 45.394435),
LatLng(23.732322, 78.385142),
LatLng(21.721160, 90.394435),
LatLng(13.732322, 59.385142),
LatLng(47.721160, 80.394435),
LatLng(25.732322, 60.385142),
];
How can I achieve this. Thanks in advance.
The gmaps_multidestination package does the track.
The relevant code to run a batch request for travel times is copy and pasted below:
import 'package:google_maps_webservice/distance.dart';
import 'package:meta/meta.dart';
/// Computes travel times from [myLocation] to [destinations] in batch using
/// Google Distance Matrix API and [apiKey].
///
/// Requires Google Maps API Key, Google Distance Matrix API, and is subject
/// to the limitations of the Matrix API (such as maximum destinations per
/// request)
Future<Map<Location, Duration>> batchTravelTimes(
{#required Location myLocation,
#required List<Location> destinations,
#required String apiKey}) async =>
(await GoogleDistanceMatrix(apiKey: apiKey)
.distanceWithLocation([myLocation], destinations))
.results
.expand((row) => row.elements)
.toList()
.asMap()
.map((i, location) => MapEntry(
destinations[i], Duration(seconds: location.duration.value)));
The code to connect the above batching_future is:
/// Computes travel times from `O` to `[D1,D2,D3]` in batch.
/// Requires Google Maps API Key, Google Distance Matrix API, and is subject
/// to the limitations of the Matrix API (such as maximum destinations per
/// request)
import 'package:batching_future/batching_future.dart';
import 'package:google_maps_webservice/distance.dart';
import 'package:meta/meta.dart';
typedef MyLocationProvider = Future<Location> Function();
BatchingFutureProvider<Location, Duration> batchingFutureTravelTime(
{#required MyLocationProvider myLocationProvider,
#required String apiKey}) =>
createBatcher(
(destinations) async => (await batchTravelTimes(
apiKey: apiKey,
myLocation: await myLocationProvider(),
destinations: destinations))
.values
.toList(),
maxBatchSize: 20,
maxWaitDuration: Duration(milliseconds: 200),
);

Show name of the place with Google Directions API

I am trying to make a request to the Google Directions API with multiple waypoints. Everything works fine so far, but the main problem that I'm having is that when the Google Maps app is open for the user, all that the user can see are the coordinates.
I am working on a Flutter App, but probably this request is the same for all devices and platforms, so it's not really Flutter-specific.
I want to show the name of the companies/places on the route.
It could be either a web request or a request using the URL scheme for the Google Maps mobile app.
This is what I'm doing so far, with the coordinates.
Future<void> launchGoogleMaps(BuildContext context) async {
Position userLocation = await Geolocator().getLastKnownPosition(
desiredAccuracy: LocationAccuracy.bestForNavigation,
);
String googleMapsAppUrl = 'comgooglemapsurl://?';
if (customFirstPlace != null) {
googleMapsAppUrl +=
"saddr=${customFirstPlace.latitude},${customFirstPlace.longitude}";
} else if (!shouldStartWithUserLocation) {
googleMapsAppUrl +=
"saddr=${circuitCompanies[0].lat},${circuitCompanies[0].lng}";
}
String googleMapsWebUrl = "http://www.google.com/maps/dir";
googleMapsWebUrl += "/${userLocation.latitude},${userLocation.longitude}";
circuitCompanies.forEach((CompanyModel element) {
int elementIndex = circuitCompanies.indexOf(element);
// If it's the first element, the "direction"
// parameter will be added to specify the beginning.
// If not, the "to" parameter will be added
// to specify a waypoint (a stop).
if (elementIndex == 0) {
googleMapsAppUrl += "&daddr=${element.lat},${element.lng}";
} else {
googleMapsAppUrl += "+to:${element.lat},${element.lng}";
}
googleMapsWebUrl += "/${element.lat},${element.lng}";
});
if (await canLaunch("comgooglemaps://")) {
print('launching com googleUrl $googleMapsAppUrl');
await launch(googleMapsAppUrl);
} else if (await canLaunch(googleMapsWebUrl)) {
print('launching web url $googleMapsWebUrl');
await launch(googleMapsWebUrl);
} else {
showDialog(
builder: (_) {
return SingleActionDialog(
title: "Erreur",
onConfirmTap: () => Navigator.pop(context),
bodyText: "Un erreur s'est produit.",
confirmText: "Fermer",
);
},
context: context,
);
}
}
How could I show the appropriate route, with the name of the places that the user will go, instead of only showing the coordinates? I have access to the precise place address as well.
Thanks!
I managed to solve this issue. I instead used the web URL provided by the Google Maps API.
I made a function that returns the address of the place following the Google Maps standard, instead of just passing coordinates.
Future<String> getEncodedCompanyAddress(CompanyModel model) async {
String _encodedAddress = "";
model.address = await CompanyAddressDAO().getCompanyAddress(
model.id,
);
_encodedAddress = model.details.title +
", " +
model.address.street +
", " +
model.address.city +
", " +
model.address.state;
_encodedAddress = Uri.encodeFull(_encodedAddress);
_encodedAddress = _encodedAddress.replaceAll("%20", "+");
return _encodedAddress;
}
Now, instead of showing only the coordinates, the actual place name is shown in the directions of the Google Maps app.

Async and await

I want to draw markers for zipCode. But I can see only a few markers.
I thought it was because of async and await, but I don't know where to add them.
Somebody please help me.
var zipCode=[...]; //zipCode is array of zip codes.
function func1() {
zipCode.forEach((item, index) => {
drawZipCodeMarker(item.zip);
});
}
function drawZipCodeMarker(zip){
geocoder.geocode({'address':zip}, (results, status) => {
console.log(zip);
console.log(results);
if (results != null) {
var temp = new google.maps.Marker({position : results[0].geometry.location, map:map, title:zip});
}
});
}
You are using Geocoding service of Maps JavaScript API. The services in Google Maps JavaScript API have a per session limit described in the documentation as.
Note: The additional rate limit is applied per user session, regardless of how many users share the same project. When you first load the API, you are allocated an initial quota of requests. Once you use this quota, the API enforces rate limits on additional requests on a per-second basis. If too many requests are made within a certain time period, the API returns an OVER_QUERY_LIMIT response code.
The per-session rate limit prevents the use of client-side services for batch requests, such as batch geocoding. For batch requests, use the Geocoding API web service.
source: https://developers.google.com/maps/documentation/javascript/geocoding
As far as I know, initially you have a bucket of 10 requests. Once the bucket is empty request is denied. The bucket is refilled at the rate 1 request per second. So, you have to throttle your geocoding requests in order to stay within allowed per session limits.
You should check the status of the response. If status is OVER_QUERY_LIMIT, so you exhausted your bucket and need retry the request. You can use Exponential Backoff approach for retrying logic (https://en.wikipedia.org/wiki/Exponential_backoff).
var zipCode=[...]; //zipCode is array of zip codes.
var delayFactor = 0;
function func1() {
zipCode.forEach((item, index) => {
drawZipCodeMarker(item.zip);
});
}
function drawZipCodeMarker(zip) {
geocoder.geocode({'address':zip}, (results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
console.log(zip);
console.log(results);
if (results != null) {
var temp = new google.maps.Marker({position : results[0].geometry.location, map:map, title:zip});
}
} else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
delayFactor++;
setTimeout(function () {
drawZipCodeMarker(zip)
}, delayFactor * 1100);
} else {
console.log("Error: " + status);
}
});
}
I hope this helps!

how to get a geocode api address pattern .fromaddress?

Im using geocode api from google maps and Im trying to use the answer from server to fill up a form, the problem is, it's not a pattern of object, the result[0].address_components sometimes return 4, 5 and 7 obj and I can`t to know with one is the city, country etc, there is some way to get like result.something.street, result.something.city etc?
else{
Geocode.fromAddress(cep).then(
response => {
const { lat, lng } = response.results[0].geometry.location;
console.log(response.results[0].address_components);
console.log(response);
},
error => {
console.error(error);
}
);
}
You need to filter the object
Working Fiddle
function getValue(adress_components, component_name) {
return adress_components.filter(c => c.types[0] == component_name)[0].long_name
}
var components = response.results[0].address_components;
console.log(getValue(components, 'street_number'));
console.log(getValue(components, 'locality'));
console.log(getValue(components, 'country'));
console.log(getValue(components, 'postal_code'));