Search code examples
swiftgoogle-mapsgoogle-maps-markersmarkerclusterer

How to update multiple location without clearing GoogleMap


I have load couple of users in map with clustering and now I want to update the users location as per the users new location which I receive from server.

I'm able to do that by clearing the map and load new users data from server but it looks like markers are jumping and it not looks proper.

Is there any way to update the marker locations without clearing the GoogleMap?

Here is the link of my question : Google Map with Cluster and Custom view marker lagging too much while zoomIn and zoomOut

Reference Screen

enter image description here

if some one is moved from his location then how can I update his/her location once I receive updated data from server. (Without clearing the map)

My Code

func setMarkers() {
        for i in 0..<SharedData.sharedInstance.allFriends.count {
            let marker = GMSMarker()
            let friend = SharedData.sharedInstance.allFriends[i]
            marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
            marker.accessibilityHint = String(i)
            marker.icon = #imageLiteral(resourceName: "trans")
            marker.tracksViewChanges = true
            marker.map = mapView

            arrMarkers.append(marker)
            self.generatePOIItems(String(format: "%d", i), position: marker.position, icon: nil, friend: friend, userIndex: i)
        }
        clusterManager.cluster()
        clusterManager.setDelegate(self, mapDelegate: self)
    }

    func updateMarkers() {
        for i in 0..<arrMarkers.count {
            let marker = arrMarkers[i]
            let friend = SharedData.sharedInstance.allFriends[i]
            marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
            marker.accessibilityHint = String(i)
            marker.icon = #imageLiteral(resourceName: "trans")
            marker.tracksViewChanges = true
            marker.map = mapView
        }
        self.defaultCamera(latitude: SharedData.sharedInstance.userLocation.coordinate.latitude, longitude: SharedData.sharedInstance.userLocation.coordinate.longitude)
    }

EDIT

func generatePOIItems(_ accessibilityLabel: String, position: CLLocationCoordinate2D, icon: UIImage?, friend: WallBeeppClass, userIndex: Int) {
        let name = "Item \(accessibilityLabel)"
        let item = POIItem(position: CLLocationCoordinate2DMake(position.latitude, position.longitude), name: name, friend: friend, userIndex: userIndex)
        clusterManager.add(item)
    }


func updateMarkers() {
        for i in 0..<arrMarkers.count {
            let marker = arrMarkers[i]
            let friend = SharedData.sharedInstance.allFriends[i]

            CATransaction.begin()
            CATransaction.setAnimationDuration(1.0)
            marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
            CATransaction.commit()
        }
    }

EDIT 1

If I change some users location from backend and when I got users new location then I update the marker position using above code but the issue is that new location users are still located at old location. and if I clear & redraw the users data then it works fine.

EDIT 2

func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
        marker.groundAnchor = CGPoint(x: 0.1, y: 0.45)
        if let markerData = (marker.userData as? POIItem) {
            let infoWindow = Bundle.main.loadNibNamed("InitialMapInfoView", owner: self, options: nil)?.first as! InitialMapInfoView
            infoWindow.imgUser.sd_setImage(with: URL(string: markerData.friend.user_details.user_photo_small), placeholderImage: #imageLiteral(resourceName: "User_profile"), options: .highPriority, completed: nil)

            if !markerData.friend.user_details.isUserOnline {
                infoWindow.imgCar.image = UIImage.init(named: "small_inactive_" + markerData.friend.user_details.car_personality_name)
            }
            else {
                infoWindow.imgCar.image = UIImage.init(named: "small_" + markerData.friend.user_details.car_personality_name)
            }

            if markerData.friend.user_details.user_id == 88 {
                print("Will Rendrer Marker: \(markerData.friend.user_details.latitude)")
                print("Will Rendrer Marker: \(markerData.friend.user_details.longitude)")
            }

            infoWindow.lblName.text = markerData.friend.user_details.name
            infoWindow.btnImgVW.tag = markerData.userIndex
            infoWindow.btnImgVW.addTarget(self, action: #selector(btnUserTapped(_:)), for: .touchUpInside)
            marker.accessibilityHint = String(markerData.userIndex)
            marker.iconView = infoWindow
            marker.tracksViewChanges = false
        }

Please guide me to do this.


Solution

  • you can subclass GMSMarker, add id of your objects, then get markers by object id you got from server and update position. Here is some code to explain what I mean

        class MyMarker: GMSMarker {
    
             var id: String? = nil
    
        }
    

    add id to your marker

    func setMarkers() {
    
            let marker = MyMarker()
            let friend = SharedData.sharedInstance.allFriends[I]
            marker.id = friend.id
    

    than update by id

    for friend in SharedData.sharedInstance.allFriends {
            guard
                let marker = array.first { $0.id == friend.id }
            else { contiunue }
            marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
        }
    

    don't add marker to map again, just change it's position