We’ve shown several ways of getting a base layer into the map, but what about the map object itself? The map object is where you go when you need control over the viewing pane, extents, layer order, projection, and access to the layers. It’s a collection of functionality that applies to the map as a whole to all of its parts equally.
Adding, querying and acting upon layers
If you use the map object for nothing else, you will want to add layers to your map. Otherwise, all you have is the base map, and where’s the fun in that? First, let’s add a layer to the map:
var census = new OpenLayers.Layer.WMS( “Census Blocks”, “http://descartes.renci.org/geoserver/wms”, { layers: “oreilly:census”, srs: map.projection, transparent: true }, { isBaseLayer: false } ); var boundaries = new OpenLayers.Layer.WMS( “State Boundaries”, “http://descartes.renci.org/geoserver/wms”, { layers: “oreilly:state_boundaries”, srs: map.projection, transparent: true }, { isBaseLayer: false } ); map.addLayers([layer, boundaries]);
Here we add two layers: “Census Blocks” and “State Boundaries.” In the layer constructor, the first argument is always the name of the layer. The second argument, in the case of WMS, is the URL of the WMS server. The third argument is an object that gives the parameters to send to the WMS server. In general, the parameter name is the property name, and the value is the property value. Other arguments may be added when actual querying takes place, such as the image format requested or the bounding box, but these are extra arguments that help you customize your WMS object. The final argument is an “options” argument, where named options, usually the name of properties of the layer object, are passed to the constructor so they don’t have to be set later. OpenLayers constructors follow this “options passing” object as the final parameter quite often.
OpenLayers provides us a number of ways to get at layers once they’ve been added to the map. The querying functions are:
* Map.getLayersBy(property, value)
* Map.getLayersByName(name)
* Map.getLayersByClass(class)
The first function, getLayersBy, is the most general function, allowing you to access any layers who have a particular property set, such as isBaseLayer or sphericalMercator. Arbitrary properties can be set on a layer by either adding them to the options object in the constructor, or by adding them post-hoc after construction. This allows you to customize things like whether layers show in a layer switcher, whether they’re shared by multiple users, or other kinds of information data that the OpenLayers folks didn’t think of.
The getLayerByName function does what it sounds like it does and gets a list of layers who all share the same name. It’s an exact query, but since OpenLayers makes no restrictions on how many layers can have a given name, it returns an array and not a single layer object.
The getLayersByClass function takes a class name string, such as OpenLayers.Layer.WFS and returns all layers whose class is that. It does not return subclasses of that class name, so you cannot pass OpenLayers.Layer.Layer and expect to retrieve all layers.
If you want to iterate over all the layers in a map, simply access the .layers property of the map object, and all the layers, including the base layers, are contained therein. It is generally advisable to manipulate layers after they’ve been added to the map, as the act of adding them to the map changes a few properties of the layer.
Another common task on layers that is accessed through the map object is manipulating the Z-index of layers. Z-indexing decides which layers are “over” other layers. Generally speaking, a layer’s Z-index is the same as the order in which it was added to the layer, assuming it’s not a base layer. It would seem intuitive that the Z-index of the layer would be stored on the layer, but this is not the case: Z-indexing is stored and adjusted by the map object.
The lowest base layer is index 0, and others are sequentially numbered above that. There is no need for them to be contiguous – OpenLayers merely uses this number for sorting. It is possible and sometimes desirable to set a layer’s index to some large number to ensure that it remains over the top of any other layers that may be added to the map during use. The functions for manipulating the Z-index of layers are:
* map.getLayerIndex(layer) – Get the index of the layer.
* map.setLayerIndex(layer, ix) – Set the index of the layer to .
* map.raiseLayer(layer, delta) – Add “delta” to the index of the layer.
It is possible, but not desirable to raise base layers over the top of overlays using these functions, so to avoid this, always check the .isBaseLayer property of a layer before adjusting the Z-index.
Removing a layer should always be performed using the map.removeLayer(layer) method of the map object. This method removes the layer from the map object, sets the layer’s map property to null, and also removes the layer’s <div> tag from the browser’s HTML document. Without doing all three of these, you risk leaking resources and leaving dangling references to outdated layer or map objects, or introducing strange and hard-to-debug visual artifacts into your page.
A final caveat: depending on your application, you may find yourself wanting to serialize layers or map objects for layer use. A layer should always be removed from a map before serializing the layer, and all layers should be removed from a map before serializing the map, as the layer object has a map property set to the map that it’s attached to, creating a circular reference in the object structure. Failing to do this will result in strange and hard-to-debug errors, especially using popular JSON serializers.
Getting and setting map projection and extents
Generally, when a map is created, unless the property controls is passed into the options object in the constructor, a navigational control is added to the map, allowing a user to use mouse navigation the way one would familiar web mapping products like google. However, this may well not be enough for the power-user of OpenLayers. Programmatically setting the viewport and extent is something you can do within the map object.
The following options can be passed in the options object of the Map constructor to control the way the map behaves from the start (many of these may also be adjusted automatically when you add a base layer to the map):
- minScale – The denominator of the ratio of real-world-size to map-size. This can often be left out, but if not, it should be smaller than the maxScale number. This means, counterintuitively, that the minScale is not the most zoomed out, but the most zoomed in scale. Think of it as the “minimum amount of scaling applied”
- maxScale – Same as minScale, but the largest denominator instead of the smallest. This will refer to the most zoomed out portion of the map.
- minExtent – The minimum viewable extent, in map units, given as an . This area must always be viewable in the map.
- maxExtent – The maximum viewable extent, in map units, given in the same way as . This is the virtual area of the map, whether it’s in view currently or not. Tiles will not be retrieved if they lie outside of maxExtent. **Note that maxExtent should nearly always be set if you intend on putting multiple layers on the map, or odd things will happen, like missing tiles or zoom levels**. The default max extent is [-180,-90,180,90]
- maxResolution – The maximum number of units-per-pixel on a single map tile. Will often be set by other parameters either to the constructor or as part of the base map. The default, barring any other setting, is 360.0/256.0.
- minResolution – The minimum number of units-per-pixel on a single map tile.
- restrictedExtent – Set this if you are not displaying the entire world. It should be set to a Bounds object (see min- and maxExtent) in the same units as the map projection.
- numZoomLevels – The number of increments between the most-zoomed-in and most-zoomed-out a map can get.
- projection – A string that refers to a projection code. Look for codes at SpatialReference.org. Projections are fundamental, and should always be set, even if just for your own reference. This property determines map units, valid values for map extent, and what projection is requested for layers that are layered on top of the base layer.
- displayProjection – This is used by certain controls, like mouse position, to reproject the map coordinates used by OpenLayers to position things into human readable coordinates like longitude and latitude or state-plane coordinates.
You may note that the actual physical size of the map on the page is not part of the constructor options. This is generally controlled through CSS or in the HTML document, and cannot directly be set by the OpenLayers library. Size can be changed during runtime by manipulating the CSS that styles the map’s <div> element. When this size changes, you should call the map.updateSize() method to tell the map object about the change. This will allow it to recompute the viewing extent and such.
Once the map is created and the user is interacting with it, you may still find yourself wanting to snap to a particular feature, view, location, and zoom-level programmatically. These functions allow you to do this:
- getCenter() – Returns a object (which has a .lon and .lat property). Counterintuitively, this object is in the map projection, whether or not the map projection uses lon and lat degrees.
- zoom(z) – Returns an integer zoom level. 0 is the most zoomed out. Positive integers zoom in. Fires an zoomend event to listeners that the zoom has changed.
- pan(xamt, yamt) – Pan the map so that its center point is adjusted by xamt and yamt, which are floats given in map projection units. Fires a moveend event to let listeners know that the location has changed.
- panTo(lonlat) – Pan the map so that its center point is the same as a LonLat object. Once again LonLat objects contain map coordinate pairs, **not** longitudes and latitudes. Fires a moveend event to let listeners know that the location has changed.
- setCenter(lonlat, zoom, dragging, zchange) – Set the center and zoom point. If dragging is set to true, let listeners know that the location has changed. If zchange is true, then let listeners know that the zoom level has changed.
- getProjectionObject() – returns the projection object from the base layer. This can be used to transform LatLon objects or points into this coordinate system from another.
Let’s take a timeout for a moment to consider an example. Say you have a list of features whose locations are saved for the user to snap to when he/she selects them from a dropdown list on the page. We want to snap to these features upon the change in the dropdown list. Here’s how we’d do this using the methods contained in this section and a little extra JQuery magic:
var map = new OpenLayers.Map(‘map’); map.addLayer(new OpenLayers.OSM(“OSM”)); var mySpecialFeatures = { ... }; $(“#specialfeatures”).change(function() { var selectedFeature = $(“#spatialfeatures”).val(); if(mySpecialFeatures.hasOwnProperty(selectedFeature)) { map.panTo(mySpecialFeatures[selectedFeature].lonlat); } }); $(“#recenter”).click(function() { map.setCenter( new OpenLayers.LonLat(0,0).transform( new OpenLayers.Projection(“EPSG:4326”), map.getProjectionObject()) 0, false, false // don’t notify listeners. ); });
where in the HTML there are fragments similar to this somewhere in the page:
<select id='specialfeatures'>...</select> <input type='button' id='recenter' value='Recenter' />
Walking through the example, we define mySpecialFeatures, an object which contains properties whose names correspond to the values of options present in a <select> tag in the HTML document. The property values of the object contain LonLat objects in the map projection coordinates. We have a map object, and we add an OpenStreetMap layer to the map. The OpenStreetMap layer will set things for us like maxExtent, minExtent, zoom levels, and so on, so we can safely ignore them for this application. We then add two event handlers using JQuery (if you are not comfortable with JQuery, you can use a DOM manipulation library of your choosing or specify onchange or onclick handlers in the HTML code). The first event handler attaches to the select tag. It gets the value of our drop-down box upon selection, and recenters the map using the map.panTo method. The second event handler recenters our map to the origin (which is the prime meridian at the equator, longitude-latitude (0,0)) using the map.setCenter method, which sets zoom and pan at the same time.
This should get you started with the Map object. In the next post we will talk about vector-based feature layers.