Question

How do I style different elements of a layer differently, depending on the value of an attribute?

For example, I have time zone data which includes an attribute associating an integer from 1 to 8 to each time zone, for the purposes of colouring the time zones on a map. How can I associate a style to each value of the attribute, and use it to colour the time zones in different colours?

Was it helpful?

Solution

This answer is for Geotools 9.2

Below is an example which you can adopt, see below for some ideas how to apply it to your requirements.

The example is about polygons. It has different styles for selected and visible features and for small and large scales:

protected final StyleFactory styleFactory =
  CommonFactoryFinder.getStyleFactory(GeoTools.getDefaultHints());
protected final FilterFactory2 filterFactory =
  CommonFactoryFinder.getFilterFactory2();

protected Rule createLayerRule
  ( Color outlineColor
  , float strokeWidth
  , Color fillColor
  , float opacity
  , Filter filter
  , double minScaleDenominator
  , double maxScaleDenominator)
{
  Stroke stroke =
      outlineColor != null
    ? styleFactory.createStroke
       ( filterFactory.literal(outlineColor)
       , filterFactory.literal(strokeWidth)
       , filterFactory.literal(opacity))
    : null;//Stroke.NULL;
  Fill fill = 
      fillColor != null 
    ? styleFactory.createFill
       ( filterFactory.literal(fillColor)
       , filterFactory.literal(opacity))
    : null;//Fill.NULL;

  PolygonSymbolizer symbolizer = 
    styleFactory.createPolygonSymbolizer(stroke, fill, null);

  return createRule(filter, minScaleDenominator, maxScaleDenominator, symbolizer);
}

// IDs of visible features, programmatically updated. 
protected final Set<FeatureId> visibleFeatureIDs = new HashSet<FeatureId>();

// IDs of selected features, programmatically updated. 
protected final Set<FeatureId> selectedFeatureIDs = new HashSet<FeatureId>();

protected Style createLayerStyle()
{
  Filter selectionFilter = filterFactory.id(selectedFeatureIDs);
  Filter visibilityFilter = filterFactory.and
    ( Arrays.asList
        ( filterFactory.not
            (selectionFilter)
        , filterFactory.id(visibleFeatureIDs)
        )
    );
  FeatureTypeStyle fts = styleFactory.createFeatureTypeStyle
    ( new Rule[]
      {
        // hope constants below are self explaining
        createLayerRule
          ( SELECTED_OUTLINE_COLOR 
          , STROKE_WIDTH_LARGE_SCALE
          , SELECTED_FILL_COLOR
          , SELECTED_OPACITY
          , selectionFilter
          , STYLE_SCALE_LIMIT
          , Double.NaN)
      , createLayerRule
          ( UNSELECTED_OUTLINE_COLOR
          , STROKE_WIDTH_LARGE_SCALE
          , UNSELECTED_FILL_COLOR
          , UNSELECTED_OPACITY
          , visibilityFilter
          , STYLE_SCALE_LIMIT
          , Double.NaN)
      , createLayerRule
          ( SELECTED_OUTLINE_COLOR
          , STROKE_WIDTH_SMALL_SCALE
          , SELECTED_FILL_COLOR
          , SELECTED_OPACITY
          , selectionFilter
          , Double.NaN
          , STYLE_SCALE_LIMIT)
      , createLayerRule
          ( UNSELECTED_OUTLINE_COLOR
          , STROKE_WIDTH_SMALL_SCALE
          , UNSELECTED_FILL_COLOR
          , UNSELECTED_OPACITY
          , visibilityFilter
          , Double.NaN
          , STYLE_SCALE_LIMIT)
      }
    );

  Style style = styleFactory.createStyle();
  style.featureTypeStyles().add(fts);

  return style;
}

// layer creation
FeatureLayer someMethode()
{
  ...
  FeatureLayer layer = new FeatureLayer
    ( dataStore.getFeatureSource()
    , createLayerStyle()
    , "Zipcodes"
    );
  ...
  return layer;
}

// style update if visible or selected features have changed
void someOtherMethod(FeatureLayer layer)
{
   ... // update selectedFeatureIDs or visibleFeatureIDs
   layer.setStyle(createLayerStyle());
}

Of course optimizations are possible and welcome.

For your requirement the following may help:

  1. You need 8 rules (see createRule(..) above), if you want to have one style for all scales (or 16 for small and large scales).
  2. Define 8 filters using FilterFactory.equals(Expression, Expression) where first expression is of type AttributeExpressionImpl and second of type LiteralExpressionImpl
  3. Be aware that there is another method equal (without s) in FilterFactory2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top