smithmicro/mapbox-gl-circle

Style switcher no longer working with GL JS 0.44.1

mblomdahl opened this issue · 2 comments

When attempting to update GL JS version from 0.40.1 to 0.44.1, we found that the style-layer switching no longer works.

How it was (successfully) handled in the latest mapbox-gl-circle version:

  1. a circle listens to styledataloading upon being added to a map
  2. when switching style layer, the circle would remove itself from the map and wait for styledata firing
  3. on styledata firing, the circle would add itself back to the map

Was working really well.

Here's the code that does it:

class MapboxCircle {

    /* snip */

    /**
     * When map style is changed, remove circle assets from map and add it back on next MapboxGL 'styledata' event.
     * @param {MapDataEvent} event
     * @private
     */
    _onMapStyleDataLoading(event) {
        if (this.map) {
            this.map.once('styledata', () => {
                // noinspection JSUnresolvedVariable
                this.addTo(event.target);
            });
            this.remove();
        }
    }

    /* snip */

    addTo(map, before) {
        const addCircleAssetsOnMap = () => {
            /* snip */
            map.on('styledataloading', this._onMapStyleDataLoading);
            /* snip */
    }

    /* snip */

    /**
     * Remove source data, layers and listeners from map.
     * @return {MapboxCircle}
     * @public
     */
    remove() {
        this.map.off('styledataloading', this._onMapStyleDataLoading);

        this.observer.disconnect();

        if (this.options.editable) {
            this._unbindBroadcastListeners();
            MapboxCircle._removeActiveEditableCircle(this);

            this.off('radiuschanged', this._onRadiusChanged).off('centerchanged', this._onCenterChanged);

            this._unbindRadiusHandlesListeners();
            this.map.removeLayer(this._circleRadiusHandlesId);

            this._unbindCenterHandleListeners();
            this.map.removeLayer(this._circleCenterHandleId);

            this.map.removeSource(this._circleRadiusHandlesSourceId);
            this.map.removeSource(this._circleCenterHandleSourceId);
        }

        this.map.off('zoomend', this._onZoomEnd);
        this._unbindCircleFillListeners();
        this.map.removeLayer(this._circleFillId);
        this.map.removeLayer(this._circleStrokeId);

        this.map.removeSource(this._circleSourceId);

        this.map = null;

        return this;
    }

    /* snip */

}

What happens with the latest version is that remove() call fails because, apparently, the circle assets already does not exist.

Question: @ryanbaumann is there some earlier event we should listen to in order to detect-and-handle a style layer change?

@mblomdahl I would recommend:

  1. Checking if the style is loaded on the styledata event.
  2. Checking if the circle layers and sources exist before trying to remove them or add them.
    • EX:
    if (map.getLayer('my-layer')) { map.removeLayer('my-layer') }
    if ((map.getSource('my-source')) { map.removeSource('my-layer') }
    

cc @JulieMunro

add me to the review team :)