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