Unable to Get Current Map Center & Zoom Level

3546
4
Jump to solution
11-13-2019 01:05 PM
SteveEllis1
New Contributor II

I am using the ArcGIS 100.6 iOS SDK and am trying to determine the current center of the map view in lat/long coordinates and the view area.  I also want to invoke a listener to detect when a user pans of zooms the map to get the new center and view area.  I am need this information to create and update queries to Firebase/GeoFire so that I can place the appropriate markers on the map based on the viewable area.  As the user zooms out more markers should become visible.

Google maps has a simple way to do this:  center = map.getCenter.

I cannot find a simple answer to this in the SDK documentation.

I have tried setting  currentCenter = mapView.center, but the result is in screen coordinates and there is no concise documentation as to how to convert this point to lat/long.

Thanks,

Steve

0 Kudos
1 Solution

Accepted Solutions
Nicholas-Furness
Esri Regular Contributor

There are a few approaches you can take.

1. Read the current viewpoint as a Center and Scale and use the targetGeometry (it will be a point):

let mapCenter = mapView.currentViewpoint(with: .centerAndScale)?.targetGeometry as? AGSPoint

2. Get the UI center (as you were) and convert it to map coordinates:

let mapCenter = mapView.screen(toLocation: mapView.center)

3. Use the visibleArea property to derive the center:

let mapCenter = mapView.visibleArea?.extent.center

In all those cases, the coordinate will be in the map's spatial reference. You'll want to convert them to lat/lon like this:

if let latLon = AGSGeometryEngine.projectGeometry(mapCenter, to: .wgs84()) as? AGSPoint {
    let lat = latLon.y
    let lon = latLon.x
}

If you find yourself needing latitude and longitude a lot, you can create an extension on AGSPoint:

extension AGSPoint {
    var latitude: Double {
        return (AGSGeometryEngine.projectGeometry(self, to: .wgs84()) as? AGSPoint)?.y ?? 0
    }

    var longitude: Double {
        return (AGSGeometryEngine.projectGeometry(self, to: .wgs84()) as? AGSPoint)?.x ?? 0
    }
}

Note that if you're just using the Lat/Lon for display, you could make use of AGSCoordinateFormatter.LatitudeLongitudeStringFromPoint:format:decimalPlaces:()

As for detecting when there's a new center, there have been a couple of questions about this recently which should help you:

Hope this helps!

View solution in original post

4 Replies
MichaelDavis3
Occasional Contributor III

I use AGSViewpoint to get the current extent of the map:

AGSViewpoint *viewpoint = [AGSViewpoint viewpointWithTargetExtent:self.mapView.visibleArea.extent rotation:self.mapView.rotation];

Once you have that I think you can get the center point using viewpoint.targetGeometry.extent.center.x and viewpoint.targetGeometry.extent.center.y 

0 Kudos
Nicholas-Furness
Esri Regular Contributor

There are a few approaches you can take.

1. Read the current viewpoint as a Center and Scale and use the targetGeometry (it will be a point):

let mapCenter = mapView.currentViewpoint(with: .centerAndScale)?.targetGeometry as? AGSPoint

2. Get the UI center (as you were) and convert it to map coordinates:

let mapCenter = mapView.screen(toLocation: mapView.center)

3. Use the visibleArea property to derive the center:

let mapCenter = mapView.visibleArea?.extent.center

In all those cases, the coordinate will be in the map's spatial reference. You'll want to convert them to lat/lon like this:

if let latLon = AGSGeometryEngine.projectGeometry(mapCenter, to: .wgs84()) as? AGSPoint {
    let lat = latLon.y
    let lon = latLon.x
}

If you find yourself needing latitude and longitude a lot, you can create an extension on AGSPoint:

extension AGSPoint {
    var latitude: Double {
        return (AGSGeometryEngine.projectGeometry(self, to: .wgs84()) as? AGSPoint)?.y ?? 0
    }

    var longitude: Double {
        return (AGSGeometryEngine.projectGeometry(self, to: .wgs84()) as? AGSPoint)?.x ?? 0
    }
}

Note that if you're just using the Lat/Lon for display, you could make use of AGSCoordinateFormatter.LatitudeLongitudeStringFromPoint:format:decimalPlaces:()

As for detecting when there's a new center, there have been a couple of questions about this recently which should help you:

Hope this helps!

SteveEllis1
New Contributor II

Thanks, Nick.

Just as a follow-up since my app only uses Lat/Long can I set the target geometry for my maps so that all map operations are in Lat/Long and not have to change spatial references?

0 Kudos
Nicholas-Furness
Esri Regular Contributor

Hi Steve. Maybe

It depends on the Basemap. Runtime determines the spatial reference to use by looking at the Basemap first (or if there isn't a basemap it has some fallback logic). Most likely your Basemap will be in Web Mercator, and so all coordinates for retrieved features ‌will be in Web Mercator too. This is to avoid having the Runtime re-project from source data every time it needs to draw things. That can rapidly affect performance.

If you use a WGS84 Basemap, you will see coordinates in Lat Lon.

Generally, my previous suggestions will be more flexible and won't lock you to one basemap spatial reference or another.

Also note that if you provide points created with AGSPointMakeWGS84() (or the standard AGSPoint constructor, specifying a Spatial Reference of .wgs84()) then you can provide those to set the viewpoint, etc. and Runtime will convert them appropriately. Really, your issue will typically only arise when reading coordinates and displaying them to the user (also when debugging and sanity checking against known latitudes and longitudes).