Redrawing google route and updating markers without reloading the Map

What I am trying to achieve is to load a map and display route between two markers retrieved from database. I want to be able to retrieve new coordinates every few seconds and draw and place markers on map without reloading map. I was able to do this using javascript and ajax but now i need same implementation using ionic typescript. But honestly dont know how

Current Project Setup

Ionic:

Ionic CLI : 7.1.1 (/Users/remmessesthegreat/.nvm/versions/node/v16.4.2/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.8.5
@angular-devkit/build-angular : 12.1.4
@angular-devkit/schematics : 12.2.12
@angular/cli : 12.1.4
@ionic/angular-toolkit : 4.0.0

Capacitor:

Capacitor CLI : 3.4.1
@capacitor/android : 3.4.1
@capacitor/core : 3.4.1
@capacitor/ios : 3.4.1

Cordova:

Cordova CLI : 11.0.0
Cordova Platforms : none
Cordova Plugins : no whitelisted plugins (0 plugins total)

Utility:

cordova-res : 0.15.4
native-run (update available: 1.7.2) : 1.5.0

System:

NodeJS : v16.4.2 (/Users/remmessesthegreat/.nvm/versions/node/v16.4.2/bin/node)
npm : 8.18.0
OS : macOS Unknown
Xcode : Xcode 14.3 Build version 14E222b

Currently this is the code i have thats working on displaying routes and markers. I know its a bit messy and all over the place but should give an idea of what i want to create but honestly i’m not that good at this.

import { Component, ViewChild, ElementRef } from '@angular/core';
import { Geolocation } from '@ionic-native/geolocation/ngx';
import { NativeGeocoder, NativeGeocoderResult, NativeGeocoderOptions } from '@ionic-native/native-geocoder/ngx';
import { ModalController, AlertController, LoadingController } from '@ionic/angular';
import { HttpClient } from '@angular/common/http';
import { Storage } from '@capacitor/storage';
import { google } from "google-maps";
import * as GoogleMapsLoader from 'google-maps';

@Component({
  selector: 'app-track',
  templateUrl: './track.page.html',
  styleUrls: ['./track.page.scss'],
})
export class TrackPage{

  @ViewChild('hmap', { static: false }) mapElement: ElementRef;
  map: any;
  pois: any;
  address: string;
  email: string;
  latitude: any;
  longitude: any;
  duration: any;
  distance: any;
  mlat: any;
  mlng: any;
  userid: string =""
  deliverToLat: any =""
  deliverToLng: any =""
  currentaddress: string =""
  deliverTo: string =""
  contractor_name: string =""
  
  driverdetails: any;
  markerData: any;
  private loader: HTMLIonLoadingElement;
  private loaderLoading = false;

  constructor(
    public modalController: ModalController,
    public alert: AlertController,
    public loadingController: LoadingController,
    private http: HttpClient,
    private geolocation: Geolocation,
    private nativeGeocoder: NativeGeocoder
    
  ) {
    
   }

  ngOnInit() {
    

  }

  ionViewWillEnter() {

    var heighDevice = window.screen.height;
    var FirstELement = document.getElementById('hmap');//MyAppModal id element 
    var heightElm = (heighDevice  * 100) / 100; // 40 is height in vh  
    // add the height to the element
    FirstELement.style["height"] =  heightElm + "px";
    // somecode
    this.simpleLoader();
    this.getDriverLocation();
    this.dismissLoading();
    
  }

 

  loadMap() {
    var directionDisplay;
     this.map = new google.maps.Map(
      document.getElementById("hmap") as HTMLElement,
      {
        zoom: 20,
        disableDefaultUI: true,
        mapTypeId: 'roadmap',
        center: { lat: this.mlat, lng: this.mlng },
      }
      
    );

    var rendererOptions = {
      map: this.map,
      suppressMarkers: true
  };
    const directionsRenderer = new google.maps.DirectionsRenderer();
    const directionsService = new google.maps.DirectionsService();

    directionDisplay = new google.maps.DirectionsRenderer(rendererOptions);


    
    directionDisplay.setMap(this.map);
    

    this.calculateAndDisplayRoute(directionsService, directionDisplay);
    

    
  }

  async calculateAndDisplayRoute(
    directionsService: google.maps.DirectionsService,
    directionsRenderer: google.maps.DirectionsRenderer
  ) {
    directionsService
      .route({
        origin: { lat: this.mlat, lng: this.mlng }, // Haight.
        destination: { lat: parseFloat(this.deliverToLat), lng: parseFloat(this.deliverToLng) }, // Ocean Beach.
        // Note that Javascript allows us to access the constant
        // using square brackets and a string value as its
        // "property."
        
        travelMode: google.maps.TravelMode.DRIVING,
      })
      .then((response) => {
        directionsRenderer.setDirections(response);
        this.addContractorMarker();
        this.addUserMarker();
        const directionData = response.routes[0].legs[0];

        this.duration = directionData.duration.text;
        this.distance = directionData.distance.text;
        
      })
      .catch((e) => window.alert("Directions request failed due to " + e));
  }

  


  async setSessionObject(latitude,longitude) {
    await Storage.set({
      key: 'userlocation',
      value: JSON.stringify({
        latitude: latitude,
        longitude: longitude
      })

    });
  }

  

 

  async getSessionObject()
  {
    const ret = await Storage.get({ key: 'user'});
    const user = JSON.parse(ret.value);

    
this.email = user.email;
    return user;
  }


 

  dismiss() {
    // using the injected ModalController this page
    // can "dismiss" itself and optionally pass back data
    this.modalController.dismiss({
      'dismissed': true
    });
  }

 
  async getDriverLocation()
    {
     
    
    const ret = await Storage.get({ key: 'driver'});
    const profile = JSON.parse(ret.value);
    
      this.deliverTo = profile.deliverTo;
      this.contractor_name = profile.first_name
          
            this.http.get('https://driversauth.example.co.za/Controller/getDriverLocation?driver_id='+ profile.driverid)
            .subscribe(data => {
    
            this.driverdetails = data['driverlocation'];
  
            console.log(data);
              
            this.mlng= parseFloat(this.driverdetails.longitude),
            this.mlat = parseFloat(this.driverdetails.latitude)
            this.getAddressDetails();
            
           
            });
    
  
   
      console.log('New location'); 
    }

    async getAddressDetails(){
  
   

      const ret = await Storage.get({ key: 'user'});
      const user = JSON.parse(ret.value);
    
       
          this.http.get('https://usersauth.example.co.za/UserAddress/gethomeaddress?user_id='+ user.user_id)
          .subscribe(data => {
              
          
          this.currentaddress = data['user']['homeaddress'];
          

          if(this.deliverTo == 'homeaddress')
          {
          this.deliverToLat = data['user']['homelat'];
          this.deliverToLng = data['user']['homelng'];
          }
          if(this.deliverTo == 'workaddress')
          {
          this.deliverToLat = data['user']['worklat'];
          this.deliverToLng = data['user']['worklng'];
          }

          this.loadMap(); 
             }, error => {
    
              
            console.log(error);
    
              });

        

    }

    async addContractorMarker(){
      let position = new google.maps.LatLng(this.mlat,this.mlng);
      let mapMarker = new google.maps.Marker({
        position: position,
        icon: {
          url:'../assets/icon/bluepulse.gif',
          size: new google.maps.Size(36, 30),
          scaledSize: new google.maps.Size(36, 30),
          anchor: new google.maps.Point(20, 20)
          }
      });
      mapMarker.setMap(this.map);
    }

    async addUserMarker(){
      let position = new google.maps.LatLng(this.deliverToLat,this.deliverToLng);
      let mapMarker = new google.maps.Marker({
        position: position,
        icon: {
          url:'../assets/icon/location-marker.gif',
          size: new google.maps.Size(36, 30),
          scaledSize: new google.maps.Size(36, 30),
          anchor: new google.maps.Point(20, 20)
          }
      });
      mapMarker.setMap(this.map);
    }

    async removeMarkers(){
      let mapMarker = new google.maps.Marker();

      mapMarker.setMap(null);

    }

 

  

    public simpleLoader() {
      this.loaderLoading = true;
      this.loadingController.create({
          message:'Loading...',
          cssClass:'loader-css-class',
          showBackdrop: true
      }).then(load => {
          this.loader = load;
          load.present().then(() => { this.loaderLoading = false; });
      });
    }
    
    public dismissLoading() {
      const interval = setInterval(() => {
          if (this.loader || !this.loaderLoading) {
              this.loader.dismiss().then(() => { this.loader = null; clearInterval(interval)});
          } else if (!this.loader && !this.loaderLoading) {
              clearInterval(interval);
          }
      }, 1000);
    }



   
}


The code above output the following. What i need help with is

  1. Page Lifecycle I want to load the data first before loading the map. Once data has loaded use data to draw route and add markers.
  2. I want to be able to get data from database at certain intervals and update map with new data without reloading the map or refreshing the page.
  3. if possible i would also like the duration and distance to also update as the driver moves towards destination.

Just to add a little bit of context. There is a driver who has an app that updates his/her location as they move. coordinates are saved on database as they move. User gets to see driver as they are coming to them and duration and distance.

I’m not the best of programmers and honestly need help with this specific functionality to get the app to be more interactive with user being able to see or track the driver as they are approaching. I apologise if my explanation is bad. Thank you in advance

Hi Guys, I have managed to get it working buy loading map first then calculating route and adding markers after. Now the problems is that the polyline keeps getting darker and darker because its not being removed on intervals. Looked it up and someone set Setmap(Null) when i do i get undefined property. Here is the full working code. It works as i expect it to but now i just want to make sure polyline also gets reset and not draw on previous one. I also tried suppressPolyline: true but it completely removes the polyline and only shows markers. Thanks in advance

import { Component, ViewChild, ElementRef } from '@angular/core';
import { Geolocation } from '@ionic-native/geolocation/ngx';
import { NativeGeocoder, NativeGeocoderResult, NativeGeocoderOptions } from '@ionic-native/native-geocoder/ngx';
import { ModalController, AlertController, LoadingController } from '@ionic/angular';
import { HttpClient } from '@angular/common/http';
import { Storage } from '@capacitor/storage';
import { google } from "google-maps";
import * as GoogleMapsLoader from 'google-maps';

@Component({
  selector: 'app-track',
  templateUrl: './track.page.html',
  styleUrls: ['./track.page.scss'],
})
export class TrackPage{

  @ViewChild('hmap', { static: false }) mapElement: ElementRef;
  map: any;
  pois: any;
  address: string;
  email: string;
  latitude: any;
  longitude: any;
  duration: any;
  distance: any;
  mlat: any;
  mlng: any;
  userid: string =""
  deliverToLat: any;
  deliverToLng: any;
  currentaddress: string =""
  deliverTo: string =""
  contractor_name: string =""
  directionDisplay: any;
  
  driverdetails: any;
  markerData: any;
  private loader: HTMLIonLoadingElement;
  private loaderLoading = false;

  constructor(
    public modalController: ModalController,
    public alert: AlertController,
    public loadingController: LoadingController,
    private http: HttpClient,
    private geolocation: Geolocation,
    private nativeGeocoder: NativeGeocoder
    
  ) {
    
   }

  ngOnInit() {
    

  }

  ionViewWillEnter() {

    var heighDevice = window.screen.height;
    var FirstELement = document.getElementById('hmap');//MyAppModal id element 
    var heightElm = (heighDevice  * 100) / 100; // 40 is height in vh  
    // add the height to the element
    FirstELement.style["height"] =  heightElm + "px";
    // somecode
    this.simpleLoader();
    
    this.initMap();
    setInterval(() => {
      this.getDriverLocation()}
      , 3000);
    this.dismissLoading();
    
  }


  
  async initMap(): Promise<void> {
    
    this.map = new google.maps.Map(document.getElementById("hmap") as HTMLElement, {
      center: { lat: -25.9363294, lng: 28.1882604 },
      zoom: 10,
        disableDefaultUI: true,
        mapTypeId: 'roadmap',
    
    });

    console.log('Map loaded');
  }


  async setSessionObject(latitude,longitude) {
    await Storage.set({
      key: 'userlocation',
      value: JSON.stringify({
        latitude: latitude,
        longitude: longitude
      })

    });
  }

  

 

  async getSessionObject()
  {
    const ret = await Storage.get({ key: 'user'});
    const user = JSON.parse(ret.value);

    
this.email = user.email;
    return user;
  }


 

  dismiss() {
    // using the injected ModalController this page
    // can "dismiss" itself and optionally pass back data
    this.modalController.dismiss({
      'dismissed': true
    });
  }

 
  async getDriverLocation()
    {
      console.log('Driver Details loaded'); 
    
    const ret = await Storage.get({ key: 'driver'});
    const profile = JSON.parse(ret.value);

    const ret1 = await Storage.get({ key: 'user'});
          const user = JSON.parse(ret1.value);
    
      this.deliverTo = profile.deliverTo;
      this.contractor_name = profile.first_name
          
            this.http.get('https://driversauth.example.co.za/ControllerName/getDriverLocation?driver_id='+ profile.driverid)
            .subscribe(data => {
    
            this.driverdetails = data['driverlocation'];
  
           
              
            this.mlng= this.driverdetails.longitude;
            this.mlat = this.driverdetails.latitude;

            
    
       
          this.http.get('https://usersauth.example.co.za/UserAddress/gethomeaddress?user_id='+ user.user_id)
          .subscribe(data => {
              
          
          this.currentaddress = data['user']['homeaddress'];
          
          

          if(this.deliverTo == 'homeaddress')
          {
          this.deliverToLat = data['user']['homelat'];
          this.deliverToLng = data['user']['homelng'];
          }
          if(this.deliverTo == 'workaddress')
          {
          this.deliverToLat = data['user']['worklat'];
          this.deliverToLng = data['user']['worklng'];
          }
          
          
          
          var rendererOptions = {
            map: this.map,
            suppressMarkers: true
       
        };
          const directionsRenderer = new google.maps.DirectionsRenderer();
          const directionsService = new google.maps.DirectionsService();
          
          this.directionDisplay = new google.maps.DirectionsRenderer(rendererOptions);
          
      
          
          this.directionDisplay.setMap(this.map);
          
      
          this.calculateAndDisplayRoute(directionsService, this.directionDisplay);
  


         
             }, error => {
    
              
            console.log(error);
    
              });
          
            
           
            });



            
     
    }


    async calculateAndDisplayRoute(
    
      directionsService: google.maps.DirectionsService,
      directionsRenderer: google.maps.DirectionsRenderer
  ) {
    
      directionsService
        .route({
          origin: { lat: parseFloat(this.mlat), lng: parseFloat(this.mlng) }, // Haight.
          destination: { lat: parseFloat(this.deliverToLat), lng: parseFloat(this.deliverToLng) }, // Ocean Beach.
          // Note that Javascript allows us to access the constant
          // using square brackets and a string value as its
          // "property."
          
          travelMode: google.maps.TravelMode.DRIVING,
        })
        .then((response) => {
          directionsRenderer.setDirections(response);
          this.removeMarkers();
          this.addContractorMarker();
          this.addUserMarker();
          const directionData = response.routes[0].legs[0];
  
          this.duration = directionData.duration.text;
          this.distance = directionData.distance.text;
          
        })
        .catch((e) => window.alert("Directions request failed due to " + e));
    }

    async addContractorMarker(){
      let position = new google.maps.LatLng(this.mlat,this.mlng);
      let mapMarker = new google.maps.Marker({
        position: position,
        icon: {
          url:'../assets/icon/bluepulse.gif',
          size: new google.maps.Size(36, 30),
          scaledSize: new google.maps.Size(36, 30),
          anchor: new google.maps.Point(20, 20)
          }
      });
      mapMarker.setMap(this.map);
    }

    async addUserMarker(){
      let position = new google.maps.LatLng(this.deliverToLat,this.deliverToLng);
      let mapMarker = new google.maps.Marker({
        position: position,
        icon: {
          url:'../assets/icon/location-marker.gif',
          size: new google.maps.Size(36, 30),
          scaledSize: new google.maps.Size(36, 30),
          anchor: new google.maps.Point(20, 20)
          }
      });
      mapMarker.setMap(this.map);
    }

    async removeMarkers(){
      let mapMarker = new google.maps.Marker();

      mapMarker.setMap(null);

    }

    
 

  

    public simpleLoader() {
      this.loaderLoading = true;
      this.loadingController.create({
          message:'Loading...',
          cssClass:'loader-css-class',
          showBackdrop: true
      }).then(load => {
          this.loader = load;
          load.present().then(() => { this.loaderLoading = false; });
      });
    }
    
    public dismissLoading() {
      const interval = setInterval(() => {
          if (this.loader || !this.loaderLoading) {
              this.loader.dismiss().then(() => { this.loader = null; clearInterval(interval)});
          } else if (!this.loader && !this.loaderLoading) {
              clearInterval(interval);
          }
      }, 1000);
    }



   
}

So i tried the following

 async removeLine() {
      this.directionDisplay.setMap(null);
    }

It works only if i set the interval at 1000. Anything greater than that it does not work. It makes the like blink every. second. If there is anyone who can suggest a better way of this implementation please anything is welcome.

setInterval(() => {
      this.removeLine();
      this.getDriverLocation()}
      , 1000);

It does what its intended to do I’m just not sure if this approach is good enough. I’ve heard and read about observables but i dont know where i would start to implement them. So that i can have it working as efficient as possible.