最近项目里面要集成天地图,实现地名搜索、逆地址解析、点聚合等一些功能。实战中遇到一些问题,都总结到这篇文章里面了,我也会持续继续深度开发天地图,也会在这篇文章继续更新的。
vue项目中引入天地图
引入天地图主要有下面的四个步骤
- 注册用户
- 创建新应用
- 获取服务许可(Key)
- 使用天地图api服务
- 注册用户
按照流程注册即可,如果是单位注册,注册后需要工作人员审核(需要一定的时间)
- 创建新应用
注意这里应用类型选择浏览器端(先不要填写域名白名单)
选择完浏览器端后域名白名单先不要填写,如果前期填写了域名白名单会出现
只显示logo
而不显示图层
3. 获取Key 赋值key
4. 引入天地图api服务(方式一)
直接找到网页API导航,选择JavaScript API4.0入门指导
在index文件中直接引入。
<script src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥" type="text/javascript"></script>
<template>
<div id="mapDiv" class="map-container"></div>
</template>
<script setup>
import { onMounted, ref } from "vue";
const zoom = ref(12);
onMounted(() => {
initMap();
});
const initMap = () => {
const map = new T.Map("mapDiv", {
projection: "EPSG:4326",
});
// map.setMapType(TMAP_SATELLITE_MAP); // 设置卫星图
map.centerAndZoom(new T.LngLat(116.40769, 39.90445), zoom.value); // 中心点坐标和缩放级别
};
</script>
<style lang="scss" scoped>
.map-container {
width: 800px;
height: 640px;
}
</style>
- 引入天地图api服务
(方式二)
下载npm天地图的包,引用天地图vue组件库 官方文档:vue-tianditu
pnpm i vue-tianditu
引入:引入推荐使用全局引入,本人之前测试过按需引入结果导致坐
点聚合
时,不显示聚合点。修改成全局引入后即可解决。
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import VueTianditu from "vue-tianditu";
const app = createApp(App);
app.use(VueTianditu, {
v: "4.0", //目前只支持4.0版本
tk: "your map token"
});
app.mount("#app");
<!-- App.vue -->
<template>
<div class="mapDiv">
<tdt-map :center="state.center" :zoom="state.zoom"></tdt-map>
</div>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
import { TdtMap } from "vue-tianditu";
const state = reactive({
center: [113.280637, 23.125178],
zoom: 12
});
</script>
<style>
.mapDiv {
width: 100%;
height: 100%;
}
</style>
实现点聚合
点聚合是使用的方式二进行的地图引入,在vue-tianditu文档中也有详细的文档。
在页面中我们需要引入天地图的组件以及对应的样式文件,并设置天地图的显示点聚合的坐标点。
我们先看一下天地图组件的属性
熟悉属性后还是比较简单的,直接参考文档中的代码即可正确的显示点聚合的功能了
<template>
<div>
<tdt-map style="width: 800px; height: 640px" :center="state.center" :zoom="state.zoom" :loadConfig="loadConfig" @init="mapInit">
<tdt-marker-clusterer :markers="markers" :styles="styles"></tdt-marker-clusterer>
<tdt-marker :position="state.center" :draggable="false" icon="https://soullyoko.github.io/vue-tianditu/marker_red.png"></tdt-marker>
<tdt-infowindow v-model:target="target" :content="content"></tdt-infowindow>
</tdt-map>
</div>
</template>
<script setup>
import { reactive, onMounted } from 'vue';
import 'vue-tianditu/lib/style.css';
const loadConfig = { v: '4.0', tk: '申请下来的key' };
const target = ref(null);
const content = ref('');
const styles = ref([
{
// url: 'https://api.tianditu.gov.cn/img/map/markers/b1.png',
size: [32, 32],
offset: [-16, -32], // 居中偏移
textColor: '#FFFFFF',
textSize: 12,
range: [0, 50],
},
{
// url: 'https://api.tianditu.gov.cn/img/map/markers/b2.png',
size: [48, 48],
offset: [-24, -48],
textColor: '#FF0000',
textSize: 14,
range: [50, 200],
},
{
// url: 'https://api.tianditu.gov.cn/img/map/markers/b3.png',
size: [64, 64],
offset: [-32, -64],
textColor: '#000000',
textSize: 16,
range: [200, 500],
},
]);
const map = ref(null); // 地图组件
// 生成北京周边坐标(示例)
const markers = ref(
Array.from({ length: 500 }, (_, i) => ({
position: [116.3 + Math.random() * 0.5, 39.8 + Math.random() * 0.5],
extData: `cluster-${i}`,
}))
);
// 地图配置
const state = reactive({
center: [116.404, 39.915], // 中心点
zoom: 16, // 缩放比例
});
</script>
tdt-marker
是天地图的点标记组件,如果希望导航或者点击地图更改中心点并标记,直接修改position属性即可。其中icon是标记的图片,需要我们自己去找,官方文档上的图片在网络不好时会不显示。tdt-marker-clusterer
是天地图实现点聚合的组件,markers属性就是标记的聚合点,style是聚合点的样式。tdt-infowindow
是当用户点击标记点时显示的文字信息。可供用户进行自定义显示。
设置当前位置为地图中心点
当用户首次进入地图页面需要手动获取用户的当前位置信息,需要调用浏览器的内置对象
navigator
的geolocation
方法。并设置中心点为当前位置。如果用户没有开启浏览器的位置权限信息给出相应的提示。
- 开启位置信息:
- 提示:
可以监听地图的点击事件,当用户点击地图时能够获取到点击经纬度,调用逆地址解析api获取位置详细信息,设置地图中心点即可实现地图点击位置切换。
需要调用天地图的逆地址解析api逆地理编码查询
onMounted(() => {
getLocation(); // 获取当前经纬度
});
// 获取当前位置信息
const getLocation = () => {
if (!navigator.geolocation) {
ElMessage.error('浏览器不支持地理位置服务');
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
state.center = [position.coords.longitude, position.coords.latitude];
},
(err) => {
ElMessageBox.alert('请开启浏览器/电脑位置服务!');
}
);
};
逆地址解析(点击切换位置)
可以监听地图的点击事件,当用户点击地图时能够获取到点击经纬度,调用逆地址解析api获取位置详细信息,设置地图中心点即可实现地图点击位置切换。
需要调用天地图的逆地址解析api逆地理编码查询
<template>
<div>
<tdt-map style="width: 800px; height: 640px" :center="state.center" :zoom="state.zoom" :loadConfig="loadConfig" @init="mapInit" @click="onClick">
<tdt-marker-clusterer :markers="markers" :styles="styles"></tdt-marker-clusterer>
<tdt-marker :position="state.center" :draggable="false" icon="https://soullyoko.github.io/vue-tianditu/marker_red.png"></tdt-marker>
<tdt-infowindow v-model:target="target" :content="content"></tdt-infowindow>
</tdt-map>
</div>
</template>
// 地图点击时触发
const onClick = (e) => {
state.center = [e.lnglat.lng, e.lnglat.lat]; // 设置中心点坐标
getTiandituAddress(e.lnglat.lng, e.lnglat.lat);
};
// 天地图逆地址解析
const getTiandituAddress = async (lng, lat) => {
const response = await fetch(`https://api.tianditu.gov.cn/geocoder?postStr={'lon':${lng},'lat':${lat},'ver':1}&tk=自己申请的Key`);
const data = await response.json();
console.log('逆地址解析结果', data);
return data.result;
};
地名搜索
官方文档中有地名搜索的组件,实测发现还是存在一些bug,具体如下:
bug目前还没解决,于是自己封装了一个搜索地名,点击切换坐标的函数。下面是实现流程。
基于天地图地名搜索API配合天地图自定义组件
tdt-control
来实现.
使用element-plus中的el-select组件支持输入框联想和自定义选项值,将地名搜索后的经过整合到页面上,仿照官方文档的样子进行排版。
<tdt-map style="width: 800px; height: 640px" :center="state.center" @click="onClick" :zoom="state.zoom" :loadConfig="loadConfig" @init="mapInit">
<tdt-marker-clusterer :markers="markers" :styles="styles"></tdt-marker-clusterer>
<tdt-marker :position="state.center" :draggable="false" icon=""></tdt-marker>
<tdt-infowindow v-model:target="target" :content="content"></tdt-infowindow>
<tdt-control position="topleft">
<el-select
v-model="hotPointID"
filterable
remote
reserve-keyword
placeholder="输入地点关键词"
:remote-method="searchAddress"
:loading="loading"
clearable
style="width: 380px; margin-bottom: 5px"
@change="handleChange"
>
<el-option v-for="(item, index) in options" :key="item.hotPointID" :label="item.name" :value="item.lonlat + ',' + index">
<span>{{ item.name }}</span>
<span style="font-size: 12px; color: #a8abb2; margin-left: 10px">{{ item.address }}</span>
</el-option>
<template #loading>
<svg class="circular" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" />
</svg>
</template>
</el-select>
</tdt-control>
</tdt-map>
// 自定义控件搜索周边信息
const searchAddress = async (queryString) => {
if (!queryString) return;
console.log('自定义控件搜索周边信息');
try {
const params = {
postStr: JSON.stringify({
keyWord: queryString,
level: '12', // 搜索等级
queryRadius: '10000',
pointLonlat: state.center[0] + ',' + state.center[1],
queryType: '3', // 查询类型 1:普通搜索3:周边搜索服务
start: 0, // 起始记录
count: 20, // 每页数量
}),
tk: loadConfig.tk,
type: 'query',
};
const response = await fetch(`http://api.tianditu.gov.cn/v2/search?postStr=${encodeURIComponent(params.postStr)}&tk=${loadConfig.tk}&type=${params.type}`);
const data = await response.json();
console.log('搜索结果', data);
if (data && data.pois) {
options.value = data.pois;
}
} catch (error) {
ElMessage.error('搜索失败');
} finally {
}
};
天地图提供了不同的地名搜索,可以根据需求来更换api
返回当前位置
最后做了一个高德腾讯地图都有的功能,点击返回当前位置。
也是使用了天地图自定义组件
tdt-control
,在地图的右下角增加一个返回当前位置的图标,点击这个图标获取当前位置信息,设置中心点,即可实现。
<tdt-map style="width: 800px; height: 640px" :center="state.center" @click="onClick" :zoom="state.zoom" :loadConfig="loadConfig" @init="mapInit">
<tdt-marker-clusterer :markers="markers" :styles="styles"></tdt-marker-clusterer>
<tdt-marker :position="state.center" :draggable="false" icon=""></tdt-marker>
<tdt-infowindow v-model:target="target" :content="content"></tdt-infowindow>
<!-- 自定义返回当前位置控件 -->
<tdt-control position="bottomright">
<div class="controlStyle" @click.stop="controlClick">
<img style="width: 80%; height: 80%" src="../../assets/myAddress.png" alt="" />
</div>
</tdt-control>
</tdt-map>
// 点击自定义控件
const controlClick = () => {
getLocation();
};
// 获取当前位置信息
const getLocation = () => {
if (!navigator.geolocation) {
ElMessage.error('浏览器不支持地理位置服务');
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
state.center = [position.coords.longitude, position.coords.latitude];
},
(err) => {
ElMessageBox.alert('请开启浏览器/电脑位置服务!');
}
);
};
文章到此就结束了,由于项目还在谈论中后期还会有天地图的需求,我也会及时更新这篇文章的。有任何问题欢迎大家留言🤗🤗🤗