-
-
Save incanus/7e19ca99f76c0b3d32ae147872325722 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Overlay { | |
var image: UIImage? | |
var initialMetersPerPoint: Double? | |
var initialScale: Double? | |
var annotation: MGLPointAnnotation? | |
} | |
class ViewController: UIViewController, MGLMapViewDelegate { | |
var map: MGLMapView? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
map?.isPitchEnabled = false | |
map?.delegate = self | |
let image = UIImage(named: "newark.jpg")! | |
let nw = CLLocation(latitude: 40.773941, longitude: -74.22655) | |
let ne = CLLocation(latitude: 40.773941, longitude: -74.12544) | |
let sw = CLLocation(latitude: 40.712216, longitude: -74.22655) | |
let se = CLLocation(latitude: 40.712216, longitude: -74.12544) | |
let topDistance = ne.distance(from: nw) | |
let currentMeters = map?.metersPerPoint(atLatitude: (nw.coordinate.latitude + sw.coordinate.latitude) / 2) | |
let topPoints = topDistance / currentMeters! | |
let initialScale = Double(topPoints) / Double(image.size.width) | |
let annotation = MGLPointAnnotation() | |
annotation.coordinate = CLLocationCoordinate2D(latitude: (nw.coordinate.latitude + sw.coordinate.latitude) / 2, | |
longitude: (ne.coordinate.longitude + nw.coordinate.longitude) / 2) | |
overlay = Overlay() | |
overlay?.image = image | |
overlay?.initialMetersPerPoint = currentMeters | |
overlay?.initialScale = initialScale | |
overlay?.annotation = annotation | |
map?.addAnnotation(annotation) | |
} | |
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? { | |
guard annotation is MGLPointAnnotation else { | |
return nil | |
} | |
let reuseIdentifier = "overlay" | |
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) | |
if annotationView == nil, | |
let overlay = overlay, | |
let image = overlay.image, | |
let initialScale = overlay.initialScale { | |
let imageView = UIImageView(image: image) | |
imageView.frame = CGRect(x: 0, y: 0, width: imageView.bounds.size.width * CGFloat(initialScale), height: imageView.bounds.size.height * CGFloat(initialScale)) | |
annotationView = MGLAnnotationView(reuseIdentifier: reuseIdentifier) | |
annotationView?.addSubview(imageView) | |
imageView.center = annotationView!.center | |
annotationView?.alpha = 0.5 | |
} | |
return annotationView | |
} | |
func mapViewRegionIsChanging(_ mapView: MGLMapView) { | |
if let overlay = overlay, | |
let initialMetersPerPoint = overlay.initialMetersPerPoint, | |
let annotation = overlay.annotation, | |
let annotationView = mapView.view(for: annotation) { | |
let factor = CGFloat(initialMetersPerPoint / mapView.metersPerPoint(atLatitude: annotation.coordinate.latitude)) | |
annotationView.transform = CGAffineTransform(scaleX: factor, y: factor).rotated(by: MGLRadiansFromDegrees(-mapView.direction)) | |
} | |
} | |
} |
Actually this seems not correct way because of map projection. It is hard to recognize if map layer is small but if layer is big enough such as continent level, you will see what I'm saying. To fix this, need to convert point <-> lon/lat instead of using meter. (because metersPerPoints can be different based on lat)
class OverlayAnnotation: MGLPointAnnotation {
let image: UIImage
let nw: CLLocationCoordinate2D
let se: CLLocationCoordinate2D
weak var mapView: MGLMapView?
let initialMetersPerPoints: Double
let initialHorizontalScale: Double
let initialVerticalScale: Double
required init(image: UIImage, nw: CLLocationCoordinate2D, se: CLLocationCoordinate2D, mapView: MGLMapView) {
self.image = image
self.nw = nw
self.se = se
self.mapView = mapView
initialMetersPerPoints = mapView.metersPerPoint(atLatitude: (nw.latitude + se.latitude) / 2) // meters in a point at the specific latitude
let nwpt = mapView.convert(nw, toPointTo: nil)
let sept = mapView.convert(se, toPointTo: nil)
let hpt = abs(sept.x - nwpt.x)
let vpt = abs(nwpt.y - sept.y)
initialHorizontalScale = Double(hpt / image.size.width)
initialVerticalScale = Double(vpt / image.size.height)
super.init()
self.coordinate = mapView.convert(CGPoint(x: (nwpt.x + sept.x) / 2, y: (nwpt.y + sept.y) / 2), toCoordinateFrom: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class OverlayAnnotationView: MGLAnnotationView {
let imageView = UIImageView()
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
if let annotation = annotation as? OverlayAnnotation {
let annotationView: OverlayAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "overlay") as? OverlayAnnotationView ?? OverlayAnnotationView(reuseIdentifier: "overlay")
annotationView.annotation = annotation
annotationView.imageView.image = annotation.image
annotationView.imageView.frame = CGRect(x: 0,
y: 0,
width: annotation.image.size.width * CGFloat(annotation.initialHorizontalScale),
height: annotation.image.size.height * CGFloat(annotation.initialVerticalScale))
annotationView.addSubview(annotationView.imageView)
annotationView.imageView.center = CGPoint(x: annotationView.center.x, y: annotationView.center.y)
annotationView.alpha = 0.9
return annotationView
}
}
return nil
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is a workaround for mapbox/mapbox-gl-native#1350 in the style of Google's web library
GroundOverlay
.