Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Quick tour of styling languages 3

Slide 4

Slide 4 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 4 Map rendering FOSS4G 2019, August 26th/30th, Bucharest

Slide 5

Slide 5 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 5 FOSS4G 2019, August 26th/30th, Bucharest

Slide 6

Slide 6 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 6 FOSS4G 2019, August 26th/30th, Bucharest

Slide 7

Slide 7 text

SLD 1.0 example … type alpine_hut 100000.0 image/png Filter Scale dep. Symbolizer 7 FOSS4G 2019, August 26th/30th, Bucharest

Slide 8

Slide 8 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 8 FOSS4G 2019, August 26th/30th, Bucharest

Slide 9

Slide 9 text

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

Slide 10

Slide 10 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 10 FOSS4G 2019, August 26th/30th, Bucharest

Slide 11

Slide 11 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 11 FOSS4G 2019, August 26th/30th, Bucharest

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Scale dependencies 13

Slide 14

Slide 14 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 14 FOSS4G 2019, August 26th/30th, Bucharest

Slide 15

Slide 15 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 ⚫ YSLD: ⚫ scale: (1000, 1000000) ⚫ scale: (1e3, 1e6) ⚫ zoom: (8, 16) grid: name: WGS84 15 FOSS4G 2019, August 26th/30th, Bucharest

Slide 16

Slide 16 text

Unit of Measure ⚫ Useful if you have real world measures of line thicknesses and the like … #0000FF 5 ... … stroke: blue; stroke-width: 5m; … line: stroke-color: '#0000FF' uom: metre; stroke-width: '5'; SLD YSLD CSS 16 FOSS4G 2019, August 26th/30th, Bucharest

Slide 17

Slide 17 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 17 FOSS4G 2019, August 26th/30th, Bucharest

Slide 18

Slide 18 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 18 FOSS4G 2019, August 26th/30th, Bucharest

Slide 19

Slide 19 text

Point styling 19

Slide 20

Slide 20 text

Simple image [type = 'alpine_hut'][@sd < 100k] { mark: url('symbols/alpinehut.p.16.png'); } type alpine_hut 100000.0 image/png SLD CSS 20 FOSS4G 2019, August 26th/30th, Bucharest

Slide 21

Slide 21 text

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

Slide 22

Slide 22 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 22 FOSS4G 2019, August 26th/30th, Bucharest

Slide 23

Slide 23 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 23 FOSS4G 2019, August 26th/30th, Bucharest

Slide 24

Slide 24 text

Filling polygons 24

Slide 25

Slide 25 text

Solid filling * { fill: lightgrey; stroke-width: 0.5; } #d3d3d3 0.5 SLD CSS 25 FOSS4G 2019, August 26th/30th, Bucharest

Slide 26

Slide 26 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 26 FOSS4G 2019, August 26th/30th, Bucharest

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Hatching shape://times #ADD8E6 8 [@scale < 10000] { fill: symbol('shape://times'); fill-size: 8; :fill { stroke: #ADD8E6; } } SLD CSS 29 FOSS4G 2019, August 26th/30th, Bucharest

Slide 30

Slide 30 text

Painting lines 30

Slide 31

Slide 31 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 31 FOSS4G 2019, August 26th/30th, Bucharest

Slide 32

Slide 32 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 32 FOSS4G 2019, August 26th/30th, Bucharest

Slide 33

Slide 33 text

Labeling 33

Slide 34

Slide 34 text

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

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 35 FOSS4G 2019, August 26th/30th, Bucharest

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 36 FOSS4G 2019, August 26th/30th, Bucharest

Slide 37

Slide 37 text

Polygon labels FULLNAME Arial 14.0 bold 0.5 0.5 #000000 50000 100 200 0.9 37 FOSS4G 2019, August 26th/30th, Bucharest

Slide 38

Slide 38 text

Raster styling 38

Slide 39

Slide 39 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 39 FOSS4G 2019, August 26th/30th, Bucharest

Slide 40

Slide 40 text

Contrast enhancement http://docs.geoserver.org/latest/en/user/styling/sld- reference/rastersymbolizer.html#contrastenhancement StretchToMinimumMaximum 50 800 GeoServer vendor extension SLD 40 FOSS4G 2019, August 26th/30th, Bucharest

Slide 41

Slide 41 text

Other assorted features 41

Slide 42

Slide 42 text

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

Slide 43

Slide 43 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 43 FOSS4G 2019, August 26th/30th, Bucharest

Slide 44

Slide 44 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 44 FOSS4G 2019, August 26th/30th, Bucharest

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Desktop tool export 47

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

GeoStyler 50 FOSS4G 2019, August 26th/30th, Bucharest

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

That’s all folks! Questions? [email protected] 54 FOSS4G 2019, August 26th/30th, Bucharest