1
votes

I am using mapbox-gl in a react app to render an interactive map. On map load, I want to center the map on the user's location while keeping the current level of zoom. Centering on the user's location works fine with geolocate.trigger(); but the map automatically zooms way out to the continent level. Here is a simplified version of the map component of the app. I start by setting a hard-coded center point in New York which works fine, and then when trigger() runs, it gets zoomed way out. I've tried fiddling with all the properties of the geolocate object, but none of them has any effect on the zoom that trigger() goes to, and trigger doesn't seem to take any arguments. Note that I've had to remove my mapboxgl.accessToken for security reasons. As a side note, I'm also trying to get rid of the larger blue location confidence circle but I also can't seem to do that despite setting showAccuracyCircle: false. Any mapbox tips?

React component:

import React from 'react';
import mapboxgl from 'mapbox-gl';
import './map.css';

mapboxgl.accessToken = 'ACCESS_TOKEN_STRING_GOES_HERE';

export class Map extends React.Component {
  constructor(props) {
  super(props);
    this.state = {
      lng: -73.9392,
      lat: 40.8053,
      zoom: 17.5
    };
  }

  componentDidMount() {
    const map = new mapboxgl.Map({
      container: this.mapContainer,
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [this.state.lng, this.state.lat],
      zoom: this.state.zoom
    });

    const geolocate = new mapboxgl.GeolocateControl({
      container: this.geolocateContainer,
      positionOptions: {enableHighAccuracy: true},
      fitBoundsOptions: {linear: true, maxZoom: 10},
      trackUserLocation: true,
      mapboxgl: mapboxgl,
      showAccuracyCircle: false
      })

    map.on('load', () => {
      geolocate.trigger();
    });

    map.addControl(geolocate);

  }

  render() {
    return (
      <div>
        <div ref={element => this.geolocateContainer = element} className='mapButtons' />
        <div ref={el => this.mapContainer = el} className='mapContainer' />
      </div>
    )
  }
}

Here is a code pen I put together that illustrates the issue if you insert your own mapboxgl.accessToken. If you look closely, right when the page loads up, a default view is shown at the coordinates and zoom level provided in this.state. But then it immediately centers on the user's location (this is the desired behavior) and zooms way out (I don't want to zoom out). You'll need to give the codepen page permission to access your location to see this.

https://codepen.io/lexandermorgan/pen/ZEWEzze

2
You don't really need to stress so much about hiding your access token. You can create a new public one just for this purpose, and even lock it to codepen. In the absolute worst case, someone uses your month's worth of free usage. It's never happened to me though.Steve Bennett

2 Answers

1
votes

At the risk of pointing out the obvious, you should be setting minZoom, not maxZoom:

fitBoundsOptions: {linear: true, minZoom: map.getZoom()},

Also, if you're not actually using the geolocation tracking features, or need the control itself, it may be simpler to just use the browser's geolocation API directly:

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(e => 
    map.jumpTo({ center: [e.coords.longitude, e.coords.latitude]}))
}
0
votes

I found a slightly different work-around for this. It uses ReactMapGL instead of MapboxGL. The thing that seems to have made the difference is to pass a zoom parameter to a temporary geocoderDefaultOverrides object and then unpacking the viewport and then that object into the return object in handleGeocoderViewportChange. Here are the relevant parts:

  handleGeocoderViewportChange = viewport => {
    const geocoderDefaultOverrides = { transitionDuration: 0, zoom: 16 };

    return this.handleViewportChange({
      ...viewport,
      ...geocoderDefaultOverrides
    });
  };

Then in render:

  <Geocoder
    mapRef={this.map_ref}
    mapboxApiAccessToken={MBAccessToken}
    onViewportChange={this.handleGeocoderViewportChange}
    viewport={this.state.viewport}
  />