天地图应用篇:增加全屏、图层选择功能

天地图应用篇:增加全屏、图层选择功能


本节说明:

目的:

  • 实现地图的图层切换
  • 全屏显示 / 退出全屏

案例截图

  • 示下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

案例代码

  • 示例代码:

    <template><div class="tianditu-map-container"><!-- 顶部搜索和天气栏 --><div class="map-top-bar"><div class="search-weather-box search-box-official"><el-autocompletev-if="mapOptions.showSearch"v-model="searchKeyword":fetch-suggestions="fetchSearchSuggestions"placeholder="搜索地名、公交站、地铁站"class="search-input"@select="handleSelectSuggestion"clearable><template #default="{ item, query, highlighted }"><div class="search-suggestion-item" :class="{ 'is-active': highlighted }"><span class="search-suggestion-icon">{{ getPoiIcon(item.catalog) }}</span><span class="search-suggestion-title" v-html="highlightKeyword(item.value, query)"></span><span class="search-suggestion-type">{{ item.catalog }}</span><span class="search-suggestion-meta">{{ item.address }}</span></div></template><template #append><el-button :icon="Search" @click="searchLocation" :loading="searchLoading"><!-- 搜索 --></el-button></template></el-autocomplete></div></div><!-- 右上角按钮组 --><div class="map-toolbar-top-right"><el-tooltip content="全屏" placement="left"><el-button v-if="mapOptions.showFullscreen" :icon="isFullscreen ? Fold : FullScreen" @click="toggleFullscreen" circle /></el-tooltip></div><!-- 地图容器 --><div id="tianditu-map" class="map-container"></div><!-- 标记管理和表单 --><div class="marker-form" v-if="showMarkerForm"><el-form :model="markerForm" label-width="100px"><el-form-item label="名称" prop="name"><el-input v-model="markerForm.name" placeholder="请输入标记名称" /></el-form-item><el-form-item label="纬度" prop="lat"><el-input v-model="markerForm.lat" type="number" placeholder="请输入纬度" /></el-form-item><el-form-item label="经度" prop="lng"><el-input v-model="markerForm.lng" type="number" placeholder="请输入经度" /></el-form-item><el-form-item label="描述" prop="description"><el-input v-model="markerForm.description" type="textarea" :rows="2" placeholder="请输入描述" /></el-form-item><el-form-item><el-button type="primary" @click="saveMarker">保存</el-button><el-button @click="cancelMarker">取消</el-button></el-form-item></el-form></div><div class="markers-list" v-if="markers.length > 0"><h4>已保存的标记</h4><el-table :data="markers" style="width: 100%"><el-table-column prop="name" label="名称" /><el-table-column prop="description" label="描述" /><el-table-column label="坐标" width="200"><template #default="scope">{{ scope.row.lat.toFixed(6) }}, {{ scope.row.lng.toFixed(6) }}</template></el-table-column><el-table-column label="操作" width="250"><template #default="scope"><el-button size="small" @click="centerOnMarker(scope.row)" :icon="Location">定位</el-button><el-button size="small" type="primary" @click="navigateToMarker(scope.row)" :icon="Position">导航</el-button><el-button size="small" type="danger" @click="removeMarker(scope.$index)" :icon="Delete">删除</el-button></template></el-table-column></el-table></div></div>
    </template><script setup>
    import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
    import { ElMessage, ElMessageBox } from 'element-plus'
    import { Location, Position, Search, FullScreen, Fold, Promotion, Guide, Place, School, Delete } from '@element-plus/icons-vue'
    import { h } from 'vue'// 天地图API密钥
    const TIANDITU_KEY = '08pfngl6ytjjs8sjgjeef7ac2lsiissc'// 响应式数据
    const markers = ref([])
    const showMarkerForm = ref(false)
    const markerForm = ref({name: '',lat: '',lng: '',description: ''
    })// 地图相关变量
    let markerObjs = []
    let mapObj = null
    let mapTypeControl = null// 功能开关参数
    const mapOptions = reactive({showSearch: true,showLayerSwitch: true,showFullscreen: true
    })// 其他状态
    const isFullscreen = ref(false)
    const searchKeyword = ref('')
    const searchLoading = ref(false)// 全屏切换
    function toggleFullscreen() {const el = document.getElementById('tianditu-map')?.parentElementif (!el) returnif (!isFullscreen.value) {if (el.requestFullscreen) el.requestFullscreen()else if (el.webkitRequestFullscreen) el.webkitRequestFullscreen()else if (el.mozRequestFullScreen) el.mozRequestFullScreen()else if (el.msRequestFullscreen) el.msRequestFullscreen()isFullscreen.value = true} else {if (document.exitFullscreen) document.exitFullscreen()else if (document.webkitExitFullscreen) document.webkitExitFullscreen()else if (document.mozCancelFullScreen) document.mozCancelFullScreen()else if (document.msExitFullscreen) document.msExitFullscreen()isFullscreen.value = false}
    }// 监听全屏状态变化
    document.addEventListener('fullscreenchange', () => {isFullscreen.value = !!document.fullscreenElement
    })// 搜索相关函数
    function highlightKeyword(text, keyword) {if (!keyword) return textconst reg = new RegExp(`(${keyword})`, 'gi')return text.replace(reg, '<span class="search-highlight">$1</span>')
    }function getPoiIcon(catalog) {if (!catalog) return h(Location)if (catalog.includes('地铁')) return h(Promotion)if (catalog.includes('公交')) return h(Guide)if (catalog.includes('火车站') || catalog.includes('高铁')) return h(Place)if (catalog.includes('学校')) return h(School)return h(Location)
    }async function fetchSearchSuggestions(query, cb) {if (!query) { cb([]); return }const url = `https://api.tianditu.gov.cn/search?postStr={\"keyWord\":\"${encodeURIComponent(query)}\",\"level\":\"9\",\"queryType\":\"1\",\"start\":0,\"count\":10}&type=query&tk=${TIANDITU_KEY}`try {const res = await fetch(url)const data = await res.json()if (data && data.pois && Array.isArray(data.pois)) {cb(data.pois.map(item => ({value: item.name,address: item.address,catalog: item.catalog,lon: item.lonlat.split(' ')[0],lat: item.lonlat.split(' ')[1]})))} else {cb([])}} catch { cb([]) }
    }function handleSelectSuggestion(item) {if (item.lon && item.lat && mapObj) {mapObj.centerAndZoom(new window.T.LngLat(item.lon, item.lat), 16)// 添加高亮markerconst marker = new window.T.Marker(new window.T.LngLat(item.lon, item.lat))mapObj.addOverLay(marker)// 弹窗显示详细信息const popupContent = `<div style='min-width:180px;'><h4 style='margin:0 0 8px 0;'>${item.value}</h4><div style='font-size:13px;color:#666;margin-bottom:6px;'>${item.catalog || ''}</div><div style='font-size:12px;color:#999;margin-bottom:8px;'>${item.address || ''}</div><div style='font-size:12px;color:#999;'>坐标: ${item.lat}, ${item.lon}</div></div>`const infoWin = new window.T.InfoWindow(popupContent, { offset: new window.T.Pixel(0, -20) })mapObj.openInfoWindow(infoWin, new window.T.LngLat(item.lon, item.lat))ElMessage.success('已定位到:' + item.value)}
    }// 动态加载天地图API
    function loadTiandituScript() {return new Promise((resolve, reject) => {if (window.T) {resolve()return}const script = document.createElement('script')script.src = `https://api.tianditu.gov.cn/api?v=4.0&tk=${TIANDITU_KEY}`script.onload = resolvescript.onerror = rejectdocument.head.appendChild(script)})
    }// 初始化地图
    async function initMap() {await loadTiandituScript()await nextTick()if (!window.T) {ElMessage.error('天地图API加载失败')return}mapObj = new window.T.Map('tianditu-map')mapObj.centerAndZoom(new window.T.LngLat(116.4074, 39.9042), 12)mapObj.enableScrollWheelZoom()mapObj.enableDoubleClickZoom()mapObj.enableKeyboard()// 添加控件 (图层切换)if (mapOptions.showLayerSwitch) {mapTypeControl = new window.T.Control.MapType()mapObj.addControl(mapTypeControl)}// 地图点击事件mapObj.addEventListener('click', onMapClick)
    }// 地图点击事件
    function onMapClick(e) {markerForm.value.lat = e.latlng.getLat().toFixed(6)markerForm.value.lng = e.latlng.getLng().toFixed(6)showMarkerForm.value = true
    }// 标记相关函数
    function saveMarker() {if (!markerForm.value.name || !markerForm.value.lat || !markerForm.value.lng) {ElMessage.warning('请填写完整信息')return}const markerData = {id: Date.now(),name: markerForm.value.name,lat: parseFloat(markerForm.value.lat),lng: parseFloat(markerForm.value.lng),description: markerForm.value.description}markers.value.push(markerData)addMarkerToMap(markerData)showMarkerForm.value = falseElMessage.success('标记保存成功')
    }function addMarkerToMap(markerData) {if (!window.T) returnconst marker = new window.T.Marker(new window.T.LngLat(markerData.lng, markerData.lat))marker.data = markerDatamarker.addEventListener('click', (e) => {showMarkerPopup(e, markerData)})mapObj.addOverLay(marker)markerObjs.push(marker)markerData._marker = marker
    }function showMarkerPopup(e, markerData) {const popupContent = `<div style='min-width:180px;'><h4 style='margin:0 0 8px 0;'>${markerData.name}</h4><div style='font-size:13px;color:#666;margin-bottom:6px;'>${markerData.description || ''}</div><div style='font-size:12px;color:#999;margin-bottom:8px;'>坐标: ${markerData.lat.toFixed(6)}, ${markerData.lng.toFixed(6)}</div><div style='display:flex;gap:8px;'><button onclick="window.tdtNavigate(${markerData.lat},${markerData.lng},'${markerData.name}')" style='background:#409EFF;color:#fff;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;'>导航</button><button onclick="navigator.clipboard.writeText('${markerData.lat},${markerData.lng}')" style='background:#67C23A;color:#fff;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;'>复制坐标</button></div></div>`const infoWin = new window.T.InfoWindow(popupContent, { offset: new window.T.Pixel(0, -20) })mapObj.openInfoWindow(infoWin, new window.T.LngLat(markerData.lng, markerData.lat))
    }function cancelMarker() {showMarkerForm.value = falsemarkerForm.value = {name: '',lat: '',lng: '',description: ''}
    }function centerOnMarker(marker) {if (mapObj) {mapObj.centerAndZoom(new window.T.LngLat(marker.lng, marker.lat), 16)ElMessage.success('已定位到标记')}
    }function navigateToMarker(marker) {window.tdtNavigate(marker.lat, marker.lng, marker.name)
    }async function removeMarker(index) {const marker = markers.value[index]try {await ElMessageBox.confirm('确定要删除这个标记吗?', '警告', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'})if (marker._marker) {mapObj.removeOverLay(marker._marker)const i = markerObjs.indexOf(marker._marker)if (i !== -1) markerObjs.splice(i, 1)}markers.value.splice(index, 1)ElMessage.success('标记已删除')} catch {}
    }async function searchLocation() {if (!searchKeyword.value.trim()) {ElMessage.warning('请输入地名')return}searchLoading.value = trueconst url = `https://api.tianditu.gov.cn/geocoder?ds={"keyWord":"${encodeURIComponent(searchKeyword.value)}"}&tk=${TIANDITU_KEY}`try {const res = await fetch(url)const data = await res.json()if (data && data.location) {const { lon, lat } = data.locationmapObj.centerAndZoom(new window.T.LngLat(lon, lat), 16)ElMessage.success('已定位到:' + searchKeyword.value)} else {ElMessage.warning('未找到地名')}} catch {ElMessage.error('地名搜索失败')}searchLoading.value = false
    }// 工具函数
    function toggleMapType() {if (!mapTypeControl) returnmapTypeControl._switchMapType()
    }// 导航跳转函数(全局)
    window.tdtNavigate = function(lat, lng, name) {const url = `https://map.tianditu.gov.cn/navigation.html?lat=${lat}&lng=${lng}&name=${encodeURIComponent(name)}`window.open(url, '_blank')
    }// 生命周期
    onMounted(async () => {await initMap()
    })onUnmounted(() => {if (mapObj) {markerObjs.forEach(marker => mapObj.removeOverLay(marker))markerObjs.length = 0mapObj = null}if (window.tdtNavigate) delete window.tdtNavigate
    })
    </script><style scoped>
    .tianditu-map-container {position: relative;padding: 0;max-width: 100vw;height: 50vh;background: #f5f7fa;
    }.map-top-bar {position: absolute;top: 10px;left: 10px;z-index: 500;display: flex;flex-direction: row;align-items: center;
    }.search-weather-box {display: flex;align-items: center;background: #fff;border-radius: 8px;box-shadow: 0 2px 8px rgba(0,0,0,0.08);padding: 8px 16px;gap: 16px;
    }.search-box-official {background: #fff;border: 1px solid #dcdfe6;box-shadow: 0 2px 8px rgba(0,0,0,0.08);border-radius: 8px;/* padding: 4px 12px; */padding: 0;
    }.search-input {width: 340px;font-size: 15px;border-radius: 8px;border: none;box-shadow: none;
    }.map-toolbar-top-right {position: absolute;top: 16px;right: 120px;z-index: 500;display: flex;flex-direction: row;gap: 8px;}.map-container {width: 100%;height: 100%;border-radius: 0;overflow: hidden;border: none;margin: 0;
    }.marker-form {position: absolute;left: 50px;top: 80px;z-index: 30;background: var(--el-bg-color-page);padding: 20px;border-radius: 8px;border: 1px solid var(--el-border-color-light);
    }.markers-list {position: absolute;right: 32px;bottom: 32px;z-index: 30;background: var(--el-bg-color-page);padding: 20px;border-radius: 8px;border: 1px solid var(--el-border-color-light);max-width: 400px;max-height: 300px;overflow: auto;
    }.markers-list h4 {margin-bottom: 15px;color: var(--el-color-primary);
    }.search-suggestion-item {display: flex;align-items: center;padding: 6px 12px;border-radius: 6px;transition: background 0.2s;cursor: pointer;
    }.search-suggestion-item.is-active,
    .search-suggestion-item:hover {background: #f0f7ff;
    }.search-suggestion-icon {margin-right: 8px;color: #409EFF;font-size: 18px;display: flex;align-items: center;
    }.search-suggestion-title {font-weight: 500;color: #222;margin-right: 8px;
    }.search-suggestion-type {color: #aaa;font-size: 13px;margin-left: 8px;margin-right: 8px;
    }.search-suggestion-meta {color: #999;font-size: 13px;flex: 1;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
    }.search-highlight {color: #409EFF;background: #e6f7ff;border-radius: 2px;padding: 0 2px;
    }</style>

完结。

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

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

相关文章

从零开始,系统学习AI与机器学习:一份真诚的学习路线图

人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;正在深刻改变众多行业的面貌&#xff0c;掌握这些技术已成为许多技术从业者提升竞争力的重要路径。无论你是希望进入这个充满潜力的领域&#xff0c;还是期望在现有技术基础上进行拓展&#xff0c;一份…

NVIDIA CWE 2025 上海直击:从 GPU 集群到 NeMo 2.0,企业 AI 智能化的加速引擎

前言 8 月 8 日&#xff0c;我受邀参加了在上海举办的 NVIDIA CWE 大会。作为一个正在企业内部推动 AI 落地的从业者&#xff0c;这场会议对我来说不仅是“充电”&#xff0c;更像是一场“解题会”。参会感受 在分享干货之前&#xff0c;我先谈谈这次参会的不同感受。给我感受特…

Web攻防-大模型应用LLM安全提示词注入不安全输出代码注入直接间接数据投毒

知识点&#xff1a; 1、WEB攻防-LLM安全-API接口安全&代码注入 2、WEB攻防-LLM安全-提示词注入&不安全输出 Web LLM&#xff08;Large Language Model&#xff09;攻击指针对部署在Web端的AI大语言模型的攻击行为。攻击者通过恶意提示词注入、训练数据窃取、模型逆向工…

docker compose再阿里云上无法使用的问题

最原始的Dokcerfile # 使用官方Python 3.6.8镜像 FROM python:3.6.8-slimWORKDIR /app# 复制依赖文件 COPY requirements.txt .RUN pip install --upgrade pip # 检查并安装依赖&#xff08;自动处理未安装的包&#xff09; RUN pip install --no-cache-dir -r requirements.tx…

C++STL容器List的模拟实现

一、引言list的实现&#xff0c;还是比较简单的&#xff0c;大家只要想着土家楼的形状&#xff0c;画出图来就好了&#xff0c;不需要过多担心。本次的博客会发出一个完整的实现List的List.hpp&#xff0c;以后也会这样&#xff0c;主要是分段发被说孩子分段生。二、模拟List由…

区块链 + 域名Web3时代域名投资的新风口(上)

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

电子电气架构 --- 软件会给汽车带来哪些变化?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

在rtthread中,互斥量不能在中断服务例程中使用?以及线程多次持有互斥量的情况怎么理解?

互斥锁的所有权&#xff1a;互斥量的状态只有两种&#xff0c;开锁或闭锁&#xff08;两种状态值&#xff09;。当有线程持有它时&#xff0c;互斥量处于闭锁状态&#xff0c;由这个线程获得它的所有权。相反&#xff0c;当这个线程释放它时&#xff0c;将对互斥量进行开锁&…

力扣32:最长有效括号

力扣32:最长有效括号题目思路代码题目 给你一个只包含 ‘(’ 和 ‘)’ 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号 子串 的长度。 左右括号匹配&#xff0c;即每个左括号都有对应的右括号将其闭合的字符串是格式正确的&#xff0c;比如 “…

机器学习实例应用

K最近邻算法K近邻算法(KNN,k-Nearest Neighbor),每个样本都可以用它的最接近的K个邻近值来代表。算法说明&#xff1a;①输入没有标签的新数据&#xff0c;将新数据的每个特征与样本集中数据对应的特征进行比较&#xff0c;然后算法提取样本集中特征最相似数据&#xff08;最近…

力扣 hot100 Day77

连做了几个动态规划的中等题&#xff0c;还是比较有套路的&#xff0c;这里只简要分析一下最长递增子序列&#xff0c;设定dp[i]为以nums[i]结尾的最长子序列&#xff0c;递推公式就好推了乘积最大子数组&#xff0c;和上面类似&#xff0c;但考虑到负负得正&#xff0c;所以需…

深入解析RabbitMQ与AMQP-CPP:从原理到实战应用

一、RabbitMQ安装 1.安装 RabbitMQ sudo apt install rabbitmq-serverRabbitMQ 的简单使用 # 启动服务 sudo systemctl start rabbitmq-server.service # 查看服务状态 sudo systemctl status rabbitmq-server.service # 安装完成的时候默认有个用户 guest &#xff0c;但是权限…

(论文速读)ViDAR:视觉自动驾驶预训练框架

论文题目&#xff1a;Visual Point Cloud Forecasting enables Scalable Autonomous Driving&#xff08;视觉点云预测实现可扩展的自动驾驶&#xff09; 会议&#xff1a;CVPR2024 摘要&#xff1a;与对通用视觉的广泛研究相比&#xff0c;可扩展视觉自动驾驶的预训练很少被探…

《Unity Shader入门精要》学习笔记二

1、基础光照&#xff08;1&#xff09;看世界的光模拟真实的光照环境来生成一张图像&#xff0c;需要考虑3种物理现象。光线从光源中被发射出来。光线和场景中的一些物体相交&#xff1a;一些光线被物体吸收了&#xff0c;而另一些光线被散射到其他方向摄像机吸收了一些光&…

Windchill 11.0使用枚举类型自定义实用程序实现生命周期状态管理

一、Enumerated Type Customization Utility 枚举类型自定义实用程序,可用于添加或编辑枚举类型的值,在Windchill 12.0+中可直接在类型和属性管理中编辑,如下图所示,而在Windchill 11.0中只能通过windchill shell启动程序,下面将详细介绍Windchill 11.0中启动并使用枚举类…

UGUI源码剖析(10):总结——基于源码分析的UGUI设计原则与性能优化策略

UGUI源码剖析&#xff08;第十章&#xff09;&#xff1a;总结——基于源码分析的UGUI设计原则与性能优化策略 本系列文章对UGUI的核心组件与系统进行了深入的源代码级分析。本章旨在对前述内容进行系统性总结&#xff0c;提炼出UGUI框架最核心的设计原则&#xff0c;并基于这些…

STM32N6引入NPU,为边缘AI插上“隐形的翅膀”

2025年的春天格外特别。伴随着人形机器人、DeepSeek的强势刷屏&#xff0c;AI成了最有前景的赛道。万物皆可AI&#xff0c;万物也在寻觅用上AI或者让AI“转正”的“aha moment”。 帮助机器更好地“思考”&#xff0c;让更多的AI走向边缘&#xff0c;是AI发展的重要趋势之一。…

演练:使用VB开发多智能体协作的荣格八维分析器

在大语言模型高速发展的时代&#xff0c;我们面对困难的语义分析任务&#xff0c;通过构建智能体进行处理是一个流行趋势。本文将介绍如何使用 Visual Basic .NET 开发一个多智能体协作系统&#xff0c;用于分析聊天记录中特定人物的荣格八维人格类型。 本文使用 CC-BY-NC-SA …

llamafactory使用qlora训练

llamafactory使用qlora训练 1.环境搭建 conda create -n qlora python3.10 -y conda activate qlora# 克隆LLaMA-Factory仓库 git clone https://github.com/hiyouga/LLaMA-Factory.git# 进入仓库目录 cd LLaMA-Factory# 切换到0.9.4版本 git checkout v0.9.4pip install -e .2…

模型微调/量化技术整理

一、模型微调技术1.模型微调简介大模型微调(Fine-tuning)&#xff0c;是指在已经预训练好的大语言模型基础上&#xff08;基座模型&#xff09;&#xff0c;使用特定的数据集进行进一步训练&#xff0c;让模型适应特定任务或领域。通常LLM的预训练是无监督的&#xff0c;但微调…