maps icon indicating copy to clipboard operation
maps copied to clipboard

MapView does not display CircleLayer or fire onDidFinishLoadingMap callback or onRegionDidChange callback when offline and map has never been loaded online

Open bryanboyko opened this issue 3 years ago • 3 comments

Describe the bug

MapView does not display CircleLayer or fire onDidFinishLoadingMap callback or onRegionDidChange callback when offline and map has never been loaded online

To Reproduce

  1. Delete app to ensure Mapbox has not cached/persisted anything
  2. Install app
  3. createPack
  4. getPack to ensure createPack result is persisted
  5. cut network connection so app is offline
  6. open map
  7. note that tiles load in expected zoom range and within expected bounds
  8. note that only SymbolLayers load but not CircleLayers
  9. note that onRegionDidChange MapView callback is never fired
  10. note that onDidFinishLoadingMap MapView callback is never fired
  11. re-enable network connection and reload map - note that all expected MapView layers appear, onRegionDidChange callback fires, and onDidFinishLoadingMap callback fires

Please include a single standalone React Native component.

class MapBoxMap extends Component {
  // Points that never get clustered
  _renderPoints = (featureDefinition, index) => {
    const {
      onSelectFeature,
    } = this.props;

    const {
      featureCollection,
      minZoomLevel = 1,
      maxZoomLevel = MAPBOX_MAX_ZOOM_LEVEL,
      styles,
    } = featureDefinition;

    const {
      point,
      pointText,
      pointSelected,
      pointSelectedText,
      pointSymbol,
      pointSymbolSelected,
    } = styles;

    return (
      <MapboxGL.ShapeSource
        key={`points ${index}`}
        id={`points ${index}`}
        shape={featureCollection}
        ref={shape => (this.pointShape = shape)}
      >
        {/* Point selected */}
        { pointSelected &&
          <MapboxGL.CircleLayer
            id={`point_selected ${index}`}
            belowLayerID={`point_selected_text ${index}`}
            filter={['==', ['get', 'selected'], true]}
            style={pointSelected}
            minZoomLevel={minZoomLevel}
            maxZoomLevel={maxZoomLevel}
          />
        }

        {/* Point symbol */}
        { pointSymbol &&
          <MapboxGL.SymbolLayer
            id={`point_symbol ${index}`}
            filter={['!=', 'selected', true]}
            style={pointSymbol}
            minZoomLevel={minZoomLevel}
            maxZoomLevel={maxZoomLevel}
          />
        }

        {/* Point symbol selected */}
        { pointSymbolSelected &&
          <MapboxGL.SymbolLayer
            id={`point_symbol_selected ${index}`}
            filter={['==', ['get', 'selected'], true]}
            style={pointSymbolSelected}
            minZoomLevel={minZoomLevel}
            maxZoomLevel={maxZoomLevel}
          />
        }
      </MapboxGL.ShapeSource>
    );
  }

  render() {
    const {
      style,
      disabled,
      zoomDisabled,
      onMapLayout,
    } = this.props;

    return (
      <View style={StyleSheet.flatten([styles.mapContainer, style])}>
        <MapboxGL.MapView 
          ref={(ref) => (this._map = ref)}
          style={styles.map} 
          showUserLocation
          scrollEnabled={!disabled}
          zoomEnabled={!disabled && !zoomDisabled}
          pitchEnabled={!disabled}
          rotateEnabled={!disabled}
          onLayout={e => {
            this._layout = e.nativeEvent.layout;
            if (onMapLayout) {
              onMapLayout();
            }
          }}
          onRegionDidChange={async (shape) => {
            console.log('onRegionDidChange');
          }} 
          onDidFinishLoadingMap={() => {
            console.log('onDidFinishLoadingMap');
          }}
          minZoomLevel={1}
          maxZoomLevel={MAPBOX_MAX_ZOOM_LEVEL}
          compassEnabled={false}
          scaleBarEnabled={false}
          attributionPosition={{ bottom: 5, left: 85 }}
        >
          <MapboxGL.Camera 
            ref={(ref) => (this._camera = ref)}
            zoomLevel={this.state.initialZoomLevel}
            centerCoordinate={this.state.initialCenterCoordinate}
            bounds={this.state.initialBounds}
            minZoomLevel={1}
            maxZoomLevel={MAPBOX_MAX_ZOOM_LEVEL}
            animationDuration={10}
          />
          <MapboxGL.UserLocation
            showsUserHeadingIndicator
            visible
          />

          {this._renderPoints()}

        </MapboxGL.MapView> 
      </View>
    );
  }
}


const ShapeStyles = {
  // Parking pois
  parkingPointSymbol: {
    iconImage: MapParkingIcon,
    iconSize: Platform.OS === 'ios' ? 0.45 : 1.0,
    iconPitchAlignment: 'viewport',
    iconRotationAlignment: 'viewport',
  },
  parkingPointSymbolSelected: {
    iconImage: MapParkingPopIcon,
    iconSize: Platform.OS === 'ios' ? 0.2 : 0.5,
    iconAllowOverlap: true,
    iconPitchAlignment: 'viewport',
    iconRotationAlignment: 'viewport',
    iconOffset: Platform.OS === 'ios' ? [0, -105] : [0, -40],
  },
  parkingPointSelected: {
    circlePitchAlignment: 'map',
    circleColor: AppTheme.poiPurple,
    circleRadius: 2,
    circleStrokeWidth: 1,
    circleStrokeColor: 'white',
  },
}

Expected behavior

  1. MapView should render pointSelected MapboxGL.CircleLayer offline without needing to first render while online
  2. MapView should fire onRegionDidChange offline without first loading online
  3. MapView should fire onDidFinishLoadingMap offline without first loading online

Actual behavior

See above description and repro steps

Versions (please complete the following information):

  • Platform: iOS
  • Platform OS: iOS 15.5
  • Device: iPhone 13
  • Emulator/ Simulator: yes
  • Dev OS: MacOS 12.4
  • @rnmapbox/maps "@rnmapbox/maps": "github:rnmapbox/maps#main" $RNMapboxMapsImpl = 'mapbox' $RNMapboxMapsVersion = '~> 10.6.0'
  • React Native Version 0.68.2

bryanboyko avatar Jul 26 '22 15:07 bryanboyko

+1

As a hacky workaround we pre-load all custom feature styling on a MapView off-screen to load custom stylings into ambient cache. Not ideal though.

wen-kai avatar Jul 27 '22 19:07 wen-kai

Hi thanks for the report.

Can you please make the example self contained, right now there are consants, etc missing from the example. Having a self contained example makes it easy to just copy your code into our BugRepExample.js and try out.

The simpler to reproduce the issue the more likely we can look into it. Thanks for the understanding.

mfazekas avatar Jul 29 '22 13:07 mfazekas

@mfazekas unfortunately i wasn't able to repro in the simplest MapView ShapeSource implementation with only CircleLayer and SymbolLayer. I'll try later to slowly build to only the exact configuration that causes the issue and then add the code to this issue when I've got it.

NOTE: above workaround from @wen-kai is a solution for now

bryanboyko avatar Aug 02 '22 14:08 bryanboyko

I'm closing this, we'll reopen if we can reproduce

mfazekas avatar Sep 16 '22 08:09 mfazekas