plugins icon indicating copy to clipboard operation
plugins copied to clipboard

fix(google-maps): map's dimensions

Open vallemar opened this issue 3 years ago • 5 comments

If we call the following code in ready event the following error will occur.

mapView.animateCamera(
            CameraUpdate.fromCoordinates([{lat:  36.13326, lng: -5.45051}],
                zoom
            )
        );
  System.err: StackTrace:
  System.err: animateCamera(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\@nativescript\google-maps\index.android.js:709:0)
  System.err:   at initPositionMap(file: app\webpack:\@nativescript\template-blank-vue-ts\app\components\MapRoute.vue?a1e2:338:21)
  System.err:   at followPosition(file: app\webpack:\@nativescript\template-blank-vue-ts\app\components\MapRoute.vue?a1e2:295:11)
  System.err:   at mapReady(file: app\webpack:\@nativescript\template-blank-vue-ts\app\components\MapRoute.vue?a1e2:329:11)
  System.err:   at invokeWithErrorHandling(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\nativescript-vue\dist\index.js:1871:0)
  System.err:   at invoker(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\nativescript-vue\dist\index.js:2525:0)
  System.err:   at _handleEvent(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\@nativescript\core\data\observable\index.js:233:0)
  System.err:   at notify(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\@nativescript\core\data\observable\index.js:216:0)
  System.err:   at onMapReady(file: app\webpack:\@nativescript\template-blank-vue-ts\node_modules\@nativescript\google-maps\index.android.js:355:0)
  System.err:   at com.tns.Runtime.callJSMethodNative(Native Method)
  System.err:   at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302)
  System.err:   at com.tns.Runtime.callJSMethodImpl(Runtime.java:1188)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1175)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1153)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1149)
  System.err:   at com.tns.gen.com.google.android.gms.maps.OnMapReadyCallback.onMapReady(Unknown Source:10)
  System.err:   at com.google.android.gms.maps.zzaf.zzb(com.google.android.gms:play-services-maps@@18.0.0:1)
  System.err:   at com.google.android.gms.maps.internal.zzaq.zza(com.google.android.gms:play-services-maps@@18.0.0:5)
  System.err:   at com.google.android.gms.internal.maps.zzb.onTransact(com.google.android.gms:play-services-maps@@18.0.0:3)
  System.err:   at android.os.Binder.transact(Binder.java:1067)
  System.err:   at ex.c(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (190400-0):2)
  System.err:   at com.google.maps.api.android.lib6.impl.bg.run(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (190400-0):1)
  System.err:   at android.os.Handler.handleCallback(Handler.java:938)
  System.err:   at android.os.Handler.dispatchMessage(Handler.java:99)
  System.err:   at android.os.Looper.loopOnce(Looper.java:210)
  System.err:   at android.os.Looper.loop(Looper.java:299)
  System.err:   at android.app.ActivityThread.main(ActivityThread.java:8108)
  System.err:   at java.lang.reflect.Method.invoke(Native Method)
  System.err:   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
  System.err:   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
  System.err: Caused by: com.google.maps.api.android.lib6.common.apiexception.c: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occurred for the map view.  Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions.

Font: https://stackoverflow.com/questions/25231949/add-bounds-to-map-to-avoid-swiping-outside-a-certain-region

vallemar avatar Nov 12 '22 22:11 vallemar

I'm not sure about this PR since onMapLoaded is called later than onMapReady and we are penalizing everything that can be done while onMapLoaded occurs. I leave this PR open to discuss what would be the best approach. Anyway, this fixes the problem.

Maybe we can add an onMapLoaded event, but I think this would be confusing or it can be clearly indicated in the docs

vallemar avatar Nov 12 '22 22:11 vallemar

Hmm, I'm not in favour of removing the ready event for the mapLoaded event if it pushes back code execution.

Couple of things here. Are you just trying to set your map to a single location? fromCoordinates takes an array of Coordinates and a padding to return a CameraPosition from the calculated bounding box, looks to me like you want fromCoordinate(coord: Coordinate, zoom: number).

It seems fromCoordinates is working in the ready event on iOS and in android if wrapped by a setTimeout(cb, 0). (@triniwiz maybe you could shed some light on why setTimout works?) Another way to do this is to assign the map dimensions manually from the MapView.

Stackblitz Examples

herefishyfish avatar Nov 13 '22 00:11 herefishyfish

I am not in favor of removing the ready event either, I have left it that way so you can see what is happening.

On the other hand I don't think setTimeout is a viable solution, depending on the phone it will take more or less to paint (I think) and this can cause errors. Also, I think there are already too many setTimeout in NS.

This part seems like a good solution to me, but if in the end it was left like this, I would have to expose it in the documentation for this to work, the problem with this is that you should know exactly the size you expect from the map:

this.map.animateCamera(
       CameraUpdate.fromCoordinates(
         [
           {
             lat:-32.13123,
             ing: 122.12333,
           },
           {
             lat:-32.23123,
             ing: 122.32333,
           },
         ],
         /** Ideally you'd get these values from the mapView */
         Screen.mainScreen.widthPixels,
         Screen.mainScreen.heightPixels * 0.6,
         100 // Padding
       )
     );

Anyway I think that adding another event with mapLoaded makes sense, since it is the same SDK that emits these events and we would be aligned with the SDK

vallemar avatar Nov 13 '22 10:11 vallemar

@vallemar I found this google paragraph:

Do not change the camera with this camera update until the map has undergone layout (in order for this method to correctly determine the appropriate bounding box and zoom level, the map must have a size). Otherwise an IllegalStateException will be thrown. It is NOT sufficient for the map to be available (i.e. getMap() returns a non-null object); the view containing the map must have also undergone layout such that its dimensions have been determined. If you cannot be sure that this has occured, use newLatLngBounds(LatLngBounds, int, int, int) instead and provide the dimensions of the map manually.

I suspect that calling animateCamera inside NativeScript's layoutChanged event listener would also be sufficient.

CatchABus avatar Nov 22 '22 14:11 CatchABus

@herefishyfish could result if, or also that the developer subscribes to the event after on ready

EDIT: I think I'm going to close the PR, now if someone passes it I could see a solution in android here

vallemar avatar Nov 22 '22 14:11 vallemar