Label styling through Display Rules

On this page you will gain knowledge of how to style marker labels using Display Rules. NB: the stylings show on this page are only available when using MapsIndoors together with the Mapbox Maps SDK.

Basic styling and Flat Labels are available as of SDK version 4.3.0, Graphic Labels are available as of SDK version 4.4.0

To get an overview of what Display Rules are and can be used for, read the Display Rules page first.

Basic styling

There are a number of fields in Display Rules that can be used to style the label:

MapsIndoors.getMainDisplayRule()?.let { dr ->
    // The color of the label as a hex string
    val labelTextColor: String? = dr.labelTextColor
    // The size of the label in pixels
    val labelTextSize: Int? = dr.labelTextSize
    // The opacity of the label as a value between 0 and 1
    val labelTextOpacity: Float? = dr.labelTextOpacity
    // The color of the label's halo
    val labelHaloColor: String? = dr.labelHaloColor
    // The width of the halo in pixels, this value should not be more than 1/4 of the LabelSize
    val labelHaloWidth: Int? = dr.labelHaloWidth
    // The distance at which the halo begins to blur, this should not be larger than HaloWidth
    val labelHaloBlur: Int? = dr.labelHaloBlur
}

In addition to these styling fields there are also fields that determine when to display the label. If you want a full list of the fields available for configuration on Display Rules, look here.

All examples have been using the demo solution and all changes have been applied to the Main Display Rule.

Styling the label text

With these fields it is possible to style the label to fit your design. In the following example we create a function that changes the styling on a label by doubling the size of the text, and changing the text color to green ("#00FF00").

fun styleLabelText(dr: MPDisplayRule) {
    dr.labelTextSize = dr.labelTextSize?.times(2)
    dr.labelTextColor = "#00FF00"
}

If we apply this function to a Display Rule, it could look like this:

Styling the label halo

It is also possible to style the halo, but the halo is a bit harder to properly style. the haloWidth and haloBlur fields have immense impact on the feel of the labels, so make sure to try out many possible configurations! In this example we change the text size to be 24 to get a bigger range out of the halo. Here we want a soft halo, so we make the haloBlur larger than the haloWidth:

fun styleLabelHalo(dr: MPDisplayRule) {
    dr.labelTextSize = 24
    dr.labelHaloWidth = 1
    dr.labelHaloColor = "#000040"
    dr.labelHaloBlur = 3
}

If applied it might look like this:

Styling text and halo

With the knowledge of styling the text and label we can now coordinate the styling of the entire label, and create a style that utilizes both. In this example we have a function that modifies the label to be twice as large as it was set in the CMS, and make the text white, with a thin outline halo.

fun styleLabel(dr: MPDisplayRule) {
    dr.labelTextSize = dr.labelTextSize?.times(2)
    dr.labelTextColor = "#FFFFFF"
    dr.labelHaloWidth = 1
    dr.labelHaloColor = "#000000"
    dr.labelHaloBlur = 0
}

If applied it might look like this:

Flat labels

By changing the labelType field from the default floating to flat, it becomes possible to align the label with the map instead of the camera.

Flat labels are best shown by disabling the icon, letting the text become centered on the location. Here is an example of a function that changes to type of a label to flat and hides the icon to center the label:

fun setLabelToFlat(dr: MPDisplayRule) {
    dr.isIconVisible = false
    dr.labelType = MPLabelType.FLAT
}

Now the label will be drawn "below" the marker, flat on the ground.

It is possible to change the rotation of the label by modifying the bearing field. This field is measured in degrees where 0° is pointing north and 90° is pointing east. Here is an example where the type is changed to flat and the bearing of the label is changed to a new value:

fun changeLabelBearing(dr: MPDisplayRule, newBearing: Float) {
    dr.labelType = MPLabelType.FLAT
    dr.labelBearing = newBearing
}

If applied with a bearing of 45° it will look like this:

A flat label is styleable, just like a floating label:

fun styleFlatLabel(dr: MPDisplayRule) {
    dr.isIconVisible = false
    dr.labelType = MPLabelType.FLAT
    dr.labelBearing = 45.0f
    dr.labelTextColor = "#FF0000"
    dr.labelTextSize = 100
    dr.labelHaloColor = "#FFFF00"
    dr.labelHaloWidth = 3
}

If applied the labels will look like this:

You now have knowledge of how to style labels and create flat labels when using MapsIndoors on Android, use it wisely.

Graphic Labels

The idea behind Graphic Labels is based on 9-slicing and Mapbox's stretchable images.

By changing the labelType field from the default floating to graphic, the label will be moved to center on the anchor point and it will be adorned with a background, like shown here below:

Parts of a Graphic Label

A graphic label is a combination of multiple values that make it work, namely: a Label, a Background image, a content area, and stretch points in both the vertical (Y) and horizontal (X) directions. Most of these values are kept in a MPLabelGraphic, which is used to ensure that the values are inherited together. This is important because changing just a single one of these values will have major implications on the entire graphic label.

"graphic": {
    "backgroundImage": "https://someurl.com",
    "stretchX": [
        [
            15,
            16
        ]
    ],
    "stretchY": [
        [
            15,
            16
        ]
    ],
    "content": [
        9,
        9,
        17,
        17
    ]
}

Above is an example of the contents of the MPLabelGraphic in JSON format, in this example the size of the image is 32x32px. Notice that the label itself is not present in the data structure, that is because the graphic label itself is invariant to the label, these values will ensure that no matter then length, size or styling of the label text, the graphic label will adapt.

Label

The label is the same as for all the other label types, and all styling still applies. If you skipped the part click here to learn more about label styling.

Background Image

The background image is in essence just an image with specific dimension. It is important that if the background image is changed, it must maintain the same size as the previous image, otherwise you might encounter weird stretching behavior, or in the worst case the graphic will not even show.

Content Area

The content area denotes a rectangle defined as [left, top, right, bottom] where each value is the number of pixels from the images origin.

The content area describes the area within the image where it can place the text from the label.

StretchX/StretchY

The stretch points describe areas that should be repeated to seamlessly stretch the image to contain the text.

A stretch point is defined as a double array [[int]], because it is possible to define multiple stretch points. each area is defined in the inner array, like [[15,16]]. In that stretch point we have defined that the Graphic Label can duplicate, or stretch, the pixels from 15 to 16 in order to contain the label text.

it is possible to set multiple stretch point in the same direction, take this example: [[15,16],[31,32]], in this example we have some element between pixel 16 and 31 that we do not want to stretch, therefore we have placed the stretch points on both sides of the element.

It is not possible to set the stretch point to be placed on the same pixel, eg. [[15,15]] will not work.

If you want to see an example of how a graphic label could be defined, see this section.

Showing Graphic Labels

To start showing Graphic Labels you simply need to update the labelType on the Display Rule to MPLabelType.GRAPHIC

fun setLabelToGraphic(dr: MPDisplayRule) {
    dr.labelType = MPLabelType.GRAPHIC
}

Inserting Custom Graphics

It is very easy to insert your own Graphic Label, you will simply have to create a new MPLabelGraphic and override the Display Rule with it.

fun setNewGraphicLabel(dr: MPDisplayRule, graphic: MPLabelGraphic) {
    dr.labelStyleGraphic = graphic
}

Creating the MPLabelGraphic on the other hand is a bit more involved, follow the example below to get a better idea of how to set it up.

Example

In this example we will create a simple graphic label with rounded corners, and one that is similar, but also has a feature in the middle that we have to work around. We will make the graphic in 200x200px as this makes it a bit easier to see how the graphic will look when stretched. In essence we only need the graphic to encompass the un-stretchable features + 2 pixels per stretch point.

Above we have the example, the corners have a radius of 16 pixels. Now we have to define the stretchable areas, which should range from the end of the first corner to the start of the next corner. We also want to define a content area, here we want 6 pixels of padding from the black border.

Above the StretchX/Y has been illustrated, with the Content area in red, the StretchX in blue and StretchY in green. Notice how the stretchable areas are already repeating a lot, in theory this image could be reduced to 32x32 pixels!

Lets define the graphic label in numbers:

val image: String = "https://www.website.com/graphic.png" // not a real link
val stretchX: Array<IntArray> = arrayOf(intArrayOf(15, 184)) // use all the flat pixels
val stretchY: Array<IntArray> = arrayOf(intArrayOf(15, 184))
val content: IntArray = intArrayOf(10, 10, 189, 189) // the border is 4px wide + 6px padding

val graphic: MPLabelGraphic = MPLabelGraphic(
    backgroundImage = image,
    stretchX = stretchX,
    stretchY = stretchY,
    content = content
)

This example is similar to the first, but has a star on top of the box, and as we do not want to stretch the star, so we will have to be more creative with our stretchable areas.

We can color in the stretchable areas and the content area:

This example can be described numerically like this:

val image: String = "https://www.website.com/graphic_with_star.png" // not a real link
val stretchX: Array<IntArray> = arrayOf(intArrayOf(15, 79), intArrayOf(120, 184))
val stretchY: Array<IntArray> = arrayOf(intArrayOf(55, 184))
val content: IntArray = intArrayOf(10, 50, 189, 189)

val graphic: MPLabelGraphic = MPLabelGraphic(
    backgroundImage = image,
    stretchX = stretchX,
    stretchY = stretchY,
    content = content
)

And this is how it will look when place on the map:

Now you know how to enable Graphic Labels, and how to define your own.

Last updated