expo-gaode-map 0.1.0
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/.eslintrc.js +5 -0
- package/PUBLISHING.md +244 -0
- package/README.md +990 -0
- package/android/build.gradle +48 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +455 -0
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +337 -0
- package/android/src/main/java/expo/modules/gaodemap/managers/CameraManager.kt +128 -0
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +324 -0
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +122 -0
- package/android/src/main/java/expo/modules/gaodemap/modules/LocationManager.kt +247 -0
- package/android/src/main/java/expo/modules/gaodemap/modules/SDKInitializer.kt +45 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +151 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +127 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/HeatMapView.kt +97 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +204 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MultiPointView.kt +103 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonView.kt +114 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineView.kt +138 -0
- package/build/ExpoGaodeMap.types.d.ts +24 -0
- package/build/ExpoGaodeMap.types.d.ts.map +1 -0
- package/build/ExpoGaodeMap.types.js +14 -0
- package/build/ExpoGaodeMap.types.js.map +1 -0
- package/build/ExpoGaodeMapModule.d.ts +7 -0
- package/build/ExpoGaodeMapModule.d.ts.map +1 -0
- package/build/ExpoGaodeMapModule.js +14 -0
- package/build/ExpoGaodeMapModule.js.map +1 -0
- package/build/ExpoGaodeMapView.d.ts +31 -0
- package/build/ExpoGaodeMapView.d.ts.map +1 -0
- package/build/ExpoGaodeMapView.js +141 -0
- package/build/ExpoGaodeMapView.js.map +1 -0
- package/build/components/overlays/Circle.d.ts +18 -0
- package/build/components/overlays/Circle.d.ts.map +1 -0
- package/build/components/overlays/Circle.js +63 -0
- package/build/components/overlays/Circle.js.map +1 -0
- package/build/components/overlays/Cluster.d.ts +22 -0
- package/build/components/overlays/Cluster.d.ts.map +1 -0
- package/build/components/overlays/Cluster.js +35 -0
- package/build/components/overlays/Cluster.js.map +1 -0
- package/build/components/overlays/HeatMap.d.ts +21 -0
- package/build/components/overlays/HeatMap.d.ts.map +1 -0
- package/build/components/overlays/HeatMap.js +34 -0
- package/build/components/overlays/HeatMap.js.map +1 -0
- package/build/components/overlays/Marker.d.ts +17 -0
- package/build/components/overlays/Marker.d.ts.map +1 -0
- package/build/components/overlays/Marker.js +57 -0
- package/build/components/overlays/Marker.js.map +1 -0
- package/build/components/overlays/MultiPoint.d.ts +21 -0
- package/build/components/overlays/MultiPoint.d.ts.map +1 -0
- package/build/components/overlays/MultiPoint.js +34 -0
- package/build/components/overlays/MultiPoint.js.map +1 -0
- package/build/components/overlays/Polygon.d.ts +22 -0
- package/build/components/overlays/Polygon.d.ts.map +1 -0
- package/build/components/overlays/Polygon.js +100 -0
- package/build/components/overlays/Polygon.js.map +1 -0
- package/build/components/overlays/Polyline.d.ts +20 -0
- package/build/components/overlays/Polyline.d.ts.map +1 -0
- package/build/components/overlays/Polyline.js +60 -0
- package/build/components/overlays/Polyline.js.map +1 -0
- package/build/components/overlays/index.d.ts +8 -0
- package/build/components/overlays/index.d.ts.map +1 -0
- package/build/components/overlays/index.js +18 -0
- package/build/components/overlays/index.js.map +1 -0
- package/build/index.d.ts +10 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +28 -0
- package/build/index.js.map +1 -0
- package/build/modules/AMapLocation.d.ts +58 -0
- package/build/modules/AMapLocation.d.ts.map +1 -0
- package/build/modules/AMapLocation.js +141 -0
- package/build/modules/AMapLocation.js.map +1 -0
- package/build/modules/AMapSDK.d.ts +27 -0
- package/build/modules/AMapSDK.d.ts.map +1 -0
- package/build/modules/AMapSDK.js +43 -0
- package/build/modules/AMapSDK.js.map +1 -0
- package/build/modules/AMapView.d.ts +39 -0
- package/build/modules/AMapView.d.ts.map +1 -0
- package/build/modules/AMapView.js +61 -0
- package/build/modules/AMapView.js.map +1 -0
- package/build/types/common.types.d.ts +133 -0
- package/build/types/common.types.d.ts.map +1 -0
- package/build/types/common.types.js +31 -0
- package/build/types/common.types.js.map +1 -0
- package/build/types/index.d.ts +12 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +17 -0
- package/build/types/index.js.map +1 -0
- package/build/types/location.types.d.ts +306 -0
- package/build/types/location.types.d.ts.map +1 -0
- package/build/types/location.types.js +93 -0
- package/build/types/location.types.js.map +1 -0
- package/build/types/map-view.types.d.ts +213 -0
- package/build/types/map-view.types.d.ts.map +1 -0
- package/build/types/map-view.types.js +6 -0
- package/build/types/map-view.types.js.map +1 -0
- package/build/types/overlays.types.d.ts +296 -0
- package/build/types/overlays.types.d.ts.map +1 -0
- package/build/types/overlays.types.js +6 -0
- package/build/types/overlays.types.js.map +1 -0
- package/build/types/sdk.types.d.ts +113 -0
- package/build/types/sdk.types.d.ts.map +1 -0
- package/build/types/sdk.types.js +6 -0
- package/build/types/sdk.types.js.map +1 -0
- package/docs/followUserLocation.md +186 -0
- package/expo-module.config.json +9 -0
- package/ios/ExpoGaodeMap.podspec +29 -0
- package/ios/ExpoGaodeMapModule.swift +48 -0
- package/ios/ExpoGaodeMapView.swift +38 -0
- package/package.json +45 -0
- package/src/ExpoGaodeMap.types.ts +68 -0
- package/src/ExpoGaodeMapModule.ts +21 -0
- package/src/ExpoGaodeMapView.tsx +151 -0
- package/src/components/overlays/Circle.tsx +73 -0
- package/src/components/overlays/Cluster.tsx +38 -0
- package/src/components/overlays/HeatMap.tsx +37 -0
- package/src/components/overlays/Marker.tsx +66 -0
- package/src/components/overlays/MultiPoint.tsx +37 -0
- package/src/components/overlays/Polygon.tsx +107 -0
- package/src/components/overlays/Polyline.tsx +69 -0
- package/src/components/overlays/index.ts +18 -0
- package/src/index.ts +55 -0
- package/src/modules/AMapLocation.ts +164 -0
- package/src/modules/AMapSDK.ts +48 -0
- package/src/modules/AMapView.ts +68 -0
- package/src/types/README.md +186 -0
- package/src/types/common.types.ts +155 -0
- package/src/types/index.ts +74 -0
- package/src/types/location.types.ts +364 -0
- package/src/types/map-view.types.ts +249 -0
- package/src/types/overlays.types.ts +346 -0
- package/src/types/sdk.types.ts +128 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
package expo.modules.gaodemap.modules
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.amap.api.location.AMapLocationClient
|
|
6
|
+
import com.amap.api.maps.MapsInitializer
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SDK 初始化管理器
|
|
10
|
+
*/
|
|
11
|
+
object SDKInitializer {
|
|
12
|
+
private const val TAG = "SDKInitializer"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 初始化高德地图和定位 SDK
|
|
16
|
+
*/
|
|
17
|
+
fun initSDK(context: Context, androidKey: String) {
|
|
18
|
+
try {
|
|
19
|
+
Log.d(TAG, "开始初始化 SDK...")
|
|
20
|
+
|
|
21
|
+
// 更新地图隐私合规
|
|
22
|
+
MapsInitializer.updatePrivacyShow(context, true, true)
|
|
23
|
+
MapsInitializer.updatePrivacyAgree(context, true)
|
|
24
|
+
MapsInitializer.setApiKey(androidKey)
|
|
25
|
+
Log.d(TAG, "地图 SDK 初始化完成")
|
|
26
|
+
|
|
27
|
+
// 更新定位隐私合规
|
|
28
|
+
AMapLocationClient.updatePrivacyShow(context, true, true)
|
|
29
|
+
AMapLocationClient.updatePrivacyAgree(context, true)
|
|
30
|
+
AMapLocationClient.setApiKey(androidKey)
|
|
31
|
+
Log.d(TAG, "定位 SDK 初始化完成")
|
|
32
|
+
|
|
33
|
+
} catch (e: Exception) {
|
|
34
|
+
Log.e(TAG, "SDK 初始化失败", e)
|
|
35
|
+
throw Exception("SDK 初始化失败: ${e.message}")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 获取 SDK 版本
|
|
41
|
+
*/
|
|
42
|
+
fun getVersion(): String {
|
|
43
|
+
return MapsInitializer.getVersion()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
package expo.modules.gaodemap.overlays
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import com.amap.api.maps.AMap
|
|
6
|
+
import com.amap.api.maps.model.Circle
|
|
7
|
+
import com.amap.api.maps.model.CircleOptions
|
|
8
|
+
import com.amap.api.maps.model.LatLng
|
|
9
|
+
import expo.modules.kotlin.AppContext
|
|
10
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
11
|
+
import expo.modules.kotlin.views.ExpoView
|
|
12
|
+
|
|
13
|
+
class CircleView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
14
|
+
|
|
15
|
+
@Suppress("unused")
|
|
16
|
+
private val onPress by EventDispatcher()
|
|
17
|
+
|
|
18
|
+
private var circle: Circle? = null
|
|
19
|
+
private var aMap: AMap? = null
|
|
20
|
+
private var center: LatLng? = null
|
|
21
|
+
private var radius: Double = 1000.0
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 设置地图实例
|
|
25
|
+
*/
|
|
26
|
+
@Suppress("unused")
|
|
27
|
+
fun setMap(map: AMap) {
|
|
28
|
+
android.util.Log.d("CircleView", "setMap 被调用")
|
|
29
|
+
aMap = map
|
|
30
|
+
// 不立即创建,等 props 设置完成后再创建
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 设置圆心
|
|
35
|
+
*/
|
|
36
|
+
fun setCenter(centerMap: Map<String, Double>) {
|
|
37
|
+
android.util.Log.d("CircleView", "setCenter 被调用: $centerMap")
|
|
38
|
+
val lat = centerMap["latitude"]
|
|
39
|
+
val lng = centerMap["longitude"]
|
|
40
|
+
if (lat != null && lng != null) {
|
|
41
|
+
center = LatLng(lat, lng)
|
|
42
|
+
android.util.Log.d("CircleView", "圆心设置为: lat=$lat, lng=$lng")
|
|
43
|
+
|
|
44
|
+
// 如果圆形已存在,更新它;否则创建新圆形
|
|
45
|
+
circle?.let {
|
|
46
|
+
android.util.Log.d("CircleView", "更新现有圆形的圆心")
|
|
47
|
+
it.center = center
|
|
48
|
+
} ?: run {
|
|
49
|
+
android.util.Log.d("CircleView", "圆形不存在,尝试创建")
|
|
50
|
+
createOrUpdateCircle()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 设置半径
|
|
57
|
+
*/
|
|
58
|
+
fun setRadius(radiusValue: Double) {
|
|
59
|
+
android.util.Log.d("CircleView", "setRadius 被调用: $radiusValue")
|
|
60
|
+
radius = radiusValue
|
|
61
|
+
circle?.let {
|
|
62
|
+
android.util.Log.d("CircleView", "更新现有圆形的半径")
|
|
63
|
+
it.radius = radius
|
|
64
|
+
}
|
|
65
|
+
// 半径可以后续更新,不需要在这里创建圆形
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 设置填充颜色
|
|
70
|
+
*/
|
|
71
|
+
fun setFillColor(color: Int) {
|
|
72
|
+
android.util.Log.d("CircleView", "setFillColor 被调用: ${Integer.toHexString(color)}")
|
|
73
|
+
circle?.let {
|
|
74
|
+
it.fillColor = color
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 设置边框颜色
|
|
80
|
+
*/
|
|
81
|
+
fun setStrokeColor(color: Int) {
|
|
82
|
+
android.util.Log.d("CircleView", "setStrokeColor 被调用: ${Integer.toHexString(color)}")
|
|
83
|
+
circle?.let {
|
|
84
|
+
it.strokeColor = color
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 设置边框宽度
|
|
90
|
+
*/
|
|
91
|
+
fun setStrokeWidth(width: Float) {
|
|
92
|
+
android.util.Log.d("CircleView", "setStrokeWidth 被调用: $width")
|
|
93
|
+
circle?.let {
|
|
94
|
+
it.strokeWidth = width
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 设置 z-index
|
|
100
|
+
*/
|
|
101
|
+
fun setZIndex(zIndex: Float) {
|
|
102
|
+
circle?.let {
|
|
103
|
+
it.zIndex = zIndex
|
|
104
|
+
} ?: createOrUpdateCircle()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 创建或更新圆形
|
|
109
|
+
*/
|
|
110
|
+
private fun createOrUpdateCircle() {
|
|
111
|
+
android.util.Log.d("CircleView", "createOrUpdateCircle 被调用")
|
|
112
|
+
android.util.Log.d("CircleView", "aMap: $aMap, center: $center, radius: $radius")
|
|
113
|
+
|
|
114
|
+
// 必须同时有地图实例和圆心才能创建
|
|
115
|
+
val map = aMap ?: run {
|
|
116
|
+
android.util.Log.w("CircleView", "⚠️ aMap 为 null,无法创建圆形")
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
val centerPoint = center ?: run {
|
|
121
|
+
android.util.Log.w("CircleView", "⚠️ center 为 null,无法创建圆形")
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (circle == null) {
|
|
126
|
+
android.util.Log.d("CircleView", "创建新圆形 - center: $centerPoint, radius: $radius")
|
|
127
|
+
val options = CircleOptions()
|
|
128
|
+
.center(centerPoint)
|
|
129
|
+
.radius(radius)
|
|
130
|
+
.fillColor(Color.argb(50, 0, 0, 255)) // 默认半透明蓝色
|
|
131
|
+
.strokeColor(Color.BLUE) // 默认蓝色边框
|
|
132
|
+
.strokeWidth(10f) // 默认边框宽度
|
|
133
|
+
|
|
134
|
+
circle = map.addCircle(options)
|
|
135
|
+
android.util.Log.d("CircleView", "✅ 圆形创建成功: $circle")
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 移除圆形
|
|
141
|
+
*/
|
|
142
|
+
fun removeCircle() {
|
|
143
|
+
circle?.remove()
|
|
144
|
+
circle = null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override fun onDetachedFromWindow() {
|
|
148
|
+
super.onDetachedFromWindow()
|
|
149
|
+
removeCircle()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
package expo.modules.gaodemap.overlays
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.amap.api.maps.AMap
|
|
5
|
+
import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
6
|
+
import com.amap.api.maps.model.LatLng
|
|
7
|
+
import com.amap.api.maps.model.Marker
|
|
8
|
+
import com.amap.api.maps.model.MarkerOptions
|
|
9
|
+
import expo.modules.kotlin.AppContext
|
|
10
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
11
|
+
import expo.modules.kotlin.views.ExpoView
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 点聚合视图
|
|
15
|
+
* 注意:高德 Android SDK 的点聚合功能需要额外依赖,这里提供基础实现
|
|
16
|
+
* 实际使用时可能需要引入 com.amap.api:3dmap-cluster 库
|
|
17
|
+
*/
|
|
18
|
+
class ClusterView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
19
|
+
|
|
20
|
+
private val onPress by EventDispatcher()
|
|
21
|
+
@Suppress("unused")
|
|
22
|
+
private val onClusterPress by EventDispatcher()
|
|
23
|
+
|
|
24
|
+
private var aMap: AMap? = null
|
|
25
|
+
private var markers: MutableList<Marker> = mutableListOf()
|
|
26
|
+
private var points: List<Map<String, Any>> = emptyList()
|
|
27
|
+
@Suppress("unused")
|
|
28
|
+
private var radius: Int = 60
|
|
29
|
+
@Suppress("unused")
|
|
30
|
+
private var minClusterSize: Int = 2
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 设置地图实例
|
|
34
|
+
*/
|
|
35
|
+
@Suppress("unused")
|
|
36
|
+
fun setMap(map: AMap) {
|
|
37
|
+
aMap = map
|
|
38
|
+
createOrUpdateCluster()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 设置聚合点数据
|
|
43
|
+
*/
|
|
44
|
+
fun setPoints(pointsList: List<Map<String, Any>>) {
|
|
45
|
+
points = pointsList
|
|
46
|
+
createOrUpdateCluster()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 设置聚合半径
|
|
51
|
+
*/
|
|
52
|
+
fun setRadius(radiusValue: Int) {
|
|
53
|
+
radius = radiusValue
|
|
54
|
+
createOrUpdateCluster()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 设置最小聚合数量
|
|
59
|
+
*/
|
|
60
|
+
fun setMinClusterSize(size: Int) {
|
|
61
|
+
minClusterSize = size
|
|
62
|
+
createOrUpdateCluster()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 设置图标
|
|
67
|
+
*/
|
|
68
|
+
@Suppress("UNUSED_PARAMETER")
|
|
69
|
+
fun setIcon(iconUri: String?) {
|
|
70
|
+
// 简化处理,实际需要实现图片加载
|
|
71
|
+
createOrUpdateCluster()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 创建或更新聚合
|
|
76
|
+
* 注意:这是简化实现,完整的点聚合需要使用专门的聚合库
|
|
77
|
+
*/
|
|
78
|
+
private fun createOrUpdateCluster() {
|
|
79
|
+
aMap?.let { map ->
|
|
80
|
+
// 清除旧的标记
|
|
81
|
+
markers.forEach { it.remove() }
|
|
82
|
+
markers.clear()
|
|
83
|
+
|
|
84
|
+
// 简化实现:直接添加所有点作为标记
|
|
85
|
+
// 实际应用中应该使用点聚合算法
|
|
86
|
+
points.forEach { point ->
|
|
87
|
+
val lat = (point["latitude"] as? Number)?.toDouble()
|
|
88
|
+
val lng = (point["longitude"] as? Number)?.toDouble()
|
|
89
|
+
|
|
90
|
+
if (lat != null && lng != null) {
|
|
91
|
+
val markerOptions = MarkerOptions()
|
|
92
|
+
.position(LatLng(lat, lng))
|
|
93
|
+
.icon(BitmapDescriptorFactory.defaultMarker())
|
|
94
|
+
|
|
95
|
+
val marker = map.addMarker(markerOptions)
|
|
96
|
+
marker?.let { markers.add(it) }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 设置点击监听
|
|
101
|
+
map.setOnMarkerClickListener { clickedMarker ->
|
|
102
|
+
if (markers.contains(clickedMarker)) {
|
|
103
|
+
onPress(mapOf(
|
|
104
|
+
"latitude" to clickedMarker.position.latitude,
|
|
105
|
+
"longitude" to clickedMarker.position.longitude
|
|
106
|
+
))
|
|
107
|
+
true
|
|
108
|
+
} else {
|
|
109
|
+
false
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 移除聚合
|
|
117
|
+
*/
|
|
118
|
+
fun removeCluster() {
|
|
119
|
+
markers.forEach { it.remove() }
|
|
120
|
+
markers.clear()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun onDetachedFromWindow() {
|
|
124
|
+
super.onDetachedFromWindow()
|
|
125
|
+
removeCluster()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
package expo.modules.gaodemap.overlays
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.amap.api.maps.AMap
|
|
5
|
+
import com.amap.api.maps.model.LatLng
|
|
6
|
+
import com.amap.api.maps.model.TileOverlay
|
|
7
|
+
import com.amap.api.maps.model.TileOverlayOptions
|
|
8
|
+
import com.amap.api.maps.model.HeatmapTileProvider
|
|
9
|
+
import expo.modules.kotlin.AppContext
|
|
10
|
+
import expo.modules.kotlin.views.ExpoView
|
|
11
|
+
|
|
12
|
+
class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
13
|
+
|
|
14
|
+
private var heatmapOverlay: TileOverlay? = null
|
|
15
|
+
private var aMap: AMap? = null
|
|
16
|
+
private var dataList: MutableList<LatLng> = mutableListOf()
|
|
17
|
+
private var radius: Int = 50
|
|
18
|
+
private var opacity: Double = 0.6
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 设置地图实例
|
|
22
|
+
*/
|
|
23
|
+
@Suppress("unused")
|
|
24
|
+
fun setMap(map: AMap) {
|
|
25
|
+
aMap = map
|
|
26
|
+
createOrUpdateHeatMap()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 设置热力图数据
|
|
31
|
+
*/
|
|
32
|
+
fun setData(data: List<Map<String, Any>>) {
|
|
33
|
+
dataList.clear()
|
|
34
|
+
data.forEach { point ->
|
|
35
|
+
val lat = (point["latitude"] as? Number)?.toDouble()
|
|
36
|
+
val lng = (point["longitude"] as? Number)?.toDouble()
|
|
37
|
+
if (lat != null && lng != null) {
|
|
38
|
+
dataList.add(LatLng(lat, lng))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
createOrUpdateHeatMap()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 设置热力图半径
|
|
46
|
+
*/
|
|
47
|
+
fun setRadius(radiusValue: Int) {
|
|
48
|
+
radius = radiusValue
|
|
49
|
+
createOrUpdateHeatMap()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 设置透明度
|
|
54
|
+
*/
|
|
55
|
+
fun setOpacity(opacityValue: Double) {
|
|
56
|
+
opacity = opacityValue
|
|
57
|
+
createOrUpdateHeatMap()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 创建或更新热力图
|
|
62
|
+
*/
|
|
63
|
+
private fun createOrUpdateHeatMap() {
|
|
64
|
+
aMap?.let { map ->
|
|
65
|
+
if (dataList.isNotEmpty()) {
|
|
66
|
+
// 移除旧的热力图
|
|
67
|
+
heatmapOverlay?.remove()
|
|
68
|
+
|
|
69
|
+
// 创建热力图提供者
|
|
70
|
+
val builder = HeatmapTileProvider.Builder()
|
|
71
|
+
builder.data(dataList)
|
|
72
|
+
builder.radius(radius)
|
|
73
|
+
|
|
74
|
+
// 创建热力图图层
|
|
75
|
+
val heatmapTileProvider = builder.build()
|
|
76
|
+
val tileOverlayOptions = TileOverlayOptions()
|
|
77
|
+
.tileProvider(heatmapTileProvider)
|
|
78
|
+
|
|
79
|
+
heatmapOverlay = map.addTileOverlay(tileOverlayOptions)
|
|
80
|
+
// 注意:TileOverlay 不支持 transparency 属性,透明度通过 HeatmapTileProvider 控制
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 移除热力图
|
|
87
|
+
*/
|
|
88
|
+
fun removeHeatMap() {
|
|
89
|
+
heatmapOverlay?.remove()
|
|
90
|
+
heatmapOverlay = null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun onDetachedFromWindow() {
|
|
94
|
+
super.onDetachedFromWindow()
|
|
95
|
+
removeHeatMap()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
package expo.modules.gaodemap.overlays
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.amap.api.maps.AMap
|
|
5
|
+
import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
6
|
+
import com.amap.api.maps.model.LatLng
|
|
7
|
+
import com.amap.api.maps.model.Marker
|
|
8
|
+
import com.amap.api.maps.model.MarkerOptions
|
|
9
|
+
import expo.modules.kotlin.AppContext
|
|
10
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
11
|
+
import expo.modules.kotlin.views.ExpoView
|
|
12
|
+
|
|
13
|
+
class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
14
|
+
|
|
15
|
+
private val onPress by EventDispatcher()
|
|
16
|
+
private val onDragStart by EventDispatcher()
|
|
17
|
+
private val onDrag by EventDispatcher()
|
|
18
|
+
private val onDragEnd by EventDispatcher()
|
|
19
|
+
|
|
20
|
+
private var marker: Marker? = null
|
|
21
|
+
private var aMap: AMap? = null
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 设置地图实例
|
|
25
|
+
*/
|
|
26
|
+
@Suppress("unused")
|
|
27
|
+
fun setMap(map: AMap) {
|
|
28
|
+
aMap = map
|
|
29
|
+
createOrUpdateMarker()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 设置标记位置
|
|
34
|
+
*/
|
|
35
|
+
fun setPosition(position: Map<String, Double>) {
|
|
36
|
+
val lat = position["latitude"] ?: return
|
|
37
|
+
val lng = position["longitude"] ?: return
|
|
38
|
+
|
|
39
|
+
marker?.let {
|
|
40
|
+
it.position = LatLng(lat, lng)
|
|
41
|
+
} ?: createOrUpdateMarker()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 设置标题
|
|
46
|
+
*/
|
|
47
|
+
fun setTitle(title: String) {
|
|
48
|
+
marker?.let { it.title = title }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 设置描述
|
|
53
|
+
*/
|
|
54
|
+
fun setDescription(description: String) {
|
|
55
|
+
marker?.let { it.snippet = description }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 设置是否可拖拽
|
|
60
|
+
*/
|
|
61
|
+
fun setDraggable(draggable: Boolean) {
|
|
62
|
+
marker?.let { it.isDraggable = draggable }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 设置是否显示信息窗口
|
|
67
|
+
*/
|
|
68
|
+
fun setShowsInfoWindow(show: Boolean) {
|
|
69
|
+
marker?.let {
|
|
70
|
+
if (show) {
|
|
71
|
+
it.showInfoWindow()
|
|
72
|
+
} else {
|
|
73
|
+
it.hideInfoWindow()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 设置透明度
|
|
80
|
+
*/
|
|
81
|
+
fun setOpacity(opacity: Float) {
|
|
82
|
+
marker?.let { it.alpha = opacity }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 设置旋转角度
|
|
87
|
+
*/
|
|
88
|
+
fun setMarkerRotation(rotation: Float) {
|
|
89
|
+
marker?.let { it.rotateAngle = rotation }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 设置锚点
|
|
94
|
+
*/
|
|
95
|
+
fun setAnchor(anchor: Map<String, Float>) {
|
|
96
|
+
val x = anchor["x"] ?: 0.5f
|
|
97
|
+
val y = anchor["y"] ?: 1.0f
|
|
98
|
+
marker?.setAnchor(x, y)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 设置是否平贴地图
|
|
103
|
+
*/
|
|
104
|
+
fun setFlat(flat: Boolean) {
|
|
105
|
+
marker?.let { it.isFlat = flat }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 设置图标
|
|
110
|
+
*/
|
|
111
|
+
fun setMarkerIcon(iconUri: String?) {
|
|
112
|
+
iconUri?.let {
|
|
113
|
+
// 这里需要根据 URI 加载图片
|
|
114
|
+
// 可以支持本地资源、网络图片等
|
|
115
|
+
try {
|
|
116
|
+
// 简化处理,实际需要实现图片加载逻辑
|
|
117
|
+
marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
118
|
+
} catch (e: Exception) {
|
|
119
|
+
e.printStackTrace()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 设置 z-index
|
|
126
|
+
*/
|
|
127
|
+
fun setZIndex(zIndex: Float) {
|
|
128
|
+
marker?.let { it.zIndex = zIndex }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 创建或更新标记
|
|
133
|
+
*/
|
|
134
|
+
private fun createOrUpdateMarker() {
|
|
135
|
+
aMap?.let { map ->
|
|
136
|
+
if (marker == null) {
|
|
137
|
+
val options = MarkerOptions()
|
|
138
|
+
marker = map.addMarker(options)
|
|
139
|
+
|
|
140
|
+
// 设置点击监听
|
|
141
|
+
map.setOnMarkerClickListener { clickedMarker ->
|
|
142
|
+
if (clickedMarker == marker) {
|
|
143
|
+
onPress(mapOf(
|
|
144
|
+
"latitude" to clickedMarker.position.latitude,
|
|
145
|
+
"longitude" to clickedMarker.position.longitude
|
|
146
|
+
))
|
|
147
|
+
true
|
|
148
|
+
} else {
|
|
149
|
+
false
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 设置拖拽监听
|
|
154
|
+
map.setOnMarkerDragListener(object : AMap.OnMarkerDragListener {
|
|
155
|
+
override fun onMarkerDragStart(draggedMarker: Marker?) {
|
|
156
|
+
if (draggedMarker == marker) {
|
|
157
|
+
draggedMarker?.let {
|
|
158
|
+
onDragStart(mapOf(
|
|
159
|
+
"latitude" to it.position.latitude,
|
|
160
|
+
"longitude" to it.position.longitude
|
|
161
|
+
))
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
override fun onMarkerDrag(draggedMarker: Marker?) {
|
|
167
|
+
if (draggedMarker == marker) {
|
|
168
|
+
draggedMarker?.let {
|
|
169
|
+
onDrag(mapOf(
|
|
170
|
+
"latitude" to it.position.latitude,
|
|
171
|
+
"longitude" to it.position.longitude
|
|
172
|
+
))
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
override fun onMarkerDragEnd(draggedMarker: Marker?) {
|
|
178
|
+
if (draggedMarker == marker) {
|
|
179
|
+
draggedMarker?.let {
|
|
180
|
+
onDragEnd(mapOf(
|
|
181
|
+
"latitude" to it.position.latitude,
|
|
182
|
+
"longitude" to it.position.longitude
|
|
183
|
+
))
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 移除标记
|
|
194
|
+
*/
|
|
195
|
+
fun removeMarker() {
|
|
196
|
+
marker?.remove()
|
|
197
|
+
marker = null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
override fun onDetachedFromWindow() {
|
|
201
|
+
super.onDetachedFromWindow()
|
|
202
|
+
removeMarker()
|
|
203
|
+
}
|
|
204
|
+
}
|