一、前言
大家好,這里分享一個 Vue3 + OpenLayers 的小案例:
模仿共享單車的電子圍欄功能,用戶在地圖上繪制停泊點時,系統會自動判斷該點是否在規劃好的電子圍欄內(多邊形或圓形)。
這個功能在實際項目中有很大應用場景,比如:
共享單車/電動車:判斷用戶還車是否在規定區域;
物流調度:判斷車輛停靠是否在任務范圍內;
園區/景區管理:判斷人員是否進入限制區域。
下面我們通過一個完整的 Vue3 + OpenLayers 示例來實現。
三、功能效果
二、環境依賴
Vue3 + Vite + TypeScript
OpenLayers (ol)
Element Plus(消息提示用)
安裝依賴:
npm install ol element-plus
四、核心實現思路
初始化地圖:加載 OSM 底圖,添加一個點圖層和一個圍欄圖層。
繪制電子圍欄:提前設置一個多邊形區域和一個圓形區域。
交互繪制點:通過
Draw
交互讓用戶選擇停泊點。判斷點是否在圍欄內:利用
geometry.intersectsCoordinate(coord)
方法判斷坐標是否落在圍欄內。消息提示:使用
ElMessage
提示用戶結果。
五、完整代碼示例
<!--* @Author: 彭麒* @Date: 2025/9/4* @Email: 1062470959@qq.com* @Description: 此源碼版權歸吉檀迦俐所有,可供學習和借鑒或商用。-->
<template><div class="container"><div class="w-full flex justify-center flex-wrap"><div class="font-bold text-[24px]">vue3+openlayers: 模仿共享單車,判斷點是否放在規劃的電子圍欄內</div></div><h4><el-button type="primary" size="small" @click="drawImage">繪制停泊點</el-button></h4><div id="vue-openlayers"></div></div>
</template><script setup lang="ts">
import "ol/ol.css";
import { onMounted, ref } from "vue";
import { Map, View } from "ol";
import Tile from "ol/layer/Tile";
import OSM from "ol/source/OSM";
import LayerVector from "ol/layer/Vector";
import SourceVector from "ol/source/Vector";
import Fill from "ol/style/Fill";
import Feature from "ol/Feature";
import { Point, Circle as OLCircle, Polygon } from "ol/geom";
import Stroke from "ol/style/Stroke";
import Style from "ol/style/Style";
import CircleStyle from "ol/style/Circle";
import Draw from "ol/interaction/Draw";
import { ElMessage } from "element-plus";// 地圖對象
const map = ref<Map | null>(null);
const draw = ref<Draw | null>(null);// 點數據源
const source = new SourceVector({wrapX: false,
});// 圍欄數據源
const dataSource = new SourceVector({wrapX: false,
});// 多邊形數據
const polygonData = [[[116.005, 39.005],[115.006, 40.008],[112.008, 39.008],[116.005, 39.005],],
];// 圓形數據
const circleData = {circleCenter: [115.992, 38.5],circleRadius: 0.5,
};// 顯示多邊形
const showPolygon = () => {const polygonFeature = new Feature({geometry: new Polygon(polygonData),});dataSource.addFeature(polygonFeature);
};// 顯示圓形
const showCircle = () => {const circleFeature = new Feature({geometry: new OLCircle(circleData.circleCenter, circleData.circleRadius),});dataSource.addFeature(circleFeature);
};// 初始化地圖
const initMap = () => {const mapLayer = new Tile({source: new OSM(),});const pointLayer = new LayerVector({source: source,style: new Style({image: new CircleStyle({radius: 5,fill: new Fill({color: "#f0f",}),}),}),});const weilan = new LayerVector({source: dataSource,style: new Style({fill: new Fill({color: "transparent",}),stroke: new Stroke({width: 2,color: "red",}),}),});map.value = new Map({target: "vue-openlayers",layers: [mapLayer, weilan, pointLayer],view: new View({projection: "EPSG:4326",center: [115.006, 39.508],zoom: 8,}),});
};// 繪制停泊點
const drawImage = () => {if (!map.value) return;source.clear();// 停止上一次繪制if (draw.value !== null) {map.value.removeInteraction(draw.value);}draw.value = new Draw({source: source,type: "Point",});map.value.addInteraction(draw.value);draw.value.on("drawend", (e) => {if (!map.value) return;map.value.removeInteraction(draw.value as Draw);const coord = (e.feature.getGeometry() as Point).getCoordinates();const arr = dataSource.getFeatures();let flag = 0;for (let i = 0; i < arr.length; i++) {const polygonGeometry = arr[i].getGeometry();if (polygonGeometry?.intersectsCoordinate(coord)) {flag++;}}if (flag) {ElMessage.success({message: "在電子圍欄內",duration: 1000,});} else {ElMessage.error({message: "在電子圍欄外",duration: 1000,});}});
};onMounted(() => {initMap();showPolygon();showCircle();
});
</script><style scoped>
.container {width: 840px;height: 600px;margin: 50px auto;border: 1px solid #42b983;
}#vue-openlayers {width: 800px;height: 430px;margin: 0 auto;border: 1px solid #42b983;position: relative;
}
</style>
七、總結與擴展
本文實現了一個 基礎電子圍欄判斷功能,在真實業務中可以擴展為:
支持多圍欄:一個城市多個禁停區/允許停放區;
圍欄編輯:后臺管理系統可視化繪制/修改電子圍欄;
軌跡回放:判斷車輛行駛軌跡是否進入圍欄;
性能優化:大規模電子圍欄渲染(可用 GeoJSON 數據源)。