Slide 1

Slide 1 text

Creating stunning maps with GeoServer With SLD and CSS Ing. Andrea Aime GeoSolutions 1

Slide 2

Slide 2 text

GeoSolutions Enterprise Support Services Deployment Subscription Professional Training Customized Solutions GeoNode • Offices in Italy & US, Global Clients/Team • 40+ collaborators, 30+ Engineers • Our products • Our Offer

Slide 3

Slide 3 text

Affiliations We strongly support Open Source, it Is in our core We actively participate in OGC working groups and get funded to advance new open standards We support standards critical to GEOINT

Slide 4

Slide 4 text

Quick tour of styling languages 4

Slide 5

Slide 5 text

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 5 Map rendering

Slide 6

Slide 6 text

Shared concepts ● Layers (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 6

Slide 7

Slide 7 text

Styled Layer Descriptor 1.0 and 11 ● OGC styling standard, XML based ● Was meant for machine export but ended up being edited a lot by hand ● Can be generated by external tools and imported (with some hand tweaking) 7

Slide 8

Slide 8 text

SLD 1.0 example … type alpine_hut 100000.0 image/png Filter Scale dep. Symbolizer

Slide 9

Slide 9 text

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 9

Slide 10

Slide 10 text

GeoCSS ● Compact syntax, familiar for web developers ● CQL based filtering, rule nesting and cascading keeps styling compact ● 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'); } 10

Slide 11

Slide 11 text

MBStyles (aka MapBox GL) ● Symbols as “sprites” (symbol collections) ● Can be applied both on the client side and the server side ● Online editors available, complex expressions still require writing JSON ● JSON based, designed for GUI editing (like SLD) instead of hand editing ● Scale control based only on Web Mercator zoom levels ●

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Styling concepts: Scale dependencies 13

Slide 14

Slide 14 text

Scale dependency Filters ● SLD: ● 1000 ● 1000000 ● CSS ● [@sd > 1k][@sd < 1M] Compact expression of large numbers makes them readable at a glance, e.g., 100k, 1M , 10M Show buildings as user zooms in

Slide 15

Slide 15 text

Unit of Measure ● Real world measures, sizes grow as one zooms in … #0000FF 5 ... … stroke: blue; stroke-width: 5m; SLD CSS

Slide 16

Slide 16 text

Transformation functions ● Use a different value depending on the current scale/zoom level ● For non linear scaling [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

Slide 17

Slide 17 text

Transformation functions in SLD #e66e89 wms_scale_denominator 2 400000 1.9 800000 1.4 1500000 1 3000000 0.8 6000000 0.5 SLD

Slide 18

Slide 18 text

Point styling 18

Slide 19

Slide 19 text

Simple symbol [type = 'alpine_hut'][@sd < 100k] { mark: url('symbols/alpinehut.p.16.png'); } type alpine_hut 100000.0 image/png SLD CSS

Slide 20

Slide 20 text

SVG as a scalable, fillable shape [type = 'bank'][@sd < 6k] { mark: symbol('file://symbols/bank.svg'); :mark { fill: #734a08 }; mark-size: 14; } type bank 6000 file://symbols/bank.svg #734a08 14 CSS bank.svg

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

● Here are some examples: ● From TTF fonts using the name ttf://#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) …… ) ● Build your own, pluggable system ● Full docs at: http://docs.geoserver.org/latest/en/user/styling/sld/exte nsions/pointsymbols.html Other mark options

Slide 23

Slide 23 text

Filling polygons 23

Slide 24

Slide 24 text

Solid filling * { fill: lightgrey; stroke-width: 0.5; } #d3d3d3 0.5 SLD CSS

Slide 25

Slide 25 text

Overlap solid fills with repeated icons fill [@sd < 800k][type in ('cemetery', 'grave_yard')] { fill: #aacbaf; [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

Slide 26

Slide 26 text

Hatching shape://times #ADD8E6 8 [@scale < 10000] { fill: symbol('shape://times'); fill-size: 8; :fill { stroke: #ADD8E6; } } SLD CSS

Slide 27

Slide 27 text

Line symbology 27

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Labeling 30

Slide 31

Slide 31 text

Vendor options • Priority labelling, static or attribute based • Deluge of vendor options to control in detail labelling: • group • labelAllGroup • spaceAround • followLine • maxDisplacement • repeat • maxAngleDelta • autoWrap • forceLeftToRight • conflictResolution • goodnessOfFit • polygonAlign • graphic-resize • graphic-margin • partials • underlineText • strikethroughText • charSpacing • wordSpacing

Slide 32

Slide 32 text

Polygon labels FULLNAME Arial 14.0 bold 0.5 0.5 #000000 50000 100 200 0.9 SLD

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Raster styling 35

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

Contrast enhancement http://docs.geoserver.org/latest/en/user/styling/sld-reference/rastersymbolizer. html#contrastenhancement StretchToMinimumMaximum 50 800 GeoServer vendor extension SLD

Slide 38

Slide 38 text

Other assorted features 38

Slide 39

Slide 39 text

Color blending and alpha compositing multiply color-burn difference Source Destination https://docs.geoserver.org/latest/en/user/styling/sld/extensions/composite-blend/index.html More info at: Mask with alpha compositing multiply, 0.5

Slide 40

Slide 40 text

Z ordering https://docs.geoserver.org/latest/en/user/styling/sl d/extensions/z-order/syntax.html#z-ordering-acros s-layers [class = 'motorways'] { stroke: #990000, #ff6666; stroke-width: 8, 6; stroke-linecap: round; z-index: 0, 2; } [class = 'railways'] { stroke: #333333; stroke-width: 3; z-index: 1; } [class = 'railways'] { stroke: #ffffff; stroke-width: 1.5; stroke-dasharray: 5 5; z-index: 2; } * { sort-by: "z_order"; sort-by-group: "roadsGroup"; } CSS 40

Slide 41

Slide 41 text

Rendering transformations • WPS + WMS + rendering optimizations • In this slide, on the fly contour extraction * { 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 41

Slide 42

Slide 42 text

Jiffle 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 On the fly NDVI computation from Sentinel 2 images

Slide 43

Slide 43 text

Point and click editors 43

Slide 44

Slide 44 text

QGIS SLD export • Basic vector and raster styling covered • Much advanced bits missing though • Needs sponsoring on both ends (QGIS and GeoServer)

Slide 45

Slide 45 text

GeoStyler https://geostyler.github.io/geostyler-demo/

Slide 46

Slide 46 text

MapStore styler https://mapstore.readthedocs.io/en/latest/user-guide/layer-settings/#visual-editor-style

Slide 47

Slide 47 text

That’s all folks! Questions? [email protected] 47