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 ● Offices in Italy & US, Clients Worldwide ● 30+ collaborators, 25+ Engineers ● www.geosolutionsgroup.com ● Our products ● Our Offer Enterprise Support Services Deployment Subscription Professional Training Customized Solutions GeoNode

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 ● 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 6

Slide 7

Slide 7 text

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 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) ● 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

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

What’s next ● Going to explore styling concepts ● Languages used in examples ● SLD 1.0 + GS extensions ● GeoCSS SLD CSS

Slide 14

Slide 14 text

Scale dependencies 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Expressing 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

Slide 17

Slide 17 text

Unit of Measure ● Useful if you have real world measures of line thicknesses and the like … #0000FF 5 ... … stroke: blue; stroke-width: 5m; SLD CSS

Slide 18

Slide 18 text

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

Slide 19

Slide 19 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 20

Slide 20 text

Point styling 20

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Marks (SVG in this case) [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 23

Slide 23 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 24

Slide 24 text

● Many other options! ● Built-in symbol names (well known marks): circle, square, triangle, … ● 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) …… ) ● See more here: http://docs.geoserver.org/latest/en/user/styling/sld/exte nsions/pointsymbols.html Other mark options

Slide 25

Slide 25 text

Filling polygons 25

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Filling Painting lines 29

Slide 30

Slide 30 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 31

Slide 31 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 32

Slide 32 text

Labeling 32

Slide 33

Slide 33 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 34

Slide 34 text

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

Slide 35

Slide 35 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 36

Slide 36 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 37

Slide 37 text

Raster styling 37

Slide 38

Slide 38 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 39

Slide 39 text

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

Slide 40

Slide 40 text

Other assorted features 40

Slide 41

Slide 41 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 42

Slide 42 text

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 42

Slide 43

Slide 43 text

Geometry transformations [@scale < 10000] { fill-geometry: [offset(the_geom, 6, -6)]; fill: darkgray; z-index: 0; } [@scale < 10000] { fill: #b3b3b3; z-index: 1; } CSS 43

Slide 44

Slide 44 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 44

Slide 45

Slide 45 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

Slide 46

Slide 46 text

Legend control too (2.20.x) That “boundary” rule does help making the legend readable. Yet, we need borders and labels. Valid values: mapOnly, legendOnly Boundary</ Title> <VendorOption name="inclusion" >mapOnly</VendorOption >

Slide 47

Slide 47 text

Point and click editors 47

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

GeoStyler (community module)

Slide 50

Slide 50 text

MapStore styler

Slide 51

Slide 51 text

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