高德地图实现类似百度地图工具箱标记功能(画线测距,点标记)

项目场景:

实现百度地图工具栏–标记功能。包括点标记和手绘路线测距。
百度地图链接
在这里插入图片描述
在这里插入图片描述


解决方案:

引用高德地图和使用到的插件

index.html

<script type="text/javascript">
	 window._AMapSecurityConfig = {
	 	//您的code
		securityJsCode: '',
	}
</script>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=您申请的key值&plugin=AMap.Geocoder,AMap.RangingTool"></script>

vue2文件

<template>
  <div class="mapWrap">
    <div id="wMap" @click="handleClickBtn"></div>
    <div class="mouseToolWrap">
      <div v-for="(item,index) in tools" @click="changeTool(index)" class="tool">
        <img :src=" curTool == index+1 ? require(`@/assets/img/${item.icon}1.png`):  require(`@/assets/img/${item.icon}.png`)" alt="">
        <span :style="{color:curTool == index+1 ? '#3988FB':'#3d3d3d'}">{{ item.name }}</span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: '',
  components: {},
  data() {
    return {
      map: null,     //  地图
      curTool: 1,    //  选中工具
      tools: [
        { icon: 'cj', name: '测距' },
        { icon: 'bj', name: '标记' },
      ],
      distanceTool: null,  // 打分
      geocoder: null,    // 地理编码
      iconlist: [
        {
          url: require(`@/assets/img/img1.png`),
          offset: new AMap.Pixel(-20, 20),
          size: new AMap.Size(34, 46),
        },
        {
          url: require(`@/assets/img/img2.png`),
          offset: new AMap.Pixel(17, 23),
          size: new AMap.Size(34, 46),
        },
        {
          url: require(`@/assets/img/img3.png`),
          offset: new AMap.Pixel(17, 23),
          size: new AMap.Size(34, 46),
        },
        {
          url: require(`@/assets/img/img4.png`),
          offset: new AMap.Pixel(17, 23),
          size: new AMap.Size(34, 46),
        },
      ],
      showIcon: false,    // 展示图标列表
      infoWindow: null,   // 窗体
      curMark: null,      // 当前鼠标打点
      curMarkInfo: {      // 当前鼠标打点点位信息
        lnglat: '',
        icon: '',
        addr: ''
      },
      markers: [],        // 打点列表
      polylines: [],      // 测距列表
      delArr: []
    }
  },
  created() { },
  mounted() {
    this.initMap()
    if (this.curTool == 2) {
      this.cancelRangingTool()
    } else if (this.curTool == 1) {
      this.drawRangingTool()
    }
  },
  methods: {
    changeTool(index) {
      if (this.curMarkInfo.lnglat !== '') {
        this.saveMarkInfo()
      }
      this.curTool = index + 1
    },
    // 地图和窗体初始化并监听
    initMap() {
      this.map = new AMap.Map('wMap', {
        center: [116.40285,39.900912],
        zoom: 15,
        pitch: 50,    // 俯仰角度
        resizeEnable: true, // 是否监控地图容器尺寸变化
        viewMode: "3D",
        features: ["bg", "road", "point", "building"]
      })
      this.map.on('click', (e) => {
        if (this.curMarkInfo.lnglat == '' && this.curTool == 2) {
          // 点标记
          this.drawPoint(e)
          this.curTool = 0
        } else if (this.curMarkInfo.lnglat !== '') {
          // 保存,同 saveMark 事件
          this.saveMarkInfo()
        } else {
          this.infoWindow.close()
        }
      })
      this.infoWindow = new AMap.InfoWindow({
        offset: new AMap.Pixel(0, -46),
        autoMove: false
      })
      this.infoWindow.on('close', () => {
        this.saveMarkInfo(true)
      })
    },
    // 清空地图
    clearAll() {
      this.map.clearMap()
      this.markers = []
      this.curMarkInfo.lnglat = ''
      this.curMarkInfo.icon = ''
      this.curMarkInfo.addr = ''
    },
    // 窗体点击事件
    handleClickBtn(e) {
      // 保存
      if (e.target.dataset.event == "saveMark") {
        this.saveMarkInfo()
        // 删除
      } else if (e.target.dataset.event == "delMark") {
        this.markers = this.markers.filter(i => i._amap_id != this.curMark._amap_id)
        this.map.remove(this.curMark)
        this.infoWindow.close()
        // 更换窗体页面
      } else if (e.target.dataset.event == "isShowIcon") {
        this.showIcon = !this.showIcon
        this.drawInfo()
      } else if (e.target.dataset.event == "choseIcon") {
        this.curMark.setIcon(this.iconlist[Number(e.target.dataset.chosedicon)].url)
        this.markers.find(i => i._amap_id == this.curMark._amap_id).icon = Number(e.target.dataset.chosedicon)
        this.showIcon = false
        this.curMarkInfo.icon = Number(e.target.dataset.chosedicon)
        this.drawInfo()
      }
    },
    // 测距
    drawRangingTool() {
      this.distanceTool = new AMap.RangingTool(this.map)
      this.distanceTool.turnOn()

      this.distanceTool.on('addnode', ({ marker, positon, type }) => {
        this.curTool = 0
      })
      this.distanceTool.on('removenode', ({ target, polyline, points, distance }) => {
        console.log('target', target);
        console.log('polyline', polyline);
        console.log('points', points);
        console.log('distance', distance);
      })
      this.distanceTool.on('end', ({ target, polyline, points, distance }) => {
        this.cancelRangingTool()
        polyline.onlyid = this.polylines.length
        this.polylines.push(polyline)
        // 删除事件(官网没有)
        this.delArr = document.getElementsByClassName('delimg');
        this.delArr[this.delArr.length - 1].setAttribute("curindex", this.delArr.length - 1)
        this.delArr[this.delArr.length - 1].addEventListener('click', (e) => this.getCurImg(e))
      })

    },
    getCurImg(e) {
      this.polylines.splice(Number(e.target.getAttribute("curindex")), 1)
    },
    // 保存点位
    saveMarkInfo(notClose) {
      if (!notClose && this.infoWindow.getIsOpen()) {
        this.infoWindow.close()
      }
      if (this.curMarkInfo.lnglat !== '') {

        this.markers.forEach((i, index) => {
          let obj = JSON.parse(JSON.stringify(this.curMarkInfo))

          if (!i.addr) {
            i.addr = obj.addr
            i.icon = obj.icon
            i.lnglat = obj.lnglat
            i.setLabel({
              content: obj.addr, //设置文本标注内容
            });
          } else {
            i.setLabel({
              content: i.addr
            })
          }
          // 确保每一个点只有一次点击事件
          if (index == this.markers.length - 1 && i.uniqueId == undefined) {
            i.uniqueId = index
            i.on('click', (e) => {
              this.getClick(e)
            })
          }

        })
        this.curMarkInfo.lnglat = ''
        this.curMarkInfo.icon = ''
        this.curMarkInfo.addr = ''
      }
    },
    // 点的点击事件
    getClick(e) {
      if (e.originEvent.target.getAttribute("class") == 'amap-marker-label') {
        if (this.infoWindow.getIsOpen()) {
          // 保存其他点位的信息
          if (this.markers[this.markers.length - 1].uniqueId) {
            this.markers.forEach(i => {
              i.setLabel({
                content: i.addr
              })
            })
          } else {
            this.saveMarkInfo()
          }
        }
        this.curMark = e.target
        this.curMarkInfo =
        {
          addr: e.target.addr,
          icon: e.target.icon,
          lnglat: e.target.lnglat
        }
        this.showIcon = false
        this.curMark.setLabel({ content: '' })
        this.drawInfo(true)
      }
    },
    // 关闭测距
    cancelRangingTool() {
      if (this.distanceTool) {
        this.distanceTool.turnOff(false)
        this.distanceTool = null
      }
    },
    // 画点
    drawPoint(e) {
      this.curMark = new AMap.Marker({
        position: e.lnglat,
        icon: this.iconlist[0].url,
        offset: new AMap.Pixel(-17, -40),

      });
      this.curMarkInfo.lnglat = e.lnglat
      this.regeoCode(e.lnglat)
      this.markers.push(this.curMark);
      this.map.add(this.markers);
    },
    // 窗体
    drawInfo(setLocation) {
      var _html = "";
      let iconhtml =
        `${this.iconlist.map((item, index) => {
          return `<img class="icons" src="${item.url}" data-event="choseIcon" data-chosedIcon=${index}></img>`
        }).join('')
        }`
      _html =
        `<div class="mouseMarker-wrap">` +
        `<div class="mouseMarker-topTitle">添加标记</div>` +
        (!this.showIcon ?
          (`<div class="mouseMarker-bottomWrap" >` +
            `<div class="mouseMarker-leftPart">` +
            `<div class="mouseMarker-location">${this.curMarkInfo.addr}</div>` +
            `<div class="mouseMarker-btns">` +
            `<div data-event="saveMark">保存</div>` +
            `<div data-event="delMark">删除</div>` +
            `</div>` +
            `</div>` +
            `<div class="mouseMarker-rightPart" >` +
            `<img src="${this.curMarkInfo.icon ? this.iconlist[this.curMarkInfo.icon].url : this.iconlist[0].url}" alt="" data-event="isShowIcon" >` +
            `<div data-event="isShowIcon" }>更换</div>` +
            `</div>` +
            `</div>`) :
          (
            `<div class="mouseMarker-iconWrap" >` +
            iconhtml +
            `</div>`
          )
        ) +
        `</div>`;
      this.infoWindow.setContent(_html);
      // 在地图上打开信息窗体
      if (setLocation) {
        this.infoWindow.open(this.map, this.curMarkInfo.lnglat);
      }

    },
    // 逆地理解码
    regeoCode(lnglat) {
      if (!this.geocoder) {
        this.geocoder = new AMap.Geocoder({
          city: "010", //城市设为北京,默认:“全国”
          radius: 1000 //范围,默认:500
        });
      }
      this.geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode.formattedAddress) {
          this.showIcon = false
          this.curMarkInfo.addr = result.regeocode.formattedAddress
          this.drawInfo(true)
        } else {
          this.showIcon = false
          this.curMarkInfo.addr = JSON.stringify(result)
          this.drawInfo(true)
        }
      });
    }
  },
  computed: {},
  watch: {
    curTool: {
      handler(newVal, oldVal) {
        if (newVal == 2) {
          this.cancelRangingTool()
        } else if (newVal == 1) {
          this.drawRangingTool()

        }
      }
    },

  }
}
</script>
<style lang="scss">
#wMap .amap-icon {
  overflow: hidden !important;
}
#wMap .amap-info-content {
  padding: 0px !important;
  border: none !important;
}
#wMap .amap-info-close {
  top: 7px !important;
}
#wMap .amap-marker-label {
  cursor: pointer;
  background-color: rgb(255, 255, 255);
  border: 1px solid rgb(128, 128, 128);
  padding: 1px 2px;
  white-space: nowrap;
  font-size: 12px;
  color: rgb(51, 51, 51);
}
.mouseMarker-wrap {
  width: 345px;
  .mouseMarker-topTitle {
    width: 100%;
    border-bottom: 1px solid #ccc;
    height: 31px;
    background-color: #f9f9f9;

    font-size: 14px;
    font-family: Arial, Helvetica, SimSun, sans-serif;
    color: #4d4d4d;
    padding-left: 11px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    line-height: 31px;
  }
  .mouseMarker-iconWrap {
    margin: 10px;
    display: flex;
    justify-content: space-evenly;
    .icons {
      cursor: pointer;
    }
  }
  .mouseMarker-bottomWrap {
    margin: 8px 0 0 11px;
    color: #333;
    font-size: 12px;
    font-family: tahoma, arial, 宋体;

    .mouseMarker-leftPart {
      width: 285px;
      float: left;
      .mouseMarker-btns {
        display: flex;
        justify-content: end;
        margin: 8px -1px 15px 0;
        div {
          width: 46px;
          height: 24px;
          line-height: 20px;
          text-align: center;
          padding: 0;
          vertical-align: middle;
          cursor: pointer;
          border: 1px solid #cbcbcb;
          border-radius: 2px;
          background: -webkit-linear-gradient(top, #fff, #efefef);
          background: -o-linear-gradient(top, #fff, #efefef);
          background: -moz-linear-gradient(top, #fff, #efefef);
          background: -webkit-gradient(
            linear,
            left top,
            left bottom,
            from(#fff),
            to(#efefef)
          );
          background: linear-gradient(to bottom, #fff, #efefef);
          &:first-of-type {
            margin-right: 5px;
          }
        }
      }
    }
    .mouseMarker-rightPart {
      float: left;
      width: 32px;
      text-align: center;
      margin-left: 6px;
      cursor: pointer;
      img {
        width: 20px;
      }
      div {
        color: #4673cc;
        text-decoration: underline;
      }
    }
  }
}
</style>
<style scoped lang='scss'>
.mapWrap,
#wMap {
  width: 100%;
  height: 100%;
  position: relative;
}

.mouseToolWrap {
  width: 200px;
  height: 40px;
  position: absolute;
  top: 110px;
  right: 20px;
  background-color: #fff;
  display: flex;
  align-items: center;
  padding: 6px 0;
  .tool {
    width: calc(calc(100% - 1px) / 2);
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    img {
      margin-right: 8px;
    }
    span {
      font-family: Source Han Sans, Source Han Sans;
      font-weight: 400;
      font-size: 14px;
    }
    &:first-child {
      border-right: 1px solid #ebebeb;
      img {
        width: 16px;
        height: 16px;
      }
    }
    &:last-child {
      img {
        width: 12px;
        height: 16px;
      }
    }
  }
}
</style>

在这里插入图片描述


问题描述

功能其实还是有不完善的地方,RangingTool测距工具每条路线的删除事件没有。这个只能通过获取删除图片的dom元素处理。还有一个未解决的bug是:当路线只有两个点,随意点击任意一点的移除事件触发RangingTool测距工具的removenode事件,但是没办法确定删除的是哪条路线。
真心觉得难的不是需求,是官方Api不完善,全网找了好多天都找不到解决办法。如果有幸被官方看见,可以完善一下吗?或者有人能把提建议的地址告诉我吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值