| Version 5 (modified by ahocevar, 5 years ago) |
|---|
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 an elegant 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.extend(
{fillColor: "green", fillOpacity: 1, strokeColor: "black"},
OpenLayers.Feature.Vector.style["default"]);
var layer = new OpenLayers.Layer.Vector("points", {styleMap: styleMap});
Ok, not imprssive 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.extend(
{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 StyleHash 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 style, based on the symbolizer from above
var style = new OpenLayers.Style(symbolizer);
var ruleSmall = new OpenLayers.Rule.Comparison({
type: OpenLayers.Rule.Comparison.EQUAL_TO,
property: "size",
value: "small",
symbolizer: {"Point": {pointRadius: 10}}});
var ruleLarge = new OpenLayers.Rule.Comparison({
type: OpenLayers.Rule.Comparison.EQUAL_TO,
property: "size",
value: "large",
symbolizer: {"Point": {pointRadius: 20}}});
style.addRules([ruleSmall, ruleLarge]);
vectorLayer.styleMap.styles["default"] = style;
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.
Every rule can have separate symbolizers for "Point", "Line" and "Polygon". In the above example, we only used one ("Point"). The symbolizers inside rules do not have to be complete symbolizers, because they extend the default symbolizer passed with the constructor of OpenLayers.Style.
In the example, we only used the Comparison rule, and only its subtype EQUAL_TO. 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.
