vue3+高德地图如何绘制电子围栏

1、准备工作

首先需要去高德开放平台注册账号,并创建一个应用的key和私钥

https://lbs.amap.com/

然后在你的项目中安装高德依赖

npm install @amap/amap-jsapi-loader

2、封装一个画围栏组件 名为MapContainer.vue(可直接使用)

<template>
  <div class="campus-page">
    <div id="campusMap"></div>
    <div class="searchMap">
      <a-input v-model="input" placeholder="请输入地点" id="tipinput" style="width: 100%; padding-right: 10px"></a-input>
    </div>
    <div class="input-card" style="width: 120px" v-if="title !== '详情'">
      <button class="btn" @click="createPolygon()" style="margin-bottom: 5px"> 新建 </button>

      <button class="btn" @click="closePolygon()" style="margin-bottom: 5px">结束</button>
      <button class="btn" @click="clearPolygon()">清除</button>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, ref, watch } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';

interface PolygonData {
  key: number[][];
  mapId: string;
}

export default defineComponent({
  props: {
    path: {
      type: String,
      required: false,
    },
    title: {
      type: String,
      required: false,
    },
  },
  setup(props, { emit }) {
    const pathArr = ref<PolygonData[]>([]);
    const searchKeyword = ref('');
    const map = ref<any>(null);
    const input = ref('');
    const auto = ref<any>(null);
    const placeSearch = ref<any>(null);
    const polygon = ref<any>(null);
    let polyEditor: any = null;
    const onSearch = () => {
      if (searchKeyword.value !== '') {
        const bounds = map.value.getBounds(); // 获取当前视野的南北边界经纬度
        placeSearch.value.searchInBounds(searchKeyword.value, bounds);
      }
    };

    const initMap = async () => {
      window._AMapSecurityConfig = {
        securityJsCode: '你的秘钥',
      };
      await AMapLoader.load({
        key: '你应用的key',
        version: '2.0',
        plugins: [
          'AMap.PolygonEditor',
          'AMap.AutoComplete',
          'AMap.PlaceSearch',
          'AMap.Scale',
          'AMap.OverView',
          'AMap.ToolBar',
          'AMap.MapType',
          'AMap.PolyEditor',
          'AMap.CircleEditor',
          'AMap.Geolocation',
          'AMap.Geocoder',
          'AMap.Polygon',
          'AMap.AMapUI',
          'AMap.DragPolygon',
        ],
      })
        .then((AMap) => {
          map.value = new AMap.Map('campusMap', {
            viewMode: '3D',
            zoom: 11,
          });

          searchMap();
          if(props.title === '新增'){
            clearPolygon()
          }
          if (props.path) {
            const pathson = props.path.split(',');
            let pathUse: number[][] = [];
            for (let i = 0; i < pathson.length; i += 2) {
              pathUse.push([Number(pathson[i]), Number(pathson[i + 1])]);
            }

            polygon.value = new AMap.Polygon({
              map: map.value,
              path: pathUse,
              strokeColor: '#f6cdf6',
              fillColor: '#74b6fd',
            });

            map.value.addOverlay(polygon.value);
            map.value.setFitView();
          }
        })
        .catch((e) => {
          console.log(e);
        });
      initEditor();
    };

    const searchMap = () => {
      auto.value = new AMap.AutoComplete({
        input: 'tipinput',
      });
      placeSearch.value = new AMap.PlaceSearch({
        map: map.value,
      });
      auto.value.on('select', selectSite);
    };

    const selectSite = (e: any) => {
      if (e.poi.location) {
        placeSearch.value.setCity(e.poi.adcode);
        placeSearch.value.search(e.poi.name);
      } else {
        console.error('查询地址失败,请重新输入地址');
      }
    };

    const initEditor = () => {
      polyEditor = new AMap.PolygonEditor(map.value);
      polyEditor.on('add', (data: any) => {
        const polygon = data.target;
        polyEditor.addAdsorbPolygons(polygon);
        polygon.on('dblclick', () => {   
          polyEditor.setTarget(polygon);
          polyEditor.open();
        });
      });
      polyEditor.on('end', (data: any) => {
        const obj: PolygonData = {
          key: data.target._opts.path,
          mapId: data.target._amap_id,
        };
        if (pathArr.value.length > 0) {
          const isRepeat = pathArr.value.some((item, index) => {
            if (item.mapId === obj.mapId) {
              pathArr.value[index] = obj;
              return true;
            }
          });
          if (!isRepeat) {
            pathArr.value.push(obj);
          }
        } else {
          pathArr.value.push(obj);
        }
        console.log(pathArr.value);
      });
      polyEditor.open();
    };

    const createPolygon = () => {
      polyEditor.close();
      polyEditor.setTarget();
      polyEditor.open();
    };

    const closePolygon = () => {
      polyEditor.close();
      emit('onPatharr', pathArr.value);
    };

    const clearPolygon = () => {
      polyEditor.close();
      map.value.clearMap();
      pathArr.value = [];
      emit('onPatharr', pathArr.value);
    };

    const startPolygon = () => {
      polyEditor.open();
    };

    const campusOk = () => {
      polyEditor.close();
      if (pathArr.value.length < 1) {
        console.warn('请划至少划分一个区域位置!');
      }
    };

    const submit = () => {
      console.log(pathArr.value);
    };

    onMounted(() => {
      initMap();
    });

    return {
      pathArr,
      searchKeyword,
      map,
      input,
      auto,
      placeSearch,
      polygon,
      onSearch,
      createPolygon,
      closePolygon,
      clearPolygon,
      startPolygon,
      campusOk,
      submit,
    };
  },
});
</script>

<style scoped lang="less">
#campusMap {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 80vh;
  flex: 7;
  position: relative;
}

.campus-page {
  position: relative;
}

.searchMap {
  position: absolute;
  top: 10px;
  right: 0;
}

.input-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  word-wrap: break-word;
  background-color: #fff;
  background-clip: border-box;
  border-width: 0;
  border-radius: 25px;
  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5);
  position: absolute;
  bottom: 10%;
  right: 20px;
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  padding: 7.5px 12.5px;
}

.btn {
  display: inline-block;
  font-weight: 400;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  border: 1px solid transparent;
  transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
  background-color: transparent;
  background-image: none;
  color: #25a5f7;
  border-color: #25a5f7;
  padding: 0.25rem 0.5rem;
  line-height: 1.5;
  border-radius: 1rem;
  -webkit-appearance: button;
  cursor: pointer;
}

.btn:hover {
  color: #fff;
  background-color: #25a5f7;
  border-color: #25a5f7;
}

.btn:hover {
  text-decoration: none;
}
</style>

3、引入使用

先导入  修改为你组件存放地址

import regionMap from '../../components/MapContainer.vue';

在你需要使用的地方放入
path要是不需要回显 

    <regionMap v-if="visible" :path="preRegion" :title="title" @onPatharr="getPatharr"></regionMap>

得到围栏经纬度方法  

function getPatharr(e) {
  regionList.value = e[0].key;
}

至此就可以实现高德地图+vue3画电子围栏了!

### 在 Vue3 中集成高德地图 API 实现电子围栏功能 #### 初始化 Map 对象并加载高德地图 为了在 Vue3 项目中使用高德地图,首先需要初始化 `Map` 对象。这可以通过引入高德地图的 JavaScript SDK 并配置相应的密钥来完成[^1]。 ```javascript import { onMounted } from &#39;vue&#39;; export default { setup() { let map; onMounted(() => { map = new AMap.Map(&#39;container&#39;, { zoom: 10, center: [116.397428, 39.90923], // 设置初始中心点 }); }); return {}; }, }; ``` 上述代码展示了如何通过 `onMounted` 生命周期钩子,在组件挂载完成后初始化地图对象。 --- #### 使用定位插件获取当前位置 要实现更精确的地图交互体验,可以利用高德地图提供的 `AMap.Geolocation` 插件进行地理定位[^2]。以下是具体实现方式: ```javascript const geolocationPlugin = () => { const geolocation = new AMap.Geolocation({ enableHighAccuracy: true, // 是否启用高精度定位 timeout: 10000, // 超时时间设置为10秒 }); map.addControl(geolocation); geolocation.getCurrentPosition((status, result) => { if (status === &#39;complete&#39;) { console.log(&#39;当前地理位置:&#39;, result.position); } else { console.error(&#39;定位失败&#39;); } }); }; onMounted(() => { map = new AMap.Map(&#39;container&#39;, { zoom: 10, center: [116.397428, 39.90923], }); geolocationPlugin(); }); ``` 此部分实现了基于用户的实际位置调整地图视图的功能。 --- #### 绘制电子围栏区域 绘制电子围栏通常涉及定义一个多边形或多段线路径,并将其显示在地图上。以下是一个简单的多边形绘制示例[^3]: ```javascript const drawFence = () => { const fencePath = [ [116.397428, 39.90923], // 坐标点 A1 [116.407428, 39.91923], // 坐标点 A2 [116.417428, 39.90923], // 坐标点 A3 [116.407428, 39.89923], // 坐标点 A4 [116.397428, 39.90923], // 返回起点形成闭合 ]; const polygon = new AMap.Polygon({ path: fencePath, strokeColor: &#39;#FF33FF&#39;, strokeWeight: 6, fillColor: &#39;#1791fc&#39;, fillOpacity: 0.35, }); map.add(polygon); // 将多边形添加到地图中 }; onMounted(() => { map = new AMap.Map(&#39;container&#39;, { zoom: 10, center: [116.397428, 39.90923], }); drawFence(); }); ``` 以上代码片段演示了如何创建一个封闭的多边形作为电子围栏--- #### 查询附近 POI 点 如果希望进一步增强用户体验,可以在指定区域内搜索附近的兴趣点(POIs)。例如,针对给定的坐标范围执行查询操作: ```javascript const searchNearbyPoi = async () => { const keywords = [&#39;国贸三期&#39;, &#39;东直门&#39;, &#39;奥体森林公园&#39;]; // 关键词列表 const poiSearch = new AMap.PlaceSearch(); await Promise.all( keywords.map(async keyword => { const results = await new Promise(resolve => poiSearch.search(keyword, (status, response) => resolve(response)) ); console.log(`关键词 "${keyword}" 的搜索结果`, results.pois); }) ); }; onMounted(() => { map = new AMap.Map(&#39;container&#39;, { zoom: 10, center: [116.397428, 39.90923], }); searchNearbyPoi(); }); ``` 这段代码允许开发者快速检索特定关键字对应的地点信息。 --- ### 总结 通过结合高德地图的基础功能与 Vue3 的响应式特性,能够轻松构建具备复杂交互逻辑的应用程序。无论是基础的地图展示还是高级的电子围栏功能,都可以借助官方提供的丰富 API 完成开发目标。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值