Skip To Content

Navigating the map

In this topic

The map view includes options for defining and changing the map extent as well as the user experience when the extent is modified. It is important to note that the basemap layer (the first layer added to the map) defines the following map properties:

  • Initial extent
  • Full extent
  • Spatial reference

While initial extent can be modified, the spatial reference cannot be changed explicitly. This topic discusses developer and end-user solutions for working with the map extent.

Setting the map extent

To set the map extent, use the zoomToEnvelope:animated: method on the map view by passing in an evelope geometry representing the area you want to zoom to.

override func viewDidLoad() {
 //add a layer to the map
 let tiledLayer = AGSTiledMapServiceLayer(URL: NSURL(string:  ""))
 self.mapView.addMapLayer(tiledLayer, withName: "Tiled Layer")
 //zoom to an area
 let envelope = AGSEnvelope(xmin: -124.83145667, ymin: 30.49849464, xmax: -113.91375495,  ymax: 44.69150688,  spatialReference: mapView.spatialReference) 
 self.mapView.zoomToEnvelope(envelope, animated: true)
Alternatively, you can also zoom to an arbitrary geometry on the map (such as the shape of a country or river) using the zoomToGeometry:withPadding:animated: method.

The envelope or geometry you use to zoom the map must have the same spatial reference as that of the map.

Getting the map extent

You may not know the extent of the map until the map has been loaded. You can use the visibleArea property of the map view to get the extent of the map.

let mapExtent = self.mapView.visibleArea()

The visibleArea property returns a polygon that contains a vertex for each of the four corners on the map, starting with the top-left corner, progressing in a clockwise direction.

If the map does not contain any rotation, the area represented by the visibleArea polygon coincides exactly with the polygon's enclosing envelope. Thus you could use the visibleArea polygon or its envelope as the map extent.

However, if the map has been rotated, the visibleArea polygon and the polygon's envelope will be different. The envelope represents an area that is slightly bigger than the polygon such that it entirely contains the polygon. In this case, use the visibleArea polygon to get the map extent.

Tracking panning and zooming

The map view provides two notifications for extent changes, AGSMapViewDidEndPanningNotification and AGSMapViewDidEndZoomingNotification. These notifications are broadcast after the map has been panned or zoomed, respectively. The following code is an example of how to listen for notifications when the user pans or zooms the map. It displays an alert showing the new map extent retrieved from the envelope property of the map view:

func mapViewDidLoad(mapView: AGSMapView!) {
 //register for pan notifications
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "respondToEnvChange:", name: AGSMapViewDidEndPanningNotification, object: nil)
 //register for zoom notifications
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "respondToEnvChange:", name: AGSMapViewDidEndZoomingNotification, object: nil)
 // The method that should be called when the notification arises
 func respondToEnvChange(notification:NSNotification) {
  //create the string containing the new map extent NSString*
  let theString = "xmin = \(mapView.visibleAreaEnvelope.xmin),\nymin = \(mapView.visibleAreaEnvelope.ymin),\nxmax = \(mapView.visibleAreaEnvelope.xmax),\nymax = \(mapView.visibleAreaEnvelope.ymax)"
  //display the new map extent in a simple alert
  let alertView = UIAlertView(title: "Finished Panning", message: theString, delegate: nil, cancelButtonTitle: "OK")

You should note that these notifications are broadcast when the processor is idle; therefore, there might be a slight delay between when the user finished performing the action and when the notification was raised. Also, notificatons are delievered on the main thread. You should not block this thread by performing expensive tasks; otherwise, your application appears sluggish to the user.

Changing the map extent

As previously mentioned, you can use the zoomToEnvelope:animated method on a map view to set a map view's extent. You can also center the map at a given point using the map view's centerAtPoint:animated method:

let newPoint = AGSPoint(x: -93.032201, y: 49.636213, spatialReference: self.mapView.spatialReference)
self.mapView.centerAtPoint(newPoint, animated: true)

User gestures

The user can perform several gestures that change the map view's extent at run time. All of these trigger the MapDidEndPanning and MapDidEndZooming notifications.

User ActionMap ActionNotification raised


Zoom out on map



Zoom in on map


Double tap

Zoom in on map


Two finger tap

Zoom out on map


Swipe (any direction)

Pan map in direction of swipe


Two finger twist= (see the following note)

Rotate the map


Enable the allowRotationByPinching property on AGSMapView AGSMapView to enable the Two finger twist gesture.

Enable wrap around

The world is round. It does not end at the date line. However, most flat representations of the earth only extend up to 180 east and west longitude. This makes it difficult to visualize areas that span across the date line, or routes that traverse the Pacific Ocean.

With wrap around support, it is possible to visualize a world map extending seamlessly beyond the date line. The eastern and western hemispheres wrap around each other forming a continuous map, and gives the impression that the map is endless. Panning a map becomes similar to spinning a globe.

Wrap around
A map with wrap around enabled

To enable wrap around, invoke the enableWrapAround method on AGSMapView.



The following following requirements must be satisfied before enabling wrap around :

  • The map's full envelope must cover the entire world.
  • The map's spatial reference must be WGS 84 (WKID=4326) or Web Mercator (WKID=102113, 102100, or 3857). This means that all tiled layers on the map must belong to one of these spatial references. Dynamic layers, on the other hand, can be in any spatial reference because they are capable of reprojecting their data.
  • Dynamic layers must be based on map services from ArcGIS Server 10.0 or higher. This is because earlier versions of the REST API do not support well-known text (WKT) values for spatial reference, which is required for making dynamic map services support wrap around.
  • If any of these requirements are not satisfied and you try to enable wrap around, the wrapAroundStatus property on AGSMapView indicates wrap around is not supported.


if self.mapView.wrapAroundStatus() == .Unsupported  {
 println("Wrap around is not supported")

Normalizing geometries

To better understand wrap around, visualize a map as being composed of frames. The portion of a map between -180 longitude and +180 longitude is frame 0. This frame is regularly visible even when wrap around is not enabled. Adjacent to this frame on the east is frame 1, which extends hypothetically between +180 and +540 longitude. Adjacent to frame 0 on the west is frame -1, which extends hypothetically between -180 and -540 longitude.

Depending on the frame being displayed, longitude values reported by a map may be real (within -180 and +180) or hypothetical (extend beyond -180 or +180). Here are some examples of geometries that may contain hypothetical coordinates:

  • A map's envelope
  • Touch coordinates reported by a map's delegates
  • Geometries digitized by a sketch layer

When geometries contain hypothetical coordinates, normalize them before using them to perform spatial queries or storing them in a geodatabase. This process of normalizing translates coordinates of the geometry from other frames into frame 0. It is difficult to programmatically check at run-time if geometries contain hypothetical values, and need to be normalized or not. It is safer to always normalize geometries when wrap around is enabled.

You can normalize geometries using the normalizeCentralMeridianOfGeometry: method on AGSGeometryEngine.

let geo:AGSGeometry = ...
if self.mapView.wrapAroundStatus() == .Enabled {
 geo = AGSGeometryEngine.defaultGeometryEngine().normalizeCentralMeridianOfGeometry(geo)