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

时间:2024-03-02 06:57:43

一、效果展示

在这里插入图片描述

二、核心代码讲解

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>

兄弟,点个赞再走