Styling point data¶
Point data in SLD can be depicted with PointSymbolizer
and labelled with TextSymbolizer
.
This section describe an existing, realistic style, available in the data directory that depicts the point landmarks layer (bptlandmarks
) with icons and labels.
The dataset¶
The bptlandmarks
layer (Boulder point landmarks) contains the location of significant point entities such as malls, schools, airports and the like. The attribute structure is reported in the GeoServer page for such layer as in the figure below:
The style will use the MTFCC
code to categorize the various points in the different types (e.g., schools have MTFCC = K2543
, and eventually use FULLNAME
for the label).
This results in the following map:
The complete style we’ll be referring to is named point_landmark
, you can have a look at the full style in the GeoServer style editor:
Point symbolizers¶
A point symbolizer depicts a symbol by means of a Mark
or an External Graphic
.
The former is a built-in vector symbol that can be stroked and filled at the styler’s will, but only a handful of such symbols are available, whilst the latter can be a user-provided image or SVG graphic.
The point landmark styles use the Open Street Map icons for most of the locations. The images have been added inside the data directory, inside styles/img
, since this allows to refer them by relative path:
Given the above symbols, a point symbolizer looks as follows:
<sld:PointSymbolizer>
<sld:Graphic>
<sld:ExternalGraphic>
<sld:OnlineResource xlink:type="simple" xlink:href="./img/landmarks/school.png" />
<sld:Format>image/png</sld:Format>
</sld:ExternalGraphic>
</sld:Graphic>
<VendorOption name="labelObstacle">true</VendorOption>
</sld:PointSymbolizer>
The icon is depicted on the screen as-is, at its natural resolutions.
The labelObstacle
vendor parameter, specific to GeoServer, makes sure the point icon is treated as a label obstacle. That means it makes sure no label will ever be depicted over the point.
Text symbolizers for points¶
The text symbolizer associates a label with a point using an attribute value as the label source. The following symbolizer is used to label schools:
<sld:TextSymbolizer>
<sld:Label>
<ogc:PropertyName>FULLNAME</ogc:PropertyName>
</sld:Label>
<sld:Font>
<sld:CssParameter name="font-family">Arial</sld:CssParameter>
<sld:CssParameter name="font-size">12.0</sld:CssParameter>
<sld:CssParameter name="font-style">normal</sld:CssParameter>
<sld:CssParameter name="font-weight">normal</sld:CssParameter>
</sld:Font>
<sld:LabelPlacement>
<sld:PointPlacement>
<sld:AnchorPoint>
<sld:AnchorPointX>
<ogc:Literal>0.5</ogc:Literal>
</sld:AnchorPointX>
<sld:AnchorPointY>
<ogc:Literal>1.0</ogc:Literal>
</sld:AnchorPointY>
</sld:AnchorPoint>
<sld:Displacement>
<sld:DisplacementX>
<ogc:Literal>0.0</ogc:Literal>
</sld:DisplacementX>
<sld:DisplacementY>
<ogc:Literal>-10.0</ogc:Literal>
</sld:DisplacementY>
</sld:Displacement>
<sld:Rotation>
<ogc:Literal>0.0</ogc:Literal>
</sld:Rotation>
</sld:PointPlacement>
</sld:LabelPlacement>
<sld:Halo>
<sld:Radius>
<ogc:Literal>1.5</ogc:Literal>
</sld:Radius>
<sld:Fill>
<sld:CssParameter name="fill">#FFFFFF</sld:CssParameter>
</sld:Fill>
</sld:Halo>
<sld:Fill>
<sld:CssParameter name="fill">#000033</sld:CssParameter>
</sld:Fill>
<sld:Priority>200000</sld:Priority>
<sld:VendorOption name="autoWrap">100</sld:VendorOption>
</sld:TextSymbolizer>
Highlights about the above style:
- Uses
FULLNAME
as the label source - Uses a Arial 12pt font
- Places the label below the point and offsets it by 10 pixel to the south
- Applies a white halo to make it stand out of the background map
- Sets its priority to 200000 (high, important) to make sure the label is depicted in preference to others
- Uses the
autoWrap
option to make it wrap on the next line if it’s larger than 100 pixels (the full list of labelling vendor options is available in the GeoServer user guide).
Using Rules to assign a different styling to each point¶
A Rule is a SLD construct allowing the style editor to control scale dependencies and filter data so that only certain data is depicted using the symbolizers contained in the rule.
The rule for the school points looks as follows:
<sld:Rule>
<sld:Name>school</sld:Name>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>MTFCC</ogc:PropertyName>
<ogc:Literal>K2543</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<sld:MaxScaleDenominator>100000</sld:MaxScaleDenominator>
<sld:PointSymbolizer>
<!-- same as above -->
</sld:PointSymbolizer>
<sld:TextSymbolizer>
<!-- same as above -->
</sld:TextSymbolizer>
</sld:Rule>
Highlights about the above rule:
- makes sure the symbolizers are applied only to the features whose
MTFCC = K2543
- shows the symbols only when the scale denominator is below 100000 (e.g., shows them at 1:10000, but not at 1:2000000).
Using dynamic symbolizers to reduce the style size¶
The overall point_landmark
style has 8 different rules using different symbols for each type and amounts to almost 550 lines of XML. The same style could be written in a much more compact way if we could store the symbol name in some attribute and expand it in the external graphic URL.
Standard SLD 1.0 does not allow for that, but GeoServer supports extensions to it known as dynamic symbolizers that allow for generic CQL expressions to be embedded in the URL.
The data directory already contains a secondary layer, bptlandmarks_2876
, which is using a different projection and has an IMAGE
attribute containing the file names.
The style can then be reduced to a single rule using the following point symbolizer:
<sld:PointSymbolizer>
<sld:Graphic>
<sld:ExternalGraphic>
<sld:OnlineResource xlink:type="simple" xlink:href="./img/landmarks/${IMAGE}" />
<sld:Format>image/png</sld:Format>
</sld:ExternalGraphic>
</sld:Graphic>
<VendorOption name="labelObstacle">true</VendorOption>
</sld:PointSymbolizer>
Here is the overall style:
<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor
xmlns="http://www.opengis.net/sld"
xmlns:sld="http://www.opengis.net/sld"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0.0">
<sld:UserLayer>
<sld:LayerFeatureConstraints>
<sld:FeatureTypeConstraint/>
</sld:LayerFeatureConstraints>
<sld:UserStyle>
<sld:Name>tl 2010 08013 pointlm</sld:Name>
<sld:Title/>
<sld:FeatureTypeStyle>
<sld:Rule>
<sld:Name>landmarks</sld:Name>
<ogc:Filter>
<ogc:Not>
<ogc:PropertyIsNull>
<ogc:PropertyName>IMAGE</ogc:PropertyName>
</ogc:PropertyIsNull>
</ogc:Not>
</ogc:Filter>
<sld:MaxScaleDenominator>100000</sld:MaxScaleDenominator>
<sld:PointSymbolizer>
<sld:Graphic>
<sld:ExternalGraphic>
<sld:OnlineResource xlink:type="simple" xlink:href="./img/landmarks/${IMAGE}" />
<sld:Format>image/png</sld:Format>
</sld:ExternalGraphic>
</sld:Graphic>
<VendorOption name="labelObstacle">true</VendorOption>
</sld:PointSymbolizer>
<sld:TextSymbolizer>
<sld:Label>
<ogc:PropertyName>FULLNAME</ogc:PropertyName>
</sld:Label>
<sld:Font>
<sld:CssParameter name="font-family">Arial</sld:CssParameter>
<sld:CssParameter name="font-size">12.0</sld:CssParameter>
<sld:CssParameter name="font-style">normal</sld:CssParameter>
<sld:CssParameter name="font-weight">normal</sld:CssParameter>
</sld:Font>
<sld:LabelPlacement>
<sld:PointPlacement>
<sld:AnchorPoint>
<sld:AnchorPointX>
<ogc:Literal>0.5</ogc:Literal>
</sld:AnchorPointX>
<sld:AnchorPointY>
<ogc:Literal>1.0</ogc:Literal>
</sld:AnchorPointY>
</sld:AnchorPoint>
<sld:Displacement>
<sld:DisplacementX>
<ogc:Literal>0.0</ogc:Literal>
</sld:DisplacementX>
<sld:DisplacementY>
<ogc:Literal>-14.0</ogc:Literal>
</sld:DisplacementY>
</sld:Displacement>
<sld:Rotation>
<ogc:Literal>0.0</ogc:Literal>
</sld:Rotation>
</sld:PointPlacement>
</sld:LabelPlacement>
<sld:Halo>
<sld:Radius>
<ogc:Literal>1.5</ogc:Literal>
</sld:Radius>
<sld:Fill>
<sld:CssParameter name="fill">#FFFFFF</sld:CssParameter>
</sld:Fill>
</sld:Halo>
<sld:Fill>
<sld:CssParameter name="fill">#000033</sld:CssParameter>
</sld:Fill>
<sld:Priority>200000</sld:Priority>
<sld:VendorOption name="autoWrap">100</sld:VendorOption>
</sld:TextSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:UserLayer>
</sld:StyledLayerDescriptor>
Note
Using CSS the style is even shorter:
[@scale < 200000] {
mark-mime: 'image/png';
-gt-mark-label-obstacle: true;
label: [FULLNAME];
label-anchor: 0.5 1.0;
label-offset: 0.0 -14.0;
label-rotation: 0.0;
font-fill: #000033;
font-family: Arial;
font-size: 12;
font-style: normal;
font-weight: normal;
halo-color: #FFFFFF;
halo-radius: 1.5;
-gt-label-priority: 200000;
-gt-label-auto-wrap: 100;
mark: url('./img/landmarks/${IMAGE}');
}
And here is a map using this alternate style: