Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Camera Zoom based on Radius Google Maps iOS SDK

I am working on an app that displays certain markers based on a radius around your current location. The radius is between 100 - 5000 meters. I change the radius with an UISlider and redraw the GMSCircle.

My problem is that I want to update the camera zoom according to the slider value but I don't have an idea by which scale to divide.

This is how I create the camera in the viewDidLoad method where the initial zoom value is 15:

GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:locationManager.location.coordinate.latitude longitude:locationManager.location.coordinate.longitude  zoom:15];

Here's a screenshot of what I am working on.

enter image description here

Does anyone know what scale should I use to move the zoom accordingly?

Thanks a lot!

Granit

like image 609
Granit Avatar asked Sep 30 '14 07:09

Granit


5 Answers

I just created extension for GMSCameraUpdate.

input parameters:

coordinate - your center coordinate

radius - radius of visible bounds

extension GMSCameraUpdate {

    static func fit(coordinate: CLLocationCoordinate2D, radius: Double) -> GMSCameraUpdate {
        var leftCoordinate = coordinate
        var rigthCoordinate = coordinate

        let region = MKCoordinateRegionMakeWithDistance(coordinate, radius, radius)
        let span = region.span

        leftCoordinate.latitude = coordinate.latitude - span.latitudeDelta
        leftCoordinate.longitude = coordinate.longitude - span.longitudeDelta
        rigthCoordinate.latitude = coordinate.latitude + span.latitudeDelta
        rigthCoordinate.longitude = coordinate.longitude + span.longitudeDelta

        let bounds = GMSCoordinateBounds(coordinate: leftCoordinate, coordinate: rigthCoordinate)
        let update = GMSCameraUpdate.fit(bounds, withPadding: -15.0)

        return update
    }

}
like image 92
LLIAJLbHOu Avatar answered Nov 14 '22 00:11

LLIAJLbHOu


With the help of Saxon Druce,finally I did it.

class MapUtil {

class func translateCoordinate(coordinate: CLLocationCoordinate2D, metersLat: Double,metersLong: Double) -> (CLLocationCoordinate2D) {
    var tempCoord = coordinate

    let tempRegion = MKCoordinateRegionMakeWithDistance(coordinate, metersLat, metersLong)
    let tempSpan = tempRegion.span

    tempCoord.latitude = coordinate.latitude + tempSpan.latitudeDelta
    tempCoord.longitude = coordinate.longitude + tempSpan.longitudeDelta

    return tempCoord
}

class func setRadius(radius: Double,withCity city: CLLocationCoordinate2D,InMapView mapView: GMSMapView) {

    let range = MapUtil.translateCoordinate(city, metersLat: radius * 2, metersLong: radius * 2)

    let bounds = GMSCoordinateBounds(coordinate: city, coordinate: range)

    let update = GMSCameraUpdate.fitBounds(bounds, withPadding: 5.0)    // padding set to 5.0

    mapView.moveCamera(update)

    // location
    let marker = GMSMarker(position: city)
    marker.title = "title"
    marker.snippet = "snippet"
    marker.flat = true
    marker.map = mapView

    // draw circle
    let circle = GMSCircle(position: city, radius: radius)
    circle.map = mapView
    circle.fillColor = UIColor(red:0.09, green:0.6, blue:0.41, alpha:0.5)

    mapView.animateToLocation(city) // animate to center
}

}enter image description here

like image 44
tounaobun Avatar answered Nov 14 '22 01:11

tounaobun


For Swift 3

extension GMSCircle {
var bounds: GMSCoordinateBounds {
    return [0, 90, 180, 270].map {
        GMSGeometryOffset(position, radius, $0)
        }.reduce(GMSCoordinateBounds()) {
            $0.includingCoordinate($1)
    }
}
}

Usage:

mapView.animate(with: .fit(circle.bounds))
like image 45
Jovan Stankovic Avatar answered Nov 14 '22 01:11

Jovan Stankovic


Here's a simpler solution for getting the bounds of a GMSCircle. It doesn't rely on MapKit and avoids the two calls that change the camera position (moveCamera and animateToLocation)

import GoogleMaps

extension GMSCircle {
    func bounds () -> GMSCoordinateBounds {
        func locationMinMax(_ positive : Bool) -> CLLocationCoordinate2D {
            let sign: Double = positive ? 1 : -1
            let dx = sign * self.radius  / 6378000 * (180 / .pi)
            let lat = position.latitude + dx
            let lon = position.longitude + dx / cos(position.latitude * .pi / 180)
            return CLLocationCoordinate2D(latitude: lat, longitude: lon)
        }

        return GMSCoordinateBounds(coordinate: locationMinMax(true),
                               coordinate: locationMinMax(false))
    }
}

After adding this file to your project, all you have to do is:

let update = GMSCameraUpdate.fit(myCircle.bounds())
myMap.animate(with: update)

where myCircle and myMap are replaced by the actual circle and map.

like image 31
Vlad Lego Avatar answered Nov 14 '22 01:11

Vlad Lego


You could use the fitBounds method of GMSCameraUpdate, passing in a GMSCoordinateBounds which is calculated from the edges of your circle.

Based on this answer, it looks like you could use MKCoordinateRegionMakeWithDistance to convert your centre (lat/lon) plus radius (metres) into a MKCoordinateRegion, which will convert the metres into a span in degrees, therefore allowing you to calculate the coordinates in degrees which you'd use to create the GMSCoordinateBounds.

like image 5
Saxon Druce Avatar answered Nov 13 '22 23:11

Saxon Druce