React Native Maps: Easy Bird's Eye View Animation
Tags: reactnative, javascript, beginners, tutorial
Published: 2023-08-22 11:44:23

1. Introduction
2. Setting Up Project
3. Understanding the MapView Props
4. Creating the Animation
5. Conclusion
6. </> [Full Code](https://github.com/noahvelasco/React-Native-Maps-Animation-Tutorial)

## Introduction
Hey there, fellow developers! Ever thought about giving your React Native maps a fresh twist? Today, we're diving into creating a bird's-eye view animation, offering users an engaging and elevated perspective. And the best part? It's completely free to use the map and the animation! Just a few lines of code and we got ourselves a nice bird's eye view animation! Our goal is to create something like the following - 

![final prod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rzlngque8t64a23nwrj.gif)


### Setting Up Project

1. [Create an Expo Project](https://docs.expo.dev/get-started/create-a-project/)
2. [Add the MapView dependency](https://docs.expo.dev/versions/latest/sdk/map-view/)
`npx expo install react-native-maps`

3. Create a basic Map View

```
import React from "react";
import { StyleSheet, View } from "react-native";
import MapView from "react-native-maps";

export default function App() {
  return (
    <View style={styles.container}>
      <MapView style={styles.map} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  map: {
    width: "100%",
    height: "100%",
  },
});

```

and you should have something like the following.

![mapview default](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4kqw0crl0qfk5wismvnt.png) 

Great we are already halfway there!

### Understanding the MapView Props

Now for the fun part - understanding the relevant MapView props! When reading the full [MapView documentation](https://github.com/react-native-maps/react-native-maps/blob/master/docs/mapview.md) you can see the **MANY** props but we will only need the following:

- **mapType**: Prop controlling which map layer type we are using. I use "satellite" since we only care about the map and not the pins nor pin labels, but feel free to use any other layer.

- **camera**: Prop controlling which region we are viewing on screen, the heading (direction faced), the zoom level, and the 'pitch' (up-down angle).

Let's now test out these props! Let's try mapping the pyramids from a strictly top view.

```
<MapView
        style={styles.map}
        mapType="satellite"
        camera={{
          center: {
            latitude: 29.978,
            longitude: 31.131,
          },
          pitch: 0, // Change this value to set the desired pitch
          heading: 0, // Direction faced by the camera, in degrees clockwise from North.
          zoom: 15.5, // Closer values mean a higher zoom level.
        }}
      />
```

and we get the following -


![mapview basic camera unconfigured](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g177z3lddsv5afcjh5c0.png)


Relative to the original, modifying the **pitch** to 90 we get -

![modified pitch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vttf09sargalqwybu38.png)

We can see we have created an angle of depression.


Next - relative to the original, modifying the **heading** to 180 we get -

![modified heading](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om22t5rfvox34bqgkrpe.png)

We can see we have ended up on the other side of the imaginary orbit focused on the pyramids.


We now know that pitch controls the angle of depression focused about the specified region and the heading controls the direction we are facing on an imaginary orbit about the specified region. Now lets animate it!

### Creating the Animation

In order to create the animation, we must first understand how the animation is going to work. We want the camera to stay focused on a region as it orbits the specified region.


![animation sketch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13oxa2tb31j5d5skq1e7.png)

The only thing we will need to update is where we are on that circle, thus we only need to update the heading every so often. The center and the pitch will remain the same for the animations entirety. 

To update the heading every so often we will need to update the headings state, thus we will use useState. We will also be updating the state on an interval so that we can get a "bird's eye view" orbiting animation. Below is what we add before the return - 

```
 //animation to circle map
  const [heading, setHeading] = useState(0);
  useEffect(() => {
    const intervalId = setInterval(() => {
      setHeading((prevHeading) => (prevHeading + 0.1) % 360); // Increment heading, and reset to 0 after reaching 360
    }, 10);

    return () => clearInterval(intervalId); // Clear the interval when component is unmounted
  }, []);
```

and update the header variable to be dynamic - 
```
heading: heading, // Direction faced by the camera in degrees clockwise from North.
```
We are done and should have something like this now -

 
![final prod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rzlngque8t64a23nwrj.gif)

## Conclusion
And that's a wrap! With the bird's-eye view effect in place, your React Native maps just got a whole lot cooler. It's these thoughtful touches that can make an app truly stand out. Keep exploring, keep innovating, and as always, happy coding!

### Please like and follow me on Github @[noahvelasco](https://github.com/noahvelasco)!


## </> Full Code 

[Full Code on Github](https://github.com/noahvelasco/React-Native-Maps-Animation-Tutorial)

```
import React, { useState, useEffect } from "react";
import { StyleSheet, View } from "react-native";
import MapView from "react-native-maps";

export default function App() {
  //animation to circle map
  const [heading, setHeading] = useState(0);
  useEffect(() => {
    const intervalId = setInterval(() => {
      setHeading((prevHeading) => (prevHeading + 0.1) % 360); // Increment heading, and reset to 0 after reaching 360
    }, 10);

    return () => clearInterval(intervalId); // Clear the interval when component is unmounted
  }, []);

  return (
    <View style={styles.container}>
      <MapView
        style={styles.map}
        mapType="satellite"
        camera={{
          center: {
            latitude: 29.978,
            longitude: 31.131,
          },
          pitch: 90, // Change this value to set the desired pitch
          heading: heading, // Direction faced by the camera, in degrees clockwise from North.
          zoom: 15.5, // Closer values mean a higher zoom level.
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  map: {
    width: "100%",
    height: "100%",
  },
});

```