Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating Stunning Maps in GeoServer: mastering SLD and CSS styles

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

September 02, 2018
Tweet

More Decks by Simone Giannecchini

Other Decks in Programming

Transcript

  1. Creating stunning maps with GeoServer With SLD, CSS, YSLD and

    MBStyles Ing. Andrea Aime GeoSolutions 1
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. ⚫ 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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