Skip to content

Commit 50673f0

Browse files
authored
Merge pull request #38 from HudHud-Maps/cluster-touch
Expand Clusters on Tap
2 parents 780730d + 857c1ce commit 50673f0

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

Sources/MapLibreSwiftUI/Examples/Layers.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c
123123
.iconColor(.white)
124124
.predicate(NSPredicate(format: "cluster != YES"))
125125
}
126+
.onTapMapGesture(on: ["simple-circles-non-clusters"], onTapChanged: { _, features in
127+
print("Tapped on \(features.first)")
128+
})
129+
.expandClustersOnTapping(clusteredLayers: [ClusterLayer(
130+
layerIdentifier: "simple-circles-clusters",
131+
sourceIdentifier: "points"
132+
)])
126133
.ignoresSafeArea(.all)
127134
}
128135

Sources/MapLibreSwiftUI/Extensions/MapView/MapViewGestures.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,29 @@ extension MapView {
5858
return
5959
}
6060

61+
if let clusteredLayers {
62+
if let gestureRecognizer = sender as? UITapGestureRecognizer, gestureRecognizer.numberOfTouches == 1 {
63+
let point = gestureRecognizer.location(in: sender.view)
64+
for clusteredLayer in clusteredLayers {
65+
let features = mapView.visibleFeatures(
66+
at: point,
67+
styleLayerIdentifiers: [clusteredLayer.layerIdentifier]
68+
)
69+
if let cluster = features.first as? MLNPointFeatureCluster,
70+
let source = mapView.style?
71+
.source(withIdentifier: clusteredLayer.sourceIdentifier) as? MLNShapeSource
72+
{
73+
let zoomLevel = source.zoomLevel(forExpanding: cluster)
74+
75+
if zoomLevel > 0 {
76+
mapView.setCenter(cluster.coordinate, zoomLevel: zoomLevel, animated: true)
77+
break // since we can only zoom on one thing, we can abort the for loop here
78+
}
79+
}
80+
}
81+
}
82+
}
83+
6184
// Process the gesture into a context response.
6285
let context = processContextFromGesture(mapView, gesture: gesture, sender: sender)
6386
// Run the context through the gesture held on the MapView (emitting to the MapView modifier).
@@ -97,3 +120,14 @@ extension MapView {
97120
coordinate: mapView.convert(point, toCoordinateFrom: mapView))
98121
}
99122
}
123+
124+
/// Provides the layer identifier and it's source identifier.
125+
public struct ClusterLayer {
126+
public let layerIdentifier: String
127+
public let sourceIdentifier: String
128+
129+
public init(layerIdentifier: String, sourceIdentifier: String) {
130+
self.layerIdentifier = layerIdentifier
131+
self.sourceIdentifier = sourceIdentifier
132+
}
133+
}

Sources/MapLibreSwiftUI/MapView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public struct MapView: UIViewRepresentable {
2828

2929
private var locationManager: MLNLocationManager?
3030

31+
var clusteredLayers: [ClusterLayer]?
32+
3133
public init(
3234
styleURL: URL,
3335
camera: Binding<MapViewCamera> = .constant(.default()),

Sources/MapLibreSwiftUI/MapViewModifiers.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ public extension MapView {
108108
return newMapView
109109
}
110110

111+
/// Add a default implementation for tapping clustered features. When tapped, the map zooms so that the cluster is
112+
/// expanded.
113+
/// - Parameter clusteredLayers: An array of layers to monitor that can contain clustered features.
114+
/// - Returns: The modified MapView
115+
func expandClustersOnTapping(clusteredLayers: [ClusterLayer]) -> MapView {
116+
var newMapView = self
117+
118+
newMapView.clusteredLayers = clusteredLayers
119+
120+
return newMapView
121+
}
122+
111123
func mapViewContentInset(_ inset: UIEdgeInsets) -> Self {
112124
var result = self
113125

0 commit comments

Comments
 (0)