diff options
Diffstat (limited to 'iosApp/iosApp/Map/BaseMapView.swift')
-rw-r--r-- | iosApp/iosApp/Map/BaseMapView.swift | 182 |
1 files changed, 172 insertions, 10 deletions
diff --git a/iosApp/iosApp/Map/BaseMapView.swift b/iosApp/iosApp/Map/BaseMapView.swift index b247c30..322ae45 100644 --- a/iosApp/iosApp/Map/BaseMapView.swift +++ b/iosApp/iosApp/Map/BaseMapView.swift @@ -21,14 +21,16 @@ import WhirlyGlobeMaplyComponent import shared struct BaseMapView: UIViewControllerRepresentable { - typealias UIViewControllerType = MaplyViewController + typealias UIViewControllerType = OurMaplyViewController @Binding var mapLayer: MapLayer + @Binding var markers: [Marker] + var markerCallback: ((Int32?) -> Void)? var link: BaseMapLink class Coordinator: NSObject, MaplyViewControllerDelegate { var parent: BaseMapView - var uiViewController: MaplyViewController? + var uiViewController: OurMaplyViewController? var loader: MaplyQuadImageLoader? = nil // Source: https://stackoverflow.com/questions/65923718 @@ -48,8 +50,24 @@ struct BaseMapView: UIViewControllerRepresentable { self.parent = uiViewController } - func maplyViewController(_ viewC: MaplyViewController, didClick annotation: MaplyAnnotation) { - print("Clicked map! :D") + func maplyViewController(_ viewC: MaplyViewController, + didTapAt coord: MaplyCoordinate) { + if let callback = parent.markerCallback { + callback(nil) + } + } + + func maplyViewController(_ viewC: MaplyViewController, + didSelect selectedObj: NSObject, + atLoc coord: MaplyCoordinate, + onScreen screenPt: CGPoint) { + if let marker = selectedObj as? MaplyScreenMarker { + if let id = marker.userObject as? Int32 { + if let callback = parent.markerCallback { + callback(id) + } + } + } } } @@ -57,8 +75,8 @@ struct BaseMapView: UIViewControllerRepresentable { Coordinator(self) } - func makeUIViewController(context: Context) -> MaplyViewController { - let mapViewController = MaplyViewController(mapType: .typeFlat) + func makeUIViewController(context: Context) -> OurMaplyViewController { + let mapViewController = OurMaplyViewController(mapType: .typeFlat) mapViewController.delegate = context.coordinator let tileInfo = Utils.tileInfoFrom(layer: mapLayer) @@ -87,7 +105,7 @@ struct BaseMapView: UIViewControllerRepresentable { return mapViewController } - func updateUIViewController(_ uiViewController: MaplyViewController, context: Context) { + func updateUIViewController(_ uiViewController: OurMaplyViewController, context: Context) { context.coordinator.uiViewController = uiViewController context.coordinator.link = link @@ -95,6 +113,10 @@ struct BaseMapView: UIViewControllerRepresentable { context.coordinator.loader?.changeTileInfo(Utils.tileInfoFrom(layer: mapLayer)) uiViewController.setZoomLimits(minZoom: mapLayer.minZoom, maxZoom: mapLayer.maxZoom) + + // MARK: - Set markers + uiViewController.display(markers: markers, + isReport: false) } static func dismantleUIViewController(_ uiViewController: MaplyViewController, coordinator: Coordinator) { @@ -103,12 +125,15 @@ struct BaseMapView: UIViewControllerRepresentable { } } -extension MaplyViewController { +class OurMaplyViewController: MaplyViewController { enum Action { case zoomIn case zoomOut } + private var objects = [MaplyComponentObject]() + private var geofenceObjects = [MaplyComponentObject]() + func action(_ action: Action) { DispatchQueue.main.async { switch action { @@ -120,7 +145,9 @@ extension MaplyViewController { } } - func focusOn(point: MaplyCoordinate, height: Float = 0.0000264, animated: Bool = true) { + func focusOn(point: MaplyCoordinate, + height: Float = 0.0000264, + animated: Bool = true) { let z = max(height, getMinZoom()) if animated { animate(toPosition: point, height: z, time: 0.2) @@ -141,6 +168,136 @@ extension MaplyViewController { focusOn(point: pos, height: height(forMapScale: zoom)) } + func clear(geofences: Bool = false) { + if geofences { + remove(geofenceObjects) + geofenceObjects.removeAll() + } else { + remove(objects) + objects.removeAll() + } + } + + func display(markers: [Marker], + isReport: Bool, + center: Bool = false) { + clear() + + let points = markers.map { marker in + MaplyCoordinateMakeWithDegrees(Float(marker.longitude), + Float(marker.latitude)) + } + + let fontSize = 11.0 + let colorReport = Color.green + let colorLabel = Color.secondary + let colorLabelOutline = Color.systemBackground + + let vectorDesc: [AnyHashable : Any] = [ + kMaplyColor: colorReport, + kMaplyVecWidth: 20.0 + ] + + let labelDesc: [AnyHashable : Any] = [ + kMaplyFont: UIFont.boldSystemFont(ofSize: fontSize), + kMaplyTextColor: colorLabel, + kMaplyTextOutlineColor: colorLabelOutline, + kMaplyTextOutlineSize: 3.0 + ] + + /* MARK: - Draw markers for positions */ + let screenMarkers = markers.enumerated().map { (i, marker) -> MaplyScreenMarker in + let screenMarker = MaplyScreenMarker() + screenMarker.layoutImportance = .greatestFiniteMagnitude + screenMarker.loc = MaplyCoordinateMakeWithDegrees(Float(marker.longitude), + Float(marker.latitude)) + var type: Marker.Type_ = .default_ + if isReport { + // For reports, position, start and end icons must be different + switch i { + case markers.startIndex: type = .reportStart + case markers.endIndex: type = .reportEnd + default: type = .reportPosition + } + } else { + type = marker.type + } + screenMarker.image = getIcon(markerType: type) + + var size = 50.0 + if isReport { + // For reports, position, start and end sizes must be different + switch i { + case markers.startIndex: size = 50.0 + case markers.endIndex: size = 50.0 + default: size = 25.0 + } + } + screenMarker.size = CGSize(width: size, height: size) + screenMarker.userObject = marker.id + screenMarker.selectable = true + + return screenMarker + } + + if let objs = addScreenMarkers(screenMarkers, desc: nil, mode: .any) { + objects.append(objs) + } + + /* MARK: - Add labels for markers */ + if !isReport && !markers.isEmpty { + let screenLabels = markers.map { marker -> MaplyScreenLabel in + let label = MaplyScreenLabel() + label.layoutImportance = .greatestFiniteMagnitude + var text = marker.name + if marker.name.count >= 20 { + let end = marker.name.index(marker.name.startIndex, offsetBy: 20) + text = String(marker.name[..<end]) + } + label.text = text + label.loc = MaplyCoordinateMakeWithDegrees(Float(marker.longitude), + Float(marker.latitude)) + label.offset = CGPoint(x: 0.0, y: 25.0) + + return label + } + + if let objs = addScreenLabels(screenLabels, desc: labelDesc) { + objects.append(objs) + } + } + + /* MARK: - Draw polyline for report */ + if isReport && !markers.isEmpty { + let geoJSON: [AnyHashable : Any] = [ + "type": "FeatureCollection", + "features": [ + [ + "type": "LineString", + "coordinates": points.map({ point in + [point.x, point.y] + }) + ] + ] + ] + if let vector = MaplyVectorObject(fromGeoJSONDictionary: geoJSON) { + if let objs = addVectors([vector], desc: vectorDesc, mode: .any) { + objects.append(objs) + } + } + } + + /* MARK: - Center map to bounds */ + if center && !markers.isEmpty { + let box = MaplyBoundingBoxExpandByFraction( + MaplyBoundingBoxFromCoordinates(points, UInt32(points.count)), 0.1) + let center = MaplyCoordinate(x: (box.ur.x + box.ll.x) / 2, + y: (box.ur.y + box.ll.y) / 2) + let zoom = max(findHeight(toViewBounds: box, pos: center), getMinZoom()) + setPosition(center, height: zoom) + } + } + func setZoomLimits(minZoom: Int32, maxZoom: Int32) { setZoomLimitsMin( height(forMapScale: Float(truncating: @@ -152,11 +309,16 @@ extension MaplyViewController { ?? MapCalculus.companion.zoomLevelToScale(zoom: 1)! ))) } + + private func getIcon(markerType: Marker.Type_) -> UIImage { + return UIImage(named: MarkerTransformations + .markerTypeToImageName(markerType: markerType))! + } } // Source: https://stackoverflow.com/questions/65923718 class BaseMapLink: ObservableObject { - @Published var action: MaplyViewController.Action? + @Published var action: OurMaplyViewController.Action? func zoomIn() { action = .zoomIn |