React Native Maps - takeSnapshot not capturing markers
Asked Answered
T

4

7

react-native: https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz react: 16.13.1 react-native-maps: 0.28.0

I want to get markers as a part of the snapshot. When we use takeSnapshot method all markers are ignored.

const snapshot = this.viewRefTest.takeSnapshot({
  format: 'png', // image formats: 'png', 'jpg' (default: 'png')
  quality: 0.5, // image quality: 0..1 (only relevant for jpg, default: 1)
  result: 'file', // result types: 'file', 'base64' (default: 'file')
});

<MapView
  ref={(viewRefTest) => {
    this.viewRefTest = viewRefTest;
  }}
  showsUserLocation={true}
  followUserLocation={true}>
  <MapView.Marker coordinate={item.location}>
    <Image
      style={{ width: 30, height: 30 }}
      source={require('../../assets/images/trophy.png')}
    />
    <Callout style={{ width: 250, flexDirection: 'row', alignItems: 'center' }}>
      <Text>$23</Text>
      <View>
        <Text style={{ fontSize: 12 }}>Custom Text!</Text>
      </View>
    </Callout>
  </MapView.Marker>
</MapView>;

Please let me know the possibility of this.

Thrilling answered 7/9, 2021 at 23:5 Comment(0)
T
2

After too many tries & combinations of adding delays, height/width, I was not able to capture custom markers using takeSnapshot method.

As a workaround, I have used captureRef method of react-native-view-shot

https://github.com/gre/react-native-view-shot

const uri = await captureRef(this.viewRefTest, {
            format: "png",
            quality: 1
        })

<MapView
  ref={(viewRefTest) => {
    this.viewRefTest = viewRefTest;
  }}
  showsUserLocation={true}
  followUserLocation={true}>
  <MapView.Marker coordinate={item.location}>
    <Image
      style={{ width: 30, height: 30 }}
      source={require('../../assets/images/trophy.png')}
    />
    <Callout style={{ width: 250, flexDirection: 'row', alignItems: 'center' }}>
      <Text>$23</Text>
      <View>
        <Text style={{ fontSize: 12 }}>Custom Text!</Text>
      </View>
    </Callout>
  </MapView.Marker>
</MapView>

CaptureRef Returns a Promise of the image URI. It helps capture a React Native view to an image. We can mention height, width, quality & format for the captured image.

Thrilling answered 21/9, 2021 at 6:40 Comment(0)
W
1

Could you try use width and height?

const snapshot = this.viewRefTest.takeSnapshot({
  width: 500,
  height: 500,
  format: 'png',
  quality: 0.5,
  result: 'file',
});

snapshot.then((uri) => {
  console.log(uri);
});
Wight answered 8/9, 2021 at 6:9 Comment(0)
I
0

You can solve that by creating a Snapshot with "react-native-view-shot"

Injurious answered 19/9, 2021 at 16:39 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Tyson
S
0

I think this bug depends on when you call this.viewRefTest.takeSnapshot()

You can check in my https://expo.dev/@duongtungls/expo-map-view-example

I think call takeSnapshot just after map mounted won't get marker or map. If call after callback onMapReady still need wait some hundreds of milisecond to take fully snapshot for both map and marker.

I hope this example code can help you solve problem.

import { StatusBar } from 'expo-status-bar';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import { Ionicons } from '@expo/vector-icons';

export default function App() {
  const mapRef = useRef(null);
  const [uri, setUri] = useState(null);

  const takeSnapshot = useCallback(() => {
    if (!mapRef || !mapRef.current) {
      return;
    }
    setTimeout(() => {
      const snapshot = mapRef.current.takeSnapshot({
        format: 'png', // image formats: 'png', 'jpg' (default: 'png')
        quality: 0.5, // image quality: 0..1 (only relevant for jpg, default: 1)
        result: 'file', // result types: 'file', 'base64' (default: 'file')
      });
      snapshot.then((uri) => {
        setUri(uri);
      });
    }, 800); // I add some timeout delay because without delay snapnot won't have map or marker.
  }, [mapRef]);

  return (
    <View style={styles.container}>
      {!uri && (
        <MapView
          ref={mapRef}
          style={{
            width: '100%',
            height: '100%',
          }}
          initialRegion={{
            latitude: 37.78825,
            longitude: -122.4324,
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0421,
          }}
          onMapReady={takeSnapshot} // I think need wait for map ready to take snapshot but seem still need wait by setTimeout to get fully snapshot
        >
          <Marker
            coordinate={{
              latitude: 37.78825,
              longitude: -122.4324,
            }}
            title={'Test'}
          >
            <Ionicons name="trophy" size={32} color="red" />
            <Text>This is a marker</Text>
          </Marker>
        </MapView>
      )}
      {uri && (
        <Image
          style={{
            width: '100%',
            height: '100%',
            resizeMode: 'contain',
            borderColor: 'red',
            borderWidth: 10,
          }}
          source={{
            uri,
          }}
        />
      )}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Snapshot take after map mounted

enter image description here

Snapshot take after onMapReady and 800ms delay

enter image description here

Best regards,

Spinelli answered 20/9, 2021 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.