Issue #191
Basic with Google Maps
Add to Podfile pod 'GoogleMaps'
Add a custom marker
import GoogleMaps
final class StopMarker: GMSMarker {
let stop: Stop
init(stop: Stop) {
self.stop = stop
super.init()
self.title = stop.name
self.position = stop.toCoordinate()
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
imageView.layer.cornerRadius = 15
imageView.image = UIImage(named: "pin")
self.iconView = imageView
}
}
Show markers
func handle(stops: [Stop]) {
self.stops = stops
stops
.map({ StopMarker(stop: $0) })
.forEach {
$0.map = mapView
}
}
Assigning $0.map = mapView
means telling GMSMapView
to start rendering markers
Handle tap
extension ViewController: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
zoomIn(coordinate: marker.position)
return false
}
func mapView(_ mapView: GMSMapView, didTapInfoWindowOf marker: GMSMarker) {
guard let stopMarker = marker as? StopMarker else {
return
}
let detailViewController = StopDetailViewController(stop: stopMarker.stop)
presentPanModal(detailViewController)
}
}
Clustering
Add google-maps-ios-utils manually by following https://github.com/googlemaps/google-maps-ios-utils/blob/master/Swift.md
Otherwise, with CocoaPods, we get error
[!] The 'Pods-MyApp' target has transitive dependencies that include static binaries: (/Users/khoa/Projects/MyApp/Pods/GoogleMaps/Base/Frameworks/GoogleMapsBase.framework, /Users/khoa/Projects/MyApp/Pods/GoogleMaps/Maps/Frameworks/GoogleMaps.framework, and /Users/khoa/Projects/MyApp/Pods/GoogleMaps/Maps/Frameworks/GoogleMapsCore.framework)
Add ClusterItem
import Foundation
import CoreLocation
class ClusterItem: NSObject, GMUClusterItem {
let position: CLLocationCoordinate2D
let stop: Stop
init(stop: Stop) {
self.stop = stop
self.position = stop.toCoordinate()
}
}
Set up cluster manager
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
renderer.delegate = self
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
clusterManager.setDelegate(self, mapDelegate: self)
Default algorithm GMUNonHierarchicalDistanceBasedAlgorithm
A simple clustering algorithm with O(nlog n) performance. Resulting clusters are not
* hierarchical.
* High level algorithm:
* 1. Iterate over items in the order they were added (candidate clusters).
* 2. Create a cluster with the center of the item.
* 3. Add all items that are within a certain distance to the cluster.
* 4. Move any items out of an existing cluster if they are closer to another cluster.
* 5. Remove those items from the list of candidate clusters.
* Clusters have the center of the first element (not the centroid of the items within it).
Make ClusterItem
and add to clusterManager
. In the end, call clusterManager.cluster()
func handle(stops: [Stop]) {
self.stops = stops
stops
.map({ StopMarker(stop: $0) })
.forEach {
let item = ClusterItem(stop: $0.stop)
clusterManager.add(item)
}
clusterManager.cluster()
}
By default, clusterManager uses renderer to render default pin marker. Implement GMUClusterRendererDelegate
to use our custom StopMarker
extension ViewController: GMUClusterRendererDelegate {
func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
switch object {
case let clusterItem as ClusterItem:
return StopMarker(stop: clusterItem.stop)
default:
return nil
}
}
}
Finally handle tapping on cluster and cluster item
extension ViewController: GMUClusterManagerDelegate {
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
print("tap cluster")
return false
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap clusterItem: GMUClusterItem) -> Bool {
print("tap cluster item")
return false
}
}