/** * TrackerMap * Copyright (C) 2021-2022 Iván Ávalos , Henoch Ojeda * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import SwiftUI import Combine import WhirlyGlobeMaplyComponent import shared struct BaseMapView: UIViewControllerRepresentable { typealias UIViewControllerType = MaplyViewController @Binding var mapLayer: MapLayer var link: BaseMapLink class Coordinator: NSObject, MaplyViewControllerDelegate { var parent: BaseMapView var uiViewController: MaplyViewController? 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: BaseMapView) { self.parent = uiViewController } func maplyViewController(_ viewC: MaplyViewController, didClick annotation: MaplyAnnotation) { print("Clicked map! :D") } } func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> MaplyViewController { let mapViewController = MaplyViewController(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) } return mapViewController } func updateUIViewController(_ uiViewController: MaplyViewController, context: Context) { context.coordinator.uiViewController = uiViewController context.coordinator.link = link // MARK: - Set map layer context.coordinator.loader?.changeTileInfo(Utils.tileInfoFrom(layer: mapLayer)) uiViewController.setZoomLimits(minZoom: mapLayer.minZoom, maxZoom: mapLayer.maxZoom) } static func dismantleUIViewController(_ uiViewController: MaplyViewController, coordinator: Coordinator) { coordinator.loader?.shutdown() uiViewController.teardown() } } extension MaplyViewController { enum Action { case zoomIn case zoomOut } 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 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)! ))) } } // Source: https://stackoverflow.com/questions/65923718 class BaseMapLink: ObservableObject { @Published var action: MaplyViewController.Action? func zoomIn() { action = .zoomIn } func zoomOut() { action = .zoomOut } }