Skip to main content

Show Point Annotations

Shows Point annotation with images

import React, { useRef, useState } from 'react';
import { View, Text, StyleSheet, Image } from 'react-native';
import {
  Callout,
  Camera,
  FillLayer,
  MapView,
  PointAnnotation,
  ShapeSource,
  getAnnotationsLayerID,
} from '@rnmapbox/maps';
import { Point, Position } from 'geojson';
import { Button } from '@rneui/base';

import Bubble from '../common/Bubble';
import { ExampleWithMetadata } from '../common/ExampleMetadata'; // exclude-from-doc

const ANNOTATION_SIZE = 40;

const styles = {
  annotationContainer: {
    alignItems: 'center',
    backgroundColor: 'white',
    borderColor: 'rgba(0, 0, 0, 0.45)',
    borderRadius: ANNOTATION_SIZE / 2,
    borderWidth: StyleSheet.hairlineWidth,
    height: ANNOTATION_SIZE,
    justifyContent: 'center',
    overflow: 'hidden',
    width: ANNOTATION_SIZE,
  },
  matchParent: {
    flex: 1,
  },
} as const;

type AnnotationWithRemoteImageProps = {
  id: string;
  title: string;
  coordinate: Position;
};

const AnnotationWithRemoteImage = ({
  id,
  coordinate,
  title,
}: AnnotationWithRemoteImageProps) => {
  const pointAnnotation = useRef<PointAnnotation>(null);

  return (
    <PointAnnotation
      id={id}
      coordinate={coordinate}
      title={title}
      draggable
      onSelected={(feature) =>
        console.log('onSelected:', feature.id, feature.geometry.coordinates)
      }
      onDrag={(feature) =>
        console.log('onDrag:', feature.id, feature.geometry.coordinates)
      }
      onDragStart={(feature) =>
        console.log('onDragStart:', feature.id, feature.geometry.coordinates)
      }
      onDragEnd={(feature) =>
        console.log('onDragEnd:', feature.id, feature.geometry.coordinates)
      }
      ref={pointAnnotation}
    >
      <View style={styles.annotationContainer}>
        <Image
          source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
          style={{ width: ANNOTATION_SIZE, height: ANNOTATION_SIZE }}
          onLoad={() => pointAnnotation.current?.refresh()}
          // Prevent rendering bitmap at unknown animation state
          fadeDuration={0}
        />
      </View>
      <Callout title="This is a sample loading a remote image" />
    </PointAnnotation>
  );
};

const ShowPointAnnotation = () => {
  const [coordinates, setCoordinates] = useState([
    [-73.99155, 40.73581],
    [-73.99155, 40.73681],
  ]);
  const [layerRendering, setLayerRendering] = useState<'below' | 'above'>(
    'below',
  );

  const renderAnnotations = () => {
    const items = [];

    for (let i = 0; i < coordinates.length; i++) {
      const coordinate = coordinates[i];

      const title = `Lon: ${coordinate[0]} Lat: ${coordinate[1]}`;
      const id = `pointAnnotation${i}`;

      if (i % 2 === 1) {
        items.push(
          null,
          <AnnotationWithRemoteImage
            key={id}
            id={id}
            coordinate={coordinate}
            title={title}
          />,
        );
      } else {
        items.push(
          null,
          <PointAnnotation
            key={id}
            id={id}
            coordinate={coordinate}
            title={title}
          >
            <View style={styles.annotationContainer} />
            <Callout title="This is an empty example" />
          </PointAnnotation>,
        );
      }
    }

    return items;
  };

  return (
    <>
      <MapView
        onPress={(feature) => {
          setCoordinates((prevState) => [
            ...prevState,
            (feature.geometry as Point).coordinates,
          ]);
        }}
        style={styles.matchParent}
        deselectAnnotationOnTap={true}
      >
        <Camera
          defaultSettings={{ centerCoordinate: coordinates[0], zoomLevel: 16 }}
        />

        {renderAnnotations()}

        <ShapeSource
          id="polygon"
          shape={{
            coordinates: [
              [
                [-73.98813787946587, 40.73199795542578],
                [-73.98313197853199, 40.7388685230859],
                [-73.98962548210226, 40.74155214586244],
                [-73.9945841575561, 40.73468185536569],
                [-73.98813787946587, 40.73199795542578],
              ],
            ],
            type: 'Polygon',
          }}
        >
          <FillLayer
            id="polygon"
            {...{
              [layerRendering + 'LayerID']:
                getAnnotationsLayerID('PointAnnotations'),
            }}
            style={{
              fillColor: 'rgba(255, 0, 0, 0.5)',
              fillOutlineColor: 'red',
            }}
          />
        </ShapeSource>
      </MapView>

      <Bubble>
        <Text style={{ marginBottom: 10 }}>
          Click to add a point annotation
        </Text>
        <Button
          onPress={() =>
            setLayerRendering(
              (prevState) =>
                (({ above: 'below', below: 'above' } as const)[prevState]),
            )
          }
        >
          Render Polygon {{ above: 'below', below: 'above' }[layerRendering]}
        </Button>
      </Bubble>
    </>
  );
};

export default ShowPointAnnotation;


ShowPointAnnotation.png}