DEV Community

Cover image for React Native Maps: Easy Bird's Eye View Animation
Noah Velasco
Noah Velasco

Posted on

React Native Maps: Easy Bird's Eye View Animation

  1. Introduction
  2. Setting Up Project
  3. Understanding the MapView Props
  4. Creating the Animation
  5. Conclusion
  6. </> Full Code

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

Setting Up Project

  1. Create an Expo Project
  2. Add the MapView dependency
    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%",
  },
});

Enter fullscreen mode Exit fullscreen mode

and you should have something like the following.

mapview default

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 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.
        }}
      />
Enter fullscreen mode Exit fullscreen mode

and we get the following -

mapview basic camera unconfigured

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

modified pitch

We can see we have created an angle of depression.

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

modified heading

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

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
  }, []);
Enter fullscreen mode Exit fullscreen mode

and update the header variable to be dynamic -

heading: heading, // Direction faced by the camera in degrees clockwise from North.
Enter fullscreen mode Exit fullscreen mode

We are done and should have something like this now -

final prod

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!

</> Full Code

Full Code on Github

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%",
  },
});

Enter fullscreen mode Exit fullscreen mode

Top comments (0)