aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--iosApp/iosApp/Map/BaseMapView.swift182
-rw-r--r--iosApp/iosApp/Map/MapView.swift4
-rw-r--r--iosApp/iosApp/Map/MapWrapperView.swift7
-rw-r--r--iosApp/iosApp/Units/UnitsViewModel.swift21
4 files changed, 201 insertions, 13 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
diff --git a/iosApp/iosApp/Map/MapView.swift b/iosApp/iosApp/Map/MapView.swift
index c5bbc8a..a34bf63 100644
--- a/iosApp/iosApp/Map/MapView.swift
+++ b/iosApp/iosApp/Map/MapView.swift
@@ -22,6 +22,8 @@ struct MapView: View {
@StateObject var unitsViewModel: UnitsViewModel
var body: some View {
- MapWrapperView(layer: $unitsViewModel.mapLayerType)
+ MapWrapperView(layer: $unitsViewModel.mapLayerType,
+ markers: $unitsViewModel.markers,
+ markerCallback: unitsViewModel.selectUnitWith)
}
}
diff --git a/iosApp/iosApp/Map/MapWrapperView.swift b/iosApp/iosApp/Map/MapWrapperView.swift
index 0e9eaf8..cc56937 100644
--- a/iosApp/iosApp/Map/MapWrapperView.swift
+++ b/iosApp/iosApp/Map/MapWrapperView.swift
@@ -22,12 +22,17 @@ import shared
struct MapWrapperView: View {
@Binding var layer: MapLayer
+ @Binding var markers: [Marker]
+ var markerCallback: ((Int32?) -> Void)?
@ObservedObject var link: BaseMapLink = BaseMapLink()
var body: some View {
ZStack {
// MARK: - Map
- BaseMapView(mapLayer: $layer, link: link)
+ BaseMapView(mapLayer: $layer,
+ markers: $markers,
+ markerCallback: markerCallback,
+ link: link)
// MARK: - Attribution
VStack {
diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift
index 04c0436..dc6236f 100644
--- a/iosApp/iosApp/Units/UnitsViewModel.swift
+++ b/iosApp/iosApp/Units/UnitsViewModel.swift
@@ -49,7 +49,12 @@ class UnitsViewModel: ObservableObject {
}
@Published var isEditing = false
@Published var unitsDisplayMode: UnitsDisplayMode = .list
- @Published var units: [UnitInformation] = []
+ @Published var units: [UnitInformation] = [] {
+ didSet {
+ markers = units.compactMap(Marker.companion.fromUnit)
+ }
+ }
+ @Published var markers: [Marker] = []
@Published var selectedUnit: UnitInformation? = nil
@Published var mapLayerType: MapLayer = .companion.defaultLayer
@Published var geofences: [Int: Geofence] = [:]
@@ -81,6 +86,20 @@ class UnitsViewModel: ObservableObject {
self.geofences = geofences
}
+ func selectUnitWith(position id: Int32?) {
+ if id == nil {
+ print("Deselecting unit")
+ selectedUnit = nil
+ return
+ }
+ print("Selecting unit with position id: \(id ?? 0)")
+ if let unit = units.first(where: {
+ Int32(truncating: $0.position?.id ?? 0) == id
+ }) {
+ selectedUnit = unit
+ }
+ }
+
func toggleDisplayMode() {
switch unitsDisplayMode {
case .map: