expo-gaode-map-navigation 2.0.12 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +29 -16
  2. package/android/build.gradle +8 -4
  3. package/android/src/main/AndroidManifest.xml +8 -0
  4. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +83 -15
  5. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +13 -3
  6. package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +36 -39
  7. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +5 -2
  8. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +122 -10
  9. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +2 -2
  10. package/android/src/main/java/expo/modules/gaodemap/map/search/ExpoGaodeMapSearchModule.kt +751 -0
  11. package/build/index.d.ts +26 -126
  12. package/build/index.d.ts.map +1 -1
  13. package/build/index.js +11 -612
  14. package/build/index.js.map +1 -1
  15. package/build/map/ExpoGaodeMapOfflineModule.d.ts +5 -0
  16. package/build/map/ExpoGaodeMapOfflineModule.d.ts.map +1 -1
  17. package/build/map/ExpoGaodeMapOfflineModule.js.map +1 -1
  18. package/build/map/components/overlays/HeatMap.d.ts.map +1 -1
  19. package/build/map/components/overlays/HeatMap.js +21 -2
  20. package/build/map/components/overlays/HeatMap.js.map +1 -1
  21. package/build/map/index.d.ts +3 -0
  22. package/build/map/index.d.ts.map +1 -1
  23. package/build/map/index.js +3 -0
  24. package/build/map/index.js.map +1 -1
  25. package/build/map/search/ExpoGaodeMapSearch.types.d.ts +340 -0
  26. package/build/map/search/ExpoGaodeMapSearch.types.d.ts.map +1 -0
  27. package/build/map/search/ExpoGaodeMapSearch.types.js +19 -0
  28. package/build/map/search/ExpoGaodeMapSearch.types.js.map +1 -0
  29. package/build/map/search/ExpoGaodeMapSearchModule.d.ts +74 -0
  30. package/build/map/search/ExpoGaodeMapSearchModule.d.ts.map +1 -0
  31. package/build/map/search/ExpoGaodeMapSearchModule.js +47 -0
  32. package/build/map/search/ExpoGaodeMapSearchModule.js.map +1 -0
  33. package/build/map/search/index.d.ts +156 -0
  34. package/build/map/search/index.d.ts.map +1 -0
  35. package/build/map/search/index.js +171 -0
  36. package/build/map/search/index.js.map +1 -0
  37. package/build/map/types/map-view.types.d.ts +4 -2
  38. package/build/map/types/map-view.types.d.ts.map +1 -1
  39. package/build/map/types/map-view.types.js.map +1 -1
  40. package/build/map/utils/ErrorHandler.js +11 -11
  41. package/build/map/utils/ErrorHandler.js.map +1 -1
  42. package/build/map/utils/OfflineMapManager.d.ts +4 -0
  43. package/build/map/utils/OfflineMapManager.d.ts.map +1 -1
  44. package/build/map/utils/OfflineMapManager.js +6 -0
  45. package/build/map/utils/OfflineMapManager.js.map +1 -1
  46. package/build/route-geometry.d.ts +13 -0
  47. package/build/route-geometry.d.ts.map +1 -0
  48. package/build/route-geometry.js +154 -0
  49. package/build/route-geometry.js.map +1 -0
  50. package/build/route-planning.d.ts +21 -0
  51. package/build/route-planning.d.ts.map +1 -0
  52. package/build/route-planning.js +67 -0
  53. package/build/route-planning.js.map +1 -0
  54. package/build/web-api-fallback.d.ts +5 -0
  55. package/build/web-api-fallback.d.ts.map +1 -0
  56. package/build/web-api-fallback.js +160 -0
  57. package/build/web-api-fallback.js.map +1 -0
  58. package/build/web-route-following.d.ts +3 -0
  59. package/build/web-route-following.d.ts.map +1 -0
  60. package/build/web-route-following.js +178 -0
  61. package/build/web-route-following.js.map +1 -0
  62. package/expo-module.config.json +4 -2
  63. package/ios/ExpoGaodeMapNaviView.swift +16 -17
  64. package/ios/ExpoGaodeMapNavigation.podspec +2 -1
  65. package/ios/map/ExpoGaodeMapOfflineModule.swift +61 -0
  66. package/ios/map/ExpoGaodeMapSearchModule.swift +773 -0
  67. package/ios/map/modules/LocationManager.swift +9 -3
  68. package/ios/map/overlays/PolylineView.swift +6 -12
  69. package/package.json +2 -2
  70. package/plugin/build/withGaodeMap.js +12 -0
  71. package/android/src/main/java/expo/modules/gaodemap/navigation/managers/RouteCalculator.kt +0 -173
@@ -1,21 +1,27 @@
1
1
  package expo.modules.gaodemap.map.overlays
2
2
 
3
3
  import android.content.Context
4
+ import android.graphics.Color
4
5
  import android.os.Looper
5
6
  import android.util.Log
6
7
  import com.amap.api.maps.AMap
8
+ import com.amap.api.maps.CameraUpdateFactory
9
+ import com.amap.api.maps.model.Gradient
10
+ import com.amap.api.maps.model.HeatmapTileProvider
7
11
  import com.amap.api.maps.model.LatLng
8
12
  import com.amap.api.maps.model.TileOverlay
9
13
  import com.amap.api.maps.model.TileOverlayOptions
10
- import com.amap.api.maps.model.HeatmapTileProvider
11
- import com.amap.api.maps.CameraUpdateFactory
14
+ import com.amap.api.maps.model.WeightedLatLng
12
15
  import expo.modules.kotlin.AppContext
13
16
  import expo.modules.kotlin.views.ExpoView
17
+ import expo.modules.gaodemap.map.utils.LatLngParser
14
18
  import java.util.concurrent.ExecutorService
15
19
  import java.util.concurrent.Executors
16
- import expo.modules.gaodemap.map.utils.LatLngParser
17
20
 
18
21
  class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
22
+ private companion object {
23
+ const val TAG = "HeatMapView"
24
+ }
19
25
 
20
26
  private val executor: ExecutorService = Executors.newSingleThreadExecutor()
21
27
  private val applyUpdateRunnable = Runnable { applyUpdateOnMain() }
@@ -25,9 +31,10 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
25
31
 
26
32
  private var heatmapOverlay: TileOverlay? = null
27
33
  private var aMap: AMap? = null
28
- private var dataList: MutableList<LatLng> = mutableListOf()
34
+ private var dataList: MutableList<WeightedLatLng> = mutableListOf()
29
35
  private var radius: Int = 50
30
36
  private var opacity: Double = 0.6
37
+ private var gradient: Gradient? = null
31
38
 
32
39
  /**
33
40
  * 设置地图实例
@@ -36,6 +43,7 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
36
43
  fun setMap(map: AMap) {
37
44
  aMap = map
38
45
  needsRebuild = true
46
+ Log.d(TAG, "setMap: map attached")
39
47
  scheduleUpdate()
40
48
  }
41
49
 
@@ -46,7 +54,8 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
46
54
  */
47
55
  fun setData(data: List<Any>?) {
48
56
  dataList.clear()
49
- dataList.addAll(LatLngParser.parseLatLngList(data))
57
+ dataList.addAll(parseWeightedLatLngList(data))
58
+ Log.d(TAG, "setData: raw=${data?.size ?: 0}, parsed=${dataList.size}, ${formatPointStats(dataList)}")
50
59
  needsRebuild = true
51
60
  scheduleUpdate()
52
61
  }
@@ -56,6 +65,7 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
56
65
  */
57
66
  fun setRadius(radiusValue: Int) {
58
67
  radius = radiusValue
68
+ Log.d(TAG, "setRadius: $radiusValue")
59
69
  needsRebuild = true
60
70
  scheduleUpdate()
61
71
  }
@@ -65,10 +75,20 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
65
75
  */
66
76
  fun setOpacity(opacityValue: Double) {
67
77
  opacity = opacityValue
68
- applyOverlayOpacity()
78
+ Log.d(TAG, "setOpacity: $opacityValue")
79
+ needsRebuild = true
80
+ scheduleUpdate()
81
+ }
82
+
83
+ fun setGradient(gradientValue: Map<String, Any>?) {
84
+ gradient = parseGradient(gradientValue)
85
+ Log.d(TAG, "setGradient: hasGradient=${gradient != null}, raw=${gradientValue != null}")
86
+ needsRebuild = true
87
+ scheduleUpdate()
69
88
  }
70
89
 
71
90
  fun setVisible(visibleValue: Boolean) {
91
+ Log.d(TAG, "setVisible: $visibleValue, points=${dataList.size}, hasOverlay=${heatmapOverlay != null}, needsRebuild=$needsRebuild")
72
92
  if (!visibleValue) {
73
93
  visible = false
74
94
  updateToken += 1
@@ -95,6 +115,7 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
95
115
  private fun scheduleUpdate() {
96
116
  updateToken += 1
97
117
  removeCallbacks(applyUpdateRunnable)
118
+ Log.d(TAG, "scheduleUpdate: token=$updateToken, mapAttached=${aMap != null}, visible=$visible, points=${dataList.size}")
98
119
  postDelayed(applyUpdateRunnable, 32)
99
120
  }
100
121
 
@@ -142,8 +163,11 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
142
163
  val map = aMap ?: return
143
164
  val token = updateToken
144
165
  val pointsSnapshot = ArrayList(dataList)
166
+ val latLngSnapshot = pointsSnapshot.map { it.latLng }
145
167
  val radiusValue = radius.coerceIn(10, 200)
146
168
  val opacityValue = opacity.coerceIn(0.0, 1.0)
169
+ val gradientValue = gradient
170
+ Log.d(TAG, "applyUpdate: token=$token, visible=$visible, points=${pointsSnapshot.size}, radius=$radiusValue, opacity=$opacityValue, gradient=${gradientValue != null}, ${formatPointStats(pointsSnapshot)}")
147
171
 
148
172
  if (!visible) {
149
173
  applyOverlayVisibility()
@@ -151,6 +175,7 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
151
175
  }
152
176
 
153
177
  if (pointsSnapshot.isEmpty()) {
178
+ Log.w(TAG, "applyUpdate: no valid heatmap points, removing overlay")
154
179
  heatmapOverlay?.remove()
155
180
  heatmapOverlay = null
156
181
  return
@@ -164,19 +189,25 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
164
189
 
165
190
  executor.execute {
166
191
  try {
167
- val provider = HeatmapTileProvider.Builder()
168
- .data(pointsSnapshot)
192
+ val builder = HeatmapTileProvider.Builder()
193
+ .data(latLngSnapshot)
169
194
  .radius(radiusValue)
170
- .build()
195
+
196
+ gradientValue?.let { builder.gradient(it) }
197
+
198
+ val provider = builder.build()
171
199
 
172
200
  post {
173
201
  if (token != updateToken) {
202
+ Log.d(TAG, "addOverlay skipped: stale token=$token, current=$updateToken")
174
203
  return@post
175
204
  }
176
205
  if (aMap !== map) {
206
+ Log.d(TAG, "addOverlay skipped: map instance changed")
177
207
  return@post
178
208
  }
179
209
  if (!visible) {
210
+ Log.d(TAG, "addOverlay skipped: hidden")
180
211
  return@post
181
212
  }
182
213
 
@@ -200,9 +231,10 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
200
231
  applyOverlayVisibility()
201
232
  applyOverlayOpacity()
202
233
  forceRefresh()
234
+ Log.i(TAG, "addOverlay success: id=${runCatching { heatmapOverlay?.id }.getOrNull()}, points=${pointsSnapshot.size}, radius=$radiusValue, opacity=$opacityValue")
203
235
  }
204
236
  } catch (t: Throwable) {
205
- Log.e("HeatMapView", "Failed to build heatmap", t)
237
+ Log.e(TAG, "Failed to build heatmap", t)
206
238
  }
207
239
  }
208
240
  }
@@ -217,11 +249,91 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
217
249
  fun removeHeatMap() {
218
250
  updateToken += 1
219
251
  removeCallbacks(applyUpdateRunnable)
252
+ Log.d(TAG, "removeHeatMap")
220
253
  heatmapOverlay?.remove()
221
254
  heatmapOverlay = null
222
255
  dataList.clear()
223
256
  needsRebuild = true
224
257
  }
258
+
259
+ private fun parseWeightedLatLngList(data: Any?): List<WeightedLatLng> {
260
+ if (data == null || data !is List<*>) return emptyList()
261
+
262
+ val result = mutableListOf<WeightedLatLng>()
263
+ for (item in data) {
264
+ val point = parseWeightedLatLng(item)
265
+ if (point != null) {
266
+ result.add(point)
267
+ } else if (item is List<*>) {
268
+ result.addAll(parseWeightedLatLngList(item))
269
+ }
270
+ }
271
+ return result
272
+ }
273
+
274
+ private fun parseWeightedLatLng(data: Any?): WeightedLatLng? {
275
+ val latLng = LatLngParser.parseLatLng(data) ?: return null
276
+ val intensity = when (data) {
277
+ is Map<*, *> -> listOf(data["intensity"], data["weight"], data["count"], data["value"])
278
+ .firstOrNull { it is Number }
279
+ is List<*> -> data.getOrNull(2)
280
+ else -> null
281
+ }
282
+ val weight = ((intensity as? Number)?.toDouble() ?: 1.0).takeIf { it.isFinite() && it > 0.0 } ?: 1.0
283
+ return WeightedLatLng(latLng, weight)
284
+ }
285
+
286
+ private fun parseGradient(gradientValue: Map<String, Any>?): Gradient? {
287
+ if (gradientValue == null) return null
288
+ val rawColors = gradientValue["colors"] as? List<*> ?: return null
289
+ val rawStartPoints = gradientValue["startPoints"] as? List<*> ?: return null
290
+ if (rawColors.size < 2 || rawColors.size != rawStartPoints.size) {
291
+ Log.w(TAG, "parseGradient ignored: colors=${rawColors.size}, startPoints=${rawStartPoints.size}")
292
+ return null
293
+ }
294
+
295
+ val colors = IntArray(rawColors.size)
296
+ val startPoints = FloatArray(rawStartPoints.size)
297
+ for (index in rawColors.indices) {
298
+ val color = parseColor(rawColors[index]) ?: run {
299
+ Log.w(TAG, "parseGradient ignored: invalid color at index=$index, value=${rawColors[index]}")
300
+ return null
301
+ }
302
+ val startPoint = (rawStartPoints[index] as? Number)?.toFloat() ?: run {
303
+ Log.w(TAG, "parseGradient ignored: invalid startPoint at index=$index, value=${rawStartPoints[index]}")
304
+ return null
305
+ }
306
+ colors[index] = color
307
+ startPoints[index] = startPoint.coerceIn(0f, 1f)
308
+ }
309
+ return Gradient(colors, startPoints)
310
+ }
311
+
312
+ private fun parseColor(value: Any?): Int? {
313
+ return when (value) {
314
+ is Number -> value.toInt()
315
+ is String -> runCatching { Color.parseColor(value) }.getOrNull()
316
+ else -> null
317
+ }
318
+ }
319
+
320
+ private fun formatPointStats(points: List<WeightedLatLng>): String {
321
+ if (points.isEmpty()) return "bounds=empty"
322
+ var minLat = Double.POSITIVE_INFINITY
323
+ var maxLat = Double.NEGATIVE_INFINITY
324
+ var minLng = Double.POSITIVE_INFINITY
325
+ var maxLng = Double.NEGATIVE_INFINITY
326
+ var totalIntensity = 0.0
327
+ points.forEach { point ->
328
+ val latLng: LatLng = point.latLng
329
+ minLat = minOf(minLat, latLng.latitude)
330
+ maxLat = maxOf(maxLat, latLng.latitude)
331
+ minLng = minOf(minLng, latLng.longitude)
332
+ maxLng = maxOf(maxLng, latLng.longitude)
333
+ totalIntensity += point.intensity
334
+ }
335
+ return "bounds=[$minLat,$minLng]-[$maxLat,$maxLng], totalIntensity=$totalIntensity"
336
+ }
225
337
 
226
338
  override fun onDetachedFromWindow() {
227
339
  super.onDetachedFromWindow()
@@ -27,8 +27,8 @@ class HeatMapViewModule : Module() {
27
27
  view.setOpacity(opacity)
28
28
  }
29
29
 
30
- Prop<Map<String, Any>?>("gradient") { _: HeatMapView, _ ->
31
- // iOS only, ignore on Android
30
+ Prop<Map<String, Any>?>("gradient") { view: HeatMapView, gradient ->
31
+ view.setGradient(gradient)
32
32
  }
33
33
 
34
34
  Prop<Boolean>("allowRetinaAdapting") { _: HeatMapView, _ ->