I have a point dataset that is intended only as labels. Each label has a pre-calculated minZoom attribute to one decimal place, e.g. 6.1. While there are labels that share the same value, they vary considerably. I've figured out how to programmatically add a single label. It's workable, I suppose, to add a layer for each label. But performance may suffer. Is there a way, either via Mapbox Studio or programmatically (for the iOS SDK) to set the camera stops individually for each label but keep them within a single layer?
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle)
{
// Try adding point with label
let coordinates: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 49, longitude: -114)
let testPt = MGLPointFeature()
testPt.coordinate = coordinates
testPt.title = "Testing label"
testPt.attributes = ["title": testPt.title as Any]
let src = MGLShapeSource(identifier: "testPtID", features: [testPt], options: nil)
mapView.style?.addSource(src)
let symbols = MGLSymbolStyleLayer(identifier: "testPtSym", source: src)
let color = UIColor(red: 0.08, green: 0.75, blue: 0.96, alpha: 1.0)
symbols.textColor = MGLStyleValue(rawValue: color)
symbols.text = MGLStyleValue(rawValue: "{title}")
symbols.textFontSize = MGLStyleValue(rawValue: 24)
symbols.textOpacity = MGLStyleValue(interpolationMode: .exponential,
cameraStops: [
6: MGLStyleValue(rawValue: 0),
6.1: MGLStyleValue(rawValue: 1)
], options: nil
)
mapView.style?.addLayer(symbols)
}
Best Answer
Mapbox Studio and Mapbox Maps SDK for iOS v4.0 support expressions, which are much more flexible and powerful than style functions. The first step is to convert your existing
textOpacity
style function to an expression. Based on this migration guide, the expression would look like this:(If you want a smooth fade between these zoom levels, you can use the
mgl_interpolate:withCurveType:parameters:stops:
function instead of themgl_step:from:stops:
function.)The snippet above associates each zoom level with an integer literal for convenience, but each zoom level can be associated with a full-blown expression:
Unfortunately, it isn’t possible to vary the stop dictionary’s keys based on each feature’s
minZoom
attribute. But since you know that theminZoom
values only go out to one decimal place, you can programmatically generate all the possible keys, setting each one to an expression that checks whether theminZoom
attribute is greater than that particular zoom level:Depending on the layer’s minimum and maximum zoom levels, this is a lot of stops, so I’m not sure if the performance is any better than what you’re seeing with individual layers for each feature. It probably also depends on how many features your source contains. If it doesn’t contain a lot of features, you could optimize the stop dictionary by only including stops for actual
minZoom
values: