We will see a brief explanation before continuing with this recipe. The goal, as in the other recipes in the chapter, is to style the features of a vector layer depending on their attributes' values or their kind of feature.
So, an OpenLayers.Layer.Vector
layer class can have an OpenLayers.StyleMap
instance associated with it, which determines the default style of the layers if it has only one OpenLayers.Style
, or the set of styles that can be applied for each render intent if it contains more than one OpenLayers.Style
. In its own way, each OpenLayers.Style
instance can be used in two forms:
OpenLayers.Rule
instances associated with itHere we arrive to the main concept of this recipe, the rules.
A rule is nothing more than a join between a filter (concretely an OpenLayers.Filter
) and a symbolizer, if the filter matches the feature then the symbolizer is applied.
This simple thing gives us lot of flexibilities and power to style our features. In addition to the possibility to use symbolizers with attribute replacement, we can also use the set of filters OpenLayers offers us: comparison filters, spatial filters, or logical filters.
The goal of this recipe is to load a GML file with European countries and style them depending on their AREA
attribute, as shown in the folloing screenshot:
div
element to hold the map:<div id="ch07_custom_rules" style="width: 100%; height: 95%;"></div>
<script type="text/javascript"> // Create the map using the specified DOM element var map = new OpenLayers.Map("ch07_custom_rules"); var osm = new OpenLayers.Layer.OSM(); map.addLayer(osm); map.setCenter(new OpenLayers.LonLat(40,50).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), 3);
AREA
attribute of the features. The following code has the rule to check if the value is less than 10,000:var aRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN, property: "AREA", value: 10000 }), symbolizer: { fillColor: "#EBC137", fillOpacity: 0.5, strokeColor: "black" } });
var bRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.AND, filters: [ new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN, property: "AREA", value: 10000 }), new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, property: "AREA", value: 25000 }) ] }), symbolizer: { fillColor: "#E38C2D", fillOpacity: 0.7, strokeColor: "black" } });
var cRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.AND, filters: [ new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN, property: "AREA", value: 25000 }), new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, property: "AREA", value: 50000 }) ] }), symbolizer: { fillColor: "#DB4C2C", fillOpacity: 0.7, strokeColor: "black" } });
var dRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.AND, filters: [ new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN, property: "AREA", value: 50000 }), new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, property: "AREA", value: 100000 }) ] }), symbolizer: { fillColor: "#771E10", fillOpacity: 0.7, strokeColor: "black" } });
var eRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, property: "AREA", value: 100000 }), symbolizer: { fillColor: "#48110C", fillOpacity: 0.7, strokeColor: "black" } });
var style = new OpenLayers.Style(); style.addRules([aRule, bRule, cRule, dRule, eRule]);
map.addLayer(new OpenLayers.Layer.Vector("World Cities (GeoJSON)", { protocol: new OpenLayers.Protocol.HTTP({ url: "http://localhost:8080/openlayers-cookbook/recipes/data/europe.gml", format: new OpenLayers.Format.GML() }), styleMap: new OpenLayers.StyleMap(style), strategies: [new OpenLayers.Strategy.Fixed()] })); </script>
As we described at the beginning of the recipe, an OpenLayers.Style
instance admits a set of OpenLayers.Rule
instances to style the features.
Given a rule, all the features that match the specified OpenLayers.Filter
are styled with the specified symbolizer hash, and thanks to the filters, we have enough flexibility to create the comparison or logical filters.
In the code, we have created five filters. Let's describe two of them.
The aRule
rule is formed by a comparison filter that matches all the features with an AREA
attribute having a value less than 10,000:
var aRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN, property: "AREA", value: 10000 }), symbolizer: { fillColor: "#EBC137", fillOpacity: 0.5, strokeColor: "black" } });
The bRule
uses a more complex rule. In this case, it is a logical AND
filter composed of two comparison filters. It matches all the features to check whether their AREA
attribute is greater than 10,000 and less than or equal to 25,000:
var bRule = new OpenLayers.Rule({ filter: new OpenLayers.Filter.Logical({ type: OpenLayers.Filter.Logical.AND, filters: [ new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.GREATER_THAN, property: "AREA", value: 10000 }), new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, property: "AREA", value: 25000 }) ] }), symbolizer: { fillColor: "#E38C2D", fillOpacity: 0.7, strokeColor: "black" } });
Once we have created all the desired rules, we can create an OpenLayers.Style
instance:
var style = new OpenLayers.Style(); style.addRules([aRule, bRule, cRule, dRule, eRule]);
Then apply it to the vector layer:
map.addLayer(new OpenLayers.Layer.Vector("World Cities (GeoJSON)", { protocol: new OpenLayers.Protocol.HTTP({ url: "http://localhost:8080/openlayers-cookbook/recipes/data/europe.gml", format: new OpenLayers.Format.GML() }), styleMap: new OpenLayers.StyleMap(style), strategies: [new OpenLayers.Strategy.Fixed()] }));
Because the vector layer must read data from a GML file in our server, we have made use of an OpenLayers.Protocol.HTTP
instance that loads files from the specified URL and uses an instance in the OpenLayers.Format.GML
format to read it.
Finally, to center the map's viewport, we needed to transform the coordinates.
Because the base layer of the map is OpenStreetMap, this makes the map's projection to become EPSG:900913, while we are specifying the center location as latitude/longitude using the EPSG:4326. Because of this we need to make a transformation:
map.setCenter(new OpenLayers.LonLat(40,50).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), 3);
In our code, we have created the style with the sentences:
var style = new OpenLayers.Style(); style.addRules([aRule, bRule, cRule, dRule, eRule]);
But the OpenLayers.Style
constructor can accept two parameters: a symbolizer hash, to be used as the default style, and a set of options where we need to specify instance properties. With this in mind we can also instantiate the style as:
var style = new OpenLayers.Style({ our_default_style }, { rules: [aRule, bRule, cRule, dRule, eRule] });
18.227.26.217