腾讯地图开发-三维多边形的添加、选取、展示

一、效果展示

在这里插入图片描述

二、核心代码讲解

1、引入地图api

<script src="https://map.qq.com/api/gljs?v=1.exp&key=你的开发key&libraries=geometry"></script>

2、初始化地图

this.map = new TMap.Map(this.mapEleId, {
    
    
        center,
        zoom: 17,
        minZoom: 15,
        pitch: 45,
        viewMode: '3D',
        mapStyleId: 'style3',
        baseMap: {
    
    
          // 类型:失量底图
          type: 'vector',
          // 仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
          features: ['base', 'building2d'],
        },
      })
  • mapStyleId 是地图风格id,现在使用了暗色风格,在开发者面板里设置
  • baseMap 的设置是为了去除所有建筑的默认3d效果,并隐藏所有文字,仅仅显示底图,主要是为了突出我们新增的三维建筑

3、隐藏比例尺和腾讯地图logo

<style lang="less" scoped>
::v-deep #areaMap {
    
    
  .rotate-circle,
  .tmap-zoom-control {
    
    
    opacity: 0.5; // 缩放旋转控件半透明
  }
  .tmap-scale-control {
    
    
    display: none; // 隐藏比例尺
  }
  a {
    
    
    display: none; // 隐藏腾讯logo
  }
}
</style>
  • 通过css直接控制

4、获取点坐标

// 点击地图取坐标(只用于取点,非业务需求,可删)
this.map.on('click', (e) => {
    
    
  console.log(`点击坐标:${
      
      e.latLng.lat}, ${
      
      e.latLng.lng}`)
})

5、添加三维多边形

这里是添加一个多边形的代码,方便理解,和实际源码有所不同

var path = [
		[40.03847438521698,116.26140117645264],
		[40.038178675807515,116.26140117645264],
		[40.03791582192258,116.26208782196045],
	]
	//转为LatLng数组
	path = path.map(p => {
    
    
		return new TMap.LatLng(p[0], p[1]);
	});

	//初始化polygon
	var polygon = new TMap.MultiPolygon({
    
    
		id: 'polygon-layer', //图层id
		map: map, //设置多边形图层显示到哪个地图实例中
		//多边形样式
		styles: {
    
    
			'style-1': new TMap.ExtrudablePolygonStyle({
    
    
				'color': 'rgba(0,125,255,0.9)', //面填充色
				'showBorder':true, //是否显示拔起面的边线
				'extrudeHeight':30, //多边形拔起高度
				'borderColor': 'rgba(0,125,255,1)' //边线颜色
			})
		},
		//多边形数据
		geometries: [
			{
    
    
				'id': 'geometry-1', //该多边形在图层中的唯一标识(删除、更新数据时需要)
				'styleId': 'style-1', //绑定样式名
				'paths': path, //多边形轮廓
			}
		]
	});
  • 多边形是由点组成的,请从按顺时针安排点,例如显示一个长方体,那么需要在地图上按顺时针点击4个点
  • 一个polygon里面可以放多个geometry和多个style,一个geometry的风格对应一个styleId

6、多边形选取及高亮风格

 // 当前选中建筑增加高亮样色
 this.polygon.on('mousemove', (res) => {
    
    
   if (res && res.geometry) {
    
    
     const index = Number(res.geometry.id.split('-')[1])
     // 0是区域多边形,不做高亮
     if (index === 0) {
    
    
       this.mapEle.style.cursor = 'default' // 鼠标形状-默认
       this.polygon.setStyles(this.defaultStyles)
     } else {
    
    
       this.mapEle.style.cursor = 'pointer' // 鼠标形状-手指
       this.polygon.setStyles(this.createStyles(index))
     }
   }
 })
 this.polygon.on('mouseout', () => {
    
    
   this.mapEle.style.cursor = 'default'
   this.polygon.setStyles(this.defaultStyles)
 })
  • polygon添加mousemove、mouseout事件,参数res可以获取当前选取到的geometry对象,里面有对象id,对象id是添加的时候用户自定义的
  • 变更风格通过polygon.setStyles方法实现,但这个方法是需要传style数组,通过geometry绑定的styleId来关联风格。如示例图那样,3个多边形,其中1个高亮,那么得要构建style数组:2个蓝色,选中的黄色。这种方式感觉还是比较麻烦的,不知有没有更好的方法

7、添加文字

这里是添加一个文字的代码,方便理解,和实际源码有所不同

var label = new TMap.MultiLabel({
    
    
  id: "label-layer",
  map: map,
  styles: {
    
    
    label: new TMap.LabelStyle({
    
    
      color: "#3777FF", //颜色属性
      size: 20, //文字大小属性
      offset: {
    
     x: 0, y: 0 }, //文字偏移属性单位为像素
      angle: 0, //文字旋转属性
      alignment: "center", //文字水平对齐属性
      verticalAlignment: "middle", //文字垂直对齐属性
    }),
  },
  geometries: [
    {
    
    
      id: "label", //点图形数据的标志信息
      styleId: "label", //样式id
      position: new TMap.LatLng(40.040074, 116.273519), //标注点位置
      content: "腾讯北京总部", //标注文本
      properties: {
    
    
        //标注点的属性数据
        title: "label",
      },
    },
  ],
});
  • 其中position我们需要填多边形的中心点,中心点可以通过 TMap.geometry.computeCentroid(path) 获取,path是多边形点集合
  • 默认是没有TMap.geometry对象的,需要在 “1、引入地图api”的时候加上&libraries=geometry

三、源码

这里使用了vue


<template>
  <div class="box">
    <div class="bd">
      <div id="areaMap"></div>
      <!-- <div class="btns">
        <button class="btn-start" @click="getPathStart">范围取点开始</button> <button class="btn-end" @click="getPathEnd">范围取点结束</button>
      </div> -->
    </div>
  </div>
</template>
<script>
/* global TMap */
export default {
     
     
  components: {
     
     },
  data() {
     
     
    return {
     
     }
  },
  computed: {
     
     },
  created() {
     
     
    this.tempPath = '' // (只用于取点,非业务需求,可删)
    this.isBuildHover = false // 是否建筑选中状态
    this.polygon = null // 整个多边形对象
    this.map = null // 腾讯地图对象
    this.mapEle = null // 地图html对象
    this.mapEleId = 'areaMap' // 地图html对象id
    this.center = [40.040578084070226, 116.27488872367269] // 地图中心点
    this.areaStyle = {
     
     
      faceColor: 'rgba(243, 165, 92,0.2)', // 面填充色
      borderColor: 'rgba(243, 165, 92,0.3)', // 边线颜色
    }
    this.buildStyle = {
     
     
      faceColor: 'rgba(45, 92, 179,0.9)', // 面填充色
      borderColor: 'rgba(45, 92, 179,1)', // 边线颜色
    }
    this.hoverStyle = {
     
     
      faceColor: 'rgba(245, 197, 64,0.9)', // 面填充色
      borderColor: 'rgba(245, 197, 64,1)', // 边线颜色
    }
    this.datas = this.createPaths()
    this.defaultStyles = this.createStyles()
  },
  mounted() {
     
     
    this.initMap()
    this.initPaths()
    this.addLabels()
    this.addPolygons()
  },
  beforeDestroy() {
     
     
    if (this.map) {
     
     
      this.map.destroy()
    }
  },
  methods: {
     
     
    // 初始化坐标(把坐标转换为 TMap.LatLng 对象)
    initPaths() {
     
     
      this.datas.forEach((item) => {
     
     
        // eslint-disable-next-line no-param-reassign
        item.path = item.path.map((p) => {
     
     
          return new TMap.LatLng(p[0], p[1])
        })
      })
    },

    // 创建风格
    createStyles(hoverIndex) {
     
     
      const result = {
     
     }
      this.datas.forEach((item, index) => {
     
     
        result[`buildStyle-${
       
       index}`] = new TMap.ExtrudablePolygonStyle({
     
     
          color: index === hoverIndex ? this.hoverStyle.faceColor : item.style.faceColor, // 面填充色
          showBorder: true, // 是否显示拔起面的边线
          extrudeHeight: item.style.height, // 多边形拔起高度
          borderColor: index === hoverIndex ? this.hoverStyle.borderColor : item.style.borderColor, // 边线颜色
        })
      })
      return result
    },

    // 创建几何图形
    createGeometries() {
     
     
      const result = []
      this.datas.forEach((item, index) => {
     
     
        result.push({
     
     
          id: `geometry-${
       
       index}`, // 该多边形在图层中的唯一标识
          styleId: `buildStyle-${
       
       index}`, // 绑定样式名
          paths: item.path, // 多边形轮廓
        })
      })
      return result
    },

    // 创建文字几何图形
    createLabelGeometries() {
     
     
      const result = []
      this.datas.forEach((item, index) => {
     
     
        if (!item.showLabel) return
        const center = TMap.geometry.computeCentroid(item.path) // 获取多边形中心点
        result.push({
     
     
          id: `geometry-${
       
       index}`, // 点图形数据的标志信息
          styleId: 'label', // 样式id
          position: center, // 标注点位置
          content: item.name, // 标注文本
          properties: {
     
     
            // 标注点的属性数据
            title: 'label',
          },
        })
      })
      return result
    },

    // 添加文字
    addLabels() {
     
     
      // eslint-disable-next-line no-unused-vars
      const label = new TMap.MultiLabel({
     
     
        id: 'label-layer',
        map: this.map,
        zIndex: 1,
        enableCollision: false, // 是否文本标注碰撞检测(碰撞到部分会隐藏),默认false
        styles: {
     
     
          label: new TMap.LabelStyle({
     
     
            color: '#c4d7ff', // 颜色属性
            size: 16, // 文字大小属性
          }),
        },
        geometries: this.createLabelGeometries(),
      })
    },

    // 添加多边形
    addPolygons() {
     
     
      // 初始化polygon
      this.polygon = new TMap.MultiPolygon({
     
     
        id: 'polygon-layer', // 图层id
        map: this.map,
        styles: this.defaultStyles,
        geometries: this.createGeometries(),
      })

      // 当前选中建筑增加高亮样色
      this.polygon.on('mousemove', (res) => {
     
     
        if (res && res.geometry) {
     
     
          const index = Number(res.geometry.id.split('-')[1])
          // 0是区域多边形,不做高亮
          if (index === 0) {
     
     
            this.mapEle.style.cursor = 'default' // 鼠标形状-默认
            this.polygon.setStyles(this.defaultStyles)
          } else {
     
     
            this.mapEle.style.cursor = 'pointer' // 鼠标形状-手指
            this.polygon.setStyles(this.createStyles(index))
          }
        }
      })
      this.polygon.on('mouseout', () => {
     
     
        this.mapEle.style.cursor = 'default'
        this.polygon.setStyles(this.defaultStyles)
      })
    },

    // 初始化地图
    initMap() {
     
     
      this.mapEle = document.getElementById(this.mapEleId)
      const center = new TMap.LatLng(this.center[0], this.center[1])
      this.map = new TMap.Map(this.mapEleId, {
     
     
        center,
        zoom: 17,
        minZoom: 15,
        pitch: 45,
        viewMode: '3D',
        mapStyleId: 'style3',
        baseMap: {
     
     
          // 类型:失量底图
          type: 'vector',
          // 仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
          features: ['base', 'building2d'],
        },
      })

      // 点击地图取坐标(只用于取点,非业务需求,可删)
      this.map.on('click', (e) => {
     
     
        console.log(`点击坐标:${
       
       e.latLng.lat}, ${
       
       e.latLng.lng}`)
        this.tempPath += `[${
       
       e.latLng.lat}, ${
       
       e.latLng.lng}],`
      })
    },

    // 范围取点开始(只用于取点,非业务需求,可删)
    getPathStart() {
     
     
      this.tempPath = ''
    },

    // 范围取点结束(只用于取点,非业务需求,可删)
    getPathEnd() {
     
     
      console.log(this.tempPath)
    },

    // 建筑path数据
    createPaths() {
     
     
      return [
        {
     
     
          name: '小区范围',
          showLabel: false,
          style: {
     
     
            height: 0,
            faceColor: this.areaStyle.faceColor,
            borderColor: this.areaStyle.borderColor,
          },
          path: [
            [40.0415034138471, 116.27143701549642],
            [40.04236049909073, 116.27774645381885],
            [40.03957369699148, 116.27834242471181],
            [40.03852857619138, 116.27210238608075],
          ],
        },
        {
     
     
          name: '腾讯总部',
          showLabel: true,
          style: {
     
     
            height: 50,
            faceColor: this.buildStyle.faceColor,
            borderColor: this.buildStyle.borderColor,
          },
          path: [
            [40.04107841094325, 116.27230542328437],
            [40.041359657954686, 116.27439019479755],
            [40.03976347236319, 116.27476008106316],
            [40.0394850839455, 116.27266499006839],
          ],
        },
        {
     
     
          name: '2号楼',
          showLabel: true,
          style: {
     
     
            height: 150,
            faceColor: this.buildStyle.faceColor,
            borderColor: this.buildStyle.borderColor,
          },
          path: [
            [40.039843514986984, 116.27532780045226],
            [40.039919308531985, 116.27587508165402],
            [40.039512505180205, 116.27596764022701],
            [40.039457345501866, 116.27541386155372],
          ],
        },
        {
     
     
          name: '3号楼',
          showLabel: true,
          style: {
     
     
            height: 50,
            faceColor: this.buildStyle.faceColor,
            borderColor: this.buildStyle.borderColor,
          },
          path: [
            [40.04172105241769, 116.27504164650861],
            [40.041792322301546, 116.27602317768105],
            [40.04184059937072, 116.27641732170355],
            [40.04193073913048, 116.27665819301683],
            [40.04202305483084, 116.27735726159221],
            [40.04118263621495, 116.27754753094041],
            [40.04108942488904, 116.276747879087],
            [40.04107631409111, 116.27645335150191],
            [40.04106977757095, 116.27631291052137],
            [40.040985934586736, 116.27599635170418],
            [40.0408917307709, 116.27523477887087],
          ],
        },
      ]
    },
  },
}
</script>

<style lang="less" scoped>
.bd {
     
     
  position: relative;
  background: #2d5cb3;
}
#areaMap {
     
     
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  z-index: 0;
}

.btns {
     
     
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 1;
}

::v-deep #areaMap {
     
     
  .rotate-circle,
  .tmap-zoom-control {
     
     
    opacity: 0.5;
  }
  .tmap-scale-control {
     
     
    display: none; // 隐藏比例尺
  }
  a {
     
     
    display: none; // 隐藏腾讯logo
  }
}
</style>

兄弟,点个赞再走

猜你喜欢

转载自blog.csdn.net/iamlujingtao/article/details/117062493