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

Creating stunning maps with GeoServer With SLD, CSS, YSLD and MBStyles

Creating stunning maps with GeoServer With SLD, CSS, YSLD and MBStyles

Bac74c17d65c22d0ae63915251f7750f?s=128

Simone Giannecchini
PRO

August 29, 2019
Tweet

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 2019, August 26th/30th, Bucharest
  3. Quick tour of styling languages 3

  4. 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 2019, August 26th/30th, Bucharest
  5. 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 2019, August 26th/30th, Bucharest
  6. Styled Layer Descriptor 1.0 and 11 ⚫ The only OGC

    styling standard ⚫ XML based, verbose, hard to hand edit ⚫ Was meant for machine export but ended up being edited a lot by hand ⚫ Autocomplete in the style editor ⚫ Can be generated by external tools and imported ⚫ However interoperability is limited ⚫ Often needs to be hand tweaked 6 FOSS4G 2019, August 26th/30th, Bucharest
  7. 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 2019, August 26th/30th, Bucharest
  8. 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 2019, August 26th/30th, Bucharest
  9. 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) ⚫ Autocomplete in the style editor ⚫ Does not get any more compact than this: ⚫ Cons: some are confused by “rule cascading” → can now be turned off [type = 'alpine_hut'][@sd < 100k] { mark: url('symbols/alpinehut.p.16.png'); } 9 FOSS4G 2019, August 26th/30th, Bucharest
  10. MBStyles (aka MapBox GL) ⚫ JSON based, designed for GUI

    editing (like SLD) instead of hand editing ⚫ Only Web Mercator zoom level based scale control ⚫ Symbols coming from “sprites” (symbol collections) ⚫ Unlike others, no styling extensions ⚫ No rendering transformations ⚫ Limited expressions usage ⚫ Pro: can be applied both on the client side and the server side 10 FOSS4G 2019, August 26th/30th, Bucharest
  11. 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 2019, August 26th/30th, Bucharest
  12. What’s next ⚫ Going to explore styling concepts ⚫ Languages

    used in examples ⚫ SLD 1.0 + GS extensions ⚫ YSLD ⚫ GeoCSS YSLD SLD CSS 12 FOSS4G 2019, August 26th/30th, Bucharest
  13. Scale dependencies 13

  14. 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 2019, August 26th/30th, Bucharest
  15. 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 2019, August 26th/30th, Bucharest
  16. 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 2019, August 26th/30th, Bucharest
  17. 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 2019, August 26th/30th, Bucharest
  18. 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 2019, August 26th/30th, Bucharest
  19. Point styling 19

  20. 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 2019, August 26th/30th, Bucharest
  21. 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 2019, August 26th/30th, Bucharest
  22. 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 2019, August 26th/30th, Bucharest
  23. ⚫ 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://MULTIPOLYGON(((-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 2019, August 26th/30th, Bucharest
  24. Filling polygons 24

  25. Solid filling * { fill: lightgrey; 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 2019, August 26th/30th, Bucharest
  26. Solid fills and 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 2019, August 26th/30th, Bucharest
  27. 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 2019, August 26th/30th, Bucharest
  28. 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 2019, August 26th/30th, Bucharest
  29. 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 2019, August 26th/30th, Bucharest
  30. Painting lines 30

  31. 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 2019, August 26th/30th, Bucharest
  32. Dashes/Marks/images along a line * { 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 32 FOSS4G 2019, August 26th/30th, Bucharest
  33. Labeling 33

  34. Vendor options 34 FOSS4G 2019, August 26th/30th, Bucharest

  35. 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 35 FOSS4G 2019, August 26th/30th, Bucharest
  36. 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 36 FOSS4G 2019, August 26th/30th, Bucharest
  37. 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> 37 FOSS4G 2019, August 26th/30th, Bucharest
  38. Raster styling 38

  39. A DEM and a color map ⚫ SRTM from USGS

    ⚫ Standard color map ⚫ Also shaded relief (not shown in the css below) [@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 39 FOSS4G 2019, August 26th/30th, Bucharest
  40. 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 40 FOSS4G 2019, August 26th/30th, Bucharest
  41. Other assorted features 41

  42. Color blending and alpha compositing http://docs.geoserver.org/stable/user/styling/sld-extensions/composite-blend/index.html More info at: 42

    FOSS4G 2019, August 26th/30th, Bucharest
  43. 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 43 FOSS4G 2019, August 26th/30th, Bucharest
  44. Geometry transformations [@scale < 10000] { fill-geometry: [offset(the_geom, 6, -6)];

    fill: darkgray; z-index: 0; } [@scale < 10000] { fill: #b3b3b3; z-index: 1; } CSS 44 FOSS4G 2019, August 26th/30th, Bucharest
  45. 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 45 FOSS4G 2019, August 26th/30th, Bucharest
  46. 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 46 FOSS4G 2019, August 26th/30th, Bucharest
  47. Desktop tool export 47

  48. QGIS SLD export work ⚫ In QGIS 2.18, Bonn code

    sprint improvements ⚫ In QGIS 3.0 support for label exports (thanks for OpenGeoGroep sponsoring) 48 FOSS4G 2019, August 26th/30th, Bucharest
  49. Raster symbolizer export ⚫ Thanks to OSGeo UK sponsorship, GeoServer

    PSC donation, and GeoSolutions in- kind support ⚫ Available since QGIS 3.4.5 49 FOSS4G 2019, August 26th/30th, Bucharest
  50. GeoStyler 50 FOSS4G 2019, August 26th/30th, Bucharest

  51. MapStore styler (in the making) 51 FOSS4G 2019, August 26th/30th,

    Bucharest
  52. MapStore styler 52 FOSS4G 2019, August 26th/30th, Bucharest

  53. SLDEditor 53 FOSS4G 2019, August 26th/30th, Bucharest

  54. That’s all folks! Questions? info@geo-solutions.it 54 FOSS4G 2019, August 26th/30th,

    Bucharest