Davide Valiante
Davide Valiante

Reputation: 155

Picking the right Zoom level for different cities in GoogleMaps

I have an activity implementing OnMapReadyCallback to display some markers. Before opening the map i provide a target city which i'd like to look at closer on the map basically by calling :

 LatLng currentCity = new LatLng(cityLat,cityLng)
 CameraUpdate location = CameraUpdateFactory.newLatLngZoom(currentCity,13);
 googleMap.animateCamera(location);

The main problem here is that the zoom level is just an arbitrary number which works fine for some city and bad for others (Too zoomed in, Not enough zoomed in). What i would like to achieve is to determine the zoom level dynamically depending on the city in the same way Google Maps does.

I know that the bigger the ViewPort of the city is, the smaller the zoom needs to be but i can't find a method to get the ViewPort for a given city and then changing the zoom level accordingly

EDIT : I was thinking about using a Geocoder to get a list of adress using the latitude and longitude of the city using

List<Address> addresses =  mGeocoder.getFromLocation(Lat,Lon,maxLimit);

and then iterating over this list to find out the outermost adresses avaible for that city, in order to build a LatLngBounds to pass at setLatLngBoundsForCameraTarget() method. The main problem with this approach is that, once again, the "maxLimit" is arbitrary and needs to be quite big for a big city, eventually returning a really big List

Upvotes: 1

Views: 1193

Answers (1)

xomena
xomena

Reputation: 32178

You can retrieve a view port for the city from the Geocoding API reverse geocoding response.

You should execute HTTP request to retrieve city view port from your activity. Once you receive the response you can construct the LatLngBounds instance and move camera accordingly.

Sample reverse geocoding request that gets city from coordinates is the following https://maps.googleapis.com/maps/api/geocode/json?latlng=47.376887%2C8.541694&result_type=locality&key=YOUR_API_KEY

I wrote a small example for Map activity that receives lat and lng from the intent, executes the reverse geocoding HTTP request using the Volley library and moves camera to show the city view port.

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private float lat;
    private float lng;
    private String name;
    private RequestQueue mRequestQueue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent i = getIntent();
        this.lat = i.getFloatExtra("lat", 0);
        this.lng = i.getFloatExtra("lng", 0);
        this.name = i.getStringExtra("name");

        mRequestQueue = Volley.newRequestQueue(this);

        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Sydney and move the camera
        LatLng pos = new LatLng(this.lat, this.lng);
        mMap.addMarker(new MarkerOptions().position(pos).title(this.name));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(pos));

        this.fetchReverseGeocodeJson();
    }

    private void fetchReverseGeocodeJson() {
        // Pass second argument as "null" for GET requests
        JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET,
               "https://maps.googleapis.com/maps/api/geocode/json?latlng=" + this.lat + "%2C" + this.lng + "&result_type=locality&key=AIzaSyBrPt88vvoPDDn_imh-RzCXl5Ha2F2LYig",
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        try {
                            String status = response.getString("status");
                            if (status.equals("OK")) {
                                JSONArray results = response.getJSONArray("results");
                                JSONObject item = results.getJSONObject(0);
                                JSONObject geom = item.getJSONObject("geometry");
                                JSONObject bounds = geom.getJSONObject("viewport");
                                JSONObject ne = bounds.getJSONObject("northeast");
                                JSONObject sw = bounds.getJSONObject("southwest");

                                LatLngBounds mapbounds = new LatLngBounds(new LatLng(sw.getDouble("lat"),sw.getDouble("lng")),
                                        new LatLng(ne.getDouble("lat"), ne.getDouble("lng")));

                                mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapbounds, 0));
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        VolleyLog.e("Error: ", error.getMessage());
                    }
                }
        );

        /* Add your Requests to the RequestQueue to execute */
        mRequestQueue.add(req);
    }
}

You can find a complete sample project at github:

https://github.com/xomena-so/so44735477

Hope this helps!

Upvotes: 2

Related Questions