This article describes more advanced labeling topics. The labeling process starts with explaining the labeling process.

The labeling process

Figure 1, “Labeling sequence diagram” shows the typical workflow of labeling domain objects in a view.

labeling sequence
Figure 1. Labeling sequence diagram

When the view receives a paint request through the method paintGXYView(), it asks the view label placer to compute positions for all layers. The view label placer collects relevant label information (for example, by querying the layer) and decides which labels get painted and where they are painted. This information is stored in the layer’s label locations. After this, the view loops over all of its layers and asks each layer to paint their labels. In its turn the layer queries its stored label locations. For each label, a label painter is retrieved and asked to paint the label.

Using label painters and label editors programmatically

For some reasons you might want to access a label painter or label editor programmatically, for example to retrieve the bounds of a label, or to manually paint or edit a label. After setting the domain object on the painter and/or editor using setObject, the following information is required:

  • the label index of the label to work with, in case your domain object requires multiple labels (see setLabelIndex). It is up to the label painter implementation to determine how many labels it allows to paint (see getLabelCount).

  • the sub label index of the label to work with, in case your domain object requires multiple labels (see setSubLabelIndex). It is up to the label painter implementation to determine how many sublabels it allows to paint (see getSubLabelCount).

  • the location of the label to work with (see setLabelLocation). The location instance is used to position the label by the label painter. It is adjusted by the label editor in the editLabel method.

If you want to reuse the label location stored in the ILcdGXYEditableLabelsLayer, as determined, for example, by the view label placer, you can retrieve it from the layer’s label location using ALcdLabelLocations.getLabelLocationSFCT, as described in Storing and retrieving label locations. To store a label location that has been changed by a label editor use ALcdLabelLocations.putLabelLocation.

Program: Determining the location of the labels shows how to access an ILcdGXYLabelPainter2 to determine the bounds of a label.

Program: Determining the location of the labels
// obtain the location information from the ALcdLabelLocations instance
labelLocations.getLabelLocationSFCT(domain_object, labelIndex, subLabelIndex, view, labelLocation);

// let the label painter interpret this information
ILcdGXYLabelPainter label_painter = layer.getGXYLabelPainter(domain_object);
if (label_painter instanceof ILcdGXYLabelPainter2) {
  ILcdGXYLabelPainter2 label_painter_2 = (ILcdGXYLabelPainter2) label_painter;
  label_painter_2.setLabelIndex(labelIndex);
  label_painter_2.setSubLabelIndex(subLabelIndex);
  label_painter_2.setLabelLocation(labelLocation);
  label_painter_2.labelBoundsSFCT(graphics, mode, context, rectangleSFCT);
  // rectangleSFCT now contains the location (in view coordinates) of the label
}

Implementing your own label painter

To implement an ILcdGXYLabelPainter2, you need to support the following major operations:

  • labelBoundsSFCT: calculates the bounds and rotation of the label. The bounds of the label is stored in the given Rectangle and the rotation is returned as a double.

  • paintLabel: actually paints the label.

  • isLabelTouched: allows interaction with the label.

  • labelAnchorPointSFCT: allows to retrieve an anchor point of the label for other application objects to use, for example as a base position for depending labels (see Labeling labels).

Optionally, you can provide snap targets for other editors to snap to with the supportLabelSnap and labelSnapTarget methods.

Implementing your own label editor

The most important method when implementing an ILcdGXYLabelEditor is editLabel. This method is responsible for changing the label location in response to the user interaction. The information about the input is available in the ILcdGXYContext instance that is passed as a parameter. How this input is interpreted depends on the mode that is passed as parameter.

It is the task of the editor to apply the information that is given in the context and the mode to the TLcdLabelLocation instance that was previously set on it. The class that asked the editor to apply the changes can then retrieve the TLcdLabelLocation instance. Thus, it is not the responsibility of the ILcdGXYLabelEditor to persist the changes, for example in an ALcdLabelLocations instance, but it is up to the client of the label editor to do this.

Because the label painter provides the visual indication while the user is editing the label, the implementation of the label editor is usually tightly coupled with the implementation of the label painter. This is similar to the situation with the painters and editors used to paint/edit the domain objects as described in Using an ILcdGXYEditor.

Implementing your own placement algorithm

To completely customize the label placement in your application, you can write your own ILcdGXYLabelingAlgorithm. A labeling algorithm has two major steps:

  1. collect relevant label information (see the collectLabelInfo method)

  2. determine label positions (see the computeLabelPlacements method)

Because the labeling itself may take place asynchronously, it is important to collect all relevant information that cannot be accessed asynchronously in the collect step.

Because labeling is often about iterating over a number of possible positions and checking if they overlap, a special class ALcdGXYDiscretePlacementsLabelingAlgorithm is provided to support this. To implement this algorithm, you need to implement the following:

  • an iterator for the possible labels

  • an iterator for the possible label positions of each label

  • an evaluator that checks if a label position is qualified for placement. Usually an evaluator checks if a label overlaps with the already placed labels using an ILcdLabelConflictChecker.

The labels.createalgorithm.* sample shows how to create a simple ALcdGXYDiscretePlacementsLabelingAlgorithm that places all labels on the object’s anchor point, avoiding overlapping labels.