expo-gaode-map-navigation 1.1.5 → 1.1.6
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.
- package/README.md +213 -73
- package/android/build.gradle +10 -0
- package/android/src/main/cpp/CMakeLists.txt +24 -0
- package/android/src/main/cpp/cluster_jni.cpp +848 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
- package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
- package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
- package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
- package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
- package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
- package/build/ExpoGaodeMapNaviView.d.ts +7 -7
- package/build/ExpoGaodeMapNaviView.js +10 -11
- package/build/ExpoGaodeMapNavigationModule.d.ts +2 -1
- package/build/index.d.ts +35 -33
- package/build/index.js +70 -106
- package/build/map/ExpoGaodeMapModule.d.ts +2 -201
- package/build/map/ExpoGaodeMapModule.js +586 -18
- package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
- package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
- package/build/map/ExpoGaodeMapView.js +66 -58
- package/build/map/components/FoldableMapView.d.ts +38 -0
- package/build/map/components/FoldableMapView.js +209 -0
- package/build/map/components/MapContext.d.ts +12 -0
- package/build/map/components/MapContext.js +54 -0
- package/build/map/components/MapUI.d.ts +18 -0
- package/build/map/components/MapUI.js +29 -0
- package/build/map/components/overlays/Circle.js +34 -3
- package/build/map/components/overlays/Cluster.d.ts +3 -1
- package/build/map/components/overlays/Cluster.js +31 -2
- package/build/map/components/overlays/HeatMap.d.ts +3 -1
- package/build/map/components/overlays/HeatMap.js +33 -3
- package/build/map/components/overlays/Marker.d.ts +1 -1
- package/build/map/components/overlays/Marker.js +37 -32
- package/build/map/components/overlays/MultiPoint.js +1 -1
- package/build/map/components/overlays/Polygon.js +30 -3
- package/build/map/components/overlays/Polyline.js +36 -3
- package/build/map/index.d.ts +25 -5
- package/build/map/index.js +59 -18
- package/build/map/types/common.types.d.ts +40 -0
- package/build/map/types/common.types.js +0 -4
- package/build/map/types/index.d.ts +3 -2
- package/build/map/types/map-view.types.d.ts +108 -3
- package/build/map/types/native-module.types.d.ts +363 -0
- package/build/map/types/native-module.types.js +5 -0
- package/build/map/types/offline.types.d.ts +132 -0
- package/build/map/types/offline.types.js +5 -0
- package/build/map/types/overlays.types.d.ts +137 -24
- package/build/map/utils/ErrorHandler.d.ts +110 -0
- package/build/map/utils/ErrorHandler.js +421 -0
- package/build/map/utils/GeoUtils.d.ts +20 -0
- package/build/map/utils/GeoUtils.js +76 -0
- package/build/map/utils/OfflineMapManager.d.ts +148 -0
- package/build/map/utils/OfflineMapManager.js +217 -0
- package/build/map/utils/PermissionUtils.d.ts +91 -0
- package/build/map/utils/PermissionUtils.js +255 -0
- package/build/map/utils/PlatformDetector.d.ts +102 -0
- package/build/map/utils/PlatformDetector.js +186 -0
- package/build/types/index.d.ts +1 -0
- package/build/types/index.js +1 -0
- package/build/types/native-module.types.d.ts +69 -0
- package/build/types/native-module.types.js +2 -0
- package/build/types/naviview.types.d.ts +1 -1
- package/expo-module.config.json +12 -10
- package/ios/ExpoGaodeMapNavigation.podspec +9 -0
- package/ios/map/ExpoGaodeMapModule.swift +485 -75
- package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
- package/ios/map/ExpoGaodeMapView.swift +611 -62
- package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
- package/ios/map/MapPreloadManager.swift +348 -0
- package/ios/map/cpp/ClusterEngine.cpp +110 -0
- package/ios/map/cpp/ClusterEngine.hpp +20 -0
- package/ios/map/cpp/ColorParser.cpp +135 -0
- package/ios/map/cpp/ColorParser.hpp +14 -0
- package/ios/map/cpp/GeometryEngine.cpp +574 -0
- package/ios/map/cpp/GeometryEngine.hpp +159 -0
- package/ios/map/cpp/QuadTree.cpp +92 -0
- package/ios/map/cpp/QuadTree.hpp +42 -0
- package/ios/map/cpp/README.md +55 -0
- package/ios/map/managers/UIManager.swift +72 -1
- package/ios/map/modules/LocationManager.swift +123 -166
- package/ios/map/overlays/CircleView.swift +16 -32
- package/ios/map/overlays/CircleViewModule.swift +12 -12
- package/ios/map/overlays/ClusterAnnotation.swift +32 -0
- package/ios/map/overlays/ClusterView.swift +331 -45
- package/ios/map/overlays/ClusterViewModule.swift +20 -6
- package/ios/map/overlays/HeatMapView.swift +135 -32
- package/ios/map/overlays/HeatMapViewModule.swift +20 -8
- package/ios/map/overlays/MarkerView.swift +613 -130
- package/ios/map/overlays/MarkerViewModule.swift +38 -18
- package/ios/map/overlays/MultiPointView.swift +168 -10
- package/ios/map/overlays/MultiPointViewModule.swift +27 -5
- package/ios/map/overlays/PolygonView.swift +62 -23
- package/ios/map/overlays/PolygonViewModule.swift +18 -12
- package/ios/map/overlays/PolylineView.swift +21 -13
- package/ios/map/overlays/PolylineViewModule.swift +18 -12
- package/ios/map/utils/ClusterNative.h +96 -0
- package/ios/map/utils/ClusterNative.mm +377 -0
- package/ios/map/utils/ColorParser.swift +12 -1
- package/ios/map/utils/CppBridging.mm +13 -0
- package/ios/map/utils/GeometryUtils.swift +34 -0
- package/ios/map/utils/LatLngParser.swift +87 -0
- package/ios/map/utils/PermissionManager.swift +135 -6
- package/package.json +3 -2
- package/shared/cpp/ClusterEngine.cpp +110 -0
- package/shared/cpp/ClusterEngine.hpp +20 -0
- package/shared/cpp/ColorParser.cpp +135 -0
- package/shared/cpp/ColorParser.hpp +14 -0
- package/shared/cpp/GeometryEngine.cpp +574 -0
- package/shared/cpp/GeometryEngine.hpp +159 -0
- package/shared/cpp/QuadTree.cpp +92 -0
- package/shared/cpp/QuadTree.hpp +42 -0
- package/shared/cpp/README.md +55 -0
- package/shared/cpp/tests/benchmark_js.js +41 -0
- package/shared/cpp/tests/run.sh +17 -0
- package/shared/cpp/tests/test_main.cpp +276 -0
- package/build/map/ExpoGaodeMap.types.d.ts +0 -41
- package/build/map/ExpoGaodeMap.types.js +0 -24
- package/build/map/utils/EventManager.d.ts +0 -10
- package/build/map/utils/EventManager.js +0 -26
- package/build/map/utils/ModuleLoader.d.ts +0 -73
- package/build/map/utils/ModuleLoader.js +0 -112
|
@@ -1,70 +1,90 @@
|
|
|
1
1
|
import ExpoModulesCore
|
|
2
2
|
|
|
3
|
-
public class
|
|
3
|
+
public class MarkerViewModule: Module {
|
|
4
4
|
public func definition() -> ModuleDefinition {
|
|
5
|
-
Name("
|
|
5
|
+
Name("MarkerView")
|
|
6
6
|
|
|
7
|
-
View(
|
|
7
|
+
View(MarkerView.self) {
|
|
8
8
|
// 🔑 声明专属事件(避免与其他组件冲突)
|
|
9
9
|
Events("onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd")
|
|
10
10
|
|
|
11
11
|
// 拆分 position 为两个独立属性以兼容 React Native 旧架构
|
|
12
|
-
Prop("latitude") { (view:
|
|
12
|
+
Prop("latitude") { (view: MarkerView, lat: Double) in
|
|
13
13
|
view.setLatitude(lat)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
Prop("longitude") { (view:
|
|
16
|
+
Prop("longitude") { (view: MarkerView, lng: Double) in
|
|
17
17
|
view.setLongitude(lng)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
Prop("title") { (view:
|
|
20
|
+
Prop("title") { (view: MarkerView, title: String) in
|
|
21
21
|
view.setTitle(title)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
Prop("snippet") { (view:
|
|
24
|
+
Prop("snippet") { (view: MarkerView, snippet: String) in
|
|
25
25
|
view.setDescription(snippet)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
Prop("draggable") { (view:
|
|
28
|
+
Prop("draggable") { (view: MarkerView, draggable: Bool) in
|
|
29
29
|
view.setDraggable(draggable)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
Prop("icon") { (view:
|
|
32
|
+
Prop("icon") { (view: MarkerView, source: String?) in
|
|
33
33
|
view.setIconUri(source)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
Prop("iconWidth") { (view:
|
|
36
|
+
Prop("iconWidth") { (view: MarkerView, width: Double) in
|
|
37
37
|
view.iconWidth = width
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
Prop("iconHeight") { (view:
|
|
40
|
+
Prop("iconHeight") { (view: MarkerView, height: Double) in
|
|
41
41
|
view.iconHeight = height
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
Prop("customViewWidth") { (view:
|
|
44
|
+
Prop("customViewWidth") { (view: MarkerView, width: Double) in
|
|
45
45
|
view.customViewWidth = width
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
Prop("customViewHeight") { (view:
|
|
48
|
+
Prop("customViewHeight") { (view: MarkerView, height: Double) in
|
|
49
49
|
view.customViewHeight = height
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
Prop("centerOffset") { (view:
|
|
52
|
+
Prop("centerOffset") { (view: MarkerView, offset: [String: Double]) in
|
|
53
53
|
view.setCenterOffset(offset)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
Prop("animatesDrop") { (view:
|
|
56
|
+
Prop("animatesDrop") { (view: MarkerView, animate: Bool) in
|
|
57
57
|
view.setAnimatesDrop(animate)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
Prop("pinColor") { (view:
|
|
60
|
+
Prop("pinColor") { (view: MarkerView, color: String) in
|
|
61
61
|
view.setPinColor(color)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
Prop("canShowCallout") { (view:
|
|
65
|
-
view.
|
|
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
|
|
5
|
-
|
|
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.
|
|
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 !
|
|
65
|
+
guard !pointsData.isEmpty else { return }
|
|
35
66
|
|
|
36
67
|
var items: [MAMultiPointItem] = []
|
|
37
|
-
for point in
|
|
38
|
-
guard let
|
|
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 =
|
|
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
|
|
3
|
+
public class MultiPointViewModule: Module {
|
|
4
4
|
public func definition() -> ModuleDefinition {
|
|
5
|
-
Name("
|
|
5
|
+
Name("MultiPointView")
|
|
6
6
|
|
|
7
|
-
View(
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
13
|
+
class PolygonView: ExpoView {
|
|
13
14
|
let onPolygonPress = EventDispatcher()
|
|
14
15
|
|
|
15
16
|
/// 多边形点数组
|
|
16
|
-
var points: [
|
|
17
|
+
var points: [Any] = []
|
|
17
18
|
/// 填充颜色
|
|
18
|
-
var fillColor:
|
|
19
|
+
var fillColor: String?
|
|
19
20
|
/// 边框颜色
|
|
20
|
-
var strokeColor:
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
103
|
+
guard outerCoords.count >= 3 else { return }
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
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: [
|
|
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:
|
|
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:
|
|
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
|
|
3
|
+
public class PolygonViewModule: Module {
|
|
4
4
|
public func definition() -> ModuleDefinition {
|
|
5
|
-
Name("
|
|
5
|
+
Name("PolygonView")
|
|
6
6
|
|
|
7
|
-
View(
|
|
8
|
-
Events("onPolygonPress")
|
|
7
|
+
View(PolygonView.self) {
|
|
8
|
+
Events("onPolygonPress", "onPolygonSimplified")
|
|
9
9
|
|
|
10
|
-
Prop("points") { (view:
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Prop("points") { (view: PolygonView, points: [Any]) in
|
|
11
|
+
view.setPoints(points)
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
-
Prop("fillColor") { (view:
|
|
14
|
+
Prop("fillColor") { (view: PolygonView, color: String?) in
|
|
15
15
|
view.setFillColor(color)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
Prop("strokeColor") { (view:
|
|
18
|
+
Prop("strokeColor") { (view: PolygonView, color: String?) in
|
|
19
19
|
view.setStrokeColor(color)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
Prop("strokeWidth") { (view:
|
|
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:
|
|
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?
|
|
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
|
|
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:
|
|
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
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
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:
|
|
206
|
+
func setStrokeColor(_ color: String?) {
|
|
199
207
|
strokeColor = color
|
|
200
208
|
renderer = nil
|
|
201
209
|
forceRerender()
|