Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic iconImage value in SymbolLayerStyle not showing icon #293

Closed
ErTurco opened this issue Mar 11, 2024 · 5 comments
Closed

Dynamic iconImage value in SymbolLayerStyle not showing icon #293

ErTurco opened this issue Mar 11, 2024 · 5 comments

Comments

@ErTurco
Copy link

ErTurco commented Mar 11, 2024

Hi, I have an issue with Feature rendering on ShapeSource with SymbolLayer.
There is the code:

import React, { useRef, useState } from 'react';
import {
  Dimensions,
  SafeAreaView,
  StyleProp,
  Text,
  TextStyle,
  View,
  ViewStyle,
  useColorScheme,
} from 'react-native';

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen';

import MapLibreGL, { SymbolLayerStyle } from '@maplibre/maplibre-react-native';
import GeoJSON from 'geojson';

// Will be null for most users (only Mapbox authenticates this way).
// Required on Android. See Android installation notes.
MapLibreGL.setAccessToken(null);

const WIDTH = Dimensions.get('window').width;
const HEIGHT = Dimensions.get('window').height;

function getMaxHeight() {
    return HEIGHT < WIDTH ? HEIGHT : WIDTH;
}

interface CustomCalloutStyles {
  mapPinLayer: SymbolLayerStyle;
  customCalloutText: StyleProp<TextStyle>;
  calloutContainerStyle: StyleProp<ViewStyle>;
}

const styles: CustomCalloutStyles = {
  mapPinLayer: {
    iconAllowOverlap: true,
    iconAnchor: 'bottom',
    iconSize: 0.2,
    iconImage: ['get', 'icon'],
    // iconImage: 'https://www.pngall.com/wp-content/uploads/2017/05/Map-Marker-Free-Download-PNG.png',
  },
  customCalloutText: {
    color: 'black',
    fontSize: 16,
  },
  calloutContainerStyle: {
    backgroundColor: 'white',
    width: 60,
    height: 40,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
};

function App(): React.JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';
  const map = useRef<MapLibreGL.MapView>(null);
  const camera = useRef<MapLibreGL.Camera>(null);
  const [selectedFeature, setSelectedFeature] = useState<GeoJSON.Feature>();

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  function onMapReady(): void {
    console.log('onMapReady');
  }

  const featureCollection: GeoJSON.FeatureCollection = {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
        properties: {
          icon: 'https://www.pngall.com/wp-content/uploads/2017/05/Map-Marker-Free-Download-PNG.png',
          message: 'Hello!',
        },
        geometry: {
          type: 'Point',
          coordinates: [12.33235962957478, 42.89990295270986],
        },
      },
    ],
  };

  const onPinPress = (e: any): void => {
    if (selectedFeature) {
      setSelectedFeature(undefined);
      return;
    }

    const feature = e?.features[0];
    setSelectedFeature(feature);
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <MapLibreGL.MapView
          ref={map}
          style={{
            width: WIDTH,
            height: getMaxHeight()
          }}
          logoEnabled={false}
          attributionEnabled={false}
          onDidFinishLoadingMap= {onMapReady}
      >
          <MapLibreGL.Camera 
              ref={camera}
              bounds={{ne: [6.5, 35.4], sw: [18.6, 47.3]}}
          />
          <MapLibreGL.ShapeSource
            id="mapPinsSource"
            shape={featureCollection}
            onPress={onPinPress}>
            <MapLibreGL.SymbolLayer
              id="mapPinsLayer"
              style={styles.mapPinLayer}
            />
          </MapLibreGL.ShapeSource>
          {selectedFeature && (
            <MapLibreGL.MarkerView
              id="selectedFeatureMarkerView"
              coordinate={(selectedFeature.geometry as GeoJSON.Point).coordinates}>
              <View style={styles.calloutContainerStyle}>
                <Text style={styles.customCalloutText}>{selectedFeature.properties?.message}</Text>
              </View>
            </MapLibreGL.MarkerView>
          )}
      </MapLibreGL.MapView>
    </SafeAreaView>
  );
}

export default App;

In the CustomCalloutStyles if I set the directly the value for iconImage I can see the marker icon, otherwise (passing the value from the Feature, the line commented) I can't see the marker on map.
How can I set dinamically the value for the iconImage, setting it in the Feature object?

Version(s) affected

  • Platform: iOS
  • OS version: iOS 17.2
  • Device type: iPhone 15 Pro Max
  • Emulator/ Simulator: Yes
  • Development OS: macOS 14.3.1 Sonoma
  • maplibre-react-native Version 10.0.0-alpha.2
  • React Native Version 0.73.5
@ErTurco
Copy link
Author

ErTurco commented Mar 26, 2024

Hi, I tried also following the example ShapeSourceIcon, but I can't use MapLibreGL.Images as in the example because in version 10.0.0-alpha.2 it must have children.

@ErTurco
Copy link
Author

ErTurco commented Apr 15, 2024

Adding MapLibreGL.Images with child, it works.

@tyrauber
Copy link
Collaborator

Hi @ErTurco, it sounds like we need to update the example. Can you make a PR or post the change here?

@ErTurco
Copy link
Author

ErTurco commented Apr 16, 2024

Hi, the working example:

import React, { useRef, useState } from 'react';
import {
  Dimensions,
  SafeAreaView,
  StyleProp,
  Text,
  TextStyle,
  View,
  ViewStyle,
  useColorScheme,
} from 'react-native';

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen';

import MapLibreGL, { SymbolLayerStyle } from '@maplibre/maplibre-react-native';
import GeoJSON from 'geojson';

// Will be null for most users (only Mapbox authenticates this way).
// Required on Android. See Android installation notes.
MapLibreGL.setAccessToken(null);

const WIDTH = Dimensions.get('window').width;
const HEIGHT = Dimensions.get('window').height;

function getMaxHeight() {
    return HEIGHT < WIDTH ? HEIGHT : WIDTH;
}

interface CustomCalloutStyles {
  mapPinLayer: SymbolLayerStyle;
  customCalloutText: StyleProp<TextStyle>;
  calloutContainerStyle: StyleProp<ViewStyle>;
}

const styles: CustomCalloutStyles = {
  mapPinLayer: {
    iconAllowOverlap: true,
    iconAnchor: 'bottom',
    iconSize: 0.2,
    iconImage: ['get', 'icon']
  },
  customCalloutText: {
    color: 'black',
    fontSize: 16,
  },
  calloutContainerStyle: {
    backgroundColor: 'white',
    width: 60,
    height: 40,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
};

function Test(): React.JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';
  const map = useRef<MapLibreGL.MapView>(null);
  const camera = useRef<MapLibreGL.Camera>(null);
  **const [images, setImages] = useState<any>({
    'defaultMarker': { uri: 'https://www.pngall.com/wp-content/uploads/2017/05/Map-Marker-Free-Download-PNG.png' }
  });**
  const [selectedFeature, setSelectedFeature] = useState<GeoJSON.Feature>();

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  function onMapReady(): void {
    console.log('onMapReady');
  }

  const featureCollection: GeoJSON.FeatureCollection = {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        id: '9d10456e-bdda-4aa9-9269-04c1667d4552',
        properties: {
          icon: 'defaultMarker',
          message: 'Hello!',
        },
        geometry: {
          type: 'Point',
          coordinates: [12.33235962957478, 42.89990295270986],
        },
      },
    ],
  };

  const onPinPress = (e: any): void => {
    if (selectedFeature) {
      setSelectedFeature(undefined);
      return;
    }

    const feature = e?.features[0];
    setSelectedFeature(feature);
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <MapLibreGL.MapView
          ref={map}
          style={{
            width: WIDTH,
            height: getMaxHeight()
          }}
          logoEnabled={false}
          attributionEnabled={false}
          onDidFinishLoadingMap= {onMapReady}
      >
          <MapLibreGL.Camera 
              ref={camera}
              bounds={{ne: [6.5, 35.4], sw: [18.6, 47.3]}}
          />
          **<MapLibreGL.Images
              images={images}>
              <View></View>
          </MapLibreGL.Images>**
          <MapLibreGL.ShapeSource
            id="mapPinsSource"
            shape={featureCollection}
            onPress={onPinPress}>
            <MapLibreGL.SymbolLayer
              id="mapPinsLayer"
              style={styles.mapPinLayer}
            />
          </MapLibreGL.ShapeSource>
          {selectedFeature && (
            <MapLibreGL.MarkerView
              id="selectedFeatureMarkerView"
              coordinate={(selectedFeature.geometry as GeoJSON.Point).coordinates}>
              <View style={styles.calloutContainerStyle}>
                <Text style={styles.customCalloutText}>{selectedFeature.properties?.message}</Text>
              </View>
            </MapLibreGL.MarkerView>
          )}
      </MapLibreGL.MapView>
    </SafeAreaView>
  );
}

export default Test;

@KiwiKilian
Copy link
Collaborator

Example and required children has been fixed, thanks for the report!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants