The code below is to take a specific number of references from a database, make circle overlays from some coordinates given from some DBSCAN function, and plot the circle overlays on the map. Every 10 seconds the circles are removed from the map and updated with the same ones from the database. The problem is that the circles aren't being shown. I have tried debugging this to no avail. Any advice/help is appreciated.
import MapKit
import SwiftUI
import Firebase
import FirebaseAnalytics
import FirebaseAnalyticsSwift
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
/* Variable region accounts for showing specific coordinate region within span, showcasing input coordinates */
@State var annotationItems: [User] = []
@State var locations: [CLLocation] = []
@State var circleOverlays: [MKCircle] = []
func plotUsers() {
for i in 0...20
{
var latData = 0.0
var longData = 0.0
var userName = ""
var userAge = 0
var ref: DatabaseReference!
ref = Database.database().reference().child("users").child(String(i))
ref.getData(completion: { error, snapshot in
guard error == nil else {
print("issue")
return;
}
var a: [String: Any] = [:]
//turning datasnapshot returned from database into a dictionary
a = snapshot?.value as! Dictionary<String, Any>
//assigning values from the dictionary to variables so we don't have to type all the necessary error stuff every time
latData = (a["locData"] as? [String:Any])?["lat"] as? Double ?? -1
longData = (a["locData"] as? [String:Any])?["long"] as? Double ?? -1
userName = (a["name"]) as! String
userAge = Int((a["age"] as? [String:Any])?["age"] as? String ?? "-1") ?? -5
annotationItems.append(User(name:userName,age: userAge,latitude: latData,longitude: longData))
self.locations.append(CLLocation(latitude: latData, longitude: longData))
});
}
print("@@@@@@@@@@@@@@@@@@@@@@@Locations:@@@@@@@@@@@@@@@@@@@@@@@@",locations.count)
let dbscan = DBSCAN(self.locations)
let (sequence, places) = dbscan.findCluster(eps: 1000.0, minPts: 2)
print("@@@@@@@@@@@@@@@@@@@@@@@Places:@@@@@@@@@@@@@@@@@@@@@@@@",places)
for place in places {
print("Cluster:", place.members.count)
let circle = MKCircle(center: place.location.coordinate, radius: 10000)
self.circleOverlays.append(circle)
}
self.viewModel.mapView.addOverlays(circleOverlays)
print("@@@@@@@@@@@@@@@@@@@@@@@Circles:@@@@@@@@@@@@@@@@@@@@@@@@",circleOverlays)
}
private var timer: Timer?
var body: some View {
Map(coordinateRegion: $viewModel.region,
showsUserLocation: true)
.onAppear() {
// viewModel.mapView.delegate = viewModel
let _ = self.plotUsers()
// let _ = self.plotUsers()
timer?.invalidate()
Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { _ in
let _ = self.plotUsers()
self.locations.removeAll()
self.viewModel.mapView.removeOverlays(circleOverlays)
self.circleOverlays.removeAll()
}
}
}
}
struct ContentView_Previews: PreviewProvider { /* Shows map */
static var previews: some View {
ContentView()
}
}
final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate, MKMapViewDelegate {
@Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(
latitude: 38.898022, longitude: -77.050604),
span: MKCoordinateSpan(
latitudeDelta: 0.05, longitudeDelta: 0.05)) /* Can substitute region coordinates with longitude,latitude from firebase */
@Published var map = MKMapView()
var locationManager: CLLocationManager? /* Enables location services*/
let mapView: MKMapView!
override init() {
mapView = MKMapView()
super.init()
mapView.delegate = self
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let circleOverlay = overlay as? MKCircle {
let circleRenderer = MKCircleRenderer(circle: circleOverlay)
circleRenderer.fillColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.3)
circleRenderer.strokeColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.7)
circleRenderer.lineWidth = 2.0
return circleRenderer
}
return MKOverlayRenderer()
}
}
Im new to Swift so Im not entirely sure if the $viewModel.region should somehow be set to the MKMapView created in the ContentViewModel class.
Here is
MKMapViewwithUIViewRepresentableif you decide to go that route. This places a circle wherever the user taps on the map by addingMKCirclesto an array. Not totally what you're looking for - I wasn't sure how to incorporate and test your database function - but hopefully this helps in some way to see one option: