This is the P2PU Archive. If you want the current site, go to www.p2pu.org!

Online Maps with OpenLayers

Tiles, rasters, and vectors: Using different types of layers

Nick Doiron's picture
Wed, 2011-03-16 18:20

When you first get started with a mapping program called OpenLayers, you must wonder, what's so important about layers?  How do you work with them?

Tile versus Vector

We're using two types of layers already:

  • The OpenStreetMap layer is made of smaller images called tiles ( think of floor tiles ).   As you move the map to one side or another, the page loads more tiles to cover new areas.  When you zoom in, the map loads new tiles to show more detail.  Here's a sample OpenStreetMap tile and its URL: http://tile.openstreetmap.org/9/141/193.png
  • We use a vector layer ( called myPointLayer in examples ) to show points and markers.  Points, lines, and shapes in a vector layer are represented by coordinates, so they are loaded once, then are moved along with your map.

If it's only one download, why doesn't the OpenStreetMap layer use vectors, too?  A single highway could be hundreds or thousands of points, but when you're zoomed out or seeing only part of the highway, most of that detail would be meaningless.  Tiles show you the end product, with a much smaller download.  When you use the OpenStreetMap editors you are accessing the vector data directly, so you need to zoom in on small parts of the map and wait for streets to load.

Rasters

Tiles and other non-vector layers are considered to be rasters.  An example of a raster layer that is not a tile layer would be a single satellite photo, or a large heatmap image which was not broken into separate tiles.  These images would be very complex to represent as point-by-point data, so instead it is sent as an image.

Different layers on a map

OpenLayers comes with a simple control to switch layers, and to turn layers on and off.  The best-known example is on OpenStreetMap.org  Click the (+) button in the upper-right of the map to switch between different tile designs.

You can use this on your own maps to switch between OpenStreetMap and maps from many other sources and formats.  Bing and Google have Terms of Service which limit use, but USUALLY if people can view your map online-only, without signing in, paying, copying data, or doing illegal things, it's useable.

Add the Layer Switcher

I start with one of my older jsFiddle maps with some points on it and add these two lines:

layerControl  new OpenLayers.Control.LayerSwitcher();
map.addControl(layerControl);

http://jsfiddle.net/UAxun/104/

Right away you'll notice that my stars are called "Layer Name" from when I created pointLayer.  If you did the same thing, now would be a good time to change the name.

Switch between OpenStreetMap and Google Maps

Add the script http://maps.google.com/maps/api/js?sensor=false&v=3.2&.js -- In jsFiddle use Manage Resources to add it to your page.  If you're using GPS for the user's location, change sensor=false in that URL to sensor=true

Add these lines, and you have Google's roadmap:

gmap new OpenLayers.Layer.Google("Google Streets"visibility:falsetypegoogle.maps.MapTypeId.ROADMAP );
map.addLayer(gmap);

You can add several Google layers by changing the type to google.maps.MapTypeId.TERRAIN , google.maps.MapTypeId.SATELLITE, and google.maps.MapTypeId.HYBRID.  Change the name in quotes, too, so your users know which is which.

Switch between OpenStreetMap and Bing Maps

I can't get this working in jsFiddle yet, but here are good examples of Bing Maps and OpenLayers:

Without API key: http://openlayers.org/dev/examples/ve-novibrate.html
Newer style, requires API key: http://openlayers.org/blog/2010/12/18/bing-tiles-for-openlayers/

Clickable Layers

Let's suppose I want a map of Taxis and Buses.  The viewer can hide Taxis if they want to see only Buses, and vice versa.  My first thought is to organize it like this:

taxis = [ .... ];  // list | array of taxis
buses = [ ... ]; // list | array of buses

taxiLayer = new OpenLayers.Layer.Vector  ....
for( t = 0; t < taxis.length; t = t + 1){
    // adds each taxi from the list into taxiLayer
    thisTaxi = new OpenLayers.Feature.Vector ....
    taxiLayer.addFeature ( thisTaxi )
}
busLayer = new OpenLayers.Layer.Vector  ...
for( b = 0; b < buses.length; b = b + 1){
   // adds each bus from the list into busLayer
    thisBus = new OpenLayers.Feature.Vector ....
    busLayer.addFeature ( thisBus )
}
map.addLayers( [ taxiLayer, busLayer ] );

selectControl = new OpenLayers.Control.SelectFeature( taxiLayer );
selectControl2 = new OpenLayers.Control.SelectFeature( busLayer );
 

Unfortunately, a map can only have one active SelectControl at a time, and a SelectControl only watches one layer.  This means all of the clickable icons must be in one layer.  So how can you show and hide the taxis and buses separately?

Instead, put both in one layer, but use arrays (lists) to keep track of which are taxis and which are buses, like this.

taxis = [ .... ];  // list | array of taxis
var taxiMarkers = [ ]; // empty array of taxi PointFeatures --- use "var" so it can be accessed by the page later
buses = [ ... ]; // list | array of buses
var busMarkers = [ ]; // empty array of bus PointFeatures --- using "var"

var drivingLayer = new OpenLayers.Layer.Vector ...   // again, use var so it can be accessed by the page later

for( t = 0; t < taxis.length; t = t + 1 ){
    thisTaxi = new OpenLayers.Feature.Vector ....
    drivingLayer.addFeature ( thisTaxi );
    taxiMarkers.push ( thisTaxi  );   // adds the feature to the list
}
for( b = 0; b < buses.length; b = b + 1 ){
    thisBus = new OpenLayers.Feature.Vector ....
    drivingLayer.addFeature ( thisBus );
    busMarkers.push ( thisBus );  // adds the feature to the list
}
map.addLayer( drivingLayer );

Get rid of the LayerSwitcher control, because it will only show one layer.  You'll have to create your own in HTML and JavaScript.  This is a user-friendly way to create each check box:

<label>
    <img width="20" height="20" src="_Taxi_Icon.jpg"/>
    <input id="MyTaxiLayer" type="checkbox"/>
    Taxis
</label>
<hr/>

A <label> means someone can click any part of this line to change the checkbox.
The second line is an icon to represent your layer.  It should match the icon used on the map.
The third line is the checkbox itself, which should have a unique id.
The fourth line is the label the user sees for your checkbox.
The fifth line closes the label.
The sixth line uses <hr/> to draw a black horizontal line below this layer.  If you are going horizontally, use a | or other vertical boundary instead.

In JavaScript, set the initial state of your checkboxes to true (checked) or false (unchecked) depending on what layers are visible at the beginning, and tell it to switch layers when clicked

document.getElementById(  "MyTaxiLayer" ).checked = true;
document.getElementById"MyTaxiLayer" ).onclick function(){
         
ifdocument.getElementById"MyTaxiLayer" ).checked ){
             // user clicked to turn the box on
             pointLayer.addFeatures taxiMarkers );
        }
        else {
             // user clicked to turn the box off
             pointLayer.removeFeatures taxiMarkers );
        }
  }

 // repeat for other layers
document.getElementById( "MyBusLayer" ).checked = true;
...

If you're not familiar with HTML, you can set up two columns for your checkbox and map, using a table.
<table>
   <tr>
       <td>
             <!-- Checkboxes in left column -->
       </td>
       <td>
             <!-- map-div in right column -->
       </td>
   </tr>
</table>

I have a working example up at http://jsfiddle.net/UAxun/105/   in case you have trouble with adding the layer controls.