maps icon indicating copy to clipboard operation
maps copied to clipboard

[Bug]: Existing layers when the map is offline

Open orca-nazar opened this issue 2 years ago • 10 comments

Mapbox Implementation

Mapbox

Mapbox Version

10.16.1

Platform

Android

@rnmapbox/maps version

#main

Standalone component to reproduce

import Mapbox, { Camera, MapView } from '@rnmapbox/maps';
import React, { useState } from 'react';
import { Button } from 'react-native';

const getStyles = (isDark) => ({
  mapView: { flex: 1 },
  overlay: {
    fillColor: isDark ? 'hsl(76,26%,75%)' : 'hsl(200,46%,69%)',
  },
});

const { Dark, Light } = Mapbox.StyleURL;

const BugReportExample = () => {
  const [styleUrl, setStyleUrl] = useState(Light);
  const isDark = styleUrl === Dark;
  const buttonTitle = isDark ? 'Set Light' : 'Set Dark';
  const styles = getStyles(isDark);

  return (
    <>
      <Button
        title={buttonTitle}
        onPress={() => setStyleUrl(isDark ? Light : Dark)}
      />
      <MapView style={styles.mapView} styleURL={styleUrl}>
        <Camera centerCoordinate={[-74.00597, 40.71427]} zoomLevel={14} />
        <Mapbox.VectorSource id="composite">
          <Mapbox.FillLayer
            id="national-park"
            sourceLayerID="landuse_overlay"
            sourceID="composite"
            style={styles.overlay}
          />
        </Mapbox.VectorSource>
      </MapView>
    </>
  );
};

export default BugReportExample;

Observed behavior and steps to reproduce

In our app we experience this issue when styles are switched in 2 scenarios

  1. Fast switching between dark and satellite mode (can't reproduce it in Example app). Our workaround is to apply(mount) custom sources and layers only after onDidFinishLoadingMap is fired
  2. In offline mode between switching dark and light mode

The second scenario could be reproducable by using BugReportExample

  1. In online mode open Bug Report Template TS
  2. Go Offline
  3. Switch to Dark mode. Dark styles will be missed as no connection
  4. Switch back to Light mode. Actual result: Error while updating property 'reactStyle' of a view managed by: RNMBXFillLayer null Set layer property "fill-color" failed: Layer national-park is not in style:

Expected behavior

No issues

Notes / preliminary analysis

It happens only when color is dynamically changed: fillColor: isDark ? 'hsl(76,26%,75%)' : 'hsl(200,46%,69%)', No issues in this case: fillColor: 'hsl(76,26%,75%)'

Additional links and references

No response

orca-nazar avatar Nov 01 '23 10:11 orca-nazar

I got some similar errors when changing the styleURL. This one seems to be caused by the compass:

Error while updating property 'reactStyle' of a view managed by: RCTMGLSymbolLayer
...
Caused by com.mapbox.maps.MapboxStyleException: Set layer property "icon-rotate" failed:
Layer mapboxUserLocationHeadingIndicator is not in style
159.71372985839844
       at com.mapbox.maps.extension.style.layers.Layer.updateProperty(Layer.kt:152)
       at com.mapbox.maps.extension.style.layers.Layer.setProperty$extension_style_publicRelease(Layer.kt:141)
       at com.mapbox.maps.extension.style.layers.generated.SymbolLayer.iconRotate(SymbolLayer.kt:809)
       at com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory.setIconRotate(RCTMGLStyleFactory.java:1318)
       at com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory.setSymbolLayerStyle(RCTMGLStyleFactory.java:255)
       at com.mapbox.rctmgl.components.styles.layers.RCTMGLSymbolLayer.addStyles(RCTMGLSymbolLayer.kt:31)
       at com.mapbox.rctmgl.components.styles.layers.RCTLayer.setReactStyle(RCTLayer.kt:124)
       at com.mapbox.rctmgl.components.styles.layers.RCTMGLSymbolLayerManager.setReactStyle(RCTMGLSymbolLayerManager.kt:60)
       at java.lang.reflect.Method.invoke(Method.java)
       ...

bviebahn avatar Nov 06 '23 19:11 bviebahn

image

I don't see this warning on main.

I've needed to add existing flags for the source and layer as those were referring to existing layers in the style:

import Mapbox, { Camera, MapView } from '@rnmapbox/maps';
import React, { useState } from 'react';
import { Button } from 'react-native';

const getStyles = (isDark) => ({
  mapView: { flex: 1 },
  overlay: {
    fillColor: isDark ? 'hsl(76,26%,75%)' : 'hsl(200,46%,69%)',
  },
});

const { Dark, Light } = Mapbox.StyleURL;

const BugReportExample = () => {
  const [styleUrl, setStyleUrl] = useState(Light);
  const isDark = styleUrl === Dark;
  const buttonTitle = isDark ? 'Set Light' : 'Set Dark';
  const styles = getStyles(isDark);

  return (
    <>
      <Button
        title={buttonTitle}
        onPress={() => setStyleUrl(isDark ? Light : Dark)}
      />
      <MapView style={styles.mapView} styleURL={styleUrl}>
        <Camera centerCoordinate={[-74.00597, 40.71427]} zoomLevel={14} />
        <Mapbox.VectorSource id="composite" existing>
          <Mapbox.FillLayer
            id="national-park"
            sourceLayerID="landuse_overlay"
            sourceID="composite"
            existing
            style={styles.overlay}
          />
        </Mapbox.VectorSource>
      </MapView>
    </>
  );
};

export default BugReportExample;

mfazekas avatar Nov 14 '23 18:11 mfazekas

@mfazekas It always reproduces even with existing property. The problem is the next: once the new styles are applied, all features will be removed from map including "existing", but the logic to recreate them doesn't exist. Should not they be skipped, as creating/deleting "existing" features should be handled by mapbox itself

orca-nazar avatar Dec 06 '23 10:12 orca-nazar

@mfazekas It always reproduces even with existing property. The problem is the next: once the new styles are applied, all features will be removed from map including "existing", but the logic to recreate them doesn't exist. Should not they be skipped, as creating/deleting "existing" features should be handled by mapbox itself

@orca-nazar can you be please more specific. Which @rnmapbox/maps version have you tested with , which component you've tried? The one in my comment? - https://github.com/rnmapbox/maps/issues/3152#issuecomment-1810898667

mfazekas avatar Dec 06 '23 11:12 mfazekas

Correct, I use the latest version and your component

orca-nazar avatar Dec 06 '23 11:12 orca-nazar

@orca-nazar I don't see the issue on current #main.

import Mapbox, { Camera, MapView } from '@rnmapbox/maps';
import React, { useState } from 'react';
import { Button } from 'react-native';

const getStyles = (isDark) => ({
  mapView: { flex: 1 },
  overlay: {
    fillColor: isDark ? 'hsl(76,26%,75%)' : 'hsl(200,46%,69%)',
  },
});

const { Dark, Light } = Mapbox.StyleURL;

const BugReportExample = () => {
  const [styleUrl, setStyleUrl] = useState(Light);
  const isDark = styleUrl === Dark;
  const buttonTitle = isDark ? 'Set Light' : 'Set Dark';
  const styles = getStyles(isDark);

  return (
    <>
      <Button
        title={buttonTitle}
        onPress={() => setStyleUrl(isDark ? Light : Dark)}
      />
      <MapView style={styles.mapView} styleURL={styleUrl}>
        <Camera
          defaultSettings={{
            centerCoordinate: [-74.00597, 40.71427],
            zoomLevel: 8,
          }}
        />
        <Mapbox.VectorSource id="composite" existing>
          <Mapbox.FillLayer
            id="national-park"
            sourceLayerID="landuse_overlay"
            sourceID="composite"
            existing
            style={styles.overlay}
          />
        </Mapbox.VectorSource>
      </MapView>
    </>
  );
};

export default BugReportExample;

https://github.com/rnmapbox/maps/assets/52435/4aa3d02e-8064-44d5-95a0-612805cec2e6

mfazekas avatar Dec 06 '23 13:12 mfazekas

Please check the steps to reproduce, the main point here was to go to offline mode. But before it, you need to clear the map data. You can go to app settings and clear data storage or delete/install the app. Then please follow the steps in the video. Thanks :) @mfazekas

orca-nazar avatar Dec 06 '23 13:12 orca-nazar

I think we need to add a check that if component is declared mExisitng but layer doesn't exists then we need to defer adding the layer until it's available, ideally we can use mapView.waitForLayer( for that.

https://github.com/rnmapbox/maps/blob/12946ef74f3fe98e9bf967c7ea46049a5a3e1e2c/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXLayer.kt#L286-L299

mfazekas avatar Dec 06 '23 13:12 mfazekas

Sounds good. Also, I'm wondering if this technique can be useful for the next case:

Fast switching between dark and satellite mode (can't reproduce it in Example app). Our workaround is to apply(mount) custom sources and layers only after onDidFinishLoadingMap is fired

So it could applied to filters and styles props updates

orca-nazar avatar Dec 06 '23 14:12 orca-nazar

Hi, any updates on this issue? I'm experiencing the same issue on Android, on iOS it looks without any problem. Thank you

jnocz avatar Feb 14 '24 09:02 jnocz