ArcGIS Runtime SDK for .NET

Label map features

Features and graphics in your ArcGIS Runtime SDK app can be labeled using a combination of attribute values, text strings, and values calculated with an expression. You can determine how labels are positioned and prioritized, and how conflicts between overlapping labels are automatically and dynamically resolved. Define any number of label classes for a layer to set unique labels for distinct groups of features.

Define labels for features or graphics

Feature layers and graphics overlays provide the ability to show or hide labels in the map and to control a variety of labeling behavior. A label definition is used to specify what labels look like (font, size, color, angle, and so on), at which scales they should be visible, the text to display (which attributes, for example), as well as which features should be labeled. If you want to label all features in your layer the same way, you can define labeling with a single label definition. If you want to display different labels for different types of features, you can add as many label definitions as you need to define distinct sets of features for labeling. For graphics overlays and feature layers, labels are rendered by the client app.

Note:

At this release, labeling of feature layers and graphics overlays is only supported in 2D (maps). In 3D (scenes), only map image sublayer labeling is supported.

A label definition is constructed as a JSON string using the syntax defined in the Web map specification for label definition. Most properties in the label definition are optional and will use a default value if not assigned explicitly. At a minimum, you must provide a labelExpressionInfo (or labelExpression), a labelPlacement option, and a symbol (with at least color, font size, and type) to display labels for a layer. The JSON below provides the most basic label definition for a layer.

{
  "labelExpressionInfo": 
  {
    "expression": "return $feature.address;"
  },
  "labelPlacement": "esriServerPolygonPlacementAlwaysHorizontal",
  "symbol": 
  {
    "color": [255,0,255,123],
    "font": { "size": 16 },
    "type": "esriTS"
  }
}

The preceding example uses an Arcade expression for the labelExpressionInfo to label each feature with the value of its address attribute. See the Arcade documentation for information about working with Arcade expressions across the ArcGIS platform. The use of Arcade expressions is recommended when labeling feature layers or graphics overlays.

Caution:

Label definitions for a map image layer must use the ArcGIS Server REST API for label expressions. Arcade expressions are not supported for labels rendered by ArcGIS Server.

In your ArcGIS Runtime SDK code, the JSON label definitions are managed by the LabelDefinition class. Two static methods on the class, FromJson and ToJson, allow you to serialize and deserialize JSON label definitions. Feature layers, map image sublayers, and graphics overlays all maintain a collection of label definitions in a LabelDefinitions property. Labels for a layer or graphics overlay can be shown or hidden using the LabelsEnabled property.

Note:

ArcGIS Runtime will render labels for web map layers that have label definitions stored with them. You can use the LabelDefinition.ToJson method to deserialize label definitions stored with a web map to a JSON string.

The following example creates a label definition and adds it to a feature layer's label definition collection.

// Create a StringBuilder to create the label definition JSON string
StringBuilder addressLabelsBuilder = new StringBuilder();
addressLabelsBuilder.AppendLine("{");
//     Define a labeling expression that will show the address attribute value
addressLabelsBuilder.AppendLine("\"labelExpressionInfo\": {");
addressLabelsBuilder.AppendLine("\"expression\": \"return $feature.address;\"},");
//     Align labels horizontally
addressLabelsBuilder.AppendLine("\"labelPlacement\": \"esriServerPolygonPlacementAlwaysHorizontal\",");
//     Don't allow labels to overlap other labels
addressLabelsBuilder.AppendLine("\"allowOverlapOfLabel\": \"exclude\",");
//     Use a green bold text symbol
addressLabelsBuilder.AppendLine("\"symbol\": {");
addressLabelsBuilder.AppendLine("\"color\": [0,255,50,255],");
addressLabelsBuilder.AppendLine("\"font\": {\"size\": 18, \"weight\": \"bold\"},");
addressLabelsBuilder.AppendLine("\"type\": \"esriTS\"}");
addressLabelsBuilder.AppendLine("}");

// Get the label definition string
var addressLabelsJson = addressLabelsBuilder.ToString();

// Create a new LabelDefintion object using the static FromJson method
LabelDefinition labelDef = LabelDefinition.FromJson(addressLabelsJson);

// Clear the current collection of label definitions (if any)
_parcelsLayer.LabelDefinitions.Clear();

// Add this label definition to the collection
_parcelsLayer.LabelDefinitions.Add(labelDef);

// Make sure labeling is enabled for the layer
_parcelsLayer.LabelsEnabled = true;

Parcels labeled with their address

Some of the more common aspects of label behavior you can control for a label class are described in the following section (web map specification names in parentheses). A more comprehensive list (as well as the specifics of the JSON syntax) are available in the Web map specification for label definition.

  • Label text (labelExpressionInfo.expression)—A label expression can be used to determine the text to display for each feature in the label definition. The label text can come from a combination of available attributes, text strings, and expressions. A label showing length in meters from values in feet from an attribute named length_ft, for example, may look like this: ($feature.length_ft * 0.3048) + ' meters'. A feature with a length_ft value of 343 would result in a label of 104.546 meters.
  • Text symbol (symbol)—The font, size, color, angle, and so on, used to display labels in the definition. You can also provide a border or background for the label symbol.
  • Maximum scale (maxScale)—The largest scale at which labels in the definition are shown. This value represents the scale denominator for the zoomed-in scale; a value of 0 means a maximum scale is not applied.
  • Minimum scale (minScale)—The smallest scale at which labels in the definition are shown. This value represents the scale denominator for the zoomed-out scale; a value of 0 means a minimum scale is not applied.
  • Placement (labelPlacement)—Labels can be placed at a specified position relative to the features they describe. There are different options for placement depending on the geometry of the feature being labeled. Line features, for example, may have labels placed above the center of the line, below the center of the line, above the end point, and so on.
  • Position (deconflictionStrategy)—Logic for positioning labels can be controlled using a variety of options, such as whether they should be allowed to overlap with features in the layer.
  • Priority (priority)—A label definition can be given a priority relative to other definitions in the layer. If labels from different definitions conflict in their placement, the label from the highest-priority definition will be displayed.
  • Label overlap with other labels (allowOverlapOfLabel)—Whether other labels are allowed to overlap this label. One of the following values is expected: allow means that labels are allowed to overlap this label, avoid means that labels that would overlap will move as much possible to minimize the overlap, and exclude (the default) means that labels that would overlap are not placed.
  • Label overlap with features—Whether other labels are allowed to overlap a polygon edge (allowOverlapOfFeatureBoundary) or feature (allowOverlapOfFeatureInterior). One of the following values is expected: allow means that labels are allowed to overlap, avoid means that labels that would overlap will move as much possible to minimize the overlap, and exclude means that labels that would overlap a feature are not placed. The default value is allow for lines and polygons and exclude for points.
  • Which features to label (where)—The features labeled with the label definition are determined by evaluating an attribute expression. If this expression is not defined, all features are included in the definition. When using multiple label definitions, it's important that expressions uniquely assign features for each definition.

Creating multiple label definitions for a single layer is useful when you want to distinguish labels for certain types of features. When labeling a cities layer, for example, you may want to display capital cities with a larger font or different color.

Define labels for a map image layer

Labels for map image sublayers (ArcGISMapImageLayer) can be defined in much the same way as labels for feature layers and graphics overlays. The main difference is that labels for map image layers are rendered by the server and not in your client app. You must therefore use ArcGIS Server REST API syntax to define your label expressions, rather than the Arcade syntax you can use with feature layers and graphics overlays. Labels for a map image sublayer are supported for layers displayed in 2D (maps) and in 3D (scenes).

The JSON below creates a label definition that uses labelExpression with ArcGIS Server REST syntax. This differs from the preceding example for graphics and features that used labelExpressionInfo.expression and Arcade syntax.

{
  "labelExpression": "[areaname]",
  "labelPlacement": "esriServerPointLabelPlacementAboveCenter",
  "symbol": {
    "color": [255,0,255,123],
    "font": {"size": 16},
    "type": "esriTS"
  }
}

The following example creates two label definitions (with REST syntax for the label expressions) and adds them to the label definitions collection for a map image sublayer. The where expression is used to identify features for each label definition, one for capital cities and one for all other cities.

// Define two label definitions: one for capital cities and one for everything else
StringBuilder capitalLabelsBuilder = new StringBuilder();
StringBuilder otherLabelsBuilder = new StringBuilder();

// Use a StringBuilder to create the label definition JSON string for capital cities
capitalLabelsBuilder.AppendLine("{");
//     Define a labeling expression (REST syntax) that will show the 'areaname' attribute value
capitalLabelsBuilder.AppendLine("\"labelExpression\": \"[areaname]\",");
//     Align labels above the center of each point
capitalLabelsBuilder.AppendLine("\"labelPlacement\": \"esriServerPointLabelPlacementAboveCenter\",");
//     Don't allow labels to overlap other labels
capitalLabelsBuilder.AppendLine("\"allowOverlapOfLabel\": \"exclude\",");
//     Use a white bold text symbol
capitalLabelsBuilder.AppendLine("\"symbol\": {");
capitalLabelsBuilder.AppendLine("\"color\": [255,255,255,255],");
capitalLabelsBuilder.AppendLine("\"font\": {\"size\": 18, \"weight\": \"bold\"},");
capitalLabelsBuilder.AppendLine("\"type\": \"esriTS\"},");
//     This definition is for cities with a value of 'Y' for the capital attribute
capitalLabelsBuilder.AppendLine("\"where\": \"[capital] = 'Y'\"");
capitalLabelsBuilder.AppendLine("}");

// Get the label definition string for capital cities
var capitalLabelsJson = capitalLabelsBuilder.ToString();

// Create a LabelDefintion object for capital cities using the static FromJson method
LabelDefinition capitalsLabelDef = LabelDefinition.FromJson(capitalLabelsJson);

// Use a StringBuilder to create the label definition JSON string for non-capitals               
otherLabelsBuilder.AppendLine("{");
//     Define a labeling expression (REST syntax) that will show the 'areaname' attribute value
otherLabelsBuilder.AppendLine("\"labelExpression\": \"[areaname]\",");
//     Align labels above the center of each point
otherLabelsBuilder.AppendLine("\"labelPlacement\": \"esriServerPointLabelPlacementAboveCenter\",");
//     Don't allow labels to overlap other labels
otherLabelsBuilder.AppendLine("\"allowOverlapOfLabel\": \"exclude\",");
//     Use a smaller beige text symbol
otherLabelsBuilder.AppendLine("\"symbol\": {");
otherLabelsBuilder.AppendLine("\"color\": [255,255,110,255],");
otherLabelsBuilder.AppendLine("\"font\": {\"size\": 12},");
otherLabelsBuilder.AppendLine("\"type\": \"esriTS\"},");
//     This definition is for cities with a value of 'N' for the capital attribute
otherLabelsBuilder.AppendLine("\"where\": \"[capital] = 'N'\"");
otherLabelsBuilder.AppendLine("}");

// Get the label definition string for non-capitals
var otherLabelsJson = otherLabelsBuilder.ToString();

// Create a LabelDefintion object for non-capitals using the static FromJson method
LabelDefinition othersLabelDef = LabelDefinition.FromJson(otherLabelsJson);

// Get the cities sublayer (first sublayer in an ArcGISMapImageLayer)
ArcGISMapImageSublayer subLayer = _citiesLayer.Sublayers[0] as ArcGISMapImageSublayer;

// Enable labels
subLayer.LabelsEnabled = true;

// Clear any existing label definitions
subLayer.LabelDefinitions.Clear();
  // Add the two label definitions to the collection
subLayer.LabelDefinitions.Add(capitalsLabelDef);
subLayer.LabelDefinitions.Add(othersLabelDef);
Note:

The label definitions in the preceding code would also work for a feature layer or graphics overlay (assuming the 'areaname' attribute is present in the data).

Label classes for capital and noncapital cities