How to Animate Map Markers Using Mapbox and React Hooks
Beautiful mapping experiences are game-changers in apps. How do we make this happen in a web app?
Everyone takes notice of an app that has a good map experience. We’ve all seen mobile apps that makes this happen: you’re waiting on your ride share and can actually see your driver getting closer! So how do we make this happen on a web app?
I prefer Mapbox over Google Maps for a few reasons, mainly that I find it more performant. The following examples will be using React and a third party NPM module,
react-mapbox-gl. You can do all the same using vanilla JS and your view library of choice.
Map Setup (React-mapbox-gl Example)
Once we have our map set up and rending, we can create our animated marker. This can be using a marker, or a symbol like in the example above. We’re also going to use another package called Turf. Turf is basically lodash for map functions. It’s very handy.
React Hooks are all the hype recently. Hooks allow us to leverage a lot of the features we’re used to with class-based components, without the overhead of classes. In this example we are going to use two different hooks, useState and useEffect.
Our component is going to accept a prop that is an array of locations for a given period of time. I’m assuming your application is updating the location data every so many seconds. If you have a more event-based pattern such as web sockets, more power to you 👏. The first thing we want to do is initialize the current location we will be giving to our map provider.
const [currentLocation, setCurrentLocation] = useState(null);
Next, we want to set up our effect, which will essentially walk through our location coordinates array. We’re going to use a web API function called
Breaking down this effect a little more. To start with, we want to make sure our locations prop isn’t empty (
length == 0). If so, we want to return and do nothing else. Once we know we have coordinates, we’ll use Turf to build out our more detailed array of coordinates. This can take an array of X number of items, and create an array of cords however many steps long. Very helpful! Then, we want to define our animate function. This is where we will actually set our state with the current location from our array. Make sure we have a fallback, in case we come up with
Assuming our timeStep isn’t greater than our number of steps, we’ll continue to call
requestAnimationFrame passing it our animate function. Once we run out of steps, the animation will cease from being called. In the example above, we assume we will be getting new locations about every 30 seconds. Below the animate function is our call to cancel the animation frame, and kick off a new frame. This will happen when our array of locations changes.
useEffect has a nice way of preventing from running during every component render. That is the second parameter of
useState: an array of props to watch and compare.
Finally, we will render our marker, with the state of the current location: