LuciadRIA supports OGC SLD/SE styling and filtering functions out-of-the-box. On top of those, LuciadRIA pre-defines a range of custom styling and filtering functions. If you still need more functionality in addition to the pre-defined functions, you can plug in your own custom functions.

This article elaborates on the usage and the expected outcome of the pre-defined functions. It also shows you how to plug in your own functions.

Using the pre-defined functions

You can make use of these pre-defined custom functions:

  • vertices: a geometry function that returns all points of a geometry.

  • startPoint: a geometry function that returns the first point of a geometry.

  • endPoint: a geometry function that returns the last point of a geometry.

  • startAngle: a geometry function that returns the angle of the line starting at the start point of the geometry.

  • endAngle: a geometry function that returns the angle of the line ending at the end point of the geometry.

  • Recode: a transformation function that transforms a set of discrete attribute values into another set of values.

  • Categorize: a transformation function that transforms a continuous-valued attribute into a set of discrete values.

  • Interpolate: a transformation function that transforms a continuous-valued attribute into another continuous range of values.

  • strTrim: a text-altering function that returns a copy of the string with leading and trailing blank spaces omitted.

  • dateFormat: a text-altering function that returns a formatted date string.

Vertices

You can use the vertices function to add styling to the vertices of your feature geometry. You either replace the styling you already defined on the geometry itself, or you add the styling on top of that styling. The function has a single parameter: the name of the feature property that points to the geometry of which you want to style the individual vertices. No matter if you provide this parameter or not, LuciadRIA always chooses the feature geometry itself to fetch vertices from.

functions vertices
Figure 1. Use of the 'vertices' function to style the individual vertices of the polygon

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Rule>
    <PolygonSymbolizer>
      <Fill>
        <SvgParameter name="fill">#add5ec</SvgParameter>
      </Fill>
      <Stroke>
        <SvgParameter name="stroke">#17afe0</SvgParameter>
      </Stroke>
    </PolygonSymbolizer>
    <PointSymbolizer>
      <Geometry>
        <!-- The geometry on which we want to apply this point symbolizer styling = the vertices of the base geometry -->
        <ogc:Function name="vertices">
          <ogc:PropertyName>the_geom</ogc:PropertyName>
        </ogc:Function>
      </Geometry>
      <Graphic>
        <Mark>
          <WellKnownName>circle</WellKnownName>
          <Fill>
            <SvgParameter name="fill">#0000FF</SvgParameter>
          </Fill>
        </Mark>
        <Size>8</Size>
      </Graphic>
    </PointSymbolizer>
  </Rule>
</FeatureTypeStyle>

StartPoint and startAngle, endPoint and endAngle

You can use the startPoint or endPoint function to add styling to the first or last vertex of your feature geometry. You either replace the styling you already defined on the geometry itself, or you add the styling on top of that styling. The function has a single parameter: the name of the feature property that points to the geometry of which you want to style the individual vertices. No matter if you provide this parameter or not, LuciadRIA always chooses the feature geometry itself to fetch vertices from. The startPoint or endPoint function can be combined with the startAngle and endAngle function to add a custom correctly rotated arrow at the start or end of a line.

functions customArrows
Figure 2. Use of the functions that allow for custom arrows at the start- and endpoint of a directional line

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se"
                  xmlns:ogc="http://www.opengis.net/ogc"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://www.opengis.net/ogc
                   http://schemas.opengis.net/filter/1.1.0/filter.xsd
                   http://www.opengis.net/se
                   http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd"
                  version="1.1.0">
  <Description>
    <Title>San Diego To Los Angeles</Title>
  </Description>
  <Rule>
    <LineSymbolizer>
      <Description>The line connecting San Diego and Los Angeles</Description>
      <Stroke>
        <SvgParameter name="stroke">#FF0000</SvgParameter>
        <SvgParameter name="stroke-width">2</SvgParameter>
      </Stroke>
    </LineSymbolizer>
    <PointSymbolizer>
      <Description>A green arrow in San Diego</Description>
      <Geometry>
        <ogc:Function name="startPoint">
          <ogc:PropertyName>the_geom</ogc:PropertyName>
        </ogc:Function>
      </Geometry>
      <Graphic>
        <Mark>
          <WellKnownName>triangle</WellKnownName>
          <Fill>
            <SvgParameter name="fill">#00FF00</SvgParameter>
            <SvgParameter name="fill-opacity">0.5</SvgParameter>
          </Fill>
          <Stroke>
            <SvgParameter name="stroke">#00FF00</SvgParameter>
            <SvgParameter name="stroke-width">2</SvgParameter>
          </Stroke>
        </Mark>
        <Size>30</Size>
        <Rotation>
          <ogc:Function name="startAngle">
            <ogc:PropertyName>the_geom</ogc:PropertyName>
          </ogc:Function>
        </Rotation>
      </Graphic>
    </PointSymbolizer>
    <PointSymbolizer>
      <Description>A blue arrow in Los Angeles</Description>
      <Geometry>
        <ogc:Function name="endPoint">
          <ogc:PropertyName>the_geom</ogc:PropertyName>
        </ogc:Function>
      </Geometry>
      <Graphic>
        <Mark>
          <WellKnownName>triangle</WellKnownName>
          <Fill>
            <SvgParameter name="fill">#0000FF</SvgParameter>
            <SvgParameter name="fill-opacity">0.5</SvgParameter>
          </Fill>
          <Stroke>
            <SvgParameter name="stroke">#0000FF</SvgParameter>
            <SvgParameter name="stroke-width">2</SvgParameter>
          </Stroke>
        </Mark>
        <Size>30</Size>
        <Rotation>
          <ogc:Function name="endAngle">
            <ogc:PropertyName>the_geom</ogc:PropertyName>
          </ogc:Function>
        </Rotation>
      </Graphic>
    </PointSymbolizer>

  </Rule>
</FeatureTypeStyle>

Recode

You can use the Recode function to apply specific styling based on a certain feature property that varies discretely. The parameters you need for this function are the property that diversifies the styling, followed by the value pairs that map each property value to the applicable styling.

functions recode
Figure 3. Use of the 'Recode' function to color the different states based on their sub-region

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Description>
    <Title>States</Title>
  </Description>
  <Rule>
    <PolygonSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#555555</SvgParameter>
      </Stroke>
      <Fill>
        <SvgParameter name="fill">
          <!-- Fill color based on sub_region using recode -->
          <ogc:Function name="Recode">
            <!-- Value to transform -->
            <ogc:Function name="strTrim">
              <ogc:PropertyName>SUB_REGION</ogc:PropertyName>
            </ogc:Function>

            <!-- Map of input to output values -->
            <ogc:Literal>N Eng</ogc:Literal>
            <ogc:Literal>#6495ED</ogc:Literal>

            <ogc:Literal>Mid Atl</ogc:Literal>
            <ogc:Literal>#B0C4DE</ogc:Literal>

            <ogc:Literal>S Atl</ogc:Literal>
            <ogc:Literal>#00FFFF</ogc:Literal>

            <ogc:Literal>E N Cen</ogc:Literal>
            <ogc:Literal>#9ACD32</ogc:Literal>

            <ogc:Literal>E S Cen</ogc:Literal>
            <ogc:Literal>#00FA9A</ogc:Literal>

            <ogc:Literal>W N Cen</ogc:Literal>
            <ogc:Literal>#FFF8DC</ogc:Literal>

            <ogc:Literal>W S Cen</ogc:Literal>
            <ogc:Literal>#F5DEB3</ogc:Literal>

            <ogc:Literal>Mtn</ogc:Literal>
            <ogc:Literal>#F4A460</ogc:Literal>

            <ogc:Literal>Pacific</ogc:Literal>
            <ogc:Literal>#87CEEB</ogc:Literal>
          </ogc:Function>
        </SvgParameter>
      </Fill>
    </PolygonSymbolizer>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>
      </Label>
      <LabelPlacement>
        <PointPlacement></PointPlacement>
      </LabelPlacement>
      <Font>
        <SvgParameter name="font-family">Tahoma</SvgParameter>
        <SvgParameter name="font-size">20</SvgParameter>
      </Font>
    </TextSymbolizer>
  </Rule>
</FeatureTypeStyle>

Categorize

The Categorize function allows you to apply specific styling based on a certain feature property that varies continuously. The parameters you need for this function are the property that diversifies the styling, followed by the value pairs that map threshold values to the applicable styling for that value range.

functions categorize
Figure 4. Use of the 'Categorize' function to apply color to states based on their population density (population/area): red for densely populated areas (>100 people/m²), blue for sparsely populated areas (<20 people/m²), and yellow for all areas in between (between 20 and 100 people/m²).

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Description>
    <Title>States</Title>
  </Description>
  <Rule>
    <PolygonSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#555555</SvgParameter>
      </Stroke>
      <Fill>
        <SvgParameter name="fill">
          <ogc:Function name="Categorize">
            <!-- Value to transform -->
            <ogc:Div>
              <ogc:PropertyName>POP1996</ogc:PropertyName>
              <ogc:PropertyName>AREA</ogc:PropertyName>
            </ogc:Div>

            <!-- Output values and thresholds -->
            <ogc:Literal>#87CEEB</ogc:Literal>
            <ogc:Literal>20</ogc:Literal>
            <ogc:Literal>#FFFACD</ogc:Literal>
            <ogc:Literal>100</ogc:Literal>
            <ogc:Literal>#F08080</ogc:Literal>

          </ogc:Function>
        </SvgParameter>
      </Fill>
    </PolygonSymbolizer>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>
      </Label>
      <LabelPlacement>
        <PointPlacement></PointPlacement>
      </LabelPlacement>
      <Font>
        <SvgParameter name="font-family">Tahoma</SvgParameter>
        <SvgParameter name="font-size">20</SvgParameter>
      </Font>
    </TextSymbolizer>
  </Rule>
</FeatureTypeStyle>

Interpolate

With the Interpolate function, you can interpolate colors or numbers based on a feature property. For its parameters, you provide the property and assign discrete color or number values to specific property values on the range. These discrete color or number values will be interpolated for property values in between the defining property values.

The Interpolate function allows you to define:

  • A method: specifies if you want to interpolate color or numeric values. The default method is color. Make sure that the method is in-sync with the discrete values that you provide.

  • A mode: specifies on what mapping curve you want to interpolate the values. Only the linear mapping curve option is available. It’s the default option for mode.

functions interpolate
Figure 5. The 'Interpolate' function is used here to assign colors to USA states based on their population size. It interpolates the defining colors: yellow, green, and red.

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Description>
    <Title>States</Title>
  </Description>
  <Rule>
    <PolygonSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#555555</SvgParameter>
      </Stroke>
      <Fill>
        <SvgParameter name="fill">
          <ogc:Function name="Interpolate">
            <!-- Property to transform -->
            <ogc:PropertyName>POP1996</ogc:PropertyName>

            <!-- Mapping curve definition pairs (input, output) -->
            <ogc:Literal>0</ogc:Literal>
            <ogc:Literal>#fefeee</ogc:Literal>

            <ogc:Literal>9000000</ogc:Literal>
            <ogc:Literal>#00ff00</ogc:Literal>

            <ogc:Literal>23000000</ogc:Literal>
            <ogc:Literal>#ff0000</ogc:Literal>

            <!-- Interpolation method - color or numeric - defaults to color -->
            <ogc:Literal>color</ogc:Literal>

            <!-- Interpolation mode - only linear is implemented - defaults to linear -->
            <ogc:Literal>linear</ogc:Literal>
          </ogc:Function>
        </SvgParameter>
      </Fill>
    </PolygonSymbolizer>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>
      </Label>
      <LabelPlacement>
        <PointPlacement></PointPlacement>
      </LabelPlacement>
      <Font>
        <SvgParameter name="font-family">Tahoma</SvgParameter>
        <SvgParameter name="font-size">20</SvgParameter>
      </Font>
    </TextSymbolizer>
  </Rule>
</FeatureTypeStyle>
functions interpolate numeric
Figure 6. The 'Interpolate' function is used here to assign font sizes to the state labels based on the state population size. It applies numeric interpolation to increase the font size of the label text for states with larger populations.

Expand for the code that creates the image above:

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Description>
    <Title>States</Title>
  </Description>
  <Rule>
    <PolygonSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#555555</SvgParameter>
      </Stroke>
      <Fill>
        <SvgParameter name="fill">#cccccc</SvgParameter>
      </Fill>
    </PolygonSymbolizer>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>
      </Label>
      <LabelPlacement>
        <PointPlacement></PointPlacement>
      </LabelPlacement>
      <Font>
        <SvgParameter name="font-family">Tahoma</SvgParameter>
        <SvgParameter name="font-size">
          <ogc:Function name="Interpolate">
            <!-- Property to transform -->
            <ogc:PropertyName>POP1996</ogc:PropertyName>

            <!-- Mapping curve definition pairs (input, output) -->
            <ogc:Literal>0</ogc:Literal>
            <ogc:Literal>10</ogc:Literal>

            <ogc:Literal>9000000</ogc:Literal>
            <ogc:Literal>20</ogc:Literal>

            <ogc:Literal>23000000</ogc:Literal>
            <ogc:Literal>30</ogc:Literal>

            <!-- Interpolation method -->
            <ogc:Literal>numeric</ogc:Literal>
          </ogc:Function>
        </SvgParameter>
      </Font>
    </TextSymbolizer>
  </Rule>
</FeatureTypeStyle>

dateFormat

The 'dateFormat' string formatting function formats a date according to the desired pattern. Check out the supported patterns strings in Table 1, “dateFormat patterns”. There are two ways to use the date formatting functionality. You can use the custom function Program: 'dateFormat', but you can also use the specific Symbology Encoding date formatting function Program: 'FormatDate'.

Program: Using the 'dateFormat' function to show the date-property nicely formatted when used in a label.
<Label>
  <Function name="dateFormat">
    <ogc:Literal>dd-MMMit-yyyy</ogc:Literal>
    <ogc:PropertyName>DATE</ogc:PropertyName>
  </Function>
</Label>
Program: Using the 'FormatDate' tag to show the date-property nicely formatted when used in a label.
<Label>
  <FormatDate>
    <DateValue>
      <ogc:PropertyName>DATE</ogc:PropertyName>
    </DateValue>
    <Pattern>DD-M-YYYY - hh:mm a</Pattern>
  </FormatDate>
</Label>
Table 1. dateFormat patterns
Pattern string Meaning

YYYY

Four digit year

YY

Two-digit year (without century and millennium)

MM

Two-digit month

M

Month, leading zero omitted

MMM

Month displayed by three letter acronym (“FEB”), ISO 639 two-letter language codes as defined by ISO 639 can be appended to create language-dependent variants (MMMde would yield “DEZ” instead of “DEC”)

MMMMM

for display of full month (“February”). The two-letter language code can be appended (MMMMMde would result in ‘Februar’).

DD

Two-digit day

D

Day, leading zero omitted

hh

hour, h is used to omit a leading zero

mm

minute, m is used to omit a leading zero

ss

second, s is used to omit a leading zero

a

am/pm marker

.

point, will appear literally in the result

/

slash, literally

:

colon. literally

-

minus, literally

strTrim

The 'strTrim' string trimming function trims whitespace from the start and the end of a given property.

Program: Using the 'strTrim' function to trim the property used as a label
<Label>
  <ogc:Function name="strTrim">
    <ogc:PropertyName>NAME</ogc:PropertyName>
  </ogc:Function>
</Label>

Adding custom functions

You can add your own functions as functionEvaluators in the SEPainterCreateOptions. You must define your custom functions with a unique name. They can have any number of literals or feature properties as arguments. You define those arguments in the SLD definition when you’re using your custom functions. You can even use nested functions, as illustrated by the sample.

We implemented an example in the SymbologyEncoding sample, where roads now get a width depending on their name. The road names in the sample data convey the road type because they typically contain interstate, state or us.

custom functions
Figure 7. Use of a set of custom functions to differentiate the width of roads based on their type

You could accomplish exactly the same capability through the pre-defined Recode function, but we chose to add two simple custom functions to give you an idea of how a custom function works.

First, you create your SEPainter with an extra option functionEvaluators.

Program: Providing custom functions for road styling demonstrates how to provide the custom functions needed to style the roads based on their type.

Program: Providing custom functions for road styling (from samples/symbologyencoding/SampleLayer.ts)
painter = await createPainterFromString(seSource, {
  strict: true,
  functionEvaluators: roadFunctionEvaluators,
});

Program: Creating custom functions for road styling demonstrates how to create the custom functions needed to style the roads based on their type.

Program: Creating custom functions for road styling (from samples/symbologyencoding/RoadCustomStyling.ts)
export const roadFunctionEvaluators: { [name: string]: FunctionEvaluator<string | number | null | Shape | boolean> } = {
  "roadOuterWidthByName": (name: string): number => {
    if (name.indexOf("Interstate Route") > -1) {
      return 8;
    } else if (name.indexOf("US Route") > -1) {
      return 6;
    } else if (name.indexOf("State Route") > -1) {
      return 4;
    } else {
      return 0;
    }
  },
  "roadInnerWidthFromOuterWidth": (outerWidth: number): number => {
    return outerWidth - 2;
  },
}

Second, you adapt your SLD file to use these functions to determine the stroke widths of your roads instead of providing the widths as a fixed number.

Program: Using custom functions for road styling demonstrates how to use the custom functions to style the roads based on their type in the SLD file. You can see that the roadOuterWidthByName function uses the parameter ogc:PropertyName NAME as an argument. It also shows that the second function, roadInnerWidthFromOuterWidth, uses the nested function roadInnerWidthByName as its argument.

Program: Using custom functions for road styling
<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" version="1.1.0">
  <Description>
    <Title>US roads</Title>
  </Description>
  <Rule>
    <MinScaleDenominator>6.0E5</MinScaleDenominator>
    <MaxScaleDenominator>5.0E6</MaxScaleDenominator>
    <LineSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#93622a</SvgParameter>
        <SvgParameter name="stroke-width">
          <ogc:Function name="roadOuterWidthByName">
            <ogc:PropertyName>NAME</ogc:PropertyName>
          </ogc:Function>
        </SvgParameter>
      </Stroke>
    </LineSymbolizer>
    <LineSymbolizer>
      <Stroke>
        <SvgParameter name="stroke">#ffaf64</SvgParameter>
        <SvgParameter name="stroke-width">
          <ogc:Function name="roadInnerWidthFromOuterWidth">
            <ogc:Function name="roadOuterWidthByName">
              <ogc:PropertyName>NAME</ogc:PropertyName>
            </ogc:Function>
          </ogc:Function>
        </SvgParameter>
      </Stroke>
    </LineSymbolizer>
  </Rule>
</FeatureTypeStyle>

You can provide any property of the feature you want to your function for styling:

  • Providing feature properties: In code, you fetch a regular feature property with feature.property["property_name"]. In your SLD definition, you pass it along correctly as <ogc:PropertyName>property_name</ogc:PropertyName>.

  • Providing a feature ID: In code, you fetch the ID of your feature with feature.id. In your SLD definition, you pass it along correctly as <ogc:PropertyName>id</ogc:PropertyName>.

  • Providing a feature shape: In code, you fetch the shape of your feature with feature.shape or with feature.geometry. In your SLD definition, you pass it along correctly as <ogc:PropertyName>the_geom</ogc:PropertyName> or <ogc:PropertyName>GEOMETRY</ogc:PropertyName>.