Defining custom rules to style features

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:

  • Having a symbolizer hash acting as the default style to apply to the features
  • Having some OpenLayers.Rule instances associated with it

Here 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:

Defining custom rules to style features

How to do it...

  1. Once created an HTML file with the OpenLayers dependencies, add the div element to hold the map:
    <div id="ch07_custom_rules" style="width: 100%; height: 95%;"></div>
  2. In the JavaScript code section, initialize the map, add OpenStreetMap as the base layer, and center the map at the desired place:
    <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);
  3. Now, define five different rules to style elements based on the 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"
            }
        });
  4. The following code has the rule to check if the value is between 10,000 and 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"
            }
        });
  5. The rule to check if the value is between 25,000 and 50,000:
        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"
            }
        });
  6. The rule to check if the value is between 50,000 and 100,000:
        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"
            }
        });
  7. And finally, the rule to check for values greater than 100,000:
        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"
            }
        });
  8. Create the style with the customary rules defined previously:
        var style = new OpenLayers.Style();
        style.addRules([aRule, bRule, cRule, dRule, eRule]);
  9. Finally, create a vector layer that loads the GML file and uses the previous style:
        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>

How it works...

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()]
    }));

Note

We have created an OpenLayers.StyleMap instance passing only one style and not a style for each desired render intent. This means there will be no render intents in the layer, or expressed in other words, all the render intents will be rendered with the same style.

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);

There's more...

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]
    });

See also

  • The Working with unique value rules recipe
  • The Styling features using symbolizers recipe
  • The Improving style using StyleMap and the replacement of feature's attributes recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.26.217