aboutsummaryrefslogtreecommitdiff
path: root/iosApp/iosApp/Map/MapView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'iosApp/iosApp/Map/MapView.swift')
-rw-r--r--iosApp/iosApp/Map/MapView.swift307
1 files changed, 16 insertions, 291 deletions
diff --git a/iosApp/iosApp/Map/MapView.swift b/iosApp/iosApp/Map/MapView.swift
index 572db64..6b0fa20 100644
--- a/iosApp/iosApp/Map/MapView.swift
+++ b/iosApp/iosApp/Map/MapView.swift
@@ -21,310 +21,35 @@ import WhirlyGlobeMaplyComponent
import shared
struct MapView: UIViewControllerRepresentable {
- typealias UIViewControllerType = OurMaplyViewController
+ typealias UIViewControllerType = MapViewController
- @Binding var mapLayer: MapLayer
+ @Binding var layer: MapLayer
@Binding var markers: [Marker]
- var markerCallback: ((Int32?) -> Void)?
- var link: BaseMapLink
+ var markerCallback: MarkerCallback?
- class Coordinator: NSObject, MaplyViewControllerDelegate {
- var parent: MapView
- var uiViewController: OurMaplyViewController?
- var loader: MaplyQuadImageLoader? = nil
-
- // Source: https://stackoverflow.com/questions/65923718
- var cancellable: AnyCancellable?
- var link: BaseMapLink? {
- didSet {
- cancellable = link?.$action.sink(receiveValue: { action in
- guard let action = action else {
- return
- }
- self.uiViewController?.action(action)
- })
- }
- }
-
- init(_ uiViewController: MapView) {
- self.parent = uiViewController
- }
-
- 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)
- }
- }
- }
- }
+ class Coordinator {
+ var shouldCenter: Bool = true
}
func makeCoordinator() -> Coordinator {
- Coordinator(self)
+ return Coordinator()
}
- func makeUIViewController(context: Context) -> OurMaplyViewController {
- let mapViewController = OurMaplyViewController(mapType: .typeFlat)
- mapViewController.delegate = context.coordinator
-
- let tileInfo = Utils.tileInfoFrom(layer: mapLayer)
- mapViewController.setZoomLimits(minZoom: mapLayer.minZoom,
- maxZoom: mapLayer.maxZoom)
-
- let sampleParams = MaplySamplingParams()
- sampleParams.coordSys = MaplySphericalMercator(webStandard: ())
- sampleParams.coverPoles = true
- sampleParams.edgeMatching = true
- sampleParams.minZoom = tileInfo.minZoom
- sampleParams.maxZoom = tileInfo.maxZoom
- sampleParams.singleLevel = true
- sampleParams.maxTiles = 25
-
- let loader = MaplyQuadImageLoader(params: sampleParams, tileInfo: tileInfo, viewC: mapViewController)
- loader?.baseDrawPriority = kMaplyImageLayerDrawPriorityDefault
- loader?.imageFormat = .imageUShort565
- context.coordinator.loader = loader
-
- DispatchQueue.main.async {
- let point = MaplyCoordinateMakeWithDegrees(-100.36, 23.191)
- mapViewController.focusOn(point: point, height: 0.4, animated: false)
- }
-
- return mapViewController
+ func makeUIViewController(context: Context) -> MapViewController {
+ let mapVC = MapViewController()
+ mapVC.markerCallback = markerCallback
+ mapVC.mapLayer = layer
+ return mapVC
}
- func updateUIViewController(_ uiViewController: OurMaplyViewController, context: Context) {
- context.coordinator.uiViewController = uiViewController
- context.coordinator.link = link
-
+ func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
// MARK: - Set map layer
- context.coordinator.loader?.changeTileInfo(Utils.tileInfoFrom(layer: mapLayer))
- uiViewController.setZoomLimits(minZoom: mapLayer.minZoom,
- maxZoom: mapLayer.maxZoom)
+ uiViewController.setMapLayer(layer)
// MARK: - Set markers
uiViewController.display(markers: markers,
- isReport: false)
- }
-
- static func dismantleUIViewController(_ uiViewController: MaplyViewController, coordinator: Coordinator) {
- coordinator.loader?.shutdown()
- uiViewController.teardown()
- }
-}
-
-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 {
- case .zoomIn:
- self.zoomIn()
- case .zoomOut:
- self.zoomOut()
- }
- }
- }
-
- 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)
- } else {
- setPosition(point, height: z)
- }
- }
-
- func zoomIn() {
- let pos = getPosition()
- let zoom = currentMapScale() / 2
- focusOn(point: pos, height: height(forMapScale: zoom))
- }
-
- func zoomOut() {
- let pos = getPosition()
- let zoom = currentMapScale() * 2
- 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:
- MapCalculus.companion.zoomLevelToScale(zoom: maxZoom)
- ?? MapCalculus.companion.zoomLevelToScale(zoom: 21)!
- )),
- max: height(forMapScale: Float(truncating:
- MapCalculus.companion.zoomLevelToScale(zoom: minZoom)
- ?? 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: OurMaplyViewController.Action?
-
- func zoomIn() {
- action = .zoomIn
- }
-
- func zoomOut() {
- action = .zoomOut
+ isReport: false,
+ center: context.coordinator.shouldCenter)
+ context.coordinator.shouldCenter = false
}
}