expo-gaode-map-navigation 1.1.5-next.1 → 1.1.5-next.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 (136) hide show
  1. package/android/build.gradle +10 -0
  2. package/android/src/main/cpp/CMakeLists.txt +24 -0
  3. package/android/src/main/cpp/cluster_jni.cpp +848 -0
  4. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
  5. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
  6. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
  7. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
  8. package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
  9. package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
  10. package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
  11. package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
  12. package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
  13. package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
  14. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
  15. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
  16. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
  17. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
  18. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
  19. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
  20. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
  21. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
  22. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
  23. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
  24. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
  25. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
  26. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
  27. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
  28. package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
  29. package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
  30. package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
  31. package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
  32. package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
  33. package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
  34. package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
  35. package/build/ExpoGaodeMapNaviView.d.ts +7 -7
  36. package/build/ExpoGaodeMapNaviView.js +8 -8
  37. package/build/ExpoGaodeMapNavigationModule.d.ts +2 -1
  38. package/build/index.d.ts +35 -33
  39. package/build/index.js +70 -106
  40. package/build/map/ExpoGaodeMapModule.d.ts +2 -201
  41. package/build/map/ExpoGaodeMapModule.js +584 -14
  42. package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
  43. package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
  44. package/build/map/ExpoGaodeMapView.js +66 -58
  45. package/build/map/components/FoldableMapView.d.ts +38 -0
  46. package/build/map/components/FoldableMapView.js +209 -0
  47. package/build/map/components/MapContext.d.ts +12 -0
  48. package/build/map/components/MapContext.js +54 -0
  49. package/build/map/components/MapUI.d.ts +18 -0
  50. package/build/map/components/MapUI.js +29 -0
  51. package/build/map/components/overlays/Circle.js +34 -3
  52. package/build/map/components/overlays/Cluster.d.ts +3 -1
  53. package/build/map/components/overlays/Cluster.js +31 -2
  54. package/build/map/components/overlays/HeatMap.d.ts +3 -1
  55. package/build/map/components/overlays/HeatMap.js +33 -3
  56. package/build/map/components/overlays/Marker.d.ts +1 -1
  57. package/build/map/components/overlays/Marker.js +37 -32
  58. package/build/map/components/overlays/MultiPoint.js +1 -1
  59. package/build/map/components/overlays/Polygon.js +30 -3
  60. package/build/map/components/overlays/Polyline.js +36 -3
  61. package/build/map/index.d.ts +25 -5
  62. package/build/map/index.js +59 -18
  63. package/build/map/types/common.types.d.ts +40 -0
  64. package/build/map/types/common.types.js +0 -4
  65. package/build/map/types/index.d.ts +3 -2
  66. package/build/map/types/map-view.types.d.ts +108 -3
  67. package/build/map/types/native-module.types.d.ts +363 -0
  68. package/build/map/types/native-module.types.js +5 -0
  69. package/build/map/types/offline.types.d.ts +132 -0
  70. package/build/map/types/offline.types.js +5 -0
  71. package/build/map/types/overlays.types.d.ts +137 -24
  72. package/build/map/utils/ErrorHandler.d.ts +110 -0
  73. package/build/map/utils/ErrorHandler.js +421 -0
  74. package/build/map/utils/GeoUtils.d.ts +20 -0
  75. package/build/map/utils/GeoUtils.js +76 -0
  76. package/build/map/utils/OfflineMapManager.d.ts +148 -0
  77. package/build/map/utils/OfflineMapManager.js +217 -0
  78. package/build/map/utils/PermissionUtils.d.ts +91 -0
  79. package/build/map/utils/PermissionUtils.js +255 -0
  80. package/build/map/utils/PlatformDetector.d.ts +102 -0
  81. package/build/map/utils/PlatformDetector.js +186 -0
  82. package/build/types/index.d.ts +1 -0
  83. package/build/types/index.js +1 -0
  84. package/build/types/native-module.types.d.ts +69 -0
  85. package/build/types/native-module.types.js +2 -0
  86. package/build/types/naviview.types.d.ts +1 -1
  87. package/expo-module.config.json +12 -10
  88. package/ios/ExpoGaodeMapNavigation.podspec +9 -0
  89. package/ios/map/ExpoGaodeMapModule.swift +485 -75
  90. package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
  91. package/ios/map/ExpoGaodeMapView.swift +611 -62
  92. package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
  93. package/ios/map/MapPreloadManager.swift +348 -0
  94. package/ios/map/cpp/ClusterEngine.cpp +110 -0
  95. package/ios/map/cpp/ClusterEngine.hpp +20 -0
  96. package/ios/map/cpp/ColorParser.cpp +135 -0
  97. package/ios/map/cpp/ColorParser.hpp +14 -0
  98. package/ios/map/cpp/GeometryEngine.cpp +574 -0
  99. package/ios/map/cpp/GeometryEngine.hpp +159 -0
  100. package/ios/map/cpp/QuadTree.cpp +92 -0
  101. package/ios/map/cpp/QuadTree.hpp +42 -0
  102. package/ios/map/cpp/README.md +55 -0
  103. package/ios/map/cpp/tests/benchmark_js.js +41 -0
  104. package/ios/map/cpp/tests/run.sh +17 -0
  105. package/ios/map/cpp/tests/test_main.cpp +276 -0
  106. package/ios/map/managers/UIManager.swift +72 -1
  107. package/ios/map/modules/LocationManager.swift +114 -165
  108. package/ios/map/overlays/CircleView.swift +16 -32
  109. package/ios/map/overlays/CircleViewModule.swift +12 -12
  110. package/ios/map/overlays/ClusterAnnotation.swift +32 -0
  111. package/ios/map/overlays/ClusterView.swift +331 -45
  112. package/ios/map/overlays/ClusterViewModule.swift +20 -6
  113. package/ios/map/overlays/HeatMapView.swift +135 -32
  114. package/ios/map/overlays/HeatMapViewModule.swift +20 -8
  115. package/ios/map/overlays/MarkerView.swift +613 -130
  116. package/ios/map/overlays/MarkerViewModule.swift +38 -18
  117. package/ios/map/overlays/MultiPointView.swift +168 -10
  118. package/ios/map/overlays/MultiPointViewModule.swift +27 -5
  119. package/ios/map/overlays/PolygonView.swift +62 -23
  120. package/ios/map/overlays/PolygonViewModule.swift +18 -12
  121. package/ios/map/overlays/PolylineView.swift +21 -13
  122. package/ios/map/overlays/PolylineViewModule.swift +18 -12
  123. package/ios/map/utils/ClusterNative.h +96 -0
  124. package/ios/map/utils/ClusterNative.mm +377 -0
  125. package/ios/map/utils/ColorParser.swift +12 -1
  126. package/ios/map/utils/CppBridging.mm +13 -0
  127. package/ios/map/utils/GeometryUtils.swift +34 -0
  128. package/ios/map/utils/LatLngParser.swift +87 -0
  129. package/ios/map/utils/PermissionManager.swift +135 -6
  130. package/package.json +1 -1
  131. package/build/map/ExpoGaodeMap.types.d.ts +0 -41
  132. package/build/map/ExpoGaodeMap.types.js +0 -24
  133. package/build/map/utils/EventManager.d.ts +0 -10
  134. package/build/map/utils/EventManager.js +0 -26
  135. package/build/map/utils/ModuleLoader.d.ts +0 -73
  136. package/build/map/utils/ModuleLoader.js +0 -112
@@ -1,70 +1,90 @@
1
1
  import ExpoModulesCore
2
2
 
3
- public class NaviMarkerViewModule: Module {
3
+ public class MarkerViewModule: Module {
4
4
  public func definition() -> ModuleDefinition {
5
- Name("NaviMarkerView")
5
+ Name("MarkerView")
6
6
 
7
- View(NaviMarkerView.self) {
7
+ View(MarkerView.self) {
8
8
  // 🔑 声明专属事件(避免与其他组件冲突)
9
9
  Events("onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd")
10
10
 
11
11
  // 拆分 position 为两个独立属性以兼容 React Native 旧架构
12
- Prop("latitude") { (view: NaviMarkerView, lat: Double) in
12
+ Prop("latitude") { (view: MarkerView, lat: Double) in
13
13
  view.setLatitude(lat)
14
14
  }
15
15
 
16
- Prop("longitude") { (view: NaviMarkerView, lng: Double) in
16
+ Prop("longitude") { (view: MarkerView, lng: Double) in
17
17
  view.setLongitude(lng)
18
18
  }
19
19
 
20
- Prop("title") { (view: NaviMarkerView, title: String) in
20
+ Prop("title") { (view: MarkerView, title: String) in
21
21
  view.setTitle(title)
22
22
  }
23
23
 
24
- Prop("snippet") { (view: NaviMarkerView, snippet: String) in
24
+ Prop("snippet") { (view: MarkerView, snippet: String) in
25
25
  view.setDescription(snippet)
26
26
  }
27
27
 
28
- Prop("draggable") { (view: NaviMarkerView, draggable: Bool) in
28
+ Prop("draggable") { (view: MarkerView, draggable: Bool) in
29
29
  view.setDraggable(draggable)
30
30
  }
31
31
 
32
- Prop("icon") { (view: NaviMarkerView, source: String?) in
32
+ Prop("icon") { (view: MarkerView, source: String?) in
33
33
  view.setIconUri(source)
34
34
  }
35
35
 
36
- Prop("iconWidth") { (view: NaviMarkerView, width: Double) in
36
+ Prop("iconWidth") { (view: MarkerView, width: Double) in
37
37
  view.iconWidth = width
38
38
  }
39
39
 
40
- Prop("iconHeight") { (view: NaviMarkerView, height: Double) in
40
+ Prop("iconHeight") { (view: MarkerView, height: Double) in
41
41
  view.iconHeight = height
42
42
  }
43
43
 
44
- Prop("customViewWidth") { (view: NaviMarkerView, width: Double) in
44
+ Prop("customViewWidth") { (view: MarkerView, width: Double) in
45
45
  view.customViewWidth = width
46
46
  }
47
47
 
48
- Prop("customViewHeight") { (view: NaviMarkerView, height: Double) in
48
+ Prop("customViewHeight") { (view: MarkerView, height: Double) in
49
49
  view.customViewHeight = height
50
50
  }
51
51
 
52
- Prop("centerOffset") { (view: NaviMarkerView, offset: [String: Double]) in
52
+ Prop("centerOffset") { (view: MarkerView, offset: [String: Double]) in
53
53
  view.setCenterOffset(offset)
54
54
  }
55
55
 
56
- Prop("animatesDrop") { (view: NaviMarkerView, animate: Bool) in
56
+ Prop("animatesDrop") { (view: MarkerView, animate: Bool) in
57
57
  view.setAnimatesDrop(animate)
58
58
  }
59
59
 
60
- Prop("pinColor") { (view: NaviMarkerView, color: String) in
60
+ Prop("pinColor") { (view: MarkerView, color: String) in
61
61
  view.setPinColor(color)
62
62
  }
63
63
 
64
- Prop("canShowCallout") { (view: NaviMarkerView, show: Bool) in
65
- view.setCanShowCallout(show)
64
+ Prop("canShowCallout") { (view: MarkerView, canShow: Bool) in
65
+ view.canShowCallout = canShow
66
+ }
67
+
68
+ Prop("growAnimation") { (view: MarkerView, enabled: Bool) in
69
+ view.growAnimation = enabled
70
+ }
71
+ Prop("cacheKey") { (view: MarkerView, key: String) in
72
+ view.setCacheKey(key)
73
+ }
74
+
75
+ Prop("position") { (view: MarkerView, position: [String: Double]?) in
76
+ view.setPosition(position)
77
+ }
78
+
79
+ // 平滑移动路径
80
+ Prop("smoothMovePath") { (view: MarkerView, path: [[String: Double]]) in
81
+ view.setSmoothMovePath(path)
66
82
  }
67
83
 
84
+ // 平滑移动时长(秒)
85
+ Prop("smoothMoveDuration") { (view: MarkerView, duration: Double) in
86
+ view.setSmoothMoveDuration(duration)
87
+ }
68
88
  }
69
89
  }
70
90
  }
@@ -1,11 +1,20 @@
1
1
  import ExpoModulesCore
2
2
  import AMapNaviKit
3
+ import UIKit
3
4
 
4
- class NaviMultiPointView: ExpoView {
5
- var points: [[String: Any]] = []
5
+ class MultiPointView: ExpoView {
6
+ let onMultiPointPress = EventDispatcher()
7
+
8
+ var pointsData: [[String: Any]] = []
9
+ var iconUri: String?
10
+ var iconWidth: Double?
11
+ var iconHeight: Double?
12
+ var anchorX: Double = 0.5
13
+ var anchorY: Double = 0.5
6
14
 
7
15
  private var mapView: MAMapView?
8
16
  private var multiPointOverlay: MAMultiPointOverlay?
17
+ private var renderer: MAMultiPointOverlayRenderer?
9
18
 
10
19
  required init(appContext: AppContext? = nil) {
11
20
  super.init(appContext: appContext)
@@ -17,10 +26,31 @@ class NaviMultiPointView: ExpoView {
17
26
  }
18
27
 
19
28
  func setPoints(_ points: [[String: Any]]) {
20
- self.points = points
29
+ self.pointsData = points
21
30
  updateMultiPoint()
22
31
  }
23
32
 
33
+ func setIcon(_ iconUri: String?) {
34
+ self.iconUri = iconUri
35
+ updateIcon()
36
+ }
37
+
38
+ func setIconWidth(_ width: Double?) {
39
+ self.iconWidth = width
40
+ updateIcon()
41
+ }
42
+
43
+ func setIconHeight(_ height: Double?) {
44
+ self.iconHeight = height
45
+ updateIcon()
46
+ }
47
+
48
+ func setAnchor(x: Double, y: Double) {
49
+ self.anchorX = x
50
+ self.anchorY = y
51
+ renderer?.anchor = CGPoint(x: x, y: y)
52
+ }
53
+
24
54
  private func updateMultiPoint() {
25
55
  guard let mapView = mapView else { return }
26
56
 
@@ -28,30 +58,158 @@ class NaviMultiPointView: ExpoView {
28
58
  if let oldOverlay = multiPointOverlay {
29
59
  mapView.remove(oldOverlay)
30
60
  multiPointOverlay = nil
61
+ renderer = nil
31
62
  }
32
63
 
33
64
  // 验证数据有效性
34
- guard !points.isEmpty else { return }
65
+ guard !pointsData.isEmpty else { return }
35
66
 
36
67
  var items: [MAMultiPointItem] = []
37
- for point in points {
38
- guard let latitude = point["latitude"] as? Double,
39
- let longitude = point["longitude"] as? Double else {
68
+ for point in pointsData {
69
+ guard let coordinate = LatLngParser.parseLatLng(point) else {
40
70
  continue
41
71
  }
42
72
 
43
73
  let item = MAMultiPointItem()
44
- item.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
74
+ item.coordinate = coordinate
75
+
76
+ // 如果是 Map,尝试获取 ID
77
+ if let pointDict = point as? [String: Any] {
78
+ if let customerId = pointDict["customerId"] as? String {
79
+ item.customID = customerId
80
+ } else if let id = pointDict["id"] as? String {
81
+ item.customID = id
82
+ }
83
+ }
84
+
45
85
  items.append(item)
46
86
  }
47
87
 
48
88
  guard !items.isEmpty else { return }
49
89
 
50
90
  let overlay = MAMultiPointOverlay(multiPointItems: items)
91
+ self.multiPointOverlay = overlay
51
92
  mapView.add(overlay)
52
- multiPointOverlay = overlay
53
93
  }
54
94
 
95
+ func getRenderer() -> MAMultiPointOverlayRenderer? {
96
+ guard let overlay = multiPointOverlay else { return nil }
97
+
98
+ if renderer == nil {
99
+ renderer = MAMultiPointOverlayRenderer(multiPointOverlay: overlay)
100
+ renderer?.anchor = CGPoint(x: anchorX, y: anchorY)
101
+ updateIcon()
102
+ }
103
+ return renderer
104
+ }
105
+
106
+ private func updateIcon() {
107
+ guard let iconUri = iconUri else { return }
108
+
109
+ // 构建缓存 key
110
+ let w = Int(iconWidth ?? 0)
111
+ let h = Int(iconHeight ?? 0)
112
+ let key = "multipoint|\(iconUri)|\(w)x\(h)"
113
+
114
+ // 1. 尝试从缓存获取
115
+ if let cached = IconBitmapCache.shared.image(forKey: key) {
116
+ self.renderer?.icon = cached
117
+ refreshOverlay()
118
+ return
119
+ }
120
+
121
+ loadIcon(iconUri: iconUri) { [weak self] image in
122
+ guard let self = self, let image = image else { return }
123
+
124
+ var finalImage = image
125
+ if let w = self.iconWidth, let h = self.iconHeight {
126
+ finalImage = self.resizeImage(image: image, targetSize: CGSize(width: w, height: h))
127
+ } else if let w = self.iconWidth {
128
+ let h = image.size.height * (w / image.size.width)
129
+ finalImage = self.resizeImage(image: image, targetSize: CGSize(width: w, height: h))
130
+ } else if let h = self.iconHeight {
131
+ let w = image.size.width * (h / image.size.height)
132
+ finalImage = self.resizeImage(image: image, targetSize: CGSize(width: w, height: h))
133
+ }
134
+
135
+ // 写入缓存
136
+ IconBitmapCache.shared.setImage(finalImage, forKey: key)
137
+
138
+ self.renderer?.icon = finalImage
139
+ self.refreshOverlay()
140
+ }
141
+ }
142
+
143
+ private func refreshOverlay() {
144
+ self.renderer?.setNeedsUpdate()
145
+ // 强制刷新:通过重新添加 overlay 触发更新
146
+ if let mapView = self.mapView, let overlay = self.multiPointOverlay {
147
+ mapView.remove(overlay)
148
+ mapView.add(overlay)
149
+ }
150
+ }
151
+
152
+ private func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
153
+ UIGraphicsBeginImageContextWithOptions(targetSize, false, 0.0)
154
+ image.draw(in: CGRect(origin: .zero, size: targetSize))
155
+ let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
156
+ UIGraphicsEndImageContext()
157
+ return resizedImage ?? image
158
+ }
159
+
160
+ private func loadIcon(iconUri: String, completion: @escaping (UIImage?) -> Void) {
161
+ if iconUri.hasPrefix("http://") || iconUri.hasPrefix("https://") {
162
+ guard let url = URL(string: iconUri) else {
163
+ completion(nil)
164
+ return
165
+ }
166
+ URLSession.shared.dataTask(with: url) { data, _, _ in
167
+ guard let data = data, let image = UIImage(data: data) else {
168
+ DispatchQueue.main.async { completion(nil) }
169
+ return
170
+ }
171
+ DispatchQueue.main.async { completion(image) }
172
+ }.resume()
173
+ } else if iconUri.hasPrefix("file://") {
174
+ let path = String(iconUri.dropFirst(7))
175
+ completion(UIImage(contentsOfFile: path))
176
+ } else {
177
+ completion(UIImage(named: iconUri))
178
+ }
179
+ }
180
+
181
+ func handleMultiPointClick(item: MAMultiPointItem) {
182
+ // 查找对应的 point 数据
183
+ var index = -1
184
+ var pointData: [String: Any]?
185
+
186
+ // 优先通过 customID 查找
187
+ if let customID = item.customID {
188
+ index = pointsData.firstIndex { point in
189
+ return (point["customerId"] as? String) == customID || (point["id"] as? String) == customID
190
+ } ?? -1
191
+ }
192
+
193
+ // 如果没找到,尝试通过坐标查找(不够精确,但作为备选)
194
+ if index == -1 {
195
+ index = pointsData.firstIndex { point in
196
+ guard let lat = point["latitude"] as? Double,
197
+ let lng = point["longitude"] as? Double else { return false }
198
+ return abs(lat - item.coordinate.latitude) < 0.000001 && abs(lng - item.coordinate.longitude) < 0.000001
199
+ } ?? -1
200
+ }
201
+
202
+ if index != -1 {
203
+ pointData = pointsData[index]
204
+ onMultiPointPress([
205
+ "index": index,
206
+ "customerId": pointData?["customerId"] ?? pointData?["id"] ?? "",
207
+ "latitude": item.coordinate.latitude,
208
+ "longitude": item.coordinate.longitude
209
+ ])
210
+ }
211
+ }
212
+
55
213
  /**
56
214
  * 移除多点覆盖物
57
215
  */
@@ -76,4 +234,4 @@ class NaviMultiPointView: ExpoView {
76
234
  removeMultiPoint()
77
235
  mapView = nil
78
236
  }
79
- }
237
+ }
@@ -1,12 +1,34 @@
1
1
  import ExpoModulesCore
2
2
 
3
- public class NaviMultiPointViewModule: Module {
3
+ public class MultiPointViewModule: Module {
4
4
  public func definition() -> ModuleDefinition {
5
- Name("NaviMultiPointView")
5
+ Name("MultiPointView")
6
6
 
7
- View(NaviMultiPointView.self) {
8
- Prop("points") { (view: NaviMultiPointView, points: [[String: Any]]) in
9
- view.setPoints(points)
7
+ View(MultiPointView.self) {
8
+ Events("onMultiPointPress")
9
+
10
+ Prop("points") { (view: MultiPointView, points: [[String: Any]]) in
11
+ view.setPoints(points)
12
+ }
13
+
14
+ Prop("icon") { (view: MultiPointView, icon: String?) in
15
+ view.setIcon(icon)
16
+ }
17
+
18
+ Prop("iconWidth") { (view: MultiPointView, width: Double?) in
19
+ view.setIconWidth(width)
20
+ }
21
+
22
+ Prop("iconHeight") { (view: MultiPointView, height: Double?) in
23
+ view.setIconHeight(height)
24
+ }
25
+
26
+ Prop("anchor") { (view: MultiPointView, anchor: [String: Double]?) in
27
+ if let anchor = anchor {
28
+ let x = anchor["x"] ?? 0.5
29
+ let y = anchor["y"] ?? 0.5
30
+ view.setAnchor(x: x, y: y)
31
+ }
10
32
  }
11
33
  }
12
34
  }
@@ -1,5 +1,6 @@
1
1
  import ExpoModulesCore
2
2
  import AMapNaviKit
3
+ import CoreLocation
3
4
 
4
5
  /**
5
6
  * 多边形覆盖物视图
@@ -9,17 +10,22 @@ import AMapNaviKit
9
10
  * - 管理多边形样式(填充色、边框色、边框宽度)
10
11
  * - 响应属性变化并更新渲染
11
12
  */
12
- class NaviPolygonView: ExpoView {
13
+ class PolygonView: ExpoView {
13
14
  let onPolygonPress = EventDispatcher()
14
15
 
15
16
  /// 多边形点数组
16
- var points: [[String: Double]] = []
17
+ var points: [Any] = []
17
18
  /// 填充颜色
18
- var fillColor: Any?
19
+ var fillColor: String?
19
20
  /// 边框颜色
20
- var strokeColor: Any?
21
+ var strokeColor: String?
21
22
  /// 边框宽度
22
23
  var strokeWidth: Float = 0
24
+ /// 简化容差 (米)
25
+ var simplificationTolerance: Double = 0.0
26
+
27
+ /// 简化完成事件派发器
28
+ let onPolygonSimplified = EventDispatcher()
23
29
 
24
30
  /// 地图视图引用
25
31
  private var mapView: MAMapView?
@@ -63,11 +69,7 @@ class NaviPolygonView: ExpoView {
63
69
  * @param map 地图视图
64
70
  */
65
71
  func setMap(_ map: MAMapView) {
66
- let isNewMap = self.mapView == nil
67
72
  self.mapView = map
68
-
69
- // 无论是否是新地图,都调用 updatePolygon
70
- // 这确保了即使在 setMap 之前设置了 props,覆盖物也能被正确创建
71
73
  updatePolygon()
72
74
  }
73
75
 
@@ -78,22 +80,51 @@ class NaviPolygonView: ExpoView {
78
80
  guard let mapView = mapView else { return }
79
81
  if let old = polygon { mapView.remove(old) }
80
82
 
81
- // 🔑 坐标验证和过滤
82
- var coords = points.compactMap { point -> CLLocationCoordinate2D? in
83
- guard let lat = point["latitude"],
84
- let lng = point["longitude"],
85
- lat >= -90 && lat <= 90,
86
- lng >= -180 && lng <= 180 else {
87
- return nil
88
- }
89
- return CLLocationCoordinate2D(latitude: lat, longitude: lng)
83
+ // 🔑 使用支持嵌套列表的坐标解析器
84
+ let nestedCoords = LatLngParser.parseLatLngListList(points)
85
+ guard !nestedCoords.isEmpty else { return }
86
+
87
+ // 第一项是外轮廓
88
+ var outerCoords = nestedCoords[0]
89
+
90
+ // 🔑 坐标简化 (如果设置了容差)
91
+ if simplificationTolerance > 0 {
92
+ let originalCount = outerCoords.count
93
+ outerCoords = GeometryUtils.simplifyPolyline(outerCoords, tolerance: simplificationTolerance)
94
+
95
+ // 派发简化事件
96
+ onPolygonSimplified([
97
+ "originalCount": originalCount,
98
+ "simplifiedCount": outerCoords.count
99
+ ])
90
100
  }
91
101
 
92
102
  // 🔑 至少需要3个点才能绘制多边形
93
- guard coords.count >= 3 else { return }
103
+ guard outerCoords.count >= 3 else { return }
94
104
 
95
- polygon = MAPolygon(coordinates: &coords, count: UInt(coords.count))
96
- mapView.add(polygon!)
105
+ // 处理内孔 (hollowShapes)
106
+ var hollowShapes: [MAOverlay] = []
107
+ if nestedCoords.count > 1 {
108
+ for i in 1..<nestedCoords.count {
109
+ var ring = nestedCoords[i]
110
+ if ring.count >= 3 {
111
+ if let hole = MAPolygon(coordinates: &ring, count: UInt(ring.count)) {
112
+ hollowShapes.append(hole)
113
+ }
114
+ }
115
+ }
116
+ }
117
+
118
+ // 创建主多边形
119
+ if let mainPolygon = MAPolygon(coordinates: &outerCoords, count: UInt(outerCoords.count)) {
120
+ // 如果有内孔,设置 hollowShapes 属性
121
+ if !hollowShapes.isEmpty {
122
+ mainPolygon.hollowShapes = hollowShapes
123
+ }
124
+
125
+ self.polygon = mainPolygon
126
+ mapView.add(mainPolygon)
127
+ }
97
128
 
98
129
  renderer = nil
99
130
  }
@@ -118,7 +149,7 @@ class NaviPolygonView: ExpoView {
118
149
  * 设置多边形点数组
119
150
  * @param points 点数组
120
151
  */
121
- func setPoints(_ points: [[String: Double]]) {
152
+ func setPoints(_ points: [Any]) {
122
153
  self.points = points
123
154
  updatePolygon()
124
155
  }
@@ -127,7 +158,7 @@ class NaviPolygonView: ExpoView {
127
158
  * 设置填充颜色
128
159
  * @param color 颜色值
129
160
  */
130
- func setFillColor(_ color: Any?) {
161
+ func setFillColor(_ color: String?) {
131
162
  fillColor = color
132
163
  renderer = nil
133
164
  updatePolygon()
@@ -137,7 +168,7 @@ class NaviPolygonView: ExpoView {
137
168
  * 设置边框颜色
138
169
  * @param color 颜色值
139
170
  */
140
- func setStrokeColor(_ color: Any?) {
171
+ func setStrokeColor(_ color: String?) {
141
172
  strokeColor = color
142
173
  renderer = nil
143
174
  updatePolygon()
@@ -152,6 +183,14 @@ class NaviPolygonView: ExpoView {
152
183
  renderer = nil
153
184
  updatePolygon()
154
185
  }
186
+
187
+ /**
188
+ * 设置简化容差
189
+ */
190
+ func setSimplificationTolerance(_ tolerance: Double) {
191
+ simplificationTolerance = tolerance
192
+ updatePolygon()
193
+ }
155
194
 
156
195
  /**
157
196
  * 视图即将从父视图移除时调用
@@ -1,33 +1,39 @@
1
1
  import ExpoModulesCore
2
2
 
3
- public class NaviPolygonViewModule: Module {
3
+ public class PolygonViewModule: Module {
4
4
  public func definition() -> ModuleDefinition {
5
- Name("NaviPolygonView")
5
+ Name("PolygonView")
6
6
 
7
- View(NaviPolygonView.self) {
8
- Events("onPolygonPress")
7
+ View(PolygonView.self) {
8
+ Events("onPolygonPress", "onPolygonSimplified")
9
9
 
10
- Prop("points") { (view: NaviPolygonView, points: [[String: Double]]) in
11
- view.setPoints(points)
12
- }
10
+ Prop("points") { (view: PolygonView, points: [Any]) in
11
+ view.setPoints(points)
12
+ }
13
13
 
14
- Prop("fillColor") { (view: NaviPolygonView, color: String) in
14
+ Prop("fillColor") { (view: PolygonView, color: String?) in
15
15
  view.setFillColor(color)
16
16
  }
17
17
 
18
- Prop("strokeColor") { (view: NaviPolygonView, color: String) in
18
+ Prop("strokeColor") { (view: PolygonView, color: String?) in
19
19
  view.setStrokeColor(color)
20
20
  }
21
21
 
22
- Prop("strokeWidth") { (view: NaviPolygonView, width: Double) in
22
+ Prop("strokeWidth") { (view: PolygonView, width: Double) in
23
23
  view.setStrokeWidth(Float(width))
24
24
  }
25
+
26
+ Prop("simplificationTolerance") { (view: PolygonView, tolerance: Double) in
27
+ view.setSimplificationTolerance(tolerance)
28
+ }
25
29
 
26
- OnViewDidUpdateProps { (view: NaviPolygonView) in
30
+ OnViewDidUpdateProps { (view: PolygonView) in
31
+ // 属性更新完成后,如果还没连接地图,尝试连接
27
32
  if !view.isMapConnected() {
33
+ // 查找父视图 ExpoGaodeMapView
28
34
  var parent = view.superview
29
35
  while parent != nil {
30
- if let mapView = parent as? NaviMapView {
36
+ if let mapView = parent as? ExpoGaodeMapView {
31
37
  view.setMap(mapView.mapView)
32
38
  return
33
39
  }
@@ -1,5 +1,6 @@
1
1
  import ExpoModulesCore
2
2
  import AMapNaviKit
3
+ import CoreLocation
3
4
 
4
5
  /**
5
6
  * 折线覆盖物视图
@@ -9,17 +10,19 @@ import AMapNaviKit
9
10
  * - 支持纹理贴图(仅 3D 地图支持)
10
11
  * - 管理折线样式(线宽、颜色)
11
12
  */
12
- class NaviPolylineView: ExpoView {
13
+ class PolylineView: ExpoView {
13
14
  /// 折线点数组
14
15
  var points: [[String: Double]] = []
15
16
  /// 线宽
16
17
  var strokeWidth: Float = 0
17
18
  /// 线条颜色
18
- var strokeColor: Any?
19
+ var strokeColor: String?
19
20
  /// 是否虚线
20
21
  var isDotted: Bool = false
21
22
  /// 纹理图片 URL
22
23
  var textureUrl: String?
24
+ /// 简化容差 (米)
25
+ var simplificationTolerance: Double = 0.0
23
26
 
24
27
  /// 点击事件派发器
25
28
  let onPolylinePress = EventDispatcher()
@@ -76,6 +79,14 @@ class NaviPolylineView: ExpoView {
76
79
  updatePolyline()
77
80
  }
78
81
 
82
+ /**
83
+ * 设置简化容差
84
+ */
85
+ func setSimplificationTolerance(_ tolerance: Double) {
86
+ simplificationTolerance = tolerance
87
+ updatePolyline()
88
+ }
89
+
79
90
  /**
80
91
  * 更新折线覆盖物
81
92
  */
@@ -83,15 +94,12 @@ class NaviPolylineView: ExpoView {
83
94
  guard let mapView = mapView else { return }
84
95
  if let old = polyline { mapView.remove(old) }
85
96
 
86
- // 🔑 坐标验证和过滤
87
- var coords = points.compactMap { point -> CLLocationCoordinate2D? in
88
- guard let lat = point["latitude"],
89
- let lng = point["longitude"],
90
- lat >= -90 && lat <= 90,
91
- lng >= -180 && lng <= 180 else {
92
- return nil
93
- }
94
- return CLLocationCoordinate2D(latitude: lat, longitude: lng)
97
+ // 🔑 使用统一的坐标解析器
98
+ var coords = LatLngParser.parseLatLngList(points)
99
+
100
+ // 🔑 坐标简化 (如果设置了容差)
101
+ if simplificationTolerance > 0 && coords.count > 2 {
102
+ coords = GeometryUtils.simplifyPolyline(coords, tolerance: simplificationTolerance)
95
103
  }
96
104
 
97
105
  // 🔑 至少需要2个点才能绘制折线
@@ -133,7 +141,7 @@ class NaviPolylineView: ExpoView {
133
141
  return
134
142
  }
135
143
  URLSession.shared.dataTask(with: imageUrl) { [weak self] data, _, error in
136
- if let error = error {
144
+ if error != nil {
137
145
  return
138
146
  }
139
147
  guard let data = data, let image = UIImage(data: data) else {
@@ -195,7 +203,7 @@ class NaviPolylineView: ExpoView {
195
203
  * 设置线条颜色
196
204
  * @param color 颜色值
197
205
  */
198
- func setStrokeColor(_ color: Any?) {
206
+ func setStrokeColor(_ color: String?) {
199
207
  strokeColor = color
200
208
  renderer = nil
201
209
  forceRerender()