mapboxmapbox-iosmapbox-expressions

Conditional color expression for Mapbox v10 iOS SDK


With the Mapbox v10 SDK reaching the release candidate stage, I've started updating an existing iOS app that was built on the previous release of the Mapbox iOS SDK (v6.3). The app shows circular markers on the map to represent the location of some GeoJSON features. An example feature looks like this:

{
  "properties" : {
    "type" : "TRUCK",
    "needsHelp" : false,
  },
  "id" : 12345,
  "type" : "Feature",
  "geometry" : {
    "type" : "Point",
    "coordinates" : [
      -122.28992161530911,
      47.46347019873241
    ]
  }
}

I'm using runtime styling with this CircleLayer and the .circleColor property of this layer is being set to an expression which should work as follows:

if (feature.properties.needsHelp == true) {
   // the circle color should be red
} else {
   // the circle color is determined by the value of the features "type" property
}

In the previous version of the Mapbox iOS SDK, expressions were implemented using NSExpression, of course, and I used a combination of the ternary operator and the MGL_Match operator to achieve this behavior. With the new v10 iOS SDK, expressions now have their own DSL and I understand that you can also define them inline using raw JSON to be more consistent with Mapbox GL JS. Unfortunately, I find myself struggling to wrap my head around the correct way to implement this expression logic using the new SDK.

At the moment, I have the expression defined like this:

let colorExpression = Exp(.match) {
    Exp(.get) { "type" }
    "TRUCK"
    UIColor.systemBlue
    "SHIP"
    UIColor.systemOrange
    "AIRCRAFT"
    UIColor.systemGreen
    UIColor.systemGray // default color if some other "type" value
}

circleLayer.circleColor = .expression(colorExpression)

This provides the "else" logic described above but I'm still missing the "if" logic to first check the ".needsHelp" feature property to see if it's true and then return UIColor.red.

I've been looking through the Mapbox Style Specification document and it looks like the 'case' operator could be used to provide if/else functionality. One of the Mapbox v10 SDK examples here shows how to use the .switchCase operator in an expression but it's not entirely clear to me how the "else" logic that I have defined above would fit into that example usage of the .switchCase operator. Can anyone offer some insight into that? Thanks very much.


Solution

  • After more trial and error, I think I've found a way to solve my problem. There may be other (better?) ways to implement the same logic but the expression below seems to be working properly for me:

    let colorExpression = Exp(.switchCase) {
        Exp(.eq) {
            Exp(.get) { "needsHelp" }
            true
        }
        UIColor.systemRed
        Exp(.match) {
            Exp(.get) { "type" }
            "TRUCK"
            UIColor.systemBlue
            "SHIP"
            UIColor.systemOrange
            "AIRCRAFT"
            UIColor.systemGreen
            UIColor.systemGray
        }
    }