This is the P2PU Archive. If you want the current site, go to www.p2pu.org!
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:
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:false, type: google.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 ] );
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:
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(){
if( document.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.