@rnmapbox/maps 10.3.0-beta.1 → 10.3.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.
Files changed (86) hide show
  1. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXMarkerViewContent.kt +55 -0
  2. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXMarkerViewContentManager.kt +7 -2
  3. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXMarkerViewManager.kt +0 -2
  4. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotation.kt +14 -1
  5. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt +11 -0
  6. package/android/src/main/java/com/rnmapbox/rnmbx/components/location/RNMBXNativeUserLocationManager.kt +25 -24
  7. package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt +3 -2
  8. package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt +57 -39
  9. package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt +0 -9
  10. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/RNMBXStyleFactory.kt +60 -0
  11. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphere.kt +4 -4
  12. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/atmosphere/RNMBXAtmosphereManager.kt +2 -1
  13. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/light/RNMBXLightManager.kt +2 -1
  14. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXSource.kt +2 -6
  15. package/android/src/main/java/com/rnmapbox/rnmbx/components/styles/terrain/RNMBXTerrainManager.kt +2 -1
  16. package/android/src/main/java/com/rnmapbox/rnmbx/events/FeatureClickEvent.java +5 -6
  17. package/android/src/main/java/com/rnmapbox/rnmbx/modules/RNMBXModule.kt +1 -0
  18. package/android/src/main/java/com/rnmapbox/rnmbx/modules/RNMBXSnapshotModule.kt +56 -18
  19. package/android/src/main/java/com/rnmapbox/rnmbx/utils/ConvertUtils.kt +0 -30
  20. package/android/src/main/java/com/rnmapbox/rnmbx/utils/extensions/Dynamic.kt +3 -1
  21. package/android/src/main/java/com/rnmapbox/rnmbx/utils/extensions/ReadableArray.kt +16 -14
  22. package/ios/RNMBX/RNMBXBackgroundLayer.swift +1 -1
  23. package/ios/RNMBX/RNMBXCalloutComponentView.mm +10 -0
  24. package/ios/RNMBX/RNMBXCircleLayer.swift +1 -1
  25. package/ios/RNMBX/RNMBXFillExtrusionLayer.swift +1 -1
  26. package/ios/RNMBX/RNMBXFillLayer.swift +1 -1
  27. package/ios/RNMBX/RNMBXHeatmapLayer.swift +1 -1
  28. package/ios/RNMBX/RNMBXHillshadeLayer.swift +1 -1
  29. package/ios/RNMBX/RNMBXLayer.swift +2 -2
  30. package/ios/RNMBX/RNMBXLineLayer.swift +1 -1
  31. package/ios/RNMBX/RNMBXMapView.swift +18 -1
  32. package/ios/RNMBX/RNMBXMapViewComponentView.mm +3 -0
  33. package/ios/RNMBX/RNMBXMapViewModule.mm +1 -1
  34. package/ios/RNMBX/RNMBXModelLayer.swift +1 -1
  35. package/ios/RNMBX/RNMBXModule.swift +1 -0
  36. package/ios/RNMBX/RNMBXPointAnnotation.swift +25 -3
  37. package/ios/RNMBX/RNMBXPointAnnotationComponentView.mm +1 -0
  38. package/ios/RNMBX/RNMBXRasterLayer.swift +1 -1
  39. package/ios/RNMBX/RNMBXRasterParticleLayer.swift +1 -1
  40. package/ios/RNMBX/RNMBXSkyLayer.swift +1 -1
  41. package/ios/RNMBX/RNMBXSnapshotModule.swift +3 -1
  42. package/ios/RNMBX/RNMBXStyle.swift +36 -0
  43. package/ios/RNMBX/RNMBXSymbolLayer.swift +1 -1
  44. package/lib/module/Mapbox.native.js.map +1 -1
  45. package/lib/module/components/MapView.js +95 -113
  46. package/lib/module/components/MapView.js.map +1 -1
  47. package/lib/module/components/MarkerView.js +93 -76
  48. package/lib/module/components/MarkerView.js.map +1 -1
  49. package/lib/module/components/UserLocation.js +2 -1
  50. package/lib/module/components/UserLocation.js.map +1 -1
  51. package/lib/module/modules/offline/offlineManager.js +2 -12
  52. package/lib/module/modules/offline/offlineManager.js.map +1 -1
  53. package/lib/module/specs/RNMBXMarkerViewContentNativeComponent.ts +13 -1
  54. package/lib/module/specs/RNMBXPointAnnotationNativeComponent.ts +1 -0
  55. package/lib/module/utils/styleMap.js +4 -0
  56. package/lib/module/utils/styleMap.js.map +1 -1
  57. package/lib/typescript/scripts/autogenHelpers/generateCodeWithEjs.d.mts.map +1 -1
  58. package/lib/typescript/src/Mapbox.native.d.ts +1 -1
  59. package/lib/typescript/src/Mapbox.native.d.ts.map +1 -1
  60. package/lib/typescript/src/components/Camera.d.ts +2 -2
  61. package/lib/typescript/src/components/Camera.d.ts.map +1 -1
  62. package/lib/typescript/src/components/MapView.d.ts +53 -41
  63. package/lib/typescript/src/components/MapView.d.ts.map +1 -1
  64. package/lib/typescript/src/components/MarkerView.d.ts +10 -17
  65. package/lib/typescript/src/components/MarkerView.d.ts.map +1 -1
  66. package/lib/typescript/src/components/UserLocation.d.ts.map +1 -1
  67. package/lib/typescript/src/modules/offline/offlineManager.d.ts.map +1 -1
  68. package/lib/typescript/src/specs/RNMBXMarkerViewContentNativeComponent.d.ts +6 -0
  69. package/lib/typescript/src/specs/RNMBXMarkerViewContentNativeComponent.d.ts.map +1 -1
  70. package/lib/typescript/src/specs/RNMBXPointAnnotationNativeComponent.d.ts +1 -0
  71. package/lib/typescript/src/specs/RNMBXPointAnnotationNativeComponent.d.ts.map +1 -1
  72. package/lib/typescript/src/utils/MapboxStyles.d.ts +16 -0
  73. package/lib/typescript/src/utils/MapboxStyles.d.ts.map +1 -1
  74. package/lib/typescript/src/utils/styleMap.d.ts.map +1 -1
  75. package/package.json +1 -1
  76. package/setup-jest.js +1 -1
  77. package/src/Mapbox.native.ts +5 -1
  78. package/src/components/Camera.tsx +2 -2
  79. package/src/components/MapView.tsx +137 -154
  80. package/src/components/MarkerView.tsx +118 -95
  81. package/src/components/UserLocation.tsx +3 -2
  82. package/src/modules/offline/offlineManager.ts +2 -14
  83. package/src/specs/RNMBXMarkerViewContentNativeComponent.ts +13 -1
  84. package/src/specs/RNMBXPointAnnotationNativeComponent.ts +1 -0
  85. package/src/utils/MapboxStyles.ts +18 -0
  86. package/src/utils/styleMap.ts +4 -0
@@ -1,13 +1,24 @@
1
1
  package com.rnmapbox.rnmbx.components.annotation
2
2
 
3
3
  import android.content.Context
4
+ import android.view.MotionEvent
4
5
  import android.view.View.MeasureSpec
5
6
  import android.view.ViewGroup
7
+ import com.facebook.react.bridge.Arguments
8
+ import com.facebook.react.bridge.ReactContext
9
+ import com.facebook.react.uimanager.UIManagerHelper
6
10
  import com.facebook.react.views.view.ReactViewGroup
11
+ import com.rnmapbox.rnmbx.components.camera.BaseEvent
7
12
 
8
13
  class RNMBXMarkerViewContent(context: Context): ReactViewGroup(context) {
9
14
  var inAdd: Boolean = false
10
15
 
16
+ // Track last reported translation to avoid feedback loop:
17
+ // Mapbox sets setTranslationX(512) → we fire event → JS sets transform:[{translateX:512}]
18
+ // → Fabric calls setTranslationX(512) again → same value → no re-fire.
19
+ private var lastReportedTx = Float.NaN
20
+ private var lastReportedTy = Float.NaN
21
+
11
22
  init {
12
23
  allowRenderingOutside()
13
24
  }
@@ -17,6 +28,50 @@ class RNMBXMarkerViewContent(context: Context): ReactViewGroup(context) {
17
28
  configureParentClipping()
18
29
  }
19
30
 
31
+ override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
32
+ // On ACTION_DOWN, tell the parent MapView not to intercept subsequent MOVE/UP
33
+ // events for pan/zoom recognition — that would send CANCEL to child Pressables
34
+ // and suppress onPress. Android resets the disallow flag on each new DOWN, so
35
+ // calling this once per gesture is sufficient. See maplibre-react-native#1289.
36
+ if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
37
+ parent?.requestDisallowInterceptTouchEvent(true)
38
+ }
39
+ return super.dispatchTouchEvent(ev)
40
+ }
41
+
42
+ override fun setTranslationX(translationX: Float) {
43
+ super.setTranslationX(translationX)
44
+ maybeFireAnnotationPositionEvent()
45
+ }
46
+
47
+ override fun setTranslationY(translationY: Float) {
48
+ super.setTranslationY(translationY)
49
+ maybeFireAnnotationPositionEvent()
50
+ }
51
+
52
+ private fun maybeFireAnnotationPositionEvent() {
53
+ val tx = translationX
54
+ val ty = translationY
55
+ // Dedup: skip if value unchanged (prevents feedback loop when Fabric
56
+ // re-applies the same transform prop back to setTranslationX/Y).
57
+ if (tx == lastReportedTx && ty == lastReportedTy) return
58
+ lastReportedTx = tx
59
+ lastReportedTy = ty
60
+
61
+ val reactContext = context as? ReactContext ?: return
62
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) ?: return
63
+ // Use getSurfaceId(view) — more reliable for Fabric than getSurfaceId(context)
64
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
65
+ dispatcher.dispatchEvent(
66
+ BaseEvent(surfaceId, id, "topAnnotationPosition",
67
+ Arguments.createMap().apply {
68
+ putDouble("x", tx.toDouble())
69
+ putDouble("y", ty.toDouble())
70
+ },
71
+ canCoalesce = true)
72
+ )
73
+ }
74
+
20
75
  private fun configureParentClipping() {
21
76
  val parent = parent
22
77
  if (parent is android.view.ViewGroup) {
@@ -2,13 +2,14 @@ package com.rnmapbox.rnmbx.components.annotation
2
2
 
3
3
  import com.facebook.react.bridge.ReactApplicationContext
4
4
  import com.facebook.react.uimanager.ThemedReactContext
5
- import com.facebook.react.uimanager.ViewGroupManager
6
5
  import com.facebook.react.viewmanagers.RNMBXMarkerViewContentManagerInterface
6
+ import com.rnmapbox.rnmbx.components.AbstractEventEmitter
7
7
 
8
8
 
9
9
  class RNMBXMarkerViewContentManager(reactApplicationContext: ReactApplicationContext) :
10
- ViewGroupManager<RNMBXMarkerViewContent>(),
10
+ AbstractEventEmitter<RNMBXMarkerViewContent>(reactApplicationContext),
11
11
  RNMBXMarkerViewContentManagerInterface<RNMBXMarkerView> {
12
+
12
13
  override fun getName(): String {
13
14
  return REACT_CLASS
14
15
  }
@@ -17,6 +18,10 @@ class RNMBXMarkerViewContentManager(reactApplicationContext: ReactApplicationCon
17
18
  return RNMBXMarkerViewContent(context)
18
19
  }
19
20
 
21
+ override fun customEvents(): Map<String, String> {
22
+ return mapOf("topAnnotationPosition" to "onAnnotationPosition")
23
+ }
24
+
20
25
  companion object {
21
26
  const val REACT_CLASS = "RNMBXMarkerViewContent"
22
27
  }
@@ -96,8 +96,6 @@ class RNMBXMarkerViewManager(reactApplicationContext: ReactApplicationContext) :
96
96
  }
97
97
  }
98
98
  }
99
-
100
-
101
99
  })
102
100
  }
103
101
  }
@@ -36,7 +36,7 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
36
36
  private val mTitle: String? = null
37
37
  private val mSnippet: String? = null
38
38
  private var mAnchor: Array<Float>? = null
39
- private val mIsSelected = false
39
+ private var mIsSelected = false
40
40
  private var mDraggable = false
41
41
  private var mChildView: View? = null
42
42
  private var mChildBitmap: Bitmap? = null
@@ -187,7 +187,19 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
187
187
  }
188
188
  }
189
189
 
190
+ fun setReactSelected(selected: Boolean) {
191
+ if (selected && !mIsSelected) {
192
+ pointAnnotations?.let {
193
+ it.deselectSelectedAnnotation()
194
+ it.selectAnnotation(this)
195
+ }
196
+ } else if (!selected && mIsSelected) {
197
+ pointAnnotations?.deselectAnnotation(this)
198
+ }
199
+ }
200
+
190
201
  fun doSelect(shouldSendEvent: Boolean) {
202
+ mIsSelected = true
191
203
  if (calloutView != null) {
192
204
  makeCallout()
193
205
  }
@@ -197,6 +209,7 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
197
209
  }
198
210
 
199
211
  fun doDeselect() {
212
+ mIsSelected = false
200
213
  mManager.handleEvent(makeEvent(false))
201
214
  mCalloutSymbol?.let { mCalloutSymbol ->
202
215
  pointAnnotations?.delete(mCalloutSymbol)
@@ -78,6 +78,17 @@ class RNMBXPointAnnotationManager(reactApplicationContext: ReactApplicationConte
78
78
  annotation.setAnchor(mapValue.getDouble("x").toFloat(), mapValue.getDouble("y").toFloat())
79
79
  }
80
80
 
81
+ override fun setSelected(
82
+ annotation: RNMBXPointAnnotation,
83
+ value: Dynamic
84
+ ) {
85
+ if (value.isNull) {
86
+ Logger.e("RNMBXPointAnnotationManager", "selected value is null")
87
+ return
88
+ }
89
+ annotation.setReactSelected(value.asBoolean())
90
+ }
91
+
81
92
  @ReactProp(name = "draggable")
82
93
  override fun setDraggable(annotation: RNMBXPointAnnotation, draggable: Dynamic) {
83
94
  annotation.setDraggable(draggable.asBoolean())
@@ -11,8 +11,11 @@ import com.google.gson.Gson
11
11
  import com.google.gson.stream.JsonWriter
12
12
  import com.mapbox.bindgen.Value
13
13
  import com.mapbox.maps.extension.style.expressions.generated.Expression
14
+ import com.rnmapbox.rnmbx.components.location.RNMBXNativeUserLocationManager.Companion.TAG
14
15
  import com.rnmapbox.rnmbx.rncompat.dynamic.*
15
16
  import com.rnmapbox.rnmbx.utils.Logger
17
+ import com.rnmapbox.rnmbx.utils.extensions.asBooleanOrNull
18
+ import com.rnmapbox.rnmbx.utils.extensions.asStringOrNull
16
19
  import com.rnmapbox.rnmbx.utils.extensions.toJsonArray
17
20
  import java.io.StringWriter
18
21
  import javax.annotation.Nonnull
@@ -27,51 +30,50 @@ class RNMBXNativeUserLocationManager : ViewGroupManager<RNMBXNativeUserLocation>
27
30
 
28
31
  @ReactProp(name = "androidRenderMode")
29
32
  override fun setAndroidRenderMode(userLocation: RNMBXNativeUserLocation, mode: Dynamic) {
30
- if (!mode.isNull) {
31
- Logger.e("RNMBXNativeUserLocationManager", "androidRenderMode is deprecated, use puckBearing instead")
32
- }
33
- when (mode.asString()) {
34
- "compass" -> userLocation.androidRenderMode = RenderMode.COMPASS
35
- "gps" -> userLocation.androidRenderMode = RenderMode.GPS
36
- "normal" -> userLocation.androidRenderMode = RenderMode.NORMAL
33
+ mode.asStringOrNull()?.let {
34
+ Logger.e(TAG, "androidRenderMode is deprecated, use puckBearing instead")
35
+
36
+ when (it) {
37
+ "compass" -> userLocation.androidRenderMode = RenderMode.COMPASS
38
+ "gps" -> userLocation.androidRenderMode = RenderMode.GPS
39
+ "normal" -> userLocation.androidRenderMode = RenderMode.NORMAL
40
+ }
37
41
  }
38
42
  }
39
43
 
40
44
  @ReactProp(name = "puckBearing")
41
45
  override fun setPuckBearing(view: RNMBXNativeUserLocation, value: Dynamic) {
42
- when (value?.asString()) {
46
+ when (value.asStringOrNull()) {
43
47
  "heading" -> view.puckBearing = PuckBearing.HEADING
44
48
  "course" -> view.puckBearing = PuckBearing.COURSE
45
49
  null -> Unit
46
50
  else ->
47
- Logger.e("RNMBXNativeUserLocationManager", "unexpected value for puckBearing: $value")
51
+ Logger.e(TAG, "unexpected value for puckBearing: $value")
48
52
  }
49
53
  }
50
54
 
51
55
  @ReactProp(name = "puckBearingEnabled")
52
56
  override fun setPuckBearingEnabled(view: RNMBXNativeUserLocation, value: Dynamic) {
53
- if (!value.isNull) {
54
- if (value.type == ReadableType.Boolean) {
55
- view.puckBearingEnabled = value.asBoolean()
56
- } else {
57
- Logger.e("RNMBXNativeUserLocationManager", "unexpected value for puckBearingEnabled: $value")
58
- }
57
+ value.asBooleanOrNull()?.let {
58
+ view.puckBearingEnabled = it
59
+ } ?: run {
60
+ Logger.e(TAG, "unexpected value for puckBearingEnabled: $value")
59
61
  }
60
62
  }
61
63
 
62
64
  @ReactProp(name = "topImage")
63
65
  override fun setTopImage(view: RNMBXNativeUserLocation, value: Dynamic?) {
64
- view.topImage = value?.asString()
66
+ view.topImage = value?.asStringOrNull()
65
67
  }
66
68
 
67
69
  @ReactProp(name = "bearingImage")
68
70
  override fun setBearingImage(view: RNMBXNativeUserLocation, value: Dynamic?) {
69
- view.bearingImage = value?.asString()
71
+ view.bearingImage = value?.asStringOrNull()
70
72
  }
71
73
 
72
74
  @ReactProp(name = "shadowImage")
73
75
  override fun setShadowImage(view: RNMBXNativeUserLocation, value: Dynamic?) {
74
- view.shadowImage = value?.asString()
76
+ view.shadowImage = value?.asStringOrNull()
75
77
  }
76
78
 
77
79
  @ReactProp(name = "scale", defaultDouble = 1.0)
@@ -98,11 +100,10 @@ class RNMBXNativeUserLocationManager : ViewGroupManager<RNMBXNativeUserLocation>
98
100
 
99
101
  companion object {
100
102
  const val REACT_CLASS = "RNMBXNativeUserLocation"
103
+ const val TAG = "RNMBXNativeUserLocationManager"
101
104
  }
102
105
  }
103
106
 
104
-
105
-
106
107
  fun _convertToDoubleValueOrExpression(value: Dynamic?, name: String): Value? {
107
108
  if (value == null) {
108
109
  return null
@@ -111,7 +112,7 @@ fun _convertToDoubleValueOrExpression(value: Dynamic?, name: String): Value? {
111
112
  ReadableType.Array -> {
112
113
  val array = value.asArray()
113
114
  if (array == null) {
114
- Logger.e("RNMBXNativeUserLocationManager", "_convertToDoubleValueOrExpression: array is null for $name")
115
+ Logger.e(TAG, "_convertToDoubleValueOrExpression: array is null for $name")
115
116
  return null
116
117
  }
117
118
  Expression.fromRaw(Gson().toJson(array.toJsonArray()))
@@ -120,10 +121,10 @@ fun _convertToDoubleValueOrExpression(value: Dynamic?, name: String): Value? {
120
121
  Value.valueOf(value.asDouble())
121
122
  else -> {
122
123
  Logger.e(
123
- "RNMBXNativeUserLocationmanager",
124
- "_convertToExpressionString: cannot convert $name to a double or double exrpession. $value"
124
+ TAG,
125
+ "_convertToExpressionString: cannot convert $name to a double or double expression. $value"
125
126
  )
126
- return null
127
+ null
127
128
  }
128
129
  }
129
130
  }
@@ -12,6 +12,7 @@ import com.rnmapbox.rnmbx.utils.ExpressionParser
12
12
  import com.rnmapbox.rnmbx.utils.ViewRefTag
13
13
  import com.rnmapbox.rnmbx.utils.ViewTagResolver
14
14
  import com.rnmapbox.rnmbx.utils.extensions.toCoordinate
15
+ import com.rnmapbox.rnmbx.utils.extensions.toScreenBox
15
16
  import com.rnmapbox.rnmbx.utils.extensions.toScreenCoordinate
16
17
  import com.rnmapbox.rnmbx.utils.extensions.toValueHashMap
17
18
 
@@ -116,7 +117,7 @@ class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver:
116
117
  val layerIds = ConvertUtils.toStringList(withLayerIDs)
117
118
 
118
119
  it.queryRenderedFeaturesAtPoint(
119
- ConvertUtils.toPointF(atPoint),
120
+ atPoint.toScreenCoordinate(),
120
121
  ExpressionParser.from(withFilter),
121
122
  if (layerIds.size == 0) null else layerIds,
122
123
  createCommandResponse(promise)
@@ -135,7 +136,7 @@ class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver:
135
136
  val layerIds = ConvertUtils.toStringList(withLayerIDs)
136
137
 
137
138
  it.queryRenderedFeaturesInRect(
138
- ConvertUtils.toRectF(withBBox),
139
+ if (withBBox.size() == 0) null else withBBox.toScreenBox(),
139
140
  ExpressionParser.from(withFilter),
140
141
  if (layerIds.size == 0) null else layerIds,
141
142
  createCommandResponse(promise)
@@ -2,11 +2,8 @@ package com.rnmapbox.rnmbx.components.mapview
2
2
 
3
3
  import android.content.Context
4
4
  import android.graphics.BitmapFactory
5
- import android.graphics.PointF
6
- import android.graphics.RectF
7
5
  import android.os.Handler
8
6
  import android.os.Looper
9
- import android.util.Log
10
7
  import android.view.Gravity
11
8
  import android.view.View
12
9
  import android.view.View.OnLayoutChangeListener
@@ -701,24 +698,26 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
701
698
  return true
702
699
  }
703
700
  }
704
- val screenPoint = mMap?.pixelForCoordinate(point)
701
+ val screenPointPx = mMap?.pixelForCoordinate(point)
705
702
  val touchableSources = allTouchableSources
706
703
  val hits = HashMap<String?, List<Feature?>?>()
707
- if (screenPoint != null) {
708
- handleTapInSources(LinkedList(touchableSources), screenPoint, hits, ArrayList(), object : HandleTap {
704
+ if (screenPointPx != null) {
705
+ handleTapInSources(LinkedList(touchableSources), screenPointPx, hits, ArrayList(), object : HandleTap {
709
706
  override fun run(hitTouchableSources: List<RNMBXSource<*>?>?, hits: Map<String?, List<Feature?>?>) {
707
+ /** Android Mapbox SDK returns screen coordinates in physical pixels, while JS expects density-independent pixels. */
708
+ val screenPointDp = toDp(screenPointPx)
710
709
  if (hits.size > 0) {
711
710
  val source = getTouchableSourceWithHighestZIndex(hitTouchableSources as List<RNMBXSource<*>>?)
712
711
  if (source != null && source.hasPressListener() && source.iD != null && source.iD in hits) {
713
712
  source.onPress(RNMBXSource.OnPressEvent(
714
713
  hits[source.iD] as List<Feature>,
715
714
  GeoJSONUtils.toLatLng(point),
716
- PointF(screenPoint.x.toFloat(), screenPoint.y.toFloat())
715
+ screenPointDp
717
716
  ))
718
717
  return
719
718
  }
720
719
  }
721
- val event = MapClickEvent(_this, LatLng(point), screenPoint)
720
+ val event = MapClickEvent(_this, LatLng(point), screenPointDp)
722
721
  mManager.handleEvent(event)
723
722
  }
724
723
 
@@ -732,9 +731,10 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
732
731
  if (pointAnnotations.getAndClearAnnotationDragged()) {
733
732
  return true
734
733
  }
735
- val screenPoint = mMap?.pixelForCoordinate(point)
736
- if (screenPoint != null) {
737
- val event = MapClickEvent(_this, LatLng(point), screenPoint, EventTypes.MAP_LONG_CLICK)
734
+ val screenPointPx = mMap?.pixelForCoordinate(point)
735
+ if (screenPointPx != null) {
736
+ val screenPointDp = toDp(screenPointPx)
737
+ val event = MapClickEvent(_this, LatLng(point), screenPointDp, EventTypes.MAP_LONG_CLICK)
738
738
  mManager.handleEvent(event)
739
739
  }
740
740
 
@@ -908,48 +908,61 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
908
908
  }
909
909
  }
910
910
 
911
- private fun getDisplayDensity(): Float {
912
- return mContext.resources.displayMetrics.density
911
+ private fun getDisplayDensity(): Double {
912
+ return mContext.resources.displayMetrics.density.toDouble()
913
913
  }
914
914
 
915
- fun getCoordinateFromView(pixel: ScreenCoordinate, response: CommandResponse) {
916
- val density: Float = getDisplayDensity()
917
- val screenCoordinate = ScreenCoordinate(pixel.x * density, pixel.y * density)
915
+ /** Converts a point from physical pixels to density-independent pixels. */
916
+ private fun toDp(pointPx: ScreenCoordinate): ScreenCoordinate {
917
+ val density = getDisplayDensity()
918
+ return ScreenCoordinate(pointPx.x / density, pointPx.y / density)
919
+ }
920
+
921
+ /** Converts a point from density-independent pixels to physical pixels. */
922
+ private fun toPx(pointDp: ScreenCoordinate): ScreenCoordinate {
923
+ val density = getDisplayDensity()
924
+ return ScreenCoordinate(pointDp.x * density, pointDp.y * density)
925
+ }
926
+
927
+ /** Converts a bounding box from density-independent pixels to physical pixels. */
928
+ private fun toPx(boxDp: ScreenBox): ScreenBox {
929
+ val density = getDisplayDensity()
930
+ return ScreenBox(
931
+ ScreenCoordinate(boxDp.min.x * density, boxDp.min.y * density),
932
+ ScreenCoordinate(boxDp.max.x * density, boxDp.max.y * density),
933
+ )
934
+ }
918
935
 
919
- val coordinate = mMap!!.coordinateForPixel(screenCoordinate)
936
+ fun getCoordinateFromView(pointDp: ScreenCoordinate, response: CommandResponse) {
937
+ val pointPx = toPx(pointDp)
938
+
939
+ val coordinate = mMap!!.coordinateForPixel(pointPx)
920
940
 
921
941
  response.success {
922
942
  it.putArray("coordinateFromView", coordinate.toReadableArray())
923
943
  }
924
944
  }
925
945
 
926
- fun getPointInView(coordinate: Point, response: CommandResponse) {
927
- val point = mMap!!.pixelForCoordinate(coordinate)
928
- val density = getDisplayDensity()
929
- val pointInView = PointF((point.x / density).toFloat(), (point.y / density).toFloat())
946
+ fun getPointInView(coordinates: Point, response: CommandResponse) {
947
+ val pointDp = toDp(mMap!!.pixelForCoordinate(coordinates))
930
948
 
931
949
  response.success {
932
950
  val array: WritableArray = WritableNativeArray()
933
- array.pushDouble(pointInView.x.toDouble())
934
- array.pushDouble(pointInView.y.toDouble())
951
+ array.pushDouble(pointDp.x)
952
+ array.pushDouble(pointDp.y)
935
953
  it.putArray("pointInView", array)
936
954
  }
937
955
  }
938
956
 
939
- fun queryRenderedFeaturesAtPoint(point: PointF, filter: Expression?, layerIDs: List<String>?, response: CommandResponse) {
957
+ fun queryRenderedFeaturesAtPoint(pointDp: ScreenCoordinate, filter: Expression?, layerIDs: List<String>?, response: CommandResponse) {
940
958
  if (mMap == null) {
941
959
  Logger.e("queryRenderedFeaturesAtPoint", "mapbox map is null")
942
960
  return
943
961
  }
944
- // JS sends point values in DIP (see getPointInView which divides by display density),
945
- // but Mapbox core expects screen pixel coordinates. Convert back to px here.
946
- val density: Float = getDisplayDensity()
947
- val screenCoordinate = ScreenCoordinate(
948
- (point.x * density).toDouble(),
949
- (point.y * density).toDouble()
950
- )
951
- val queryGeometry = RenderedQueryGeometry(screenCoordinate)
952
- val layers = layerIDs?.takeUnless { it.isEmpty() } ?: null;
962
+
963
+ val pointPx = toPx(pointDp)
964
+ val queryGeometry = RenderedQueryGeometry(pointPx)
965
+ val layers = layerIDs?.takeUnless { it.isEmpty() } ?: null
953
966
  val queryOptions = RenderedQueryOptions(layers, filter)
954
967
  mMap.queryRenderedFeatures(queryGeometry, queryOptions) { features ->
955
968
  if (features.isValue) {
@@ -966,14 +979,19 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
966
979
  }
967
980
  }
968
981
 
969
- fun queryRenderedFeaturesInRect(rect: RectF?, filter: Expression?, layerIDs: List<String>?, response: CommandResponse) {
982
+ fun queryRenderedFeaturesInRect(rectDp: ScreenBox?, filter: Expression?, layerIDs: List<String>?, response: CommandResponse) {
970
983
  val size = mMap.getMapOptions().size
971
- val screenBox = if (rect == null) ScreenBox(ScreenCoordinate(0.0, 0.0), ScreenCoordinate(size?.width!!.toDouble(), size?.height!!.toDouble())) else ScreenBox(
972
- ScreenCoordinate(rect.right.toDouble(), rect.bottom.toDouble() ),
973
- ScreenCoordinate(rect.left.toDouble(), rect.top.toDouble()),
974
- )
984
+
985
+ val rectPx: ScreenBox =
986
+ rectDp?.let { toPx(it) }
987
+ ?: ScreenBox(
988
+ ScreenCoordinate(0.0, 0.0),
989
+ /** No conversion needed, screen size is already returned in physical pixels. */
990
+ ScreenCoordinate(size?.width?.toDouble() ?: 0.0, size?.height?.toDouble() ?: 0.0)
991
+ )
992
+
975
993
  mMap.queryRenderedFeatures(
976
- RenderedQueryGeometry(screenBox),
994
+ RenderedQueryGeometry(rectPx),
977
995
  RenderedQueryOptions(layerIDs, filter)
978
996
  ) { features ->
979
997
  if (features.isValue) {
@@ -10,25 +10,16 @@ import com.facebook.react.uimanager.LayoutShadowNode
10
10
  import com.facebook.react.uimanager.ThemedReactContext
11
11
  import com.facebook.react.uimanager.annotations.ReactProp
12
12
  import com.rnmapbox.rnmbx.events.constants.EventKeys
13
- import com.facebook.react.common.MapBuilder
14
13
  import com.facebook.react.uimanager.ViewManagerDelegate
15
14
  import com.facebook.react.viewmanagers.RNMBXMapViewManagerDelegate
16
15
  import com.facebook.react.viewmanagers.RNMBXMapViewManagerInterface
17
- import com.mapbox.maps.MapInitOptions
18
16
  import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
19
17
  import com.mapbox.maps.plugin.gestures.gestures
20
- import com.mapbox.maps.plugin.logo.logo
21
- import com.rnmapbox.rnmbx.events.AndroidCallbackEvent
22
18
  import com.rnmapbox.rnmbx.events.constants.eventMapOf
23
- import com.rnmapbox.rnmbx.utils.ConvertUtils
24
- import com.rnmapbox.rnmbx.utils.ExpressionParser
25
19
  import com.rnmapbox.rnmbx.utils.Logger
26
20
  import com.rnmapbox.rnmbx.utils.ViewTagResolver
27
21
  import com.rnmapbox.rnmbx.utils.extensions.getAndLogIfNotBoolean
28
22
  import com.rnmapbox.rnmbx.utils.extensions.getAndLogIfNotDouble
29
- import com.rnmapbox.rnmbx.utils.extensions.toCoordinate
30
- import com.rnmapbox.rnmbx.utils.extensions.toRectF
31
- import com.rnmapbox.rnmbx.utils.extensions.toScreenCoordinate
32
23
  import java.lang.Exception
33
24
  import java.util.HashMap
34
25
 
@@ -175,6 +175,14 @@ object RNMBXStyleFactory {
175
175
  setLineGradient(layer, styleValue)
176
176
  "lineTrimOffset" ->
177
177
  setLineTrimOffset(layer, styleValue)
178
+ "lineBorderWidth" ->
179
+ setLineBorderWidth(layer, styleValue)
180
+ "lineBorderWidthTransition" ->
181
+ setLineBorderWidthTransition(layer, styleValue)
182
+ "lineBorderColor" ->
183
+ setLineBorderColor(layer, styleValue)
184
+ "lineBorderColorTransition" ->
185
+ setLineBorderColorTransition(layer, styleValue)
178
186
  "lineZOffset" ->
179
187
  setLineZOffset(layer, styleValue)
180
188
  "lineElevationReference" ->
@@ -1623,6 +1631,58 @@ object RNMBXStyleFactory {
1623
1631
  }
1624
1632
  }
1625
1633
 
1634
+ fun setLineBorderWidth(layer: LineLayer, styleValue: RNMBXStyleValue ) {
1635
+ if (styleValue.isExpression()) {
1636
+ val expression = styleValue.getExpression()
1637
+ if (expression != null) {
1638
+ layer.lineBorderWidth(expression)
1639
+ } else {
1640
+ Logger.e("RNMBXLine", "Expression for lineBorderWidth is null")
1641
+ }
1642
+ } else {
1643
+ val value = styleValue.getDouble(VALUE_KEY)
1644
+ if (value != null) {
1645
+ layer.lineBorderWidth(value)
1646
+ } else {
1647
+ Logger.e("RNMBXLine", "value for lineBorderWidth is null")
1648
+ }
1649
+ }
1650
+ }
1651
+
1652
+
1653
+ fun setLineBorderWidthTransition(layer: LineLayer, styleValue: RNMBXStyleValue) {
1654
+ val transition = styleValue.transition
1655
+ if (transition != null) {
1656
+ layer.lineBorderWidthTransition(transition);
1657
+ }
1658
+ }
1659
+
1660
+ fun setLineBorderColor(layer: LineLayer, styleValue: RNMBXStyleValue ) {
1661
+ if (styleValue.isExpression()) {
1662
+ val expression = styleValue.getExpression()
1663
+ if (expression != null) {
1664
+ layer.lineBorderColor(expression)
1665
+ } else {
1666
+ Logger.e("RNMBXLine", "Expression for lineBorderColor is null")
1667
+ }
1668
+ } else {
1669
+ val value = styleValue.getInt(VALUE_KEY)
1670
+ if (value != null) {
1671
+ layer.lineBorderColor(value)
1672
+ } else {
1673
+ Logger.e("RNMBXLine", "value for lineBorderColor is null")
1674
+ }
1675
+ }
1676
+ }
1677
+
1678
+
1679
+ fun setLineBorderColorTransition(layer: LineLayer, styleValue: RNMBXStyleValue) {
1680
+ val transition = styleValue.transition
1681
+ if (transition != null) {
1682
+ layer.lineBorderColorTransition(transition);
1683
+ }
1684
+ }
1685
+
1626
1686
  fun setLineZOffset(layer: LineLayer, styleValue: RNMBXStyleValue ) {
1627
1687
  if (styleValue.isExpression()) {
1628
1688
  val expression = styleValue.getExpression()
@@ -4,8 +4,7 @@ import android.content.Context
4
4
  import com.facebook.react.bridge.ReadableMap
5
5
  import com.mapbox.maps.MapboxMap
6
6
  import com.mapbox.maps.extension.style.atmosphere.generated.Atmosphere
7
- import com.mapbox.maps.extension.style.terrain.generated.Terrain
8
- import com.mapbox.maps.extension.style.terrain.generated.removeTerrain
7
+ import com.mapbox.maps.extension.style.atmosphere.generated.removeAtmosphere
9
8
  import com.rnmapbox.rnmbx.components.RemovalReason
10
9
  import com.rnmapbox.rnmbx.components.mapview.RNMBXMapView
11
10
  import com.rnmapbox.rnmbx.components.styles.RNMBXStyle
@@ -42,7 +41,8 @@ class RNMBXAtmosphere(context: Context?) : AbstractSourceConsumer(context) {
42
41
  }
43
42
 
44
43
  override fun removeFromMap(mapView: RNMBXMapView, reason: RemovalReason): Boolean {
45
- mapView.savedStyle?.let { it.removeTerrain() }
44
+ mapView.savedStyle?.let { it.removeAtmosphere() }
45
+ mAtmosphere = null
46
46
  mMap = null
47
47
  return super.removeFromMap(mapView, reason)
48
48
  }
@@ -55,7 +55,7 @@ class RNMBXAtmosphere(context: Context?) : AbstractSourceConsumer(context) {
55
55
  mAtmosphere?.also {
56
56
  RNMBXStyleFactory.setAtmosphereLayerStyle(
57
57
  it, RNMBXStyle(
58
- context, mReactStyle!!,
58
+ context, mReactStyle,
59
59
  mMap!!
60
60
  )
61
61
  )
@@ -2,6 +2,7 @@ package com.rnmapbox.rnmbx.components.styles.atmosphere
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
4
  import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.rnmapbox.rnmbx.utils.extensions.asMapOrNull
5
6
  import com.facebook.react.uimanager.ViewGroupManager
6
7
  import com.facebook.react.uimanager.ViewManagerDelegate
7
8
  import com.facebook.react.uimanager.annotations.ReactProp
@@ -30,7 +31,7 @@ class RNMBXAtmosphereManager : ViewGroupManager<RNMBXAtmosphere>(), RNMBXAtmosph
30
31
 
31
32
  @ReactProp(name = "reactStyle")
32
33
  override fun setReactStyle(atmosphere: RNMBXAtmosphere, reactStyle: Dynamic) {
33
- atmosphere.setReactStyle(reactStyle.asMap())
34
+ atmosphere.setReactStyle(reactStyle.asMapOrNull())
34
35
  }
35
36
 
36
37
  companion object {
@@ -2,6 +2,7 @@ package com.rnmapbox.rnmbx.components.styles.light
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
4
  import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.rnmapbox.rnmbx.utils.extensions.asMapOrNull
5
6
  import com.facebook.react.uimanager.ViewGroupManager
6
7
  import com.facebook.react.uimanager.annotations.ReactProp
7
8
  import com.facebook.react.viewmanagers.RNMBXLightManagerInterface
@@ -18,7 +19,7 @@ class RNMBXLightManager : ViewGroupManager<RNMBXLight>(),
18
19
 
19
20
  @ReactProp(name = "reactStyle")
20
21
  override fun setReactStyle(light: RNMBXLight, reactStyle: Dynamic) {
21
- light.setReactStyle(reactStyle.asMap())
22
+ light.setReactStyle(reactStyle.asMapOrNull())
22
23
  }
23
24
 
24
25
  companion object {