maplibre-react-native icon indicating copy to clipboard operation
maplibre-react-native copied to clipboard

Dynamically rendered RasterLayer does not display on Android

Open atkingtornado opened this issue 1 year ago • 3 comments

Hello, I am having an issue that seems to be specific to Android when trying to dynamically render multiple RasterLayer elements. Specifically, the layers do not display on the map, even though I have confirmed that the render function runs (and it works/displays just fine on iOS). If I force a re-draw of MapLibreGL.MapView the layers will show up properly, but this resets the map camera location and flashes to white which is not a great user experience. Here is some example code:

...
  const layerEls = []
  timeMatchTimes.forEach((timeToMatch, i) => {
    let isVisible = false
    if (i === sliderValue) {
      isVisible = true
    }

    let timeIndex = findClosestTimeIndex(dayjs.utc(timeToMatch), layerData.times)
    let time = layerData.times[timeIndex]
    let timeURLStr = dayjs.utc(time).format("YYYYMMDD_HHmmss")

    let layerID = layerData.id + timeURLStr
    let sourceID = layerData.id + timeURLStr + "source"


    let rasterSourceProps = {
      id: sourceID,
      tileUrlTemplates: [
        `https://tiledata.satsquatch.com/tilesdata/${sat+"_"+band}/${sector}/${timeURLStr}/{z}/{x}/{y}.png`,
      ],
      tileSize: 256,
      tms: true
    };

    layerEls.push(
      <MapLibreGL.RasterSource key={sourceID} {...rasterSourceProps}>
          <MapLibreGL.RasterLayer
            key={layerID}
            id={layerID}
            sourceID={sourceID}
            style={{rasterOpacity: isVisible ? 0.8 : 0.0, visibility: isVisible ? "visible" : "none", rasterFadeDuration: 0, rasterOpacityTransition: {duration: 0, delay: 0}}} //
          />
        </MapLibreGL.RasterSource>
    );
  });

  return (
    <>
      {layerEls}
    </>
  )

Is there something special I need to be doing to get this to work on android as expected?

Environment

  • Platform: Android
  • OS version: Android 13
  • Device type: Pixel 5
  • Emulator or Simulator: no
  • Development OS: Windows 11/macOS
  • @maplibre/maplibre-react-native Version: 10.0.0-alpha.24
  • react-native Version: 0.74.5
  • expo Version: 51.0.39

Additional context

I am using Expo development builds on physical devices (ios/android) as well as emulators

atkingtornado avatar Nov 09 '24 01:11 atkingtornado

Here is a complete example of what I am referring to: https://github.com/atkingtornado/testrasterlayers

when the "times" state gets updated on button press, the rasterlayer(s) do not render accordingly (https://github.com/atkingtornado/testrasterlayers/blob/master/app/index.tsx)

atkingtornado avatar Nov 09 '24 02:11 atkingtornado

Was able to reproduce, can only make it visible with changing the key of MapView on Android.

Adapted your example to be used within the BugReport template:

import MapLibreGL from "@maplibre/maplibre-react-native";
import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";

MapLibreGL.setAccessToken(null);

const styles = StyleSheet.create({
  map: {
    flex: 1,
    alignSelf: "stretch",
  },
  container: {
    position: "absolute",
    bottom: 90,
    right: 20,
    zIndex: 9999,
  },
  button: {
    padding: 10,
    backgroundColor: "white",
    borderRadius: 5,
    borderColor: "rgba(25, 118, 210, 0.2)",
    borderWidth: 1,
  },
  icon: {
    width: 32,
    height: 32,
  },
});

const sat = "GOES16";
const band = "14";
const sector = "CONUS";

export default function Index() {
  const [times, setTimes] = useState([]);

  const onPress = async () => {
    console.log("Press " + times.length);

    if (times.length === 0) {
      console.log("we try....");

      try {
        const response = await fetch(
          "https://tiledata.satsquatch.com/tilesdata/GOES16_14_CONUS.json",
        );

        console.log("We got response!");

        if (!response.ok) {
          throw new Error("Network response was not ok " + response.statusText);
        }

        console.log("Get JSON");
        const data = await response.json();

        console.log(JSON.stringify(data));
        console.log(JSON.stringify(data.times.slice(-10)));
        setTimes(data.times.slice(-10));
      } catch (error) {
        console.error("There was a problem with the fetch operation:", error);
      }
    } else {
      setTimes([]);
    }
  };

  console.log("Showing: " + times.length);

  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <IconButton onPress={onPress} />
      <MapLibreGL.MapView
        key={1}
        style={styles.map}
        logoEnabled={false}
        compassEnabled
        attributionPosition={{ top: 18, left: 18 }}
        styleURL="https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
      >
        {times.map((timeURLStr, i) => {
          console.log("rendering " + i);
          const isVisible = i === 0;

          const sourceID = sat + timeURLStr + "source";
          const layerID = sat + timeURLStr + "layer";

          return (
            <MapLibreGL.RasterSource
              key={sourceID}
              id={sourceID}
              tileUrlTemplates={[
                `https://tiledata.satsquatch.com/tilesdata/${sat + "_" + band}/${sector}/${timeURLStr}/{z}/{x}/{y}.png`,
              ]}
              tms
              tileSize={256}
            >
              <MapLibreGL.RasterLayer
                key={layerID}
                id={layerID}
                sourceID={sourceID}
                style={{
                  rasterOpacity: isVisible ? 0.8 : 0.0,
                  visibility: isVisible ? "visible" : "none",
                  rasterFadeDuration: 0,
                  rasterOpacityTransition: { duration: 0, delay: 0 },
                }}
              />
            </MapLibreGL.RasterSource>
          );
        })}
      </MapLibreGL.MapView>
    </View>
  );
}

type IconButtonProps = {
  onPress: () => void;
};

const IconButton = ({ onPress }: IconButtonProps) => {
  return (
    <View style={styles.container}>
      <TouchableOpacity onPress={onPress} style={styles.button}>
        <Text>Test</Text>
      </TouchableOpacity>
    </View>
  );
};

KiwiKilian avatar Nov 21 '24 06:11 KiwiKilian

I've done a quick bit of Googling, and this may be fixed in a newer version.can anyone confirm if this is still a problem, with the latest release?

chrisdebian avatar Nov 18 '25 22:11 chrisdebian