GeoServer Blog
Styling GeoServer Layers with CSS
GeoServer users have a lot to wrap their heads around. We need to optimize our servlet containers, determine projections for all those broken shapefiles, and remember to fill out layer metadata. One issue in particular that comes up again and again is difficulty with creating SLD files to style maps. It is hardly surprising that map designers fail to take advantage of some of the niftier rendering tricks that Andrea cooks up. Styler, a graphical SLD editing application that OpenGeo has been developing, is one approach to making SLD creation more palatable. But just as experienced web designers often feel limited by WYSIWYG environments, advanced users will always have a use for manual, text-based editing. Unfortunately, the highly structured, verbose nature of XML can make this strenuous.
With this in mind, I’ve been working on an extension to GeoServer allowing styling of map layers with a CSS-type syntax. This work follows in the footsteps of tools like Cartagen and Cascadenik which both apply a CSS framework to map styling.
To see how a CSS map style would look, compare the “simpleRoads” SLD from the data directory that ships with GeoServer:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name>Simple Roads</Name>
<UserStyle>
<Title>Default Styler for simple road segments</Title>
<Abstract>Light red line, 2px wide</Abstract>
<FeatureTypeStyle>
<Rule>
<Title>Roads</Title>
<LineSymbolizer>
<Stroke>
<CssParameter name="stroke">
<ogc:Literal>#AA3333</ogc:Literal>
</CssParameter>
<CssParameter name="stroke-width">
<ogc:Literal>2</ogc:Literal>
</CssParameter>
</Stroke>
</LineSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
with the equivalent CSS style:
/* @title Default styler for simple road segments
* @abstract Light red line, 2px wide
*/
* {
stroke: #AA3333;
stroke-width: 2px;
}
CSS styles are fully converted to SLD before GeoServer uses them for rendering, so the resulting SLDs can be migrated directly to other GeoServer instances, even if they don’t have the CSS extension installed. Filter functions, zoom-based styling rules, and geometry transformations are also available.
You can download the CSS extension from the nightly build server and add it to your existing GeoServer instance (2.0.0 and later only). Installation instructions are available in the CSS tutorial. All the features of the CSS extension are documented in the CSS section of the User Manual. I encourage everyone to check it out!
Extending your map styling with geometry transformations
When designing a map, sometimes you want to render something that is related to the geometries you have at hand, but which is not specifically the geometries themselves. Maybe you want to highlight the end of a line, create a drop shadow effect, or make the vertices that make up a geometry more evident to the user. Unfortunately the SLD specification that GeoServer uses for its rendering does not allow you to dynamically extract such information. If you need to achieve those effects, you will usually need to generate a new layer by preprocessing your data offline (for example, using PostGIS’s excellent spatial analysis functions).
Today I’m going to show you how to achieve those effects dynamically using what we call geometry transformations. Geometry transformations are yet another extension to SLD in order to make it more powerful. (Another example of SLD an extension that GeoServer has implemented is dynamic symbolizers.) Standard SLD allows the user to specify a <Geometry>
element in each symbolizer, but its contents can only be a <PropertyName>
; this allows a user to choose a different geometry should a spatial table contain more than one. With geometry transformations, GeoServer allows you to specify a filter function as well, which can transform the geometry. (You may want to refer to my previous post on filter functions.)
Let’s look at an example. Say we have a building layer, rendered with a plain gray fill:
We can add a twist to this plain map by adding a drop shadow beneath the buildings layer. To achieve this we will offset the buildings a bit, fill them dark gray, and then paint the standard buildings layer on top of it. The style looks like:
<FeatureTypeStyle>
<Rule>
<Title>Shadow</Title>
<PolygonSymbolizer>
<Geometry>
<ogc:Function name="offset">
<ogc:PropertyName>the_geom</ogc:PropertyName>
<ogc:Literal>0.00004</ogc:Literal>
<ogc:Literal>-0.00004</ogc:Literal>
</ogc:Function>
</Geometry>
<Fill>
<CssParameter name="fill">#555555</CssParameter>
</Fill>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
<FeatureTypeStyle>
<Rule>
<Title>Polygon</Title>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">#CCCCCC</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#000000</CssParameter>
<CssParameter name="stroke-width">0.5</CssParameter>
</Stroke>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
And the result is:
The filter function takes the geometries and offsets them by (0.00004, -0.00004). Geometry transformations occur against the original geometry, which in this particular case is in EPSG:4326, so the values of the offset are also in units of lon/lat.
You can find more examples about this functionality in the geometry transformations section of the User Manual. You can also get creative by looking at the currently available set of filter functions. Also remember, if you want a function that’s not there, it is possible to add new ones; drop by on the developer mailing list and we’ll provide you with directions.
GeoServer continuous map wrapping!
GeoServer is now able to output maps that look like continuous wrapped maps from Google!
Let’s have a look at an example. Below is a map drawn by GeoServer that is reprojected to a projection that happens to sit across the dateline, the usual “edge” of the map. As you can see the reprojection is not doing a good job where the dateline is crossed:
However, GeoServer now has what is called advanced projection handling. With this enabled, the dateline wrapping is properly handled and, in addition, the map repeats in a continuous fashion:
For more information, including how to turn on this (optional) feature, please see this post from GeoSolutions.
GeoServer hidden treasures: filter functions
Ever had the need to format some text in SLD, or to perform complex filter in WFS, and noticed that the basic elements of the OGC Filter specification left you wanting for more?
If so, welcome to the club. One thing few people know is that both SLD and WFS filtering capabilities can be extended by using filter functions. A filter function is just like a programming language function, it’s something that takes arguments and returns some result. For example, “sin(toRadians(45))” will compute the mathematical sin of 45 degrees, and “strSubstring(“hippopotamus”, 0, 5)” will return “hippo”.
The concept of filter function is standardized, but functions themselves are not, so once you start using them you’re tied to a specific server. However they often provide the level of flexibility that you just need in order to get some work done. The good news is that GeoServer already contains tens of them, from number and date formatting, to geometry manipulation, math, string wrangling. So far we just never found the time to document them, but things have changed and we have now quite a complete reference along with some examples.
Let me show you a simple example of using functions. Say we have a contour map, each isoline has an elevation, and we want to show it on the map. Unfortunately the elevation is stored as a floating point, resulting in a less than pleasing output of “150.0” or sometimes “149.999999” when we know the elevation accuracy does not go beyond the meter. To get nice labelling we can use the “numberFormat” filter function to force an integer representation instead (along with some VendorOptions):
<TextSymbolizer>
<Label>
<ogc:Function name="numberFormat">
<ogc:Literal>#</ogc:Literal>
<ogc:PropertyName>ELEVATION</ogc:PropertyName>
</ogc:Function>
</Label>
....
<VendorOption name="followLine">true</VendorOption>
<VendorOption name="repeat">250</VendorOption>
<VendorOption name="maxDisplacement">150</VendorOption>
<VendorOption name="maxAngleDelta">30</VendorOption>
</TextSymbolizer>
Notice how the the ELEVATION field is formatted as an integer number following the simple formatting pattern provided (for a full reference see the the Java DecimalFormat documentation):
I hope you’ll find interesting and clever uses of the existing filter functions to improve the way you work with GeoServer. Next time I’ll show you my favourite one, which is also a new feature in GeoServer 2.0.1, called “geometry transformations”. Stay tuned to learn more about it.
REST Security Update for 1.7.x
A recent post describes a security issue with RESTful services in GeoServer that was fixed for GeoServer 2.0.1. A patch has been created for 1.7.x and is now available. Any users using the restconfig plugin with GeoServer 1.7 are urged to apply the patch.
Note that by applying the patch the same rules as described here apply. Users will have to either update systems that rely on anonymous access via GET operations or alternatively configure the security subsystem to allow them.
Tutorials
- Using Logical Operators in GeoServer Filters
- Exploring CQL/ECQL Filtering in GeoServer
- Using Spatial Operators in GeoServer Filters
- Using Value Comparison Operators in GeoServer Filters
- Using Binary Comparison Operators in GeoServer Filters
- Utilizing the Demo Section in Geoserver
- How to Implement Basic Security in Geoserver
- How to create Tile Layers with GeoServer
- How to style layers using GeoServer and QGIS
- How to Publish a GeoTIFF file in GeoServer