SLDReader
SLD styling for online mapping libraries
Install / Use
/learn @NieuwlandGeo/SLDReaderREADME
About SLDReader
The purpose of this library is to translate a Styled Layer Descriptor (SLD) XML into a style function for an OpenLayers vector layer.
The library consists of two parts:
- An SLDReader that parses an SLD document into a style object.
- A function
createOlStyleFunctionthat converts the parsed style object into a function that you can use in OpenLayers to style features.
Library goals:
- Implement as much of the Symbology Encoding v1.1.0 specification as possible.
- Support some vendor-specific (GeoServer, QGIS) options as well.
- Have a good performance, but prioritize rendering accuracy.
Getting Started
Install the latest SLDReader version.
npm install @nieuwlandgeo/sldreader
Converting an SLD to an OpenLayer style function
import { Reader, createOlStyleFunction } from '@nieuwlandgeo/sldreader';
// Code below assumes that you already have an sld xml and an OpenLayers vector layer.
// First, parse the SLD XML into an SLD object.
const sldObject = Reader(sldXml);
// This example uses the first FeatureTypeStyle element in the SLD.
const featureTypeStyle = sldObject.layers[0].styles[0].featuretypestyles[0];
// Create a (feature -> [ol styles]) style function from the FeatureTypeStyle.
const styleFunction = createOlStyleFunction(featureTypeStyle);
// Apply the style function to your vector layer.
vectorLayer.setStyle(styleFunction);
Example with options
import { Reader, createOlStyleFunction } from '@nieuwlandgeo/sldreader';
import { getPointResolution } from 'ol/proj';
const sldObject = Reader(sldXml, {
// Default compatibility mode is 'OGC' according to the SLD specification.
// QGIS mode fixes a few non-standard behaviors to create a style function
// that will match the style displayed in QGIS.
compatibilityMode: 'QGIS',
// Set to 'TextSymbolizer' to convert font symbols to text symbolizers.
// Font symbolizers are converted to ExternalGraphic by default.
fontSymbolConversion: 'TextSymbolizer',
});
const styleFunction = createOlStyleFunction(featureTypeStyle, {
// Use a resolution conversion function to convert projection units per pixel into meters per pixel.
// Use this for a more accurate resolution if you use min- or max scale denominators or non-pixel uom.
convertResolution: viewResolution => {
// The map variable is the OpenLayers map containing the vector layer.
const viewProjection = map.getView().getProjection();
const viewCenter = map.getView().getCenter();
return getPointResolution(viewProjection, viewResolution, viewCenter);
},
// If you use point icons with an ExternalGraphic, supply a callback
// to update the vector layer when an image finishes loading.
// Without this callback, the image icons will stay grey
// until you refresh the vector layer by panning or zooming.
imageLoadedCallback: () => {
vectorLayer.changed();
},
});
Requirements
- SLDReader requires at least OpenLayers v10.8.0 for full support of SLD features. Older versions will probably work, but lack support for custom symbols (including QGIS 'arrow' for example) and perpendicular line offsets. The peer dependency version is set to
>=7, because that's the lowest version that doesn't crash in some cases. - An up-to date browser. If you need to support older browsers, you have to compile SLDReader yourself with a different
browserslistsetting inpackage.json.- The browsers supported by SLDReader can be found here: https://browsersl.ist/#q=defaults .
- If you want to build and/or run SLDReader, NodeJS v18.18 or higher is required.
SLD feature support
The SLDReader library can read both SLD v1.0 and SLD v1.1 documents, which will both be converted to the same SLD object structure. Most of the Symbology Encoding v1.1.0 specification is implemented by SLDReader. Supported and unsupported features are documented below.
PointSymbolizer
Example:
<se:PointSymbolizer>
<se:Graphic>
<se:Mark>
<se:WellKnownName>square</se:WellKnownName>
<se:Fill>
<se:SvgParameter name="fill">#FF0000</se:SvgParameter>
</se:Fill>
<se:Stroke>
<se:SvgParameter name="stroke">#880000</se:SvgParameter>
<se:SvgParameter name="stroke-width">2</se:SvgParameter>
</se:Stroke>
</se:Mark>
<se:Size>10</se:Size>
<se:Rotation>45</se:Rotation>
<se:Displacement>
<se:DisplacementX>0</se:DisplacementX>
<se:DisplacementY>14</se:DisplacementY>
</se:Displacement>
</se:Graphic>
</se:PointSymbolizer>
Marks with well known symbol names are supported: circle, square, triangle, star, cross, x, hexagon, octagon. ExternalGraphic icons are supported. Some vendor-specific marks (GeoServer, QGIS) are also supported, see the Mark Gallery demo page.
Two custom marks are also supported: horline for a horizontal line through the center and backslash for a line from the top left to the bottom right. Use backslash instead of horline if you want to have diagonal hashing as a polygon graphic fill.
The Size and Rotation elements can use <ogc:PropertyName> to read the values from each feature.
Only one Graphic per PointSymbolizer is supported. Each Graphic can only have one Mark or one ExternalGraphic.
ExternalGraphic
External graphics can be used with an OnlineResource linking to a valid image url.
<se:ExternalGraphic>
<se:OnlineResource xlink:type="simple" xlink:href="assets/img/flag-nl.png"/>
<se:Format>image/png</se:Format>
</se:ExternalGraphic>
A valid image url can also be a base64 url:
<se:ExternalGraphic>
<se:OnlineResource xlink:type="simple" xlink:href="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="/>
<se:Format>image/jpeg</se:Format>
</se:ExternalGraphic>
Instead of using base64 urls inside an OnlineResource, external graphics can also be embedded as base64 string using InlineContent with encoding="base64".
<se:ExternalGraphic>
<se:InlineContent encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==</se:InlineContent>
<se:Format>image/jpeg</se:Format>
</se:ExternalGraphic>
Inline content can also be SVG with encoding="xml".
<se:ExternalGraphic>
<se:InlineContent encoding="xml">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M50,3l12,36h38l-30,22l11,36l-31-21l-31,21l11-36l-30-22h38z" fill="#0F0" stroke="#040" stroke-width="2"/>
</svg>
</se:InlineContent>
<se:Format>image/svg+xml</se:Format>
</se:ExternalGraphic>
Important notes:
- SLDReader does not support
ColorReplacementinsideExternalGraphics. - Do not include the
<?xml ... ?>header for inline SVG content. - Make sure that inline SVG has
widthandheightattributes. Without it, (most?) browsers cannot properly load the SVG as an image.
QGIS parametric SVG support (experimental)
SLD's with parametric embedded SVG's exported by QGIS should be able to be used in SLDReader.
Support for this functionality is quite hacky and experimental, but appears to work for simple examples.
Custom mark symbols
It's possible to register your own symbols under your own WellKnownName.
Custom symbol coordinates must be entered in counterclockwise order and must all lie within a [-1, -1, 1, 1] bounding box.
The coordinates will be scaled by the symbol <Size> parameter.
Example (see the Mark Gallery demo page):
SLDReader.registerCustomSymbol('crystal', [
[0.5, 0],
[0.75, 0.75],
[0, 0.5],
[-1, 1],
[-0.5, 0],
[-0.75, -0.75],
[0, -0.5],
[1, -1],
]);
<se:PointSymbolizer>
<se:Graphic>
<se:Mark>
<se:WellKnownName>crystal</se:WellKnownName>
<!-- ...etc... -->
</se:Mark>
</se:Graphic>
</se:PointSymbolizer>
Font symbols
In SLD, it's possible to use a font symbol by supplying an onlineresource that points to a (TTF) font file, together with an index pointing towards a single character within the font file.
Example (renders a spider on systems that have the Webdings font installed):
<se:PointSymbolizer>
<se:Graphic>
<se:Mark>
<se:OnlineResource xlink:href="ttf://Webdings" xlink:type="simple"/>
<se:Format>ttf</se:Format>
<se:MarkIndex>33</se:MarkIndex>
<se:Fill>
<se:SvgParameter name="fill">#FF0000</se:SvgParameter>
</se:Fill>
<se:Stroke>
<se:SvgParameter name="stroke-width">3</se:SvgParameter>
<se:SvgParameter name="stroke">#0000FF</se:SvgParameter>
</se:Stroke>
</se:Mark>
<se:Size>32</se:Size>
</se:Graphic>
</se:PointSymbolizer>
SLDReader also supports the Geoserver font symbol shorthand, by pointing to a symbol within the wellknownname.
Example (same spider as above):
<se:PointSymbolizer>
<se:Graphic>
<se:Mark>
<se:WellKnownName>ttf://Webdings#0x0021</se:WellKnownName>
<!-- fill,stroke,size etc.. -->
</se:Mark>
</se:Graphic>
</se:PointSymbolizer>
Font symbols are converted to images by rendering them as an ExternalGraphic by default. By passing the option fontSymbolConversion: 'TextSymbolizer' when reading an sld, mark symbols are converted to text symbolizers.
const mySld = Reader(fontSymbolsSld, {
fontSymbolConversion: 'TextSymbolizer',
});
Both opt
