看过的知识不等于学会。唯有用心总结、系统记录,并通过温故知新反复实践,才能真正掌握一二
作为一名摸爬滚打三年的前端开发,开源社区给了我饭碗,我也将所学的知识体系回馈给大家,助你少走弯路!
OpenLayers、Leaflet 快速入门 ,每周保持更新 2 个案例
Cesium 快速入门,每周保持更新 4 个案例

OpenLayers 综合案例-信息窗体-弹窗

Vue 3 + OpenLayers 实现的 WebGIS 应用提供了完整的信息窗体-弹窗功能

主要功能

  1. 地图点击弹窗(显示坐标、缩放、分辨率)
  2. 双击添加点标记(弹窗可删除)
  3. 框选(Ctrl+拖动)弹窗显示包络框
  4. 要素删除功能(单个删除、全部删除)
  5. 右键菜单(放大、缩小、定位、关闭)
    在这里插入图片描述

MP4效果动画链接地址

技术栈

该环境下代码即拿即用

Vue 3.5.13+
OpenLayers 10.5.0+
Vite 6.3.5+
<template><div class="ol-tutorial-demo-container"><div ref="mapContainer" class="map"></div><!-- 状态栏 --><div class="statusbar"><span>坐标: {{ mouseCoord }}</span><span>缩放: {{ zoom }}</span><span>旋转: {{ rotation }}°</span><span>分辨率: {{ resolution }}</span></div><!-- 框选包络框弹窗 --><div v-if="boxInfo" class="popup" :style="boxPopupStyle"><div><strong>框选范围</strong></div><div>西南: {{ boxInfo.sw }}</div><div>东北: {{ boxInfo.ne }}</div><button class="close-btn" @click="boxInfo = null">关闭</button></div><!-- 点标记弹窗 --><div v-if="pointPopup" class="popup" :style="pointPopupStyle"><div><strong>点标记</strong></div><div>经度: {{ pointPopup.lon }}</div><div>纬度: {{ pointPopup.lat }}</div><button class="close-btn" @click="removePoint(pointPopup.id)">删除</button><button class="close-btn" @click="pointPopup = null">关闭</button></div><!-- 地图点击弹窗 --><div v-if="mapPopup" class="popup" :style="mapPopupStyle"><div><strong>地图信息</strong></div><div>经度: {{ mapPopup.lon }}</div><div>纬度: {{ mapPopup.lat }}</div><div>缩放: {{ mapPopup.zoom }}</div><div>分辨率: {{ mapPopup.resolution }}</div><button class="close-btn" @click="mapPopup = null">关闭</button></div><!-- 右键菜单 --><ulv-if="contextMenu.visible"class="context-menu":style="contextMenu.style"><li @click="zoomIn">放大一级</li><li @click="zoomOut">缩小一级</li><li @click="centerBeijing">定位到北京</li><li @click="closeContextMenu">关闭</li></ul></div>
</template><script setup>
import { ref, onMounted, onUnmounted, nextTick } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import { Point } from "ol/geom";
import Feature from "ol/Feature";
import { Style, Stroke, Circle, Fill } from "ol/style";
import { defaults as defaultControls, FullScreen, ScaleLine } from "ol/control";
import { defaults as defaultInteractions } from "ol/interaction/defaults";
import { fromLonLat, toLonLat } from "ol/proj";
import DragBox from "ol/interaction/DragBox";
import { platformModifierKeyOnly } from "ol/events/condition";
import "ol/ol.css";const map = ref(null);
const mapContainer = ref(null);
const vectorSource = ref(null);
const pointLayer = ref(null);
const dragBox = ref(null);// 状态栏
const mouseCoord = ref("");
const zoom = ref(0);
const rotation = ref(0);
const resolution = ref(0);// 地图弹窗
const mapPopup = ref(null);
const mapPopupStyle = ref({});// 点标记
const points = ref([]); // {id, lon, lat, feature}
const pointPopup = ref(null);
const pointPopupStyle = ref({});
let pointId = 1;
function addPoint(lon, lat) {const feature = new Feature({ geometry: new Point(fromLonLat([lon, lat])) });feature.setStyle(new Style({image: new Circle({radius: 8,fill: new Fill({ color: "#ff5722" }),stroke: new Stroke({ color: "#fff", width: 2 }),}),}));pointLayer.value.getSource().addFeature(feature);points.value.push({ id: pointId++, lon, lat, feature });
}
function removePoint(id) {const idx = points.value.findIndex((p) => p.id === id);if (idx !== -1) {pointLayer.value.getSource().removeFeature(points.value[idx].feature);points.value.splice(idx, 1);pointPopup.value = null;}
}// 框选
const boxInfo = ref(null);
const boxPopupStyle = ref({});// 右键菜单
const contextMenu = ref({ visible: false, style: {}, pixel: null });
function closeContextMenu() {contextMenu.value.visible = false;
}
function zoomIn() {map.value.getView().setZoom(map.value.getView().getZoom() + 1);closeContextMenu();
}
function zoomOut() {map.value.getView().setZoom(map.value.getView().getZoom() - 1);closeContextMenu();
}
function centerBeijing() {map.value.getView().setCenter(fromLonLat([116.4, 39.9]));map.value.getView().setZoom(12);closeContextMenu();
}onMounted(() => {// 初始化图层const baseLayer = new TileLayer({source: new XYZ({url: "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}",}),});vectorSource.value = new VectorSource();pointLayer.value = new VectorLayer({ source: new VectorSource() });// 初始化地图map.value = new Map({target: mapContainer.value,layers: [baseLayer, pointLayer.value],view: new View({ center: fromLonLat([116.4, 39.9]), zoom: 12 }),controls: defaultControls().extend([new FullScreen(), new ScaleLine()]),interactions: defaultInteractions({doubleClickZoom: false, // 禁用双击缩放}),});// 状态栏zoom.value = map.value.getView().getZoom();rotation.value = ((map.value.getView().getRotation() * 180) /Math.PI).toFixed(1);resolution.value = map.value.getView().getResolution().toFixed(2);map.value.on("pointermove", (evt) => {const [lon, lat] = toLonLat(evt.coordinate);mouseCoord.value = `${lon.toFixed(6)}, ${lat.toFixed(6)}`;});map.value.getView().on("change:rotation", () => {rotation.value = ((map.value.getView().getRotation() * 180) /Math.PI).toFixed(1);});map.value.getView().on("change:resolution", () => {resolution.value = map.value.getView().getResolution().toFixed(2);zoom.value = map.value.getView().getZoom().toFixed(2);});// 单击弹窗map.value.on("singleclick", (evt) => {closeContextMenu();// 检查点标记const feature = map.value.forEachFeatureAtPixel(evt.pixel, (f) => f);if (feature &&pointLayer.value.getSource().getFeatures().includes(feature)) {// 点标记弹窗const [lon, lat] = toLonLat(feature.getGeometry().getCoordinates());pointPopup.value = {id: points.value.find((p) => p.feature === feature).id,lon: lon.toFixed(6),lat: lat.toFixed(6),};pointPopupStyle.value = {left: evt.pixel[0] + 20 + "px",top: evt.pixel[1] + 20 + "px",};return;}// 地图弹窗const [lon, lat] = toLonLat(evt.coordinate);mapPopup.value = {lon: lon.toFixed(6),lat: lat.toFixed(6),zoom: zoom.value,resolution: resolution.value,};mapPopupStyle.value = {left: evt.pixel[0] + 20 + "px",top: evt.pixel[1] + 20 + "px",};});// 双击添加点标记map.value.on("dblclick", (evt) => {const [lon, lat] = toLonLat(evt.coordinate);addPoint(lon, lat);// 自动弹窗nextTick(() => {pointPopup.value = {id: pointId - 1,lon: lon.toFixed(6),lat: lat.toFixed(6),};pointPopupStyle.value = {left: evt.pixel[0] + 20 + "px",top: evt.pixel[1] + 20 + "px",};});evt.preventDefault();});// 框选dragBox.value = new DragBox({ condition: platformModifierKeyOnly });map.value.addInteraction(dragBox.value);dragBox.value.on("boxend", (e) => {const extent = dragBox.value.getGeometry().getExtent();const sw = toLonLat([extent[0], extent[1]]);const ne = toLonLat([extent[2], extent[3]]);boxInfo.value = {sw: `${sw[0].toFixed(6)}, ${sw[1].toFixed(6)}`,ne: `${ne[0].toFixed(6)}, ${ne[1].toFixed(6)}`,};boxPopupStyle.value = {left: e.target.box_.endPixel_[0] + 20 + "px",top: e.target.box_.endPixel_[1] + 20 + "px",};});// 右键菜单mapContainer.value.addEventListener("contextmenu", (e) => {e.preventDefault();contextMenu.value = {visible: true,style: { left: e.clientX + "px", top: e.clientY + "px" },};});
});onUnmounted(() => {if (map.value) map.value.dispose();
});
</script><style scoped>
.ol-tutorial-demo-container {position: relative;width: 100vw;height: 100vh;overflow: hidden;font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.map {width: 100%;height: 100%;
}
.statusbar {position: absolute;left: 20px;bottom: 20px;background: rgba(255, 255, 255, 0.95);border-radius: 8px;padding: 10px 18px;font-size: 1rem;color: #1a237e;display: flex;gap: 18px;z-index: 10;box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.popup {position: absolute;min-width: 180px;background: #fffbe7;border: 1px solid #ffe082;border-radius: 8px;padding: 15px 20px;box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);z-index: 20;color: #795548;
}
.close-btn {margin-top: 10px;background: #ffc107;border: none;border-radius: 6px;padding: 6px 12px;color: #fff;font-weight: 600;cursor: pointer;
}
.close-btn:hover {background: #ff9800;
}
.context-menu {position: absolute;z-index: 30;background: #fff;border: 1px solid #eee;border-radius: 8px;box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);list-style: none;padding: 0;margin: 0;min-width: 140px;font-size: 1rem;
}
.context-menu li {padding: 12px 18px;cursor: pointer;color: #1976d2;border-bottom: 1px solid #f5f5f5;transition: background 0.2s;
}
.context-menu li:last-child {border-bottom: none;
}
.context-menu li:hover {background: #e3f2fd;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916704.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916704.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916704.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GaussDB 开发基本规范

1 集中式1.1数据库价值特性推荐特性分类特性列表说明表类型PARTITION表数据分区存储引擎行存储按行顺序存储表&#xff0c;建议点查&#xff0c;增删改操作较多场景下使用事务事务块显式启动事务单语句事务不显式启动事务&#xff0c;单语句即为事务扩容在线扩容扩节点和数据重…

工作中使用git可能遇到的场景

1.main历史发布版本出问题需要查看&#xff0c;怎么切换历史发布版本&#xff1f;git reset --hard commitid 更新本地库和代码2.A分支的代码已经做过一些功能&#xff0c;想迁移到B分支当前在A分支git checkout B &#xff08;切换到B分支&#xff09;git cherry-pick A的com…

【Spring AI】本地大型语言模型工具-Ollama

Ollama 是一个专注于在本地运行大型语言模型&#xff08;LLM&#xff09;的工具&#xff0c;支持多种开源模型&#xff08;如 Llama 3、Mistral、Gemma 等&#xff09;&#xff0c;提供简单的命令行和 API 接口。<dependency><groupId>org.springframework.ai</…

电机S加减速

STM32步进电机S型加减速算法_stm32___build__-2048 AI社区 以上&#xff0c;电机加减速说的非常清楚&#xff0c;收藏点赞&#xff01;

一、初识 Linux 与基本命令

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月28日 专栏&#xff1a;Linux教程 思维导图 一、Linux 简介 1.1 什么是 Linux? Linux 是一种自由、开源的类Unix操作系统内核&#xff0c;由林纳斯托瓦兹 (Linus Torvalds) 在1991年首次发布。我们通常所说的 “Linux 系统…

解决angular与jetty websocket 每30s自动断连的问题

背景&#xff1a;前端&#xff1a;angular 12&#xff0c;websocket接口由lib.dom.d.ts提供后端&#xff1a;java&#xff0c;websocket接口由jetty 12提供问题现象&#xff1a;前端连上server后&#xff0c;每隔30s就会断开&#xff0c;由于长时间空闲&#xff0c;会导致webso…

【机器学习深度学习】模型私有化部署与微调训练:赋能特定问题处理能力

目录 前言 一、私有化部署的背景&#xff1a;通用能力 ≠ 企业实用 暴露问题 二、微调训练的核心目的 2.1 动作一&#xff1a;私有化部署&#xff08;Private Deployment&#xff09; 2.2 动作二&#xff1a;领域微调&#xff08;Domain Fine-Tuning&#xff09; 2.3 微…

Seq2Seq学习笔记

Seq2Seq模型概述Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;是一种基于深度学习的序列生成模型&#xff0c;主要用于处理输入和输出均为序列的任务&#xff0c;如机器翻译、文本摘要、对话生成等。其核心思想是将可变长度的输入序列映射为另一个可变长度的输出序列。…

react useId

useId useId 是 React 18 引入的一个内置 Hook&#xff0c;用于生成唯一且稳定的 ID &#xff0c; 主要用于&#xff0c;解决在客户端和服务器端渲染&#xff08;SSR&#xff09;时&#xff0c;动态生成 ID 可能导致的冲突问题&#xff1b; 特别适合用于&#xff0c;需要关联 H…

排水管网实时监测筑牢城市安全防线

排水管网的实时监测工作&#xff0c;强调其对于保障城市安全的重要作用。“排水管网”明确了具体的关注对象&#xff0c;它是城市基础设施的重要组成部分&#xff0c;承担着雨水、污水排放等关键功能。“实时监测”突出了监测的及时性和持续性&#xff0c;意味着能够随时获取排…

SZU大学物理实验报告|电位差计

写在前面&#xff1a;博文里放图片&#xff0c;主要省去了对文档的排版时间&#xff0c;实验还是要自己做的&#xff0c;反正都要去实验室上课&#xff0c;顺带锻炼下动手能力。有些结果是实验手写的&#xff0c;所以看不到&#xff0c;有结果的可以对下结果差的不太多就行&…

RoPE简单解析

文章目录简介拆解一些tricks简介 因为RoPE的优异性能&#xff0c;其已成为各种大模型中位置编码的首选&#xff0c;包括多模态模型&#xff1b;在一些多模态模型或视频理解模型中&#xff0c;甚至会用到多维度RoPE。虽然RoPE已广泛应用&#xff0c;之前也看了不少针对其原理解…

windows 获取 APK 文件的包名和启动 Activity 名称

使用 aapt 命令确保环境变量配置正确&#xff1a;首先需要确保你的系统环境变量中包含了 Android SDK 的 build-tools 目录路径。这是因为 aapt 工具位于该目录下。运行命令&#xff1a; 打开命令提示符&#xff08;CMD&#xff09;&#xff0c;然后输入以下命令来查看 APK 的详…

【Mac版】Linux 入门命令行快捷键+联想记忆

Linux Mac 用户终端命令行快捷键 符号速查全解作为一个刚接触 Linux 和终端的 macOS 用户&#xff0c;常常被命令行的各种快捷键和符号弄得头晕脑胀&#xff0c;本文将带你系统地掌握命令行中最常用的快捷键和符号&#xff0c;并通过逻辑联想帮助你轻松记住每一个组合。一、基…

AUTOSAR Mcal Dio - 模块介绍 + EB配置工具介绍

文章目录1. 模块简介2. 主要功能3. 缩略语4. API接口5. 功能介绍5.1. ChannelGroup5.2. Dio_MaskedWritePort6. 序列图6.1.读GPIO电平6.2. 设置GPIO电平7. EB 工具配置7.1.General7.2.DioPort8. 参考资料1. 模块简介 Dio&#xff0c;全称“Digital Input Output”。Dio模块&am…

ICT模拟零件测试方法--晶体管测试

ICT模拟零件测试方法–晶体管测试 文章目录ICT模拟零件测试方法--晶体管测试晶体管测试晶体管测试配置晶体管测试配置晶体管测量选项晶体管测试 i3070 在线测试软件为每个晶体管提供两种测试&#xff1a; 使用二极管测试对晶体管的两个 PN 结进行测试。这是检查设备存在的快速…

AI算法实现解析-C++实例

基于C++实现的AI 以下是基于C++实现的AI/机器学习相关示例,涵盖基础算法、计算机视觉、自然语言处理等领域,适合不同阶段的学习者参考: 基础机器学习算法 线性回归 使用梯度下降法预测连续值,核心公式: 损失函数: 逻辑回归 二分类问题实现,Sigmoid函数: K-Means…

亚马逊云科技实战架构:构建可扩展、高效率、无服务器应用

对于今天的开发者、架构师和技术爱好者而言&#xff0c;云计算早已超越了简单的“虚拟机租赁”或“服务器托管”阶段。它已经演化为一套丰富、强大且精密的工具集&#xff0c;能够以前所未有的方式设计、部署和扩展应用程序。真正的云原生思维&#xff0c;是掌握并运用多种架构…

论文阅读:《无约束多目标优化的遗传算法,群体和进化计算》

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

嵌入式单片机中位带操作控制与实现

STM32 单片机的SRAM有两个区支持位带(bit-band)操作。 那么,什么是位带,位带操作的原理是怎样的呢? 今天来梳理一下这个知识点。 在介绍位带操作之前,先看一看 ARM Crotext-M3 的存储器映射。 CM3 的地址空间是 4GB, 程序可以在代码区,内部 SRAM 区以及外部 RAM 区中执…