FeatureLayer and FeaturePainter

Vector features are visualized in a view/feature/FeatureLayer. The most important aspect of a FeatureLayer is that it must define a view/feature/FeaturePainter.

The feature painter determines how the features in the layer are visualized. It allows you to:

The most important method on the FeaturePainter is the paintBody method:

paintBody(geoCanvas, //The GeoCanvas to render on
          feature,   //The Feature that should be rendered
          shape,     //The Shape to render
          layer,     //The layer containing the feature
          map,       //The map containing the layer
          paintState //The paint state, indicating whether the Feature is selected or not
);

In this method, you have full control over how you want to render the Feature, what styling you want to use, …​ . For example, a very straightforward implementation could be

const featurePainter = new FeaturePainter();
//Use a custom paintBody implementation
featurePainter.paintBody = function(geoCanvas, feature, shape, layer, map, paintState) {
  geoCanvas.drawShape(shape, {
    stroke: {
      color: "rgb(0,0,255)",
      width: 5
    },
    fill: {color: "rgba(0,0,255,0.5)"}
  });
};

A feature is visualized and styled by drawing on a view/style/GeoCanvas instance. The GeoCanvas instance is passed as the first parameter of the painter’s draw methods. It performs vector feature drawing operations in a geographical coordinate reference, which is identified via the shape’s reference.

In this specific example, we:

  • Use the shape of the feature as the geometry to render

  • Specify a stroke and line color as styling

  • Use the same styling for all objects, even when they are selected, because we’re ignoring the paint state.

More advanced examples are available in the remainder of this tutorial.

There are more specialized sub-classes of FeaturePainter available in the API, designed for certain use cases.

For example, you can achieve the behavior of the example above by using a BasicFeaturePainter.

Styling options

You can style a shape in several ways:

  • You can render the shape in accordance with its shape type, and make use of the shape styling options offered by view/style/ShapeStyle:

    • stroke style determines the style of the strokes that form the polylines and the outlines of polygons. You can choose between simple stroke style options or more complex stroked line styles. The simple stroke style is represented by view/style/LineStyle. It contains options like the line color, line width and dashing. You can use view/style/complexstroke/ComplexStrokedLineStyle to achieve more complex stroked styles. It allows you to stroke a line with complex patterns composed of different shapes and text, by means of view/style/complexstroke/PatternFactory.

    • line markers allow you to add markers at the beginning and the end of a line.

    • fill style determines how polygons are filled. A fill style can be configured as a fill color or as a fill pattern. Fill styles are not applied to polylines.

    • paint order determines the visualization order of shapes in a layer.

    • line type determines how lines between consecutive points in the shape are interpreted. For shapes that are defined in a geodetic coordinate system, the line type translates to geodetic lines, if you chose the SHORTEST_DISTANCE value, or rhumb lines if you chose the CONSTANT_BEARING value.

  • You can render the shape as an icon. An icon is an image like a JPEG or PNG file.

  • You can display a text string at a shape’s focus point.

For detailed information on how to apply these styling options, see the API reference documentation. The relevant classes and objects for styling are view/style/GeoCanvas, view/style/ShapeStyle, view/style/IconStyle, view/style/FillStyle, view/style/LineStyle and view/style/complexstroke/ComplexStrokedLineStyle.

Examples

Distinct styling for selected objects

In the following example, we use distinct styling for selected and non-selected objects. We check the `paintState`before deciding which styling to use.

In the example, zones are polygons drawn with a fill and stroke style. If an object is selected, we want to use a distinct stroke color, stroke width and dashing pattern. Selected objects are also visualized with a fill pattern, in addition to the background color.

Program: a FeaturePainter that styles polygons differently based on their selection status (from samples/selection/main.js)
  var painter = new FeaturePainter();

  var selectedPattern = new HatchedImageBuilder()
    .patterns([HatchedImageBuilder.Pattern.SLASH, HatchedImageBuilder.Pattern.BACKGROUND])
    .lineColor("rgba( 255, 255, 255, 0.5)")
    .lineWidth(4)
    .patternSize(20, 20)
    .backgroundColor("rgba(0 ,0 , 255, 0.5)")
    .build();

  painter.paintBody = function(geoCanvas, feature, shape, layer, map, state) {
    if (state.selected) {
      geoCanvas.drawShape(shape, {
        stroke: {
          color: "rgb(255,99,71)",
          width: 5,
          dash: [8, 2]
        },
        fill: {
          color: "rgba(0,0,255,0.5)",
          image: selectedPattern
        }
      });
    } else {
      geoCanvas.drawShape(shape, {
        stroke: {
          color: "rgb(0,0,255)",
          width: 5
        },
        fill: {
          color: "rgba(0,0,255,0.5)"
        }
      });
    }
  };

Advanced example: flight plan with waypoints

This example shows a more complex painter. A polyline that represents a flight track, is drawn as a wide yellow line. On top of this line, and each point of the track, a waypoint icon is drawn.

When the track is selected, the line becomes red.

trackwaypoints
const style = {
  strokeWidth: 6,
  stroke: {
    color: "rgba(255,255,0,1)"
  }
};
const selectedStyle = {
  strokeWidth: 6,
  stroke: {
    color: "rgba(255,255,0,1)"
  }
};

const painter = new FeaturePainter();
painter.paintBody = function(geoCanvas, feature, shape, layer, map, paintState) {
  if (shape instanceof Polyline) {
    let i;
    // draw a line, style depends on whether the line is selected or not
    geoCanvas.drawShape(shape, paintState.selected ? selectedStyle : style);
    // and draw an icon on each point in the polyline
    i = shape.pointCount;
    while (i--) {
      geoCanvas.drawIcon(shape.getPoint(i), {
        url: "../../resources/img/waypoint.png",
        width: "32px",
        height: "32px",
        offsetX: -16,
        offsetY: -16
      });
    }
  }
};

For the complete list of supported drawing operations on the GeoCanvas, see the API reference.