google-maps-ios-utils icon indicating copy to clipboard operation
google-maps-ios-utils copied to clipboard

Marker disappeared on cluster zoom 

Open hiteshborse12 opened this issue 4 years ago • 12 comments

I am working on a cluster. Showing cluster using marker GMSMapView and GMUClusterManager. Markers clusters are showing properly but marker disappeared on map zoom.

Note: Assiging custom image to marker icon: let marker = GMSMarker(position: position) //custome marker image marker.icon = icon clusterManager.add(marker)

Code example

import UIKit
import GoogleMaps
import GoogleMapsUtils
class ViewController: UIViewController,GMSMapViewDelegate {
    @IBOutlet weak var mapview: GMSMapView!
    private var clusterManager: GMUClusterManager!
    
    override func viewDidLoad(){
        let iconGenerator = GMUDefaultClusterIconGenerator()
        let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
         let renderer = GMUDefaultClusterRenderer(mapView: mapview,
                                       clusterIconGenerator: iconGenerator)
        renderer.delegate = self
        self.clusterManager = GMUClusterManager(map: self.mapview ?? GMSMapView(), algorithm: algorithm, renderer: renderer)
        self.clusterManager.setDelegate(self, mapDelegate: self)

        // Add ClusterItems
        for i in 0..<10{
            let img = UIImage(named: "pin")!
            self.generateClusterItems(lat: "\(19+i)", lng:  "\(72+i)", name: "\(i)", icon: img)
        }
        self.clusterManager.cluster()
        self.mapview.animate(to: GMSCameraPosition(latitude: 19, longitude: 72, zoom: mapview.minZoom))
        
    }
    /// adds them to the cluster manager.
    private func generateClusterItems(lat: String, lng: String,name: String, icon: UIImage) {
        guard let lat = Double(lat) else { return  }
        guard let lng = Double(lng) else { return  }
        let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
        let marker = GMSMarker(position: position)
        //custome marker image
        marker.icon = icon
        clusterManager.add(marker)
    }
}
//MARK:- GMUClusterManagerDelegate-
extension ViewController: GMUClusterManagerDelegate,GMUClusterRendererDelegate {
    func clusterManager(_ clusterManager: GMUClusterManager, didTap clusterItem: GMUClusterItem) -> Bool {
        print("didTap clusterItem")
        return true
    }
    func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
        print("didTap cluster")
        return true
    }
}

Project code and sample video: link

hiteshborse12 avatar Jul 30 '20 13:07 hiteshborse12

I'm able to reproduce this. It appears that there is a bug when you try to add a GMSMarker directly. While I look into a fix, please create a class that conforms to GMUClusterItem as a workaround:

class ClusterItem: GMUClusterItem {
    var position: CLLocationCoordinate2D

    init(position: CLLocationCoordinate2D) {
        self.position= position
    }
}

class ViewController: UIViewController {

    /// adds them to the cluster manager.
    private func generateClusterItems(lat: String, lng: String,name: String, icon: UIImage) {
        guard let lat = Double(lat) else { return  }
        guard let lng = Double(lng) else { return  }
        let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
        let item = ClusterIte(position: position)
        clusterManager.add(item)
    }
}

... and then attach a custom marker through the GMUClusterRendererDelegate method:

extension ViewController: GMUClusterManagerDelegate,GMUClusterRendererDelegate {
  func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
    marker.icon = UIImage(named: "pin")
  }
}

arriolac avatar Jul 30 '20 15:07 arriolac

I did the above changes.. and it fixed the marker disappear issue. But now I am not able to see the cluster (10+). Sending you code and screenshot

class ViewController: UIViewController,GMSMapViewDelegate { @IBOutlet weak var mapview: GMSMapView! private var clusterManager: GMUClusterManager!

override func viewDidLoad(){
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let renderer = GMUDefaultClusterRenderer(mapView: mapview,
                                             clusterIconGenerator: iconGenerator)
    renderer.delegate = self
    self.clusterManager = GMUClusterManager(map: self.mapview ?? GMSMapView(), algorithm: algorithm, renderer: renderer)
    self.clusterManager.setDelegate(self, mapDelegate: self)
    for i in 0..<10{
        let img = UIImage(named: "pin")!
        self.generateClusterItems(lat: "\(19+i)", lng:  "\(72+i)", name: "\(i)", icon: img)
    }
    self.clusterManager.cluster()
    self.mapview.animate(to: GMSCameraPosition(latitude: 19, longitude: 72, zoom: mapview.minZoom))
}

private func generateClusterItems(lat: String, lng: String,name: String, icon: UIImage) {
    guard let lat = Double(lat) else { return  }
    guard let lng = Double(lng) else { return  }
    let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
    **let item = ClusterItem(position: position)**
    clusterManager.add(item)
}

} extension ViewController: GMUClusterManagerDelegate,GMUClusterRendererDelegate { func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) { marker.icon = UIImage(named: "pin") }

} class ClusterItem:NSObject, GMUClusterItem { var position: CLLocationCoordinate2D init(position: CLLocationCoordinate2D) { self.position = position } }

Simulator Screen Shot - iPhone 11 Pro Max - 2020-07-30 at 22 13 23

ViewController.swift.zip

hiteshborse12 avatar Jul 30 '20 16:07 hiteshborse12

Meant to say that you also need to check the type of marker.userData and only change the image if it is a GMUClusterItem:

    func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
      if marker.userData is GMUClusterItem {
        marker.icon = UIImage(named: "pin")
      }
    }

arriolac avatar Jul 30 '20 17:07 arriolac

Oh yes make sense. All issues fixed now. Thanks for the quick help.

hiteshborse12 avatar Jul 30 '20 17:07 hiteshborse12

Reopening this issue because this is still a bug with the library. The code snippet you shared earlier should work.

arriolac avatar Jul 30 '20 17:07 arriolac

Is there an ETA for this fix? The bug is reproducible in the project's sample app as well. Hope to avoid releasing an update to my app with a workaround if the library will be fixed soon. Well, hope to avoid releasing a workaround, period :)

carloshwa avatar Sep 11 '20 03:09 carloshwa

Also experiencing this issue

MichaelNeas avatar Sep 23 '20 21:09 MichaelNeas

:tada: This issue has been resolved in version 3.3.1 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

googlemaps-bot avatar Sep 25 '20 17:09 googlemaps-bot

Great. Thanks :-)

hiteshborse12 avatar Oct 01 '20 06:10 hiteshborse12

@arriolac the problem still exists. GMSMarker disappears by changing the zoom if its position value (latitude and longitude) changes in the background and of course marker is related with the GMUClusterManager.

barnavarga avatar Oct 21 '20 15:10 barnavarga

@barnavarga can you provide a code snippet to repro that?

arriolac avatar Apr 05 '21 22:04 arriolac

@arriolac Hello! I have:

pod 'GoogleMaps', '6.2.1'
pod 'GooglePlaces', '6.2.1'
pod 'Google-Maps-iOS-Utils', '~> 4.1.0'

and problem is still here. The workaround above didn't help. My markers have iconView as a horizontal rectangle to the right of the anchor, and disappear (during zoom) when the left side of the rectangle goes off the edge of the screen. My code:

final class MapViewController: UIViewController {
    ...
    private lazy var clusterManager: GMUClusterManager? = {
        let buckets: [NSNumber] = [10, 25, 50, 100, 250, 500, 1000]
        let images: [UIImage] = buckets.map { _ in
            UIImage(named: "cluster") ?? UIImage()
        }
        let iconGenerator = GMUDefaultClusterIconGenerator(buckets: buckets, backgroundImages: images)
        let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
        renderer.minimumClusterSize = 1
        renderer.maximumClusterZoom = 13
        
        guard let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm(clusterDistancePoints: 20) else { return nil }
        let manager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
        manager.setDelegate(self, mapDelegate: self)
        return manager
    }()
    ...
    func setupMarkers(_ events: [MapEventModel]) {
        clusterManager?.clearItems()
        for (i, event) in events.enumerated() {
            let customMarker = CustomMarkerView(tag: i, model: event)
            let marker = GMSMarker()
            marker.iconView = customMarker
            marker.position = event.coordinate
            marker.groundAnchor = CGPoint(x: 0.0, y: 1.0)
            marker.appearAnimation = .fadeIn
            marker.zIndex = Int32(i)
            clusterManager?.add(marker)
        }
        clusterManager?.cluster()
    }
    ...
}

SparklingAir avatar Jul 19 '22 09:07 SparklingAir