Vue项目天地图集成实现逆地址解析、点聚合、高效搜索...

最近项目里面要集成天地图,实现地名搜索、逆地址解析、点聚合等一些功能。实战中遇到一些问题,都总结到这篇文章里面了,我也会持续继续深度开发天地图,也会在这篇文章继续更新的。

vue项目中引入天地图

引入天地图主要有下面的四个步骤

  • 注册用户
  • 创建新应用
  • 获取服务许可(Key)
  • 使用天地图api服务
    在这里插入图片描述
  1. 注册用户 按照流程注册即可,如果是单位注册,注册后需要工作人员审核(需要一定的时间)
    在这里插入图片描述
  2. 创建新应用注意这里应用类型选择浏览器端(先不要填写域名白名单)

选择完浏览器端后域名白名单先不要填写,如果前期填写了域名白名单会出现只显示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>
  1. 引入天地图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是当用户点击标记点时显示的文字信息。可供用户进行自定义显示。

设置当前位置为地图中心点

当用户首次进入地图页面需要手动获取用户的当前位置信息,需要调用浏览器的内置对象navigatorgeolocation方法。并设置中心点为当前位置。如果用户没有开启浏览器的位置权限信息给出相应的提示。

  • 开启位置信息:
    在这里插入图片描述
  • 提示:
    在这里插入图片描述

可以监听地图的点击事件,当用户点击地图时能够获取到点击经纬度,调用逆地址解析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('请开启浏览器/电脑位置服务!');
        }
    );
};

文章到此就结束了,由于项目还在谈论中后期还会有天地图的需求,我也会及时更新这篇文章的。有任何问题欢迎大家留言🤗🤗🤗

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值