Share
Creating Stunning Maps in GeoServer: mastering SLD and CSS styles
Various software can style maps and generate a proper SLD document for OGC compliant WMS like GeoServer to use. However, in most occasions, the styling allowed by the graphical tools is pretty limited and not good enough to achieve good looking, readable and efficient cartographic output. For those that like to write their own styles CSS also represents a nice alternatives thanks to its compactness and expressiveness.
Several topics will be covered, providing examples in both SLD and CSS for each, including: mastering multi-scale styling, using GeoServer extensions to build common hatch patterns, line styling beyond the basics, such as cased lines, controlling symbols along a line and the way they repeat, leveraging TTF symbol fonts and SVGs to generate good looking point thematic maps, using the full power of GeoServer label lay-outing tools to build pleasant, informative maps on both point, polygon and line layers, including adding road plates around labels, leverage the labeling subsystem conflict resolution engine to avoid overlaps in stand alone point symbology, blending charts into a map, dynamically transform data during rendering to get more explicative maps without the need to pre-process a large amount of views.
The presentation aims to provide the attendees with enough information to master SLD/CSS documents and most of GeoServer extensions to generate appealing, informative, readable maps that can be quickly rendered on screen.
Simone Giannecchini PRO
Transcript
51 slides
-
Creating stunning maps with GeoServer With SLD, CSS, YSLD and
MBStyles Ing. Andrea Aime GeoSolutions 1 -
GeoSolutions ⚫ Founded in Italy in late 2006 ⚫ Expertise
• Image Processing, GeoSpatial Data Fusion • Java, Java Enterprise, C++, Python • JPEG2000, JPIP, Advanced 2D visualization ⚫ Supporting/Developing FOSS4G projects ⚫ GeoServer, MapStore ⚫ GeoNetwork, GeoNode, Ckan ⚫ Clients ⚫ Public Agencies ⚫ Private Companies ⚫ http://www.geo-solutions.it 2 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Languages SLD 1.0 core SLD 1.1 core YSLD extension MBStyles
community GeoCSS extension SLD 1.0 inspired object model, with extensions parse parse parse parse and translate parse and translate 4 Map rendering FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Shared concepts ⚫ Layer (the styles applies to) ⚫ Rules
⚫ Filters/selectors (what should be painted) ⚫ Scale dependencies (zoomed in, zoomed out?) ⚫ Symbolizers (how should it be painted) ⚫ Point ⚫ Line ⚫ Polygon ⚫ Text 5 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Styled Layer Descriptor 1.0 and 11 ⚫ The only OGC
standard ⚫ XML based, verbose, hard to hand edit, was meant for machine export but ended up being edited a lot by hand ⚫ Can be generated by external tools and imported ⚫ However interoperability is limited ⚫ Often needs to be hand tweaked 6 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
SLD 1.0 example <!–- Boilerplate beginning ommitted --> … <sld:Rule>
<ogc:Filter> <ogc:PropertyIsEqualTo> <ogc:PropertyName>type</ogc:PropertyName> <ogc:Literal>alpine_hut</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <sld:MaxScaleDenominator>100000.0</sld:MaxScaleDenominator> <sld:PointSymbolizer> <sld:Graphic> <sld:ExternalGraphic> <sld:OnlineResource xlink:type="simple" xlink:href="symbols/alpinehut.p.16.png"/> <sld:Format>image/png</sld:Format> </sld:ExternalGraphic> </sld:Graphic> </sld:PointSymbolizer> </sld:Rule> <!–- Boilerplate end ommitted --> Filter Scale dep. Symbolizer 7 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
YSLD ⚫ SLD in YAML syntax ⚫ Filtering by CQL
⚫ Can define reusable variables and blocks ⚫ Verbosity it’s between SLD and CSS ⚫ Has a notion of zoom levels, if needed feature-styles: - rules: - filter: type = 'alpine_hut' scale: (,100000.0) symbolizers: - point: symbols: - external: url: symbols/alpinehut.p.16.png format: image/png 8 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
GeoCSS ⚫ Compact syntax, familiar for web developers ⚫ CQL
based filtering, rule nesting and cascading keeps complex styling compact (you just express the overrides to the base) ⚫ The only style language with auto-complete in the style editor ⚫ Does not get any more compact than this: ⚫ Cons: some are confused by “rule cascading” [type = 'alpine_hut'][@sd < 100k] { mark: url('symbols/alpinehut.p.16.png'); } 9 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
MBStyles (aka MapBox GL) ⚫ Whole different beast ⚫ JSON
based, designed for GUI editing (like SLD) instead of hand editing ⚫ Only zoom level based scale control ⚫ Symbols coming from “sprites” (symbol collections) ⚫ Pro: can be applied both on the client side and the server side 10 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
MBStyles (aka MapBox GL) { "version": 8, … boilerplate omitted
here "name": "mountain huts", "sprite": "https://my.sever/sprite", "layers": [ { "id": "huts", "type": "symbol", "minzoom": 9, "filter": [ "==", "type", "alpine_hut" ], "layout": { "icon-image": "alpinehut", "icon-size": 1, "icon-allow-overlap": true } } ] } Filter (in postfix notation!) Scale dep. Symbolizer The sprint contains various images, like in videogames 11 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
What’s next ⚫ Going to explore styling concepts ⚫ Languages
used in examples ⚫ SLD 1.0 + GS extensions ⚫ YSLD ⚫ GeoCSS YSLD SLD CSS 12 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Types of Scale dependency ⚫ Decide whether to symbolize based
on the scale or not ⚫ E.g., at lower scales/lower zoom levels do not show buildings ⚫ Symbolize in a different way depending on the scale ⚫ E.g., different thickness based on the current zoom 14 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Expressing scale dependency filters ⚫ SLD: ⚫ <MinScaleDenominator> 1000 </MinScaleDenominator>
⚫ <MaxScaleDenominator> 1000000 </MaxScaleDenominator> ⚫ CSS ⚫ [@sd > 1k][@sd < 1M] ⚫ Compact expression of large numbers makes them readable at a glance, e.g., 100k, 1M ⚫ YSLD: ⚫ scale: (1000, 1000000) ⚫ scale: (1e3, 1e6) ⚫ zoom: (8, 16) grid: name: WGS84 15 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Unit of Measure ⚫ Useful if you have real world
measures of line thicknesses and the like … <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre"> <Stroke> <CssParameter name="stroke">#0000FF</CssParameter> <CssParameter name="stroke-width">5</CssParameter> </Stroke> </LineSymbolizer> ... … stroke: blue; stroke-width: 5m; … line: stroke-color: '#0000FF' uom: metre; stroke-width: '5'; SLD YSLD CSS 16 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Transformation functions ⚫ Another way of setting a different value
depending on the current scale/zoom level ⚫ Useful if the scaling is not linear [class = 'highway’ and type in ('motorway’, 'motorway_link’)] [@sd < 25M] { stroke: #e66e89; stroke-width: categorize(@sd, 2, 400k, 1.9, 800k, 1.4, 1.5M, 1, 3M, 0.8, 6M, 0.5); ⚫ Less than 400k → 2px ⚫ [400k, 800k] → 1.9px ⚫ [800k, 1.5M] → 1.4px ⚫ [1.5M, 3M] → 1 ⚫ [3M, 6M] → 0.8 ⚫ Above 6M -> 0.5 CSS 17 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Transformation functions in SLD <sld:LineSymbolizer> <sld:Stroke> <sld:CssParameter name="stroke">#e66e89</sld:CssParameter> <sld:CssParameter name="stroke-width">
<ogc:Function name="Categorize"> <ogc:Function name="env"> <ogc:Literal>wms_scale_denominator</ogc:Literal> </ogc:Function> <ogc:Literal>2</ogc:Literal> <ogc:Literal>400000</ogc:Literal> <ogc:Literal>1.9</ogc:Literal> <ogc:Literal>800000</ogc:Literal> <ogc:Literal>1.4</ogc:Literal> <ogc:Literal>1500000</ogc:Literal> <ogc:Literal>1</ogc:Literal> <ogc:Literal>3000000</ogc:Literal> <ogc:Literal>0.8</ogc:Literal> <ogc:Literal>6000000</ogc:Literal> <ogc:Literal>0.5</ogc:Literal> </ogc:Function> </sld:CssParameter> </sld:Stroke> </sld:LineSymbolizer> SLD 18 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Simple image [type = 'alpine_hut'][@sd < 100k] { mark: url('symbols/alpinehut.p.16.png');
} <sld:Rule> <ogc:Filter> <ogc:PropertyIsEqualTo> <ogc:PropertyName>type</ogc:PropertyName> <ogc:Literal>alpine_hut</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <sld:MaxScaleDenominator>100000.0</sld:MaxScaleDenominator> <sld:PointSymbolizer> <sld:Graphic> <sld:ExternalGraphic> <sld:OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="symbols/alpinehut.p.16.png"/> <sld:Format>image/png</sld:Format> </sld:ExternalGraphic> </sld:Graphic> </sld:PointSymbolizer> </sld:Rule> SLD CSS 20 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Marks (SVG in this case) [type = 'bank'][@sd < 6k]
{ mark: symbol('file://symbols/bank.svg'); :mark { fill: #734a08 }; mark-size: 14; } feature-styles: - rules: - filter: type = 'bank' scale: (,6000.0) symbolizers: - point: symbols: - mark: shape: file://symbols/bank.svg fill-color: ! '#734a08' size: 14 YSLD CSS 21 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Marks composition and override [type = 'fountain’] { [@sd <
6k] { mark: symbol(circle), symbol(circle); :nth-mark(1) { fill: #b5d0d0 }; :nth-mark(2) { fill: #576ddf }; mark-size: 10, 3; }; [@sd < 3k] { mark: symbol('file://symbols/fountain.svg'); :mark { fill: #576ddf; }; } } CSS 22 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
⚫ Many other options! ⚫ Built-in symbol names (well known
marks): circle, square, triangle, … ⚫ From TTF fonts using the name ttf://<fontname>#charcode ⚫ Windbarbs, e.g.: windbarbs://default(15)[kts] ⚫ WKT specification, e.g. wkt://MULTILINESTRING((-0.25 -0.25, -0.125 -0.25), (0.125 - 0.25, 0.25 -0.25), (-0.25 0.25, -0.125 0.25), (0.125 0.25, 0.25 0.25)) ⚫ See more here: http://docs.geoserver.org/latest/en/user/styling/sld/exte nsions/pointsymbols.html Other mark options 23 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Solid filling * { fill: lightgrey; stroke: black; stroke-width: 0.5;
} <sld:PolygonSymbolizer> <sld:Fill> <sld:CssParameter name="fill">#d3d3d3</sld:CssParameter> </sld:Fill> <sld:Stroke> <sld:CssParameter name="stroke-width">0.5</sld:CssParameter> </sld:Stroke> </sld:PolygonSymbolizer> SLD CSS 25 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Filling with repeating images fill [@sd < 800k][type in ('cemetery',
'grave_yard')] { fill: #aacbaf; [@sd < 50k] { [religion = 'jewish'] { fill: #aacbaf, url('symbols/grave_yard_jewish.png'); }; [religion = 'christian'] { fill: #aacbaf, url('symbols/grave_yard_christian.png'); }; [religion = 'INT-generic'] { fill: #aacbaf, url('symbols/grave_yard_generic.png'); }; }; } CSS 26 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Filling with repeating images (YSLD) feature-styles: - rules: - filter:
type IN ('cemetery','grave_yard') scale: (,800000.0) symbolizers: - polygon: fill-color: ! '#aacbaf' - filter: (type IN ('cemetery','grave_yard')) AND religion = 'jewish' scale: (,50000.0) symbolizers: - polygon: fill-graphic: symbols: - external: url: symbols/grave_yard_jewish.png format: image/png # continues in the next slide First uniform background fill Then foreground symbols for various religions YSLD 27 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Filling with repeating images (YSLD) - filter: (type IN ('cemetery','grave_yard'))
AND religion = 'christian' scale: (,50000.0) symbolizers: - polygon: fill-graphic: symbols: - external: url: symbols/grave_yard_christian.png format: image/png - filter: (type IN ('cemetery','grave_yard')) AND religion = 'INT-generic' scale: (,50000.0) symbolizers: - polygon: fill-graphic: symbols: - external: url: symbols/grave_yard_generic.png format: image/png YSLD 28 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Hatching <sld:PolygonSymbolizer> <sld:Fill> <sld:GraphicFill> <sld:Graphic> <sld:Mark> <sld:WellKnownName>shape://times</sld:WellKnownName> <sld:Stroke> <sld:CssParameter name="stroke">#ADD8E6</sld:CssParameter>
</sld:Stroke> </sld:Mark> <sld:Size>8</sld:Size> </sld:Graphic> </sld:GraphicFill> </sld:Fill> </sld:PolygonSymbolizer> </sld:Rule> [@scale < 10000] { fill: symbol('shape://times'); fill-size: 8; :fill { stroke: #ADD8E6; } } SLD CSS 29 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Solid lines (OSM admin borders) [type = 'administrative'] { [admin_level
<= 4], [admin_level = 5 or admin_level = 6][@sd <= 400k], [admin_level = 7 or admin_level = 8][@sd <= 200k], [admin_level = 9 or admin_level = 10][@sd <= 100k] { stroke: #ac46ac; stroke-opacity: 0.4; } } CSS 31 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Dashes … <sld:LineSymbolizer> <sld:Stroke> <sld:CssParameter name="stroke">#6B4900</sld:CssParameter> <sld:CssParameter name="stroke-width">0.1</sld:CssParameter> <sld:CssParameter name="stroke-dasharray">2
2</sld:CssParameter> </sld:Stroke> </sld:LineSymbolizer> … stroke: #6B4900; stroke-width: 0.1; stroke-dasharray: 2 2; … SLD CSS 32 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Alternating dashes with marks * { stroke: darkRed, symbol('circle'); stroke-dasharray:
10 14, 6 18; stroke-dashoffset: 14, 0; :stroke { fill: darkRed; size: 6; } } ⚫ Two coordinated dashed lines ⚫ One made with lines ⚫ One made with circles ⚫ The offset shifts them to have one appear in the empty spaces of the other CSS 33 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Point labels and obstacles [@sd < 200k] { label: [FULLNAME];
label-anchor: 0.5 1.0; label-offset: 0.0 -14.0; font-fill: #000033; font-family: Arial; font-size: 12; halo-color: white; halo-radius: 1.5; label-priority: 200000; label-auto-wrap: 100; mark: url('./img/landmarks/${IMAGE}’); mark-label-obstacle: true; } «FULLNAME» attribute Auto wrapping label with halo. Data driven symbol URL Labels won’t overlap the symbol CSS 36 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Line labels [@sd < 200k] { label: [LABEL_NAME]; font-fill: #000000;
font-family: Arial; font-size: 13; font-style: normal; font-weight: bold; halo-color: #FFFFFF; halo-radius: 1; label-follow-line: true; label-repeat: 400; label-group: true; label-max-displacement: 200; } Draw «LABEL_NAME», black, with white halo Draw them along lines, fuse segments with same label, repeat CSS 37 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Polygon labels <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">14.0</sld:CssParameter> <sld:CssParameter name="font-weight">bold</sld:CssParameter> </sld:Font> <sld:LabelPlacement> <sld:PointPlacement> <sld:AnchorPoint> <sld:AnchorPointX>0.5</sld:AnchorPointX> <sld:AnchorPointY>0.5</sld:AnchorPointY> </sld:AnchorPoint> </sld:PointPlacement> </sld:LabelPlacement> <sld:Fill> <sld:CssParameter name="fill">#000000</sld:CssParameter> </sld:Fill> <sld:Priority>50000</sld:Priority> <sld:VendorOption name="autoWrap">100</sld:VendorOption> <sld:VendorOption name="maxDisplacement">200</sld:VendorOption> <sld:VendorOption name="goodnessOfFit">0.9</sld:VendorOption> </sld:TextSymbolizer> 38 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
A DEM and a color map ⚫ SRTM from USGS
⚫ Standard color map ⚫ In 2.14.x we’ll also be able to add shaded relief (not shown here) [@sd > 75000] { raster-channels: auto; raster-color-map: color-map-entry(#00BFBF, -100.0, 0) color-map-entry(#00FF00, 920.0, 0) color-map-entry(#00FF00, 920.0, 1.0) color-map-entry(#FFFF00, 1940.0, 1.0) color-map-entry(#FFFF00, 1940.0, 1.0) color-map-entry(#FF7F00, 2960.0, 1.0) color-map-entry(#FF7F00, 2960.0, 1.0) color-map-entry(#BF7F3F, 3980.0, 1.0) color-map-entry(#BF7F3F, 3980.0, 1.0) color-map-entry(#141514, 5000.0, 1.0); } CSS 40 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Contrast enhancement http://docs.geoserver.org/latest/en/user/styling/sld- reference/rastersymbolizer.html#contrastenhancement <sld:RasterSymbolizer> <sld:ContrastEnhancement> <sld:Normalize> <sld:VendorOption name="algorithm"> StretchToMinimumMaximum
</sld:VendorOption> <sld:VendorOption name="minValue">50</sld:VendorOption> <sld:VendorOption name="maxValue">800</sld:VendorOption> </sld:Normalize> </sld:ContrastEnhancement> </sld:RasterSymbolizer> GeoServer vendor extension SLD 41 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Color blending and alpha compositing http://docs.geoserver.org/stable/user/styling/sld-extensions/composite-blend/index.html More info at: 43
FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Z ordering http://docs.geoserver.org/latest/en/user/styling/sld- extensions/z-order/example.html [class = 'motorways'] { stroke: #990000,
#ff6666; stroke-width: 8, 6; stroke-linecap: round; z-index: 0, 3; } [class = 'railways'] { stroke: #333333; stroke-width: 3; z-index: 2; } [class = 'railways'] { stroke: #ffffff; stroke-width: 1.5; stroke-dasharray: 5 5; z-index: 3; } * { sort-by: "z_order"; sort-by-group: "roadsGroup"; } CSS 44 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Geometry transformations [@scale < 10000] { fill-geometry: [offset(the_geom, 6, -6)];
fill: darkgray; z-index: 0; } [@scale < 10000] { fill: #b3b3b3; z-index: 1; } CSS 45 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
Rendering transformations * { transform: ras:Contour(levels: 1100 1200 1300 1400
1500 1600 1700 1800); stroke: black; label: [GRAY-INDEX]; font-fill: black; font-family: Sans; font-size: 12; halo-radius: 2; halo-color: white; label-follow-line: true } CSS 46 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
New transform in 2.14: map algebra * { transform: ras:Jiffle(script:
‘ nir = src[7]; vir = src[3]; dest = (nir-vir)/(nir+vir);’); raster-channels: auto; raster-color-map: color-map-entry(#00BFBF, -100.0, 0) color-map-entry(#00FF00, 920.0, 0) … } CSS 47 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
QGIS SLD export work ⚫ In QGIS 2.18, Bonn code
sprint improvements ⚫ In QGIS 3.0 support for label exports (thanks for OpenGeoGroep sponsoring) 49 FOSS4G 2018, August 29th/31st, Dar Es Salaam -
More to come ⚫ OSGeo UK sponsorship ⚫ The GeoServer
PSC looks for proposals ⚫ E.g., we could have basic raster symbolizer export 50 FOSS4G 2018, August 29th/31st, Dar Es Salaam