下面的代码是从数据库中获取特定数量的引用,根据一些 DBSCAN 函数给出的一些坐标制作圆覆盖,并在地图上绘制圆覆盖。每隔 10 秒,这些圆圈就会从地图中删除,并使用数据库中的相同圆圈进行更新。问题是没有显示圆圈。我试过调试这个无济于事。任何建议/帮助表示赞赏。
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()
}
}
我是 Swift 的新手,所以我不完全确定 $viewModel.region 是否应该以某种方式设置为在 ContentViewModel 类中创建的 MKMapView。
如果您决定走那条路,这里是带有 UIViewRepresentable 的 MKMapView。这通过将 MKCircles 添加到数组来在用户点击地图的任何地方放置一个圆圈。不完全是你要找的东西——我不确定如何合并和测试你的数据库功能——但希望这在某种程度上有助于看到一个选项:
import SwiftUI
import CoreLocation
import MapKit
struct MapTestQ2: UIViewRepresentable {
@Binding var centerCoordinate: CLLocationCoordinate2D
@State private var mapView = MKMapView()
@State private var circles: [MKCircle] = []
func makeUIView(context: Context) -> MKMapView {
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
let region = MKCoordinateRegion(center: centerCoordinate, span: span)
mapView.setRegion(region, animated: true)
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
mapView.addOverlays(circles)
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate, UIGestureRecognizerDelegate {
@State var parent: MapTestQ2
var tRecognizer = UITapGestureRecognizer()
init(_ parent: MapTestQ2) {
self.parent = parent
super.init()
self.tRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapHandler))
self.tRecognizer.delegate = self
self.parent.mapView.addGestureRecognizer(tRecognizer)
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard let circleoverlay = overlay as? MKCircle else {return MKOverlayRenderer()}
let circleRenderer = MKCircleRenderer(circle: circleoverlay)
circleRenderer.strokeColor = .blue
circleRenderer.fillColor = .systemCyan
circleRenderer.alpha = 0.5
return circleRenderer
}
@objc func tapHandler(_ gesture: UITapGestureRecognizer) {
print("Tapped")
let location = tRecognizer.location(in: self.parent.mapView)
let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView)
let acircle = MKCircle(center: coordinate, radius: 500.0)
self.parent.circles.append(acircle)
}
}
}
struct SEQ2: View {
@State private var testcoord = CLLocationCoordinate2D(latitude: 37.33461, longitude: -122.00898)
var body: some View {
MapTestQ2(centerCoordinate: $testcoord)
}
}