Skip to main content

Mapbox の ピンのタップで、一番近いピンを選びたい

悩み

  • ピンが密集しているので見づらい
    • → ピンの表示サイズを小さくした (max 15px)
  • 小さいとタップで拾いづらい
    • → タップ用の透明レイヤを用意 (30 px)
  • 見えないレイヤが隣のピンを隠してしまうことに (裏目)
    • → これは、細かく操作したいユーザに相当ストレス (のはず)
    • → 「手前」ではなく、「一番近い」ピンを選択したい

やりたいこと

  • タップ位置で拾われたピンをすべて取得し、一番近いものを選択する

変更前のコード(手前のピンを 1 個取得)

swift
.onLayerTapGesture("parksTouchArea") { queriedFeature, context in
let feature = queriedFeature.feature

print(feature) // ★
}

変更後のコード(タップ範囲のピンをすべて取得)

swift
.onLayerTapGesture("parksTouchArea") { _, context in
mapReader.map?.queryRenderedFeatures(with: context.point) { result in
guard case .success(let queriedRenderedFeatures) = result else {
print("Failed to query features: \(result)")
return
}
// for feature in queriedRenderedFeatures {
// print("=====================================")
// print(feature.queriedFeature.feature)
// }
let tapPoint = context.point

let featureAndDistance = queriedRenderedFeatures.compactMap { queriedRenderedFeature -> (Feature, CGFloat)? in
let feature = queriedRenderedFeature.queriedFeature.feature
guard let pinPoint = feature.geometry?.point else { return nil }
guard let screenPoint = mapReader.map?.point(for: pinPoint.coordinates) else { return nil }
let distance = hypot(screenPoint.x - tapPoint.x, screenPoint.y - tapPoint.y)
return (feature, distance)
}
.min(by: { $0.1 < $1.1 })

if let nearestFeature = featureAndDistance?.0 {
print(nearestFeature) // ★
}
}