首页 前端知识 vue中天地图的使用 添加点、线、面、聚合点、信息窗口、自定义右键菜单、切换地图图层操作

vue中天地图的使用 添加点、线、面、聚合点、信息窗口、自定义右键菜单、切换地图图层操作

2024-08-27 09:08:09 前端知识 前端哥 688 861 我要收藏

集合封装了几个常用的天地图方法 方便自己后续用 也方便大家直接CV 注释写的很详细了 开箱用或者复制用都可

  • 添加单个点标记

在这里插入图片描述

  • 信息窗口 信息窗口传参+点击回调

  • 在这里插入图片描述

  • 添加多个点标记
    在这里插入图片描述

  • 添加点聚合

在这里插入图片描述

  • 添加线

在这里插入图片描述

  • 添加多边形面

在这里插入图片描述

  • 覆盖物上右键菜单
  • 在这里插入图片描述
<template>
  <div>
    <div class="tool_container">
      <button class="_btn" type="button" @click="addMarker(demoLnglat)">
        添加点
      </button>
      <button class="_btn" type="button" @click="addMarkers(demoPath)">
        添加多个点
      </button>
      <button class="_btn" type="button" @click="addMarkerCluster()">
        添加点聚合
      </button>
      <button class="_btn" type="button" @click="addLine(demoPath)">
        添加线
      </button>
      <button class="_btn" type="button" @click="addPolygon(demoPath)">
        添加面
      </button>
      <button class="_btn" type="button" @click="changeLayer('BZ')">
        切换标准图层
      </button>
      <button class="_btn" type="button" @click="changeLayer('WX')">
        切换卫星图层
      </button>
      <button class="_btn" type="button" @click="changeLayer('WXLW')">
        切换卫星路网图层
      </button>
      <button class="_btn" type="button" @click="changeLayer('DX')">
        切换地形图层
      </button>
      <button class="_btn" type="button" @click="changeLayer('DXLW')">
        切换地形路网图层
      </button>

      <button class="_btn" type="button" @click="clearMap()">清空所有</button>
    </div>
    <!--Tips 这个 @contextmenu.prevent 是阻止浏览器上地图默认的右键事件 -->
    <div @contextmenu.prevent id="mapID" class="map_container"></div>

    <InfoWindow
      ref="infoWindow"
      v-show="showInfoWindow"
      :infoWindow="mapConfig.infoWindow"
      :data="mapConfig.infoWindowData"
      @callback="infoWindowCallback"
    ></InfoWindow>
  </div>
</template>
<script>
  import './mapTDT.min.js' //引入天地图服务
  //Tips  这里的文件就是把服务器的文件下载到本地再引用  如【https://api.tianditu.gov.cn/api?v=4.0&tk=你的秘钥】在浏览器打开下载  修改下文件名放在当前文件同级即可

  import InfoWindow from './infowindow' //信息窗口 在后面
  export default {
    data() {
      return {
        demoLnglat: '120.209809, 30.246587', //模拟经纬度
        // 模拟点阵数组
        demoPath: [
          [120.13292, 30.2624],
          [120.16339, 30.25492],
          [120.16159, 30.23089],
          [120.13181, 30.23252],
        ],
        mapConfig: {
          map: null, //地图容器
          zoom: 10, //缩放等级
          center: [120.209809, 30.246587], //默认中心点
          contextMenu: null, //右键菜单
          marker: null, //点
          markers: null, //多个点
          markerCluster: null, //点聚合
          line: null, //线
          polygon: null, //面
          infoWindow: null, //信息窗口
          infoWindowData: {}, //信息窗口数据
        },
        showInfoWindow: false, //信息窗口显示
      }
    },
    components: { InfoWindow },
    mounted() {
      this.initMap() //初始化地图
    },
    methods: {
      // 初始化地图
      initMap() {
        this.mapConfig.map = new T.Map('mapID')
        this.mapConfig.map.centerAndZoom(
          this.returnLnglat(this.mapConfig.center),
          this.mapConfig.zoom
        )
        this.initMapAfter() //加载地图后方法
      },
      //初始化地图后操作
      initMapAfter() {
        //todo do something
      },
      // 添加单个点标记
      addMarker(lnglat) {
        this.clearMap() //清除覆盖物

        // 自定义标记点图标
        let markerObj = {
          icon: new T.Icon({
            iconUrl: 'http://api.tianditu.gov.cn/img/map/markerA.png',
            iconSize: new T.Point(30, 40),
            iconAnchor: new T.Point(15, 40),
          }),
        }
        this.mapConfig.marker = new T.Marker(
          this.returnLnglat(lnglat)
          // markerObj
        )

        // 添加标记点右键单击事件
        this.mapConfig.marker.addEventListener('contextmenu', (event) => {
          console.log('添加标记点右键单击事件', event)
          //todo do something
        })

        this.mapConfig.map.addOverLay(this.mapConfig.marker)
        this.reset('marker') //自适应画面

        //点标记添加点击事件并传参
        this.addClickHandler(this.mapConfig.marker, {
          lnglat: lnglat,
        })
      },
      // 添加点击事件返回
      addClickHandler(marker, params, index) {
        marker.addEventListener('click', (e) => {
          this.mapConfig.map.panTo(this.returnLnglat(e.lnglat), 12) //将地图的中心点变换到指定的地理坐标
          this.markerClick(e, params, index)
        })
      },
      // 点击时间打开信息窗体
      markerClick(e, params, index) {
        console.log(e, params, index)
        this.showInfoWindow = true //显示信息窗体
        this.mapConfig.infoWindowData = params //传递数据

        // 创建信息窗口对象
        this.mapConfig.infoWindow = new T.InfoWindow(
          this.$refs['infoWindow'].$el,
          { offset: new T.Point(0, -20), closeButton: false }
        )

        setTimeout(() => {
          this.mapConfig.map.openInfoWindow(this.mapConfig.infoWindow, e.lnglat) //打开信息窗口
        }, 0)
      },
      // 信息窗口点击回调
      infoWindowCallback(data) {
        console.log('信息窗口点击回调', data)
        //todo do something
        this.closeInfoWindow() // 关闭信息弹窗
      },
      // 关闭信息弹窗
      closeInfoWindow() {
        if (this.mapConfig.infoWindow) {
          this.mapConfig.infoWindow.closeInfoWindow()
        }
      },

      // 添加多个点标记
      addMarkers(path) {
        this.clearMap() //清除覆盖物
        let tempMarkers = []
        path.forEach((element) => {
          let tempMarker = new T.Marker(this.returnLnglat(element))
          this.mapConfig.map.addOverLay(tempMarker)
          tempMarkers.push(tempMarker)
        })
        this.mapConfig.markers = tempMarkers
        this.reset('markers') //自适应画面
      },
      // 添加点聚合
      addMarkerCluster() {
        this.clearMap('markerCluster') //清除覆盖物
        let tempMarkerCluster = []
        for (var i = 0; i < 100; i++) {
          // 定义浙江省的大致经纬度范围
          var minLng = 118.018 // 最小经度
          var maxLng = 123.7088 // 最大经度
          var minLat = 27.0973 // 最小纬度
          var maxLat = 31.0493 // 最大纬度

          // 随机生成浙江省范围内的经度和纬度
          var randomLng = Math.random() * (maxLng - minLng) + minLng
          var randomLat = Math.random() * (maxLat - minLat) + minLat

          var marker = new T.Marker(this.returnLnglat([randomLng, randomLat]), {
            title: i,
          })
          tempMarkerCluster.push(marker)
        }

        this.mapConfig.markerCluster = new T.MarkerClusterer(
          this.mapConfig.map,
          { markers: tempMarkerCluster }
        )

        this.reset('markerCluster') //自适应画面
      },
      // 添加单个线条
      addLine(path) {
        this.clearMap() //清除覆盖物
        const tempPath = []
        path.forEach((element) => {
          tempPath.push(this.returnLnglat(element))
        })
        this.mapConfig.line = new T.Polyline(tempPath)
        this.mapConfig.map.addOverLay(this.mapConfig.line)
        this.reset('line') //自适应画面
      },
      // 添加单个多边形覆盖物
      addPolygon(path) {
        this.clearMap() //清除覆盖物
        const tempPath = []
        path.forEach((element) => {
          tempPath.push(this.returnLnglat(element))
        })
        this.mapConfig.polygon = new T.Polygon(tempPath)

        // 添加右键单击事件
        this.mapConfig.polygon.addEventListener('contextmenu', (event) => {
          this.addRightMenu(event)
        })

        this.mapConfig.map.addOverLay(this.mapConfig.polygon)
        this.reset('polygon') //自适应画面
      },
      // 创建右键菜单
      addRightMenu(e) {
        console.log('addRightMenu', e)
        if (this.mapConfig.contextMenu) this.clearRightMenu() //清除右键菜单

        this.mapConfig.contextMenu = document.createElement('div')
        this.mapConfig.contextMenu.id = 'contextMenu'
        this.mapConfig.contextMenu.innerHTML = `<div class='menu-item' id='edit'>编辑</div>
         <div class='menu-item' id='del'>删除</div>`

        // 设置菜单位置
        this.mapConfig.contextMenu.style.left = e.layerPoint.x + 'px'
        this.mapConfig.contextMenu.style.top = e.layerPoint.y + 'px'

        this.mapConfig.map
          .getContainer()
          .appendChild(this.mapConfig.contextMenu) // 将菜单添加到地图容器中

        document.getElementById('edit').addEventListener('click', () => {
          console.log('编辑')
          this.clearRightMenu() //清除右键菜单
        })
        document.getElementById('del').addEventListener('click', () => {
          console.log('删除')
          this.clearRightMenu() //清除右键菜单
        })

        // 监听地图的点击事件 隐藏右键菜单
        this.mapConfig.map.addEventListener('click', () => {
          this.clearRightMenu() //清除右键菜单
        })
      },
      // 清除右键菜单
      clearRightMenu() {
        var contextMenu = document.querySelector('#contextMenu')
        if (contextMenu) {
          this.mapConfig.map.getContainer().removeChild(contextMenu)
        }
        this.mapConfig.contextMenu = null
      },

      // 图层切换
      changeLayer(type) {
        let layerType = null
        switch (type) {
          case 'BZ': //标准
            layerType = window.TMAP_NORMAL_MAP
            break
          case 'WX': //卫星
            layerType = window.TMAP_SATELLITE_MAP
            break
          case 'WXLW': //卫星路网
            layerType = window.TMAP_HYBRID_MAP
            break
          case 'DX': //地形
            layerType = window.TMAP_TERRAIN_MAP
            break
          case 'DXLW': //地形路网
            layerType = window.TMAP_TERRAIN_HYBRID_MAP
            break
          default:
            break
        }
        this.mapConfig.map.setMapType(layerType)
      },
      // 清除地图
      clearMap(type) {
        switch (type) {
          case 'marker':
            if (this.mapConfig.marker) {
              this.mapConfig.map.removeOverLay(this.mapConfig.marker) //移除覆盖物到地图上
              this.mapConfig.marker = null
            }

            break
          case 'line':
            if (this.mapConfig.line) {
              this.mapConfig.map.removeOverLay(this.mapConfig.line) //移除覆盖物到地图上
              this.mapConfig.line = null
            }

            break

          case 'markers':
            if (this.mapConfig.markers) {
              this.mapConfig.markers.forEach((item) => {
                this.mapConfig.map.removeOverLay(item) //移除覆盖物到地图上
              })
              this.mapConfig.markers = null
            }
            break
          case 'circleMarker':
            if (this.mapConfig.circleMarker) {
              this.mapConfig.map.removeOverLay(this.mapConfig.circleMarker)
              this.mapConfig.circleMarker = null
            }
            break

          default:
            this.mapConfig.map.clearOverLays()

            //  清除所有聚合点标记
            if (this.mapConfig.markerCluster) {
              this.mapConfig.markerCluster.clearMarkers() //移除覆盖物到地图上
              this.mapConfig.markerCluster = null
            }

            // 清除信息窗口
            if (this.mapConfig.infoWindow) {
              this.mapConfig.infoWindow.closeInfoWindow()
            }

            break
        }
      },
      // 自适应标记覆盖物到合适范围
      reset(drawType) {
        let mapData = ''
        switch (drawType) {
          case 'marker':
            mapData = [this.mapConfig.marker.getLngLat()]
            break
          case 'markers':
            let tempMakerArr = []
            this.mapConfig.markers.forEach((element) => {
              tempMakerArr.push(this.returnLnglat(element.or))
            })
            mapData = tempMakerArr
            break

          case 'markerCluster':
            // 获取所有标记点的经度和纬度坐标
            var allLng = 0
            var allLat = 0
            const tempMarkerClusterArr = this.mapConfig.map.getOverlays()
            tempMarkerClusterArr.forEach((element) => {
              allLng += element.or.lng
              allLat += element.or.lat
            })

            // 计算中心点的经纬度坐标
            var centerLng = allLng / tempMarkerClusterArr.length
            var centerLat = allLat / tempMarkerClusterArr.length

            // 这里模拟计算有误差 一般固定写某个经纬度和层级
            this.mapConfig.map.centerAndZoom(
              this.returnLnglat([centerLng, centerLat]),
              7
            )

            break

          case 'line':
            mapData = this.mapConfig.line.getLngLats()
            break
          case 'polygon':
            mapData = this.mapConfig.polygon.getLngLats()[0] //获取覆盖物点阵数组
            break

          default:
            break
        }

        this.mapConfig.map.setViewport(mapData) //适应范围
      },
      // 返回天地图经纬度对象
      returnLnglat(data) {
        let x,
          y = null
        switch (typeof data) {
          case 'string':
            let lnglat = data.split(',')
            x = lnglat[0]
            y = lnglat[1]
            break
          case 'object':
            if (data && data.lng) {
              x = data.lng
              y = data.lat
            } else {
              x = data[0]
              y = data[1]
            }

            break

          default:
            break
        }
        return new T.LngLat(x, y)
      },
    },
  }
</script>
<style lang="scss" scoped>
  // 工具栏
  .tool_container {
    padding: 20px;
    ._btn {
      border: none;
      border-radius: 3px;
      padding:8px 12px;
      font-size: 12px;
      line-height: 1;
      background-color: #1890ff;
      color: #fff;

      &:not(:first-of-type) {
        margin-left: 15px;
      }
    }
  }
  .map_container {
    width: 1000px;
    height: 600px;
    margin: 30px auto;
    z-index: 0;
    // 移除默认左下角logo文字  ———— ::v-deep不行的话用/deep/
    ::v-deep .tdt-control-copyright {
      display: none !important;
      opacity: 0 !important;
    }

    // 自定义右键菜单
    ::v-deep #contextMenu {
      position: absolute;
      z-index: 400;
      background: #fff;
      border-radius: 2px;
      .menu-item {
        height: 35px;
        line-height: 35px;
        word-break: break-all;
        padding: 0 10px;
        font-size: 12px;
        min-width: 60px;
        text-align: center;
        white-space: nowrap;
        &:hover {
          background-color: #f3f3ee;
        }
      }
    }
  }
</style>

InfoWindow文件

<template>
  <div class="infowindowClass">
    <div class="windows_close" @click="close"></div>
    <div class="_head">信息窗口自定义</div>
    <div class="_body">
      {{ data }}
    </div>
    <div class="_foot">
      <el-button type="primary" @click="callback">确定</el-button>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      // 传递数据对象
      data: {
        type: Object,
        default: () => {},
      },
      // 信息窗口对象
      infoWindow: {
        type: Object,
        default: () => {},
      },
    },
    methods: {
      // 关闭
      close() {
        this.infoWindow.closeInfoWindow()
      },
      // 确认回调
      callback() {
        this.$emit('callback', this.data)
      },
    },
  }
</script>

<style lang="scss">
  // $color: red;
  $color: rgba(255, 255, 255, 1);

  // 信息窗口隐藏源码样式
  .tdt-infowindow-content-wrapper,
  .tdt-infowindow-tiptdt-infowindow-content-wrapper {
    color: unset;
    background: transparent;
    box-shadow: unset;
  }
  .tdt-infowindow-content {
    margin: 0;
  }

  .tdt-infowindow-tip-container {
    display: none;
  }

  // 信息窗口隐藏源码样式 - end
  .infowindowClass {
    position: relative;
    // position: absolute;
    // top: 0;
    // left: 0;
    display: flex;
    flex-direction: column;
    width: 300px;
    height: 150px;
    padding: 10px;
    background-color: $color;
    border-radius: 10px;
    // zhtips: 三角形
    &::before {
      position: absolute;
      bottom: -9px;
      left: 50%;
      width: 0;
      height: 0;
      content: '';
      border-color: $color transparent transparent transparent;
      border-style: solid;
      border-width: 10px 10px 0 10px;
      transform: translate(-50%, 0);
    }

    ._head {
      padding-bottom: 10px;
    }
    ._body {
      flex: 1;
    }
    ._foot {
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }

  //zhtips: 窗口右上角关闭按钮X
  $closeColor: #333;
  .windows_close {
    position: absolute;
    top: 0;
    right: 0;
    width: 30px;
    height: 30px;
    transform: rotate(45deg);
    &::before {
      position: absolute;
      top: 50%;
      left: 50%;
      display: block;
      width: 10px;
      height: 1px;
      content: '';
      background-color: $closeColor;
      transform: translate3d(-50%, -50%, 0);
    }

    &::after {
      position: absolute;
      top: 50%;
      left: 50%;
      display: block;
      width: 1px;
      height: 10px;
      content: '';
      background-color: $closeColor;
      transform: translate3d(-50%, -50%, 0);
    }
  }
</style>

参考
天地图示例:http://lbs.tianditu.gov.cn/api/js4.0/examples.html
天地图API:http://lbs.tianditu.gov.cn/api/js4.0/class.html

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17003.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!