Track your fleet with the JavaScript Fleet Tracking Library

The JavaScript Fleet Tracking Library lets you visualize the locations of vehicles in your fleets in near real time. The library uses the On Demand Rides and Deliveries API to allow visualization of vehicles as well as trips. The JavaScript Fleet Tracking Library contains a JavaScript map component that is a drop-in replacement for a standard google.maps.Map entity and data components to connect with Fleet Engine.

Components

The JavaScript Fleet Tracking Library provides components for visualization of vehicles and trip waypoints, as well as raw data feeds for ETA or remaining distance to a trip.

Fleet Tracking map view

The Fleet Tracking map view component visualizes the location of vehicles and the trip waypoints. If the route for a vehicle is known, the map view component animates that vehicle as it moves along its predicted path.

Fleet Tracking map view
example

Location providers

Location providers work with information stored in Fleet Engine to send location information for tracked objects into the journey sharing map.

Vehicle location provider

The vehicle location provider displays a single vehicle's location information. It has information on the vehicle location and current trip assigned to the vehicle.

Fleet location provider

The fleet location provider displays location information for multiple vehicles. You can filter to display a specific vehicle and its location, or you can display the vehicle locations for the entire fleet.

Control the visibility of tracked locations

Visibility rules determine when a tracked location object is visible on the Map for a Fleet Engine location provider. Note - Using a custom or derived location provider may change the visibility rules.

Vehicles

A vehicle is visible as soon as it is created in Fleet Engine, and is visible when the vehicle_state is Online. This means a vehicle can be visible even when there is no current trip assigned to the vehicle.

Waypoint location markers

A waypoint location marker indicates points along a vehicle's journey starting with the origin and ending with the final destination. The waypoint location markers can be defined as the following:

  • Origin - indicates the starting location for the vehicle trip
  • Intermediate - indicates stopovers for the vehicle trip
  • Destination - indicates final location for the vehicle trip

Planned vehicle waypoints are shown on the map as origin, intermediate and destination markers.

Get started with the JavaScript Fleet Tracking Library

Before using the JavaScript Fleet Tracking Library, make sure you are familiar with Fleet Engine and with getting an API key. Then create a trip ID and vehicle ID claim.

Create a trip ID and vehicle ID claim

To track vehicles using the vehicle location provider, create a JSON Web Token (JWT) with a trip ID and vehicle ID claim.

To create the JWT payload, add an additional claim in the authorization section with the keys tripid and vehicleid and set the value of each key to *. The token should be created using the Fleet Engine Service Super User Cloud IAM role. Note that this grants broad access to create, read, and modify Fleet Engine entities, and should only be shared with trusted users.

The following example shows how to create a token for tracking by vehicle and task:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "private_key_id_of_consumer_service_account"
}
.
{
  "iss": "superuser@yourgcpproject.iam.gserviceaccount.com",
  "sub": "superuser@yourgcpproject.iam.gserviceaccount.com",
  "aud": "https://fleetengine.googleapis.com/",
  "iat": 1511900000,
  "exp": 1511903600,
  "scope": "https://www.googleapis.com/auth/xapi",
  "authorization": {
    "tripid": "*",
    "vehicleid": "*",
  }
}

Create an authentication token fetcher

The JavaScript Fleet Tracking Library requests a token using the authentication token fetcher when any of the following is true:

  • It does not have a valid token, such as when it hasn't called the fetcher on a fresh page load, or when the fetcher hasn't returned with a token.
  • The token it fetched previously has expired.
  • The token it fetched previously is within one minute of expiring.

Otherwise, the library uses the previously issued, still valid token and does not call the fetcher.

You can create an authentication token fetcher to retrieve a token created with the appropriate claims on your servers using a service account certificate for your project. It is important to only create tokens on your servers and never share your certificates on any clients. Otherwise, you may compromise the security of your system.

The fetcher must return a data structure with two fields, wrapped in a Promise:

  • A string token.
  • A number expiresInSeconds. A token expires in this amount of time after fetching.

The following example shows how to create an authentication token fetcher:

JavaScript

function authTokenFetcher(options) {
  // options is a record containing two keys called
  // serviceType and context. The developer should
  // generate the correct SERVER_TOKEN_URL and request
  // based on the values of these fields.
  const response = await fetch(SERVER_TOKEN_URL);
  if (!response.ok) {
    throw new Error(response.statusText);
  }
  const data = await response.json();
  return {
    token: data.Token,
    expiresInSeconds: data.ExpiresInSeconds
  };
}

TypeScript

function authTokenFetcher(options: {
  serviceType: google.maps.journeySharing.FleetEngineServiceType,
  context: google.maps.journeySharing.AuthTokenContext,
}): Promise<google.maps.journeySharing.AuthToken> {
  // The developer should generate the correct
  // SERVER_TOKEN_URL based on options.
  const response = await fetch(SERVER_TOKEN_URL);
  if (!response.ok) {
    throw new Error(response.statusText);
  }
  const data = await response.json();
  return {
    token: data.token,
    expiresInSeconds: data.expiration_timestamp_ms - Date.now(),
  };
}

When implementing the server-side endpoint for minting the tokens, keep the following in mind:

  • The endpoint must return an expiry time for the token; in the example above, it is given as data.ExpiresInSeconds.
  • The authentication token fetcher must pass the expiry time (in seconds, from time of fetching) to the library, as shown in the example.
  • The SERVER_TOKEN_URL depends on your backend implementation, these are example URLs:
    • https://SERVER_URL/token/driver/VEHICLE_ID
    • https://SERVER_URL/token/consumer/TRIP_ID
    • https://SERVER_URL/token/fleet_reader

Load a map from HTML

The following example shows how to load the JavaScript Journey Sharing library from a specified URL. The callback parameter executes the initMap function after the API loads. The defer attribute lets the browser continue rendering the rest of your page while the API loads.

 <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=journeySharing&v=beta" defer></script>

Follow a vehicle

This section shows how to use the JavaScript Fleet Tracking Library to follow a vehicle. Make sure to load the library from the callback function specified in the script tag before running your code.

Instantiate a vehicle location provider

The JavaScript Fleet Tracking Library predefines a location provider for the On Demand Rides and Deliveries API. Use your project ID and a reference to your token factory to instantiate it.

JavaScript

locationProvider =
    new google.maps.journeySharing
        .FleetEngineVehicleLocationProvider({
          projectId,
          authTokenFetcher,

          // Optionally, you may specify
          // vehicleId to immediately start
          // tracking.
          vehicleId: 'your-vehicle-id',
});

TypeScript

locationProvider =
    new google.maps.journeySharing
        .FleetEngineVehicleLocationProvider({
          projectId,
          authTokenFetcher,

          // Optionally, you may specify
          // vehicleId to immediately start
          // tracking.
          vehicleId: 'your-vehicle-id',
});

Initialize the map view

After loading the JavaScript Journey Sharing library, initialize the map view and add it to the HTML page. Your page should contain a <div> element that holds the map view. The <div> element is named map_canvas in the example below.

JavaScript

const mapView = new
    google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  // Styling customizations; see below.
  vehicleMarkerSetup: vehicleMarkerSetup,
  anticipatedRoutePolylineSetup:
      anticipatedRoutePolylineSetup,
  // Any undefined styling options will use defaults.
});

// If you did not specify a vehicle ID in the
// location provider constructor, you may do so here.
// Location tracking will start as soon as this is set.
locationProvider.vehicleId
                        = 'your-vehicle-id';

// Give the map an initial viewport to allow it to
// initialize; otherwise the 'ready' event above may
// not fire. The user also has access to the mapView
// object to customize as they wish.
mapView.map.setCenter('Times Square, New York, NY');
mapView.map.setZoom(14);

TypeScript

const mapView = new
    google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  // Styling customizations; see below.
  anticipatedRoutePolylineSetup:
      anticipatedRoutePolylineSetup,
  // Any undefined styling options will use defaults.
});

// If you did not specify a vehicle ID in the
// location provider constructor, you may do so here.
// Location tracking will start as soon as this is set.
locationProvider.vehicleId = 'your-vehicle-id';

// Give the map an initial viewport to allow it to
// initialize; otherwise the 'ready' event above may
// not fire. The user also has access to the mapView
// object to customize as they wish.
mapView.map.setCenter('Times Square, New York, NY');
mapView.map.setZoom(14);

Listen to change events

You can retrieve meta information about a vehicle from the vehicle object using the location provider. The meta information includes the ETA and remaining distance before the vehicle's next pickup or dropoff. Changes to the meta information trigger an update event. The following example shows how to listen to these change events.

JavaScript

locationProvider.addListener('update', e => {
  // e.vehicle contains data that may be
  // useful to the rest of the UI.
  if (e.vehicle) {
    console.log(e.vehicle.vehicleState);
  }
});

TypeScript

locationProvider.addListener('update',
    (e: google.maps.journeySharing.FleetEngineVehicleLocationProviderUpdateEvent) => {
  // e.vehicle contains data that may be useful to the rest of the UI.
  if (e.vehicle) {
    console.log(e.vehicle.vehicleState);
  }
});

Listen for errors

Errors that arise asynchronously from requesting vehicle information trigger error events. The following example shows how to listen for these events in order to handle errors.

JavaScript

locationProvider.addListener('error', e => {
  // e.error is the error that triggered the event.
  console.error(e.error);
});

TypeScript

locationProvider.addListener('error', (e: google.maps.ErrorEvent) => {
  // e.error is the error that triggered the event.
  console.error(e.error);
});

Stop tracking

To stop the location provider from tracking the vehicle, remove the vehicle ID from the location provider.

JavaScript

locationProvider.vehicleId = '';

TypeScript

locationProvider.vehicleId = '';

Remove the location provider from the map view

The following example shows how to remove a location provider from the map view.

JavaScript

mapView.removeLocationProvider(locationProvider);

TypeScript

mapView.removeLocationProvider(locationProvider);

View a vehicle fleet

This section shows how to use the JavaScript Journey Sharing library to view a vehicle fleet. Make sure to load the library from the callback function specified in the script tag before running your code.

Instantiate a vehicle fleet location provider

The JavaScript Fleet Tracking Library pre defines a location provider that fetches multiple vehicles from the On Demand Rides and Deliveries API. Use your project ID as well as a reference to your token fetcher to instantiate it.

JavaScript

locationProvider =
    new google.maps.journeySharing
        .FleetEngineFleetLocationProvider({
          projectId,
          authTokenFetcher,

          // Optionally, specify location bounds to
          // limit which vehicles are
          // retrieved and immediately start tracking.
          locationRestriction: {
            north: 37.3,
            east: -121.8,
            south: 37.1,
            west: -122,
          },
          // Optionally, specify a filter to limit
          // which vehicles are retrieved.
          vehicleFilter:
            'attributes.foo = "bar" AND attributes.baz = "qux"',
        });

TypeScript

locationProvider =
    new google.maps.journeySharing
        .FleetEngineFleetLocationProvider({
          projectId,
          authTokenFetcher,

          // Optionally, specify location bounds to
          // limit which vehicles are
          // retrieved and immediately start tracking.
          locationRestriction: {
            north: 37.3,
            east: -121.8,
            south: 37.1,
            west: -122,
          },
          // Optionally, specify a filter to limit
          // which vehicles are retrieved.
          vehicleFilter:
            'attributes.foo = "bar" AND attributes.baz = "qux"',
        });

vehicleFilter specifies a query used to filter vehicles displayed on the map. This filter is passed directly to Fleet Engine. See ListVehiclesRequest for supported formats.

locationRestriction limits the area in which to display vehicles on the map. It also controls whether location tracking is active or not. Location tracking won't start until this is set.

Once the location provider is constructed, initialize the map view.

Set location restriction using the map viewport

The locationRestriction bounds can be configured to match the area visible in the map view.

JavaScript

google.maps.event.addListenerOnce(
  mapView.map, 'bounds_changed', () => {
    const bounds = mapView.map.getBounds();
    if (bounds) {
      // If you did not specify a location restriction in the
      // location provider constructor, you may do so here.
      // Location tracking will start as soon as this is set.
      locationProvider.locationRestriction = bounds;
    }
  });

TypeScript

google.maps.event.addListenerOnce(
  mapView.map, 'bounds_changed', () => {
    const bounds = mapView.map.getBounds();
    if (bounds) {
      // If you did not specify a location restriction in the
      // location provider constructor, you may do so here.
      // Location tracking will start as soon as this is set.
      locationProvider.locationRestriction = bounds;
    }
  });

Listen to change events

You can retrieve meta information about the fleet from the vehicles object using the location provider. The meta information includes vehicle properties such as navigation status, distance to next waypoint and custom attributes; see reference documentation for more details. Change to the meta information trigger an update event. The following example shows how to listen to these change events.

JavaScript

locationProvider.addListener('update', e => {
  // e.vehicles contains data that may be
  // useful to the rest of the UI.
  if (e.vehicles) {
    for (vehicle of e.vehicles) {
      console.log(vehicle.navigationStatus);
    }
  }
});

TypeScript

locationProvider.addListener('update',
    (e: google.maps.journeySharing.FleetEngineFleetLocationProviderUpdateEvent) => {
  // e.vehicles contains data that may be useful to the rest of the UI.
  if (e.vehicles) {
    for (vehicle of e.vehicles) {
      console.log(vehicle.navigationStatus);
    }
  }
});

Listen for errors

Errors that arise asynchronously from requesting vehicle fleet information trigger error events. For examples showing how to listen for these events, refer to Listen for errors.

Stop tracking

To stop the location provider from tracking the fleet, set the bounds of the location provider to null.

JavaScript

locationProvider.locationRestriction = null;

TypeScript

locationProvider.locationRestriction = null;

Remove the location provider from the map view

The following example shows how to remove a location provider from the map view.

JavaScript

mapView.removeLocationProvider(locationProvider);

TypeScript

mapView.removeLocationProvider(locationProvider);

Customize the look and feel of the base map

To customize the look and feel of the maps component, style your map using cloud-based tooling or by setting options directly in code.

Use cloud-based map styling

Cloud-based maps styling lets you create and edit map styles for any of your apps that use Google Maps from the Google Cloud console without requiring any changes to your code. The map styles are saved as map IDs in your Cloud project. To apply a style to your JavaScript Fleet Tracking map, specify a mapId when you create the JourneySharingMapView. The mapId field cannot be changed or added after the JourneySharingMapView has been instantiated. The following example shows how to enable a previously created map style with a map ID.

JavaScript

const mapView = new google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  mapOptions: {
    mapId: 'YOUR_MAP_ID'
  }
});

TypeScript

const mapView = new google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  mapOptions: {
    mapId: 'YOUR_MAP_ID'
  }
});

Use code-based map styling

Another way of customizing map styling is to set mapOptions when you create the JourneySharingMapView.

JavaScript

const mapView = new google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  mapOptions: {
    styles: [
      {
        "featureType": "road.arterial",
        "elementType": "geometry",
        "stylers": [
          { "color": "#CCFFFF" }
        ]
      }
    ]
  }
});

TypeScript

const mapView = new google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  mapOptions: {
    styles: [
      {
        "featureType": "road.arterial",
        "elementType": "geometry",
        "stylers": [
          { "color": "#CCFFFF" }
        ]
      }
    ]
  }
});

Use marker customizations

With the JavaScript Fleet Tracking Library, you can customize the look and feel of markers added to the map. You do this by specifying marker customizations, which the Fleet Tracking Library then applies before adding markers to the map and with every marker update.

You can create a simple customization by specifying a MarkerOptions object to apply to all markers of the same type. The changes specified in the object are applied after each marker has been created, overwriting any default options.

As a more advanced option, you can specify a customization function. Customization functions allow for styling of the markers based on data, as well as adding interactivity to markers, such as click handling. Specifically, Fleet Tracking passes data to the customization function about the type of object the marker represents: vehicle, stop, or task. This then allows marker styling to change based on the current state of the marker element itself; for example, the number of remaining stops or type of task. You can even join against data from sources outside Fleet Engine and style the marker based on that information.

Additionally, you can use customization functions to filter marker visibility. To do this, call setVisible(false) on the marker.

However, for performance reasons, we recommend filtering with the native filtering in the location provider, such as FleetEngineFleetLocationProvider.vehicleFilter. That said, when you need additional filtering functionality, you can apply filtering using the customization function.

The Fleet Tracking library provides the following customization parameters:

Change the styling of markers using MarkerOptions

The following example shows how to configure a vehicle marker's styling with a MarkerOptions object. Follow this pattern to customize the styling of any marker using any of the marker customization parameters listed above.

JavaScript

vehicleMarkerCustomization = {
  cursor: 'grab'
};

TypeScript

vehicleMarkerCustomization = {
  cursor: 'grab'
};

Change the styling of markers using customization functions

The following example shows how to configure a vehicle marker's styling. Follow this pattern to customize the styling of any marker using any of the marker customization parameters listed above.

JavaScript

vehicleMarkerCustomization =
  (params) => {
    var remainingWaypoints = params.vehicle.waypoints.length;
    params.marker.setLabel(`${remainingWaypoints}`);
  };

TypeScript

vehicleMarkerCustomization =
  (params: VehicleMarkerCustomizationFunctionParams) => {
    var remainingWaypoints = params.vehicle.waypoints.length;
    params.marker.setLabel(`${remainingWaypoints}`);
  };

Add click handling to markers

The following example shows how to add click handling to a vehicle marker. Follow this pattern to add click handling to any marker using any of the marker customization parameters listed above.

JavaScript

vehicleMarkerCustomization =
  (params) => {
    if (params.isNew) {
      params.marker.addListener('click', () => {
        // Perform desired action.
      });
    }
  };

TypeScript

vehicleMarkerCustomization =
  (params: VehicleMarkerCustomizationFunctionParams) => {
    if (params.isNew) {
      params.marker.addListener('click', () => {
        // Perform desired action.
      });
    }
  };

Filter visible markers

The following example shows how to filter which vehicle markers are visible. Follow this pattern to filter any markers using any of the marker customization parameters listed above.

JavaScript

vehicleMarkerCustomization =
  (params) => {
    var remainingWaypoints = params.vehicle.remainingWaypoints.length;
      if (remainingWaypoints > 10) {
        params.marker.setVisible(false);
      }
  };

TypeScript

vehicleMarkerCustomization =
  (params: VehicleMarkerCustomizationFunctionParams) => {
    var remainingWaypoints = params.vehicle.remainingWaypoints.length;
    if (remainingWaypoints > 10) {
      params.marker.setVisible(false);
    }
  };

Use polyline customizations when following a vehicle

With the Fleet Tracking Library, you can also customize the look and feel of the followed vehicle's route on the map. The library creates a google.maps.Polyline object for each pair of coordinates in the vehicle's active or remaining path. You can style the Polyline objects by specifying polyline customizations. The library then applies these customizations in two situations: before adding the objects to the map, and when the data used for the objects have changed.

Similar to marker customization, you can specify a set of PolylineOptions to be applied to all of the matched Polyline objects when they are created or updated.

Likewise, you can specify a customization function. Customization functions allow for individual styling of the objects based on data sent by Fleet Engine. The function can change the styling of each object based on the current state of the vehicle; for example, coloring the Polyline object a deeper shade, or making it thicker when the vehicle is moving slower. You can even join against from sources outside Fleet Engine and style the Polyline object based on that information.

You can specify the customizations using parameters provided in FleetEngineVehicleLocationProviderOptions. You can set customizations for different path states in the vehicle's journey--already traveled, actively traveling, or not yet traveled. The parameters are as follows:

Change the styling of Polyline objects using PolylineOptions

The following example shows how to configure the styling for a Polyline object with PolylineOptions. Follow this pattern to customize the styling of any Polyline object using any of the polyline customizations listed earlier.

JavaScript

activePolylineCustomization = {
  strokeWidth: 5,
  strokeColor: 'black',
};

TypeScript

activePolylineCustomization = {
  strokeWidth: 5,
  strokeColor: 'black',
};

Change the styling of Polyline objects using customization functions

The following example shows how to configure an active Polyline object's styling. Follow this pattern to customize the styling of any Polyline object using any of the polyline customization parameters listed earlier.

JavaScript

// Color the Polyline objects in green if the vehicle is nearby.
activePolylineCustomization =
  (params) => {
    const distance = params.vehicle.waypoints[0].distanceMeters;
    if (distance < 1000) {

      // params.polylines contains an ordered list of Polyline objects for
      // the path.
      for (const polylineObject of params.polylines) {
        polylineObject.setOptions({strokeColor: 'green'});
      }
    }
  };

TypeScript

// Color the Polyline objects in green if the vehicle is nearby.
activePolylineCustomization =
  (params: VehiclePolylineCustomizationFunctionParams) => {
    const distance = params.vehicle.waypoints[0].distanceMeters;
    if (distance < 1000) {

      // params.polylines contains an ordered list of Polyline objects for
      // the path.
      for (const polylineObject of params.polylines) {
        polylineObject.setOptions({strokeColor: 'green'});
      }
    }
  };

Control the visibility of Polyline objects

By default, all Polyline objects are visible. To make a Polyline object invisible, set its visible property:

JavaScript

remainingPolylineCustomization = {visible: false};

TypeScript

remainingPolylineCustomization = {visible: false};

Render traffic-aware Polyline objects

Fleet Engine returns traffic speed data for the active and remaining paths for the followed vehicle. You can use this information to style the Polyline objects according to their traffic speeds:

JavaScript

// Color the Polyline objects according to their real-time traffic levels
// using '#05f' for normal, '#fa0' for slow, and '#f33' for traffic jam.
activePolylineCustomization =
  FleetEngineVehicleLocationProvider.
      TRAFFIC_AWARE_ACTIVE_POLYLINE_CUSTOMIZATION_FUNCTION;

// Or alter the objects further after the customization function has been
// run -- in this example, change the blue for normal to green:
activePolylineCustomization =
  (params) => {
    FleetEngineVehicleLocationProvider.
        TRAFFIC_AWARE_ACTIVE_POLYLINE_CUSTOMIZATION_FUNCTION(params);
    for (const polylineObject of params.polylines) {
      if (polylineObject.get('strokeColor') === '#05f') {
        polylineObject.setOptions({strokeColor: 'green'});
      }
    }
  };

TypeScript

// Color the Polyline objects according to their real-time traffic levels
// using '#05f' for normal, '#fa0' for slow, and '#f33' for traffic jam.
activePolylineCustomization =
  FleetEngineVehicleLocationProvider.
      TRAFFIC_AWARE_ACTIVE_POLYLINE_CUSTOMIZATION_FUNCTION;

// Or alter the objects further after the customization function has been
// run -- in this example, change the blue for normal to green:
activePolylineCustomization =
  (params: VehiclePolylineCustomizationFunctionParams) => {
    FleetEngineVehicleLocationProvider.
        TRAFFIC_AWARE_ACTIVE_POLYLINE_CUSTOMIZATION_FUNCTION(params);
    for (const polylineObject of params.polylines) {
      if (polylineObject.get('strokeColor') === '#05f') {
        polylineObject.setOptions({strokeColor: 'green'});
      }
    }
  };

Display an InfoWindow for a vehicle or location marker

You can use an InfoWindow to display additional information about a vehicle or location marker.

The following example shows how to create an InfoWindow and attach it to a vehicle marker.

JavaScript

// 1. Create an info window.
const infoWindow = new google.maps.InfoWindow(
    {disableAutoPan: true});

// (Assumes a vehicle location provider.)
locationProvider.addListener('update', e => {
  if (e.vehicle) {
    const distance =
          e.vehicle.remainingDistanceMeters;
    infoWindow.setContent(
        `Your vehicle is ${distance}m away from the next drop-off point.`);

    // 2. Attach the info window to a vehicle marker.
    // This property can return multiple markers.
    const marker = mapView.vehicleMarkers[0];
    infoWindow.open(mapView.map, marker);
  }
});

// 3. Close the info window.
infoWindow.close();

TypeScript

// 1. Create an info window.
const infoWindow = new google.maps.InfoWindow(
    {disableAutoPan: true});

// (Assumes a vehicle location provider.)
locationProvider.addListener('update', (e: google.maps.journeySharing.FleetEngineVehicleLocationProviderUpdateEvent) => {
  if (e.vehicle) {
    const distance =
          e.vehicle.remainingDistanceMeters;
    infoWindow.setContent(
        `Your vehicle is ${distance}m away from the next drop-off.`);
    // 2. Attach the info window to a vehicle marker.
    // This property can return multiple markers.
    const marker = mapView.vehicleMarkers[0];
    infoWindow.open(mapView.map, marker);
  }
});

// 3. Close the info window.
infoWindow.close();

Disable automatic fitting

You can stop the map from automatically fitting the viewport to the vehicle and anticipated route by disabling automatic fitting. The following example shows how to disable automatic fitting when you configure the journey sharing map view.

JavaScript

const mapView = new
    google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  automaticViewportMode:
      google.maps.journeySharing
          .AutomaticViewportMode.NONE,
  ...
});

TypeScript

const mapView = new
    google.maps.journeySharing.JourneySharingMapView({
  element: document.getElementById('map_canvas'),
  locationProviders: [locationProvider],
  automaticViewportMode:
      google.maps.journeySharing
          .AutomaticViewportMode.NONE,
  ...
});

Replace an existing map

You can replace an existing map that includes markers or other customizations without losing those customizations.

For example, suppose you have a web page with a standard google.maps.Map entity on which a marker is shown:

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Set the size of the div element that contains the map */
      #map {
        height: 400px; /* The height is 400 pixels */
        width: 100%; /* The width is the width of the web page */
      }
    </style>
  </head>
  <body>
    <h3>My Google Maps Demo</h3>
    <!--The div element for the map -->
    <div id="map"></div>
    <script>
      // Initialize and add the map
      function initMap() {
        // The location of Oracle Park Stadium
        var oraclePark = { lat: 37.780087547237365, lng: -122.38948437884427 };,
        // The map, initially centered at Mountain View, CA.
        var map = new google.maps.Map(document.getElementById("map"));
        map.setOptions({ center: { lat: 37.424069, lng: -122.0916944 }, zoom: 14 });

        // The marker, now positioned at Oracle Park
        var marker = new google.maps.Marker({ position: oraclePark, map: map });
      }
    </script>
    <!-- Load the API from the specified URL.
      * The async attribute allows the browser to render the page while the API loads.
      * The key parameter will contain your own API key (which is not needed for this tutorial).
      * The callback parameter executes the initMap() function.
    -->
    <script
      defer
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
    ></script>
  </body>
</html>

To add the JavaScript Journey Sharing library, which includes Fleet Tracking:

  1. Add code for the authentication token factory.
  2. Initialize a location provider in the initMap() function.
  3. Initialize the map view in the initMap() function. The view contains the map.
  4. Move your customization into the callback function for the map view initialization.
  5. Add the location library to the API loader.

The following example shows the changes to be made:

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Set the size of the div element that contains the map */
      #map {
        height: 400px; /* The height is 400 pixels */
        width: 100%; /* The width is the width of the web page */
      }
    </style>
  </head>
  <body>
    <h3>My Google Maps Demo</h3>
    <!--The div element for the map -->
    <div id="map"></div>
    <script>
      let locationProvider;

      // (1) Authentication Token Fetcher
      function authTokenFetcher(options) {
        // options is a record containing two keys called
        // serviceType and context. The developer should
        // generate the correct SERVER_TOKEN_URL and request
        // based on the values of these fields.
        const response = await fetch(SERVER_TOKEN_URL);
            if (!response.ok) {
              throw new Error(response.statusText);
            }
            const data = await response.json();
            return {
              token: data.Token,
              expiresInSeconds: data.ExpiresInSeconds
            };
      }

      // Initialize and add the map
      function initMap() {
        // (2) Initialize location provider. Use FleetEngineVehicleLocationProvider
        // as appropriate.
        locationProvider = new google.maps.journeySharing.FleetEngineVehicleLocationProvider({
          YOUR_PROVIDER_ID,
          authTokenFetcher,
        });

        // (3) Initialize map view (which contains the map).
        const mapView = new google.maps.journeySharing.JourneySharingMapView({
          element: document.getElementById('map'),
          locationProviders: [locationProvider],
          // any styling options
        });

      mapView.addListener('ready', () => {
        locationProvider.vehicleId = VEHICLE_ID;

          // (4) Add customizations like before.

          // The location of Oracle Park
          var oraclePark = {lat: 37.77995187146094, lng: -122.38957020952795};
          // The map, initially centered at Mountain View, CA.
          var map = mapView.map;
          map.setOptions({center: {lat: 37.424069, lng: -122.0916944}, zoom: 14});
          // The marker, now positioned at Oracle Park
          var marker = new google.maps.Marker({position: oraclePark, map: map});
        };
      }
    </script>
    <!-- Load the API from the specified URL
      * The async attribute allows the browser to render the page while the API loads
      * The key parameter will contain your own API key (which is not needed for this tutorial)
      * The callback parameter executes the initMap() function
      *
      * (5) Add the journey sharing library to the API loader, which includes Fleet Tracking functionality.
    -->
    <script
      defer
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=journeySharing&v=beta"
    ></script>
  </body>
</html>

If you operate a vehicle with the specified ID near Oracle Park, it will render on the map.