expo-gaode-map 1.0.3 → 1.0.4
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/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +71 -5
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +90 -6
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +87 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +16 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonView.kt +22 -2
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineView.kt +83 -17
- package/build/ExpoGaodeMapView.d.ts +20 -0
- package/build/ExpoGaodeMapView.d.ts.map +1 -1
- package/build/ExpoGaodeMapView.js +55 -3
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/overlays/Polygon.d.ts +1 -0
- package/build/components/overlays/Polygon.d.ts.map +1 -1
- package/build/components/overlays/Polygon.js +15 -3
- package/build/components/overlays/Polygon.js.map +1 -1
- package/build/components/overlays/Polyline.d.ts +1 -0
- package/build/components/overlays/Polyline.d.ts.map +1 -1
- package/build/components/overlays/Polyline.js +18 -3
- package/build/components/overlays/Polyline.js.map +1 -1
- package/build/types/map-view.types.d.ts +12 -0
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +6 -0
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/docs/API.md +81 -7
- package/docs/INITIALIZATION.md +14 -4
- package/ios/ExpoGaodeMapModule.swift +91 -5
- package/ios/ExpoGaodeMapView.swift +157 -11
- package/ios/managers/OverlayManager.swift +116 -8
- package/ios/modules/LocationManager.swift +3 -0
- package/ios/overlays/PolygonView.swift +2 -0
- package/ios/overlays/PolylineView.swift +14 -0
- package/ios/utils/PermissionManager.swift +62 -7
- package/package.json +1 -1
- package/src/ExpoGaodeMapView.tsx +87 -11
- package/src/components/overlays/Polygon.tsx +16 -3
- package/src/components/overlays/Polyline.tsx +19 -3
- package/src/types/map-view.types.ts +10 -0
- package/src/types/overlays.types.ts +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package expo.modules.gaodemap
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import expo.modules.kotlin.modules.Module
|
|
5
5
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
6
6
|
import expo.modules.gaodemap.modules.SDKInitializer
|
|
@@ -17,9 +17,7 @@ import expo.modules.gaodemap.overlays.*
|
|
|
17
17
|
* - 地图视图和覆盖物注册
|
|
18
18
|
*/
|
|
19
19
|
class ExpoGaodeMapModule : Module() {
|
|
20
|
-
|
|
21
|
-
private const val TAG = "ExpoGaodeMapModule"
|
|
22
|
-
}
|
|
20
|
+
|
|
23
21
|
|
|
24
22
|
/** 定位管理器实例 */
|
|
25
23
|
private var locationManager: LocationManager? = null
|
|
@@ -181,6 +179,62 @@ class ExpoGaodeMapModule : Module() {
|
|
|
181
179
|
getLocationManager().setHttpTimeOut(httpTimeOut)
|
|
182
180
|
}
|
|
183
181
|
|
|
182
|
+
/**
|
|
183
|
+
* 设置定位精度 (iOS 专用,Android 空实现)
|
|
184
|
+
* @param accuracy 精度级别
|
|
185
|
+
*/
|
|
186
|
+
Function("setDesiredAccuracy") { _: Int ->
|
|
187
|
+
// Android 不支持此配置
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 设置定位超时时间 (iOS 专用,Android 空实现)
|
|
192
|
+
* @param timeout 超时时间(秒)
|
|
193
|
+
*/
|
|
194
|
+
Function("setLocationTimeout") { _: Int ->
|
|
195
|
+
// Android 不支持此配置
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 设置逆地理超时时间 (iOS 专用,Android 空实现)
|
|
200
|
+
* @param timeout 超时时间(秒)
|
|
201
|
+
*/
|
|
202
|
+
Function("setReGeocodeTimeout") { _: Int ->
|
|
203
|
+
// Android 不支持此配置
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 设置距离过滤器 (iOS 专用,Android 空实现)
|
|
208
|
+
* @param distance 最小距离变化(米)
|
|
209
|
+
*/
|
|
210
|
+
Function("setDistanceFilter") { _: Double ->
|
|
211
|
+
// Android 不支持此配置
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 设置是否自动暂停定位更新 (iOS 专用,Android 空实现)
|
|
216
|
+
* @param pauses 是否自动暂停
|
|
217
|
+
*/
|
|
218
|
+
Function("setPausesLocationUpdatesAutomatically") { _: Boolean ->
|
|
219
|
+
// Android 不支持此配置
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 设置是否允许后台定位 (iOS 专用,Android 空实现)
|
|
224
|
+
* @param allows 是否允许后台定位
|
|
225
|
+
*/
|
|
226
|
+
Function("setAllowsBackgroundLocationUpdates") { _: Boolean ->
|
|
227
|
+
// Android 不支持此配置
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 设置定位协议 (未实现)
|
|
232
|
+
* @param protocol 协议类型
|
|
233
|
+
*/
|
|
234
|
+
Function("setLocationProtocol") { _: Int ->
|
|
235
|
+
// 未实现
|
|
236
|
+
}
|
|
237
|
+
|
|
184
238
|
// ==================== 权限管理 ====================
|
|
185
239
|
|
|
186
240
|
/**
|
|
@@ -271,7 +325,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
271
325
|
View(ExpoGaodeMapView::class) {
|
|
272
326
|
|
|
273
327
|
// 事件
|
|
274
|
-
Events("onMapPress", "onMapLongPress", "onLoad", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress")
|
|
328
|
+
Events("onMapPress", "onMapLongPress", "onLoad", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress", "onPolygonPress", "onPolylinePress")
|
|
275
329
|
|
|
276
330
|
// 地图类型
|
|
277
331
|
Prop<Int>("mapType") { view, type ->
|
|
@@ -478,6 +532,18 @@ class ExpoGaodeMapModule : Module() {
|
|
|
478
532
|
Prop<String?>("texture") { view: PolylineView, texture ->
|
|
479
533
|
view.setTexture(texture)
|
|
480
534
|
}
|
|
535
|
+
|
|
536
|
+
Prop<Boolean>("dotted") { view: PolylineView, dotted ->
|
|
537
|
+
view.setDotted(dotted)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
Prop<Boolean>("geodesic") { view: PolylineView, geodesic ->
|
|
541
|
+
view.setGeodesic(geodesic)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
Prop<Float>("zIndex") { view: PolylineView, zIndex ->
|
|
545
|
+
view.setZIndex(zIndex)
|
|
546
|
+
}
|
|
481
547
|
}
|
|
482
548
|
|
|
483
549
|
// Polygon - 多边形
|
|
@@ -6,6 +6,7 @@ import android.view.View
|
|
|
6
6
|
import com.amap.api.maps.AMap
|
|
7
7
|
import com.amap.api.maps.MapView
|
|
8
8
|
import com.amap.api.maps.MapsInitializer
|
|
9
|
+
import com.amap.api.maps.model.LatLng
|
|
9
10
|
import expo.modules.kotlin.AppContext
|
|
10
11
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
11
12
|
import expo.modules.kotlin.views.ExpoView
|
|
@@ -50,6 +51,8 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
50
51
|
private val onMarkerDrag by EventDispatcher()
|
|
51
52
|
private val onMarkerDragEnd by EventDispatcher()
|
|
52
53
|
private val onCirclePress by EventDispatcher()
|
|
54
|
+
private val onPolygonPress by EventDispatcher()
|
|
55
|
+
private val onPolylinePress by EventDispatcher()
|
|
53
56
|
|
|
54
57
|
// 高德地图视图
|
|
55
58
|
private lateinit var mapView: MapView
|
|
@@ -114,6 +117,20 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
114
117
|
"longitude" to lng
|
|
115
118
|
))
|
|
116
119
|
}
|
|
120
|
+
onPolygonPress = { id, lat, lng ->
|
|
121
|
+
this@ExpoGaodeMapView.onPolygonPress(mapOf(
|
|
122
|
+
"polygonId" to id,
|
|
123
|
+
"latitude" to lat,
|
|
124
|
+
"longitude" to lng
|
|
125
|
+
))
|
|
126
|
+
}
|
|
127
|
+
onPolylinePress = { id, lat, lng ->
|
|
128
|
+
this@ExpoGaodeMapView.onPolylinePress(mapOf(
|
|
129
|
+
"polylineId" to id,
|
|
130
|
+
"latitude" to lat,
|
|
131
|
+
"longitude" to lng
|
|
132
|
+
))
|
|
133
|
+
}
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
// 添加地图视图到布局
|
|
@@ -149,16 +166,47 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
149
166
|
*/
|
|
150
167
|
private fun setupMapListeners() {
|
|
151
168
|
aMap.setOnMapClickListener { latLng ->
|
|
152
|
-
//
|
|
169
|
+
// 检查声明式 PolylineView
|
|
170
|
+
if (checkDeclarativePolylinePress(latLng)) {
|
|
171
|
+
return@setOnMapClickListener
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 检查声明式 PolygonView
|
|
175
|
+
if (checkDeclarativePolygonPress(latLng)) {
|
|
176
|
+
return@setOnMapClickListener
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 检查声明式 CircleView
|
|
180
|
+
if (checkDeclarativeCirclePress(latLng)) {
|
|
181
|
+
return@setOnMapClickListener
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 检查命令式圆形
|
|
153
185
|
val circleId = overlayManager.checkCirclePress(latLng)
|
|
154
186
|
if (circleId != null) {
|
|
155
187
|
overlayManager.onCirclePress?.invoke(circleId, latLng.latitude, latLng.longitude)
|
|
156
|
-
|
|
157
|
-
onMapPress(mapOf(
|
|
158
|
-
"latitude" to latLng.latitude,
|
|
159
|
-
"longitude" to latLng.longitude
|
|
160
|
-
))
|
|
188
|
+
return@setOnMapClickListener
|
|
161
189
|
}
|
|
190
|
+
|
|
191
|
+
// 检查命令式多边形
|
|
192
|
+
val polygonId = overlayManager.checkPolygonPress(latLng)
|
|
193
|
+
if (polygonId != null) {
|
|
194
|
+
overlayManager.onPolygonPress?.invoke(polygonId, latLng.latitude, latLng.longitude)
|
|
195
|
+
return@setOnMapClickListener
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 检查命令式折线
|
|
199
|
+
val polylineId = overlayManager.checkPolylinePress(latLng)
|
|
200
|
+
if (polylineId != null) {
|
|
201
|
+
overlayManager.onPolylinePress?.invoke(polylineId, latLng.latitude, latLng.longitude)
|
|
202
|
+
return@setOnMapClickListener
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 如果都没点击,触发地图点击事件
|
|
206
|
+
onMapPress(mapOf(
|
|
207
|
+
"latitude" to latLng.latitude,
|
|
208
|
+
"longitude" to latLng.longitude
|
|
209
|
+
))
|
|
162
210
|
}
|
|
163
211
|
|
|
164
212
|
aMap.setOnMapLongClickListener { latLng ->
|
|
@@ -447,6 +495,42 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
447
495
|
}
|
|
448
496
|
}
|
|
449
497
|
|
|
498
|
+
private fun checkDeclarativePolylinePress(latLng: LatLng): Boolean {
|
|
499
|
+
for (i in 0 until childCount) {
|
|
500
|
+
val child = getChildAt(i)
|
|
501
|
+
if (child is PolylineView) {
|
|
502
|
+
if (child.checkPress(latLng)) {
|
|
503
|
+
return true
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return false
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
private fun checkDeclarativePolygonPress(latLng: LatLng): Boolean {
|
|
511
|
+
for (i in 0 until childCount) {
|
|
512
|
+
val child = getChildAt(i)
|
|
513
|
+
if (child is PolygonView) {
|
|
514
|
+
if (child.checkPress(latLng)) {
|
|
515
|
+
return true
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return false
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
private fun checkDeclarativeCirclePress(latLng: LatLng): Boolean {
|
|
523
|
+
for (i in 0 until childCount) {
|
|
524
|
+
val child = getChildAt(i)
|
|
525
|
+
if (child is CircleView) {
|
|
526
|
+
if (child.checkPress(latLng)) {
|
|
527
|
+
return true
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return false
|
|
532
|
+
}
|
|
533
|
+
|
|
450
534
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
451
535
|
super.onLayout(changed, left, top, right, bottom)
|
|
452
536
|
}
|
|
@@ -32,12 +32,20 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
|
|
|
32
32
|
// Circle ID 映射
|
|
33
33
|
private val circleIdMap = mutableMapOf<com.amap.api.maps.model.Circle, String>()
|
|
34
34
|
|
|
35
|
+
// Polygon ID 映射
|
|
36
|
+
private val polygonIdMap = mutableMapOf<com.amap.api.maps.model.Polygon, String>()
|
|
37
|
+
|
|
38
|
+
// Polyline ID 映射
|
|
39
|
+
private val polylineIdMap = mutableMapOf<com.amap.api.maps.model.Polyline, String>()
|
|
40
|
+
|
|
35
41
|
// 事件回调
|
|
36
42
|
var onMarkerPress: ((String, Double, Double) -> Unit)? = null
|
|
37
43
|
var onMarkerDragStart: ((String, Double, Double) -> Unit)? = null
|
|
38
44
|
var onMarkerDrag: ((String, Double, Double) -> Unit)? = null
|
|
39
45
|
var onMarkerDragEnd: ((String, Double, Double) -> Unit)? = null
|
|
40
46
|
var onCirclePress: ((String, Double, Double) -> Unit)? = null
|
|
47
|
+
var onPolygonPress: ((String, Double, Double) -> Unit)? = null
|
|
48
|
+
var onPolylinePress: ((String, Double, Double) -> Unit)? = null
|
|
41
49
|
|
|
42
50
|
private val mainHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
43
51
|
|
|
@@ -345,11 +353,13 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
|
|
|
345
353
|
}
|
|
346
354
|
|
|
347
355
|
polylines[id] = polyline
|
|
356
|
+
polylineIdMap[polyline] = id
|
|
348
357
|
}
|
|
349
358
|
}
|
|
350
359
|
|
|
351
360
|
fun removePolyline(id: String) {
|
|
352
361
|
polylines[id]?.let { polyline ->
|
|
362
|
+
polylineIdMap.remove(polyline)
|
|
353
363
|
polyline.remove()
|
|
354
364
|
polylines.remove(id)
|
|
355
365
|
}
|
|
@@ -404,12 +414,14 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
|
|
|
404
414
|
|
|
405
415
|
val polygon = aMap.addPolygon(options)
|
|
406
416
|
polygons[id] = polygon
|
|
417
|
+
polygonIdMap[polygon] = id
|
|
407
418
|
Log.d(TAG, "✅ 多边形创建成功")
|
|
408
419
|
}
|
|
409
420
|
}
|
|
410
421
|
|
|
411
422
|
fun removePolygon(id: String) {
|
|
412
423
|
polygons[id]?.let { polygon ->
|
|
424
|
+
polygonIdMap.remove(polygon)
|
|
413
425
|
polygon.remove()
|
|
414
426
|
polygons.remove(id)
|
|
415
427
|
}
|
|
@@ -456,6 +468,78 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
|
|
|
456
468
|
return null
|
|
457
469
|
}
|
|
458
470
|
|
|
471
|
+
/**
|
|
472
|
+
* 检查点击位置是否在某个多边形内
|
|
473
|
+
*/
|
|
474
|
+
fun checkPolygonPress(latLng: LatLng): String? {
|
|
475
|
+
for ((polygon, id) in polygonIdMap) {
|
|
476
|
+
if (polygon.contains(latLng)) {
|
|
477
|
+
return id
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return null
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* 检查点击位置是否在某条折线附近
|
|
485
|
+
*/
|
|
486
|
+
fun checkPolylinePress(latLng: LatLng): String? {
|
|
487
|
+
val threshold = 20.0 // 20米容差
|
|
488
|
+
for ((polyline, id) in polylineIdMap) {
|
|
489
|
+
val points = polyline.points
|
|
490
|
+
if (points.size < 2) continue
|
|
491
|
+
|
|
492
|
+
for (i in 0 until points.size - 1) {
|
|
493
|
+
val distance = distanceToSegment(latLng, points[i], points[i + 1])
|
|
494
|
+
if (distance <= threshold) {
|
|
495
|
+
return id
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return null
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* 计算点到线段的距离(米)
|
|
504
|
+
*/
|
|
505
|
+
private fun distanceToSegment(point: LatLng, start: LatLng, end: LatLng): Double {
|
|
506
|
+
val p = android.location.Location("").apply {
|
|
507
|
+
latitude = point.latitude
|
|
508
|
+
longitude = point.longitude
|
|
509
|
+
}
|
|
510
|
+
val a = android.location.Location("").apply {
|
|
511
|
+
latitude = start.latitude
|
|
512
|
+
longitude = start.longitude
|
|
513
|
+
}
|
|
514
|
+
val b = android.location.Location("").apply {
|
|
515
|
+
latitude = end.latitude
|
|
516
|
+
longitude = end.longitude
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
val ab = a.distanceTo(b).toDouble()
|
|
520
|
+
if (ab == 0.0) return a.distanceTo(p).toDouble()
|
|
521
|
+
|
|
522
|
+
val ap = a.distanceTo(p).toDouble()
|
|
523
|
+
val bp = b.distanceTo(p).toDouble()
|
|
524
|
+
|
|
525
|
+
val t = maxOf(0.0, minOf(1.0,
|
|
526
|
+
((point.latitude - start.latitude) * (end.latitude - start.latitude) +
|
|
527
|
+
(point.longitude - start.longitude) * (end.longitude - start.longitude)) / (ab * ab)
|
|
528
|
+
))
|
|
529
|
+
|
|
530
|
+
val projection = LatLng(
|
|
531
|
+
start.latitude + t * (end.latitude - start.latitude),
|
|
532
|
+
start.longitude + t * (end.longitude - start.longitude)
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
val proj = android.location.Location("").apply {
|
|
536
|
+
latitude = projection.latitude
|
|
537
|
+
longitude = projection.longitude
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return p.distanceTo(proj).toDouble()
|
|
541
|
+
}
|
|
542
|
+
|
|
459
543
|
fun clear() {
|
|
460
544
|
circles.values.forEach { it.remove() }
|
|
461
545
|
circles.clear()
|
|
@@ -469,6 +553,9 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
|
|
|
469
553
|
|
|
470
554
|
polygons.values.forEach { it.remove() }
|
|
471
555
|
polygons.clear()
|
|
556
|
+
polygonIdMap.clear()
|
|
557
|
+
|
|
558
|
+
polylineIdMap.clear()
|
|
472
559
|
}
|
|
473
560
|
|
|
474
561
|
/**
|
|
@@ -103,6 +103,22 @@ class CircleView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* 检查点击位置是否在圆形内
|
|
108
|
+
*/
|
|
109
|
+
fun checkPress(latLng: LatLng): Boolean {
|
|
110
|
+
circle?.let { c ->
|
|
111
|
+
if (c.contains(latLng)) {
|
|
112
|
+
onPress(mapOf(
|
|
113
|
+
"latitude" to latLng.latitude,
|
|
114
|
+
"longitude" to latLng.longitude
|
|
115
|
+
))
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
106
122
|
/**
|
|
107
123
|
* 移除圆形
|
|
108
124
|
*/
|
|
@@ -17,6 +17,7 @@ class PolygonView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
17
17
|
private var polygon: Polygon? = null
|
|
18
18
|
private var aMap: AMap? = null
|
|
19
19
|
private var points: List<LatLng> = emptyList()
|
|
20
|
+
private var strokeWidth: Float = 10f
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* 设置地图实例
|
|
@@ -65,8 +66,11 @@ class PolygonView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
65
66
|
* 设置边框宽度
|
|
66
67
|
*/
|
|
67
68
|
fun setStrokeWidth(width: Float) {
|
|
69
|
+
// Android 需要乘以屏幕密度以匹配 iOS 的视觉效果
|
|
70
|
+
val density = context.resources.displayMetrics.density
|
|
71
|
+
strokeWidth = width * density
|
|
68
72
|
polygon?.let {
|
|
69
|
-
it.strokeWidth =
|
|
73
|
+
it.strokeWidth = strokeWidth
|
|
70
74
|
} ?: createOrUpdatePolygon()
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -89,7 +93,7 @@ class PolygonView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
89
93
|
.addAll(points)
|
|
90
94
|
.fillColor(Color.argb(50, 0, 0, 255))
|
|
91
95
|
.strokeColor(Color.BLUE)
|
|
92
|
-
.strokeWidth(
|
|
96
|
+
.strokeWidth(strokeWidth)
|
|
93
97
|
|
|
94
98
|
polygon = map.addPolygon(options)
|
|
95
99
|
|
|
@@ -99,6 +103,22 @@ class PolygonView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
|
|
106
|
+
/**
|
|
107
|
+
* 检查点击位置是否在多边形内
|
|
108
|
+
*/
|
|
109
|
+
fun checkPress(latLng: LatLng): Boolean {
|
|
110
|
+
polygon?.let { poly ->
|
|
111
|
+
if (poly.contains(latLng)) {
|
|
112
|
+
onPress(mapOf(
|
|
113
|
+
"latitude" to latLng.latitude,
|
|
114
|
+
"longitude" to latLng.longitude
|
|
115
|
+
))
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
102
122
|
/**
|
|
103
123
|
* 移除多边形
|
|
104
124
|
*/
|
|
@@ -7,6 +7,8 @@ import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
|
7
7
|
import com.amap.api.maps.model.LatLng
|
|
8
8
|
import com.amap.api.maps.model.Polyline
|
|
9
9
|
import com.amap.api.maps.model.PolylineOptions
|
|
10
|
+
import com.amap.api.maps.model.PolylineOptions.LineCapType
|
|
11
|
+
import com.amap.api.maps.model.PolylineOptions.LineJoinType
|
|
10
12
|
import expo.modules.kotlin.AppContext
|
|
11
13
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
12
14
|
import expo.modules.kotlin.views.ExpoView
|
|
@@ -19,6 +21,10 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
19
21
|
private var polyline: Polyline? = null
|
|
20
22
|
private var aMap: AMap? = null
|
|
21
23
|
private var points: List<LatLng> = emptyList()
|
|
24
|
+
private var strokeWidth: Float = 10f
|
|
25
|
+
private var strokeColor: Int = Color.BLUE
|
|
26
|
+
private var isDotted: Boolean = false
|
|
27
|
+
private var isGeodesic: Boolean = false
|
|
22
28
|
private var textureUrl: String? = null
|
|
23
29
|
|
|
24
30
|
/**
|
|
@@ -50,8 +56,11 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
50
56
|
* 设置线宽
|
|
51
57
|
*/
|
|
52
58
|
fun setStrokeWidth(width: Float) {
|
|
59
|
+
// Android 需要乘以屏幕密度以匹配 iOS 的视觉效果
|
|
60
|
+
val density = context.resources.displayMetrics.density
|
|
61
|
+
strokeWidth = width * density
|
|
53
62
|
polyline?.let {
|
|
54
|
-
it.width =
|
|
63
|
+
it.width = strokeWidth
|
|
55
64
|
} ?: createOrUpdatePolyline()
|
|
56
65
|
}
|
|
57
66
|
|
|
@@ -59,6 +68,7 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
59
68
|
* 设置线条颜色
|
|
60
69
|
*/
|
|
61
70
|
fun setStrokeColor(color: Int) {
|
|
71
|
+
strokeColor = color
|
|
62
72
|
polyline?.let {
|
|
63
73
|
it.color = color
|
|
64
74
|
} ?: createOrUpdatePolyline()
|
|
@@ -67,19 +77,17 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
67
77
|
/**
|
|
68
78
|
* 设置是否虚线
|
|
69
79
|
*/
|
|
70
|
-
fun
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
} ?: createOrUpdatePolyline()
|
|
80
|
+
fun setDotted(dotted: Boolean) {
|
|
81
|
+
isDotted = dotted
|
|
82
|
+
createOrUpdatePolyline()
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
/**
|
|
77
|
-
*
|
|
86
|
+
* 设置是否绘制大地线
|
|
78
87
|
*/
|
|
79
|
-
fun
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
} ?: createOrUpdatePolyline()
|
|
88
|
+
fun setGeodesic(geodesic: Boolean) {
|
|
89
|
+
isGeodesic = geodesic
|
|
90
|
+
createOrUpdatePolyline()
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
/**
|
|
@@ -122,8 +130,14 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
122
130
|
if (points.isNotEmpty()) {
|
|
123
131
|
val options = PolylineOptions()
|
|
124
132
|
.addAll(points)
|
|
125
|
-
.width(
|
|
126
|
-
.color(
|
|
133
|
+
.width(strokeWidth)
|
|
134
|
+
.color(strokeColor)
|
|
135
|
+
.geodesic(isGeodesic)
|
|
136
|
+
|
|
137
|
+
// 设置虚线样式
|
|
138
|
+
if (isDotted) {
|
|
139
|
+
options.dottedLineType = PolylineOptions.DOTTEDLINE_TYPE_SQUARE
|
|
140
|
+
}
|
|
127
141
|
|
|
128
142
|
// 设置纹理
|
|
129
143
|
textureUrl?.let { url ->
|
|
@@ -164,14 +178,66 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
164
178
|
}
|
|
165
179
|
|
|
166
180
|
polyline = map.addPolyline(options)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 检查点击位置是否在折线附近
|
|
187
|
+
*/
|
|
188
|
+
fun checkPress(latLng: LatLng): Boolean {
|
|
189
|
+
polyline?.let { line ->
|
|
190
|
+
val threshold = 20.0 // 20米容差
|
|
191
|
+
val linePoints = line.points
|
|
192
|
+
if (linePoints.size < 2) return false
|
|
193
|
+
|
|
194
|
+
for (i in 0 until linePoints.size - 1) {
|
|
195
|
+
val distance = distanceToSegment(latLng, linePoints[i], linePoints[i + 1])
|
|
196
|
+
if (distance <= threshold) {
|
|
197
|
+
onPress(mapOf(
|
|
198
|
+
"latitude" to latLng.latitude,
|
|
199
|
+
"longitude" to latLng.longitude
|
|
200
|
+
))
|
|
201
|
+
return true
|
|
172
202
|
}
|
|
173
203
|
}
|
|
174
204
|
}
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private fun distanceToSegment(point: LatLng, start: LatLng, end: LatLng): Double {
|
|
209
|
+
val p = android.location.Location("").apply {
|
|
210
|
+
latitude = point.latitude
|
|
211
|
+
longitude = point.longitude
|
|
212
|
+
}
|
|
213
|
+
val a = android.location.Location("").apply {
|
|
214
|
+
latitude = start.latitude
|
|
215
|
+
longitude = start.longitude
|
|
216
|
+
}
|
|
217
|
+
val b = android.location.Location("").apply {
|
|
218
|
+
latitude = end.latitude
|
|
219
|
+
longitude = end.longitude
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
val ab = a.distanceTo(b).toDouble()
|
|
223
|
+
if (ab == 0.0) return a.distanceTo(p).toDouble()
|
|
224
|
+
|
|
225
|
+
val t = maxOf(0.0, minOf(1.0,
|
|
226
|
+
((point.latitude - start.latitude) * (end.latitude - start.latitude) +
|
|
227
|
+
(point.longitude - start.longitude) * (end.longitude - start.longitude)) / (ab * ab)
|
|
228
|
+
))
|
|
229
|
+
|
|
230
|
+
val projection = LatLng(
|
|
231
|
+
start.latitude + t * (end.latitude - start.latitude),
|
|
232
|
+
start.longitude + t * (end.longitude - start.longitude)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
val proj = android.location.Location("").apply {
|
|
236
|
+
latitude = projection.latitude
|
|
237
|
+
longitude = projection.longitude
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return p.distanceTo(proj).toDouble()
|
|
175
241
|
}
|
|
176
242
|
|
|
177
243
|
/**
|
|
@@ -27,6 +27,26 @@ declare class CircleEventManager {
|
|
|
27
27
|
trigger(circleId: string, eventType: keyof CircleEventCallbacks): void;
|
|
28
28
|
}
|
|
29
29
|
export declare const CircleEventContext: React.Context<CircleEventManager | null>;
|
|
30
|
+
type PolygonEventCallbacks = {
|
|
31
|
+
onPress?: () => void;
|
|
32
|
+
};
|
|
33
|
+
declare class PolygonEventManager {
|
|
34
|
+
private callbacks;
|
|
35
|
+
register(polygonId: string, callbacks: PolygonEventCallbacks): void;
|
|
36
|
+
unregister(polygonId: string): void;
|
|
37
|
+
trigger(polygonId: string, eventType: keyof PolygonEventCallbacks): void;
|
|
38
|
+
}
|
|
39
|
+
export declare const PolygonEventContext: React.Context<PolygonEventManager | null>;
|
|
40
|
+
type PolylineEventCallbacks = {
|
|
41
|
+
onPress?: () => void;
|
|
42
|
+
};
|
|
43
|
+
declare class PolylineEventManager {
|
|
44
|
+
private callbacks;
|
|
45
|
+
register(polylineId: string, callbacks: PolylineEventCallbacks): void;
|
|
46
|
+
unregister(polylineId: string): void;
|
|
47
|
+
trigger(polylineId: string, eventType: keyof PolylineEventCallbacks): void;
|
|
48
|
+
}
|
|
49
|
+
export declare const PolylineEventContext: React.Context<PolylineEventManager | null>;
|
|
30
50
|
/**
|
|
31
51
|
* 高德地图视图组件,提供地图操作API和覆盖物管理功能
|
|
32
52
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoGaodeMapView.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EAGV,MAAM,EAMP,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C,eAAO,MAAM,UAAU,0DAAuE,CAAC;AAG/F,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAA2C;IAE5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB;IAI1D,UAAU,CAAC,QAAQ,EAAE,MAAM;IAI3B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,EAAE,IAAI,CAAC,EAAE,GAAG;CAM5E;AAED,eAAO,MAAM,kBAAkB,0CAAuD,CAAC;AAGvF,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAA2C;IAE5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB;IAI1D,UAAU,CAAC,QAAQ,EAAE,MAAM;IAI3B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB;CAMhE;AAED,eAAO,MAAM,kBAAkB,0CAAuD,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoGaodeMapView.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EAGV,MAAM,EAMP,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C,eAAO,MAAM,UAAU,0DAAuE,CAAC;AAG/F,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAA2C;IAE5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB;IAI1D,UAAU,CAAC,QAAQ,EAAE,MAAM;IAI3B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,EAAE,IAAI,CAAC,EAAE,GAAG;CAM5E;AAED,eAAO,MAAM,kBAAkB,0CAAuD,CAAC;AAGvF,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAA2C;IAE5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB;IAI1D,UAAU,CAAC,QAAQ,EAAE,MAAM;IAI3B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB;CAMhE;AAED,eAAO,MAAM,kBAAkB,0CAAuD,CAAC;AAGvF,KAAK,qBAAqB,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,cAAM,mBAAmB;IACvB,OAAO,CAAC,SAAS,CAA4C;IAE7D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB;IAI5D,UAAU,CAAC,SAAS,EAAE,MAAM;IAI5B,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,qBAAqB;CAMlE;AAED,eAAO,MAAM,mBAAmB,2CAAwD,CAAC;AAGzF,KAAK,sBAAsB,GAAG;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,cAAM,oBAAoB;IACxB,OAAO,CAAC,SAAS,CAA6C;IAE9D,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,sBAAsB;IAI9D,UAAU,CAAC,UAAU,EAAE,MAAM;IAI7B,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,sBAAsB;CAMpE;AAED,eAAO,MAAM,oBAAoB,4CAAyD,CAAC;AAE3F;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,gBAAgB,iFAoSpB,CAAC;AAIH,eAAe,gBAAgB,CAAC"}
|