expo-gaode-map 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +1 -0
  2. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +17 -1
  3. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +52 -5
  4. package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +184 -6
  5. package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +24 -51
  6. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +3 -0
  7. package/build/ExpoGaodeMap.types.d.ts.map +1 -1
  8. package/build/ExpoGaodeMap.types.js +0 -10
  9. package/build/ExpoGaodeMap.types.js.map +1 -1
  10. package/build/ExpoGaodeMapModule.d.ts.map +1 -1
  11. package/build/ExpoGaodeMapModule.js +0 -10
  12. package/build/ExpoGaodeMapModule.js.map +1 -1
  13. package/build/ExpoGaodeMapView.d.ts +39 -20
  14. package/build/ExpoGaodeMapView.d.ts.map +1 -1
  15. package/build/ExpoGaodeMapView.js +215 -31
  16. package/build/ExpoGaodeMapView.js.map +1 -1
  17. package/build/components/overlays/Circle.d.ts +0 -15
  18. package/build/components/overlays/Circle.d.ts.map +1 -1
  19. package/build/components/overlays/Circle.js +28 -46
  20. package/build/components/overlays/Circle.js.map +1 -1
  21. package/build/components/overlays/Cluster.d.ts +3 -15
  22. package/build/components/overlays/Cluster.d.ts.map +1 -1
  23. package/build/components/overlays/Cluster.js +3 -25
  24. package/build/components/overlays/Cluster.js.map +1 -1
  25. package/build/components/overlays/HeatMap.d.ts +3 -14
  26. package/build/components/overlays/HeatMap.d.ts.map +1 -1
  27. package/build/components/overlays/HeatMap.js +3 -24
  28. package/build/components/overlays/HeatMap.js.map +1 -1
  29. package/build/components/overlays/Marker.d.ts +2 -15
  30. package/build/components/overlays/Marker.d.ts.map +1 -1
  31. package/build/components/overlays/Marker.js +60 -46
  32. package/build/components/overlays/Marker.js.map +1 -1
  33. package/build/components/overlays/MultiPoint.d.ts +3 -14
  34. package/build/components/overlays/MultiPoint.d.ts.map +1 -1
  35. package/build/components/overlays/MultiPoint.js +3 -24
  36. package/build/components/overlays/MultiPoint.js.map +1 -1
  37. package/build/components/overlays/Polygon.d.ts +13 -16
  38. package/build/components/overlays/Polygon.d.ts.map +1 -1
  39. package/build/components/overlays/Polygon.js +41 -75
  40. package/build/components/overlays/Polygon.js.map +1 -1
  41. package/build/components/overlays/Polyline.d.ts +12 -14
  42. package/build/components/overlays/Polyline.d.ts.map +1 -1
  43. package/build/components/overlays/Polyline.js +34 -35
  44. package/build/components/overlays/Polyline.js.map +1 -1
  45. package/build/components/overlays/index.d.ts.map +1 -1
  46. package/build/components/overlays/index.js +0 -10
  47. package/build/components/overlays/index.js.map +1 -1
  48. package/build/index.d.ts.map +1 -1
  49. package/build/index.js +0 -10
  50. package/build/index.js.map +1 -1
  51. package/build/modules/AMapLocation.d.ts +47 -10
  52. package/build/modules/AMapLocation.d.ts.map +1 -1
  53. package/build/modules/AMapLocation.js +48 -20
  54. package/build/modules/AMapLocation.js.map +1 -1
  55. package/build/modules/AMapPermissions.d.ts +3 -1
  56. package/build/modules/AMapPermissions.d.ts.map +1 -1
  57. package/build/modules/AMapPermissions.js +3 -11
  58. package/build/modules/AMapPermissions.js.map +1 -1
  59. package/build/modules/AMapSDK.d.ts +5 -4
  60. package/build/modules/AMapSDK.d.ts.map +1 -1
  61. package/build/modules/AMapSDK.js +5 -14
  62. package/build/modules/AMapSDK.js.map +1 -1
  63. package/build/modules/AMapView.d.ts.map +1 -1
  64. package/build/modules/AMapView.js +0 -8
  65. package/build/modules/AMapView.js.map +1 -1
  66. package/build/types/index.d.ts.map +1 -1
  67. package/build/types/index.js +0 -10
  68. package/build/types/index.js.map +1 -1
  69. package/build/types/map-view.types.d.ts +30 -0
  70. package/build/types/map-view.types.d.ts.map +1 -1
  71. package/build/types/map-view.types.js.map +1 -1
  72. package/build/types/overlays.types.d.ts +25 -1
  73. package/build/types/overlays.types.d.ts.map +1 -1
  74. package/build/types/overlays.types.js.map +1 -1
  75. package/docs/API.md +40 -0
  76. package/docs/EXAMPLES.md +86 -2
  77. package/docs/RELEASE_GUIDE.md +178 -0
  78. package/expo-module.config.json +1 -1
  79. package/ios/ExpoGaodeMapModule.swift +42 -14
  80. package/ios/ExpoGaodeMapView.swift +210 -7
  81. package/ios/managers/OverlayManager.swift +78 -10
  82. package/ios/overlays/CircleView.swift +41 -12
  83. package/ios/overlays/MarkerView.swift +55 -3
  84. package/ios/overlays/PolygonView.swift +25 -5
  85. package/ios/overlays/PolylineView.swift +23 -4
  86. package/ios/utils/ColorParser.swift +0 -5
  87. package/package.json +1 -1
  88. package/src/ExpoGaodeMap.types.ts +1 -10
  89. package/src/ExpoGaodeMapModule.ts +1 -10
  90. package/src/ExpoGaodeMapView.tsx +257 -38
  91. package/src/components/overlays/Circle.tsx +32 -50
  92. package/src/components/overlays/Cluster.tsx +4 -26
  93. package/src/components/overlays/HeatMap.tsx +4 -25
  94. package/src/components/overlays/Marker.tsx +69 -52
  95. package/src/components/overlays/MultiPoint.tsx +4 -25
  96. package/src/components/overlays/Polygon.tsx +48 -78
  97. package/src/components/overlays/Polyline.tsx +41 -38
  98. package/src/components/overlays/index.ts +0 -11
  99. package/src/index.ts +0 -11
  100. package/src/modules/AMapLocation.ts +56 -20
  101. package/src/modules/AMapPermissions.ts +4 -11
  102. package/src/modules/AMapSDK.ts +7 -14
  103. package/src/modules/AMapView.ts +0 -8
  104. package/src/types/index.ts +1 -10
  105. package/src/types/map-view.types.ts +25 -0
  106. package/src/types/overlays.types.ts +30 -1
@@ -221,7 +221,7 @@ public class ExpoGaodeMapModule: Module {
221
221
 
222
222
  View(ExpoGaodeMapView.self) {
223
223
  // 事件 - 使用 Expo 的事件命名约定
224
- Events("onMapPress", "onMapLongPress", "onLoad")
224
+ Events("onMapPress", "onMapLongPress", "onLoad", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress")
225
225
 
226
226
  // 地图类型
227
227
  Prop("mapType") { (view: ExpoGaodeMapView, type: Int) in
@@ -390,13 +390,41 @@ public class ExpoGaodeMapModule: Module {
390
390
  view.setTitle(title)
391
391
  }
392
392
 
393
- Prop("description") { (view: MarkerView, description: String) in
394
- view.setDescription(description)
393
+ Prop("snippet") { (view: MarkerView, snippet: String) in
394
+ view.setDescription(snippet)
395
395
  }
396
396
 
397
397
  Prop("draggable") { (view: MarkerView, draggable: Bool) in
398
398
  view.setDraggable(draggable)
399
399
  }
400
+
401
+ Prop("icon") { (view: MarkerView, source: [String: Any]?) in
402
+ view.setIcon(source)
403
+ }
404
+
405
+ Prop("iconWidth") { (view: MarkerView, width: Double) in
406
+ view.iconWidth = width
407
+ }
408
+
409
+ Prop("iconHeight") { (view: MarkerView, height: Double) in
410
+ view.iconHeight = height
411
+ }
412
+
413
+ Prop("centerOffset") { (view: MarkerView, offset: [String: Double]) in
414
+ view.setCenterOffset(offset)
415
+ }
416
+
417
+ Prop("animatesDrop") { (view: MarkerView, animate: Bool) in
418
+ view.setAnimatesDrop(animate)
419
+ }
420
+
421
+ Prop("pinColor") { (view: MarkerView, color: String) in
422
+ view.setPinColor(color)
423
+ }
424
+
425
+ Prop("canShowCallout") { (view: MarkerView, show: Bool) in
426
+ view.setCanShowCallout(show)
427
+ }
400
428
  }
401
429
 
402
430
  // Circle - 圆形
@@ -411,16 +439,16 @@ public class ExpoGaodeMapModule: Module {
411
439
  view.setRadius(radius)
412
440
  }
413
441
 
414
- Prop("fillColor") { (view: CircleView, color: Int) in
442
+ Prop("fillColor") { (view: CircleView, color: String) in
415
443
  view.setFillColor(color)
416
444
  }
417
445
 
418
- Prop("strokeColor") { (view: CircleView, color: Int) in
446
+ Prop("strokeColor") { (view: CircleView, color: String) in
419
447
  view.setStrokeColor(color)
420
448
  }
421
449
 
422
- Prop("strokeWidth") { (view: CircleView, width: Float) in
423
- view.setStrokeWidth(width)
450
+ Prop("strokeWidth") { (view: CircleView, width: Double) in
451
+ view.setStrokeWidth(Float(width))
424
452
  }
425
453
  }
426
454
 
@@ -432,11 +460,11 @@ public class ExpoGaodeMapModule: Module {
432
460
  view.setPoints(points)
433
461
  }
434
462
 
435
- Prop("strokeWidth") { (view: PolylineView, width: Float) in
436
- view.setStrokeWidth(width)
463
+ Prop("strokeWidth") { (view: PolylineView, width: Double) in
464
+ view.setStrokeWidth(Float(width))
437
465
  }
438
466
 
439
- Prop("strokeColor") { (view: PolylineView, color: Int) in
467
+ Prop("strokeColor") { (view: PolylineView, color: String) in
440
468
  view.setStrokeColor(color)
441
469
  }
442
470
 
@@ -453,16 +481,16 @@ public class ExpoGaodeMapModule: Module {
453
481
  view.setPoints(points)
454
482
  }
455
483
 
456
- Prop("fillColor") { (view: PolygonView, color: Int) in
484
+ Prop("fillColor") { (view: PolygonView, color: String) in
457
485
  view.setFillColor(color)
458
486
  }
459
487
 
460
- Prop("strokeColor") { (view: PolygonView, color: Int) in
488
+ Prop("strokeColor") { (view: PolygonView, color: String) in
461
489
  view.setStrokeColor(color)
462
490
  }
463
491
 
464
- Prop("strokeWidth") { (view: PolygonView, width: Float) in
465
- view.setStrokeWidth(width)
492
+ Prop("strokeWidth") { (view: PolygonView, width: Double) in
493
+ view.setStrokeWidth(Float(width))
466
494
  }
467
495
  }
468
496
 
@@ -59,6 +59,11 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
59
59
  let onMapPress = EventDispatcher()
60
60
  let onMapLongPress = EventDispatcher()
61
61
  let onLoad = EventDispatcher()
62
+ let onMarkerPress = EventDispatcher()
63
+ let onMarkerDragStart = EventDispatcher()
64
+ let onMarkerDrag = EventDispatcher()
65
+ let onMarkerDragEnd = EventDispatcher()
66
+ let onCirclePress = EventDispatcher()
62
67
 
63
68
  // MARK: - 私有属性
64
69
 
@@ -72,6 +77,8 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
72
77
  private var overlayManager: OverlayManager!
73
78
  /// 地图是否已加载完成
74
79
  private var isMapLoaded = false
80
+ /// 是否正在处理 annotation 选择事件
81
+ private var isHandlingAnnotationSelect = false
75
82
 
76
83
  // MARK: - 初始化
77
84
 
@@ -91,6 +98,11 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
91
98
  uiManager = UIManager(mapView: mapView)
92
99
  overlayManager = OverlayManager(mapView: mapView)
93
100
 
101
+ // 设置 Circle 点击回调
102
+ overlayManager.onCirclePress = { [weak self] event in
103
+ self?.onCirclePress(event)
104
+ }
105
+
94
106
  setupDefaultConfig()
95
107
  }
96
108
 
@@ -106,13 +118,19 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
106
118
  override func addSubview(_ view: UIView) {
107
119
  super.addSubview(view)
108
120
 
121
+ print("🔧 添加子视图: \(type(of: view))")
122
+
109
123
  if let markerView = view as? MarkerView {
124
+ print("✅ 识别为 MarkerView")
110
125
  markerView.setMap(mapView)
111
126
  } else if let circleView = view as? CircleView {
127
+ print("✅ 识别为 CircleView")
112
128
  circleView.setMap(mapView)
113
129
  } else if let polylineView = view as? PolylineView {
130
+ print("✅ 识别为 PolylineView")
114
131
  polylineView.setMap(mapView)
115
132
  } else if let polygonView = view as? PolygonView {
133
+ print("✅ 识别为 PolygonView")
116
134
  polygonView.setMap(mapView)
117
135
  } else if let heatMapView = view as? HeatMapView {
118
136
  heatMapView.setMap(mapView)
@@ -315,9 +333,64 @@ extension ExpoGaodeMapView {
315
333
  * 地图单击事件
316
334
  */
317
335
  public func mapView(_ mapView: MAMapView, didSingleTappedAt coordinate: CLLocationCoordinate2D) {
336
+ // 如果正在处理 annotation 选择,跳过地图点击事件
337
+ if isHandlingAnnotationSelect {
338
+ isHandlingAnnotationSelect = false
339
+ return
340
+ }
341
+
342
+ // 检查是否点击了圆形 (声明式 CircleView)
343
+ if checkCirclePress(at: coordinate) {
344
+ return
345
+ }
346
+
347
+ // 检查是否点击了圆形 (命令式 API)
348
+ if overlayManager.checkCirclePress(at: coordinate) {
349
+ return
350
+ }
351
+
318
352
  onMapPress(["latitude": coordinate.latitude, "longitude": coordinate.longitude])
319
353
  }
320
354
 
355
+ /**
356
+ * 检查点击位置是否在圆形内
357
+ */
358
+ private func checkCirclePress(at coordinate: CLLocationCoordinate2D) -> Bool {
359
+ let circleViews = subviews.compactMap { $0 as? CircleView }
360
+ print("🔍 检查圆形点击 - 找到 \(circleViews.count) 个 CircleView")
361
+
362
+ for circleView in circleViews {
363
+ guard let circle = circleView.circle else {
364
+ print("⚠️ CircleView 没有 circle 对象")
365
+ continue
366
+ }
367
+
368
+ let circleCenter = circle.coordinate
369
+ let distance = calculateDistance(from: coordinate, to: circleCenter)
370
+ print("📍 圆心: (\(circleCenter.latitude), \(circleCenter.longitude)), 半径: \(circle.radius)m, 距离: \(distance)m")
371
+
372
+ if distance <= circle.radius {
373
+ print("✅ 点击在圆形内,触发 onPress")
374
+ circleView.onPress([
375
+ "latitude": coordinate.latitude,
376
+ "longitude": coordinate.longitude
377
+ ])
378
+ return true
379
+ }
380
+ }
381
+ print("❌ 点击不在任何圆形内")
382
+ return false
383
+ }
384
+
385
+ /**
386
+ * 计算两点间距离(米)
387
+ */
388
+ private func calculateDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> Double {
389
+ let fromLocation = CLLocation(latitude: from.latitude, longitude: from.longitude)
390
+ let toLocation = CLLocation(latitude: to.latitude, longitude: to.longitude)
391
+ return fromLocation.distance(from: toLocation)
392
+ }
393
+
321
394
  /**
322
395
  * 地图长按事件
323
396
  */
@@ -335,13 +408,63 @@ extension ExpoGaodeMapView {
335
408
  }
336
409
 
337
410
  if annotation.isKind(of: MAPointAnnotation.self) {
338
- let identifier = "marker"
339
- var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
340
- if view == nil {
341
- view = MAPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
411
+ guard let props = overlayManager.getMarkerProps(for: annotation) else {
412
+ return nil
413
+ }
414
+
415
+ let iconUri = props["icon"] as? String
416
+ let iconWidth = props["iconWidth"] as? Double ?? 40
417
+ let iconHeight = props["iconHeight"] as? Double ?? 40
418
+ let pinColor = props["pinColor"] as? String ?? "red"
419
+ let draggable = props["draggable"] as? Bool ?? false
420
+
421
+ // 如果有自定义图标,使用 MAAnnotationView
422
+ if let iconUri = iconUri, !iconUri.isEmpty {
423
+ var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "custom_marker")
424
+ if annotationView == nil {
425
+ annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: "custom_marker")
426
+ }
427
+ annotationView?.annotation = annotation
428
+ annotationView?.canShowCallout = true
429
+ annotationView?.isDraggable = draggable
430
+
431
+ // 加载图标
432
+ loadMarkerIcon(iconUri: iconUri) { image in
433
+ if let img = image {
434
+ // 调整图标大小
435
+ let size = CGSize(width: iconWidth, height: iconHeight)
436
+ UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
437
+ img.draw(in: CGRect(origin: .zero, size: size))
438
+ let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
439
+ UIGraphicsEndImageContext()
440
+
441
+ annotationView?.image = resizedImage
442
+ // 设置中心点偏移,使标注底部中间点成为经纬度对应点
443
+ annotationView?.centerOffset = CGPoint(x: 0, y: -iconHeight / 2)
444
+ }
445
+ }
446
+
447
+ return annotationView
448
+ }
449
+
450
+ // 使用大头针样式
451
+ guard let pinView = MAPinAnnotationView(annotation: annotation, reuseIdentifier: "pin_marker") else {
452
+ return nil
342
453
  }
343
- view?.canShowCallout = true
344
- return view
454
+ pinView.canShowCallout = true
455
+ pinView.animatesDrop = true
456
+ pinView.isDraggable = draggable
457
+
458
+ // 设置大头针颜色
459
+ if pinColor == "green" {
460
+ pinView.pinColor = .green
461
+ } else if pinColor == "purple" {
462
+ pinView.pinColor = .purple
463
+ } else {
464
+ pinView.pinColor = .red
465
+ }
466
+
467
+ return pinView
345
468
  }
346
469
  return nil
347
470
  }
@@ -352,7 +475,7 @@ extension ExpoGaodeMapView {
352
475
  */
353
476
  public func mapView(_ mapView: MAMapView, rendererFor overlay: MAOverlay) -> MAOverlayRenderer {
354
477
  for subview in subviews {
355
- if let circleView = subview as? CircleView, circleView.circle === overlay {
478
+ if let circleView = subview as? CircleView, let circle = circleView.circle, circle === overlay {
356
479
  return circleView.getRenderer()
357
480
  } else if let polylineView = subview as? PolylineView, polylineView.polyline === overlay {
358
481
  return polylineView.getRenderer()
@@ -363,4 +486,84 @@ extension ExpoGaodeMapView {
363
486
 
364
487
  return overlayManager.getRenderer(for: overlay) ?? MAOverlayRenderer(overlay: overlay)
365
488
  }
489
+
490
+ /**
491
+ * 标注点击事件
492
+ */
493
+ public func mapView(_ mapView: MAMapView, didSelect view: MAAnnotationView) {
494
+ guard let annotation = view.annotation, !annotation.isKind(of: MAUserLocation.self) else {
495
+ return
496
+ }
497
+
498
+ // 标记正在处理 annotation 选择,阻止地图点击事件
499
+ isHandlingAnnotationSelect = true
500
+
501
+ // 查找对应的 markerId
502
+ if let markerId = overlayManager.getMarkerId(for: annotation) {
503
+ onMarkerPress([
504
+ "markerId": markerId,
505
+ "latitude": annotation.coordinate.latitude,
506
+ "longitude": annotation.coordinate.longitude
507
+ ])
508
+ }
509
+
510
+ // 不要立即取消选中,让气泡有机会显示
511
+ // 用户点击地图其他地方时会自动取消选中
512
+ }
513
+
514
+ /**
515
+ * 标注拖拽状态变化
516
+ */
517
+ public func mapView(_ mapView: MAMapView, annotationView view: MAAnnotationView, didChange newState: MAAnnotationViewDragState, fromOldState oldState: MAAnnotationViewDragState) {
518
+ guard let annotation = view.annotation else { return }
519
+
520
+ if let markerId = overlayManager.getMarkerId(for: annotation) {
521
+ let coord = annotation.coordinate
522
+ let event: [String: Any] = [
523
+ "markerId": markerId,
524
+ "latitude": coord.latitude,
525
+ "longitude": coord.longitude
526
+ ]
527
+
528
+ switch newState {
529
+ case .starting:
530
+ onMarkerDragStart(event)
531
+ case .dragging:
532
+ onMarkerDrag(event)
533
+ case .ending, .canceling:
534
+ onMarkerDragEnd(event)
535
+ default:
536
+ break
537
+ }
538
+ }
539
+ }
540
+
541
+ /**
542
+ * 加载标记图标
543
+ * @param iconUri 图标 URI (支持 http/https/file/本地资源)
544
+ * @param completion 加载完成回调
545
+ */
546
+ private func loadMarkerIcon(iconUri: String, completion: @escaping (UIImage?) -> Void) {
547
+ if iconUri.hasPrefix("http://") || iconUri.hasPrefix("https://") {
548
+ // 网络图片
549
+ guard let url = URL(string: iconUri) else {
550
+ completion(nil)
551
+ return
552
+ }
553
+ URLSession.shared.dataTask(with: url) { data, _, _ in
554
+ guard let data = data, let image = UIImage(data: data) else {
555
+ DispatchQueue.main.async { completion(nil) }
556
+ return
557
+ }
558
+ DispatchQueue.main.async { completion(image) }
559
+ }.resume()
560
+ } else if iconUri.hasPrefix("file://") {
561
+ // 本地文件
562
+ let path = String(iconUri.dropFirst(7))
563
+ completion(UIImage(contentsOfFile: path))
564
+ } else {
565
+ // 资源文件名
566
+ completion(UIImage(named: iconUri))
567
+ }
568
+ }
366
569
  }
@@ -18,6 +18,12 @@ class OverlayManager {
18
18
  private var overlayStyles: [String: [String: Any]] = [:]
19
19
  /// 标记点字典 (id -> annotation)
20
20
  private var annotations: [String: MAPointAnnotation] = [:]
21
+ /// 标记点属性字典 (id -> props)
22
+ private var markerProps: [String: [String: Any]] = [:]
23
+ /// Circle 点击回调
24
+ var onCirclePress: (([String: Any]) -> Void)?
25
+ /// Circle ID 映射 (overlay -> id)
26
+ private var circleIdMap: [MACircle: String] = [:]
21
27
 
22
28
  /**
23
29
  * 初始化覆盖物管理器
@@ -27,6 +33,28 @@ class OverlayManager {
27
33
  self.mapView = mapView
28
34
  }
29
35
 
36
+ /**
37
+ * 检查点击位置是否在圆形内
38
+ */
39
+ func checkCirclePress(at coordinate: CLLocationCoordinate2D) -> Bool {
40
+ for (circle, circleId) in circleIdMap {
41
+ let circleCenter = circle.coordinate
42
+ let fromLocation = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
43
+ let toLocation = CLLocation(latitude: circleCenter.latitude, longitude: circleCenter.longitude)
44
+ let distance = fromLocation.distance(from: toLocation)
45
+
46
+ if distance <= circle.radius {
47
+ onCirclePress?([
48
+ "circleId": circleId,
49
+ "latitude": coordinate.latitude,
50
+ "longitude": coordinate.longitude
51
+ ])
52
+ return true
53
+ }
54
+ }
55
+ return false
56
+ }
57
+
30
58
  // MARK: - Circle 圆形
31
59
 
32
60
  /**
@@ -43,8 +71,9 @@ class OverlayManager {
43
71
 
44
72
  let circle = MACircle(center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), radius: radius)
45
73
  overlayStyles[id] = props
46
- mapView.add(circle!)
47
74
  overlays[id] = circle
75
+ circleIdMap[circle!] = id
76
+ mapView.add(circle!)
48
77
  }
49
78
 
50
79
  /**
@@ -52,10 +81,11 @@ class OverlayManager {
52
81
  * @param id 圆形唯一标识
53
82
  */
54
83
  func removeCircle(id: String) {
55
- guard let mapView = mapView, let circle = overlays[id] else { return }
84
+ guard let mapView = mapView, let circle = overlays[id] as? MACircle else { return }
56
85
  mapView.remove(circle)
57
86
  overlays.removeValue(forKey: id)
58
87
  overlayStyles.removeValue(forKey: id)
88
+ circleIdMap.removeValue(forKey: circle)
59
89
  }
60
90
 
61
91
  /**
@@ -84,9 +114,24 @@ class OverlayManager {
84
114
  let annotation = MAPointAnnotation()
85
115
  annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
86
116
  annotation.title = props["title"] as? String
87
- annotation.subtitle = props["description"] as? String
88
- mapView.addAnnotation(annotation)
117
+ annotation.subtitle = props["snippet"] as? String ?? props["description"] as? String
118
+
119
+ // 先保存 props 和 annotation,再添加到地图
120
+ // 这样 viewFor annotation 回调时就能找到 props
89
121
  annotations[id] = annotation
122
+ markerProps[id] = props
123
+
124
+ mapView.addAnnotation(annotation)
125
+ }
126
+
127
+ /**
128
+ * 根据 annotation 获取 marker 属性
129
+ * @param annotation 标记点对象
130
+ * @return 对应的属性字典
131
+ */
132
+ func getMarkerProps(for annotation: MAAnnotation) -> [String: Any]? {
133
+ guard let id = getMarkerId(for: annotation) else { return nil }
134
+ return markerProps[id]
90
135
  }
91
136
 
92
137
  /**
@@ -97,6 +142,7 @@ class OverlayManager {
97
142
  guard let mapView = mapView, let annotation = annotations[id] else { return }
98
143
  mapView.removeAnnotation(annotation)
99
144
  annotations.removeValue(forKey: id)
145
+ markerProps.removeValue(forKey: id)
100
146
  }
101
147
 
102
148
  /**
@@ -109,6 +155,15 @@ class OverlayManager {
109
155
  addMarker(id: id, props: props)
110
156
  }
111
157
 
158
+ /**
159
+ * 根据 annotation 获取 markerId
160
+ * @param annotation 标记点对象
161
+ * @return 对应的 markerId,如果未找到返回 nil
162
+ */
163
+ func getMarkerId(for annotation: MAAnnotation) -> String? {
164
+ return annotations.first(where: { $0.value === annotation })?.key
165
+ }
166
+
112
167
  // MARK: - Polyline 折线
113
168
 
114
169
  /**
@@ -178,8 +233,8 @@ class OverlayManager {
178
233
  guard !coordinates.isEmpty else { return }
179
234
  let polygon = MAPolygon(coordinates: &coordinates, count: UInt(coordinates.count))
180
235
  overlayStyles[id] = props
181
- mapView.add(polygon!)
182
236
  overlays[id] = polygon
237
+ mapView.add(polygon!)
183
238
  }
184
239
 
185
240
  /**
@@ -219,15 +274,12 @@ class OverlayManager {
219
274
  return nil
220
275
  }
221
276
 
222
- // 设置填充颜色
223
277
  if let fillColor = style?["fillColor"] {
224
278
  renderer.fillColor = ColorParser.parseColor(fillColor)
225
279
  }
226
- // 设置边框颜色
227
280
  if let strokeColor = style?["strokeColor"] {
228
281
  renderer.strokeColor = ColorParser.parseColor(strokeColor)
229
282
  }
230
- // 设置边框宽度
231
283
  if let strokeWidth = style?["strokeWidth"] as? Double {
232
284
  renderer.lineWidth = CGFloat(strokeWidth)
233
285
  }
@@ -236,13 +288,18 @@ class OverlayManager {
236
288
  } else if let polyline = overlay as? MAPolyline {
237
289
  let renderer = MAPolylineRenderer(polyline: polyline)!
238
290
 
291
+ print("🔷 OverlayManager.getRenderer(Polyline): style=\(String(describing: style))")
292
+
239
293
  // 设置线宽
240
294
  if let width = style?["width"] as? Double {
241
295
  renderer.lineWidth = CGFloat(width)
296
+ print("🔷 OverlayManager: width=\(width)")
242
297
  } else if let strokeWidth = style?["strokeWidth"] as? Double {
243
298
  renderer.lineWidth = CGFloat(strokeWidth)
299
+ print("🔷 OverlayManager: strokeWidth=\(strokeWidth)")
244
300
  } else {
245
301
  renderer.lineWidth = 8
302
+ print("🔷 OverlayManager: 使用默认 width=8")
246
303
  }
247
304
 
248
305
  // 设置线条样式
@@ -251,16 +308,20 @@ class OverlayManager {
251
308
 
252
309
  // 设置纹理或颜色
253
310
  if let textureUrl = style?["texture"] as? String, !textureUrl.isEmpty {
311
+ print("🔷 OverlayManager: 加载纹理 \(textureUrl)")
254
312
  loadPolylineTexture(url: textureUrl, renderer: renderer)
255
313
  } else {
256
314
  if let color = style?["color"] {
257
315
  let parsedColor = ColorParser.parseColor(color)
258
316
  renderer.strokeColor = parsedColor ?? .red
317
+ print("🔷 OverlayManager: color=\(color) -> \(String(describing: parsedColor))")
259
318
  } else if let strokeColor = style?["strokeColor"] {
260
319
  let parsedColor = ColorParser.parseColor(strokeColor)
261
320
  renderer.strokeColor = parsedColor ?? .red
321
+ print("🔷 OverlayManager: strokeColor=\(strokeColor) -> \(String(describing: parsedColor))")
262
322
  } else {
263
323
  renderer.strokeColor = .red
324
+ print("🔷 OverlayManager: 使用默认红色")
264
325
  }
265
326
  }
266
327
 
@@ -270,17 +331,24 @@ class OverlayManager {
270
331
  return nil
271
332
  }
272
333
 
334
+ print("🔶 OverlayManager.getRenderer(Polygon): style=\(String(describing: style))")
335
+
273
336
  // 设置填充颜色
274
337
  if let fillColor = style?["fillColor"] {
275
- renderer.fillColor = ColorParser.parseColor(fillColor)
338
+ let parsedColor = ColorParser.parseColor(fillColor)
339
+ renderer.fillColor = parsedColor
340
+ print("🔶 OverlayManager: fillColor=\(fillColor) -> \(String(describing: parsedColor))")
276
341
  }
277
342
  // 设置边框颜色
278
343
  if let strokeColor = style?["strokeColor"] {
279
- renderer.strokeColor = ColorParser.parseColor(strokeColor)
344
+ let parsedColor = ColorParser.parseColor(strokeColor)
345
+ renderer.strokeColor = parsedColor
346
+ print("🔶 OverlayManager: strokeColor=\(strokeColor) -> \(String(describing: parsedColor))")
280
347
  }
281
348
  // 设置边框宽度
282
349
  if let strokeWidth = style?["strokeWidth"] as? Double {
283
350
  renderer.lineWidth = CGFloat(strokeWidth)
351
+ print("🔶 OverlayManager: strokeWidth=\(strokeWidth)")
284
352
  }
285
353
 
286
354
  return renderer