Skip to content

Instantly share code, notes, and snippets.

@johnnewman
Last active November 21, 2022 15:15
Show Gist options
  • Save johnnewman/42b9c747d798a397231e9e36823cf7e6 to your computer and use it in GitHub Desktop.
Save johnnewman/42b9c747d798a397231e9e36823cf7e6 to your computer and use it in GitHub Desktop.
A controller that programmatically selects an annotation every 2 seconds
//
// ViewController.swift
//
// Created by John Newman on 11/18/22.
//
import UIKit
import MapboxMaps
class ViewController: UIViewController {
var mapView: MapView!
// Draws all annotations.
var annotationManager: PointAnnotationManager!
// Draws only the selected annotation.
var selectionManager: PointAnnotationManager!
lazy var redIcon: UIImage = {
icon(with: UIColor(red: 1, green: 0, blue: 0, alpha: 1))
}()
lazy var blueIcon: UIImage = {
icon(with: UIColor(red: 0, green: 0, blue: 1, alpha: 1))
}()
func icon(with color: UIColor) -> UIImage {
UIGraphicsImageRenderer(size: .init(width: 20, height: 20)).image(actions: { context in
color.setFill()
context.fill(.init(origin: .zero, size: .init(width: 25, height: 25)))
})
}
override func viewDidLoad() {
super.viewDidLoad()
let resourceOptions = ResourceOptions(
accessToken: "KEY HERE"
)
let mapInitOptions = MapInitOptions(resourceOptions: resourceOptions, cameraOptions: .init(zoom: 9.8))
mapView = MapView(frame: view.bounds, mapInitOptions: mapInitOptions)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
mapView.mapboxMap.onNext(event: .mapLoaded) { [weak self] _ in
guard let self = self else { return }
self.annotationManager = self.mapView.annotations.makePointAnnotationManager()
self.annotationManager.iconAllowOverlap = true
self.annotationManager.iconIgnorePlacement = false
self.annotationManager.textAllowOverlap = false
self.annotationManager.textIgnorePlacement = false
self.annotationManager.textOptional = true
self.annotationManager.symbolZOrder = .viewportY
self.annotationManager.annotations = Array(0...100).map { self.annotation(for: $0)}
// In this app, we draw the selected PointAnnotation in its own style layer.
self.selectionManager = self.mapView.annotations.makePointAnnotationManager()
self.selectionManager.iconAllowOverlap = true
self.selectionManager.iconIgnorePlacement = true
self.selectionManager.textIgnorePlacement = false
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: self.randomlySelectAnnotation)
}
}
func annotation(for index: Int, selected: Bool = false, coordinate: CLLocationCoordinate2D? = nil) -> PointAnnotation {
var annotation = PointAnnotation(
id: "\(index)",
coordinate: coordinate ?? CLLocationCoordinate2D(
latitude: self.mapView.cameraState.center.latitude + Double(arc4random_uniform(1000)) / 10000.0 * (arc4random() % 2 == 0 ? 1 : -1),
longitude: self.mapView.cameraState.center.latitude + Double(arc4random_uniform(1000)) / 10000.0 * (arc4random() % 2 == 0 ? 1 : -1)
)
)
let image = index % 2 == 0 ? redIcon : blueIcon
var imageName = index % 2 == 0 ? "red_icon" : "blue_icon"
annotation.iconSize = selected ? 1 : 0.77
annotation.image = .init(image: image, name: imageName)
annotation.iconAnchor = .center
annotation.textAnchor = .left
annotation.textColor = .init(selected ? .orange : .black)
annotation.textField = "Annotation \(index)"
annotation.userInfo = ["number": index]
annotation.textHaloColor = .init(UIColor.white)
annotation.textHaloWidth = 1
annotation.textJustify = .left
annotation.textOffset = [1, 0]
annotation.textSize = 10
return annotation
}
func randomlySelectAnnotation() {
let options = RenderedQueryOptions(layerIds: [annotationManager.layerId], filter: nil)
mapView.mapboxMap.queryRenderedFeatures(with: mapView.bounds, options: options) { result in
if case let .success(queriedFeatures) = result,
let id = queriedFeatures.randomElement()?.feature.identifier?.rawValue as? String,
let annotation = self.annotationManager.annotations.first(where: { $0.id == id }),
case let .point(point) = annotation.geometry {
self.selectionManager.annotations = [
self.annotation(
for: annotation.userInfo!["number"] as! Int,
selected: true,
coordinate: point.coordinates // Selected pin draws at same spot
)]
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: self.randomlySelectAnnotation)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment