peterqliu / threebox

A three.js plugin for Mapbox GL JS, with support for basic animation and advanced 3D rendering.
MIT License
526 stars 320 forks source link

How to manage the speed animation or synchronize to real position? #73

Open mahdiridho opened 5 years ago

mahdiridho commented 5 years ago

Guys,

I implement this stuff on my mapbox client app for logistic. I reference my code to the examples/logistics.html for the sample. All parts are working well from the object loader, direction line, movement animation, etc. Untill I realized it's a just static animation that move a 3d object from point A to B with several axes (xyz) matrix, not bases gps coordinates (longlat). So it has been unuseful stuff right now where the animation not connected to the real device position.

I have been spending much time to work out how to synchronize both position between device and threebox 3d object. I created a small code to calculate the new duration of animation to manage the speed, like so :

  async getDeviceLocation() {
    this.devicePos = null; // always start with null
    await new Promise((resolve, reject)=>{
      navigator.geolocation.getCurrentPosition(
        (data) => {
          this.devicePos = [data.coords.longitude, data.coords.latitude];
          return resolve()
        }, (error) => {
          console.log('Error getting location', error);
          return reject()
        }, { maximumAge:0, enableHighAccuracy: true }
      )
    })
  }

  syncPos() {
    this.getDeviceLocation().then(()=>{
      let url = "https://api.mapbox.com/directions/v5/mapbox/driving/"+[this.devicePos, this.destination].join(';')+"?geometries=geojson&access_token=" + mapboxgl.accessToken
      this.fetchFunction(url, (data)=>{
        // this.currentDatePos the start date of the animation trip
        // durationDone the estimate of duration time has been passed
        let durationDone = new Date().getTime() - this.currentDatePos;
        // animationDistanceDone the estimate of distance has been passed by animation
        let animationDistanceDone = durationDone / this.directionOpt.duration * this.distance;
        // realDistanceDone the estimate of distance has been passed on real device
        let realDistanceDone = this.distance - data.routes[0].distance;
        // newDuration the new duration will be calculated to be updated onto animation duration
        let newDuration = animationDistanceDone / realDistanceDone * this.directionOpt.duration;
        newDuration = Math.floor(newDuration);
        this.layerObj.animationQueue[0].parameters.duration = newDuration;
        this.map.flyTo({center:this.devicePos});
        setTimeout(()=>{
           if (new Date().getTime() - this.currentDatePos > this.directionOpt.duration)
             this.syncPos();
        }, 2000)
      })
    })
  }

For something reason, the above code working in some point (but not accurate) and sometimes return wrong or error in other point. I'm struggling with this puzzle and decide to ask some hands. If you have experience and other good approach, please share here?

Best