Gaode map path playback

Gaode map path playback

Create Gaode map

  • Install our Vue amap dependencies
    • Official website https://github.com/ElemeFE/vue-amap It has detailed teaching
    • Visual panel installation (I recommend a super favorite method)
    • npm install -S vue-amap
  • Configure on main.js
    // Import AMap
    import AMap from 'vue-amap'
    // register
    Vue.use(AMap)
    // load
    AMap.initAMapApiLoader({
      // Golde's key
      key: 'You're cute key',
      // Plug in collection
      plugin: ['AMapManager', 'AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor', 'Geocoder', 'Geolocation', 'AMap.MarkerClusterer', 'AMap.PolyEditor', 'AMap.CircleEditor', 'AMap.MouseTool', 'AMap.Driving', 'AMap.CitySearch', 'AMap.InfoWindow', 'AMap.LngLat', 'AMap.DistrictSearch', 'AMap.TileLayer.Traffic', 'AMap.Heatmap', 'AMap.Autocomplete', 'AMap.PlaceSearch'],
      // Gaode sdk version, the default is 1.4.4
      v: '1.4.4'
    })
    
  • If AMap's is not defined, try the following method
    • Configure in. eslintrc.js
      globals: {
        AMap: true,
        AMapUI: true,
      },
      
    • Configure in index.html
      <script type="text/javascript" src="https://Webapi. Amap. COM / maps? V = 1.4.15 & key = your lovely key ">
      </script>
      <script src="//webapi.amap.com/ui/1.1/main.js?v=1.1.1"></script>
      
  • Set the container for storing the map (the set div size of the map is not shown)
    <!-- Map -->
    <div id="container"></div>
    
  • Set up map
    mounted() {
      // Setting up the map is basically configured
      const param = {
        // Are map container size changes monitored
        resizeEnable: true,
         // Initial map level
        zoom: 15
      }
      this.map = new AMap.Map('container', param)
    },
    

If you do this, the map can be displayed

Create alignment

Style of alignment: https://lbs.amap.com/api/amap-ui/reference-amap-ui/mass-data/pathsimplifier/

  • Data transferred from the background (it can be lost in data or imported into js)

    // Route from background
    linePath: [
      {
        latitude: 39.997761,
        longitude: 116.478935,
        time: '2020-08-21 16:21:18'
      },
      {
        latitude: 39.997825,
        longitude: 116.478939,
        time: '2020-08-21 16:21:21'
      },
      {
        latitude: 39.998549,
        longitude: 116.478912,
        time: '2020-08-21 16:21:24'
      },
      {
        latitude: 39.998555,
        longitude: 116.478998,
        time: '2020-08-21 16:21:27'
      },
      {
        latitude: 39.99856,
        longitude: 116.479282,
        time: '2020-08-21 16:21:30'
      },
      {
        latitude: 39.998528,
        longitude: 116.479658,
        time: '2020-08-21 16:21:33'
      },
      {
        latitude: 39.998453,
        longitude: 116.480151,
        time: '2020-08-21 16:21:36'
      },
      {
        latitude: 39.998302,
        longitude: 116.480784,
        time: '2020-08-21 16:21:39'
      },
      {
        latitude: 39.998184,
        longitude: 116.481149,
        time: '2020-08-21 16:21:42'
      },
      {
        latitude: 39.997997,
        longitude: 116.481573,
        time: '2020-08-21 16:21:45'
      },
      {
        latitude: 39.997846,
        longitude: 116.481863,
        time: '2020-08-21 16:21:48'
      },
      {
        latitude: 39.997718,
        longitude: 116.482072,
        time: '2020-08-21 16:21:51'
      },
      {
        latitude: 39.997718,
        longitude: 116.482362,
        time: '2020-08-21 16:21:54'
      },
      {
        latitude: 39.998935,
        longitude: 116.483633,
        time: '2020-08-21 16:21:57'
      },
      {
        latitude: 39.998968,
        longitude: 116.48367,
        time: '2020-08-21 16:22:00'
      },
      {
        latitude: 39.999861,
        longitude: 116.484648,
        time: '2020-08-21 16:22:03'
      }
    ]
    
  • We need to convert the json passed in the background into an array

     // initialization
     init() {
       // The data passed in the background is json, so we change it to array
       // trajectory
       // Line route
       let linePath = this.linePath
       linePath.forEach(item => {
         // Convert json to array
         this.pathList.push([item.longitude, item.latitude])
       })
       // Set route
       this.setPath()
     },
    
  • Set route

     // Set route
     setPath() {
       let that = this
       AMapUI.load(['ui/misc/PathSimplifier', 'lib/$'], function(
         PathSimplifier
       ) {
         if (!PathSimplifier.supportCanvas) {
           console.log('The current environment does not support Canvas!')
           return
         }
         function onload() {
           that.pathSimplifierIns.renderLater()
         }
         function onerror() {
           console.log('Picture loading failed!')
         }
         // Historical track cruiser
         that.pathSimplifierIns = new PathSimplifier({
           zIndex: 100,
           map: that.map, // Map instance to which
           getPath: function(pathData) {
             // The pathData here saves the route
             return pathData.path
           },
           // Auto set view
           autoSetFitView: true,
           // Cruise style
           renderOptions: {
             // Path navigation style
             pathNavigatorStyle: {
               // Rotation angle of trolley at the beginning
               initRotateDegree: 0,
               // Width of trolley
               width: 20,
               // Height of trolley
               height: 32,
               // Automatic rotation
               autoRotate: true,
               // Polyline inflection point connection style
               lineJoin: 'round',
               // PathSimplifier provides a shortcut to create content (function) of picture content:
               // Picture address
               // The picture is loaded successfully. Redraw the onload method again
               // Picture loading failed. onerror method
               content: PathSimplifier.Render.Canvas.getImageContent(
                 'https://webapi.amap.com/images/car.png',
                 onload,
                 onerror
               ),
               // This position reminds us that we can't see the effect because we use pictures
               // To see the effect, delete the content above
               // It's a triangle. Here's how to set the border color and internal color
               // Fill color
               fillStyle: null,
               // Stroke color
               strokeStyle: null,
               // Width of edge
               lineWidth: 1,
               // The style of the path the cruiser passes through
               pathLinePassedStyle: {
                 lineWidth: 6,
                 strokeStyle: 'skyblue'
               }
             },
             // Line style
             pathLineStyle: {
               lineWidth: 6,
               strokeStyle: 'pink'
             },
             // The style of the line after the mouse is moved in
             pathLineHoverStyle: {
               lineWidth: 0,
               borderWidth: 0
             },
             // The style of the line after the mouse click
             pathLineSelectedStyle: {
               lineWidth: 6,
               borderWidth: 0,
               strokeStyle: 'blue'
             },
             pathTolerance: 0,
             keyPointTolerance: -1,
             renderAllPointsIfNumberBelow: 0 // Draw the route node, which can be set to - 1 if not required
           }
         })
         // Historical track cruiser setting data here is the data of pathData above
         that.pathSimplifierIns.setData([
           {
             name: 'trajectory',
             path: that.pathList
           }
         ])
       })
     }
    

If you do this, the route can be displayed

Create small icons

  • Data transferred from the background (it can be lost in data or imported into js)

    // icon on the map passed from the background
    inco: [
      {
        latitude: 39.997761,
        longitude: 116.478935
      },
      {
        latitude: 39.99856,
        longitude: 116.479282
      },
      {
        latitude: 39.999861,
        longitude: 116.484648
      }
    ]
    
  • Traverse to create icon

    // initial
    init() {
      // Create start and pass icon s
      this.icon.forEach(item => {
        this.addIcon(item)
      })
    },
    addIcon(item) {
      // Set the content of each icon
      const marker = new AMap.Marker({
        // picture
        icon:
          '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
          // position
        position: [item.longitude, item.latitude],
          //Set base point offset
        offset: new AMap.Pixel(-13, -30)
      })
      // Put the icon on the map
      marker.setMap(this.map)
    }
    
  • Modify the style (if the icon is too large, you can modify the image f12 to check. If the setting fails, you need to consider a deeper scope)

    // Set icon size
    /deep/.amap-icon img {
      width: 25px;
      height: 34px;
    }
    

After this step, the icon can be displayed

Create Cruise

Let's create a cruiser first, then study it, and then move it

  • Set a cruise control in the data
     // Cruiser
     navgtr: null
    
  • setPath
     // Turn on Center adaptation
     that.pathSimplifierIns.setFitView(-1)
     // Create a cruiser for the first line (i.e. index 0)
     that.navgtr = that.pathSimplifierIns.createPathNavigator(0, {
       loop: false // Loop Playback
     })
    

After this step, the car can be displayed

Add import progress bar

  • You can use iview here in any framework

    • Installation dependency
    • Import (main.js)
      // Import Vue amap
      import AMap from 'vue-amap'
      // Import iview
      import iView from 'iview'
      // Register iview
      Vue.use(iView)
      
  • Code part

        <!-- progress bar -->
        <div class="map-control">
          <!-- Start button -->
          <Icon v-if="!start" class="play-icon" type="ios-play" @click="navgControl"/>
          <!-- Pause button -->
          <Icon v-else class="play-icon" type="ios-pause" @click="navgControl"/>
          <!-- start time -->
          <span class="passed-time">00:00:00</span>
          <Slider class="map-slider"></Slider>
          <!-- multiple -->
          <div class="map-times" @mouseenter="isTimesChoose=true" @mouseleave="isTimesChoose=false">
            <div class="times-show">Double speed{{times}}</div>
            <div class="choose-box">
              <!-- <ul v-show="isTimesChoose"> -->
              <ul v-show="isTimesChoose">
                <li v-for="item in speedList" :key="item" :class="{active:times==item}" @click="changeSpeed(1)">Double speed {{item}}</li>
              </ul>
            </div>
          </div>>
          <!-- end -->
          <span class="passed-time">00:00:00</span>
        </div>
    
    // Set icon size
    /deep/.amap-icon img {
      width: 25px;
      height: 34px;
    }
    // Set circulator style
    .map-control {
      // Absolute positioning
      position: absolute;
      bottom: 0;
      left: 0;
      width: 1200px;
      height: 80px;
      line-height: 80px;
      color: #fff;
      background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
      padding: 0 40px;
      z-index: 1000;
      // Set button size
      .play-icon {
        font-size: 36px;
      }
      // Set time style
      .passed-time {
        // Relative positioning
        position: relative;
        // Convert to inline element
        display: inline-block;
        top: 1px;
        margin-left: 15px;
        font-size: 14px;
      }
      // Progress bar style
      .map-slider {
        // Convert to inline element
        display: inline-block;
        width: 75%;
        margin-left: 15px;
        position: relative;
        top: 14px;
      }
      // Modify the default progress bar style
      .choose-box {
        // Relative positioning
        position: absolute;
        top: -135px;
        left: -6px;
        height: 162px;
        // filter
        transition: all 0.5s linear;
      }
      // multiple
      .map-times {
        display: inline-block;
        position: relative;
        margin-left: 15px;
        // Double speed style
        .times-show {
          padding: 0 10px;
          line-height: 24px;
          font-size: 13px;
          border: 1px solid #fff;
          border-radius: 4px;
          // Set the mouse to the default style
          cursor: default;
        }
        // multiple
        ul {
          background: rgba(0, 0, 0, 0.7);
          padding: 10px;
          width: 70px;
          text-align: center;
          border-radius: 3px;
          li {
            height: 26px;
            line-height: 26px;
            cursor: pointer;
          }
          li.active {
            color: #ff8533;
          }
          li:hover {
            font-size: 13px;
          }
        }
      }
    }
    
    // Pause and play buttons
    navgControl() {
      this.start = !this.start
    },
    // progress bar
    changeSpeed(item) {
      this.times = item
    }
    

Calculate speed and playback time

  • We need to convert the time passed to us by the background into a timestamp

    • 2020-08-21 16:21:18 — 1597998078000

    • Continue coding in init

      linePath.forEach(item => {
        // Convert json to array
        this.pathList.push([item.longitude, item.latitude])
        // Current timestamp
        item.stampTime = new Date(item.time).getTime()
      })
      
  • We need to calculate the speed of each distance. Here, let's assume that the length of the array is x, and there are a, b, c

    • We need to calculate the speed, time and distance of a-b, and so on

    • The time and distance have given us, but the speed is poor. This primary school problem is not explained. Go to the code

    • Calculate the direct distance of 2 points, which is inconvenient to extract in for

      // Calculate the distance between two coordinate points
      distanceFun(point1, point2) {
        // That array is converted to latitude and longitude
        let p1 = new AMap.LngLat(point1[0], point1[1])
        let p2 = new AMap.LngLat(point2[0], point2[1])
        // Calculate the direct distance distance of 2 points. This function continues. You can learn about it
        let distance = Math.round(p1.distance(p2))
        return distance
      }
      
    • Calculate the 2-point direct velocity

      • Calculate how many s the next journey takes,
      • intervalTime interval seconds
      • nextDistance: next distance: m,
      • nextDistance: next section speed: km/h
      linePath.forEach((item, i) => {
        // Get to the next location
        let next = linePath[i + 1]
        // Determine if there is another one
        if (next) {
          // Calculate the interval per second
          item.intervalTime = (next.stampTime - item.stampTime) / 1000
          // Calculate the next station
          item.nextDistance = this.distanceFun(
            [item.longitude, item.latitude],
            [next.longitude, next.latitude]
          )
          // Find the specific speed
          item.nextSpeed =
            item.nextDistance / 1000 / (item.intervalTime / 60 / 60)
        }
      })
      
    • Calculate the total time (because it's too simple, let's just say it here)

      // Calculate the total time. hh:mm:ss because the calculated time is time, format it
      this.totalTime = this.getTime(
        (endPoint.stampTime - startPoint.stampTime) / 1000
      )
      
      // Format time (not explained)
      getTime(sTime) {
        let ss
        let mm = '00'
        let hh = '00'
        if (sTime > 60) {
          let s = sTime % 60
          ss = s > 9 ? s : '0' + s
          let mTime = parseInt(sTime / 60)
          if (mTime > 60) {
            let m = mTime % 60
            mm = m > 9 ? m : '0' + m
            hh = parseInt(mTime / 60)
          } else {
            mm = mTime > 9 ? mTime : '0' + mTime
          }
        } else {
          ss = sTime > 9 ? sTime : '0' + sTime
        }
        return hh + ':' + mm + ':' + ss
      }
      
      • Add in date
         // Total time
         totalTime: '00:00:00',
        
      • Total time to modify pages
          <span class="passed-time">{{totalTime}}</span>
        

Slider change event

Bind sliding event to sliding bar

<Slider class="map-slider" @on-input="sliderChange"></Slider>
// Slider change event
sliderChange(val) {
  // Calculate start distance
  let num = parseInt((val / 100) * this.pathList.length)
  // Distance to end of calculation
  let decimal =
    String((val / 100) * this.pathList.length).split('.')[1] || 0
  // Mobile trolley
  this.navgtr.moveToPoint(num, Number('0.' + decimal))
  // Redraw
  this.pathSimplifierIns.renderLater()
},

After completion, move the slider to change the trolley position

Set the status in the move

  • We need to get an open speed, two ways

    • Calculate the initial speed
    • Get the speed of array 0 directly
  • We adopt scheme 2. First, set the previously traversed data into data

     // Add this line to the init method
     // Modify global alignment data
     this.linePath = linePath
    
  • Write it in setPath to obtain the starting speed and set the starting speed for the cruiser

     // Get initial speed
     // Set the default to 0.1
     let startSpeed = 0.1
     if (that.linePath.length !== 0) {
       // Get the initial speed and judge whether it is 0. If it is not 0, return to 0 directly to give an initial speed
       startSpeed =
         that.linePath[0].nextSpeed === 0 ? 0.1 : that.linePath[0].nextSpeed
     }
     // Create a cruiser for the first line (i.e. index 0)
     that.navgtr = that.pathSimplifierIns.createPathNavigator(0, {
       loop: false, // Loop Playback
       // speed × Double speed
       speed: startSpeed * that.times
     })
    
  • Calculate the start time and end time. The original presentation is written in setPath

     let linePath = that.linePath
     let len = linePath.length
     let startPoint = linePath[0]
     let endPoint = linePath[len - 1]
    
  • Write move status

    • Modify the style of the slider and start time

       <!-- The start time is set to 00 as the elapsed time, which can no longer be fixed-->
       <span class="passed-time">{{passedTime}}</span>
       <!-- Slider modified 2 places step step tip-forma prompt box -->
       <Slider class="map-slider" @on-input="sliderChange" :step="0.0001" :tip-format="hideFormat"></Slider>
      
      // Tips for slider
      hideFormat() {
        return this.passedTime
      }
      
    • Move status

        // During movement
        that.navgtr.on('move', function() {
          // What point did you reach
          let idx = this.getCursor().idx
          // Proportional position to next node
          let tail = this.getCursor().tail
          // Total distance
          let totalIdx = idx + tail
          // Calculate next distance speed
          let point = linePath[idx]
          if (idx < len - 1) {
            // Judge whether the speed is 0. If it is 0, give a speed of 0.1
            point.nextSpeed === 0 && (point.nextSpeed = 0.1)
            // The speed here, remember × multiple
            that.navgtr.setSpeed(point.nextSpeed * that.times)
          }
          // The remaining kilometers are displayed on the form at any time
          // Determine whether there is another point and time
          point &&
            point.time &&
            infoWindow.setContent(
              `<p class="info-window">Time:<span>${point.time}`
            )
          // Set prompt box
          infoWindow.open(that.map, that.navgtr.getPosition())
          // Real time display of progress bar
          !that.isOnSlider && (that.sliderVal = (totalIdx / len) * 100)
          // Played time
          let sTime = parseInt(
            (((endPoint.stampTime - startPoint.stampTime) / 1000) *
              that.sliderVal) /
              100
          )
          // Format time
          that.passedTime = that.getTime(sTime)
          // If it's over, go back to the initial state
          if (that.navgtr.isCursorAtPathEnd()) {
            // Set as pause button
            that.start = false
            that.passedTime = that.totalTime
          }
        })
      

Trolley movement

  • First of all, we can learn about the events of the car

    • resume (colors that have passed will not be drawn)
    • Pause pause
    • start here will return to the original position
  • So according to this, we should have a clear idea

    • If the start button is set to start, you will return to the original position when you restart
    • Therefore, it is best to set resume during the move process
    • Pause after pause, you can only use resume to continue
    • So our idea is to set start after the journey
  • Modify start button

     <!-- Start button -->
     <Icon v-if="!start" class="play-icon" type="ios-play" @click="navgControl(playIcon)"/>
    
  • Modify pause button

      <!-- Pause button -->
      <Icon v-else class="play-icon" type="ios-pause" @click="navgControl('pause')"/>
    
  • Set the initial data of playIcon

    • playIcon: 'start' //Start button is to restart or continue
      
  • Modify the end of the path code in setpath

     // If it's over, go back to the initial state
     if (that.navgtr.isCursorAtPathEnd()) {
       // Set it to the start state to return the trolley to its original position
       that.playIcon = 'start'
       // Set icon status
       that.start = false
       // Set elapsed time
       that.passedTime = that.totalTime
       // Set slider status
       that.sliderVal = 100
     }
    
  • Pause start button

     // Pause and play buttons
     navgControl(action) {
       if (action === 'start') {
         let that = this
         this.passedTime = '00:00:00'
         setTimeout(() => {
           that.navgtr[action]()
         }, 300)
       } else {
         this.navgtr[action]()
       }
       // Modify icon status
       this.start = !this.start
     },
    
  • Settings are also required during movement

     // During movement
     that.navgtr.on('move', function() {
       that.playIcon = 'resume'
       //........................
    
  • Set slider (forgot to design before)

    • Bind data to slider v-model = "sliderVal"

       <Slider class="map-slider" v-model="sliderVal" @on-input="sliderChange" :step="0.0001" :tip-format="hideFormat"></Slider>
       ```
      
      
  • Then I found that the speed of modification is not good...... It turned out that I passed 1 when I passed the value... (pay attention when setting the code)

    • changeSpeed(item) remember it's item here

        <li v-for="item in speedList" :key="item" :class="{active:times==item}" @click="changeSpeed(item)">Double speed {{item}}</li>
        ```
      
      
    • Then I found... ul also forgot to set it to false

        // Modification speed
        changeSpeed(item) {
          this.times = item
          this.isTimesChoose = false
        },
      
      
      
      

Keywords: Javascript Front-end Vue.js html

Added by MNSarahG on Fri, 17 Sep 2021 13:51:31 +0300