mapbox / mapbox-gl-native

Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL
https://mapbox.com/mobile
Other
4.35k stars 1.33k forks source link

Vector Source Feature-attributes as Number being cast to Boolean #16498

Closed nitrag closed 3 years ago

nitrag commented 4 years ago

Platform: iOS Mapbox SDK version: 5.9

Steps to trigger behavior

  1. Upload points to mapbox (vector tile hosting) with attributes such as position (as Integer). ("trail_id": 1029, "position": 1, "mile_marker": 0)
  2. Load Vector Tile Source
  3. Create a text (MGLSymbolStyleLayer) layer that dynamicly styles text for each point.
let vectorSource = MGLVectorTileSource(identifier: "mapbox_hosted_tileset", configurationURL: xxxx)
style.addSource(vectorSource)

let followCircle = MGLCircleStyleLayer(identifier: "follow_waypoints", source: vectorSource)
followCircle.sourceLayerIdentifier = "points"
followCircle.circleColor = NSExpression(forConstantValue: UIColor.init(hexString: "#FF1A00"))
followCircle.circleRadius = NSExpression(forConstantValue: 9)
followCircle.circleRadius = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.5, %@)", [
    4: 0.5,
    8: 2,
    10: 6,
    12: 10
])
followCircle.minimumZoomLevel = 5
followCircle.maximumZoomLevel = 20
style.addLayer(followCircle)

let followCircleText = MGLSymbolStyleLayer(identifier: "follow_waypoints_text", source: vectorSource)
followCircleText.sourceLayerIdentifier = "points"
//Expected, however, BUG:
followCircleText.text = NSExpression(forKeyPath: "position")
//Workaround for the time being
//followCircleText.text = NSExpression(forConditional: NSPredicate(format: "position == true"), trueExpression: NSExpression(forConstantValue: "1"), falseExpression: NSExpression(forKeyPath: "position"))
followCircleText.textFontSize = NSExpression(forConstantValue: 12)
followCircleText.textFontNames = NSExpression(forConstantValue: ["Open Sans Bold"])
followCircleText.textColor = NSExpression(forConstantValue: UIColor.white)
followCircleText.minimumZoomLevel = 5
followCircleText.maximumZoomLevel = 20
style.addLayer(followCircleText)

Expected behavior

Number/Integer attributes, when applied to MGLSymbolStyleLayer.text dynamic-styling are cast to String.

Actual behavior

Attribute position with value 1 becomes true.

image (2)

Other Notes

This issue does occur when using MGLShapeSource.

followCircleText.text = NSExpression(forFunction: "castObject:toType:", arguments: [NSExpression(forKeyPath: "position"), "NSString"]) has no effect

nitrag commented 4 years ago

Thank you @1ec5 for the acknowledgement of the issue and help with the workaround via Slack.

nitrag commented 3 years ago

Confirmed no longer an issue in latest SDK.

nitrag commented 3 years ago

Sorry, Never mind....Android implementation is working:

val followCircle = CircleLayer("follow_waypoints", followDataSource.id).apply {
    withSourceLayer(Constant.Map.TileSets.Waypoints.title)
    withProperties(
        circleColor(Color.parseColor("#FF1A00")),
        circleRadius(
            interpolate(
                exponential(1.5f), zoom(),
                stop(4, 0.5f),
                stop(8, 2f),
                stop(10, 5f),
                stop(12, 7f)
            )
        )
    )
    minZoom = 8f
    maxZoom = 20f
    setFilter(eq(get("trail_id"), 3237))
}
style.addLayer(followCircle)

val followCircleText = SymbolLayer("follow_waypoints_text", followDataSource.id).apply {
    withSourceLayer(Constant.Map.TileSets.Waypoints.title)
    withProperties(
        textColor(Color.parseColor("#FFFFFF")),
        textSize(12f),
        textFont(arrayOf("Open Sans Bold", "Roboto Black")),
        symbolPlacement(Property.SYMBOL_PLACEMENT_POINT),
        textAllowOverlap(true),
        textField(toString(get("position", properties())))
    )
    minZoom = 8f
    maxZoom = 20f
    setFilter(eq(get("trail_id"), 3237))
}
style.addLayer(followCircleText)