vue2实现高德地图 JSAPI 2.0可拖拽的路线规划(DragRoute)组件实现对每个经过点设置不同的经过点名称

news/2024/7/10 1:29:42 标签: vue, 高德地图, 可拖拽路径规划

vue2_JSAPI_20DragRoute_0">vue2实现高德地图 JSAPI 2.0可拖拽的路线规划(DragRoute)组件实现对每个经过点设置不同的经过点名称

官方文档及示例

DragRoute相关API

API中没有任何方法让我们对每个经过点进行设置,所以只能我们自己实现

image-20230317163350154

实现效果如下:

image-20230317154134066

集成DragRoute到自己的组件

  1. 设置变量

    image-20230317154937284

  2. 引入DragRoute组件

    image-20230317155022084

  3. image-20230317155317539

以上步骤完成后就集成了DragRoute组件

对每个经过点设置不同的经过点名称

image-20230317160015595

_path中存储的数据如下图是一个LngLat对象,但是转换为json字符串后就是一个经纬度数组

image-20230317160642232

image-20230317160844078

父组件中

image-20230317160438249

      getRoutePath(childValue){
        this.form.routePathString=JSON.stringify(childValue)
      },

将数据库中的数据加载到重新加载到route中

image-20230317161550409

此处我将DragRoute的初始化单独抽取成了一个方法,

image-20230317161507500

此时其实已经完成了目的功能

但是存储到后端后再次加载地图所有的经过点的content都是一样的效果如下:

这是因为我们的路径点的content都在初始化时都被midMarkerOptions设置为相同的了

Snipaste_2023-03-15_16-41-59

解决路径点content相同问题

主要的思路是将route中的marker都重新修改content后再重新加载就可以实现了

image-20230317162434136

updateMindPointContext: function () {
        let pathList = this.route._list
        console.log(pathList)
        let startPoint = pathList[0]
        let endPoint = pathList[pathList.length - 1]
        let mindPoint = []
        pathList.forEach(item => {
          if (item.id != startPoint.id && item.id != endPoint.id) {
            mindPoint.push(item)
          }
        })
        let count = 1
        mindPoint.forEach(item => {
          item.marker._opts.label.content = '经过点' + count
          count++
          item.marker.setContent('')//需要set一下上面代码才会生效
        })
        pathList = []
        pathList.push(startPoint)
        pathList.push(...mindPoint)
        pathList.push(endPoint)
        this.route._list = pathList
      },

然后我们在每次初始化时都调用此方法就解决了

image-20230317162511361

组件代码

vue"><template>
  <div>
    <a-row>
      <div id="container"></div>
      <div class='input-card-ControlBar' v-show="visible">
        <div class="input-item">
          <a-checkbox @change="toggleScale" :checked="toggleScaleCheck">比例尺</a-checkbox>
        </div>

        <div class="input-item">
          <a-checkbox @change="toggleToolBar" :checked="toggleToolBarCheck">工具条</a-checkbox>
        </div>

        <div class="input-item">
          <a-checkbox @change="toggleControlBar" :checked="toggleControlBarCheck">工具条方向盘</a-checkbox>
        </div>

        <div class="input-item">
          <a-checkbox @change="toggleOverViewShow" :checked="toggleOverViewShowCheck">显示鹰眼</a-checkbox>
        </div>
      </div>
      <div class="input-card-MouseTool" style='width: 24rem;' v-show="visible">
        <div class="input-item">
          左击获取经纬度: <input type="text" :value="clickValue">
        </div>

        <div class="input-item">
          <a-radio-group v-model="drawOptionValue" :options="drawOptions" @change="onChangeDrawOption"/>
        </div>
        <div class="input-item" style="margin-top: 10px">
          <a-button type="primary" size="small" style="width: 90px" @click="clearMap">
            清除
          </a-button>
          <a-button type="primary" size="small" style="margin-left: 10px;width: 90px" @click="closeDram">
            关闭绘图
          </a-button>
        </div>
      </div>
    </a-row>
  </div>

</template>

<script>
  //这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)
  //例如: import 《组件名称》 from '《组件路径》 ';

  import AMapLoader from "@amap/amap-jsapi-loader";
  // 设置安全密钥
  window._AMapSecurityConfig = {
    securityJsCode: '61eac11f7f4a83873c6f6a6829035905',
  }
  export default {
    name: 'MapContainer',
    //import 引入的组件需要注入到对象中才能使用
    components: {},
    props: {
      visible: Boolean,
      drewData: Array,
      routePathP: Array,
    },
    data() {
      //这里存放数据
      return {
        AMap: null,
        //此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。
        map: null,
        mouseTool: null,
        //监听draw事件可获取画好的覆盖物
        overlays: [],
        auto: null,
        placeSearch: null,
        drawOptionValue: '',
        drawOptions: [
          {label: '画点', value: 'marker'},
          {label: '画折线', value: 'polyline'},
          {label: '画多边形', value: 'polygon'},
          {label: '画矩形', value: 'rectangle'},
          {label: '画圆', value: 'circle'},
          {label: '路径规划', value: 'routePath'},
          {label: '获取经纬度', value: 'position'},
        ],
        //--地图控件 --
        toggleOverViewShowCheck: true,
        toggleControlBarCheck: true,
        toggleToolBarCheck: true,
        toggleScaleCheck: true,
        scale: null,
        toolBar: null,
        controlBar: null,
        overView: null,
        //坐击经纬度
        clickValue: '',
        //可拖拽路线规划
        route: null,
        routePath: this.routePathP,
        startAndEnd:[],
      };
    },
    //计算属性 类似于 data 概念
    computed: {},
    //监控 data 中的数据变化
    watch: {
      overlays(newVal, oldVal) {
        this.$emit('getOverlaysValue', newVal)
      },
      drewData(newValue, oldValue) {
        this.mountDrewData()
      },
      routePathP(newValue, oldValue){
        this.routePath=this.routePathP;
        this.initPathAssign(this.AMap)
      },
      startAndEnd(newValue, oldValue){
        if (this.startAndEnd.length==2){
          this.routePath=this.startAndEnd.map(item=>{
            return item.getPosition()
          })
          console.log(this.routePath)
          this.initPathAssign(this.AMap)
          this.startAndEnd.forEach(item=>{
            item.remove()
          })
          this.startAndEnd=[]
        }
      }
    },
    //方法集合
    methods: {
      toggleOverViewShow(e) {
        this.toggleOverViewShowCheck = e.target.checked
        if (e.target.checked) {
          this.overView.show();
        } else {
          this.overView.hide();
        }
      },
      toggleControlBar(e) {
        this.toggleControlBarCheck = e.target.checked
        if (e.target.checked) {
          this.controlBar.show()
        } else {
          this.controlBar.hide()
        }
      },
      toggleToolBar(e) {
        this.toggleToolBarCheck = e.target.checked
        if (e.target.checked) {
          this.toolBar.show();
        } else {
          this.toolBar.hide();
        }
      },
      toggleScale(e) {
        this.toggleScaleCheck = e.target.checked
        if (e.target.checked) {
          this.scale.show();
        } else {
          this.scale.hide();
        }
      },
      closeDram() {
        this.mouseTool.close(true)
        this.drawOptionValue = ''
      },
      clearMap() {
        this.map.remove(this.overlays)
        this.overlays = [];
        this.route.destroy()
        this.$emit('getRoutePath', [])
        // this.$emit('getOverlaysValue', this.overlays)
      },
      onChangeDrawOption(e) {
        console.log('radio checked', e.target.value);
        this.draw(e.target.value)
      },
      initMapTool() {
        this.scale = new AMap.Scale();
        this.toolBar = new AMap.ToolBar({
          position: {
            top: '110px',
            right: '40px'
          }
        });
        this.controlBar = new AMap.ControlBar({
          position: {
            top: '10px',
            right: '10px',
          }
        });
        this.overView = new AMap.HawkEye({
          position: {
            top: '10px',
            left: '10px',
          },
          opened: false
        });
        this.map.addControl(this.scale);
        this.map.addControl(this.toolBar);
        this.map.addControl(this.controlBar);
        this.map.addControl(this.overView);
      },
      initMouseTool(AMap) {
        this.mouseTool = new AMap.MouseTool(this.map);
        // 监听draw事件可获取画好的覆盖物
        this.mouseTool.on('draw', function (e) {
          this.overlays.push(e.obj);
        }.bind(this))
        //为地图注册click事件获取鼠标点击出的经纬度坐标
        this.map.on('click', function (e) {
          if (this.drawOptionValue=='routePath'){
            if (this.startAndEnd.length==0){
              let start = new AMap.Marker({
                icon: "//webapi.amap.com/theme/v1.3/markers/n/start.png",
                position: [e.lnglat.getLng(),e.lnglat.getLat()],
                offset: new AMap.Pixel(-13, -30)
              });
              start.setMap(this.map);
              this.startAndEnd.push(start)
            }else if (this.startAndEnd.length==1){
              let end = new AMap.Marker({
                icon: "//webapi.amap.com/theme/v1.3/markers/n/end.png",
                position: [e.lnglat.getLng(),e.lnglat.getLat()],
                offset: new AMap.Pixel(-13, -30)
              });
              end.setMap(this.map);
              this.startAndEnd.push(end)
            }
          }
          if (this.drawOptionValue=='position'){
            this.clickValue = e.lnglat.getLng() + ',' + e.lnglat.getLat()
          }

        }.bind(this));
        this.mountDrewData()

      },
      mountDrewData(){
        if (this.drewData!=null){
          this.drewData.forEach(item => {
            this.drew(item.overlayType, item.opts)
          })
        }
      },

      updateMindPointContext: function () {
        let pathList = this.route._list
        console.log(pathList)
        let startPoint = pathList[0]
        let endPoint = pathList[pathList.length - 1]
        let mindPoint = []
        pathList.forEach(item => {
          if (item.id != startPoint.id && item.id != endPoint.id) {
            mindPoint.push(item)
          }
        })
        let count = 1
        mindPoint.forEach(item => {
          item.marker._opts.label.content = '经过点' + count
          count++
          item.marker.setContent('')//需要set一下上面代码才会生效
        })
        pathList = []
        pathList.push(startPoint)
        pathList.push(...mindPoint)
        pathList.push(endPoint)
        this.route._list = pathList
      },
      initPathAssign (AMap) {
        // this.routePath.push([104.050025, 30.6683]);
        // this.routePath.push([104.044078, 30.671447]);

        this.route = new AMap.DragRoute(this.map, this.routePath, AMap.DrivingPolicy.LEAST_FEE, {
          midMarkerOptions: {
            // icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-1.png',
            label: {
              content: '路径点'+(this.routePath.length-1)
            }
          }
        }); //构造拖拽导航类
        this.route.search(); //查询导航路径并开启拖拽导航
        this.route.on('addway', function (e) {
          // e.target.midMarkerOptions.icon= '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-'+(this.route.getWays().length+1)+'.png'
          e.target.midMarkerOptions.label.content = '路径点' + (this.route.getWays().length + 1)
          this.$emit('getRoutePath', this.route._path)
        }.bind(this))
        this.updateMindPointContext();
      },
      initMap() {
        AMapLoader.load({
          key: "b08fe7d12d1c73b37954465217194bef",             // 申请好的Web端开发者Key,首次调用 load 时必填
          version: "2.0",      // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
          "plugins": [
            "AMap.Scale",
            "AMap.HawkEye",
            "AMap.ToolBar",
            "AMap.AutoComplete",
            "AMap.PlaceSearch",
            "AMap.ControlBar",
            "AMap.MouseTool",
            "AMap.DragRoute"],         // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        }).then((AMap) => {
          this.AMap=AMap
          this.map = new AMap.Map("container", {  //设置地图容器id
            viewMode: "2D",  //  是否为3D地图模式
            zoom: 13,   // 初始化地图级别
            center: [104.065735, 30.659462], //中心点坐标  成都
            resizeEnable: true
          });
          this.initMouseTool(AMap);
          //地图工具
          this.initMapTool();
          //路径规划工具初始化
          this.initPathAssign(AMap);


        }).catch(e => {
          console.log(e);
        })
      },
      draw(type) {
        switch (type) {
          case 'marker': {
            this.mouseTool.marker({
              //同Marker的Option设置
            });
            break;
          }
          case 'polyline': {
            this.mouseTool.polyline({
              strokeColor: '#80d8ff'
              //同Polyline的Option设置
            });
            break;
          }
          case 'polygon': {
            this.mouseTool.polygon({
              fillColor: '#00b0ff',
              strokeColor: '#80d8ff'
              //同Polygon的Option设置
            });
            break;
          }
          case 'rectangle': {
            this.mouseTool.rectangle({
              fillColor: '#00b0ff',
              strokeColor: '#80d8ff'
              //同Polygon的Option设置
            });
            break;
          }
          case 'circle': {
            this.mouseTool.circle({
              fillColor: '#00b0ff',
              strokeColor: '#80d8ff'
              //同Circle的Option设置
            });
            break;
          }
        }
      },
      drew(type, opts) {
        switch (type) {
          case 'marker': {
            opts.map = this.map
            let o = new AMap.Marker(opts);
            this.overlays.push(o);
            break;
          }
          case 'polyline': {
            opts.map = this.map
            let o = new AMap.Polyline(opts)
            this.overlays.push(o);
            break;
          }
          case 'polygon': {
            opts.map = this.map
            let o = new AMap.Polygon(opts)
            this.overlays.push(o);
            break;
          }
          case 'rectangle': {
            opts.map = this.map
            let o = new AMap.Rectangle(opts)
            this.overlays.push(o);
            break;
          }
          case 'circle': {
            opts.map = this.map
            let o = new AMap.Circle(opts)
            this.overlays.push(o);
            break;
          }
        }
      }
    },
    //生命周期 - 创建完成(可以访问当前 this 实例)
    created() {
    },
    //生命周期 - 挂载完成(可以访问 DOM 元素)
    mounted() {
      this.initMap();
    },
    //生命周期 - 创建之前
    beforeCreate() {
    },
    //生命周期 - 挂载之前
    beforeMount() {
    },
    //生命周期 - 更新之前
    beforeUpdate() {
    },
    //生命周期 - 更新之后
    updated() {
    },
    //生命周期 - 销毁之前
    beforeDestroy() {
    },
    //生命周期 - 销毁完成
    destroyed() {
    },
    //如果页面有 keep-alive 缓存功能, 这个函数会触发
    activated() {
    },
  }
</script>

<style scoped>
  #container {
    padding: 0px;
    margin: 0px;
    width: 100%;
    height: 800px;
  }

  .input-item {
    height: 2.2rem;
  }

  .input-card-ControlBar {
    display: flex;
    flex-direction: column;
    min-width: 0;
    word-wrap: break-word;
    background-color: #fff;
    background-clip: border-box;
    border-radius: .25rem;
    width: 10rem;
    border-width: 0;
    border-radius: 0.4rem;
    box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
    position: fixed;
    bottom: 12rem;
    right: 2rem;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    padding: 0.75rem 1.25rem;
  }

  .input-card-MouseTool {
    display: flex;
    flex-direction: column;
    min-width: 0;
    word-wrap: break-word;
    background-color: #fff;
    background-clip: border-box;
    border-radius: .25rem;
    width: 10rem;
    border-width: 0;
    border-radius: 0.4rem;
    box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
    position: fixed;
    bottom: 12rem;
    right: 12rem;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    padding: 0.75rem 1.25rem;
  }
</style>

父组件使用示例代码

vue"><template>
  <Map-Container
    ref="mapChild"
    :visible="drawerVisible"
    :drewData="drewData"
    :routePathP="routePath"
    @getOverlaysValue="getOverlaysValue"
    @getRoutePath="getRoutePath">

  </Map-Container>
</template>

<script>
  import MapContainer from "@/pages/components/map/MapContainer";
  export default {
    name: 'Post',
    components: { MapContainer},
    data() {
      return {
        drewData: [],
        form: {
          overlays: '',
          createBy: '',
          routePathString: '',
        },
        routePath: [],
      }
    },
    methods: {
      getRoutePath(childValue){
        this.form.routePathString=JSON.stringify(childValue)
      },
      getOverlaysValue: function (childValue) {

        let overlaysString = []
        overlaysString = childValue.map(item => {
          switch (item.className) {
            case 'AMap.Marker': {
              item._opts.map = null
              let opts = item._opts
              let overlay = {
                overlayType: 'marker',
                opts: opts
              }
              return overlay
            }
            case 'Overlay.Polyline': {
              item._opts.map = null
              let opts = item._opts
              let overlay = {
                overlayType: 'polyline',
                opts: opts
              }
              return overlay
            }
            case 'Overlay.Polygon': {
              item._opts.map = null
              let opts = item._opts
              let overlay = {
                overlayType: 'polygon',
                opts: opts
              }
              return overlay
            }
            case 'Overlay.Rectangle': {
              item._opts.map = null
              let opts = item._opts
              let overlay = {
                overlayType: 'rectangle',
                opts: opts
              }
              return overlay
            }
            case 'Overlay.Circle': {
              item._opts.map = null
              let opts = item._opts
              let overlay = {
                overlayType: 'circle',
                opts: opts
              }
              return overlay
            }
          }
        })
        this.form.overlaysString = JSON.stringify(overlaysString)
      },
    }
  }
</script>

<style lang="less" scoped>
  .search {
    margin-bottom: 54px;
  }

  .fold {
    width: calc(100% - 216px);
    display: inline-block
  }

  .operator {
    margin-bottom: 18px;
  }

  @media screen and (max-width: 900px) {
    .fold {
      width: 100%;
    }
  }
</style>

http://www.niftyadmin.cn/n/158533.html

相关文章

实现 GPS 拒绝飞机导航的时间序列模型(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 该项目旨在开发一个时间序列预测模型&#xff0c;以解决GPS拒绝飞机导航的问题&#xff0c;这是空中交通管制的关键要素。该项目…

react-native android虚拟机启动 [windows下]

1. 配置环境 必须安装的依赖有&#xff1a;Node、JDK 和 Android Studio。 虽然你可以使用任何编辑器来开发应用&#xff08;编写 js 代码&#xff09;&#xff0c;但你仍然必须安装 Android Studio 来获得编译 Android 应用所需的工具和环境。 Node, JDK​ 我们建议直接使…

差速巡线机器人设计-及格(60+)的报告-2023

实践项目名称&#xff1a;差速巡线机器人设计实验目的基于差速机器人底盘和传感器&#xff0c;使用微处理器编程实现机器人快速巡线行驶。差速巡线机器人设计实验的目的是为了探索差速驱动技术在机器人巡线中的应用。通过设计和制作差速巡线机器人&#xff0c;可以测试其在不同…

安全防御 --- 防火墙

防火墙 1、基础 &#xff08;1&#xff09;防御对象&#xff1a;授权用户&#xff1b;非授权用户 &#xff08;2&#xff09;含义&#xff1a; 防火墙是一种隔离&#xff08;非授权用户所在区域间&#xff09;并过滤&#xff08;对受保护网络中的有害流量或数据包&#xff0…

epoll 两种工作方式

epoll 两种工作方式 水平触发LT 读数据 只要读缓冲区有数据 就会检测到变化 12个字符 一次读4个 要调用三次poll_wait epoll_wait 系统调用 有损耗 不好平凡调用 边沿触发ET 数据从无到有 数据来了一次epoll只会触发一次 不管有没有读完 12个字符 一次读4个 只会调用一次 但是…

数据结构—二叉树链式结构的实现

目录 0、前言 1、二叉树链式结构的创建 2、二叉树的遍历 3、 前序、中序以及后序遍历 4、 前序、中序以及后序遍历的实现——双路递归 分治思想 求叶子节点数量&#xff0c;分治思想&#xff1a; 分治思想 求第k层节点个数&#xff1a; ​编辑 分治思想 求二叉树的深…

C++11 静态断言(static_assert)

简介 C11中引入了static_assert这个关键字&#xff0c;用来做编译期间的断言&#xff0c;因此叫做静态断言。 其语法很简单&#xff1a;static_assert(常量表达式&#xff0c;提示字符串)。 如果第一个参数常量表达式的值为真(true或者非零值)&#xff0c;那么static_assert不做…

leetcode每日一题26

242. 有效的字母异位词 哈希表吧 迭代器访问hash的每个元素&#xff0c;用it->second访问数值&#xff0c;it->first访问键值 class Solution { public:bool isAnagram(string s, string t) {unordered_map<char,int> hash;if(s.length()!t.length())return fals…