腾讯地图开发-三维多边形的添加、选取、展示
一、效果展示
二、核心代码讲解
1、引入地图api
<script src="https://map.qq.com/api/gljs?v=1.exp&key=你的开发key&libraries=geometry"></script>
- 其中key通过腾讯地图服务开发者获取
- libraries 是指额外引用一些库文件,这里引用了geometry,用于获取集合图形的中心点
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>
兄弟,点个赞再走