React-mapbox-gl: Initial position issue

Created on 23 Feb 2017  Â·  19Comments  Â·  Source: alex3165/react-mapbox-gl

Hi,

I see animation on first pass. fitBounds don't change. Why?

const markerLocation = [ displayLocation[1], displayLocation[0] ]; // <lng>, <lat>

<ReactMapboxGl style="mapbox://styles/mapbox/dark-v9"
    accessToken={ accessToken }
    containerStyle={{ height: '100%' }} 
    interactive={ false }
    fitBounds={ this.getBounds(displayLocation) }
    fitBoundsOptions={ {offset: [0, -100]} }>
  <Layer type="symbol" id="marker" layout={{ 'icon-image': 'marker-15' }}>
    <Feature coordinates={ markerLocation } />
  </Layer>
</ReactMapboxGl>

Looking through the code but can't really figure out what's going on:
https://github.com/alex3165/react-mapbox-gl/blob/master/src/map.tsx#L140

PS: setting center breaks fitBounds.

Bug

All 19 comments

Is the problem seeing the animation? If so, try setting linear: true in your fitBoundsOptions.

The problem is that I don't want to animate on first pass when I set bounds in the very first time. It must be moving the map from some initial location but I never specify it.

@pronebird Can you show this.getBounds and displayLocation

Also what do you mean by: setting center breaks fitBounds can you explain the steps ?

getBounds simply calculates bbox and displayLocation at the moment is hardcoded:

  displayLocation() {
      return [40.706213526877455, -74.0044641494751]; // [<lat>, <lng>]
  }

  getBounds(center) {
    const ruler = cheapRuler(center[0], 'meters');
    const bbox = ruler.bufferPoint(center, 100000);
    return [ bbox[1], bbox[0], bbox[3], bbox[2] ]; // <lng>, <lat>, <lng>, <lat>
  }

If I set center along with fitBounds and fitBoundsOptions then fitBoundsOptions.offset does not seem to be used at all. But that happens only when I change location over time so I guess there might be some bug in update function. However, center seems to specify initial position for the map and when not supplied on first pass causes animation from whatever initial position is by default to the bounds given.

I may be wrong but if you update both center and fitBounds the former is applied later and probably overrides fitBounds?

https://github.com/alex3165/react-mapbox-gl/blob/master/src/map.tsx#L253

I'd be happy to drop center entirely but I need to somehow shift the initial position to avoid that animation each time the map appears.

I was able to workaround that by saving first location and feeding it on each render, basically at this point ReactMapboxGl thinks that center didn't change and let fitBounds animate as expected:

    if(!this._centerLocation) {
      this._centerLocation = markerLocation;
    }
    let centerLocation = this._centerLocation;

   // ...

              <ReactMapboxGl style="mapbox://styles/mapbox/dark-v9"
                  center={ centerLocation }
                  accessToken={ accessToken }
                  containerStyle={{ height: '100%' }} 
                  interactive={ false }
                  fitBounds={ this.getBounds(displayLocation) }
                  fitBoundsOptions={ {offset: [0, -100]} }>

There is still subtle animation that accommodates for offset but that's probably because of initial zoom or something related to new bounds and offset.

@pronebird Just doing some tests and indeed, if center is not specified the map will move to fit the bounds specified with fitBounds which seems to be an expected to me don't you think ? And indeed if you want to prevent this you have to specify the center of the map.

Maybe a better behaviour if center is not specified would be to calculate a center from the given bounds and use this center as a default ?

It feels to me that if I solely work with bounds then initial centering should somehow be adopted from supplied bounds.

Yep seems reasonable, I will publish a patch with the update

@pronebird Patch 1.3.1 include the update, let me know if it solve your problem so that I can close this issue

Thanks! I will check it in the morning.

Sent from my iPhone

On 23 Feb 2017, at 22:37, Alexandre notifications@github.com wrote:

@pronebird Patch 1.3.1 include the update, let me know if it solve your problem so that I can close this issue

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Hmmmm

Uncaught Error: Invalid LngLat object: (NaN, NaN)
    at new LngLat (lng_lat.js:26)
    at Function.LngLat.convert (lng_lat.js:91)
    at e.i.jumpTo (camera.js:375)
    at new e (map.js:187)
    at ReactMapboxGl.componentDidMount (map.tsx:144)

I only provide fitBounds and fitBoundsOptions

Ok providing center works as expected!

@pronebird Do you provide a valid fitBounds with Float instead of NaN object ? Do you still have the issue ?

fitBounds is [17.17093821313498, 57.57270983240012, 18.966223386865018, 61.08593716759985]. Looks correct to me.

<ReactMapboxGl style="mapbox://styles/mapbox/dark-v9"
  accessToken={ accessToken }
  containerStyle={{ height: '100%' }} 
  fitBounds={ bounds }
  fitBoundsOptions={ {offset: [0, -100]} }>

It still wants center but at least it does not animate from [0, 0] to my bounds anymore.

Ok I will consider it fixed, if there is still a problem please open a new issue explaining your process to get this issue with an example.

I think I figured out what's going on. I was giving it flat array of fitBounds, while it expected array of arrays. i.e. fixing bounds to [ [a, b], [c, d] ] did the trick, that's because cheapRuler returns [w, s, e, n]

While this issue has been resolved. fitBounds still animates on first pass. I solved that by disabling animation during first render:

  constructor() {
    super();
    this.state = { isFirstPass: true };
  }

  componentDidMount() {
    this.setState({ isFirstPass: false });
  }

  componentWillUnmount() {
    this.setState({ isFirstPass: true });
  }

render() {
  const ruler = cheapRuler(center[0], 'meters');

  // calculate bounds with cheap-ruler
  const bounds = ruler.bufferPoint([40.741895, -73.989308], 300);

  // convert lat/lng to lng/lat
  let mapBounds = [];
  for(let i = 0; i < bounds.length; i += 2) {
    mapBounds.push(bounds.slice(i, i + 2).reverse());
  }

  const mapBoundsOptions = { offset: [0, -100], animate: !this.state.isFirstPass };
  // ...
}
Was this page helpful?
0 / 5 - 0 ratings