DEV Community

I'm Luis! \^-^/
I'm Luis! \^-^/

Posted on

Let's play with Google Maps and React - Making a Car move through the road, like on Uber - Part 2

In my previous article, I explained how to make a marker move through Google Maps. In this one, I'd like to explain how to customize the icon and make it face the direction it's going on the road.

Here's where we left:

Customizing the icon

In order to customize the icon, we need to use the icon property, which allows us to set the url, size and anchor.

    const icon = {
      url: 'https://images.vexels.com/media/users/3/154573/isolated/preview/bd08e000a449288c914d851cb9dae110-hatchback-car-top-view-silhouette-by-vexels.png',
      scaledSize: new window.google.maps.Size(20, 20),
      anchor: { x: 10, y: 10 }
    }
Enter fullscreen mode Exit fullscreen mode

The url prop is a link to the image. If it has a transparent background, much better.
The scaledSize prop will scale the image. In this case, to 20x20 pixels (where the first parameter is the width and the second is the height). In addition, the size prop can be used, but it won't scale the image proportionally.
The anchor image will determine specifically where in that point the image will be displayed. Picture this as a Cardesian coordinate system, where the center is your lat/long, and you can move the marker using the x and y keys. Now the car appears on the road!

Orientation

Now we need to make the car face the direction where it's headed. Right now, it does move, but it still look kinda static, right?

I apologize in advance, but I'm about to show you a hack. The Google Maps SDK for Javascript doesn't have a property where you can change the rotation of the marker. Instead, you'll have to modify the image and rotate it with CSS. Not very funny, but it's not that bad!

The degrees

Before rotating, we need to calculate how much we should rotate the image in degrees. The image that I'm using already has 90 degrees of rotation, so that needs to be taken into consideration. Google has a function that does the job for us. It's window.google.maps.geometry.spherical.computeHeading.

As a reminder, we're rendering the car, which is between two lines, so we will use those two lines to determine where it's headed.

As a second reminder, we will update the marker's CSS, so we need to use componentDidUpdate to update the marker once its position has been set.

  componentDidUpdate = () => {
    const distance = this.getDistance()
    if (! distance) {
      return
    }

    let progress = this.path.filter(coordinates => coordinates.distance < distance)

    const nextLine = this.path.find(coordinates => coordinates.distance > distance)

    let point1, point2

    if (nextLine) {
      point1 = progress[progress.length -1]
      point2 = nextLine
    } else {
      // it's the end, so use the latest 2
      point1 = progress[progress.length - 2]
      point2 = progress[progress.length - 1]
    }

    const point1LatLng = new window.google.maps.LatLng(point1.lat, point1.lng)
    const point2LatLng = new window.google.maps.LatLng(point2.lat, point2.lng)

    const angle = window.google.maps.geometry.spherical.computeHeading(point1LatLng, point2LatLng)
    console.log(angle)
  }
Enter fullscreen mode Exit fullscreen mode

Now we need to find the marker's element and rotate it. Remembering that the marker already had 90 degrees of rotation.

  componentDidUpdate = () => {
    const distance = this.getDistance()
    if (! distance) {
      return
    }

    let progress = this.path.filter(coordinates => coordinates.distance < distance)

    const nextLine = this.path.find(coordinates => coordinates.distance > distance)

    let point1, point2

    if (nextLine) {
      point1 = progress[progress.length -1]
      point2 = nextLine
    } else {
      // it's the end, so use the latest 2
      point1 = progress[progress.length - 2]
      point2 = progress[progress.length - 1]
    }

    const point1LatLng = new window.google.maps.LatLng(point1.lat, point1.lng)
    const point2LatLng = new window.google.maps.LatLng(point2.lat, point2.lng)

    const angle = window.google.maps.geometry.spherical.computeHeading(point1LatLng, point2LatLng)
    const actualAngle = angle - 90

    const markerUrl = 'https://images.vexels.com/media/users/3/154573/isolated/preview/bd08e000a449288c914d851cb9dae110-hatchback-car-top-view-silhouette-by-vexels.png'
    const marker = document.querySelector(`[src="${markerUrl}"]`)

    if (marker) { // when it hasn't loaded, it's null
      marker.style.transform = `rotate(${actualAngle}deg)`
    }

  }

}
Enter fullscreen mode Exit fullscreen mode

Thank you for reading!

Top comments (7)

Collapse
 
bhagat profile image
Veldurthi1996 • Edited

Hey Luis, great content man. I have one requirement where I should be showing the journey of the person from point A to B. The thing here is I also wan't this journey to be download as a video. Any suggestions on this part

Collapse
 
akshatmaurya5 profile image
akshatMaurya5

is there any github repo of this code?

Collapse
 
olexanderd profile image
Alexander Danilchenko

Thanks for such a great article!

Collapse
 
nikhiljikar profile image
Nikhil Jikar

but how to appy this in live project..can you please give any suggestion as i want to track vehicle in realtime and facing chellenge in vehicle direction(heading)

Collapse
 
zerquix18 profile image
I'm Luis! \^-^/

Hi! Sorry for the late response. I'm not sure how your project is structured, but I'd try to calculate the heading for the last 2 coordinates you've received.

Collapse
 
bikash_kumar_838c567c295c profile image
Bikash Kumar

this code smothly not run i have try

Collapse
 
meenaraam profile image
Raam meena

Thank you very much man for such a valuable content