@nativescript-community/ui-mapbox 7.0.2 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [7.0.4](https://github.com/nativescript-community/ui-mapbox/compare/v7.0.3...v7.0.4) (2025-10-30)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **ios:** working marker image and other fixes ([3ec0f75](https://github.com/nativescript-community/ui-mapbox/commit/3ec0f75f72708a03cafb2a0a1cd847cea8e74206))
11
+
12
+ ## [7.0.3](https://github.com/nativescript-community/ui-mapbox/compare/v7.0.2...v7.0.3) (2025-10-29)
13
+
14
+ **Note:** Version bump only for package @nativescript-community/ui-mapbox
15
+
6
16
  ## [7.0.2](https://github.com/nativescript-community/ui-mapbox/compare/v7.0.1...v7.0.2) (2025-10-28)
7
17
 
8
18
  ### Bug Fixes
package/common.js CHANGED
@@ -13,7 +13,7 @@ export var CLogTypes;
13
13
  CLogTypes[CLogTypes["error"] = 3] = "error";
14
14
  })(CLogTypes || (CLogTypes = {}));
15
15
  export const CLog = (type, ...args) => {
16
- Trace.write(args.map((a) => (a && typeof a === 'object' ? JSON.stringify(a) : a)).join(' '), MapboxTraceCategory, type);
16
+ Trace.write(args.join(' '), MapboxTraceCategory, type);
17
17
  };
18
18
  // ------------------------------------------------------------
19
19
  export var MapStyle;
@@ -269,18 +269,9 @@ export class MapboxViewCommonBase extends ContentView {
269
269
  onStart() {
270
270
  return this.mapbox?.onStart(this.getNativeMapView());
271
271
  }
272
- // onResume(nativeMap?: any): Promise<any> {
273
- // return this.mapbox && this.mapbox.onResume(this.getNativeMapView());
274
- // }
275
- // onPause(nativeMap?: any): Promise<any> {
276
- // return this.mapbox && this.mapbox.onPause(this.getNativeMapView());
277
- // }
278
272
  onStop(nativeMap) {
279
273
  return this.mapbox?.onStop(this.getNativeMapView());
280
274
  }
281
- // onLowMemory(nativeMap?: any): Promise<any> {
282
- // return this.mapbox.onLowMemory(this.getNativeMapView());
283
- // }
284
275
  onDestroy(nativeMap) {
285
276
  return this.mapbox?.onDestroy(this.getNativeMapView());
286
277
  }
@@ -65,6 +65,7 @@ export declare class MapboxView extends MapboxViewBase {
65
65
  */
66
66
  createNativeView(): object;
67
67
  onLoaded(): void;
68
+ onUnloaded(): void;
68
69
  initNativeView(): void;
69
70
  /**
70
71
  * when the view is destroyed.
@@ -160,12 +161,6 @@ export declare class Mapbox extends MapboxCommon implements MapboxApi {
160
161
  */
161
162
  hide(): Promise<void>;
162
163
  unhide(): Promise<void>;
163
- /**
164
- * destroy the map programmatically
165
- *
166
- * Destroy the map instance.
167
- */
168
- clear(nativeMap?: any): void;
169
164
  destroy(nativeMap?: any): Promise<void>;
170
165
  /**
171
166
  * Clear Event Listeners
package/index.android.js CHANGED
@@ -174,16 +174,22 @@ export class MapboxView extends MapboxViewBase {
174
174
  onLoaded() {
175
175
  super.onLoaded();
176
176
  if (Trace.isEnabled()) {
177
- CLog(CLogTypes.info, 'onLoaded()');
177
+ CLog(CLogTypes.info, 'onLoaded()', this);
178
178
  }
179
179
  if (!this.initialized) {
180
180
  this.initMap();
181
181
  this.initialized = true;
182
182
  }
183
183
  }
184
+ onUnloaded() {
185
+ super.onUnloaded();
186
+ if (Trace.isEnabled()) {
187
+ CLog(CLogTypes.info, 'onUnloaded()', this);
188
+ }
189
+ }
184
190
  initNativeView() {
185
191
  if (Trace.isEnabled()) {
186
- CLog(CLogTypes.info, 'initNativeView(): top');
192
+ CLog(CLogTypes.info, 'initNativeView(): top', this);
187
193
  }
188
194
  this.nativeView.owner = this;
189
195
  // Application.android.on(AndroidApplication.activityStartedEvent, this.onStart, this);
@@ -202,13 +208,13 @@ export class MapboxView extends MapboxViewBase {
202
208
  * @link https://docs.nativescript.org/plugins/ui-plugin-custom
203
209
  */
204
210
  disposeNativeView() {
211
+ super.disposeNativeView();
205
212
  if (Trace.isEnabled()) {
206
- CLog(CLogTypes.info, 'disposeNativeView(): top');
213
+ CLog(CLogTypes.info, 'disposeNativeView(): top', this);
207
214
  }
208
215
  this.nativeView.owner = null;
209
216
  this.mapbox?.destroy();
210
217
  this.mapbox = null;
211
- super.disposeNativeView();
212
218
  }
213
219
  /**
214
220
  * initialize the map
@@ -455,7 +461,7 @@ export class Mapbox extends MapboxCommon {
455
461
  logoPlugin.setEnabled(!settings.hideLogo);
456
462
  logoPlugin.setPosition(Mapbox.mapPositionToGravity(settings.logoPosition));
457
463
  if (Trace.isEnabled()) {
458
- CLog(CLogTypes.info, 'show(): onMapReady() with instance:', this._mapboxMapInstance);
464
+ CLog(CLogTypes.info, 'show(): onMapReady() with instance:', this._mapboxMapInstance, this._mapboxViewInstance);
459
465
  }
460
466
  // Android SDK 7.0.0 and on requires that the style be set separately after the map
461
467
  // is initialized. We do not consider the map ready until the style has successfully
@@ -472,6 +478,9 @@ export class Mapbox extends MapboxCommon {
472
478
  }
473
479
  // initialize the event handlers now that we have a constructed view.
474
480
  this.markerManager = new MarkerManager(this._mapboxMapInstance, this._mapboxViewInstance, (marker) => {
481
+ if (Trace.isEnabled()) {
482
+ CLog(CLogTypes.info, 'MarkerManager.onMarkerClicked():');
483
+ }
475
484
  const cachedMarker = this._getClickedMarkerDetails(marker);
476
485
  if (cachedMarker?.onTap) {
477
486
  const result = cachedMarker.onTap(cachedMarker);
@@ -611,16 +620,11 @@ export class Mapbox extends MapboxCommon {
611
620
  throw ex;
612
621
  }
613
622
  }
614
- /**
615
- * destroy the map programmatically
616
- *
617
- * Destroy the map instance.
618
- */
619
- clear(nativeMap) {
623
+ async destroy(nativeMap) {
620
624
  this.clearEventListeners();
621
625
  this._markerIconDownloadCache = {};
622
626
  if (Trace.isEnabled()) {
623
- CLog(CLogTypes.info, 'destroy(): destroying mapbox view.');
627
+ CLog(CLogTypes.info, 'destroy(): destroying mapbox view.', this.view, this._mapboxViewInstance);
624
628
  }
625
629
  if (this.lineManager) {
626
630
  this.lineManager.onDestroy();
@@ -657,7 +661,7 @@ export class Mapbox extends MapboxCommon {
657
661
  const viewGroup = this._mapboxViewInstance.getParent();
658
662
  if (viewGroup !== null) {
659
663
  if (Trace.isEnabled()) {
660
- CLog(CLogTypes.info, 'destroy(): removing _mapboxViewInstance view.');
664
+ CLog(CLogTypes.info, 'destroy(): removing _mapboxViewInstance view.', this._mapboxViewInstance);
661
665
  }
662
666
  viewGroup.removeView(this._mapboxViewInstance);
663
667
  }
@@ -670,9 +674,6 @@ export class Mapbox extends MapboxCommon {
670
674
  this._mapboxMapInstance = null;
671
675
  }
672
676
  }
673
- async destroy(nativeMap) {
674
- this.clear();
675
- }
676
677
  // private enableUserLocationPlugin() {
677
678
  // if (!this.map) {
678
679
  // return;
@@ -791,30 +792,12 @@ export class Mapbox extends MapboxCommon {
791
792
  }
792
793
  this._mapboxViewInstance.onStart();
793
794
  }
794
- // async onResume(nativeMapViewInstance?: any) {
795
- // if (Trace.isEnabled()) {
796
- // CLog(CLogTypes.info, 'onResume()');
797
- // }
798
- // this._mapboxViewInstance.onResume();
799
- // }
800
- // async onPause(nativeMapViewInstance?: any) {
801
- // if (Trace.isEnabled()) {
802
- // CLog(CLogTypes.info, 'onPause()');
803
- // }
804
- // this._mapboxViewInstance.onPause();
805
- // }
806
795
  async onStop(nativeMap) {
807
796
  if (Trace.isEnabled()) {
808
797
  CLog(CLogTypes.info, 'onStop()');
809
798
  }
810
799
  this._mapboxViewInstance.onStop();
811
800
  }
812
- // async onLowMemory(nativeMap?: any) {
813
- // if (Trace.isEnabled()) {
814
- // CLog(CLogTypes.info, 'onLowMemory()');
815
- // }
816
- // this._mapboxViewInstance.onLowMemory();
817
- // }
818
801
  async onDestroy(nativeMap) {
819
802
  if (Trace.isEnabled()) {
820
803
  CLog(CLogTypes.info, 'onDestroy()');
@@ -1155,6 +1138,7 @@ export class Mapbox extends MapboxCommon {
1155
1138
  marker.android = this.markerManager.addMarker(new AndroidMarker({
1156
1139
  position: com.mapbox.geojson.Point.fromLngLat(marker.lng, marker.lat),
1157
1140
  title: marker.title,
1141
+ id: marker.id,
1158
1142
  snippet: marker.subtitle,
1159
1143
  icon: icon?.android
1160
1144
  }));
@@ -1163,7 +1147,6 @@ export class Mapbox extends MapboxCommon {
1163
1147
  this.markerManager.selectMarker(marker.android);
1164
1148
  }
1165
1149
  marker.update = (newSettings) => {
1166
- console.log('update marker', Object.keys(newSettings), newSettings);
1167
1150
  const theMarker = this._markers.find((m) => m.id === marker.id);
1168
1151
  if (theMarker) {
1169
1152
  if (newSettings.onTap) {
@@ -1201,6 +1184,9 @@ export class Mapbox extends MapboxCommon {
1201
1184
  if (!this._mapboxMapInstance) {
1202
1185
  return;
1203
1186
  }
1187
+ if (Trace.isEnabled()) {
1188
+ CLog(CLogTypes.info, '_removeMarkers: ', ids);
1189
+ }
1204
1190
  this._markers.forEach((marker) => {
1205
1191
  if (!ids || (marker && marker.id && ids.indexOf(marker.id) > -1)) {
1206
1192
  if (marker && marker.android) {
@@ -1478,7 +1464,6 @@ export class Mapbox extends MapboxCommon {
1478
1464
  }
1479
1465
  const polygonOptions = new com.mapbox.maps.plugin.annotation.generated.PolygonAnnotationOptions();
1480
1466
  const nPoints = java.util.Arrays.asList([java.util.Arrays.asList(points.map((p) => com.mapbox.geojson.Point.fromLngLat(p.lng, p.lat)))]);
1481
- console.log('add points', nPoints);
1482
1467
  polygonOptions.withPoints(nPoints);
1483
1468
  polygonOptions.withFillColor(Mapbox.getAndroidColor(options.fillColor));
1484
1469
  polygonOptions.withFillOpacity(options.fillOpacity === undefined ? 1 : options.fillOpacity);
@@ -1486,7 +1471,7 @@ export class Mapbox extends MapboxCommon {
1486
1471
  if (options.strokeColor) {
1487
1472
  polygonOptions.withFillOutlineColor(Mapbox.getAndroidColor(options.strokeColor));
1488
1473
  }
1489
- this._polylines[options.id || new Date().getTime()] = this.polygonManager.create(polygonOptions);
1474
+ this._polygons[options.id || new Date().getTime()] = this.polygonManager.create(polygonOptions);
1490
1475
  resolve();
1491
1476
  }
1492
1477
  catch (ex) {
@@ -1640,10 +1625,10 @@ export class Mapbox extends MapboxCommon {
1640
1625
  if (Trace.isEnabled()) {
1641
1626
  CLog(CLogTypes.info, 'Mapbox:setOnMapClickListener(): click event at point:', point);
1642
1627
  }
1643
- return this.checkForClickEvent({
1628
+ return (listener({
1644
1629
  lat: point.latitude(),
1645
1630
  lng: point.longitude()
1646
- });
1631
+ }) ?? true);
1647
1632
  }
1648
1633
  });
1649
1634
  com.mapbox.maps.plugin.gestures.GesturesUtils.addOnMapClickListener(this._mapboxMapInstance, this.onMapClickListener);
@@ -1670,7 +1655,7 @@ export class Mapbox extends MapboxCommon {
1670
1655
  lng: point.longitude()
1671
1656
  })
1672
1657
  });
1673
- this._getGesturesPlugin().addOnMapLongClickListener(this.onMapLongClickListener);
1658
+ com.mapbox.maps.plugin.gestures.GesturesUtils.addOnMapLongClickListener(this._mapboxMapInstance, this.onMapLongClickListener);
1674
1659
  resolve();
1675
1660
  }
1676
1661
  catch (ex) {
@@ -1789,7 +1774,7 @@ export class Mapbox extends MapboxCommon {
1789
1774
  this.onFlingListener = new com.mapbox.maps.plugin.gestures.OnFlingListener({
1790
1775
  onFling: () => listener()
1791
1776
  });
1792
- this._getGesturesPlugin().addOnFlingListener(this.onFlingListener);
1777
+ com.mapbox.maps.plugin.gestures.GesturesUtils.addOnFlingListener(this._mapboxMapInstance, this.onFlingListener);
1793
1778
  resolve();
1794
1779
  }
1795
1780
  catch (ex) {
@@ -1966,7 +1951,6 @@ export class Mapbox extends MapboxCommon {
1966
1951
  bounds: options.bounds,
1967
1952
  ...options.metadata
1968
1953
  };
1969
- console.log('downloadRegion', regionId, new com.mapbox.bindgen.Value(JSON.stringify(info)));
1970
1954
  const regionOptions = new com.mapbox.common.TileRegionLoadOptions.Builder()
1971
1955
  .geometry(bbox)
1972
1956
  .descriptors(java.util.Collections.singletonList(tilesetDescriptor))
@@ -2617,7 +2601,11 @@ export class Mapbox extends MapboxCommon {
2617
2601
  return 'file://' + path.join(knownFolders.currentApp().path, input.replace('~/', ''));
2618
2602
  }
2619
2603
  else {
2620
- const key = Object.keys(MapStyle)[Object.values(MapStyle).indexOf(input)];
2604
+ let key = Object.keys(MapStyle)[Object.values(MapStyle).indexOf(input)];
2605
+ // on android STREETS is defined as MAPBOX_STREETS field
2606
+ if (key === 'STREETS') {
2607
+ key = 'MAPBOX_STREETS';
2608
+ }
2621
2609
  // fix because MAPBOX_STREETS and others are not exposed by the
2622
2610
  const field = Style.class.getDeclaredField(key) || Style.class.getDeclaredField('MAPBOX_STREETS');
2623
2611
  field.setAccessible(true);
@@ -2825,7 +2813,6 @@ export class Mapbox extends MapboxCommon {
2825
2813
  invoke: (settings) => {
2826
2814
  settings.setEnabled(true);
2827
2815
  settings.setPulsingEnabled(true);
2828
- console.log('setPuckBearingEnabled', options.cameraMode, options.renderMode, options.renderMode !== 'NORMAL', com.mapbox.maps.plugin.PuckBearing.HEADING, com.mapbox.maps.plugin.PuckBearing.COURSE);
2829
2816
  settings.setLocationPuck(com.mapbox.maps.plugin.locationcomponent.LocationComponentUtils.createDefault2DPuck(true));
2830
2817
  settings.setPuckBearingEnabled(options.renderMode !== 'NORMAL');
2831
2818
  settings.setPuckBearing(options.cameraMode?.indexOf('COMPASS') !== -1 ? com.mapbox.maps.plugin.PuckBearing.HEADING : com.mapbox.maps.plugin.PuckBearing.COURSE);
package/index.d.ts CHANGED
@@ -67,10 +67,7 @@ export declare class Mapbox extends MapboxCommon implements MapboxApi {
67
67
  unhide(): Promise<void>;
68
68
  destroy(nativeMap?: any): Promise<void>;
69
69
  onStart(nativeMap?: any): Promise<void>;
70
- onResume(nativeMap?: any): Promise<void>;
71
- onPause(nativeMap?: any): Promise<void>;
72
70
  onStop(nativeMap?: any): Promise<void>;
73
- onLowMemory(nativeMap?: any): Promise<void>;
74
71
  onDestroy(nativeMap?: any): Promise<void>;
75
72
  setMapStyle(style: string | MapStyle, nativeMap?: any): Promise<void>;
76
73
  getImage(imageId: string, nativeMap?: any): Promise<ImageSource>;
package/index.ios.d.ts CHANGED
@@ -39,6 +39,7 @@ export declare class Mapbox extends MapboxCommon implements MapboxApi {
39
39
  removeImage(imageId: string, nativeMap?: any): Promise<void>;
40
40
  addMarkers(markers: MapboxMarker[], nativeMap?: any): Promise<void>;
41
41
  selectedMarker: MapboxMarker;
42
+ isMarkerSelected(marker: MapboxMarker): boolean;
42
43
  deselectMarker(marker: MapboxMarker): Promise<void>;
43
44
  selectMarker(marker: MapboxMarker): Promise<void>;
44
45
  removeMarkers(ids?: any, nativeMap?: any): Promise<void>;
@@ -104,8 +105,6 @@ export declare class Mapbox extends MapboxCommon implements MapboxApi {
104
105
  y: number;
105
106
  }, nativeMap?: any): LatLng;
106
107
  onStart(nativeMap?: any): Promise<void>;
107
- onResume(nativeMap?: any): Promise<void>;
108
- onPause(nativeMap?: any): Promise<void>;
109
108
  onStop(nativeMap?: any): Promise<void>;
110
109
  onLowMemory(nativeMap?: any): Promise<void>;
111
110
  onDestroy(nativeMap?: any): Promise<void>;
package/index.ios.js CHANGED
@@ -87,7 +87,7 @@ async function fetchImageIOS(imagePath) {
87
87
  if (_markerIconDownloadCache[imagePath])
88
88
  return _markerIconDownloadCache[imagePath];
89
89
  const img = await Http.getImage(imagePath);
90
- if (img && img.ios) {
90
+ if (img?.ios) {
91
91
  _markerIconDownloadCache[imagePath] = img.ios;
92
92
  return img.ios;
93
93
  }
@@ -403,7 +403,7 @@ export class Mapbox extends MapboxCommon {
403
403
  view.addSubview(nativeMap);
404
404
  this.setMapboxViewInstance(nativeMap);
405
405
  if (settings.showUserLocation) {
406
- this.showUserLocationMarker({});
406
+ this.showUserLocationMarker({ cameraMode: 'NONE' });
407
407
  }
408
408
  this.initEventHandlerShim(settings, this._mapboxViewInstance);
409
409
  if (settings.onMapReady) {
@@ -559,7 +559,7 @@ export class Mapbox extends MapboxCommon {
559
559
  return m;
560
560
  }));
561
561
  updated.forEach((m) => {
562
- if (m.icon && typeof m.icon === 'string' && m.iconDownloaded) {
562
+ if (typeof m?.icon === 'string' && m.iconDownloaded) {
563
563
  try {
564
564
  b.addImage(m.icon, m.iconDownloaded);
565
565
  delete m.iconDownloaded;
@@ -598,7 +598,8 @@ export class Mapbox extends MapboxCommon {
598
598
  _marker.lng = newSettings.lng;
599
599
  b.updateMarkerPosition(_marker.id + '', newSettings.lat, newSettings.lng);
600
600
  }
601
- if (newSettings.selected) {
601
+ if (newSettings.selected || this.isMarkerSelected(_marker)) {
602
+ // this will also update callout position
602
603
  this.selectMarker(_marker);
603
604
  }
604
605
  }
@@ -615,8 +616,11 @@ export class Mapbox extends MapboxCommon {
615
616
  }
616
617
  });
617
618
  }
619
+ isMarkerSelected(marker) {
620
+ return this.selectedMarker === marker || this.selectedMarker?.id === marker.id;
621
+ }
618
622
  async deselectMarker(marker) {
619
- if (this.selectedMarker === marker || this.selectedMarker?.id === marker.id) {
623
+ if (this.isMarkerSelected(marker)) {
620
624
  this.hideCalloutForMarkerById(marker.id + '');
621
625
  this.selectedMarker = null;
622
626
  }
@@ -627,7 +631,7 @@ export class Mapbox extends MapboxCommon {
627
631
  if (Trace.isEnabled()) {
628
632
  CLog(CLogTypes.info, 'selectMarker():', marker.id);
629
633
  }
630
- if (this.selectedMarker) {
634
+ if (this.selectedMarker && !this.isMarkerSelected(marker)) {
631
635
  this.deselectMarker(this.selectedMarker);
632
636
  }
633
637
  await this.showCalloutForMarkerById(marker.id + '');
@@ -1313,7 +1317,6 @@ export class Mapbox extends MapboxCommon {
1313
1317
  if (Trace.isEnabled()) {
1314
1318
  CLog(CLogTypes.info, 'createCalloutView1():', marker.id, marker.title, !!this._reusableCalloutView);
1315
1319
  }
1316
- this._reusableCalloutView.removeEventListener('tap');
1317
1320
  return this._reusableCalloutView;
1318
1321
  }
1319
1322
  async showCalloutForMarkerById(markerId) {
@@ -1324,10 +1327,12 @@ export class Mapbox extends MapboxCommon {
1324
1327
  if (Trace.isEnabled()) {
1325
1328
  CLog(CLogTypes.info, 'showCalloutForMarkerById():', typeof markerId, markerId);
1326
1329
  }
1330
+ const callout = this.createCalloutView(m);
1327
1331
  if (this.bridgeInstance.hasViewAnnotationForMarker(markerId)) {
1328
- return;
1332
+ // let s Update
1333
+ this.bridgeInstance.removeViewAnnotationForMarker(markerId);
1334
+ // return;
1329
1335
  }
1330
- const callout = this.createCalloutView(m);
1331
1336
  callout.on('tap', () => {
1332
1337
  try {
1333
1338
  const res = m.onCalloutTap ? m.onCalloutTap(m) : undefined;
@@ -1338,6 +1343,8 @@ export class Mapbox extends MapboxCommon {
1338
1343
  console.error('callout tap handler error', e);
1339
1344
  }
1340
1345
  });
1346
+ this._reusableCalloutView.removeEventListener('tap');
1347
+ this._reusableCalloutView.nativeViewProtected?.removeFromSuperview();
1341
1348
  try {
1342
1349
  const nativeView = createUIViewAutoSizeUIViewAutoSize(callout);
1343
1350
  if (Trace.isEnabled()) {
@@ -1707,12 +1714,12 @@ export class Mapbox extends MapboxCommon {
1707
1714
  onStart(nativeMap) {
1708
1715
  return Promise.resolve();
1709
1716
  }
1710
- onResume(nativeMap) {
1711
- return Promise.resolve();
1712
- }
1713
- onPause(nativeMap) {
1714
- return Promise.resolve();
1715
- }
1717
+ // onResume(nativeMap?: any): Promise<void> {
1718
+ // return Promise.resolve();
1719
+ // }
1720
+ // onPause(nativeMap?: any): Promise<void> {
1721
+ // return Promise.resolve();
1722
+ // }
1716
1723
  onStop(nativeMap) {
1717
1724
  return Promise.resolve();
1718
1725
  }
@@ -7,13 +7,14 @@ export declare class AndroidMarker {
7
7
  icon: android.graphics.Bitmap;
8
8
  title?: string;
9
9
  snippet?: string;
10
+ id?: string | number;
10
11
  pointAnnotation: com.mapbox.maps.plugin.annotation.generated.PointAnnotation;
11
12
  viewAnnotation: android.view.View;
12
13
  view: StackLayout;
13
14
  anchor: com.mapbox.maps.ViewAnnotationAnchorConfig;
14
15
  layerId: string;
15
- prepared: boolean;
16
16
  constructor(opts: {
17
+ id: string | number;
17
18
  position: com.mapbox.geojson.Point;
18
19
  icon: android.graphics.Bitmap;
19
20
  title?: string;
@@ -5,11 +5,11 @@ import { CLog, CLogTypes } from '../common';
5
5
  */
6
6
  export class AndroidMarker {
7
7
  constructor(opts) {
8
- this.prepared = false;
9
8
  if (!opts.title && !opts.snippet) {
10
9
  throw new Error('Marker should have either title or snippet!');
11
10
  }
12
11
  this.position = opts.position;
12
+ this.id = opts.id;
13
13
  this.icon = opts.icon;
14
14
  this.title = opts.title;
15
15
  this.snippet = opts.snippet;
@@ -23,7 +23,7 @@ export class AndroidMarker {
23
23
  this.pointAnnotation = pointAnnotationManager.create(new PointAnnotationOptions().withPoint(this.position).withIconAnchor(IconAnchor.valueOf('BOTTOM')).withIconImage(this.icon));
24
24
  this.layerId = layerId;
25
25
  if (Trace.isEnabled()) {
26
- CLog(CLogTypes.log, 'MarkerManager prepareAnnotationMarker: ' + layerId);
26
+ CLog(CLogTypes.log, 'MarkerManager prepareAnnotationMarker: ' + layerId, this.id, this.pointAnnotation);
27
27
  }
28
28
  }
29
29
  update(pointAnnotationManager) {
@@ -13,6 +13,7 @@ export declare class MarkerManager {
13
13
  private selectedMarker;
14
14
  private onInfoWindowTapped;
15
15
  private _reusableCalloutView;
16
+ private _reusableCalloutNativeView;
16
17
  private onMapClickListener;
17
18
  private onPointClickListener;
18
19
  onViewAnnotationUpdatedListener: com.mapbox.maps.viewannotation.OnViewAnnotationUpdatedListener;
@@ -28,7 +29,7 @@ export declare class MarkerManager {
28
29
  prepareViewAnnotation(marker: AndroidMarker, onInfoWindowClick: any): void;
29
30
  removeMarker(marker: AndroidMarker): void;
30
31
  selectMarker(marker: AndroidMarker, deselectIfSelected?: boolean, update?: boolean): void;
31
- deselectMarker(marker: AndroidMarker): void;
32
+ deselectMarker(marker: AndroidMarker): boolean;
32
33
  destroy(): void;
33
34
  updateOffsetX(marker: AndroidMarker, leftTop: any, width: number): void;
34
35
  isSelected(marker: AndroidMarker): boolean;
@@ -6,7 +6,7 @@ import { createInfoWindowView } from './Marker.common';
6
6
  */
7
7
  export class MarkerManager {
8
8
  constructor(map, mapView, onMarkerClick, onInfoWindowClick) {
9
- this.markerList = new Set();
9
+ this.markerList = [];
10
10
  this.map = map;
11
11
  this.mapView = mapView;
12
12
  this.onInfoWindowTapped = onInfoWindowClick;
@@ -17,13 +17,19 @@ export class MarkerManager {
17
17
  // add click listeners
18
18
  this.onPointClickListener = new com.mapbox.maps.plugin.annotation.generated.OnPointAnnotationClickListener({
19
19
  onAnnotationClick: (annotation) => {
20
- for (const marker of this.markerList) {
21
- if (marker.pointAnnotation === annotation) {
22
- if (onMarkerClick(marker)) {
23
- return true;
24
- }
25
- this.selectMarker(marker, true);
20
+ const index = this.markerList.findIndex((m) => m.pointAnnotation === annotation);
21
+ if (Trace.isEnabled()) {
22
+ CLog(CLogTypes.info, 'MarkerManager.onAnnotationClick():', annotation, index, this.markerList.map((m) => m.id));
23
+ }
24
+ if (index !== -1) {
25
+ const marker = this.markerList[index];
26
+ if (Trace.isEnabled()) {
27
+ CLog(CLogTypes.info, 'MarkerManager.onAnnotationClick(): found', annotation);
28
+ }
29
+ if (onMarkerClick(marker)) {
30
+ return true;
26
31
  }
32
+ this.selectMarker(marker, true);
27
33
  }
28
34
  return true;
29
35
  }
@@ -32,17 +38,17 @@ export class MarkerManager {
32
38
  // Map click listener to deselect all markers
33
39
  this.onMapClickListener = new com.mapbox.maps.plugin.gestures.OnMapClickListener({
34
40
  onMapClick: (point) => {
35
- if (this.selectedMarker) {
36
- this.deselectMarker(this.selectedMarker);
37
- return true;
41
+ if (Trace.isEnabled()) {
42
+ CLog(CLogTypes.log, 'MarkerManager onMapClick: ', !!this.selectedMarker);
38
43
  }
39
- return false;
44
+ return this.deselectMarker(this.selectedMarker);
40
45
  }
41
46
  });
42
47
  com.mapbox.maps.plugin.gestures.GesturesUtils.addOnMapClickListener(map, this.onMapClickListener);
43
48
  }
44
49
  deselectAll() {
45
- this.markerList.forEach((marker) => this.deselectMarker(marker));
50
+ this.deselectMarker(this.selectedMarker);
51
+ // this.markerList.forEach((marker: AndroidMarker) => this.deselectMarker(marker));
46
52
  }
47
53
  adjustViewAnnotationXOffset(marker) {
48
54
  const listener = new com.mapbox.maps.viewannotation.OnViewAnnotationUpdatedListener({
@@ -61,21 +67,20 @@ export class MarkerManager {
61
67
  updateMarker(marker) {
62
68
  // this.adjustViewAnnotationXOffset(marker);
63
69
  marker.update(this.pointAnnotationManager);
64
- com.nativescript.mapbox.ViewAnnotationManager.updateViewAnnotation(this.mapView, marker.viewAnnotation, new com.mapbox.maps.ViewAnnotationOptions.Builder().annotatedFeature(com.mapbox.maps.AnnotatedFeature.valueOf(marker.pointAnnotation.getGeometry())).build());
70
+ if (marker.viewAnnotation) {
71
+ com.nativescript.mapbox.ViewAnnotationManager.updateViewAnnotation(this.mapView, marker.viewAnnotation, new com.mapbox.maps.ViewAnnotationOptions.Builder().annotatedFeature(com.mapbox.maps.AnnotatedFeature.valueOf(marker.pointAnnotation.getGeometry())).build());
72
+ }
65
73
  }
66
74
  addMarker(marker) {
67
75
  if (Trace.isEnabled()) {
68
- CLog(CLogTypes.log, 'MarkerManager addMarker: ' + JSON.stringify(marker));
76
+ CLog(CLogTypes.log, 'MarkerManager addMarker: ', marker, !!this.selectedMarker);
77
+ }
78
+ if (!marker.pointAnnotation || this.markerList.findIndex((m) => m.pointAnnotation === marker.pointAnnotation) === -1) {
79
+ marker.prepareAnnotationMarker(this.pointAnnotationManager, MarkerManager.LAYER_ID);
80
+ this.deselectMarker(this.selectedMarker);
81
+ this.markerList.push(marker);
82
+ // this.selectMarker(marker);
69
83
  }
70
- marker.prepareAnnotationMarker(this.pointAnnotationManager, MarkerManager.LAYER_ID);
71
- this.prepareViewAnnotation(marker, (e) => {
72
- // info Window tapped.
73
- if (!this.onInfoWindowTapped(marker)) {
74
- this.deselectMarker(marker);
75
- }
76
- });
77
- this.markerList.add(marker);
78
- // this.selectMarker(marker);
79
84
  return marker;
80
85
  }
81
86
  /**
@@ -84,6 +89,9 @@ export class MarkerManager {
84
89
  */
85
90
  prepareViewAnnotation(marker, onInfoWindowClick) {
86
91
  // --- Step 1: Create a NativeScript view tree
92
+ if (Trace.isEnabled()) {
93
+ CLog(CLogTypes.info, 'MarkerManager:prepareViewAnnotation():', this._reusableCalloutView);
94
+ }
87
95
  if (this._reusableCalloutView) {
88
96
  const title = this._reusableCalloutView.getViewById('title');
89
97
  title.text = marker?.title || '';
@@ -93,20 +101,29 @@ export class MarkerManager {
93
101
  }
94
102
  else {
95
103
  this._reusableCalloutView = createInfoWindowView(marker.title, marker.snippet);
104
+ this._reusableCalloutView._setupAsRootView(Utils.android.getApplicationContext());
105
+ this._reusableCalloutView.parent = Application.getRootView();
106
+ this._reusableCalloutView._isAddedToNativeVisualTree = true;
107
+ this._reusableCalloutView.callLoaded();
108
+ }
109
+ if (!this._reusableCalloutNativeView) {
110
+ const nativeView = this._reusableCalloutView.nativeViewProtected;
111
+ const frameLayout = new android.widget.FrameLayout(this._reusableCalloutView._context);
112
+ const layoutParams = new android.widget.FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
113
+ frameLayout.addView(nativeView);
114
+ frameLayout.setLayoutParams(layoutParams);
115
+ frameLayout.measure(android.view.View.MeasureSpec.makeMeasureSpec(0, android.view.View.MeasureSpec.UNSPECIFIED), android.view.View.MeasureSpec.makeMeasureSpec(0, android.view.View.MeasureSpec.UNSPECIFIED));
116
+ frameLayout.layout(0, 0, this._reusableCalloutView.getMeasuredWidth(), this._reusableCalloutView.getMeasuredHeight());
117
+ this._reusableCalloutNativeView = frameLayout;
118
+ }
119
+ if (this._reusableCalloutNativeView.getParent()) {
120
+ if (Trace.isEnabled()) {
121
+ CLog(CLogTypes.info, 'MarkerManager:prepareViewAnnotation(): remove from parent', this._reusableCalloutNativeView.getParent());
122
+ }
123
+ this._reusableCalloutNativeView.getParent().removeView(this._reusableCalloutNativeView);
96
124
  }
97
- this._reusableCalloutView._setupAsRootView(Utils.android.getApplicationContext());
98
- this._reusableCalloutView.parent = Application.getRootView();
99
- this._reusableCalloutView._isAddedToNativeVisualTree = true;
100
- this._reusableCalloutView.callLoaded();
101
- const nativeView = this._reusableCalloutView.nativeViewProtected;
102
125
  this._reusableCalloutView.removeEventListener('tap');
103
126
  this._reusableCalloutView.on('tap', onInfoWindowClick);
104
- const frameLayout = new android.widget.FrameLayout(this._reusableCalloutView._context);
105
- const layoutParams = new android.widget.FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
106
- frameLayout.addView(nativeView);
107
- frameLayout.setLayoutParams(layoutParams);
108
- frameLayout.measure(android.view.View.MeasureSpec.makeMeasureSpec(0, android.view.View.MeasureSpec.UNSPECIFIED), android.view.View.MeasureSpec.makeMeasureSpec(0, android.view.View.MeasureSpec.UNSPECIFIED));
109
- frameLayout.layout(0, 0, nativeView.getMeasuredWidth(), nativeView.getMeasuredHeight());
110
127
  // frameLayout.setLayoutParams(new android.widget.FrameLayout.LayoutParams(nativeView.getMeasuredWidth(), nativeView.getMeasuredHeight()));
111
128
  // --- Step 3: Prepare view annotation options
112
129
  const ViewAnnotationAnchor = com.mapbox.maps.ViewAnnotationAnchor;
@@ -132,17 +149,25 @@ export class MarkerManager {
132
149
  ]))
133
150
  .build();
134
151
  // --- Step 4: Add the view to Mapbox’s ViewAnnotationManager
135
- com.nativescript.mapbox.ViewAnnotationManager.addViewAnnotation(this.mapView, frameLayout, viewAnnotationOptions);
152
+ com.nativescript.mapbox.ViewAnnotationManager.addViewAnnotation(this.mapView, this._reusableCalloutNativeView, viewAnnotationOptions);
136
153
  // --- Step 5: Store references
137
- marker.viewAnnotation = frameLayout;
154
+ marker.viewAnnotation = this._reusableCalloutNativeView;
138
155
  marker.view = this._reusableCalloutView;
139
- marker.prepared = true;
140
156
  }
141
157
  removeMarker(marker) {
142
- if (!marker.prepared)
158
+ if (Trace.isEnabled()) {
159
+ CLog(CLogTypes.info, '_removeMarkers: ', marker.id, marker.pointAnnotation);
160
+ }
161
+ if (!marker.pointAnnotation)
143
162
  return;
144
- this.markerList.delete(marker);
145
- com.nativescript.mapbox.ViewAnnotationManager.removeViewAnnotation(this.mapView, marker.viewAnnotation);
163
+ const index = this.markerList.findIndex((m) => m.pointAnnotation === marker.pointAnnotation);
164
+ if (index !== -1) {
165
+ this.markerList.splice(index, 1);
166
+ }
167
+ if (marker.viewAnnotation) {
168
+ com.nativescript.mapbox.ViewAnnotationManager.removeViewAnnotation(this.mapView, marker.viewAnnotation);
169
+ marker.viewAnnotation = null;
170
+ }
146
171
  this.pointAnnotationManager.delete(marker.pointAnnotation);
147
172
  marker.destroy();
148
173
  }
@@ -156,23 +181,34 @@ export class MarkerManager {
156
181
  this.deselectMarker(this.selectedMarker);
157
182
  }
158
183
  this.selectedMarker = marker;
159
- // this.adjustViewAnnotationXOffset(marker);
160
- com.nativescript.mapbox.ViewAnnotationManager.updateViewAnnotation(this.mapView, marker.viewAnnotation, new com.mapbox.maps.ViewAnnotationOptions.Builder().visible(java.lang.Boolean.valueOf(true)).selected(java.lang.Boolean.valueOf(true)).build());
161
- marker.viewAnnotation.setVisibility(android.view.View.VISIBLE);
184
+ this.prepareViewAnnotation(marker, (e) => {
185
+ // info Window tapped.
186
+ if (!this.onInfoWindowTapped(marker)) {
187
+ this.deselectMarker(marker);
188
+ }
189
+ });
162
190
  }
163
191
  deselectMarker(marker) {
164
192
  if (!this.selectedMarker || marker.pointAnnotation !== this.selectedMarker.pointAnnotation) {
165
- return;
193
+ return false;
194
+ }
195
+ if (Trace.isEnabled()) {
196
+ CLog(CLogTypes.log, 'MarkerManager deselectMarker: ', marker, !!this.selectedMarker);
166
197
  }
167
198
  this.selectedMarker = null;
168
- const View = android.view.View;
169
- const viewAnnotationOptionsBuilder = new com.mapbox.maps.ViewAnnotationOptions.Builder().selected(java.lang.Boolean.valueOf(false)).visible(java.lang.Boolean.valueOf(false));
199
+ // const View = android.view.View;
200
+ // const viewAnnotationOptionsBuilder = new com.mapbox.maps.ViewAnnotationOptions.Builder().selected(java.lang.Boolean.valueOf(false)).visible(java.lang.Boolean.valueOf(false));
170
201
  // if (marker.anchor) {
171
202
  // const anchorBuilder = marker.anchor.toBuilder().offsetX(0.0).build();
172
203
  // viewAnnotationOptionsBuilder.variableAnchors(java.util.Collections.singletonList(anchorBuilder));
173
204
  // }
174
- com.nativescript.mapbox.ViewAnnotationManager.updateViewAnnotation(this.mapView, marker.viewAnnotation, viewAnnotationOptionsBuilder.build());
175
- marker.viewAnnotation.setVisibility(View.INVISIBLE);
205
+ if (marker.viewAnnotation) {
206
+ com.nativescript.mapbox.ViewAnnotationManager.removeViewAnnotation(this.mapView, marker.viewAnnotation);
207
+ marker.viewAnnotation = null;
208
+ }
209
+ // com.nativescript.mapbox.ViewAnnotationManager.updateViewAnnotation(this.mapView, marker.viewAnnotation, viewAnnotationOptionsBuilder.build());
210
+ // marker.viewAnnotation.setVisibility(View.INVISIBLE);
211
+ return true;
176
212
  }
177
213
  destroy() {
178
214
  this.markerList.forEach((m) => this.removeMarker(m));
@@ -181,8 +217,10 @@ export class MarkerManager {
181
217
  const gesturePlugin = this.mapView.getPlugin('MAPBOX_GESTURES_PLUGIN_ID');
182
218
  com.mapbox.maps.plugin.gestures.GesturesUtils.removeOnMapClickListener(this.map, this.onMapClickListener);
183
219
  this.onMapClickListener = null;
184
- com.nativescript.mapbox.ViewAnnotationManager.removeOnViewAnnotationUpdatedListener(this.mapView, this.onViewAnnotationUpdatedListener);
185
- this.onViewAnnotationUpdatedListener = null;
220
+ if (this.onViewAnnotationUpdatedListener) {
221
+ com.nativescript.mapbox.ViewAnnotationManager.removeOnViewAnnotationUpdatedListener(this.mapView, this.onViewAnnotationUpdatedListener);
222
+ this.onViewAnnotationUpdatedListener = null;
223
+ }
186
224
  if (this._reusableCalloutView) {
187
225
  this._reusableCalloutView._tearDownUI();
188
226
  this._reusableCalloutView = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativescript-community/ui-mapbox",
3
- "version": "7.0.2",
3
+ "version": "7.0.4",
4
4
  "description": "Interactive, thoroughly customizable maps powered by vector tiles and OpenGL.",
5
5
  "main": "index",
6
6
  "typings": "index.d.ts",
@@ -55,5 +55,5 @@
55
55
  "dependencies": {
56
56
  "@nativescript-community/perms": "^3.0.4"
57
57
  },
58
- "gitHead": "b430be9b6de94048db69df9d79c0d3172661935a"
58
+ "gitHead": "76d122e7d75fa5889e1dcf1ff52638ad1ec67ebf"
59
59
  }
@@ -202,7 +202,7 @@ public class MapboxBridge: NSObject {
202
202
  // Register this bridge for the created MapView
203
203
  MapboxBridge.registerBridge(self, for: mv)
204
204
 
205
- addImage("default_pin", image: UIImage(named: "default_pin"))
205
+ addImage("default_pin", UIImage(named: "default_pin"))
206
206
 
207
207
  if let options = optionsOpt {
208
208
  if ((options["hideLogo"] as? Bool) == true) {
@@ -409,7 +409,7 @@ public class MapboxBridge: NSObject {
409
409
  return nil
410
410
  }
411
411
 
412
- @objc public func addImage(_ imageId: String, image: UIImage?) {
412
+ @objc public func addImage(_ imageId: String, _ image: UIImage?) {
413
413
  guard let mv = mapView else { return }
414
414
  if (image != nil) {
415
415
  imageRegistry[imageId] = image!
@@ -545,7 +545,7 @@ public class MapboxBridge: NSObject {
545
545
  annotation.allowOverlapWithPuck = true
546
546
  let image = an.image
547
547
  let imageHeight = image?.image.size.height ?? 0
548
- let offsetY = imageHeight - 12
548
+ let offsetY = imageHeight/2 + 5
549
549
  // TODO: variableAnchors is broken for now if multiple
550
550
  annotation.variableAnchors = [ViewAnnotationAnchorConfig(anchor: .bottom, offsetY: offsetY)
551
551
  // , ViewAnnotationAnchorConfig(anchor: .bottomLeft, offsetY: offsetY), ViewAnnotationAnchorConfig(anchor: .bottomRight, offsetY: offsetY)
@@ -559,6 +559,7 @@ public class MapboxBridge: NSObject {
559
559
  @objc public func updateViewAnnotationForMarker(_ markerId: String, _ lat: Double, _ lng: Double) -> Bool {
560
560
  guard mapView != nil else { return false }
561
561
  guard let view = viewAnnotationByMarkerId[markerId] else { return false }
562
+ view.view.setNeedsLayout()
562
563
  view.annotatedFeature = .geometry(Point(CLLocationCoordinate2D(latitude: lat, longitude: lng)))
563
564
  return true
564
565
  }
@@ -32,7 +32,7 @@ declare class MapboxBridge extends NSObject {
32
32
 
33
33
  setStyle(styleURIOrURL: string, completion: (success: boolean, error?: any) => void): void;
34
34
 
35
- addImage(imageId: string, image: any): void;
35
+ addImage(imageId: string, image: UIImage): void;
36
36
  removeImage(imageId: string): void;
37
37
 
38
38
  addMarkers(markers: string): void;