中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

扁平式風(fēng)格網(wǎng)站建站abc官方網(wǎng)站

扁平式風(fēng)格網(wǎng)站,建站abc官方網(wǎng)站,wordpress分享微信插件,南京市的網(wǎng)站是由那幾家公司做的摘要 在 WebGIS 開(kāi)發(fā)中,OpenLayers 是一個(gè)非常強(qiáng)大的開(kāi)源地圖庫(kù),它可以在 Web 應(yīng)用中渲染高效的地圖。本篇文章將介紹如何在 Vue 3 中使用 OpenLayers,并封裝一個(gè)自定義地圖控件組件,實(shí)現(xiàn)地圖的放大、縮小、長(zhǎng)度測(cè)量和面積測(cè)量功能…

摘要
在 WebGIS 開(kāi)發(fā)中,OpenLayers 是一個(gè)非常強(qiáng)大的開(kāi)源地圖庫(kù),它可以在 Web 應(yīng)用中渲染高效的地圖。本篇文章將介紹如何在 Vue 3 中使用 OpenLayers,并封裝一個(gè)自定義地圖控件組件,實(shí)現(xiàn)地圖的放大、縮小、長(zhǎng)度測(cè)量和面積測(cè)量功能。


1. 項(xiàng)目介紹

在 WebGIS 相關(guān)的前端開(kāi)發(fā)中,OpenLayers 是一個(gè)流行的選擇。結(jié)合 Vue 3,我們可以利用 Composition API 更好地封裝和管理地圖邏輯,使代碼更加清晰和可維護(hù)。

本篇文章將介紹如何在 Vue 3 項(xiàng)目中集成 OpenLayers,并基于此封裝一個(gè)自定義地圖組件,提供以下功能:

  1. 放大(Zoom In)
  2. 縮小(Zoom Out)
  3. 測(cè)量長(zhǎng)度(Measure Length)
  4. 測(cè)量面積(Measure Area)

2. 安裝 OpenLayers

首先,我們需要在 Vue 3 項(xiàng)目中安裝 OpenLayers。

(1)創(chuàng)建 Vue 3 項(xiàng)目

如果你還沒(méi)有 Vue 3 項(xiàng)目,可以使用以下命令創(chuàng)建一個(gè)新的 Vue 3 項(xiàng)目:

npm create vite@latest vue3-openlayers --template vue 
cd vue3-openlayers 
npm install

(2)安裝 OpenLayers

運(yùn)行以下命令安裝 OpenLayers:

npm install ol

3. 編寫 OpenLayers 自定義組件

components 目錄下創(chuàng)建 OpenLayersMap.vue 組件,該組件負(fù)責(zé)加載地圖并提供交互功能。

完整代碼

<!--* @Author: 彭麒* @Date: 2025/2/14* @Email: 1062470959@qq.com* @Description: 此源碼版權(quán)歸吉檀迦俐所有,可供學(xué)習(xí)和借鑒或商用。-->
<template><div class="container"><div class="w-full flex justify-center flex-wrap"><div class="font-bold text-[24px]">在Vue3中使用OpenLayers自定義組件(放大、縮小、長(zhǎng)度測(cè)量、面積測(cè)量)</div></div><div class="controlbox"><div class="getlength0" @click="getLength('length')"></div><div class="getarea0" @click="getArea('area')"></div><div class="zoomIn" @click="zoomIn"></div><div class="zoomOut" @click="zoomOut"></div></div><div id="vue-openlayers"></div></div>
</template><script setup>
import { onMounted, ref } from "vue";
import "ol/ol.css";
import { Map, View } from "ol";
import Tile from "ol/layer/Tile";
import OSM from "ol/source/OSM";
import MeasureTool from "@/utils/OpenLayersMeasure.ts";
import * as control from "ol/control";const map = ref(null);const zoomIn = () => {if (map.value) {let czoom = map.value.getView().getZoom();map.value.getView().setZoom(czoom + 1);}
};const zoomOut = () => {if (map.value) {let czoom = map.value.getView().getZoom();map.value.getView().setZoom(czoom - 1);}
};const getLength = (type) => {clearMeasure();MeasureTool.measure(map.value, type, true);
};const getArea = (type) => {clearMeasure();MeasureTool.measure(map.value, type, true);
};const clearMeasure = () => {MeasureTool.measure(map.value, "", false);
};const initMap = () => {let raster = new Tile({source: new OSM(),name: "OSM",});map.value = new Map({target: "vue-openlayers",layers: [raster],view: new View({center: [-12000000, 4700000],zoom: 2,}),controls: control.defaults({zoom: false,rotate: false,attribution: false,}).extend([]),});
};onMounted(() => {initMap();
});
</script><style scoped>
.container {width: 840px;height: 590px;margin: 50px auto;border: 1px solid #42B983;position: relative;
}#vue-openlayers {width: 800px;height: 470px;margin: 0 auto;border: 1px solid #42B983;position: relative;
}.controlbox {position: absolute;z-index: 200;bottom: 50px;width: 30px;padding: 5px 7px;height: 120px;right: 30px;border: 1px solid #ccc;border-radius: 4px;cursor: pointer;display: flex;align-content: space-between;flex-direction: column;background-color: #fff;
}.getlength0 {width: 18px;height: 30px;background: url(@/assets/OpenLayers/getlength.png) center center no-repeat;background-size: 16px 16px;
}.getarea0 {width: 18px;height: 30px;background: url(@/assets/OpenLayers/getarea.png) center center no-repeat;background-size: 16px 16px;
}.zoomIn {width: 18px;height: 30px;background: url(@/assets/OpenLayers/zoomin.png) center center no-repeat;background-size: 16px 16px;
}.zoomOut {width: 18px;height: 30px;background: url(@/assets/OpenLayers/zoomout.png) center center no-repeat;background-size: 16px 16px;
}
</style>

4. 測(cè)量工具 OpenLayersMeasure.ts

創(chuàng)建 utils/OpenLayersMeasure.ts 文件,封裝 OpenLayers 的測(cè)量功能:

import Draw from 'ol/interaction/Draw';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Point from 'ol/geom/Point';
import { unByKey } from 'ol/Observable';
import Overlay from 'ol/Overlay';
import { Feature } from 'ol';
import { getArea, getLength } from 'ol/sphere';
import LineString from 'ol/geom/LineString';
import Polygon from 'ol/geom/Polygon';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';export default {measure(map, measureType, show) {let source = new VectorSource(); // 創(chuàng)建一個(gè)新的矢量源let sketch; // 當(dāng)前繪制的要素let helpTooltipElement; // 幫助提示元素let helpTooltip; // 顯示幫助消息的覆蓋層let measureTooltipElement; // 測(cè)量提示元素let measureTooltip; // 顯示測(cè)量結(jié)果的覆蓋層const continuePolygonMsg = ''; // 繪制多邊形時(shí)顯示的消息const continueLineMsg = ''; // 繪制線條時(shí)顯示的消息createMeasureTooltip(); // 創(chuàng)建測(cè)量提示createHelpTooltip(); // 創(chuàng)建幫助提示const pointerMoveHandler = function (evt) {if (evt.dragging) {return;}let helpMsg = '請(qǐng)點(diǎn)擊開(kāi)始繪制'; // 默認(rèn)幫助消息if (sketch) {const geom = sketch.getGeometry();if (geom instanceof Polygon) {helpMsg = continuePolygonMsg; // 如果是多邊形,顯示相應(yīng)消息} else if (geom instanceof LineString) {helpMsg = continueLineMsg; // 如果是線條,顯示相應(yīng)消息}}helpTooltipElement.innerHTML = helpMsg; // 更新幫助提示內(nèi)容helpTooltip.setPosition(evt.coordinate); // 設(shè)置幫助提示位置helpTooltipElement.classList.remove('hidden'); // 顯示幫助提示};map.on('pointermove', pointerMoveHandler); // 監(jiān)聽(tīng)指針移動(dòng)事件map.getViewport().addEventListener('mouseout', function () {helpTooltipElement.classList.add('hidden'); // 鼠標(biāo)移出視口時(shí)隱藏幫助提示});let draw; // 繪制交互const formatLength = function (line) {const sourceProj = map.getView().getProjection(); // 獲取投影坐標(biāo)系const length = getLength(line, { projection: sourceProj }); // 計(jì)算長(zhǎng)度let output;if (length > 100) {output = (Math.round(length / 1000 * 100) / 100) + ' km'; // 如果長(zhǎng)度大于100米,顯示為公里} else {output = (Math.round(length * 100) / 100) + ' m'; // 否則顯示為米}return output;};const formatArea = function (polygon) {const sourceProj = map.getView().getProjection(); // 獲取投影坐標(biāo)系const area = getArea(polygon, { projection: sourceProj }); // 計(jì)算面積let output;if (area > 10000) {output = (Math.round(area / 1000000 * 100) / 100) + ' km<sup>2</sup>'; // 如果面積大于10000平方米,顯示為平方公里} else {output = (Math.round(area * 100) / 100) + ' m<sup>2</sup>'; // 否則顯示為平方米}return output;};for (const layerTmp of map.getLayers().getArray()) {if (layerTmp.get('name') == 'feature') {source = layerTmp.getSource(); // 獲取存放要素的矢量層}}function addInteraction() {const type = (measureType == 'area' ? 'Polygon' : 'LineString'); // 根據(jù)測(cè)量類型設(shè)置繪制類型draw = new Draw({source: source,type: type,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)', // 填充顏色}),stroke: new Stroke({color: 'rgba(255, 0, 0, 0.5)', // 線條顏色lineDash: [10, 10], // 虛線樣式width: 2, // 線條寬度}),image: new CircleStyle({radius: 5, // 圓點(diǎn)半徑stroke: new Stroke({color: 'rgba(0, 0, 0, 0.7)', // 圓點(diǎn)邊框顏色}),fill: new Fill({color: 'rgba(255, 255, 255, 0.2)', // 圓點(diǎn)填充顏色}),}),}),});map.addInteraction(draw); // 添加繪制交互let listener;draw.on('drawstart', function (evt) {sketch = evt.feature; // 設(shè)置當(dāng)前繪制的要素let tooltipCoord = evt.coordinate; // 提示坐標(biāo)listener = sketch.getGeometry().on('change', function (evt) {const geom = evt.target;let output;if (geom instanceof Polygon) {output = formatArea(geom); // 格式化面積tooltipCoord = geom.getInteriorPoint().getCoordinates(); // 獲取多邊形內(nèi)部點(diǎn)坐標(biāo)} else if (geom instanceof LineString) {output = formatLength(geom); // 格式化長(zhǎng)度tooltipCoord = geom.getLastCoordinate(); // 獲取線條最后一個(gè)點(diǎn)的坐���}measureTooltipElement.innerHTML = output; // 更新測(cè)量提示內(nèi)容measureTooltip.setPosition(tooltipCoord); // 設(shè)置測(cè)量提示位置});map.on('dblclick', function (evt) {const point = new Point(evt.coordinate);source.addFeature(new Feature(point)); // 添加雙擊點(diǎn)要素});});draw.on('drawend', function () {measureTooltipElement.className = 'tooltip tooltip-static'; // 設(shè)置測(cè)量提示樣式measureTooltip.setOffset([0, -7]); // 設(shè)置測(cè)量提示偏移sketch = null; // 清空當(dāng)前繪制的要素measureTooltipElement = null; // 清空測(cè)量提示元素createMeasureTooltip(); // 創(chuàng)建新的測(cè)量提示unByKey(listener); // 移除監(jiān)聽(tīng)器map.un('pointermove', pointerMoveHandler); // 移除指針移動(dòng)事件監(jiān)聽(tīng)map.removeInteraction(draw); // 移除繪制交互helpTooltipElement.classList.add('hidden'); // 隱藏幫助提示});}function createHelpTooltip() {if (helpTooltipElement) {helpTooltipElement.parentNode.removeChild(helpTooltipElement); // 移除舊的幫助提示元素}helpTooltipElement = document.createElement('div');helpTooltipElement.className = 'tooltip hidden'; // 設(shè)置幫助提示樣式helpTooltip = new Overlay({element: helpTooltipElement,offset: [15, 0], // 設(shè)置偏移positioning: 'center-left', // 設(shè)置定位方式});map.addOverlay(helpTooltip); // 添加幫助提示覆蓋層}function createMeasureTooltip() {if (measureTooltipElement) {measureTooltipElement.parentNode.removeChild(measureTooltipElement); // 移除舊的測(cè)量提示元素}measureTooltipElement = document.createElement('div');measureTooltipElement.className = 'tooltip tooltip-measure'; // 設(shè)置測(cè)量提示樣式measureTooltip = new Overlay({element: measureTooltipElement,offset: [0, -15], // 設(shè)置偏移positioning: 'bottom-center', // 設(shè)置定位方式});map.addOverlay(measureTooltip); // 添加測(cè)量提示覆蓋層}addInteraction(); // 添加繪制交互const vector = new VectorLayer({name: 'lineAndArea',source: source,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)', // 填充顏色}),stroke: new Stroke({color: 'red', // 線條顏色width: 2, // 線條寬度}),image: new CircleStyle({radius: 7, // 圓點(diǎn)半徑fill: new Fill({color: '#ffcc33', // 圓點(diǎn)填充顏色}),}),}),zIndex: 16, // 設(shè)置圖層順序});if (show && measureType) {map.addLayer(vector); // 顯示測(cè)量圖層} else {map.getOverlays().clear(); // 清除所有覆蓋層map.getLayers().getArray().forEach((layer, index, array) => {if (layer.get('name') == 'lineAndArea') {map.removeLayer(layer); // 移除測(cè)量圖層}});}},
};

5. 在 Vue 項(xiàng)目中使用組件

App.vue 中引入 OpenLayersMap.vue 組件:

<template> <div> <OpenLayersMap /> </div> 
</template> 
<script setup> 
import OpenLayersMap from "@/components/OpenLayersMap.vue"; 
</script>

6. 運(yùn)行項(xiàng)目

在項(xiàng)目根目錄運(yùn)行以下命令,啟動(dòng) Vue 開(kāi)發(fā)服務(wù)器:

npm run dev

然后在瀏覽器中訪問(wèn) http://localhost:5173/,你就可以看到 OpenLayers 地圖,并且可以使用放大、縮小、長(zhǎng)度測(cè)量和面積測(cè)量功能了。


7. 結(jié)語(yǔ)

本篇文章介紹了如何在 Vue 3 項(xiàng)目中集成 OpenLayers,并封裝了一個(gè)自定義地圖控件組件,實(shí)現(xiàn)了放大、縮小、長(zhǎng)度測(cè)量和面積測(cè)量功能。

你可以根據(jù)自己的需求擴(kuò)展更多功能,比如:

  • 添加更多測(cè)量單位
  • 顯示測(cè)量結(jié)果的彈窗
  • 增加圖層切換等功能

希望這篇文章能幫助到你!如果你覺(jué)得有用,請(qǐng)點(diǎn)贊支持!🚀🚀🚀


💬 交流與討論

如果你有任何問(wèn)題或建議,歡迎在評(píng)論區(qū)留言交流!💡

http://www.risenshineclean.com/news/60907.html

相關(guān)文章:

  • 去年做啥網(wǎng)站能致富廣州中小企業(yè)seo推廣運(yùn)營(yíng)
  • 網(wǎng)站分站代理如何搭建一個(gè)自己的網(wǎng)站
  • 如何給公司網(wǎng)站做優(yōu)化網(wǎng)站推廣公司推薦
  • 哪里有做網(wǎng)站技術(shù)百度關(guān)鍵字
  • 金華大企業(yè)網(wǎng)站建設(shè)有哪些小說(shuō)排行榜百度搜索風(fēng)云榜
  • wordpress主題修改ftp寧波seo網(wǎng)絡(luò)推廣
  • 謝崗鎮(zhèn)仿做網(wǎng)站網(wǎng)站排名優(yōu)化外包
  • 用動(dòng)物做logo的旅游網(wǎng)站武漢網(wǎng)站推廣排名
  • 日照手機(jī)網(wǎng)站建設(shè)能翻到國(guó)外的瀏覽器
  • 石家莊市和城鄉(xiāng)建設(shè)局網(wǎng)站快手seo
  • 做北美市場(chǎng)用哪個(gè)網(wǎng)站成都網(wǎng)站排名 生客seo
  • 網(wǎng)站設(shè)計(jì)基本要求網(wǎng)絡(luò)營(yíng)銷渠道策略研究
  • 網(wǎng)站做seo真的能帶來(lái)客戶嗎百度網(wǎng)盤官網(wǎng)下載
  • 網(wǎng)站域名后綴代表什么成都網(wǎng)站優(yōu)化排名
  • 網(wǎng)站信息可以邊建設(shè)邊組織正規(guī)優(yōu)化公司哪家好
  • 交錢做網(wǎng)站對(duì)方拿了錢不做該怎么辦網(wǎng)站維護(hù)工程師
  • 表格制作手機(jī)軟件seo關(guān)鍵詞推廣公司
  • 南寧大型網(wǎng)站推廣公司企業(yè)網(wǎng)站制作方案
  • 網(wǎng)站建設(shè)維護(hù)培訓(xùn)佛山seo外包平臺(tái)
  • 期末網(wǎng)站設(shè)計(jì)做什么網(wǎng)站比較好太原百度推廣開(kāi)戶
  • 倉(cāng)庫(kù)進(jìn)銷存管理軟件免費(fèi)版搜索引擎優(yōu)化分析
  • 做英文網(wǎng)站哪家好十堰seo優(yōu)化方法
  • 大學(xué)生兼職網(wǎng)網(wǎng)站建設(shè)計(jì)劃書海外黃岡網(wǎng)站推廣
  • 制作網(wǎng)站怎么做的網(wǎng)站優(yōu)化技巧
  • 西安制作網(wǎng)站的公司有福州seo排名優(yōu)化公司
  • 品牌型網(wǎng)站制作龍崗百度快速排名
  • 公司網(wǎng)站建設(shè)中心杭州網(wǎng)站優(yōu)化公司哪家好
  • 學(xué)校網(wǎng)站建設(shè)先進(jìn)事跡百度站長(zhǎng)平臺(tái)提交網(wǎng)站
  • 網(wǎng)站聯(lián)系我們?cè)趺醋隹诒疇I(yíng)銷的作用
  • 采購(gòu)網(wǎng)站平臺(tái)全國(guó)疫情今天最新消息