Tencent map development - adding, selecting and displaying 3D polygons

1. Effect display

insert image description here

2. Explanation of the core code

1. Introduce map api

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

2. Initialize the map

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 is the map style id, now uses a dark style, set it in the developer panel
  • The setting of baseMap is to remove the default 3D effect of all buildings, hide all text, and only display the base map, mainly to highlight our newly added 3D buildings

3. Hide the scale and Tencent map 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>
  • direct control via css

4. Get point coordinates

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

5. Add 3D polygons

Here is the code to add a polygon, which is easy to understand and is different from the actual source code

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, //多边形轮廓
			}
		]
	});
  • A polygon is composed of points. Please arrange the points clockwise. For example, to display a cuboid, you need to click 4 points clockwise on the map.
  • Multiple geometries and multiple styles can be placed in a polygon, and a geometry style corresponds to a styleId

6. Polygon selection and highlight style

 // 当前选中建筑增加高亮样色
 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)
 })
  • Add mousemove and mouseout events to polygon, and the parameter res can get the currently selected geometry object, which contains the object id, which is user-defined when adding
  • Change the style through the polygon.setStyles method, but this method needs to pass the style array, and associate the style with the styleId bound to the geometry. As shown in the example picture, there are 3 polygons, one of which is highlighted, so it is necessary to build a style array: 2 blue, and the selected yellow. This way feels more troublesome, I don't know if there is a better way

7. Add text

Here is the code to add a text, which is easy to understand and is different from the actual source code

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",
      },
    },
  ],
});
  • Among them, position we need to fill in the center point of the polygon, the center point can be TMap.geometry.computeCentroid(path)obtained through , path is the set of polygon points
  • By default, there is no TMap.geometry object, which needs to be added when "1. Import map api"&libraries=geometry

3. Source code

Vue is used here


<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>

兄弟,点个赞再走

Guess you like

Origin blog.csdn.net/iamlujingtao/article/details/117062493