集合封装了几个常用的天地图方法 方便自己后续用 也方便大家直接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