MapBox - detect zoomLevel changes

大憨熊 提交于 2020-02-04 05:32:08

问题


How can I simply detect zoom level changes? Is it possible?

I simply need to hide my annotation views when zoom level is not enough.

regionDidChange:animated: is not intended to use for me. Any other way?

I need to hide my labels here:

and show them here:

This is what I currently do with my labels:

class CardAnnotation: MGLPointAnnotation {

    var card: Card

    init(card: Card) {
        self.card = card
        super.init()

        let coordinates = card.border.map { $0.coordinate }
        let sumLatitudes = coordinates.map { $0.latitude }.reduce(0, +)
        let sumLongitudes = coordinates.map { $0.longitude }.reduce(0, +)
        let averageLatitude = sumLatitudes / Double(coordinates.count)
        let averageLongitude = sumLongitudes / Double(coordinates.count)

        coordinate = CLLocationCoordinate2D(latitude: averageLatitude, longitude: averageLongitude)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
var annotations = [CardAnnotation]()
mapView.addAnnotations(annotations)

回答1:


Of the two main ways to add overlays to an MGLMapView, the runtime styling API is better suited for text labels and also for varying the appearance based on the zoom level. While you’re at it, you might as well create the polygons using the same API too.

Start by creating polygon features for the areas you want shaded in:

var cards: [MGLPolygonFeature] = []
var coordinates: [CLLocationCoordinate2D] = […]
let card = MGLPolygonFeature(coordinates: &coordinates, count: UInt(coordinates.count))
card.attributes = ["address": 123]
// …
cards.append(card)

Within any method that runs after the map finishes loading, such as MGLMapViewDelegate.mapView(_:didFinishLoading:), add a shape source containing these features to the current style:

let cardSource = MGLShapeSource(identifier: "cards", features: cards, options: [:])
mapView.style?.addSource(cardSource)

With the shape source in place, create a style layer that renders the polygon features as mauve fills:

let fillLayer = MGLFillStyleLayer(identifier: "card-fills", source: cardSource)
fillLayer.fillColor = NSExpression(forConstantValue: #colorLiteral(red: 0.9098039216, green: 0.8235294118, blue: 0.9647058824, alpha: 1))
mapView.style?.addLayer(fillLayer)

Then create another style layer that renders labels at each polygon feature’s centroid. (MGLSymbolStyleLayer automatically calculates the centroids, accounting for irregularly shaped polygons.)

// Same source as the fillLayer.
let labelLayer = MGLSymbolStyleLayer(identifier: "card-labels", source: cardSource)
// Each feature’s address is an integer, but text has to be a string.
labelLayer.text = NSExpression(format: "CAST(address, 'NSString')")
// Smoothly interpolate from transparent at z16 to opaque at z17.
labelLayer.textOpacity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
                                      [16: 0, 17: 1])
mapView.style?.addLayer(labelLayer)

As you customize these style layers, pay particular attention to the options on MGLSymbolStyleLayer that control whether nearby symbols are automatically hidden due to collision. You may find that the automatic collision detection makes it unnecessary to specify the textOpacity property.


When you create the source, one of the options you can pass into the MGLShapeSource initializer is MGLShapeSourceOption.clustered. However, in order to use that option, you’d have to create MGLPointFeatures, not MGLPolygonFeatures. Fortunately, MGLPolygonFeature has a coordinate property that lets you find the centroid without manual calculations:

var cardCentroids: [MGLPointFeature] = []
var coordinates: [CLLocationCoordinate2D] = […]
let card = MGLPolygonFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let cardCentroid = MGLPointFeature()
cardCentroid.coordinate = card.coordinate
cardCentroid.attributes = ["address": 123]
cardCentroids.append(cardCentroid)
// …
let cardCentroidSource = MGLShapeSource(identifier: "card-centroids", features: cardCentroids, options: [.clustered: true])
mapView.style?.addSource(cardCentroidSource)

This clustered source can only be used with MGLSymbolStyleLayer or MGLCircleStyleLayer, not MGLFillStyleLayer. This example shows how to work with clustered points in more detail.




回答2:


One option is to add the labels as a MGLSymbolStyleLayer, then determine the textOpacity based on zoom level.

If you are using the current version of the Maps SDK for iOS, you could try something like:

symbols.textOpacity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", [16.9: 0, 17: 1])

The dynamically styled interactive points example shows one approach to this.




回答3:


Is the problem that when you zoom out, your annotations are too close together? If so, it is better to group them together than to hide them entirely. See Decluttering a Map with MapKit Annotation Clustering.



来源:https://stackoverflow.com/questions/50471924/mapbox-detect-zoomlevel-changes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!