Maps: MapView's onUserLocationUpdate doesn't seem to fire

Created on 15 Jul 2019  Ā·  26Comments  Ā·  Source: react-native-mapbox-gl/maps

Describe the bug
MapView's onUserLocationUpdate doesn't seem to fire.

To Reproduce

    onUserLocationUpdate = (location) => {
     console.log('location',location);
    }
    render() {
      return (
          <MapboxGL.MapView
            animated
            ref={c => this.map = c}
            styleURL={this.props.theme.styleURL}
            onUserLocationUpdate={this.onUserLocationUpdate}
            onPress={this.onPress}
            logoEnabled={false}
            compassEnabled={false}
            pitchEnabled={false}
            onRegionWillChange={this.onRegionWillChange}
            style={{ flex: 1 }}
            onDidFinishLoadingMap={this.onDidFinishLoadingMap}
            onDidFinishRenderingMap={this.onDidFinishRenderingMap}
            onDidFinishRenderingMapFully={this.onDidFinishRenderingMapFully}
            onDidFinishLoadingStyle={this.onDidFinishLoadingStyle}
            onUserLocationUpdate={this.onUserLocationUpdate}
          >
            <MapboxGL.UserLocation visible={true} renderMode="custom">
              <MapboxGL.CircleLayer id="mapboxUserLocationPluseCircle" style={layerStyles.normal.pulse} />
              <MapboxGL.CircleLayer id="mapboxUserLocationWhiteCircle" style={layerStyles.normal.background} />
              <MapboxGL.CircleLayer id="mapboxUserLocationBlueCicle" aboveLayerID="mapboxUserLocationWhiteCircle" style={layerStyles.normal.foreground} />
            </MapboxGL.UserLocation>

            <MapboxGL.Camera
              followUserLocation={this.state.currentTrackingModeIsFollowing}
              followUserMode="course"
              onUserTrackingModeChange={this.onUserTrackingModeChange}
            />

          </MapboxGL.MapView>
     )
   }

Expected behavior
Expected onUserLocationUpdate to fire the callback

Screenshots
N/A

Versions (please complete the following information):

  • Platfrom: iOS
  • Device: iPhone 7 Plus
  • OS: iOS 12.3.1.
  • SDK Version: N/A
  • react-native-mapbox-gl Version: 7.0.0-rc3
  • React Native Version 0.56.0

Additional context
Just doesn't seem to fire. I searched the repo's source code and not sure why it could be not working - seems like onUserLocationUpdate is still a prop of MapView, not Camera. Not quite sure if it's because of some props i'm passing in. Was working fine 6.1.2

Most helpful comment

We should create a throttle control for this and onRegionIsChanging similar
to ScrollView onScroll. The throttle should happen on native side to
prevent unnecessary bridge activity.

Happy to see a PR for this. The RN core ScrollView can be a good source of
inspiration for this code.

On Wed, 30 Oct 2019 at 19:39, Richard Lindhout notifications@github.com
wrote:

Probably, (maybe by only checking difference in long / lat) but I'm doing
some fairly heavy things after a location update, so I don't want to do
that every second. I think somethings like this is the only way since it
keeps firing location events even if my device does not do anything.

But I think this should be handled in te library in the native thread,
since I think all the debounces are fairly memory heavy. Have no proof for
that though :)

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/react-native-mapbox-gl/maps/issues/246?email_source=notifications&email_token=ABLAPW5MGSAC2IK563FHBHLQRHIELA5CNFSM4IDSMAX2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECVKYII#issuecomment-548056097,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ABLAPW5W4FLFZPADJSIC52TQRHIELANCNFSM4IDSMAXQ
.

All 26 comments

It does not work at all, even on the example. Waiting for the response about it.

@nitaliano any update on this would be appreciated

Using this method as well, not listed in documentation. Has it been deprecated/removed?

I’m unclear on this as well.. anyone in community have insight into this?

just using react-native-location meanwhile

It not there I think

I use the UserLocation

<Mapbox.UserLocation visible={true} onUpdate={onUpdate} />

With that on update you need to check if the distance between the old and the new point is greater than ... or else you have an update every second.

It's also not in the source code so you have to use UserLocation component
https://github.com/react-native-mapbox-gl/maps/blob/master/javascript/components/MapView.js

Any news on the above? What's the best solution?

can confirm that @RichardLindhout solution seems to be the new way to go:
The documentation is sparse, however it mentions onUpdate docs

@ferdicus you have to debounce this onUpdate since it fires at least every second and without any movement.

this weird, haven't checked the native code, however isn't it using some sort of underlying watchPosition?

thx anyways

You should log it, it's extreme how much update

My HOC component (I have a shared codebase with react-native-web)

import React, { useState, useCallback } from 'react'
import { useDebouncedCallback } from 'use-debounce'

import { distance } from './helpers'

export default function MapUserLocationHOC(WrappedComponent) {
  function Enhanced({ onUserLocationUpdate, ...rest }) {
    const [previousLocation, setPreviousLocation] = useState(null)

    const onUpdateCoords = useCallback(
      ({ coords }) => {
        if (!coords) {
          // console.log('no args to debounced location update')
          return
        }

        let needsUpdate = false
        if (previousLocation) {
          const dist = distance(previousLocation, coords, 'CM')
          if (dist > 30) {
            needsUpdate = true
          }
        } else {
          needsUpdate = true
        }

        if (needsUpdate) {
          setPreviousLocation(coords)

          // let other component know user location has changed
          onUserLocationUpdate && onUserLocationUpdate(coords)
        }
      },
      [previousLocation, setPreviousLocation, onUserLocationUpdate]
    )
    const [onDebouncedUpdate] = useDebouncedCallback(
      // function
      onUpdateCoords,
      // delay in ms
      600,
      { maxWait: 2000 }
    )

    return <WrappedComponent {...rest} onDebouncedUpdate={onDebouncedUpdate} />
  }
  return Enhanced
}

// https://www.geodatasource.com/developers/javascript
export function distance(location1, location2, unit) {
  const lat1 = location1.latitude
  const lon1 = location1.longitude

  const lat2 = location2.latitude
  const lon2 = location2.longitude
  if (lat1 === lat2 && lon1 === lon2) {
    return 0
  } else {
    var radlat1 = (Math.PI * lat1) / 180
    var radlat2 = (Math.PI * lat2) / 180
    var theta = lon1 - lon2
    var radtheta = (Math.PI * theta) / 180
    var dist =
      Math.sin(radlat1) * Math.sin(radlat2) +
      Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta)
    if (dist > 1) {
      dist = 1
    }
    dist = Math.acos(dist)
    dist = (dist * 180) / Math.PI
    dist = dist * 60 * 1.1515

    if (unit === 'K') {
      dist = dist * 1.609344
    }
    if (unit === 'M') {
      dist = dist * 1.609344 * 1000
    }
    if (unit === 'CM') {
      dist = dist * 1.609344 * 1000 * 100
    }
    if (unit === 'N') {
      dist = dist * 0.8684
    }
    return dist
  }
}

import React from 'react'
import Mapbox from '@react-native-mapbox-gl/maps'
import MapUserLocationHOC from './MapUserLocationHOC'

function MapUserLocation({ onDebouncedUpdate }) {
  return (
    <Mapbox.UserLocation
      // visible={Platform.OS === 'ios'}
      visible={false}
      animated
      onUpdate={onDebouncedUpdate}
      showUserLocation={true}
    />
  )
}

export default MapUserLocationHOC(MapUserLocation)

yeah, I've noticed that it's firing in a very high interval, even when immobile.

That's quite a workaround šŸ‘

However, that there must be a more suitable solution, no?

šŸ‘

Probably, (maybe by only checking difference in long / lat) but I'm doing some fairly heavy things after a location update, so I don't want to do that every second. I think somethings like this is the only way since it keeps firing location events even if my device does not do anything.

But I think this should be handled in te library in the native thread, since I think all the debounces are fairly memory heavy. Have no proof for that though :)

We should create a throttle control for this and onRegionIsChanging similar
to ScrollView onScroll. The throttle should happen on native side to
prevent unnecessary bridge activity.

Happy to see a PR for this. The RN core ScrollView can be a good source of
inspiration for this code.

On Wed, 30 Oct 2019 at 19:39, Richard Lindhout notifications@github.com
wrote:

Probably, (maybe by only checking difference in long / lat) but I'm doing
some fairly heavy things after a location update, so I don't want to do
that every second. I think somethings like this is the only way since it
keeps firing location events even if my device does not do anything.

But I think this should be handled in te library in the native thread,
since I think all the debounces are fairly memory heavy. Have no proof for
that though :)

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/react-native-mapbox-gl/maps/issues/246?email_source=notifications&email_token=ABLAPW5MGSAC2IK563FHBHLQRHIELA5CNFSM4IDSMAX2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECVKYII#issuecomment-548056097,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ABLAPW5W4FLFZPADJSIC52TQRHIELANCNFSM4IDSMAXQ
.

We could also copy some some code from here, looks like this is better than throttling since it will fire constantly with throttle also.
https://github.com/react-native-community/react-native-geolocation/blob/master/android/src/main/java/com/reactnativecommunity/geolocation/GeolocationModule.java#L390

 LOG  onUpdateCoords {"coords": {"accuracy": 9.977999687194824, "altitude": 44.64373779296875, "heading": 251.5358428955078, "latitude": 51.5462244, "longitude": 4.1036916, "speed": 0.08543474227190018}, "timestamp": 1573730357879}
 LOG  onUpdateCoords {"coords": {"accuracy": 7.492000102996826, "altitude": 44.64373779296875, "heading": 252.25204467773438, "latitude": 51.5462242, "longitude": 4.1036905, "speed": 0.07626981288194656}, "timestamp": 1573730359000}
 LOG  onUpdateCoords {"coords": {"accuracy": 6.244999885559082, "altitude": 45.210205078125, "heading": 336.17572021484375, "latitude": 51.5462262, "longitude": 4.1036887, "speed": 0.07873588800430298}, "timestamp": 1573730362000}
 LOG  onUpdateCoords {"coords": {"accuracy": 4.980999946594238, "altitude": 45.610595703125, "heading": 339.0922546386719, "latitude": 51.5462276, "longitude": 4.1036883, "speed": 0.08173366636037827}, "timestamp": 1573730364000}
 LOG  onUpdateCoords {"coords": {"accuracy": 3.9070000648498535, "altitude": 45.87335205078125, "heading": 280.903564453125, "latitude": 51.5462283, "longitude": 4.1036871, "speed": 0.012436928227543831}, "timestamp": 1573730369000}
 LOG  onUpdateCoords {"coords": {"accuracy": 5.051000118255615, "altitude": 46.19677734375, "heading": 128.6796417236328, "latitude": 51.5462299, "longitude": 4.1036876, "speed": 0.0030809876043349504}, "timestamp": 1573730419000}
 LOG  onUpdateCoords {"coords": {"accuracy": 6.9670000076293945, "altitude": 46.1929931640625, "heading": 169.62660217285156, "latitude": 51.5462298, "longitude": 4.1036876, "speed": 0.0038356157019734383}, "timestamp": 1573730421000}
 LOG  onUpdateCoords {"coords": {"accuracy": 8.170999526977539, "altitude": 46.1932373046875, "heading": 181.6247100830078, "latitude": 51.5462298, "longitude": 4.1036876, "speed": 0.0013805326307192445}, "timestamp": 1573730423000}
 LOG  onUpdateCoords {"coords": {"accuracy": 9.817999839782715, "altitude": 46.19488525390625, "heading": 357.03167724609375, "latitude": 51.5462298, "longitude": 4.1036876, "speed": 0.0023486786521971226}, "timestamp": 1573730424000}

When I have my phone on the table for 20 seconds this is the results now in my javascript code, instead of firing constantly.

Interestingly I've noticed, that it not always fires like crazy, sometimes it's less frequent, sometimes more... I also only monitor it via remote debugger when in the office.

My device is enormous it even does fire every second when my devices lies on the table without touching it ;)

BTW, I changed the implementation a little bit to check if location change is more than 10cm
boolean isSignificant = isMoreAccurate ? distance > 10 : distance > 100;

Thats like more than 4 inches.

The events get fired because the heading changes. I filtered this out and it helped a lot.

I've found onUpdate on UserLocation doesn't always call to process a first initial location when opening the app, either - though sometimes it does - any ideas?

I believe this can be closed.
UserLocation updates are firing via:

<MapboxGL.UserLocation onUpdate={// your callback goes here }/>

And the issue with the frequency of position updates was addressed by the minDisplacement property.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arnaudambro picture arnaudambro  Ā·  5Comments

dorthwein picture dorthwein  Ā·  3Comments

SethArchambault picture SethArchambault  Ā·  3Comments

calypsow777 picture calypsow777  Ā·  5Comments

andrei-tofan picture andrei-tofan  Ā·  5Comments