Home > Software design >  How show map annotations when map span will be 0.1?
How show map annotations when map span will be 0.1?

Time:02-02

How show map annotations when map span will be 0.1? I want map pins to not show until map span is <= 0.1

struct City: Identifiable {
    let id = UUID()
    let name: String
    let coordinate: CLLocationCoordinate2D
}

struct ContentView: View {
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))

    let annotations = [
        City(name: "London", coordinate: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275)),
        City(name: "Paris", coordinate: CLLocationCoordinate2D(latitude: 48.8567, longitude: 2.3508)),
        City(name: "Rome", coordinate: CLLocationCoordinate2D(latitude: 41.9, longitude: 12.5)),
        City(name: "Washington DC", coordinate: CLLocationCoordinate2D(latitude: 38.895111, longitude: -77.036667))
    ]

    var body: some View {
        Map(coordinateRegion: $region, annotationItems: annotations) {
            MapPin(coordinate: $0.coordinate)
        }
        .frame(width: 400, height: 300)
    }
}

How can this be done?

CodePudding user response:

You can't with MapPin because it's a type of protocol not View. Instead of it you can use MapAnnotation. Since your region parameter is binding the view, you can check map span and show/hide your annotation like this;

Map(coordinateRegion: $region, annotationItems: annotations) {
    MapAnnotation(coordinate: $0.coordinate) {
        // Use whatever value instead of 2.5
        if region.span.latitudeDelta < 2.5 {
            Image(systemName: "mappin")
                .resizable()
                .frame(width: 18, height: 36)
                .foregroundColor(Color.red)
        } else {
            EmptyView()
        }
    }
}
.frame(width: 400, height: 300)

CodePudding user response:

You can use a computed variable that returns true when the span is correct and then conditionally have the Map use the annotations.

struct SuperZoomMap: View {
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))

    let annotations = [
        City(name: "London", coordinate: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275)),
        City(name: "Paris", coordinate: CLLocationCoordinate2D(latitude: 48.8567, longitude: 2.3508)),
        City(name: "Rome", coordinate: CLLocationCoordinate2D(latitude: 41.9, longitude: 12.5)),
        City(name: "Washington DC", coordinate: CLLocationCoordinate2D(latitude: 38.895111, longitude: -77.036667))
    ]
    ///Returns true when the
    ///region.span.latitudeDelta <= 0.1 || region.span.longitudeDelta <= 0.1
    var show: Bool{
        if region.span.latitudeDelta <= 0.1 || region.span.longitudeDelta <= 0.1{
            return true
        }else{
            return false
        }
    }

    var body: some View {
        VStack{
            Text(region.span.latitudeDelta, format: .number)
            Text(region.span.longitudeDelta, format: .number)
            Map(coordinateRegion: $region, annotationItems: show ? annotations : []) {
                MapPin(coordinate: $0.coordinate)
            }
            .frame(width: 400, height: 300)
        }
    }
}

You can also filter the pins using CLLocations distance so you only plot pins within a certain distance of the center/ visible pins.

For example if you are zoomed into London exclude Paris, Rome and Washington DC.

struct SuperZoomMap: View {
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))

    let annotations = [
        City(name: "London", coordinate: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275)),
        City(name: "Paris", coordinate: CLLocationCoordinate2D(latitude: 48.8567, longitude: 2.3508)),
        City(name: "Rome", coordinate: CLLocationCoordinate2D(latitude: 41.9, longitude: 12.5)),
        City(name: "Washington DC", coordinate: CLLocationCoordinate2D(latitude: 38.895111, longitude: -77.036667))
    ]
    ///Returns true when the
    ///region.span.latitudeDelta <= 0.1 || region.span.longitudeDelta <= 0.1
    var show: Bool{
        if region.span.latitudeDelta <= 0.1 || region.span.longitudeDelta <= 0.1{
            return true
        }else{
            return false
        }
    }
    //Only show the pins within 10000 meters from the center 
    var filtered: [City]{
        guard show else {
            return []
        }
        return annotations.filter { city in
            let c = CLLocation(latitude: city.coordinate.latitude, longitude: city.coordinate.longitude)
            let current = CLLocation(latitude: region.center.latitude, longitude: region.center.longitude)
            
            return c.distance(from: current) <= 10000
        }
    }
    var body: some View {
        VStack{
            Text(filtered.count, format: .number)
            Text(region.span.latitudeDelta, format: .number)
            Text(region.span.longitudeDelta, format: .number)
            Map(coordinateRegion: $region, annotationItems: filtered) {
                MapPin(coordinate: $0.coordinate)
            }
            .frame(width: 400, height: 300)
        }
    }
}
  • Related