utils_olStyle.mjs

/**
### /utils/olStyle

The olStyle utility module exports the default olStyle method.

@module /utils/olStyle
*/

/**
@global
@typedef {Object} feature-style
A JSON mapp-style object.
@property {string} [svg] The SVG source for the icon.
@property {string} [type] The type of the icon.
@property {Array|Object} [icon] The icon configuration or an array of icon configurations.
@property {number} [width] The width of the icon or symbol.
@property {number} [height] The height of the icon or symbol.
@property {string} [strokeColor] The stroke color of the line symbol.
@property {number} [strokeWidth] The stroke width of the line symbol.
@property {string} [fillColor] The fill color of the polygon symbol.
@property {number} [fillOpacity] The fill opacity of the polygon symbol.
*/

/**
@function olStyle

@description
The olStyle method takes a mapp-style JSON representation to create an Openlayers style object for rendering Openlayers features in the Openlayers mapview.Map.

@param {feature-style} style A JSON mapp-style object.

@returns {Object} An Openlayers feature style object.
*/

export default function olStyle(style, feature) {

  if (!style) return null;

  // Array for OL Style objects.
  const Styles = []

  // The style object must always be processed as an array.
  style = Array.isArray(style) ? style : [style]

  // Iterate through style array.
  style.forEach(style => {

    // Only process icon for features if they are point geometries.
    if (style.icon) {

      // Iterate through icon style array.
      if (Array.isArray(style.icon)) {

        style.icon.forEach(icon => iconStyle(style, icon))
      } else {

        iconStyle(style, style.icon)
      }

      function iconStyle(style, icon) {

        // Calculate scale for icon render.
        let scale = icon.scale || 1
        scale *= style.scale || 1
        scale *= style.clusterScale || 1
        scale *= style.fieldScale || 1
        scale *= style.zoomInScale || 1
        scale *= style.zoomOutScale || 1
        scale *= style.highlightScale || 1

        // Create icon url from svgSymbols method if not defined as url or svg source.
        icon.url = icon.url || icon.svg || mapp.utils.svgSymbols[icon.type || 'dot'](icon, feature)

        if (!icon.url) return;

        // Push OL icon Style into Styles array.
        Styles.push(new ol.style.Style({
          image: new ol.style.Icon({
            src: icon.url,
            crossOrigin: 'anonymous',
            scale: scale,
            anchor: icon.anchor || [0.5, 0.5],
          }),
          zIndex: style.zIndex
        }))
      }
    }

    if (style.fillColor || style.strokeColor) {

      // Create OL fill.
      const fill = style.fillColor && new ol.style.Fill({
        color: mapp.utils.hexa(style.fillColor, style.fillOpacity)
      })

      // Create OL stroke.
      const stroke = style.strokeColor && new ol.style.Stroke({
        color: mapp.utils.hexa(style.strokeColor, style.strokeOpacity),
        width: parseFloat(style.strokeWidth || 1)
      })

      // Push OL vector Style into Styles array.
      Styles.push(new ol.style.Style({ fill, stroke, zIndex: style.zIndex }))
    }

    // Create label style if label text is not undefined.
    if (typeof style.label?.text !== 'undefined') {

      const text = new ol.style.Text({
        font: style.label.font || '12px sans-serif',
        text: String(style.label.text),
        overflow: style.label.overflow,
        offsetY: style.label.offsetY,
        offsetX: style.label.offsetX,
        stroke: style.label.strokeColor && new ol.style.Stroke({
          color: style.label.strokeColor,
          width: style.label.strokeWidth || 1
        }),
        fill: new ol.style.Fill({
          color: style.label.fillColor || '#000'
        })
      })

      // Push OL text Style into Styles array.
      Styles.push(new ol.style.Style({ text, zIndex: style.zIndex }))
    }

  })

  // Set Styles object to cache style.
  feature?.set?.('Styles', Styles, true)

  return Styles
}