layer_themes_categorized.mjs

/**
### mapp.layer.themes.categorized()

The module exports the categorized function as a mapp.layer.theme. 

@module /layer/themes/categorized
*/

/**
@function categorized

@description
The categorized theme method will assign a style from category matching the features properties.

Cluster features may not be styled by a categorized theme.

A theme can have a fields array to apply an icon style array for the individual property fields.

@param {Object} theme The theme configuration object.
@param {string} [theme.field] The feature property field to theme.
@param {array} [theme.fields] A fields array to style multiple feature properties.
@param {Array} theme.categories
@param {Object} feature
@param {Object} feature.properties
@param {Array} [feature.properties.features] A cluster feature will have a features array property.
*/

export default function categorized(theme, feature) {
  // The categorized theme requires feature.properties.
  if (!feature.properties) return;

  // Cluster features can not be styled by category.
  if (feature.properties.features?.length > 1) return;

  let flat;

  // Theme is using multiple fields.
  if (Array.isArray(theme.fields)) {
    // Map different theme fields
    feature.style.icon = theme.fields
      .map((field) => {
        // Get the field value from feature properties
        const catValue = feature.properties[field];

        // Find category matching field and catValue
        const cat = theme.categories.find(
          (cat) =>
            (cat.value === encodeURIComponent(catValue) ||
              cat.value === catValue) &&
            cat.field === field,
        );

        if (!cat) return;

        flat ||= Array.isArray(cat.style.icon);

        return cat.style.icon;

        // Filter out empty icon entries from map response.
      })
      .filter((icon) => !!icon);

    if (flat) {
      feature.style.icon = feature.style.icon.flat();
    }

    return;
  }

  const catValue = feature.properties[theme.field];

  const cat = theme.categories.find(
    (cat) =>
      cat.value === encodeURIComponent(catValue) || cat.value === catValue,
  );

  if (!cat) return;

  if (cat.style === null) {
    feature.style = null;
    return;
  }

  // Spread cat style to retain scale property
  feature.style = {
    ...feature.style,
    ...cat.style,
  };
}