@rnmapbox/maps 10.0.0-beta.44 → 10.0.0-beta.45

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 (34) hide show
  1. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java +0 -2
  2. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.kt +162 -51
  3. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.kt +10 -0
  4. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.kt +6 -6
  5. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraStop.kt +5 -1
  6. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt +22 -2
  7. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +17 -19
  8. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt +1 -1
  9. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.kt +2 -1
  10. package/docs/MapboxGL.md +1 -1
  11. package/docs/MarkerView.md +17 -10
  12. package/docs/PointAnnotation.md +1 -1
  13. package/docs/SymbolLayer.md +1 -1
  14. package/docs/docs.json +116 -102
  15. package/index.d.ts +1 -0
  16. package/ios/RCTMGL-v10/RCTLog.swift +5 -5
  17. package/ios/RCTMGL-v10/RCTMGLMapViewManager.swift +2 -2
  18. package/ios/RCTMGL-v10/RCTMGLMarkerView.swift +186 -105
  19. package/ios/RCTMGL-v10/RCTMGLMarkerViewManager.m +2 -1
  20. package/ios/RCTMGL-v10/RCTMGLShapeSourceManager.swift +1 -1
  21. package/ios/RCTMGL-v10/RCTMGLUtils.swift +1 -1
  22. package/ios/RCTMGL-v10/RCTMGLVectorLayer.swift +1 -1
  23. package/javascript/components/AbstractLayer.tsx +6 -3
  24. package/javascript/components/MarkerView.tsx +81 -77
  25. package/javascript/components/PointAnnotation.tsx +1 -1
  26. package/javascript/components/SymbolLayer.tsx +2 -2
  27. package/javascript/utils/index.d.ts +3 -3
  28. package/package.json +1 -1
  29. package/scripts/autogenHelpers/DocJSONBuilder.js +17 -1
  30. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewWrapper.kt +0 -8
  31. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewWrapperManager.kt +0 -21
  32. package/ios/RCTMGL-v10/RCTMGLMarkerViewWrapper.swift +0 -24
  33. package/ios/RCTMGL-v10/RCTMGLMarkerViewWrapperManager.m +0 -8
  34. package/ios/RCTMGL-v10/RCTMGLMarkerViewWrapperManager.swift +0 -14
package/docs/docs.json CHANGED
@@ -1,4 +1,98 @@
1
1
  {
2
+ "Annotation": {
3
+ "description": "",
4
+ "displayName": "Annotation",
5
+ "methods": [
6
+ {
7
+ "name": "onPress",
8
+ "docblock": null,
9
+ "modifiers": [],
10
+ "params": [],
11
+ "returns": null
12
+ },
13
+ {
14
+ "name": "symbolStyle",
15
+ "docblock": null,
16
+ "modifiers": [
17
+ "get"
18
+ ],
19
+ "params": [],
20
+ "returns": null
21
+ }
22
+ ],
23
+ "props": [
24
+ {
25
+ "name": "id",
26
+ "required": true,
27
+ "type": "string",
28
+ "default": "none",
29
+ "description": "FIX ME NO DESCRIPTION"
30
+ },
31
+ {
32
+ "name": "animated",
33
+ "required": false,
34
+ "type": "bool",
35
+ "default": "false",
36
+ "description": "FIX ME NO DESCRIPTION"
37
+ },
38
+ {
39
+ "name": "animationDuration",
40
+ "required": false,
41
+ "type": "number",
42
+ "default": "1000",
43
+ "description": "FIX ME NO DESCRIPTION"
44
+ },
45
+ {
46
+ "name": "animationEasingFunction",
47
+ "required": false,
48
+ "type": "func",
49
+ "default": "Easing.linear",
50
+ "description": "FIX ME NO DESCRIPTION"
51
+ },
52
+ {
53
+ "name": "coordinates",
54
+ "required": false,
55
+ "type": {
56
+ "name": "array",
57
+ "value": {
58
+ "type": "number"
59
+ }
60
+ },
61
+ "default": "none",
62
+ "description": "FIX ME NO DESCRIPTION"
63
+ },
64
+ {
65
+ "name": "onPress",
66
+ "required": false,
67
+ "type": "func",
68
+ "default": "none",
69
+ "description": "FIX ME NO DESCRIPTION"
70
+ },
71
+ {
72
+ "name": "children",
73
+ "required": false,
74
+ "type": "any",
75
+ "default": "none",
76
+ "description": "FIX ME NO DESCRIPTION"
77
+ },
78
+ {
79
+ "name": "style",
80
+ "required": false,
81
+ "type": "any",
82
+ "default": "none",
83
+ "description": "FIX ME NO DESCRIPTION"
84
+ },
85
+ {
86
+ "name": "icon",
87
+ "required": false,
88
+ "type": "union",
89
+ "default": "none",
90
+ "description": "FIX ME NO DESCRIPTION"
91
+ }
92
+ ],
93
+ "fileNameWithExt": "Annotation.js",
94
+ "name": "Annotation"
95
+ },
2
96
  "Atmosphere": {
3
97
  "description": "",
4
98
  "displayName": "Atmosphere",
@@ -3166,7 +3260,7 @@
3166
3260
  "name": "MapView"
3167
3261
  },
3168
3262
  "MarkerView": {
3169
- "description": "MarkerView allows you to place a interactive react native marker to the map.\n\nIf you have static view consider using PointAnnotation or SymbolLayer they'll offer much better performance\n.\nThis is based on [MakerView plugin](https://docs.mapbox.com/android/plugins/overview/markerview/) on Android\nand PointAnnotation on iOS.",
3263
+ "description": "MarkerView represents an interactive React Native marker on the map.\n\nIf you have static views, consider using PointAnnotation or SymbolLayer to display\nan image, as they'll offer much better performance. Mapbox suggests using this\ncomponent for a maximum of around 100 views displayed at one time.\n\nThis is implemented with view annotations on [Android](https://docs.mapbox.com/android/maps/guides/annotations/view-annotations/)\nand [iOS](https://docs.mapbox.com/ios/maps/guides/annotations/view-annotations).\n\nThis component has no dedicated `onPress` method. Instead, you should handle gestures\nwith the React views passed in as `children`.",
3170
3264
  "displayName": "MarkerView",
3171
3265
  "methods": [],
3172
3266
  "props": [
@@ -3175,7 +3269,7 @@
3175
3269
  "required": true,
3176
3270
  "type": "tuple",
3177
3271
  "default": "none",
3178
- "description": "The center point (specified as a map coordinate) of the marker.\nSee also #anchor."
3272
+ "description": "The center point (specified as a map coordinate) of the marker."
3179
3273
  },
3180
3274
  {
3181
3275
  "name": "anchor",
@@ -3188,26 +3282,40 @@
3188
3282
  "required": true,
3189
3283
  "type": "number",
3190
3284
  "default": "none",
3191
- "description": "`x` of anchor"
3285
+ "description": "FIX ME NO DESCRIPTION"
3192
3286
  },
3193
3287
  {
3194
3288
  "name": "y",
3195
3289
  "required": true,
3196
3290
  "type": "number",
3197
3291
  "default": "none",
3198
- "description": "`y` of anchor"
3292
+ "description": "FIX ME NO DESCRIPTION"
3199
3293
  }
3200
3294
  ]
3201
3295
  },
3202
3296
  "default": "{ x: 0.5, y: 0.5 }",
3203
- "description": "Specifies the anchor being set on a particular point of the annotation.\nThe anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0],\nwhere (0, 0) is the top-left corner of the image, and (1, 1) is the bottom-right corner.\nNote this is only for custom annotations not the default pin view.\nDefaults to the center of the view."
3297
+ "description": "Any coordinate between (0, 0) and (1, 1), where (0, 0) is the top-left corner of\nthe view, and (1, 1) is the bottom-right corner. Defaults to the center at (0.5, 0.5)."
3298
+ },
3299
+ {
3300
+ "name": "allowOverlap",
3301
+ "required": false,
3302
+ "type": "boolean",
3303
+ "default": "false",
3304
+ "description": "@v10\n\nWhether or not nearby markers on the map should all be displayed. If false, adjacent\nmarkers will 'collapse' and only one will be shown. Defaults to false."
3305
+ },
3306
+ {
3307
+ "name": "isSelected",
3308
+ "required": false,
3309
+ "type": "boolean",
3310
+ "default": "false",
3311
+ "description": "FIX ME NO DESCRIPTION"
3204
3312
  },
3205
3313
  {
3206
3314
  "name": "children",
3207
3315
  "required": true,
3208
3316
  "type": "ReactReactElement",
3209
3317
  "default": "none",
3210
- "description": "Expects one child - can be container with multiple elements"
3318
+ "description": "One or more valid React Native views."
3211
3319
  }
3212
3320
  ],
3213
3321
  "fileNameWithExt": "MarkerView.tsx",
@@ -3237,7 +3345,7 @@
3237
3345
  "name": "NativeUserLocation"
3238
3346
  },
3239
3347
  "PointAnnotation": {
3240
- "description": "PointAnnotation represents a one-dimensional shape located at a single geographical coordinate.\n\nConsider using ShapeSource and SymbolLayer instead, if you have many points and you have static images,\nthey'll offer much better performance.\n\nIf you need interactive views please use MarkerView,\nas with PointAnnotation on Android child views are rendered onto a bitmap for better performance.",
3348
+ "description": "PointAnnotation represents a one-dimensional shape located at a single geographical coordinate.\n\nConsider using ShapeSource and SymbolLayer instead, if you have many points and you have static images,\nthey'll offer much better performance.\n\nIf you need interactive views please use MarkerView,\nas with PointAnnotation child views are rendered onto a bitmap",
3241
3349
  "displayName": "PointAnnotation",
3242
3350
  "methods": [
3243
3351
  {
@@ -4381,7 +4489,7 @@
4381
4489
  {
4382
4490
  "name": "filter",
4383
4491
  "required": false,
4384
- "type": "Array",
4492
+ "type": "Expression",
4385
4493
  "default": "none",
4386
4494
  "description": "Filter only the features in the source layer that satisfy a condition that you define"
4387
4495
  },
@@ -6117,100 +6225,6 @@
6117
6225
  "fileNameWithExt": "VectorSource.js",
6118
6226
  "name": "VectorSource"
6119
6227
  },
6120
- "Annotation": {
6121
- "description": "",
6122
- "displayName": "Annotation",
6123
- "methods": [
6124
- {
6125
- "name": "onPress",
6126
- "docblock": null,
6127
- "modifiers": [],
6128
- "params": [],
6129
- "returns": null
6130
- },
6131
- {
6132
- "name": "symbolStyle",
6133
- "docblock": null,
6134
- "modifiers": [
6135
- "get"
6136
- ],
6137
- "params": [],
6138
- "returns": null
6139
- }
6140
- ],
6141
- "props": [
6142
- {
6143
- "name": "id",
6144
- "required": true,
6145
- "type": "string",
6146
- "default": "none",
6147
- "description": "FIX ME NO DESCRIPTION"
6148
- },
6149
- {
6150
- "name": "animated",
6151
- "required": false,
6152
- "type": "bool",
6153
- "default": "false",
6154
- "description": "FIX ME NO DESCRIPTION"
6155
- },
6156
- {
6157
- "name": "animationDuration",
6158
- "required": false,
6159
- "type": "number",
6160
- "default": "1000",
6161
- "description": "FIX ME NO DESCRIPTION"
6162
- },
6163
- {
6164
- "name": "animationEasingFunction",
6165
- "required": false,
6166
- "type": "func",
6167
- "default": "Easing.linear",
6168
- "description": "FIX ME NO DESCRIPTION"
6169
- },
6170
- {
6171
- "name": "coordinates",
6172
- "required": false,
6173
- "type": {
6174
- "name": "array",
6175
- "value": {
6176
- "type": "number"
6177
- }
6178
- },
6179
- "default": "none",
6180
- "description": "FIX ME NO DESCRIPTION"
6181
- },
6182
- {
6183
- "name": "onPress",
6184
- "required": false,
6185
- "type": "func",
6186
- "default": "none",
6187
- "description": "FIX ME NO DESCRIPTION"
6188
- },
6189
- {
6190
- "name": "children",
6191
- "required": false,
6192
- "type": "any",
6193
- "default": "none",
6194
- "description": "FIX ME NO DESCRIPTION"
6195
- },
6196
- {
6197
- "name": "style",
6198
- "required": false,
6199
- "type": "any",
6200
- "default": "none",
6201
- "description": "FIX ME NO DESCRIPTION"
6202
- },
6203
- {
6204
- "name": "icon",
6205
- "required": false,
6206
- "type": "union",
6207
- "default": "none",
6208
- "description": "FIX ME NO DESCRIPTION"
6209
- }
6210
- ],
6211
- "fileNameWithExt": "Annotation.js",
6212
- "name": "Annotation"
6213
- },
6214
6228
  "offlineManager": {
6215
6229
  "name": "offlineManager",
6216
6230
  "fileNameWithExt": "offlineManager.js",
package/index.d.ts CHANGED
@@ -153,6 +153,7 @@ declare namespace MapboxGL {
153
153
  const PointAnnotation = _PointAnnotation;
154
154
  const SymbolLayer = _SymbolLayer;
155
155
  const ShapeSource = _ShapeSource;
156
+ type ShapeSource = _ShapeSource;
156
157
 
157
158
  type MapboxGLEvent = _MapboxGLEvent;
158
159
  type UserTrackingMode = _UserTrackingMode;
@@ -1,19 +1,19 @@
1
- func RCTLogError(_ message: String, _ file: String=#file, _ line: UInt=#line) {
1
+ func RCTMGLLogError(_ message: String, _ file: String=#file, _ line: UInt=#line) {
2
2
  RCTMGLSwiftLog.error(message, file: file, line: line)
3
3
  }
4
4
 
5
- func RCTLogWarn(_ message: String, _ file: String=#file, _ line: UInt=#line) {
5
+ func RCTMGLLogWarn(_ message: String, _ file: String=#file, _ line: UInt=#line) {
6
6
  RCTMGLSwiftLog.warn(message, file: file, line: line)
7
7
  }
8
8
 
9
- func RCTLogInfo(_ message: String, _ file: String=#file, _ line: UInt=#line) {
9
+ func RCTMGLLogInfo(_ message: String, _ file: String=#file, _ line: UInt=#line) {
10
10
  RCTMGLSwiftLog.info(message, file: file, line: line)
11
11
  }
12
12
 
13
- func RCTLog(_ message: String, _ file: String=#file, _ line: UInt=#line) {
13
+ func RCTMGLLog(_ message: String, _ file: String=#file, _ line: UInt=#line) {
14
14
  RCTMGLSwiftLog.log(message, file: file, line: line)
15
15
  }
16
16
 
17
- func RCTLogTrace(_ message: String, _ file: String=#file, _ line: UInt=#line) {
17
+ func RCTMGLLogTrace(_ message: String, _ file: String=#file, _ line: UInt=#line) {
18
18
  RCTMGLSwiftLog.trace(message, file: file, line: line)
19
19
  }
@@ -30,7 +30,7 @@ extension RCTMGLMapViewManager {
30
30
  let view = viewRegistry![reactTag]
31
31
 
32
32
  guard let view = view! as? RCTMGLMapView else {
33
- RCTLogError("Invalid react tag, could not find RCTMGLMapView");
33
+ RCTMGLLogError("Invalid react tag, could not find RCTMGLMapView");
34
34
  rejecter(name, "Unknown find reactTag: \(reactTag)", nil)
35
35
  return;
36
36
  }
@@ -47,7 +47,7 @@ extension RCTMGLMapViewManager {
47
47
  {
48
48
  withMapView(reactTag, name: name, rejecter: rejecter) { view in
49
49
  guard let mapboxMap = view.mapboxMap else {
50
- RCTLogError("MapboxMap is not yet available");
50
+ RCTMGLLogError("MapboxMap is not yet available");
51
51
  rejecter(name, "Map not loaded yet", nil)
52
52
  return;
53
53
  }
@@ -1,152 +1,233 @@
1
1
  import MapboxMaps
2
+ import UIKit
2
3
 
3
- class RCTMGLMarkerView : UIView, RCTMGLMapComponent {
4
+ class RCTMGLMarkerView: UIView, RCTMGLMapComponent {
5
+ // MARK: - Instance variables
6
+
4
7
  static let key = "RCTMGLMarkerView"
8
+ let id: String = "marker-\(UUID().uuidString)"
5
9
 
6
- var map: RCTMGLMapView? = nil
10
+ var map: RCTMGLMapView?
7
11
 
8
- // MARK: - react view
9
- var reactSubviews : [UIView] = []
10
-
11
- @objc
12
- override func insertReactSubview(_ subview: UIView!, at atIndex: Int) {
13
- if subview is RCTMGLCallout {
14
- Logger.log(level: .warn, message: "MarkerView doesn't supports callouts")
15
- }
16
- reactSubviews.insert(subview, at: atIndex)
17
- if reactSubviews.count > 1 {
18
- Logger.log(level: .error, message: "MarkerView supports max 1 subview")
12
+ var didAddToMap = false
13
+
14
+ @objc var coordinate: String? {
15
+ didSet {
16
+ update()
19
17
  }
20
18
  }
21
-
22
- @objc
23
- override func removeReactSubview(_ subview: UIView!) {
24
- reactSubviews.removeAll(where: { $0 == subview })
25
- }
26
19
 
27
- func view() -> UIView? {
28
- return reactSubviews.first
20
+ @objc var anchor: [String: NSNumber]? {
21
+ didSet {
22
+ update()
23
+ }
29
24
  }
30
25
 
31
- // MARK: - RCTMGLMapComponent
32
-
33
- func waitForStyleLoad() -> Bool {
34
- return true
26
+ @objc var allowOverlap: Bool = false {
27
+ didSet {
28
+ update()
29
+ }
35
30
  }
36
31
 
37
- func addToMap(_ map: RCTMGLMapView, style: Style) {
38
- logged("RCTMGLMarkerView.addToMap") {
39
- self.map = map
40
- let point = try point()
41
-
42
- try point.coordinates.validate()
43
-
44
- guard let view = view() else {
45
- Logger.log(level: .error, message: "MarkerView: No subview to render")
46
- return
32
+ @objc var isSelected: Bool = false {
33
+ didSet {
34
+ let hasBecomeSelected = isSelected && !oldValue
35
+
36
+ if hasBecomeSelected {
37
+ setSelected()
38
+ } else {
39
+ update()
47
40
  }
48
- let bounds = view.bounds
49
- view.isHidden = true
50
- try viewAnnotations()?.add(view, options: ViewAnnotationOptions.init(geometry: Geometry.point(point), width: bounds.width, height: bounds.height, associatedFeatureId: nil, allowOverlap: true, anchor: .center, offsetX: 0, offsetY: 0, selected: false))
51
41
  }
52
42
  }
43
+
44
+ // MARK: - Derived variables
53
45
 
54
- func viewAnnotations() -> ViewAnnotationManager? {
46
+ var annotationManager: ViewAnnotationManager? {
55
47
  self.map?.viewAnnotations
56
48
  }
57
49
 
58
- func removeFromMap(_ map: RCTMGLMapView) {
59
- guard let view = view() else {
60
- Logger.log(level: .error, message: "MarkerView: No subview to render")
61
- return
50
+ var point: Point? {
51
+ guard let _coordinate = coordinate else {
52
+ Logger.log(level: .error, message: "[getPoint] No coordinates were set")
53
+ return nil
62
54
  }
63
- viewAnnotations()?.remove(view)
55
+
56
+ guard let _data = _coordinate.data(using: .utf8) else {
57
+ Logger.log(level: .error, message: "[getPoint] Cannot serialize coordinate")
58
+ return nil
59
+ }
60
+
61
+ guard let _feature = try? JSONDecoder().decode(Feature.self, from: _data) else {
62
+ Logger.log(level: .error, message: "[getPoint] Cannot parse serialized coordinate")
63
+ return nil
64
+ }
65
+
66
+ guard let _geometry = _feature.geometry else {
67
+ Logger.log(level: .error, message: "[getPoint] Invalid geometry")
68
+ return nil
69
+ }
70
+
71
+ guard case .point(let _point) = _geometry else {
72
+ Logger.log(level: .error, message: "[getPoint] Invalid point")
73
+ return nil
74
+ }
75
+
76
+ return _point
77
+ }
78
+
79
+ // MARK: - RCTMGLMapComponent methods
80
+
81
+ func addToMap(_ map: RCTMGLMapView, style: Style) {
64
82
  self.map = map
83
+ add()
65
84
  }
66
-
67
- override func reactSetFrame(_ frame: CGRect) {
68
- super.reactSetFrame(frame)
69
85
 
70
- _updateFrameOrAnchor()
86
+ func removeFromMap(_ map: RCTMGLMapView) {
87
+ remove()
71
88
  }
72
89
 
73
- @objc var coordinate : String? {
74
- didSet {
75
- _updateCoordinate()
90
+ // MARK: - React methods
91
+
92
+ override func reactSetFrame(_ frame: CGRect) {
93
+ let prev = self.frame
94
+ var next = frame
95
+
96
+ let frameDidChange = !next.equalTo(prev)
97
+ if (frameDidChange) {
98
+ if prev.minX == 0 || prev.minY == 0 {
99
+ // Start the view offscreen to make it invisible until the annotation manager sets it to
100
+ // the correct point on the map.
101
+ next = CGRect(
102
+ x: -10000,
103
+ y: -10000,
104
+ width: next.width,
105
+ height: next.height
106
+ )
107
+ } else {
108
+ // Calculate the next position to temporarily place the view before the annotation manager
109
+ // sets it to the correct point on the map.
110
+ let dx = (next.width - prev.width) / 2
111
+ let dy = (next.height - prev.height) / 2
112
+ next = CGRect(
113
+ x: prev.minX - dx,
114
+ y: prev.minY - dy,
115
+ width: next.width,
116
+ height: next.height
117
+ )
118
+ }
76
119
  }
120
+
121
+ super.reactSetFrame(next)
122
+ addOrUpdate()
77
123
  }
78
124
 
79
- @objc var anchor : [String:NSNumber]? {
80
- didSet {
81
- _updateFrameOrAnchor()
82
- }
125
+ override func insertReactSubview(_ subview: UIView, at atIndex: Int) {
126
+ super.insertReactSubview(subview, at: atIndex)
83
127
  }
84
128
 
85
- func point() throws -> Point {
86
- guard let coordinate = coordinate else {
87
- throw RCTMGLError.failed("no coordinates were set")
88
- }
89
-
90
- guard let data = coordinate.data(using: .utf8) else {
91
- throw RCTMGLError.failed("cannot serialize coordiante")
92
- }
93
-
94
- guard let feature = try? JSONDecoder().decode(Feature.self, from: data) else {
95
- throw RCTMGLError.failed("cannot parse serialized coordiante")
96
- }
97
-
98
- guard let geometry : Geometry = feature.geometry else {
99
- throw RCTMGLError.failed("is not a geometry")
100
- }
129
+ override func removeReactSubview(_ subview: UIView) {
130
+ super.removeReactSubview(subview)
131
+ }
132
+
133
+ func waitForStyleLoad() -> Bool {
134
+ true
135
+ }
101
136
 
102
- guard case .point(let point) = geometry else {
103
- throw RCTMGLError.failed("is not a point")
104
- }
137
+ // MARK: - Create, update, and remove methods
105
138
 
106
- return point
107
- }
139
+ private func addOrUpdate() {
140
+ if didAddToMap {
141
+ update()
142
+ } else {
143
+ add()
144
+ }
145
+ }
108
146
 
109
- func _updateCoordinate() {
110
- guard let view = view() else {
147
+ /// Because the necessary data to add an annotation arrives from different sources at unpredictable times, we let the arrival of each value trigger an attempt to add the annotation, which we only do if all of the data exists, and the annotation not been added already.
148
+ private func add() {
149
+ if didAddToMap {
111
150
  return
112
151
  }
113
152
 
114
- logged("MarkerView.updateCoordinate") {
115
- let point = try point()
153
+ guard let annotationManager = annotationManager, let _ = point else {
154
+ return
155
+ }
116
156
 
117
- try viewAnnotations()?.update(view, options: ViewAnnotationOptions(geometry: Geometry.point(point)))
157
+ do {
158
+ let options = getOptions()
159
+ try annotationManager.add(self, id: id, options: options)
160
+ didAddToMap = true
161
+ } catch {
162
+ Logger.log(level: .error, message: "[MarkerView] Error adding annotation", error: error)
118
163
  }
119
164
  }
120
-
121
- func _updateFrameOrAnchor() {
122
- guard let view = view() else {
165
+
166
+ private func update() {
167
+ if !didAddToMap {
123
168
  return
124
169
  }
125
- var options = ViewAnnotationOptions()
126
- let defaultX : CGFloat = 0.5
127
- let defaultY : CGFloat = 0.5
128
- let bounds = view.bounds
129
- options.width = bounds.width
130
- options.height = bounds.height
131
170
 
132
- if let anchor = anchor {
133
- if let anchorX = anchor["x"] {
134
- options.offsetX = bounds.width * (CGFloat(anchorX.floatValue) - defaultX)
135
- }
136
- if let anchorY = anchor["y"] {
137
- options.offsetY = bounds.height * (CGFloat(anchorY.floatValue) - defaultY)
138
- }
139
- if let view = view as? RCTMGLMarkerViewWrapper {
140
- if let anchorX = anchor["x"] {
141
- view.anchorX = CGFloat(anchorX.floatValue)
142
- }
143
- if let anchorY = anchor["y"] {
144
- view.anchorY = CGFloat(anchorY.floatValue)
145
- }
171
+ guard let annotationManager = annotationManager else {
172
+ return
173
+ }
174
+
175
+ do {
176
+ let options = getOptions()
177
+ try annotationManager.update(self, options: options)
178
+ } catch {
179
+ Logger.log(level: .error, message: "[MarkerView] Error updating annotation", error: error)
180
+ }
181
+ }
182
+
183
+ /// There is a Mapbox bug where `selected` does not cause the marker to move to the front, so we can't simply update the component.
184
+ /// This forces that effect. See https://github.com/mapbox/mapbox-maps-ios/issues/1599.
185
+ private func setSelected() {
186
+ if let options = annotationManager?.options(for: self) {
187
+ do {
188
+ annotationManager?.remove(self)
189
+ try annotationManager?.add(self, id: id, options: options)
190
+ } catch {
191
+ Logger.log(level: .error, message: "[MarkerView] Error selecting annotation", error: error)
146
192
  }
147
193
  }
148
- logged("MarkerView.updateFrame") {
149
- try viewAnnotations()?.update(view, options: options)
194
+ }
195
+
196
+ private func remove() {
197
+ annotationManager?.remove(self)
198
+ }
199
+
200
+ // MARK: - Helper functions
201
+
202
+ private func getOptions() -> ViewAnnotationOptions {
203
+ var geometry: GeometryConvertible?
204
+ if let point = point {
205
+ geometry = Geometry.point(point)
150
206
  }
207
+
208
+ let offset = getOffset()
209
+
210
+ let options = ViewAnnotationOptions(
211
+ geometry: geometry,
212
+ width: self.bounds.width,
213
+ height: self.bounds.height,
214
+ allowOverlap: allowOverlap,
215
+ offsetX: offset.dx,
216
+ offsetY: offset.dy
217
+ )
218
+ return options
219
+ }
220
+
221
+ private func getOffset() -> CGVector {
222
+ guard let anchor = anchor, let anchorX = anchor["x"]?.CGFloat, let anchorY = anchor["y"]?.CGFloat else {
223
+ return .zero
224
+ }
225
+
226
+ // Create a modified offset, normalized from 0..1 to -1..1 and scaled to
227
+ // the view size.
228
+ let x = (anchorX * 2 - 1) * (self.bounds.width / 2) * -1
229
+ let y = (anchorY * 2 - 1) * (self.bounds.height / 2)
230
+
231
+ return CGVector(dx: x, dy: y)
151
232
  }
152
233
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  RCT_EXPORT_VIEW_PROPERTY(coordinate, NSString)
8
8
  RCT_EXPORT_VIEW_PROPERTY(anchor, NSDictionary)
9
+ RCT_EXPORT_VIEW_PROPERTY(allowOverlap, BOOL)
10
+ RCT_EXPORT_VIEW_PROPERTY(isSelected, BOOL)
9
11
 
10
12
  @end
11
-