Skip to content

Releases: NieuwlandGeo/SLDReader

v0.7.3

20 Nov 11:36

Choose a tag to compare

Compatibility mode

Some software packaged implement SLD styling in a way that's slightly different from the SLD specification. Especially when the SLD specification is a bit vague on some points.

When parsing an SLD, it's possible to specify which software was used to create (or render) the SLD. In this case, SLDReader can make some changes to the parsed SLD for a better visual match between the SLD displayed in the software and the output of the SLDReader style function.

To parse an SLD in compatibility mode, add it as an option as follows:

const sldObject = SLDReader.Reader(sld, { compatibilityMode: 'QGIS' });

For now, only QGIS is available as compatibility mode option, but more can be added in the future.

In QGIS compatibility mode, a rotated line symbol inside a GraphicFill will be replaced by an unrotated slash or backslash when the rotation is an odd multiple of 45 degrees. This ensures that lines are unbroken in the graphic fill, because a (back)slash symbol spans the entire diagonal of the tiled square. A rotated line only spans part of the diagonal, causing broken lines in the fill.

More QGIS symbols

This release adds a handful of QGIS mark wellknownnames:

regular_star
half_arc
third_arc
quarter_arc
trapezoid
parallelogram_right
parallelogram_left
square_with_corners
shield
decagon
star_diamond
asterisk_fill

v0.7.2

13 Aug 09:10

Choose a tag to compare

Bugfix

This release fixes a bug with font handling. When there are multiple font-family parameters, they should be handled in the order they are given. Before this fix, only the last font-family was used.

Example:

<se:SvgParameter name="font-family">Noto Sans</se:SvgParameter>
<se:SvgParameter name="font-family">Arial</se:SvgParameter>
<se:SvgParameter name="font-family">sans-serif</se:SvgParameter>

Before fix --> fontFamily: 'sans-serif'

After fix  --> fontFamily: '"Noto Sans", Arial, sans-serif'

v0.7.1

07 Aug 14:02

Choose a tag to compare

Bugfix

Fix a crash when trying to .clone() the OpenLayers style output by createOlStyleFunction if the style uses a custom symbol.

v0.7.0

23 Jul 14:08

Choose a tag to compare

This release adds support for defining your own custom symbols using a custom WellKnownName. With this change, several QGIS- and GeoServer specific marks have been added as well.

Check out the Mark Gallery demo page for a demo.

Possible Breaking Change

Custom symbols and the newly added marks only work if you use OpenLayers v10.3.0 or higher. On lower versions, custom symbols are rendered as a square instead.

When using GraphicStroke, use OL v8.2.0 or higher to prevent visual artefacts.

If you don't use any of the above, OL v6.15 is the lowest supported version.

Added WellKnownNames

  • GeoServer:
    • shape://carrow
    • shape://oarrow
  • QGIS
    • cross_fill
    • arrow
    • filled_arrowhead
    • arrowhead
    • quarter_square
    • half_square
    • diagonal_half_square
    • right_half_triangle
    • left_half_triangle
    • semi_circle
    • third_circle
    • quarter_circle

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:

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... -->

v0.6.2

20 May 10:20

Choose a tag to compare

Added support for InlineContent

Embedding images was already possible by using a data: url as online resource for an external graphic, but the SLD spec also describes InlineContent as a way to embed an image.

This release implements the use of InlineContent for external graphics.

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>

Notes:

  • Do not include the <?xml ... ?> header for inline SVG content.
  • Make sure that inline SVG has width and height attributes. Without it, (most?) browsers cannot properly load the SVG as an image.

Added a few extra Mark symbolizers

The following marks have been added (demo):

  • QGIS:
    • equilateral_triangle
    • pentagon
  • GeoServer:
    • shape://vertline
    • shape://horline
    • shape://slash
    • shape://backslash
    • shape://dot
    • shape://plus
    • shape://times

v0.6.1

14 May 10:20

Choose a tag to compare

Fix crash when using style function on a vector tile layer

Vector tile layers use a lightweight RenderFeature class instead of Feature for performance. This resulted in crashes when using an SLD with a PointSymbolizer, since RenderFeatures do not have specific methods for mid/centerpoint calculations.

This bug has been fixed by converting a RenderFeature into a Geometry, but only when needed.

Fixing the return value of the dimension function

The builtin dimension function now returns -1 for null/undefined geometry and GeometryCollection. Previously it returned 0 in these cases, which should be returned only for true point geometries.

v0.6.0

24 Apr 09:59

Choose a tag to compare

Breaking change

The major build process changes in v0.5.0 unfortunately made the generated sldreader.js not quite compatible with some (webpack) bundlers.

I have decided to stop trying to be commonjs/amd/umd/whatever compatible and distribute SLDReader as an ES module, together with two standalone versions for use in a browser.

The build process now outputs three files (can be found in the /dist folder).

  • sldreader.js: main export used by npm, is now a pure javascript module with import/export, usable by modern javascript bundlers.
  • sldreader-standalone.js: for use in a <script> tag in browsers, together with the OpenLayers standalone script.
  • sldreader-standalone.min.js: same as above, but minified.

Minor change

The SLDReader global object now has a .version property.

v0.5.0

23 Apr 13:24

Choose a tag to compare

Breaking changes

  • Dropped support for very old browsers. Most browsers released in the last five years should be good. You can check browser support here: https://browsersl.ist/#q=defaults .
  • The minimum version of OpenLayers supported is v6.15.
  • Graphic elements with multiple ExternalGraphic and/or Mark handling has changed. Only the first ExternalGraphic or Mark encountered will be used.

Most of these other breaking changes only apply if you build or work on SLDReader yourself.

  • Minimum NodeJS version is now v18.18.0.
  • Numeric literals inside a symbolizer with non-pixel units of measure are now full literal objects:
{
    type: 'literal',
    typeHint: 'number',
    value: 10,
    uom: 'metre',
}

New functionality

Units of measure

It's now possible to use units of measure (uom) in Symbolizers.

The following units of measure are supported on symbolizers, as uom attribute:

http://www.opengeospatial.org/se/units/pixel
http://www.opengeospatial.org/se/units/metre
http://www.opengeospatial.org/se/units/foot

Values can be forced to pixels by appending px:

<se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
  <se:Graphic>
    <se:Mark>
      <se:WellKnownName>circle</se:WellKnownName>
      <se:Fill>
        <se:SvgParameter name="fill">#88aa88</se:SvgParameter>
      </se:Fill>
      <se:Stroke>
        <se:SvgParameter name="stroke">#004000</se:SvgParameter>
        <!-- Override symbolizer uom with pixels by appending px to the value. -->
        <se:SvgParameter name="stroke-width">2px</se:SvgParameter>
      </se:Stroke>
    </se:Mark>
    <se:Size>10</se:Size> <!-- in metres, as per uom attribute -->
  </se:Graphic>
</se:PointSymbolizer>

Restrictions:

  • Units of measure are not supported for GraphicStroke and GraphicFill.
  • Units of measure are not supported on stroke-dasharray.
  • Units of measure are not supported within or as return value of Function elements. The return type of Functions is always treated as dimensionless or pixels, depending on context.
  • Values will always be treated as pixels where units of measure are not supported.

QGIS SLD with parametric SVG

QGIS has the option to use SVG symbols that use one or more parameters. This is an efficient way to generate many symbols in different colors, while not having to create a separate SVG symbol for every one of those symbols.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1.0" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:ogc="http://www.opengis.net/ogc" xmlns:se="http://www.opengis.net/se">
  <NamedLayer>
    <se:Name>wgptest:parametric-svg</se:Name>
    <UserStyle>
      <se:Name>wgptest:parametric-svg</se:Name>
      <se:FeatureTypeStyle>
        <se:Rule>
          <se:Name>Single symbol</se:Name>
          <se:PointSymbolizer>
            <se:Graphic>
              <!--Parametric SVG-->
              <se:ExternalGraphic>
                <se:OnlineResource xlink:type="simple" xlink:href="base64:PHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1NzkuOTk3IDU3OS45OTciIGhlaWdodD0iNTc5Ljk5NyIgdmlld0JveD0iMCAwIDU3OS45OTcgNTc5Ljk5NyIgd2lkdGg9IjU3OS45OTciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Im00OTAuNzg4IDIzNGwtMTAuODQyLTM2LjEyOS00Ni4zODIgNjQuNDU2Yy0xMC41ODctMTguMjYyLTI4LjU4Ny01MC43ODYtMzMuMzY2LTY4LjYyNS02LjU1MS0yNC40ODEtNS44NTQtODUuMzgzLTUuMDMyLTEwNi43ODNsMS40OTItMzguODYzLTMxLjE2OCAyMy4yNmMtNS4yNTMgMy45Mi01MS43MTUgMzkuMDE0LTY1LjMxNSA2My44MjEtOS4wMzUgMTYuNTA1LTE0LjQzIDQ2LjY3LTE3LjM4NCA2OS4zNy0xNy45NDktMTEuMTE4LTMwLjc3Mi0yMC45ODctMzUuMjM2LTI3LjEyNi0xMS44NDktMTYuMzEtMjMuNzUzLTY2LjQ4NS0yOC40NzMtOTQuMjgxbC04LjExMi00Ny44NjEtMjUuOTE0IDQxLjA0OGMtNi4yMTMgOS44NDItMzcuMTkxIDYwLjQ2Ni0zNi44ODggOTAuNjQ0LjIzIDIyLjk4MSAxMy43ODQgNDMuNDg4IDI2Ljg5MyA2My4zMjMgMTAuMTQ3IDE1LjM1MyAyMC42NDEgMzEuMjI4IDIwLjczOCA0My4yNjcuMDg3IDkuOTg4LTcuNDk2IDMwLjEwOS0yMC44MjMgNTUuMjgybC04My43ODctMTQ5Ljg2NS4yNTQgNzEuODJjLjAwMi42Mi4xNDMgNjIuMzY1LTQuMjYgODcuNDgtMS44MDUgMTAuMzMzLTEzLjA5IDM0Ljk2LTE5Ljc3OSA0OC4wNTZsLTQuMjIxIDguMjU4IDQuMDYzIDguMzM2YzQuNjU0IDkuNTUzIDQ2LjU0NSA5NC4wMzYgODMuNTk3IDExOC41MTkgMzYuOTcgMjQuNDA3IDk2LjE4MiAyOC4wNTIgMTI4LjE4OCAyOC4wNTIgMS4xOTkgMCAyLjM5Mi0uMDA2IDMuNTcyLS4wMTYgNTAuNDUyLS40NTggMTIyLjI5Mi00LjkxMSAxNjMuNTA2LTM4LjE2IDM3LjEyMy0yOS45NzIgNjAuMzItOTMuMTU1IDY2Ljg0Mi0xNDIuNDc4IDUuNDQ5LTQxLjA3My0xOS4zMi0xMjUuMzMyLTIyLjE2My0xMzQuODA1em0tMjE1LjU1OSAzNi41NjFjNS44OTIgNS41NTQgMzguMzg5IDM2LjgxOSA0OS4wODQgNjAuNTkyIDMuNjc5IDguMTk2IDUuNDIxIDE5LjQzOSA3LjI2NiAzMS4zNDMgMy4zMTggMjEuNDIyIDYuNzUxIDQzLjU3MiAyMi4xMzIgNDkuODA4IDIuNzE4IDEuMTA0IDUuNzUzIDEuNjYyIDkuMDIzIDEuNjYyIDI2LjMzMiAwIDYzLjA2My0zNi4zMjUgNjkuMzEzLTQyLjcxLS40IDkuMDE1LTMuMTU4IDYxLjk3LTEzLjI0MSA4Mi44MDgtOS4xMTkgMTguNzMxLTI5LjI4MiA0MC41NDMtNDYuOTAxIDUwLjczNC0yMS40NDMgMTIuMzE4LTU2LjQ1MyAxOC4wNDctODEuNjM3IDE4LjI2bC0uODE2LjAwNGMtMjAuNzY0IDAtNDcuMjkyLTYuNzI0LTY0LjM3LTEzLjM4OC0yMy4yMjUtOS4xMTEtNTEuNjE3LTIxLjgxNC02NS4xNDQtMzkuMzE0LTE1LjU5Mi0yMC4xNzQtMjQuOTc4LTc4LjU0OS0yNi40NzMtODguNDE3IDcuODE3IDcuMjc3IDU3LjMzOSA1Mi4xMjEgOTAuMjQ3IDUyLjEyMSAyLjY1OCAwIDUuMTg0LS4yOTMgNy41MDMtLjg3IDI3LjM0My02Ljc4NSAzMy43NDctMzYuMDE2IDM5LjkzOS02NC4yODUuNzIzLTMuMjk5IDEuNDctNi43MSAyLjIzMy05Ljk4NyA1LjU0OC0yMy44OTkgMi40MDQtNzkuMjk3IDEuODQyLTg4LjM2MXoiIGZpbGw9InBhcmFtKGZpbGwpIiBmaWxsLW9wYWNpdHk9InBhcmFtKGZpbGwtb3BhY2l0eSkiIHN0cm9rZT0icGFyYW0ob3V0bGluZSkiIHN0cm9rZS1vcGFjaXR5PSJwYXJhbShvdXRsaW5lLW9wYWNpdHkpIiBzdHJva2Utd2lkdGg9InBhcmFtKG91dGxpbmUtd2lkdGgpIi8+Cjwvc3ZnPgo=?fill=%23fbd900&amp;fill-opacity=1&amp;outline=%23fb2323&amp;outline-opacity=1&amp;outline-width=25"/>
                <se:Format>image/svg+xml</se:Format>
              </se:ExternalGraphic>
              <!--Plain SVG fallback, no parameters-->
              <se:ExternalGraphic>
                <se:OnlineResource xlink:type="simple" xlink:href="base64:PHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1NzkuOTk3IDU3OS45OTciIGhlaWdodD0iNTc5Ljk5NyIgdmlld0JveD0iMCAwIDU3OS45OTcgNTc5Ljk5NyIgd2lkdGg9IjU3OS45OTciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Im00OTAuNzg4IDIzNGwtMTAuODQyLTM2LjEyOS00Ni4zODIgNjQuNDU2Yy0xMC41ODctMTguMjYyLTI4LjU4Ny01MC43ODYtMzMuMzY2LTY4LjYyNS02LjU1MS0yNC40ODEtNS44NTQtODUuMzgzLTUuMDMyLTEwNi43ODNsMS40OTItMzguODYzLTMxLjE2OCAyMy4yNmMtNS4yNTMgMy45Mi01MS43MTUgMzkuMDE0LTY1LjMxNSA2My44MjEtOS4wMzUgMTYuNTA1LTE0LjQzIDQ2LjY3LTE3LjM4NCA2OS4zNy0xNy45NDktMTEuMTE4LTMwLjc3Mi0yMC45ODctMzUuMjM2LTI3LjEyNi0xMS44NDktMTYuMzEtMjMuNzUzLTY2LjQ4NS0yOC40NzMtOTQuMjgxbC04LjExMi00Ny44NjEtMjUuOTE0IDQxLjA0OGMtNi4yMTMgOS44NDItMzcuMTkxIDYwLjQ2Ni0zNi44ODggOTAuNjQ0LjIzIDIyLjk4MSAxMy43ODQgNDMuNDg4IDI2Ljg5MyA2My4zMjMgMTAuMTQ3IDE1LjM1MyAyMC42NDEgMzEuMjI4IDIwLjczOCA0My4yNjcuMDg3IDkuOTg4LTcuNDk2IDMwLjEwOS0yMC44MjMgNTUuMjgybC04My43ODctMTQ5Ljg2NS4yNTQgNzEuODJjLjAwMi42Mi4xNDMgNjIuMzY1LTQuMjYgODcuNDgtMS44MDUgMTAuMzMzLTEzLjA5IDM0Ljk2LTE5Ljc3OSA0OC4wNTZsLTQuMjIxIDguMjU4IDQuMDYzIDguMzM2YzQuNjU0IDkuNTUzIDQ2LjU0NSA5NC4wMzYgODMuNTk3IDExOC41MTkgMzYuOTcgMjQuNDA3IDk2LjE4MiAyOC4wNTIgMTI4LjE4OCAyOC4wNTIgMS4xOTkgMCAyLjM5Mi0uMDA2IDMuNTcyLS4wMTYgNTAuNDUyLS40NTggMTIyLjI5Mi00LjkxMSAxNjMuNTA2LTM4LjE2IDM3LjEyMy0yOS45NzIgNjAuMzItOTMuMTU1IDY2Ljg0Mi0xNDIuNDc4IDUuNDQ5LTQxLjA3My0xOS4zMi0xMjUuMzMyLTIyLjE2My0xMzQuODA1em0tMjE1LjU1OSAzNi41NjFjNS44OTIgNS41NTQgMzguMzg5IDM2LjgxOSA0OS4wODQgNjAuNTkyIDMuNjc5IDguMTk2IDUuNDIxIDE5LjQzOSA3LjI2NiAzMS4zNDMgMy4zMTggMjEuNDIyIDYuNzUxIDQzLjU3MiAyMi4xMzIgNDkuODA4IDIuNzE4IDEuMTA0IDUuNzUzIDEuNjYyIDkuMDIzIDEuNjYyIDI2LjMzMiAwIDYzLjA2My0zNi4zMjUgNjkuMzEzLTQyLjcxLS40IDkuMDE1LTMuMTU4IDYxLjk3LTEzLjI0MSA4Mi44MDgtOS4xMTkgMTguNzMxLTI5LjI4MiA0MC41NDMtNDYuOTAxIDUwLjczNC0yMS40NDMgMTIuMzE4LTU2LjQ1MyAxOC4wNDctODEuNjM3IDE4LjI2bC0uODE2LjAwNGMtMjAuNzY0IDAtNDcuMjkyLTYuNzI0LTY0LjM3LTEzLjM4OC0yMy4yMjUtOS4xMTEtNTEuNjE3LTIxLjgxNC02NS4xNDQtMzkuMzE0LTE1LjU5Mi0yMC4xNzQtMjQuOTc4LTc4LjU0OS0yNi40NzMtODguNDE3IDcuODE3IDcuMjc3IDU3LjMzOSA1Mi4xMjEgOTAuMjQ3IDUyLjEyMSAyLjY1OCAwIDUuMTg0LS4yOTMgNy41MDMtLjg3IDI3LjM0My02Ljc4NSAzMy43NDctMzYuMDE2IDM5LjkzOS02NC4yODUuNzIzLTMuMjk5IDEuNDctNi43MSAyLjIzMy05Ljk4NyA1LjU0OC0yMy44OTkgMi40MDQtNzkuMjk3IDEuODQyLTg4LjM2MXoiIGZpbGw9InBhcmFtKGZpbGwpIiBmaWxsLW9wYWNpdHk9InBhcmFtKGZpbGwtb3BhY2l0eSkiIHN0cm9rZT0icGFyYW0ob3V0bGluZSkiIHN0cm9rZS1vcGFjaXR5PSJwYXJhbShvdXRsaW5lLW9wYWNpdHkpIiBzdHJva2Utd2lkdGg9InBhcmFtKG91dGxpbmUtd2lkdGgpIi8+Cjwvc3ZnPgo="/>
                <se:Format>image/svg+xml</se:Format>
              </se:ExternalGraphic>
              <!--Well known marker fallback-->
              <se:Mark>
                <se:WellKnownName>square</se:WellKnownName>
                <se:Fill>
                  <se:SvgParameter name="fill">#fbd900</se:SvgParameter>
                </se:Fill>
                <se:Stroke>
                  <se:SvgParameter name="stroke">#fb2323</se:SvgParameter>
                  <se:SvgParameter name="stroke-width">1</se:SvgParameter>
                </se:Stroke>
              </se:Mark>
              <se:Size>32</se:Size>
              <se:Displacement>
                <se:DisplacementX>0</se:DisplacementX>
                <se:DisplacementY>-4</se:DisplacementY>
              </se:Displacement>
            </se:Graphic>
          </se:PointSymbolizer>
        </se:Rule>
      </se:FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>

v0.4.6

20 Feb 14:05

Choose a tag to compare

This release adds parsing of Description elements in v1.1.0 SLD documents.

Title and abstract from a description element are added to the parent element of the description to keep the parsed SLD object structure the same as for v1.0.0 SLD documents.

Example:

<se:Rule>
  <se:Name>Other</se:Name>
  <se:Description>
    <se:Title>Other provinces</se:Title>
    <se:Abstract>This rule matches all other provinces</se:Abstract>
  </se:Description>
  ...
</se:Rule>

Results in

rule.name     --> "Other"
rule.title    --> "Other provinces"
rule.abstract --> "This rule matches all other provinces"

v0.4.5

12 Feb 12:56

Choose a tag to compare

This release fixes two problems related to comments in SLD xml files.

  • Reader crashes if the root StyledLayerDescriptor element is preceded by an xml comment.
  • Text contents of xml comments are included in labels and other SLD elements containing a value.