wiki:Styles

OpenLayers 2 is outdated. Go to the latest 3.x version: http://openlayers.org/

The OpenLayers Styles Framework

This page describes the styling functionality for vector layers proposed in #1120 and #1183, which is available in trunk and in OpenLayers 2.6. While the plain old style hashes (we still use them as symbolizers) were basically a feature property, the new StyleMap object is a layer property. Major improvements of styling itself include rule-based styles and property styles, based on a Style object. The framework was originally created for rendering features with styles from a SLD document (#533), but it should cover most use cases people might have when it comes to telling vector features or layers how they should look on the map. However, for complex styling, SLD (Styled Layer Descriptor) provides a way to define the styles.

Basics

The entry point to styling is the StyleMap object, which is used for the styleMap property of a vector layer. The idea of a style map is that features of a layer can be drawn with various intents, e.g. display (intent "default"), selected features (intent "select"), or feature editing (intent "temporary", currently unused). Other than with plain symbolizers, where e.g. OpenLayers.Control.SelectFeature has a selectStyle property, this is now all provided by the styleMap of the layer.

By default, a layer has a style map with the intents "default", "select" and "temporary". The symbolizers for those styles are identical to the symbolizers defined in OpenLayers.Layer.Vector.style. The styles apply to all features.

If we just want to have all our point features styled as green dots, we could simply create a vector layer with a StyleMap like this:

var styleMap = new OpenLayers.StyleMap(OpenLayers.Util.applyDefaults(
        {fillColor: "green", fillOpacity: 1, strokeColor: "black"},
        OpenLayers.Feature.Vector.style["default"]));
var layer = new OpenLayers.Layer.Vector("points", {styleMap: styleMap});

Ok, not impressive you might say. A simple style hash as property of the layer from which all features would inherit gave me the same result. But wait:

Using PropertyStyles

With the new style object, we can calculate a style specific to a feature. Let's say we have a point feature with attributes, one of it named "thumbnail". This attribute holds the name of an image that should be rendered at the point location. The ${value} thing means: replace ${value} by the value found in the "value" attribute of the feature's attributes hash. Also, if we select a feature, it should be drawn larger, so we know that it is selected:

var symbolizer = OpenLayers.Util.applyDefaults(
        {externalGraphic: "images/${thumbnail}.png", pointRadius: 20},
        OpenLayers.Feature.Vector.style["default"]);
var styleMap = new OpenLayers.StyleMap({"default": symbolizer, "select": {pointRadius: 30}});
var vectorLayer = new OpenLayers.Layer.Vector("thubms", {styleMap: styleMap});
...
vectorLayer.features[0].attributes.thumbnail="sight";
vectorLayer.features[1].attributes.thumbnail="bar";

The "default" intent has a special role: if the extendDefault property of the StyleMap is set to true (default), symbolizers calculated for other render intents will extend the symbolizer calcualated for the "default" intent. So if we want selected features just to have a different size or color, we only have to set a single property (in this example: pointRadius).

Something similar applied to a GeoRSS feed from Flick is shown in the georss-flickr example: The items of the feed are displayed with thumbnail versions of the image at their position. You might notice that some images are already larger than others, without being selected. This is the next benefit of the new styles:

Rule-based Styling

Until now, we were only using simple symbolizers. To get an even more exciting styling experience, we can use the Style object and rules. Let's create a style with two rules, and apply it to the vector layer from above. We will also add a new "size" property to our features, so we can see the difference:

// create a new styleMap, based on the symbolizer from above
var styleMap = new OpenLayers.StyleMap(symbolizer);

// create a mapping between feature attribute and symbolizer
var lookup = {
    "small": {pointRadius: 10},
    "large": {pointRadius: 30}
}

// add rules to the default symbolizer that check for the "size"
// attribute and apply the symbolizer defined in lookup
styleMap.addUniqueValueRules("default", "size", lookup);

vectorLayer.features[0].attributes.size="small";
vectorLayer.features[1].attributes.size="large";

vectorLayer.redraw();

If we redraw our layer now, we will see that the thumbnails have a differnt size, because different rules with a different pointRadius in their symolizer applied.

The symbolizers inside rules do not have to be complete symbolizers, because they extend the default symbolizer passed with the constructor of OpenLayers.Style or OpenLayers.StyleMap.

http://www.openlayers.org/dev/examples/styles-unique.html shows something similar in action.

Advanced Rule-based Styling

Every rule can have separate symbolizers for "Point", "Line" and "Polygon". In the above example, we did not care and just defined a default symbolizer.

If we want to define a different style for a point and a line feature, our lookup from the above example could look like this:

var lookup = {
    "small": {"Point": {pointRadius: 10}, "Line": {strokeWidth: 3}}
    "large": {"Point": {pointRadius: 30}, "Line": {strokeWidth: 5}}
}

In the above example, we did not create rules ourselves, but used the addUniqueValueRules() convenience function. Now how do we work with rules directly?

The addUniqueValueRules() in the example created two Comparison rules, with the EQUAL_TO operator. Let's do another example and style features according to a range of a feature attribute. For this we use the LESS_THAN and GREATER_THAN_OR_EQUAL_TO operators of the Comparison rule:

vectorLayer.features[0].attributes.amount=10;
vectorLayer.features[1].attributes.amount=20;

var style = new OpenLayers.Style();

var ruleLow = new OpenLayers.Rule(
    {
        filter: new OpenLayers.Filter.Comparison(
            {
                type: OpenLayers.Filter.Comparison.LESS_THAN,
                property: "amount",
                value: 20,
            }),
        symbolizer: {pointRadius: 10, fillColor: "green", fillOpacity: 0.5, strokeColor: "black"}
    });
var ruleHigh = new OpenLayers.Rule(
    {
        filter: new OpenLayers.Filter.Comparison(
            {
                type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO,
                property: "amount",
                value: 20,
            }),
        symbolizer: {pointRadius: 20, fillColor: "red", fillOpacity: 0.7, strokeColor: "black"}
    });

style.addRules([ruleLow, ruleHigh]);

There are other subtypes, like LESS_THAN, BETWEEN or LIKE. And there are other rule types, with FeatureId being the simplest. A FeatureId rule holds an array of feature ids (fid) that it will apply to. There is also the Logical rule, which allows building more complex rules by concatenating them using boolean operators (AND, OR, NOT). A Logical rule (except NOT) can have child rules.

Every rule can also have a minScaleDenominator and a maxScaleDenominator property. This allows us to specify scale ranges for which the rule should apply. We might e.g. want to show small points at small scales, but image thumbnails at large scales. The result of such rules can be seen in the sld example: Zooming in one level will turn two lakes into blue. The styles and rules from this example do not come from javascript-created style and rule objects, but from a SLD document read in by OpenLayers.Format.SLD (#533).

With SLD, styles are grouped into named layers (NamedLayer), which again have a set of named user styles (UserStyle). This is the reason why the Style object also has layerName and name properties. For each named layer, there can be a default style. This is marked by setting the isDefault property of the Style object to true.

Style Editor Add-in

A proposal for a Style Editor Add-in using the new styles framework has been made.

Last modified 4 months ago Last modified on May 20, 2016 1:08:48 AM