如上代码已经实现了一些基础功能了,现在要求如图所示,再整个地图左侧加一个如图所示的控件,题目为专题图层选择,现在主要包括人口信息,人才分布,边界,路网,景区这几个专题图层,点击勾选这几个就可以在图上展示出来,现在你就先搭个框架,后续的具体的实现功能后面在写,具体要求如下:在左侧添加一个半透明的专题图层控制面板使用卡片式设计,包含标题和分组选项实现可折叠的专题分类(人口信息、基础图层等)添加搜索过滤功能使用开关控件切换图层显示状态添加视觉反馈和悬停效果 - CSDN文库", "datePublished": "2025-07-23", "keywords": " 如上代码已经实现了一些基础功能了,现在要求如图所示,再整个地图左侧加一个如图所示的控件,题目为专题图层选择,现在主要包括人口信息,人才分布,边界,路网,景区这几个专题图层,点击勾选这几个就可以在图上展示出来,现在你就先搭个框架,后续的具体的实现功能后面在写,具体要求如下:在左侧添加一个半透明的专题图层控制面板 使用卡片式设计,包含标题和分组选项 实现可折叠的专题分类(人口信息、基础图层等) 添加搜索过滤功能 使用开关控件切换图层显示状态 添加视觉反馈和悬停效果", "description": "文章浏览阅读15次。我们正在使用Vue3和Cesium构建一个左侧专题图层控制面板。这个面板需要有以下功能: 1. 可折叠的分类(例如,不同的图层类别如'基础图层'、'专题图层'等) 2. 搜索过滤功能(可以通过输入关键词快速过滤图层) 3. 开关控件(每个图层项前面有一个开关,可以控制该图层的显示和隐藏)" }
活动介绍

<template> <!-- 主地图容器 --> <div id="cesium-container" ref="cesiumContainer"></div> <!-- 鹰眼地图容器 --> <div ref="miniMapContainer" class="mini-map" @click="handleMiniMapClick"> <div class="location-indicator" :style="indicatorStyle"></div> </div> </template> <script setup lang="ts"> import { ref, onMounted, onUnmounted } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 株洲市范围定义 const ZHUZHOU_EXTENT = { west: 112.5, east: 114.5, south: 26.0, north: 28.0 }; // 株洲市矩形区域 const ZHUZHOU_RECTANGLE = Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ); // 株洲市影像瓦片服务URL const ZHUZHOU_TILES_URL = "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png"; // 地图容器引用 const cesiumContainer = ref<HTMLDivElement | null>(null); const miniMapContainer = ref<HTMLElement | null>(null); // 地图实例 let viewer: Cesium.Viewer | null = null; let overviewViewer: Cesium.Viewer | null = null; // 位置指示器样式 const indicatorStyle = ref({ left: '50%', top: '50%', display: 'block' }); // 创建株洲市影像提供者 const createZhuzhouImageryProvider = () => { // 创建有效的版权对象 const credit = new Cesium.Credit("株洲市影像", true); return new Cesium.UrlTemplateImageryProvider({ url: ZHUZHOU_TILES_URL, minimumLevel: 1, maximumLevel: 17, tilingScheme: new Cesium.WebMercatorTilingScheme(), credit: credit // 使用有效的Credit对象 }); }; // 创建主地图 const initMainMap = () => { if (!cesiumContainer.value) return; try { // 创建株洲市影像提供者 const zhuzhouProvider = createZhuzhouImageryProvider(); // 添加世界底图作为背景 const worldProvider = new Cesium.UrlTemplateImageryProvider({ url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', credit: new Cesium.Credit("World Imagery", true) }); // 初始化主地图 viewer = new Cesium.Viewer(cesiumContainer.value, { baseLayerPicker: false, animation: false, timeline: false, navigationHelpButton: false, fullscreenButton: false, geocoder: false, homeButton: false, sceneModePicker: false, skyBox: false, skyAtmosphere: false, infoBox: false, selectionIndicator: false, terrainProvider: new Cesium.EllipsoidTerrainProvider(), sceneMode: Cesium.SceneMode.SCENE3D, }); // 隐藏版权信息 viewer.cesiumWidget.creditContainer.style.display = "none"; // 添加株洲市影像图层 viewer.imageryLayers.addImageryProvider(zhuzhouProvider); // 添加世界底图作为背景(在株洲市影像下方) viewer.imageryLayers.addImageryProvider(worldProvider, 0); // 关键修改:设置初始视野为整个株洲市区域 viewer.camera.flyTo({ destination: ZHUZHOU_RECTANGLE, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0.0 }, duration: 0 // 立即跳转,无动画 }); console.log("主地图初始化完成,加载株洲市影像"); } catch (error) { console.error("主地图初始化失败:", error); } }; // 初始化鹰眼地图 const initMiniMap = () => { if (!miniMapContainer.value) return; try { // 创建株洲市影像提供者 const zhuzhouProvider = createZhuzhouImageryProvider(); // 初始化鹰眼地图 overviewViewer = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, mapProjection: new Cesium.WebMercatorProjection(), skyBox: false, skyAtmosphere: false, // 禁用版权显示 creditContainer: document.createElement("div") }); // 添加株洲市影像图层 overviewViewer.imageryLayers.addImageryProvider(zhuzhouProvider); // 设置鹰眼地图视图为株洲范围 overviewViewer.camera.setView({ destination: ZHUZHOU_RECTANGLE }); // 隐藏UI元素 const toolbar = overviewViewer.container.getElementsByClassName( "cesium-viewer-toolbar" )[0]; if (toolbar) toolbar.style.display = "none"; // 确保版权容器被禁用 overviewViewer.cesiumWidget.creditContainer.style.display = "none"; console.log("鹰眼地图初始化完成,加载株洲市影像"); } catch (error) { console.error("鹰眼地图初始化失败:", error); } }; // 更新位置指示器 const updateIndicatorPosition = () => { if (!viewer) return; const camera = viewer.camera; const rect = camera.computeViewRectangle(); if (!rect) return; const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); // 确保在株洲范围内 const constrainedLon = Math.max( ZHUZHOU_EXTENT.west, Math.min(ZHUZHOU_EXTENT.east, lon) ); const constrainedLat = Math.max( ZHUZHOU_EXTENT.south, Math.min(ZHUZHOU_EXTENT.north, lat) ); // 计算位置百分比 const lonPercent = ((constrainedLon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((constrainedLat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; indicatorStyle.value = { left: `${lonPercent}%`, top: `${latPercent}%`, display: "block" }; }; // 监听主地图相机变化 const setupCameraListener = () => { if (!viewer) return; viewer.camera.changed.addEventListener(updateIndicatorPosition); }; // 鹰眼地图点击处理 const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer || !viewer) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; // 计算点击位置对应的经纬度 const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); // 飞向点击位置 viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 5000), duration: 1 }); }; // 组件挂载时初始化 onMounted(() => { initMainMap(); setTimeout(() => { initMiniMap(); setupCameraListener(); updateIndicatorPosition(); }, 1000); }); // 组件卸载时清理 onUnmounted(() => { if (viewer && !viewer.isDestroyed()) { viewer.destroy(); } if (overviewViewer && !overviewViewer.isDestroyed()) { overviewViewer.destroy(); } }); </script> <style scoped> /* 主地图容器样式 */ #cesium-container { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; background: #000; } /* 鹰眼地图样式 */ .mini-map { position: absolute; right: 20px; bottom: 20px; width: 200px; height: 150px; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } /* 位置指示器样式 */ .location-indicator { position: absolute; width: 14px; height: 14px; background: #ff3e3e; border: 2px solid white; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 15px rgba(255, 62, 62, 1); z-index: 100; } /* 隐藏版权信息 */ :deep(.cesium-widget) { background-color: #000 !important; } :deep(.cesium-widget-credits), :deep(.cesium-credit-textContainer), :deep(.cesium-credit-expand-link) { display: none !important; visibility: hidden !important; } </style> 如上代码已经实现了一些基础功能了,现在要求如图所示,再整个地图左侧加一个如图所示的控件,题目为专题图层选择,现在主要包括人口信息,人才分布,边界,路网,景区这几个专题图层,点击勾选这几个就可以在图上展示出来,现在你就先搭个框架,后续的具体的实现功能后面在写,具体要求如下:在左侧添加一个半透明的专题图层控制面板 使用卡片式设计,包含标题和分组选项 实现可折叠的专题分类(人口信息、基础图层等) 添加搜索过滤功能 使用开关控件切换图层显示状态 添加视觉反馈和悬停效果

时间: 2025-07-23 15:02:11 浏览: 15
<think>我们正在使用Vue3和Cesium构建一个左侧专题图层控制面板。这个面板需要有以下功能: 1. 可折叠的分类(例如,不同的图层类别如“基础图层”、“专题图层”等) 2. 搜索过滤功能(可以通过输入关键词快速过滤图层) 3. 开关控件(每个图层项前面有一个开关,可以控制该图层的显示和隐藏) 设计思路: 1. 使用Vue3的Composition API进行状态管理。 2. 使用Cesium的图层控制功能(通过控制图层的show属性或者通过图层的显隐接口)。 3. 面板的UI框架可以使用Element Plus或者其他UI库,也可以自己构建。 步骤: 一、创建Vue组件 我们将创建一个名为`LayerControlPanel`的组件。 二、数据结构 定义图层组的数据结构,每个组包含组名、折叠状态、图层列表。每个图层包含名称、是否显示、图层对象(或图层在Cesium中的引用)等。 三、实现功能 1. 可折叠分类:每个组有一个标题,点击标题可以折叠/展开该组内的图层列表。 2. 搜索过滤:在面板顶部添加一个搜索框,输入关键词后,实时过滤图层名称(也可以考虑过滤组名)。 3. 开关控件:每个图层项前有一个开关,切换开关可以控制该图层在Cesium中的显示和隐藏。 四、与Cesium集成 在切换开关时,需要调用Cesium图层对象的相应方法(例如,对于`ImageryLayer`,可以设置`show`属性;对于`Entity`,可以设置`show`属性;对于`Cesium3DTileset`,可以设置`show`属性)。 五、样式设计 使用CSS进行样式设计,使面板固定在左侧,可折叠,并且有良好的用户体验。 代码示例: 1. 定义数据结构(在Vue组件中) 2. 模板结构 3. 方法实现 下面是一个简化的实现示例:</think>### 在Cesium地图应用中实现左侧专题图层控制面板 以下是基于Vue3和Cesium实现左侧可折叠专题图层控制面板的完整方案: #### 1. 组件结构设计 ```vue:文件路径 src/components/LayerControlPanel.vue <template> <div class="layer-control-panel"> <!-- 搜索过滤区域 --> <div class="search-box"> <input v-model="searchQuery" placeholder="搜索图层..." class="search-input" /> </div> <!-- 可折叠分类区域 --> <div v-for="category in filteredCategories" :key="category.id" class="category" > <div class="category-header" @click="toggleCategory(category.id)"> <span>{{ category.name }}</span> <span class="toggle-icon"> {{ category.expanded ? '▼' : '►' }} </span> </div> <!-- 图层列表 --> <div v-show="category.expanded" class="layer-list"> <div v-for="layer in category.layers" :key="layer.id" class="layer-item" > <label class="switch"> <input type="checkbox" v-model="layer.visible" @change="toggleLayer(layer)" > <span class="slider round"></span> </label> <span class="layer-name">{{ layer.name }}</span> </div> </div> </div> </div> </template> <script setup> import { ref, computed, onMounted } from 'vue' import * as Cesium from 'cesium' // 图层数据结构 const categories = ref([ { id: 'base', name: '基础图层', expanded: true, layers: [ { id: 'osm', name: 'OpenStreetMap', visible: true, type: 'imagery' }, { id: 'terrain', name: '地形高程', visible: true, type: 'terrain' } ] }, { id: 'thematic', name: '专题图层', expanded: true, layers: [ { id: 'population', name: '人口密度', visible: false, type: 'geojson' }, { id: 'traffic', name: '交通流量', visible: false, type: 'geojson' } ] } ]) const searchQuery = ref('') // Cesium viewer实例 const viewer = ref(null) // 初始化Cesium onMounted(() => { viewer.value = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, animation: false, timeline: false }) // 初始化图层 initLayers() }) // 初始化图层到Cesium function initLayers() { categories.value.forEach(category => { category.layers.forEach(layer => { if (layer.type === 'imagery') { viewer.value.imageryLayers.addImageryProvider( new Cesium.OpenStreetMapImageryProvider() ).show = layer.visible } // 其他图层类型初始化逻辑... }) }) } // 切换图层显示状态 function toggleLayer(layer) { if (layer.type === 'imagery') { const imageryLayer = viewer.value.imageryLayers.get(layer.id) if (imageryLayer) imageryLayer.show = layer.visible } // 其他图层类型切换逻辑... } // 折叠/展开分类 function toggleCategory(categoryId) { const category = categories.value.find(c => c.id === categoryId) if (category) category.expanded = !category.expanded } // 过滤图层 const filteredCategories = computed(() => { if (!searchQuery.value) return categories.value return categories.value.map(category => ({ ...category, layers: category.layers.filter(layer => layer.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ) })).filter(category => category.layers.length > 0) }) </script> <style scoped> .layer-control-panel { position: absolute; top: 10px; left: 10px; width: 300px; background: rgba(42, 42, 42, 0.8); border-radius: 8px; padding: 15px; z-index: 100; box-shadow: 0 2px 10px rgba(0,0,0,0.3); color: white; } .search-box { margin-bottom: 15px; } .search-input { width: 100%; padding: 8px; border-radius: 4px; border: 1px solid #555; background: #333; color: white; } .category-header { padding: 10px; background: #333; border-radius: 4px; margin-bottom: 5px; cursor: pointer; display: flex; justify-content: space-between; } .layer-list { padding-left: 15px; } .layer-item { display: flex; align-items: center; padding: 8px 0; } .layer-name { margin-left: 10px; } /* 开关控件样式 */ .switch { position: relative; display: inline-block; width: 40px; height: 20px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; } .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background-color: #4caf50; } input:checked + .slider:before { transform: translateX(20px); } </style> ``` #### 2. 在主应用中使用组件 ```vue:文件路径 src/App.vue <template> <div id="app"> <div id="cesiumContainer"></div> <LayerControlPanel /> </div> </template> <script setup> import LayerControlPanel from './components/LayerControlPanel.vue' </script> <style> #app { position: relative; width: 100vw; height: 100vh; } #cesiumContainer { width: 100%; height: 100%; } </style> ``` #### 3. 关键功能实现说明 1. **可折叠分类**: - 使用`v-for`渲染分类数组 - 每个分类对象包含`expanded`属性控制展开状态 - 点击分类头部触发`toggleCategory`方法切换状态 2. **搜索过滤**: - 使用`v-model`绑定搜索框输入值 - 通过计算属性`filteredCategories`实现实时过滤 - 过滤逻辑同时处理图层名称匹配和空结果处理 3. **图层开关**: - 使用CSS自定义开关样式 - 通过`v-model`双向绑定图层的`visible`属性 - `toggleLayer`方法同步更新Cesium图层状态 4. **Cesium集成**: - 在`onMounted`生命周期初始化Cesium viewer - `initLayers`函数初始化图层到Cesium - 图层状态变化时调用Cesium API更新显示 #### 4. 优化建议 1. **性能优化**: - 对于大型数据集使用虚拟滚动 - 添加防抖处理搜索输入 - 使用Web Worker处理复杂过滤逻辑 2. **功能增强**: ```javascript // 添加图层透明度控制 function setLayerOpacity(layer, opacity) { if (layer.type === 'imagery') { const imageryLayer = viewer.value.imageryLayers.get(layer.id) imageryLayer.alpha = opacity } } // 添加图层排序控制 function moveLayer(layer, direction) { const imageryLayer = viewer.value.imageryLayers.get(layer.id) const currentIndex = viewer.value.imageryLayers.indexOf(imageryLayer) if (direction === 'up' && currentIndex > 0) { viewer.value.imageryLayers.raise(imageryLayer) } else if (direction === 'down') { viewer.value.imageryLayers.lower(imageryLayer) } } ``` 3. **状态持久化**: ```javascript // 使用localStorage保存面板状态 function savePanelState() { const state = { categories: categories.value, searchQuery: searchQuery.value } localStorage.setItem('layerPanelState', JSON.stringify(state)) } function loadPanelState() { const savedState = localStorage.getItem('layerPanelState') if (savedState) { const state = JSON.parse(savedState) categories.value = state.categories searchQuery.value = state.searchQuery } } ``` #### 5. 注意事项 1. **Cesium资源加载**: - 确保在`index.html`中正确引入Cesium库和样式 - 配置CESIUM_BASE_URL指向正确的资源路径 2. **响应式设计**: - 添加媒体查询适应移动设备 - 实现面板可拖动调整大小功能 3. **图层管理**: - 为每个图层添加唯一标识符 - 实现图层加载状态指示器 - 添加错误处理机制 此实现提供了完整的专题图层控制功能,包含可折叠分类、实时搜索过滤和开关控件。通过响应式设计确保良好的用户体验,并预留了扩展接口用于添加更多高级功能[^1]。
阅读全文

相关推荐

<template> 晴 31℃/西北风 株洲市"天空地水"动态监测平台 {{ currentTime }} {{ currentWeek }} <select v-model="projectionType" @change="switchProjectionType"> <option value="c">经纬度投影</option> <option value="w">球面墨卡托投影</option> </select> <select v-model="selectedMapType" @change="switchMapType"> <option v-for="option in mapOptions" :value="option.value" :key="option.value"> {{ option.label }} </option> </select> <select v-model="networkType" @change="switchNetworkType"> <option value="internal">内网地图</option> <option value="external">外网地图</option> </select> </template> <script setup> import { ref, onMounted } from 'vue'; import * as Cesium from 'cesium'; import "cesium/Build/Cesium/Widgets/widgets.css"; // 天地图服务密钥 const TIANDITU_TOKEN = '72d487f15710ca558987b9baaba13736'; // 当前时间和星期 const currentTime = ref(""); const currentWeek = ref(""); const weekMap = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; const updateTime = () => { const now = new Date(); currentTime.value = now.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-').replace(/(\d{4})-(\d{2})-(\d{2})/, '$ 1年$ 2月$ 3日'); currentWeek.value = weekMap[now.getDay()]; }; setInterval(updateTime, 1000); updateTime(); // 网络类型选择 const networkType = ref('external'); // 默认外网 // 地图类型选择 const selectedMapType = ref('img_c'); // 默认显示影像+注记 // 投影类型选择 const projectionType = ref('c'); // 默认经纬度投影 // 地图选项配置 const mapOptions = ref([ { value: 'img_c', label: '影像+注记' }, { value: 'vec_c', label: '矢量+注记' } ]); // Cesium相关变量 let viewer = null; let tiandituLayers = { baseLayer: null, annotationLayer: null }; // 网络类型切换 const switchNetworkType = () => { // 根据网络类型更新地图选项 if (networkType.value === 'internal') { mapOptions.value = [ { value: 'img', label: '内网影像地图' }, { value: 'vec', label: '内网矢量地图' } ]; // 设置内网默认地图类型 selectedMapType.value = 'img'; } else { mapOptions.value = [ { value: 'img', label: '天地图影像' }, { value: 'img_c', label: '影像+注记' }, { value: 'vec', label: '矢量地图' }, { value: 'vec_c', label: '矢量+注记' }, { value: 'ter', label: '地形图' } ]; // 设置外网默认地图类型 selectedMapType.value = 'img_c'; } // 重新加载地图 loadMapService(selectedMapType.value); // 重新加载石河子数据并定位 loadShiheziVector(viewer); setTimeout(flyToShihezi, 500); }; // 地图类型切换 const switchMapType = () => { if (viewer) { loadMapService(selectedMapType.value); } }; // 投影类型切换 const switchProjectionType = () => { if (viewer) { // 重新加载地图 loadMapService(selectedMapType.value); // 重新定位到石河子 setTimeout(flyToShihezi, 500); } }; // 加载地图服务 const loadMapService = (type) => { if (!viewer || !viewer.imageryLayers) return; // 清除现有图层 if (tiandituLayers.baseLayer) viewer.imageryLayers.remove(tiandituLayers.baseLayer); if (tiandituLayers.annotationLayer) viewer.imageryLayers.remove(tiandituLayers.annotationLayer); if (networkType.value === 'internal') { // 内网地图服务 - 支持c和w投影 const baseUrl = "http://59.255.48.160:81"; // 根据投影类型选择后缀 const projectionSuffix = projectionType.value === 'c' ? '_c' : '_w'; if (type === 'img') { // 内网影像地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: ${baseUrl}/img${projectionSuffix}/wmts, layer: "img", style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit("内网影像地图"), maximumLevel: 18 }) ); } else if (type === 'vec') { // 内网矢量地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: ${baseUrl}/vec${projectionSuffix}/wmts, layer: "vec", style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit("内网矢量地图"), maximumLevel: 18 }) ); } } else { // 外网天地图服务 - 支持c和w投影 // 根据投影类型动态构建URL const baseUrlTemplate = https://t{s}.tianditu.gov.cn/{layer}_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}; // 图层配置映射表 - 根据投影类型调整图层名称 const layerConfigs = { img: { layer: "img", credit: "天地图影像" }, img_c: { baseLayer: { layer: "img", credit: "天地图影像" }, annotationLayer: { layer: projectionType.value === 'c' ? "cia" : "cia_w", credit: "天地图注记" } }, vec: { layer: "vec", credit: "天地图矢量" }, vec_c: { baseLayer: { layer: "vec", credit: "天地图矢量" }, annotationLayer: { layer: projectionType.value === 'c' ? "cva" : "cva_w", credit: "天地图注记" } }, ter: { layer: "ter", credit: "天地图地形" } }; const config = layerConfigs[type]; if (!config) return; // 添加基础图层 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.layer || config.baseLayer.layer), layer: config.layer || config.baseLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.credit || config.baseLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); // 添加注记图层(如果需要) if (config.annotationLayer) { tiandituLayers.annotationLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.annotationLayer.layer), layer: config.annotationLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.annotationLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); } } }; // 保存石河子范围矩形 const shiheziRectangle = ref(null); // 加载石河子矢量数据 const loadShiheziVector = async (viewer) => { try { // 清除现有石河子数据 const dataSources = viewer.dataSources; for (let i = dataSources.length - 1; i >= 0; i--) { if (dataSources.get(i).name === 'shihezi') { dataSources.remove(dataSources.get(i)); } } // 加载石河子市整体边界 const cityDataSource = await Cesium.GeoJsonDataSource.load( "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=659001", { clampToGround: true, stroke: Cesium.Color.GREEN.withAlpha(0.8), strokeWidth: 2, fill: Cesium.Color.WHITE.withAlpha(0.3), name: 'shihezi' // 添加标识 } ); viewer.dataSources.add(cityDataSource); // 添加石河子市标签 cityDataSource.entities.values.forEach(entity => { if (entity.polygon && entity.properties && entity.properties.name) { const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()); const positions = hierarchy.positions; // 计算地理中心 const center = Cesium.BoundingSphere.fromPoints(positions).center; entity.label = { text: "石河子市", font: '18px 黑体', fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 3, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(0, 0), disableDepthTestDistance: Number.POSITIVE_INFINITY, scaleByDistance: new Cesium.NearFarScalar(1e3, 1.0, 1e6, 0.5) }; entity.position = center; } }); // 保存石河子范围(地理坐标) const positions = cityDataSource.entities.values[0].polygon.hierarchy.getValue().positions; const cartographicPositions = positions.map(pos => Cesium.Cartographic.fromCartesian(pos) ); const minLon = Math.min(...cartographicPositions.map(p => p.longitude)); const maxLon = Math.max(...cartographicPositions.map(p => p.longitude)); const minLat = Math.min(...cartographicPositions.map(p => p.latitude)); const maxLat = Math.max(...cartographicPositions.map(p => p.latitude)); shiheziRectangle.value = new Cesium.Rectangle( minLon, minLat, maxLon, maxLat ); } catch (error) { console.error("加载石河子数据失败:", error); } }; // 定位到石河子 const flyToShihezi = () => { if (viewer && shiheziRectangle.value) { // 根据当前投影类型转换坐标 let destination; if (projectionType.value === 'c') { // 经纬度投影直接使用地理坐标 destination = shiheziRectangle.value; } else { // 墨卡托投影需要转换坐标 const sw = Cesium.WebMercatorProjection.geodeticToWebMercator( new Cesium.Cartographic(shiheziRectangle.value.west, shiheziRectangle.value.south) ); const ne = Cesium.WebMercatorProjection.geodeticToWebMercator( new Cesium.Cartographic(shiheziRectangle.value.east, shiheziRectangle.value.north) ); destination = new Cesium.Rectangle( sw.x, sw.y, ne.x, ne.y ); } viewer.camera.flyTo({ destination: destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-70), roll: 0 }, duration: 1 }); } }; onMounted(async () => { try { // 设置Cesium Ion访问令牌 Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE'; // 初始化Cesium Viewer viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, timeline: false, animation: false, geocoder: false, sceneModePicker: false, navigationHelpButton: false, homeButton: false, selectionIndicator: false, infoBox: false, navigationInstructionsInitiallyVisible: false, scene3DOnly: true, terrainProvider: new Cesium.EllipsoidTerrainProvider(), // 使用默认投影类型初始化底图 imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: https://t{s}.tianditu.gov.cn/img_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}, layer: "img", style: "default", tileMatrixSetID: projectionType.value, subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) }); // 强制设置中国视角 viewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0) }); // 加载石河子数据 await loadShiheziVector(viewer); flyToShihezi(); // 加载地图服务 loadMapService(selectedMapType.value); } catch (error) { console.error("初始化失败:", error); } }); </script> <style scoped> /* 基础样式 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Microsoft YaHei", sans-serif; } .monitor-container { width: 100vw; height: 100vh; background: radial-gradient(circle at center, #0c2a50 0%, #0a1a35 100%); overflow: hidden; position: fixed; top: 0; left: 0; display: flex; flex-direction: column; } /* 顶部导航栏样式 - 重新布局 */ .top-bar { height: 70px; background: linear-gradient(90deg, #0a1a35 0%, #1a3a6e 50%, #0a1a35 100%); display: flex; align-items: center; justify-content: space-between; padding: 0 15px; position: relative; z-index: 100; border-bottom: 1px solid rgba(0, 150, 255, 0.3); } /* 左侧区域 */ .left-section { display: flex; align-items: center; flex: 0 0 auto; } /* 中间区域 */ .center-section { flex: 1 1 auto; display: flex; justify-content: center; } /* 右侧区域 */ .right-section { display: flex; align-items: center; flex: 0 0 auto; gap: 10px; } /* 控件组 */ .controls-group { display: flex; gap: 10px; } /* 天气模块 */ .weather-module { display: flex; align-items: center; color: white; font-size: 14px; min-width: 120px; justify-content: center; } .weather-icon { color: #ffcc00; margin-right: 8px; font-size: 16px; } /* 梯形标题样式 */ .platform-title { position: relative; z-index: 10; max-width: 500px; /* 限制最大宽度 */ } .trapezoid-bg { position: relative; padding: 0 40px; height: 70px; display: flex; align-items: center; } .trapezoid-bg::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 60, 113, 0.6); clip-path: polygon(0% 0%, 100% 0%, 90% 100%, 10% 100%); z-index: -1; } .platform-title h1 { font-size: 24px; font-weight: bold; background: linear-gradient(to bottom, #a2e7eb, #00f2fe); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 8px rgba(0, 242, 254, 0.3); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: 100%; } /* 时间模块 */ .time-module { color: white; font-size: 14px; min-width: 220px; text-align: center; white-space: nowrap; } /* 所有控件统一样式 */ .network-switcher select, .map-switcher select, .projection-switcher select { background: rgba(10, 26, 53, 0.8); color: #66ffff; border: 1px solid rgba(0, 150, 255, 0.5); border-radius: 4px; padding: 6px 12px; font-size: 14px; outline: none; cursor: pointer; box-shadow: 0 0 8px rgba(0, 150, 255, 0.3); transition: all 0.3s ease; min-width: 120px; } .network-switcher select:hover, .map-switcher select:hover, .projection-switcher select:hover { background: rgba(26, 58, 110, 0.8); border-color: #00f2fe; box-shadow: 0 0 12px rgba(0, 242, 254, 0.5); } .network-switcher select:focus, .map-switcher select:focus, .projection-switcher select:focus { border-color: #00f2fe; } /* Cesium容器 */ #cesiumContainer { width: 100%; height: calc(100vh - 70px); background-color: #000; position: relative; } /* 响应式调整 */ @media (max-width: 1600px) { .platform-title h1 { font-size: 20px; } .weather-module, .time-module { font-size: 13px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 5px 10px; font-size: 13px; min-width: 110px; } } @media (max-width: 1400px) { .platform-title h1 { font-size: 18px; } .trapezoid-bg { padding: 0 30px; } .time-module { min-width: 180px; } .controls-group { gap: 8px; } } @media (max-width: 1200px) { .platform-title h1 { font-size: 16px; } .trapezoid-bg { padding: 0 20px; } .time-module { min-width: 160px; font-size: 12px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 8px; font-size: 12px; min-width: 100px; } } @media (max-width: 992px) { .time-module { display: none; } .platform-title h1 { font-size: 14px; } .trapezoid-bg { padding: 0 15px; } .weather-module { min-width: auto; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 6px; font-size: 11px; min-width: 90px; } } @media (max-width: 768px) { .weather-module { display: none; } .platform-title h1 { font-size: 12px; } .trapezoid-bg { padding: 0 10px; } .controls-group { gap: 5px; } .network-switcher select, .map-switcher select, .projection-switcher select { min-width: 80px; } } </style> 如上所示代码,还有一个问题,当投影切换到经纬度投影时石河子的位置不对,离实际位置很远,没有切换,这是为什么,你修改一下发我代码

<template> 晴 31℃/西北风 株洲市"天空地水"动态监测平台 {{ currentTime }} {{ currentWeek }} <select v-model="projectionType" @change="switchProjectionType"> <option value="c">经纬度投影</option> <option value="w">球面墨卡托投影</option> </select> <select v-model="selectedMapType" @change="switchMapType"> <option v-for="option in mapOptions" :value="option.value" :key="option.value"> {{ option.label }} </option> </select> <select v-model="networkType" @change="switchNetworkType"> <option value="internal">内网地图</option> <option value="external">外网地图</option> </select> </template> <script setup> import { ref, onMounted } from 'vue'; import * as Cesium from 'cesium'; import "cesium/Build/Cesium/Widgets/widgets.css"; // 天地图服务密钥 const TIANDITU_TOKEN = '72d487f15710ca558987b9baaba13736'; // 当前时间和星期 const currentTime = ref(""); const currentWeek = ref(""); const weekMap = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; const updateTime = () => { const now = new Date(); currentTime.value = now.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-').replace(/(\d{4})-(\d{2})-(\d{2})/, '$ 1年$ 2月$ 3日'); currentWeek.value = weekMap[now.getDay()]; }; setInterval(updateTime, 1000); updateTime(); // 网络类型选择 const networkType = ref('external'); // 默认外网 // 地图类型选择 const selectedMapType = ref('img_c'); // 默认显示影像+注记 // 投影类型选择 const projectionType = ref('c'); // 默认经纬度投影 // 地图选项配置 const mapOptions = ref([ { value: 'img_c', label: '影像+注记' }, { value: 'vec_c', label: '矢量+注记' } ]); // Cesium相关变量 let viewer = null; let tiandituLayers = { baseLayer: null, annotationLayer: null }; // 网络类型切换 const switchNetworkType = () => { // 重置投影类型为默认值 projectionType.value = 'c'; // 根据网络类型更新地图选项 if (networkType.value === 'internal') { mapOptions.value = [ { value: 'img_c', label: '内网影像地图' }, { value: 'vec_c', label: '内网矢量地图' } ]; // 设置内网默认地图类型 selectedMapType.value = 'img_c'; } else { mapOptions.value = [ { value: 'img', label: '天地图影像' }, { value: 'img_c', label: '影像+注记' }, { value: 'vec', label: '矢量地图' }, { value: 'vec_c', label: '矢量+注记' }, { value: 'ter', label: '地形图' } ]; // 设置外网默认地图类型 selectedMapType.value = 'img_c'; } // 重新加载地图 loadMapService(selectedMapType.value); // 重新加载石河子数据并定位 loadShiheziVector(viewer, projectionType.value); setTimeout(flyToShihezi, 500); }; // 地图类型切换 const switchMapType = () => { if (viewer) { loadMapService(selectedMapType.value); } }; // // 投影类型切换 // const switchProjectionType = () => { // if (viewer && networkType.value === 'external') { // loadMapService(selectedMapType.value); // } // }; // 加载地图服务 const loadMapService = (type) => { if (!viewer || !viewer.imageryLayers) return; // 清除现有图层 if (tiandituLayers.baseLayer) viewer.imageryLayers.remove(tiandituLayers.baseLayer); if (tiandituLayers.annotationLayer) viewer.imageryLayers.remove(tiandituLayers.annotationLayer); if (networkType.value === 'internal') { // 内网地图服务 - 只支持c投影 const baseUrl = "http://59.255.48.160:81"; if (type === 'img_c') { // 内网影像地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: ${baseUrl}/img_c/wmts, layer: "img", style: "default", tileMatrixSetID: "c", format: "tiles", credit: new Cesium.Credit("内网影像地图"), maximumLevel: 18 }) ); } else if (type === 'vec_c') { // 内网矢量地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: ${baseUrl}/vec_c/wmts, layer: "vec", style: "default", tileMatrixSetID: "c", format: "tiles", credit: new Cesium.Credit("内网矢量地图"), maximumLevel: 18 }) ); } } else { // 外网天地图服务 - 支持c和w投影 // 根据投影类型动态构建URL const baseUrlTemplate = https://t{s}.tianditu.gov.cn/{layer}_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}; // 图层配置映射表 - 根据投影类型调整图层名称 const layerConfigs = { img: { layer: "img", credit: "天地图影像" }, img_c: { baseLayer: { layer: "img", credit: "天地图影像" }, annotationLayer: { layer: projectionType.value === 'c' ? "cia" : "cia_w", credit: "天地图注记" } }, vec: { layer: "vec", credit: "天地图矢量" }, vec_c: { baseLayer: { layer: "vec", credit: "天地图矢量" }, annotationLayer: { layer: projectionType.value === 'c' ? "cva" : "cva_w", credit: "天地图注记" } }, ter: { layer: "ter", credit: "天地图地形" } }; const config = layerConfigs[type]; if (!config) return; // 添加基础图层 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.layer || config.baseLayer.layer), layer: config.layer || config.baseLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.credit || config.baseLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); // 添加注记图层(如果需要) if (config.annotationLayer) { tiandituLayers.annotationLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.annotationLayer.layer), layer: config.annotationLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.annotationLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); } } }; // // 加载株洲矢量数据 // const loadZhuzhouVector = async (viewer) => { // try { // // 加载株洲市整体边界 // const cityDataSource = await Cesium.GeoJsonDataSource.load( // "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=430200", // { // clampToGround: true, // stroke: Cesium.Color.GREEN.withAlpha(0.8), // strokeWidth: 2, // fill: Cesium.Color.WHITE.withAlpha(0.3) // } // ); // viewer.dataSources.add(cityDataSource); // // 加载株洲各区县边界 // const countyDataSource = await Cesium.GeoJsonDataSource.load( // "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=430200_full", // { // clampToGround: true, // stroke: Cesium.Color.WHITE, // strokeWidth: 1, // fill: Cesium.Color.TRANSPARENT // } // ); // viewer.dataSources.add(countyDataSource); // // 添加区县标签 // countyDataSource.entities.values.forEach(entity => { // if (entity.polygon && entity.properties && entity.properties.name) { // const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()); // const center = Cesium.BoundingSphere.fromPoints(hierarchy.positions).center; // entity.label = { // text: entity.properties.name, // font: '18px 黑体', // fillColor: Cesium.Color.WHITE, // outlineColor: Cesium.Color.BLACK, // outlineWidth: 3, // style: Cesium.LabelStyle.FILL_AND_OUTLINE, // verticalOrigin: Cesium.VerticalOrigin.CENTER, // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // pixelOffset: new Cesium.Cartesian2(0, 0), // disableDepthTestDistance: Number.POSITIVE_INFINITY, // scaleByDistance: new Cesium.NearFarScalar(1e3, 1.0, 1e6, 0.5) // }; // entity.position = center; // } // }); // // 定位到株洲范围 // const rectangle = Cesium.Rectangle.fromDegrees(113.50, 24.94, 113.60, 26.84); // viewer.camera.flyTo({ // destination: rectangle, // orientation: { // heading: Cesium.Math.toRadians(0), // pitch: Cesium.Math.toRadians(-70), // roll: 0 // }, // duration: 2 // }); // } catch (error) { // console.error("加载株洲数据失败:", error); // const chinaRectangle = Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0); // viewer.camera.flyTo({ // destination: chinaRectangle // }); // } // }; // 修改加载石河子矢量数据 // 保存石河子范围矩形 const shiheziRectangle = ref(null); // 加载石河子矢量数据(新增函数) const loadShiheziVector = async (viewer, projectionType = 'c') => { try { // 清除现有石河子数据 const dataSources = viewer.dataSources; for (let i = dataSources.length - 1; i >= 0; i--) { if (dataSources.get(i).name === 'shihezi') { dataSources.remove(dataSources.get(i)); } } // 加载石河子市整体边界 const cityDataSource = await Cesium.GeoJsonDataSource.load( "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=659001", { clampToGround: true, stroke: Cesium.Color.GREEN.withAlpha(0.8), strokeWidth: 2, fill: Cesium.Color.WHITE.withAlpha(0.3), name: 'shihezi' // 添加标识 } ); viewer.dataSources.add(cityDataSource); // 添加石河子市标签 cityDataSource.entities.values.forEach(entity => { if (entity.polygon && entity.properties && entity.properties.name) { const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()); const positions = hierarchy.positions; // 根据投影类型转换坐标 let center; if (projectionType === 'c') { // 经纬度投影直接使用地理中心 center = Cesium.BoundingSphere.fromPoints(positions).center; } else { // 墨卡托投影需要转换坐标 const cartographicPositions = positions.map(pos => Cesium.Cartographic.fromCartesian(pos) ); // 计算平均经纬度 const avgLon = cartographicPositions.reduce((sum, pos) => sum + pos.longitude, 0) / cartographicPositions.length; const avgLat = cartographicPositions.reduce((sum, pos) => sum + pos.latitude, 0) / cartographicPositions.length; // 转换为墨卡托坐标 center = Cesium.Cartesian3.fromDegrees( Cesium.Math.toDegrees(avgLon), Cesium.Math.toDegrees(avgLat) ); } entity.label = { text: "石河子市", font: '18px 黑体', fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 3, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(0, 0), disableDepthTestDistance: Number.POSITIVE_INFINITY, scaleByDistance: new Cesium.NearFarScalar(1e3, 1.0, 1e6, 0.5) }; entity.position = center; } }); // 保存石河子范围 const positions = cityDataSource.entities.values[0].polygon.hierarchy.getValue().positions; const cartographicPositions = positions.map(pos => Cesium.Cartographic.fromCartesian(pos) ); const minLon = Math.min(...cartographicPositions.map(p => p.longitude)); const maxLon = Math.max(...cartographicPositions.map(p => p.longitude)); const minLat = Math.min(...cartographicPositions.map(p => p.latitude)); const maxLat = Math.max(...cartographicPositions.map(p => p.latitude)); shiheziRectangle.value = new Cesium.Rectangle( minLon, minLat, maxLon, maxLat ); } catch (error) { console.error("加载石河子数据失败:", error); } }; // 定位到石河子(新增函数) const flyToShihezi = () => { if (viewer && shiheziRectangle.value) { viewer.camera.flyTo({ destination: shiheziRectangle.value, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-70), roll: 0 }, duration: 1 }); } }; // 投影类型切换 const switchProjectionType = () => { if (viewer && networkType.value === 'external') { loadMapService(selectedMapType.value); // 重新加载石河子数据并定位 loadShiheziVector(viewer, projectionType.value); setTimeout(flyToShihezi, 500); } }; onMounted(async () => { try { // 设置Cesium Ion访问令牌 Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE'; // 初始化Cesium Viewer viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, timeline: false, animation: false, geocoder: false, sceneModePicker: false, navigationHelpButton: false, homeButton: false, selectionIndicator: false, infoBox: false, navigationInstructionsInitiallyVisible: false, scene3DOnly: true, terrainProvider: new Cesium.EllipsoidTerrainProvider(), imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: https://t{s}.tianditu.gov.cn/img_w/wmts?tk=${TIANDITU_TOKEN}, layer: "img", style: "default", tileMatrixSetID: "w", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) }); // 强制设置中国视角 viewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0) }); // // 加载株洲数据 // loadZhuzhouVector(viewer); // 加载石河子数据(修改为调用新函数) await loadShiheziVector(viewer); flyToShihezi(); // 加载地图服务 loadMapService(selectedMapType.value); } catch (error) { console.error("初始化失败:", error); } }); </script> <style scoped> /* 基础样式 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Microsoft YaHei", sans-serif; } .monitor-container { width: 100vw; height: 100vh; background: radial-gradient(circle at center, #0c2a50 0%, #0a1a35 100%); overflow: hidden; position: fixed; top: 0; left: 0; display: flex; flex-direction: column; } /* 顶部导航栏样式 - 重新布局 */ .top-bar { height: 70px; background: linear-gradient(90deg, #0a1a35 0%, #1a3a6e 50%, #0a1a35 100%); display: flex; align-items: center; justify-content: space-between; padding: 0 15px; position: relative; z-index: 100; border-bottom: 1px solid rgba(0, 150, 255, 0.3); } /* 左侧区域 */ .left-section { display: flex; align-items: center; flex: 0 0 auto; } /* 中间区域 */ .center-section { flex: 1 1 auto; display: flex; justify-content: center; } /* 右侧区域 */ .right-section { display: flex; align-items: center; flex: 0 0 auto; gap: 10px; } /* 控件组 */ .controls-group { display: flex; gap: 10px; } /* 天气模块 */ .weather-module { display: flex; align-items: center; color: white; font-size: 14px; min-width: 120px; justify-content: center; } .weather-icon { color: #ffcc00; margin-right: 8px; font-size: 16px; } /* 梯形标题样式 */ .platform-title { position: relative; z-index: 10; max-width: 500px; /* 限制最大宽度 */ } .trapezoid-bg { position: relative; padding: 0 40px; height: 70px; display: flex; align-items: center; } .trapezoid-bg::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 60, 113, 0.6); clip-path: polygon(0% 0%, 100% 0%, 90% 100%, 10% 100%); z-index: -1; } .platform-title h1 { font-size: 24px; font-weight: bold; background: linear-gradient(to bottom, #a2e7eb, #00f2fe); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 8px rgba(0, 242, 254, 0.3); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: 100%; } /* 时间模块 */ .time-module { color: white; font-size: 14px; min-width: 220px; text-align: center; white-space: nowrap; } /* 所有控件统一样式 */ .network-switcher select, .map-switcher select, .projection-switcher select { background: rgba(10, 26, 53, 0.8); color: #66ffff; border: 1px solid rgba(0, 150, 255, 0.5); border-radius: 4px; padding: 6px 12px; font-size: 14px; outline: none; cursor: pointer; box-shadow: 0 0 8px rgba(0, 150, 255, 0.3); transition: all 0.3s ease; min-width: 120px; } .network-switcher select:hover, .map-switcher select:hover, .projection-switcher select:hover { background: rgba(26, 58, 110, 0.8); border-color: #00f2fe; box-shadow: 0 0 12px rgba(0, 242, 254, 0.5); } .network-switcher select:focus, .map-switcher select:focus, .projection-switcher select:focus { border-color: #00f2fe; } /* Cesium容器 */ #cesiumContainer { width: 100%; height: calc(100vh - 70px); background-color: #000; position: relative; } /* 响应式调整 */ @media (max-width: 1600px) { .platform-title h1 { font-size: 20px; } .weather-module, .time-module { font-size: 13px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 5px 10px; font-size: 13px; min-width: 110px; } } @media (max-width: 1400px) { .platform-title h1 { font-size: 18px; } .trapezoid-bg { padding: 0 30px; } .time-module { min-width: 180px; } .controls-group { gap: 8px; } } @media (max-width: 1200px) { .platform-title h1 { font-size: 16px; } .trapezoid-bg { padding: 0 20px; } .time-module { min-width: 160px; font-size: 12px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 8px; font-size: 12px; min-width: 100px; } } @media (max-width: 992px) { .time-module { display: none; } .platform-title h1 { font-size: 14px; } .trapezoid-bg { padding: 0 15px; } .weather-module { min-width: auto; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 6px; font-size: 11px; min-width: 90px; } } @media (max-width: 768px) { .weather-module { display: none; } .platform-title h1 { font-size: 12px; } .trapezoid-bg { padding: 0 10px; } .controls-group { gap: 5px; } .network-switcher select, .map-switcher select, .projection-switcher select { min-width: 80px; } } </style> 检查代码,还是有问题,切换到经纬度投影时石河子位置还是不对,没有切换

<template> </template> <script setup lang="ts"> import { ref, onMounted, onUnmounted } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 株洲市范围定义 const ZHUZHOU_EXTENT = { west: 112.5, east: 114.5, south: 26.0, north: 28.0 }; // 地图容器引用 const cesiumContainer = ref<HTMLDivElement | null>(null); const miniMapContainer = ref<HTMLElement | null>(null); // 地图实例 let viewer: Cesium.Viewer | null = null; let overviewViewer: Cesium.Viewer | null = null; // 位置指示器样式 const indicatorStyle = ref({ left: '50%', top: '50%', display: 'block' }); // 创建主地图 const initMainMap = () => { if (!cesiumContainer.value) return; try { // 使用ArcGIS世界影像服务 const imageryProvider = new Cesium.ArcGisMapServerImageryProvider({ url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' }); // 初始化主地图 viewer = new Cesium.Viewer(cesiumContainer.value, { baseLayerPicker: false, animation: false, timeline: false, navigationHelpButton: false, fullscreenButton: false, geocoder: false, homeButton: false, sceneModePicker: false, skyBox: false, skyAtmosphere: false, infoBox: false, selectionIndicator: false, terrainProvider: new Cesium.EllipsoidTerrainProvider(), sceneMode: Cesium.SceneMode.SCENE3D, }); // 隐藏版权信息 viewer.cesiumWidget.creditContainer.style.display = "none"; // 设置初始视角到株洲市 viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(113.13, 27.83, 5000), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0.0 } }); console.log("主地图初始化完成"); } catch (error) { console.error("主地图初始化失败:", error); } }; // 初始化鹰眼地图 const initMiniMap = () => { if (!miniMapContainer.value) return; try { // 鹰眼地图使用相同的影像源 const imageryProvider = new Cesium.ArcGisMapServerImageryProvider({ url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' }); // 初始化鹰眼地图 overviewViewer = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, mapProjection: new Cesium.WebMercatorProjection(), skyBox: false, skyAtmosphere: false }); // 设置鹰眼地图视图为株洲范围 overviewViewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ) }); // 隐藏UI元素 const toolbar = overviewViewer.container.getElementsByClassName( "cesium-viewer-toolbar" )[0]; if (toolbar) toolbar.style.display = "none"; overviewViewer.cesiumWidget.creditContainer.style.display = "none"; console.log("鹰眼地图初始化完成"); } catch (error) { console.error("鹰眼地图初始化失败:", error); } }; // 更新位置指示器 const updateIndicatorPosition = () => { if (!viewer) return; const camera = viewer.camera; const rect = camera.computeViewRectangle(); if (!rect) return; const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); // 确保在株洲范围内 const constrainedLon = Math.max( ZHUZHOU_EXTENT.west, Math.min(ZHUZHOU_EXTENT.east, lon) ); const constrainedLat = Math.max( ZHUZHOU_EXTENT.south, Math.min(ZHUZHOU_EXTENT.north, lat) ); // 计算位置百分比 const lonPercent = ((constrainedLon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((constrainedLat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; indicatorStyle.value = { left: ${lonPercent}%, top: ${latPercent}%, display: "block" }; }; // 监听主地图相机变化 const setupCameraListener = () => { if (!viewer) return; viewer.camera.changed.addEventListener(updateIndicatorPosition); }; // 鹰眼地图点击处理 const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer || !viewer) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; // 计算点击位置对应的经纬度 const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); // 飞向点击位置 viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 5000), duration: 1 }); }; // 组件挂载时初始化 onMounted(() => { initMainMap(); setTimeout(() => { initMiniMap(); setupCameraListener(); updateIndicatorPosition(); }, 1000); }); // 组件卸载时清理 onUnmounted(() => { if (viewer && !viewer.isDestroyed()) { viewer.destroy(); } if (overviewViewer && !overviewViewer.isDestroyed()) { overviewViewer.destroy(); } }); </script> <style scoped> /* 主地图容器样式 */ #cesium-container { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; background: #000; } /* 鹰眼地图样式 */ .mini-map { position: absolute; right: 20px; bottom: 20px; width: 200px; height: 150px; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } /* 位置指示器样式 */ .location-indicator { position: absolute; width: 14px; height: 14px; background: #ff3e3e; border: 2px solid white; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 15px rgba(255, 62, 62, 1); z-index: 100; } /* 隐藏版权信息 */ :deep(.cesium-widget) { background-color: #000 !important; } :deep(.cesium-widget-credits), :deep(.cesium-credit-textContainer), :deep(.cesium-credit-expand-link) { display: none !important; visibility: hidden !important; } </style> 好的现在初始功能有了,现在借鉴他的株洲市影像瓦片,再主地图与鹰眼地图都加载,基于此修改上述代码发我

runtime-core.esm-bundler.js:51 [Vue warn]: Unhandled error during execution of mounted hook at <Map> at <App> warn$1 @ runtime-core.esm-bundler.js:51 Map.vue:33 Uncaught TypeError: Cesium.createWorldTerrain is not a function at Map.vue:33:29 at runtime-core.esm-bundler.js:2836:40 at callWithErrorHandling (runtime-core.esm-bundler.js:199:19) at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:206:17) at hook.__weh.hook.__weh (runtime-core.esm-bundler.js:2816:19) at flushPostFlushCbs (runtime-core.esm-bundler.js:385:28) at render2 (runtime-core.esm-bundler.js:6048:7) at mount (runtime-core.esm-bundler.js:3962:13) at app.mount (runtime-dom.esm-bundler.js:1775:19) at main.ts:9:5 如上所示报错修改下面代码: <template> </template> <script setup lang="ts"> import { ref, onMounted, onUnmounted } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // Cesium访问令牌 - 请替换成自己的有效令牌 Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE'; const cesiumContainer = ref<HTMLDivElement | null>(null); let viewer: Cesium.Viewer | null = null; onMounted(() => { if (!cesiumContainer.value) return; // 初始化Cesium地球 viewer = new Cesium.Viewer(cesiumContainer.value, { animation: false, baseLayerPicker: false, fullscreenButton: false, vrButton: false, geocoder: false, homeButton: false, infoBox: false, sceneModePicker: false, selectionIndicator: false, timeline: false, navigationHelpButton: false, navigationInstructionsInitiallyVisible: false, terrainProvider: Cesium.createWorldTerrain(), imageryProvider: new Cesium.ArcGisMapServerImageryProvider({ url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' }) }); // 设置初始视图位置(株洲市) viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.13, 27.83, 10000000), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0.0 }, duration: 2 }); }); onUnmounted(() => { if (viewer) { viewer.destroy(); viewer = null; } }); </script> <style scoped> #cesium-container { position: absolute; top: 0; left: 0; height: 100%; width: 100%; margin: 0; padding: 0; overflow: hidden; } /* 覆盖Cesium默认的logo */ :deep(.cesium-viewer-bottom) { display: none !important; } </style> 注意我的cesium是最新版的

<template> 坐标系: <el-radio-group v-model="coordinateSystem" size="small"> <el-radio-button label="gcj02">高德/火星坐标</el-radio-button> <el-radio-button label="bd09">百度坐标</el-radio-button> </el-radio-group> <Search @location-selected="handleLocationSelected" /> <LocationBar v-if="loaded" :update-interval="100" :use-dms-format="useDmsFormat" /> </template> <style> /* 原有样式完全不变 */ </style> <script setup lang="ts"> // 原有导入 + 新增坐标转换工具类导入 import { computed, onUnmounted, onMounted, reactive, ref } from "vue"; import LocationBar from "./location-bar.vue"; import Search from "./search.vue"; import initMap from "./init"; import { throttle } from "lodash"; import { loadRipplePoints, createMultipleRippleCircles } from "./circle.js"; import { $prototype } from "../../main.ts"; import markerImage from "@/assets/images/building.png"; import { imageDark } from "naive-ui/es/image/styles"; // 新增:导入坐标转换工具类 import { CoordinateTransformer } from "./coordinate-transformer"; // 修复类型定义 type Rectangle = any; // 原有状态 + 新增坐标系选择状态 const miniMapContainer = ref<HTMLElement>(); let viewIndicator: Rectangle; const currentPosition = reactive({ longitude: 113.361538, latitude: 27.339318, }); const ZHUZHOU_EXTENT = { west: 112.5, east: 114.5, south: 26.0, north: 28.0, }; const rippleEntities = ref<any[]>([]); const heightThreshold = 80000; const indicatorStyle = ref({ left: "50%", top: "50%", display: "block", }); const loaded = ref(false); const useDmsFormat = ref(false); const overviewViewer = ref(null); let currentMarker: any = null; // 新增:坐标系选择状态(默认高德GCJ-02) const coordinateSystem = ref("gcj02"); // 'gcj02' | 'bd09' // 原有方法完全不变(波纹可见性更新) const updateRippleVisibility = throttle(() => { if (!$prototype.$map || rippleEntities.value.length === 0) return; let shouldShow = false; const cartographic = $prototype.$map.camera.positionCartographic; if (cartographic) { const cameraHeight = cartographic.height; shouldShow = cameraHeight > heightThreshold; } rippleEntities.value.forEach((entity) => { //entity.show = shouldShow; entity.show = false; }); }, 200); // 原有方法完全不变(指示器位置更新) const updateIndicatorPosition = () => { if (!$prototype.$map) return; const camera = $prototype.$map.camera; const rect = camera.computeViewRectangle(); if (!rect) return; const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); const constrainedLon = Math.max( ZHUZHOU_EXTENT.west, Math.min(ZHUZHOU_EXTENT.east, lon) ); const constrainedLat = Math.max( ZHUZHOU_EXTENT.south, Math.min(ZHUZHOU_EXTENT.north, lat) ); const lonPercent = ((constrainedLon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((constrainedLat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; indicatorStyle.value = { left: ${lonPercent}%, top: ${latPercent}%, display: "block", }; }; // 原有方法完全不变(鹰眼地图更新) const updateOverview = () => { if (!$prototype.$map || !overviewViewer.value) return; const rectangle = $prototype.$map.camera.computeViewRectangle(); if (!rectangle) return; updateIndicatorPosition(); // 添加视口矩形更新逻辑 if (viewIndicator) { viewIndicator.rectangle.coordinates = rectangle; } }; // 原有方法完全不变(初始化鹰眼地图) const initMiniMap = () => { Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDhlNDdmYy03NzFhLTQ1ZTQtOWQ3NS1lZDAzNDc3YjE4NDYiLCJpZCI6MzAxNzQyLCJpYXQiOjE3NDcwNTMyMDN9.eaez8rQxVbPv2LKEU0sMDclPWyHKhh1tR27Vg-_rQSM"; if (!miniMapContainer.value) return; const worldProvider = new Cesium.UrlTemplateImageryProvider({ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", minimumLevel: 0, maximumLevel: 19, tilingScheme: new Cesium.WebMercatorTilingScheme(), }); const zhuzhouProvider = new Cesium.UrlTemplateImageryProvider({ url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, tilingScheme: new Cesium.WebMercatorTilingScheme(), }); overviewViewer.value = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, imageryProvider: worldProvider, terrainProvider: undefined, mapProjection: new Cesium.WebMercatorProjection(), skyBox: false, skyAtmosphere: false, }); // 禁用所有相机交互控制(新增功能代码) const cameraController = overviewViewer.value.scene.screenSpaceCameraController; cameraController.enableTranslate = false; cameraController.enableZoom = false; cameraController.enableRotate = false; cameraController.enableTilt = false; cameraController.enableLook = false; const zhuzhouLayer = overviewViewer.value.imageryLayers.addImageryProvider( zhuzhouProvider ); overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ), }); const toolbar = overviewViewer.value.container.getElementsByClassName( "cesium-viewer-toolbar" )[0]; if (toolbar) toolbar.style.display = "none"; overviewViewer.value.cesiumWidget.creditContainer.style.display = "none"; initRectangle(); }; // 原有方法完全不变(初始化视图指示器) function initRectangle() { viewIndicator = overviewViewer.value.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ), material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED, outlineWidth: 2, }, }); } // 原有方法完全不变(添加演示图形) function addDemoGraphics() { const chinaBoundary = $prototype.$map.dataSources.add( Cesium.GeoJsonDataSource.load("/shp_zz.geojson", { stroke: Cesium.Color.WHITE, fill: false, clampToGround: true, describe: null, }) ); chinaBoundary.then((dataSource) => { const entities = dataSource.entities.values; for (let entity of entities) { if (entity.polyline) { entity.polyline.fill = false; } } }); } // 原有方法完全不变(飞行到默认位置) function flyToDes() { const center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0); $prototype.$map.camera.flyTo({ destination: new Cesium.Cartesian3( -2432812.6687511606, 5559483.804371395, 2832009.419525571 ), orientation: { heading: 6.283185307179421, pitch: -1.0472145569408116, roll: 6.2831853071795205, }, complete: function () {}, }); } // 原有方法完全不变(监听相机变化) const setupCameraListener = () => { $prototype.$map.camera.changed.addEventListener(updateOverview); }; // 原有方法完全不变(鹰眼地图点击处理) const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer.value) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); $prototype.$map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000000), }); }; // 原有生命周期方法完全不变 onMounted(() => { initMap(); loaded.value = true; addDemoGraphics(); flyToDes(); setTimeout(() => { initMiniMap(); setupCameraListener(); updateOverview(); }, 1000); (async () => { try { const ripplePoints = await loadRipplePoints(); rippleEntities.value = createMultipleRippleCircles($prototype.$map, ripplePoints); $prototype.$map.camera.changed.addEventListener(updateRippleVisibility); updateRippleVisibility(); } catch (error) { console.error("加载波纹圆失败:", error); } })(); }); // 原有方法完全不变(创建标记) const createMarker = (wgsLocation) => { if (currentMarker) { $prototype.$map.entities.remove(currentMarker); } console.log("标记图片加载状态:", markerImage); console.log("创建标记位置:", wgsLocation); currentMarker = $prototype.$map.entities.add({ position: Cesium.Cartesian3.fromDegrees(wgsLocation.lng, wgsLocation.lat, 10), label: { text: wgsLocation.name + "(标记位置)", font: "18px sans-serif", fillColor: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, verticalOrigin: Cesium.VerticalOrigin.TOP, pixelOffset: new Cesium.Cartesian2(0, 20), heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, show: true, }, // 关键:用 billboard 替换 point billboard: { image: new URL("@/assets/images/building.png", import.meta.url).href, // 本地图标 width: 32, // 图标宽度(像素) height: 32, // 图标高度(像素) verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 让图标尖点对地 heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, scale: 1.0, }, }); console.log("标记实体已添加:", currentMarker); $prototype.$map.scene.requestRender(); return currentMarker; }; // 核心修改:使用工具类实现动态坐标系转换 const handleLocationSelected = (location: { lng: number; lat: number; name: string }) => { if (!$prototype.$map) return; // 根据选择的坐标系进行转换 let wgsLocation; if (coordinateSystem.value === "gcj02") { // 高德/火星坐标转WGS84 wgsLocation = CoordinateTransformer.gcj02ToWgs84(location.lng, location.lat); } else { // 百度坐标转WGS84 wgsLocation = CoordinateTransformer.bd09ToWgs84(location.lng, location.lat); } console.log(转换前(${coordinateSystem.value})坐标:, location.lng, location.lat); console.log("转换后(WGS84)坐标:", wgsLocation.lng, wgsLocation.lat); // 使用转换后的坐标执行原有逻辑 const destination = Cesium.Cartesian3.fromDegrees( wgsLocation.lng, wgsLocation.lat, 3000 ); $prototype.$map.camera.flyTo({ destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }, duration: 2, complete: () => { createMarker({ ...location, ...wgsLocation }); }, }); }; // 原有方法完全不变(组件销毁清理) onUnmounted(() => { if ($prototype.$map) { $prototype.$map.destroy(); $prototype.$map = null; } if ($prototype.$map) { $prototype.$map.camera.changed.removeEventListener(updateRippleVisibility); } console.log("组件销毁"); }); const emit = defineEmits(["onload", "onclick"]); const initMars3d = async (option: any) => { emit("onclick", true); emit("onload", $prototype.$map); }; </script> <style lang="less"> /**cesium 工具按钮栏*/ .cesium-viewer-toolbar { top: auto !important; bottom: 35px !important; left: 12px !important; right: auto !important; } .cesium-toolbar-button img { height: 100%; } .cesium-viewer-toolbar > .cesium-toolbar-button, .cesium-navigationHelpButton-wrapper, .cesium-viewer-geocoderContainer { margin-bottom: 5px; float: left; clear: both; text-align: center; } .cesium-button { background-color: rgba(23, 49, 71, 0.8); color: #e6e6e6; fill: #e6e6e6; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); line-height: 32px; } .cesium-button:hover { background: #3ea6ff; } /**cesium 底图切换面板*/ .cesium-baseLayerPicker-dropDown { bottom: 0; left: 40px; max-height: 700px; margin-bottom: 5px; background-color: rgba(23, 49, 71, 0.8); } /**cesium 帮助面板*/ .cesium-navigation-help { top: auto; bottom: 0; left: 40px; transform-origin: left bottom; background: none; background-color: rgba(23, 49, 71, 0.8); .cesium-navigation-help-instructions { background: none; } .cesium-navigation-button { background: none; } .cesium-navigation-button-selected, .cesium-navigation-button-unselected:hover { background: rgba(0, 138, 255, 0.2); } } /**cesium 二维三维切换*/ .cesium-sceneModePicker-wrapper { width: auto; } .cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon { float: right; margin: 0 3px; } /**cesium POI查询输入框*/ .cesium-viewer-geocoderContainer .search-results { left: 0; right: 40px; width: auto; z-index: 9999; } .cesium-geocoder-searchButton { background-color: rgba(23, 49, 71, 0.8); } .cesium-viewer-geocoderContainer .cesium-geocoder-input { background-color: rgba(63, 72, 84, 0.7); } .cesium-viewer-geocoderContainer .cesium-geocoder-input:focus { background-color: rgba(63, 72, 84, 0.9); } .cesium-viewer-geocoderContainer .search-results { background-color: rgba(23, 49, 71, 0.8); } /**cesium info信息框*/ .cesium-infoBox { top: 50px; background-color: rgba(23, 49, 71, 0.8); } .cesium-infoBox-title { background-color: rgba(23, 49, 71, 0.8); } /**cesium 任务栏的FPS信息*/ .cesium-performanceDisplay-defaultContainer { top: auto; bottom: 35px; right: 50px; } .cesium-performanceDisplay-ms, .cesium-performanceDisplay-fps { color: #fff; } /**cesium tileset调试信息面板*/ .cesium-viewer-cesiumInspectorContainer { top: 10px; left: 10px; right: auto; } .cesium-cesiumInspector { background-color: rgba(23, 49, 71, 0.8); } /**覆盖mars3d内部控件的颜色等样式*/ .mars3d-compass .mars3d-compass-outer { fill: rgba(23, 49, 71, 0.8); } .mars3d-contextmenu-ul, .mars3d-sub-menu { background-color: rgba(23, 49, 71, 0.8); > li > a:hover, > li > a:focus, > li > .active { background-color: #3ea6ff; } > .active > a, > .active > a:hover, > .active > a:focus { background-color: #3ea6ff; } } /* Popup样式*/ .mars3d-popup-color { color: #ffffff; } .mars3d-popup-background { background: rgba(23, 49, 71, 0.8); } .mars3d-popup-content { margin: 15px; } .mars3d-template-content label { padding-right: 6px; } .mars3d-template-titile { border-bottom: 1px solid #3ea6ff; } .mars3d-template-titile a { font-size: 16px; } .mars3d-tooltip { background: rgba(23, 49, 71, 0.8); border: 1px solid rgba(23, 49, 71, 0.8); } .mars3d-popup-btn-custom { padding: 3px 10px; border: 1px solid #209ffd; background: #209ffd1c; } .mars-dialog .mars-dialog__content { height: 100%; width: 100%; overflow: auto; padding: 5px; } .image { border: solid 2px #fff; } .content { height: 90%; padding-top: 10px; overflow-x: auto; overflow-y: auto; } .content-text { padding: 0 10px; text-indent: 30px; font-size: 17px; } .details-video { width: 100%; height: 760px; background-color: #000; } :where(.css-lt97qq9).ant-space { display: inline-flex; } :where(.css-lt97qq9).ant-space-align-center { align-items: center; } :where(.css-lt97qq9).ant-image .ant-image-mask { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(0, 0, 0, 0.5); cursor: pointer; opacity: 0; transition: opacity 0.3s; } :where(.css-lt97qq9).ant-image .ant-image-mask .ant-image-mask-info { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 4px; } :where(.css-1t97qq9)[class^="ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class^="ant-image"] [class*=" ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class*=" ant-image"] { box-sizing: border-box; } :where(.css-lt97qq9).ant-image .ant-image-img { width: 100%; height: auto; vertical-align: middle; } </style> <style scoped> .mini-map-container { position: relative; width: 100%; height: 100%; } .main-viewer { width: 100%; height: 100%; } .mini-map { position: absolute; right: 3vw; bottom: 6vh; width: 12vw; height: 17vh; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } .location-indicator { position: absolute; width: 19px; height: 19px; transform: translate(-50%, -50%); z-index: 100; /* border: 2px solid red; border-radius: 2px; */ } /* 原十字准星伪元素保持不变 */ .location-indicator::before, .location-indicator::after { content: ""; position: absolute; background-color: red; top: 50%; left: 50%; transform: translate(-50%, -50%); } .location-indicator::before { width: 14px; height: 2px; } .location-indicator::after { width: 2px; height: 14px; } .view-rectangle { position: absolute; border: 2px solid #00f2fe; z-index: 99; pointer-events: none; box-shadow: 0 0 20px rgba(0, 242, 254, 0.7); } /* 相机聚焦样式 - 四个角折角 */ .corner { position: absolute; width: 25px; height: 25px; z-index: 100; pointer-events: none; } .corner::before, .corner::after { content: ""; position: absolute; background: #00f2fe; box-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .corner-top-left { top: -2px; left: -2px; } .corner-top-left::before { top: 0; left: 0; width: 15px; height: 3px; } .corner-top-left::after { top: 0; left: 0; width: 3px; height: 15px; } .corner-top-right { top: -2px; right: -2px; } .corner-top-right::before { top: 0; right: 0; width: 15px; height: 3px; } .corner-top-right::after { top: 0; right: 0; width: 3px; height: 15px; } .corner-bottom-left { bottom: -2px; left: -2px; } .corner-bottom-left::before { bottom: 0; left: 0; width: 15px; height: 3px; } .corner-bottom-left::after { bottom: 0; left: 0; width: 3px; height: 15px; } .corner-bottom-right { bottom: -2px; right: -2px; } .corner-bottom-right::before { bottom: 0; right: 0; width: 15px; height: 3px; } .corner-bottom-right::after { bottom: 0; right: 0; width: 3px; height: 15px; } .camera-icon { position: absolute; top: 10px; right: 10px; color: #00f2fe; font-size: 24px; z-index: 100; text-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .focus-effect { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 98; border: 2px solid rgba(0, 242, 254, 0.2); border-radius: 5px; box-shadow: inset 0 0 30px rgba(0, 242, 254, 0.1); } .pulse { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; border-radius: 50%; background: rgba(0, 242, 254, 0.7); box-shadow: 0 0 0 0 rgba(0, 242, 254, 0.7); animation: pulse 2s infinite; } ::v-deep.cesium-viewer-toolbar { display: none; } </style> 检查live-map代码,其中为什么这个红色十字定位位置会不对,会呆在左上方,虽然移动后会变正确,但是刷新页面显示时就是有时候会不对,会影响观感,你阅读live-map.vue代码中鹰眼地图部分代码,尝试寻找原因修改,然后尽可能不更改其他任何无关代码,减少对代码的修改

<template> </template> <script setup lang="ts"> import { onMounted, onUnmounted, ref } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 株洲市范围常量 const ZHUZHOU_EXTENT = Cesium.Rectangle.fromDegrees( 112.5, // west 26.0, // south 114.5, // east 28.0 // north ); // 地图实例引用 const mainViewer = ref<Cesium.Viewer | null>(null); const overviewViewer = ref<Cesium.Viewer | null>(null); const rectangleEntity = ref<Cesium.Entity | null>(null); // 改用 Entity 替代 RectanglePrimitive // 初始化主地图 const initMainMap = async () => { try { // 设置Cesium访问令牌 - 替换为您的实际令牌 Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE"; // 创建主地图实例 mainViewer.value = new Cesium.Viewer('cesiumContainer', { sceneMode: Cesium.SceneMode.SCENE3D, animation: false, baseLayerPicker: false, fullscreenButton: true, geocoder: false, homeButton: true, infoBox: false, sceneModePicker: true, selectionIndicator: true, timeline: false, navigationHelpButton: false, shouldAnimate: true, // 修复地形创建方式 - 使用正确的API terrainProvider: Cesium.createWorldTerrain(), imageryProvider: new Cesium.UrlTemplateImageryProvider({ url: "http://124.232190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17 }) }); // 设置初始视图到株洲市范围 mainViewer.value.camera.flyTo({ destination: ZHUZHOU_EXTENT, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-30), roll: 0.0 }, duration: 2.0 }); // 添加错误处理 mainViewer.value.scene.globe.tileLoadProgressEvent.addEventListener((pending) => { if (pending === 0) { console.log('所有瓦片加载完成'); } }); mainViewer.value.scene.error.addEventListener((error) => { console.error('Cesium错误:', error); }); } catch (error) { console.error('初始化主地图失败:', error); } }; // 初始化鹰眼地图 const initOverviewMap = () => { try { // 创建鹰眼地图实例 overviewViewer.value = new Cesium.Viewer('overviewMap', { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, fullscreenButton: false, geocoder: false, homeButton: false, infoBox: false, sceneModePicker: false, selectionIndicator: false, timeline: false, navigationHelpButton: false, animation: false, imageryProvider: new Cesium.ArcGisMapServerImageryProvider({ url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer' }) }); // 隐藏不需要的控件 overviewViewer.value.cesiumWidget.creditContainer.style.display = "none"; // 设置鹰眼地图范围 - 使用 fromDegrees 简化 overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees(110.0, 24.0, 116.0, 30.0) }); // 添加株洲市范围指示器 - 使用 Entity 替代 RectanglePrimitive rectangleEntity.value = overviewViewer.value.entities.add({ name: '株洲市范围', rectangle: { coordinates: ZHUZHOU_EXTENT, material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED, outlineWidth: 2 } }); } catch (error) { console.error('初始化鹰眼地图失败:', error); } }; // 同步主地图和鹰眼地图 const syncMaps = () => { try { if (!mainViewer.value || !overviewViewer.value || !rectangleEntity.value) return; // 监听主地图相机变化 mainViewer.value.camera.changed.addEventListener(() => { const camera = mainViewer.value!.camera; // 计算当前视图范围 const rectangle = camera.computeViewRectangle(); if (rectangle) { // 更新鹰眼地图中的矩形 rectangleEntity.value!.rectangle!.coordinates = rectangle; // 更新鹰眼地图视角(如果矩形超出当前视图) const overviewCamera = overviewViewer.value!.camera; const overviewRectangle = overviewCamera.computeViewRectangle(); if (overviewRectangle && !Cesium.Rectangle.contains(overviewRectangle, rectangle)) { // 扩展矩形以包含当前视图 const expandedRect = new Cesium.Rectangle( Math.min(overviewRectangle.west, rectangle.west), Math.min(overviewRectangle.south, rectangle.south), Math.max(overviewRectangle.east, rectangle.east), Math.max(overviewRectangle.north, rectangle.north) ); overviewCamera.flyTo({ destination: expandedRect, duration: 0.5 }); } } }); // 鹰眼地图点击事件 overviewViewer.value.screenSpaceEventHandler.setInputAction((click: any) => { const position = click.position; const ray = overviewViewer.value!.camera.getPickRay(position); const cartesian = overviewViewer.value!.scene.globe.pick(ray, overviewViewer.value!.scene); if (cartesian) { // 主地图跳转到点击位置 mainViewer.value!.camera.flyTo({ destination: cartesian, orientation: { heading: mainViewer.value!.camera.heading, pitch: mainViewer.value!.camera.pitch, roll: 0.0 }, duration: 1.0 }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } catch (error) { console.error('地图同步失败:', error); } }; // 组件挂载时初始化地图 onMounted(() => { initMainMap(); initOverviewMap(); // 等待地图初始化完成后再同步 setTimeout(syncMaps, 1000); }); // 组件卸载时销毁地图实例 onUnmounted(() => { try { if (mainViewer.value) { mainViewer.value.destroy(); mainViewer.value = null; } if (overviewViewer.value) { overviewViewer.value.destroy(); overviewViewer.value = null; } } catch (error) { console.error('销毁地图实例失败:', error); } }); </script> <style> /* 全局重置样式 */ * { margin: 0; padding: 0; box-sizing: border-box; } html, body, #app { width: 100%; height: 100%; overflow: hidden; /* 防止滚动条 */ font-family: sans-serif; } </style> <style scoped> .map-container { /* 移除 position: relative 改为绝对定位 */ position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; background-color: #1e1e1e; /* 深色背景防止白色间隙 */ } .main-map { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; } .overview-map { position: absolute; bottom: 20px; right: 20px; width: 300px; height: 200px; border: 2px solid #fff; box-shadow: 0 0 15px rgba(0, 0, 0, 0.7); z-index: 100; background-color: #000; border-radius: 4px; overflow: hidden; /* 防止内部元素溢出 */ } /* 响应式调整 */ @media (max-width: 768px) { .overview-map { width: 150px; height: 100px; bottom: 10px; right: 10px; } } </style>那基于我刚刚发现的错误和解释,你修改一下代码发我

An error occurred while rendering. Rendering has stopped. ReferenceError: shouldShow is not defined ReferenceError: shouldShow is not defined at http://localhost:8001/src/components/common-map/live-map.vue?t=1751774207331:38:23 at Proxy.forEach (<anonymous>) at http://localhost:8001/src/components/common-map/live-map.vue?t=1751774207331:37:28 at invokeFunc (http://localhost:8001/node_modules/.vite/deps/lodash.js?v=6636ce6c:3839:28) at leadingEdge (http://localhost:8001/node_modules/.vite/deps/lodash.js?v=6636ce6c:3845:30) at debounced (http://localhost:8001/node_modules/.vite/deps/lodash.js?v=6636ce6c:3887:24) at tD.raiseEvent (http://localhost:8001/libs/Cesium/Cesium.js:96:1282) at Jt._updateCameraChanged (http://localhost:8001/libs/Cesium/Cesium.js:11295:124016) at Xi.initializeFrame (http://localhost:8001/libs/Cesium/Cesium.js:12477:35438) at uC.render (http://localhost:8001/libs/Cesium/Cesium.js:12479:1576) 如图所示报错为什么 修改以下代码:<template> <Search @location-selected="handleLocationSelected" /> <LocationBar v-if="loaded" :update-interval="100" :use-dms-format="useDmsFormat" /> </template> <style> /* @import "/temp/css/divGraphic.css"; */ </style> <script setup lang="ts"> import { computed, onUnmounted, onMounted, reactive } from "vue"; import LocationBar from "./location-bar.vue"; import Search from "./search.vue"; import initMap from "./init"; import { ref } from "vue"; import { throttle } from 'lodash'; import { loadRipplePoints, createMultipleRippleCircles } from './circle.js'; import { $prototype } from "../../main.ts"; const miniMapContainer = ref<HTMLElement>(); let viewIndicator: Rectangle; // 视图指示器样式 const currentPosition = reactive({ longitude: 113.361538, latitude: 27.339318, }); // 株洲市范围常量 const ZHUZHOU_EXTENT = { west: 112.5, // 株洲市西边界 east: 114.5, // 株洲市东边界 south: 26.0, // 株洲市南边界 north: 28.0 // 株洲市北边界 }; const rippleEntities = ref<any[]>([]); // 存储波纹圆实体 const heightThreshold = 80000; // 高度阈值(米),高于此值隐藏波纹圆 // 高度节流函数 const updateRippleVisibility = throttle(() => { if (!$prototype.$map || rippleEntities.value.length === 0) return; rippleEntities.value.forEach(entity => { entity.show = shouldShow; }); }, 200); // 每200毫秒最多执行一次 // 更新指示器位置 const updateIndicatorPosition = () => { if (!$prototype.$map) return; const camera = $prototype.$map.camera; const rect = camera.computeViewRectangle(); if (!rect) return; // 计算在株洲市范围内的相对位置 const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); const lonPercent = ((lon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((lat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; // 更新CSS指示器 indicatorStyle.value = { left: ${lonPercent}%, top: ${latPercent}%, display: "block" }; }; // 更新鹰眼地图 - 只更新指示器位置 const updateOverview = () => { if (!$prototype.$map || !overviewViewer.value) return; // 获取主地图的当前视图中心 const rectangle = $prototype.$map.camera.computeViewRectangle(); if (!rectangle) return; const center = Cesium.Rectangle.center(rectangle); currentPosition.longitude = Cesium.Math.toDegrees(center.longitude); currentPosition.latitude = Cesium.Math.toDegrees(center.latitude); // 更新指示器位置 updateIndicatorPosition(); }; const overviewViewer = ref(null); // 初始化鹰眼地图 - 使用株洲市影像 const initMiniMap = () => { Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDhlNDdmYy03NzFhLTQ1ZTQtOWQ3NS1lZDAzNDc3YjE4NDYiLCJpZCI6MzAxNzQyLCJpYXQiOjE3NDcwNTMyMDN9.eaez8rQxVbPv2LKEU0sMDclPWyHKhh1tR27Vg-_rQSM"; if (!miniMapContainer.value) return; // 创建株洲市专用影像提供器 const zhuzhouProvider = new Cesium.UrlTemplateImageryProvider({ url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); // 鹰眼地图初始化 - 使用株洲市影像 overviewViewer.value = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, imageryProvider: zhuzhouProvider, // 使用株洲市影像 terrainProvider: window.Cesium.createWorldTerrain(), }); // 设置固定视野为株洲市范围 overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ) }); // 隐藏控件 var toolbar = overviewViewer.value.container.getElementsByClassName("cesium-viewer-toolbar")[0]; if (toolbar) toolbar.style.display = "none"; overviewViewer.value.cesiumWidget.creditContainer.style.display = "none"; }; // 初始化视图指示器 function initRectangle() { // 创建视图指示器(株洲市范围框) viewIndicator = overviewViewer.value.entities.add({ rectangle: { coordinates: new Cesium.CallbackProperty(() => { return Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ); }, false), material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED, outlineWidth: 2, }, }); } // 指示器样式计算 const indicatorStyle = computed(() => { return {}; // 由updateIndicatorPosition直接设置 }); const loaded = ref(false); const useDmsFormat = ref(false); function addDemoGraphics() { const chinaBoundary = $prototype.$map.dataSources.add( Cesium.GeoJsonDataSource.load("/shp_zz.geojson", { stroke: Cesium.Color.WHITE, fill: false, clampToGround: true, describe: null, }) ); chinaBoundary.then((dataSource) => { const entities = dataSource.entities.values; for (let entity of entities) { if (entity.polyline) { entity.polyline.fill = false; } } }); } function flyToDes() { const center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0); $prototype.$map.camera.flyTo({ destination: new Cesium.Cartesian3( -2432812.6687511606, 5559483.804371395, 2832009.419525571 ), orientation: { heading: 6.283185307179421, pitch: -1.0472145569408116, roll: 6.2831853071795205, }, complete: function () {}, }); } // 监听主地图相机变化 const setupCameraListener = () => { $prototype.$map.camera.changed.addEventListener(updateOverview); }; // 鹰眼地图点击处理 const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer.value) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 计算在固定范围内的相对位置 const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; // 转换为株洲市范围内的经纬度 const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); // 主地图飞向点击位置 $prototype.$map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000000), }); }; function addImage() { var rightImageProvider = new Cesium.UrlTemplateImageryProvider({ name: "影像图", type: "xyz", layer: "vec_d", url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); $prototype.$map.imageryLayers.addImageryProvider(rightImageProvider); rightImageProvider.splitDirection = Cesium.SplitDirection.right; } onMounted(() => { initMap(); addImage(); loaded.value = true; addDemoGraphics(); flyToDes(); initMiniMap(); setupCameraListener(); setTimeout(function () { initRectangle(); }, 2000); (async () => { try { const ripplePoints = await loadRipplePoints(); rippleEntities.value = createMultipleRippleCircles( $prototype.$map, ripplePoints ); $prototype.$map.camera.changed.addEventListener(updateRippleVisibility); updateRippleVisibility(); } catch (error) { console.error('加载波纹圆失败:', error); } })(); }); let currentMarker: any = null; const createMarker = (location: { lng: number; lat: number; name: string }) => { if (currentMarker) { $prototype.$map.entities.remove(currentMarker); } currentMarker = $prototype.$map.entities.add({ position: Cesium.Cartesian3.fromDegrees( location.lng, location.lat, 50 ), point: { pixelSize: 200, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, }, label: { text: location.name, font: "40px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 1, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -20), heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), }, description: ${location.name} 经度:${location.lng.toFixed(6)} 纬度:${location.lat.toFixed(6)} , }); return currentMarker; }; const handleLocationSelected = (location: { lng: number; lat: number; name: string; }) => { if (!$prototype.$map) return; const destination = Cesium.Cartesian3.fromDegrees( location.lng, location.lat, 200 ); $prototype.$map.camera.flyTo({ destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-45), roll: 0, }, duration: 2, complete: () => { createMarker(location); }, }); }; onUnmounted(() => { if ($prototype.$map) { $prototype.$map.destroy(); $prototype.$map = null; } if ($prototype.$map) { $prototype.$map.camera.changed.removeEventListener(updateRippleVisibility); } console.log("组件销毁"); }); const emit = defineEmits(["onload", "onclick"]); const initMars3d = async (option: any) => { emit("onclick", true); emit("onload", $prototype.$map); }; </script> <style lang="less"> /**cesium 工具按钮栏*/ .cesium-viewer-toolbar { top: auto !important; bottom: 35px !important; left: 12px !important; right: auto !important; } .cesium-toolbar-button img { height: 100%; } .cesium-viewer-toolbar > .cesium-toolbar-button, .cesium-navigationHelpButton-wrapper, .cesium-viewer-geocoderContainer { margin-bottom: 5px; float: left; clear: both; text-align: center; } .cesium-button { background-color: rgba(23, 49, 71, 0.8); color: #e6e6e6; fill: #e6e6e6; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); line-height: 32px; } .cesium-button:hover { background: #3ea6ff; } /**cesium 底图切换面板*/ .cesium-baseLayerPicker-dropDown { bottom: 0; left: 40px; max-height: 700px; margin-bottom: 5px; background-color: rgba(23, 49, 71, 0.8); } /**cesium 帮助面板*/ .cesium-navigation-help { top: auto; bottom: 0; left: 40px; transform-origin: left bottom; background: none; background-color: rgba(23, 49, 71, 0.8); .cesium-navigation-help-instructions { background: none; } .cesium-navigation-button { background: none; } .cesium-navigation-button-selected, .cesium-navigation-button-unselected:hover { background: rgba(0, 138, 255, 0.2); } } /**cesium 二维三维切换*/ .cesium-sceneModePicker-wrapper { width: auto; } .cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon { float: right; margin: 0 3px; } /**cesium POI查询输入框*/ .cesium-viewer-geocoderContainer .search-results { left: 0; right: 40px; width: auto; z-index: 9999; } .cesium-geocoder-searchButton { background-color: rgba(23, 49, 71, 0.8); } .cesium-viewer-geocoderContainer .cesium-geocoder-input { background-color: rgba(63, 72, 84, 0.7); } .cesium-viewer-geocoderContainer .cesium-geocoder-input:focus { background-color: rgba(63, 72, 84, 0.9); } .cesium-viewer-geocoderContainer .search-results { background-color: rgba(23, 49, 71, 0.8); } /**cesium info信息框*/ .cesium-infoBox { top: 50px; background-color: rgba(23, 49, 71, 0.8); } .cesium-infoBox-title { background-color: rgba(23, 49, 71, 0.8); } /**cesium 任务栏的FPS信息*/ .cesium-performanceDisplay-defaultContainer { top: auto; bottom: 35px; right: 50px; } .cesium-performanceDisplay-ms, .cesium-performanceDisplay-fps { color: #fff; } /**cesium tileset调试信息面板*/ .cesium-viewer-cesiumInspectorContainer { top: 10px; left: 10px; right: auto; } .cesium-cesiumInspector { background-color: rgba(23, 49, 71, 0.8); } /**覆盖mars3d内部控件的颜色等样式*/ .mars3d-compass .mars3d-compass-outer { fill: rgba(23, 49, 71, 0.8); } .mars3d-contextmenu-ul, .mars3d-sub-menu { background-color: rgba(23, 49, 71, 0.8); > li > a:hover, > li > a:focus, > li > .active { background-color: #3ea6ff; } > .active > a, > .active > a:hover, > .active > a:focus { background-color: #3ea6ff; } } /* Popup样式*/ .mars3d-popup-color { color: #ffffff; } .mars3d-popup-background { background: rgba(23, 49, 71, 0.8); } .mars3d-popup-content { margin: 15px; } .mars3d-template-content label { padding-right: 6px; } .mars3d-template-titile { border-bottom: 1px solid #3ea6ff; } .mars3d-template-titile a { font-size: 16px; } .mars3d-tooltip { background: rgba(23, 49, 71, 0.8); border: 1px solid rgba(23, 49, 71, 0.8); } .mars3d-popup-btn-custom { padding: 3px 10px; border: 1px solid #209ffd; background: #209ffd1c; } .mars-dialog .mars-dialog__content { height: 100%; width: 100%; overflow: auto; padding: 5px; } .image { border: solid 2px #fff; } .content { height: 90%; padding-top: 10px; overflow-x: auto; overflow-y: auto; } .content-text { padding: 0 10px; text-indent: 30px; font-size: 17px; } .details-video { width: 100%; height: 760px; background-color: #000; } :where(.css-lt97qq9).ant-space { display: inline-flex; } :where(.css-lt97qq9).ant-space-align-center { align-items: center; } :where(.css-lt97qq9).ant-image .ant-image-mask { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(0, 0, 0, 0.5); cursor: pointer; opacity: 0; transition: opacity 0.3s; } :where(.css-lt97qq9).ant-image .ant-image-mask .ant-image-mask-info { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 4px; } :where(.css-1t97qq9)[class^="ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class^="ant-image"] [class*=" ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class*=" ant-image"] { box-sizing: border-box; } :where(.css-lt97qq9).ant-image .ant-image-img { width: 100%; height: auto; vertical-align: middle; } </style> <style scoped> .mini-map-container { position: relative; width: 100%; height: 100%; } .main-viewer { width: 100%; height: 100%; } .mini-map { position: absolute; right: 3vw; bottom: 6vh; width: 12vw; height: 17vh; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } .location-indicator { position: absolute; width: 14px; height: 14px; background: #ff3e3e; border: 2px solid white; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 15px rgba(255, 62, 62, 1); z-index: 100; } .view-rectangle { position: absolute; border: 2px solid #00f2fe; z-index: 99; pointer-events: none; box-shadow: 0 0 20px rgba(0, 242, 254, 0.7); } /* 相机聚焦样式 - 四个角折角 */ .corner { position: absolute; width: 25px; height: 25px; z-index: 100; pointer-events: none; } .corner::before, .corner::after { content: ""; position: absolute; background: #00f2fe; box-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .corner-top-left { top: -2px; left: -2px; } .corner-top-left::before { top: 0; left: 0; width: 15px; height: 3px; } .corner-top-left::after { top: 0; left: 0; width: 3px; height: 15px; } .corner-top-right { top: -2px; right: -2px; } .corner-top-right::before { top: 0; right: 0; width: 15px; height: 3px; } .corner-top-right::after { top: 0; right: 0; width: 3px; height: 15px; } .corner-bottom-left { bottom: -2px; left: -2px; } .corner-bottom-left::before { bottom: 0; left: 0; width: 15px; height: 3px; } .corner-bottom-left::after { bottom: 0; left: 0; width: 3px; height: 15px; } .corner-bottom-right { bottom: -2px; right: -2px; } .corner-bottom-right::before { bottom: 0; right: 0; width: 15px; height: 3px; } .corner-bottom-right::after { bottom: 0; right: 0; width: 3px; height: 15px; } .camera-icon { position: absolute; top: 10px; right: 10px; color: #00f2fe; font-size: 24px; z-index: 100; text-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .focus-effect { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 98; border: 2px solid rgba(0, 242, 254, 0.2); border-radius: 5px; box-shadow: inset 0 0 30px rgba(0, 242, 254, 0.1); } .pulse { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; border-radius: 50%; background: rgba(0, 242, 254, 0.7); box-shadow: 0 0 0 0 rgba(0, 242, 254, 0.7); animation: pulse 2s infinite; } ::v-deep.cesium-viewer-toolbar { display: none; } </style>

<template> 坐标系: <el-radio-group v-model="coordinateSystem" size="small"> <el-radio-button label="gcj02">高德/火星坐标</el-radio-button> <el-radio-button label="bd09">百度坐标</el-radio-button> </el-radio-group> <Search @location-selected="handleLocationSelected" /> <LocationBar v-if="loaded" :update-interval="100" :use-dms-format="useDmsFormat" /> </template> <style> /* 原有样式完全不变 */ </style> <script setup lang="ts"> // 原有导入 + 新增坐标转换工具类导入 import { computed, onUnmounted, onMounted, reactive, ref } from "vue"; import LocationBar from "./location-bar.vue"; import Search from "./search.vue"; import initMap from "./init"; import { throttle } from "lodash"; import { loadRipplePoints, createMultipleRippleCircles } from "./circle.js"; import { $ prototype } from "../../main.ts"; import markerImage from "@/assets/images/building.png"; import { imageDark } from "naive-ui/es/image/styles"; // 新增:导入坐标转换工具类 import { CoordinateTransformer } from "./coordinate-transformer"; // 修复类型定义 type Rectangle = any; // 原有状态 + 新增坐标系选择状态 const miniMapContainer = ref<HTMLElement>(); let viewIndicator: Rectangle; const currentPosition = reactive({ longitude: 113.361538, latitude: 27.339318, }); const ZHUZHOU_EXTENT = { west: 112.5, east: 114.5, south: 26.0, north: 28.0, }; const rippleEntities = ref<any[]>([]); const heightThreshold = 80000; const indicatorStyle = ref({ left: "50%", top: "50%", display: "block", }); const loaded = ref(false); const useDmsFormat = ref(false); const overviewViewer = ref(null); let currentMarker: any = null; // 新增:坐标系选择状态(默认高德GCJ-02) const coordinateSystem = ref("gcj02"); // 'gcj02' | 'bd09' // 原有方法完全不变(波纹可见性更新) const updateRippleVisibility = throttle(() => { if (!$ prototype.$ map || rippleEntities.value.length === 0) return; let shouldShow = false; const cartographic = $ prototype.$ map.camera.positionCartographic; if (cartographic) { const cameraHeight = cartographic.height; shouldShow = cameraHeight > heightThreshold; } rippleEntities.value.forEach((entity) => { entity.show = shouldShow; }); }, 200); // 原有方法完全不变(指示器位置更新) const updateIndicatorPosition = () => { if (!$ prototype.$ map) return; const camera = $ prototype.$ map.camera; const rect = camera.computeViewRectangle(); if (!rect) return; const center = Cesium.Rectangle.center(rect); const lon = Cesium.Math.toDegrees(center.longitude); const lat = Cesium.Math.toDegrees(center.latitude); const constrainedLon = Math.max( ZHUZHOU_EXTENT.west, Math.min(ZHUZHOU_EXTENT.east, lon) ); const constrainedLat = Math.max( ZHUZHOU_EXTENT.south, Math.min(ZHUZHOU_EXTENT.north, lat) ); const lonPercent = ((constrainedLon - ZHUZHOU_EXTENT.west) / (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100; const latPercent = 100 - ((constrainedLat - ZHUZHOU_EXTENT.south) / (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100; indicatorStyle.value = { left: ${lonPercent}%, top: ${latPercent}%, display: "block", }; }; // 原有方法完全不变(鹰眼地图更新) const updateOverview = () => { if (!$ prototype.$ map || !overviewViewer.value) return; const rectangle = $ prototype.$ map.camera.computeViewRectangle(); if (!rectangle) return; updateIndicatorPosition(); }; // 原有方法完全不变(初始化鹰眼地图) const initMiniMap = () => { Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDhlNDdmYy03NzFhLTQ1ZTQtOWQ3NS1lZDAzNDc3YjE4NDYiLCJpZCI6MzAxNzQyLCJpYXQiOjE3NDcwNTMyMDN9.eaez8rQxVbPv2LKEU0sMDclPWyHKhh1tR27Vg-_rQSM"; if (!miniMapContainer.value) return; const worldProvider = new Cesium.UrlTemplateImageryProvider({ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", minimumLevel: 0, maximumLevel: 19, tilingScheme: new Cesium.WebMercatorTilingScheme(), }); const zhuzhouProvider = new Cesium.UrlTemplateImageryProvider({ url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, tilingScheme: new Cesium.WebMercatorTilingScheme(), }); overviewViewer.value = new Cesium.Viewer(miniMapContainer.value, { sceneMode: Cesium.SceneMode.SCENE2D, baseLayerPicker: false, homeButton: false, timeline: false, navigationHelpButton: false, animation: false, scene3DOnly: true, selectionIndicator: false, infoBox: false, imageryProvider: worldProvider, terrainProvider: undefined, mapProjection: new Cesium.WebMercatorProjection(), skyBox: false, skyAtmosphere: false, }); const zhuzhouLayer = overviewViewer.value.imageryLayers.addImageryProvider( zhuzhouProvider ); overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ), }); const toolbar = overviewViewer.value.container.getElementsByClassName( "cesium-viewer-toolbar" )[0]; if (toolbar) toolbar.style.display = "none"; overviewViewer.value.cesiumWidget.creditContainer.style.display = "none"; initRectangle(); }; // 原有方法完全不变(初始化视图指示器) function initRectangle() { viewIndicator = overviewViewer.value.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( ZHUZHOU_EXTENT.west, ZHUZHOU_EXTENT.south, ZHUZHOU_EXTENT.east, ZHUZHOU_EXTENT.north ), material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED, outlineWidth: 2, }, }); } // 原有方法完全不变(添加演示图形) function addDemoGraphics() { const chinaBoundary = $ prototype.$ map.dataSources.add( Cesium.GeoJsonDataSource.load("/shp_zz.geojson", { stroke: Cesium.Color.WHITE, fill: false, clampToGround: true, describe: null, }) ); chinaBoundary.then((dataSource) => { const entities = dataSource.entities.values; for (let entity of entities) { if (entity.polyline) { entity.polyline.fill = false; } } }); } // 原有方法完全不变(飞行到默认位置) function flyToDes() { const center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0); $ prototype.$ map.camera.flyTo({ destination: new Cesium.Cartesian3( -2432812.6687511606, 5559483.804371395, 2832009.419525571 ), orientation: { heading: 6.283185307179421, pitch: -1.0472145569408116, roll: 6.2831853071795205, }, complete: function () {}, }); } // 原有方法完全不变(监听相机变化) const setupCameraListener = () => { $ prototype.$ map.camera.changed.addEventListener(updateOverview); }; // 原有方法完全不变(鹰眼地图点击处理) const handleMiniMapClick = (event: MouseEvent) => { if (!miniMapContainer.value || !overviewViewer.value) return; const rect = miniMapContainer.value.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; const lon = ZHUZHOU_EXTENT.west + (xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west); const lat = ZHUZHOU_EXTENT.north - (yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south); $ prototype.$ map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000000), }); }; // 原有生命周期方法完全不变 onMounted(() => { initMap(); loaded.value = true; addDemoGraphics(); flyToDes(); setTimeout(() => { initMiniMap(); setupCameraListener(); updateOverview(); }, 1000); (async () => { try { const ripplePoints = await loadRipplePoints(); rippleEntities.value = createMultipleRippleCircles($ prototype.$ map, ripplePoints); $ prototype.$ map.camera.changed.addEventListener(updateRippleVisibility); updateRippleVisibility(); } catch (error) { console.error("加载波纹圆失败:", error); } })(); }); // 原有方法完全不变(创建标记) const createMarker = (location: { lng: number; lat: number; name: string }) => { if (currentMarker) { $ prototype.$ map.entities.remove(currentMarker); } console.log("标记图片加载状态:", markerImage); console.log("创建标记位置:", location); currentMarker = $ prototype.$ map.entities.add({ position: Cesium.Cartesian3.fromDegrees(location.lng, location.lat, 10), label: { text: location.name + "(标记位置)", font: "18px sans-serif", fillColor: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, verticalOrigin: Cesium.VerticalOrigin.TOP, pixelOffset: new Cesium.Cartesian2(0, 40), heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, show: true, }, point: { pixelSize: 15, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 3, heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, show: true, }, }); console.log("标记实体已添加:", currentMarker); $ prototype.$ map.scene.requestRender(); return currentMarker; }; // 核心修改:使用工具类实现动态坐标系转换 const handleLocationSelected = (location: { lng: number; lat: number; name: string }) => { if (!$ prototype.$ map) return; // 根据选择的坐标系进行转换 let wgsLocation; if (coordinateSystem.value === "gcj02") { // 高德/火星坐标转WGS84 wgsLocation = CoordinateTransformer.gcj02ToWgs84(location.lng, location.lat); } else { // 百度坐标转WGS84 wgsLocation = CoordinateTransformer.bd09ToWgs84(location.lng, location.lat); } console.log(转换前(${coordinateSystem.value})坐标:, location.lng, location.lat); console.log("转换后(WGS84)坐标:", wgsLocation.lng, wgsLocation.lat); // 使用转换后的坐标执行原有逻辑 const destination = Cesium.Cartesian3.fromDegrees( wgsLocation.lng, wgsLocation.lat, 2000 ); $ prototype.$ map.camera.flyTo({ destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-45), roll: 0, }, duration: 2, complete: () => { createMarker({ ...location, ...wgsLocation }); }, }); }; // 原有方法完全不变(组件销毁清理) onUnmounted(() => { if ($ prototype.$ map) { $ prototype.$ map.destroy(); $ prototype.$ map = null; } if ($ prototype.$ map) { $ prototype.$ map.camera.changed.removeEventListener(updateRippleVisibility); } console.log("组件销毁"); }); const emit = defineEmits(["onload", "onclick"]); const initMars3d = async (option: any) => { emit("onclick", true); emit("onload", $ prototype.$ map); }; </script> <style lang="less"> /**cesium 工具按钮栏*/ .cesium-viewer-toolbar { top: auto !important; bottom: 35px !important; left: 12px !important; right: auto !important; } .cesium-toolbar-button img { height: 100%; } .cesium-viewer-toolbar > .cesium-toolbar-button, .cesium-navigationHelpButton-wrapper, .cesium-viewer-geocoderContainer { margin-bottom: 5px; float: left; clear: both; text-align: center; } .cesium-button { background-color: rgba(23, 49, 71, 0.8); color: #e6e6e6; fill: #e6e6e6; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); line-height: 32px; } .cesium-button:hover { background: #3ea6ff; } /**cesium 底图切换面板*/ .cesium-baseLayerPicker-dropDown { bottom: 0; left: 40px; max-height: 700px; margin-bottom: 5px; background-color: rgba(23, 49, 71, 0.8); } /**cesium 帮助面板*/ .cesium-navigation-help { top: auto; bottom: 0; left: 40px; transform-origin: left bottom; background: none; background-color: rgba(23, 49, 71, 0.8); .cesium-navigation-help-instructions { background: none; } .cesium-navigation-button { background: none; } .cesium-navigation-button-selected, .cesium-navigation-button-unselected:hover { background: rgba(0, 138, 255, 0.2); } } /**cesium 二维三维切换*/ .cesium-sceneModePicker-wrapper { width: auto; } .cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon { float: right; margin: 0 3px; } /**cesium POI查询输入框*/ .cesium-viewer-geocoderContainer .search-results { left: 0; right: 40px; width: auto; z-index: 9999; } .cesium-geocoder-searchButton { background-color: rgba(23, 49, 71, 0.8); } .cesium-viewer-geocoderContainer .cesium-geocoder-input { background-color: rgba(63, 72, 84, 0.7); } .cesium-viewer-geocoderContainer .cesium-geocoder-input:focus { background-color: rgba(63, 72, 84, 0.9); } .cesium-viewer-geocoderContainer .search-results { background-color: rgba(23, 49, 71, 0.8); } /**cesium info信息框*/ .cesium-infoBox { top: 50px; background-color: rgba(23, 49, 71, 0.8); } .cesium-infoBox-title { background-color: rgba(23, 49, 71, 0.8); } /**cesium 任务栏的FPS信息*/ .cesium-performanceDisplay-defaultContainer { top: auto; bottom: 35px; right: 50px; } .cesium-performanceDisplay-ms, .cesium-performanceDisplay-fps { color: #fff; } /**cesium tileset调试信息面板*/ .cesium-viewer-cesiumInspectorContainer { top: 10px; left: 10px; right: auto; } .cesium-cesiumInspector { background-color: rgba(23, 49, 71, 0.8); } /**覆盖mars3d内部控件的颜色等样式*/ .mars3d-compass .mars3d-compass-outer { fill: rgba(23, 49, 71, 0.8); } .mars3d-contextmenu-ul, .mars3d-sub-menu { background-color: rgba(23, 49, 71, 0.8); > li > a:hover, > li > a:focus, > li > .active { background-color: #3ea6ff; } > .active > a, > .active > a:hover, > .active > a:focus { background-color: #3ea6ff; } } /* Popup样式*/ .mars3d-popup-color { color: #ffffff; } .mars3d-popup-background { background: rgba(23, 49, 71, 0.8); } .mars3d-popup-content { margin: 15px; } .mars3d-template-content label { padding-right: 6px; } .mars3d-template-titile { border-bottom: 1px solid #3ea6ff; } .mars3d-template-titile a { font-size: 16px; } .mars3d-tooltip { background: rgba(23, 49, 71, 0.8); border: 1px solid rgba(23, 49, 71, 0.8); } .mars3d-popup-btn-custom { padding: 3px 10px; border: 1px solid #209ffd; background: #209ffd1c; } .mars-dialog .mars-dialog__content { height: 100%; width: 100%; overflow: auto; padding: 5px; } .image { border: solid 2px #fff; } .content { height: 90%; padding-top: 10px; overflow-x: auto; overflow-y: auto; } .content-text { padding: 0 10px; text-indent: 30px; font-size: 17px; } .details-video { width: 100%; height: 760px; background-color: #000; } :where(.css-lt97qq9).ant-space { display: inline-flex; } :where(.css-lt97qq9).ant-space-align-center { align-items: center; } :where(.css-lt97qq9).ant-image .ant-image-mask { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(0, 0, 0, 0.5); cursor: pointer; opacity: 0; transition: opacity 0.3s; } :where(.css-lt97qq9).ant-image .ant-image-mask .ant-image-mask-info { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 4px; } :where(.css-1t97qq9)[class^="ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class^="ant-image"], :where(.css-1t97qq9)[class^="ant-image"] [class*=" ant-image"], :where(.css-1t97qq9)[class*=" ant-image"] [class*=" ant-image"] { box-sizing: border-box; } :where(.css-lt97qq9).ant-image .ant-image-img { width: 100%; height: auto; vertical-align: middle; } </style> <style scoped> .mini-map-container { position: relative; width: 100%; height: 100%; } .main-viewer { width: 100%; height: 100%; } .mini-map { position: absolute; right: 3vw; bottom: 6vh; width: 12vw; height: 17vh; border: 2px solid #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; cursor: pointer; overflow: hidden; } .location-indicator { position: absolute; width: 19px; height: 19px; transform: translate(-50%, -50%); z-index: 100; border: 2px solid red; border-radius: 2px; } /* 原十字准星伪元素保持不变 */ .location-indicator::before, .location-indicator::after { content: ''; position: absolute; background-color: red; top: 50%; left: 50%; transform: translate(-50%, -50%); } .location-indicator::before { width: 12px; height: 2px; } .location-indicator::after { width: 2px; height: 12px; } /* 新增四条准星延伸线 */ .ext-line { position: absolute; background-color: red; } /* 顶部延伸线 - 从矩形边框向上延伸 */ .ext-line-top { top: -5px; left: 50%; transform: translateX(-50%); width: 2px; height: 5px; } /* 右侧延伸线 - 从矩形边框向右延伸 */ .ext-line-right { top: 50%; right: -5px; transform: translateY(-50%); width: 5px; height: 2px; } /* 底部延伸线 - 从矩形边框向下延伸 */ .ext-line-bottom { bottom: -5px; left: 50%; transform: translateX(-50%); width: 2px; height: 5px; } /* 左侧延伸线 - 从矩形边框向左延伸 */ .ext-line-left { top: 50%; left: -5px; transform: translateY(-50%); width: 5px; height: 2px; } .view-rectangle { position: absolute; border: 2px solid #00f2fe; z-index: 99; pointer-events: none; box-shadow: 0 0 20px rgba(0, 242, 254, 0.7); } /* 相机聚焦样式 - 四个角折角 */ .corner { position: absolute; width: 25px; height: 25px; z-index: 100; pointer-events: none; } .corner::before, .corner::after { content: ""; position: absolute; background: #00f2fe; box-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .corner-top-left { top: -2px; left: -2px; } .corner-top-left::before { top: 0; left: 0; width: 15px; height: 3px; } .corner-top-left::after { top: 0; left: 0; width: 3px; height: 15px; } .corner-top-right { top: -2px; right: -2px; } .corner-top-right::before { top: 0; right: 0; width: 15px; height: 3px; } .corner-top-right::after { top: 0; right: 0; width: 3px; height: 15px; } .corner-bottom-left { bottom: -2px; left: -2px; } .corner-bottom-left::before { bottom: 0; left: 0; width: 15px; height: 3px; } .corner-bottom-left::after { bottom: 0; left: 0; width: 3px; height: 15px; } .corner-bottom-right { bottom: -2px; right: -2px; } .corner-bottom-right::before { bottom: 0; right: 0; width: 15px; height: 3px; } .corner-bottom-right::after { bottom: 0; right: 0; width: 3px; height: 15px; } .camera-icon { position: absolute; top: 10px; right: 10px; color: #00f2fe; font-size: 24px; z-index: 100; text-shadow: 0 0 10px rgba(0, 242, 254, 0.8); } .focus-effect { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 98; border: 2px solid rgba(0, 242, 254, 0.2); border-radius: 5px; box-shadow: inset 0 0 30px rgba(0, 242, 254, 0.1); } .pulse { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; border-radius: 50%; background: rgba(0, 242, 254, 0.7); box-shadow: 0 0 0 0 rgba(0, 242, 254, 0.7); animation: pulse 2s infinite; } ::v-deep.cesium-viewer-toolbar { display: none; } </style> 检查live-map.vue代码,其中的鹰眼地图部分代码好像存在问题如下:鹰眼联动有问题,鹰眼图不用操作,基于此你帮我检查修改一下,尽可能不更改其他任何无关代码,减少对vue文件的修改

最新推荐

recommend-type

【Java使用配置文件连接mysql】

mysql使用druid配置连接mysql
recommend-type

Java课程设计画随机圆(1).pdf

Java课程设计画随机圆(1).pdf
recommend-type

python 一个用py3写的数据库自动备份管理系统.zip

python 一个用py3写的数据库自动备份管理系统
recommend-type

电子商务的应用论文(1).docx

电子商务的应用论文(1).docx
recommend-type

“计算机软件著作权”登记【可编辑范本】(1).doc

“计算机软件著作权”登记【可编辑范本】(1).doc
recommend-type

获取本机IP地址的程序源码分析

从给定文件信息中我们可以提取出的关键知识点是“取本机IP”的实现方法以及与之相关的编程技术和源代码。在当今的信息技术领域中,获取本机IP地址是一项基本技能,广泛应用于网络通信类的软件开发中,下面将详细介绍这一知识点。 首先,获取本机IP地址通常需要依赖于编程语言和操作系统的API。不同的操作系统提供了不同的方法来获取IP地址。在Windows操作系统中,可以通过调用Windows API中的GetAdaptersInfo()或GetAdaptersAddresses()函数来获取网络适配器信息,进而得到IP地址。在类Unix操作系统中,可以通过读取/proc/net或是使用系统命令ifconfig、ip等来获取网络接口信息。 在程序设计过程中,获取本机IP地址的源程序通常会用到网络编程的知识,比如套接字编程(Socket Programming)。网络编程允许程序之间进行通信,套接字则是在网络通信过程中用于发送和接收数据的接口。在许多高级语言中,如Python、Java、C#等,都提供了内置的网络库和类来简化网络编程的工作。 在网络通信类中,IP地址是区分不同网络节点的重要标识,它是由IP协议规定的,用于在网络中唯一标识一个网络接口。IP地址可以是IPv4,也可以是较新的IPv6。IPv4地址由32位二进制数表示,通常分为四部分,每部分由8位构成,并以点分隔,如192.168.1.1。IPv6地址则由128位二进制数表示,其表示方法与IPv4有所不同,以冒号分隔的8组16进制数表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。 当编写源代码以获取本机IP地址时,通常涉及到以下几个步骤: 1. 选择合适的编程语言和相关库。 2. 根据目标操作系统的API或系统命令获取网络接口信息。 3. 分析网络接口信息,提取出IP地址。 4. 将提取的IP地址转换成适合程序内部使用的格式。 5. 在程序中提供相应功能,如显示IP地址或用于网络通信。 例如,在Python中,可以使用内置的socket库来获取本机IP地址。一个简单的示例代码如下: ```python import socket # 获取主机名 hostname = socket.gethostname() # 获取本机IP local_ip = socket.gethostbyname(hostname) print("本机IP地址是:", local_ip) ``` 在实际应用中,获取本机IP地址通常是为了实现网络通信功能,例如建立客户端与服务器的连接,或者是在开发涉及到IP地址的其他功能时使用。 关于文件名称“getIP”,这是一个自解释的文件名,明显表示该文件或程序的作用是获取本机的IP地址。从标签“控件 源码 网络通信类 资源”中我们可以看出,这个文件很可能是一个可以嵌入其他软件中的代码片段,用以实现网络通信功能的一部分,具有较高的灵活性和重用性。 综上所述,获取本机IP地址是一个涉及到操作系统API、网络编程以及特定编程语言知识的技能。它不仅需要对编程语言提供的库函数有深入的理解,还要对操作系统的网络配置和IP协议有足够的认识。通过阅读和分析相关的源代码,如“getIP”,可以加深对网络编程实现细节的理解,并能够在实际开发中快速地应用这一技术。
recommend-type

【权威指南】:Win11笔记本上RTX4080驱动的安装与调试秘籍

# 1. Win11笔记本与RTX4080显卡介绍 随着技术的不断发展,笔记本电脑已不再是仅仅满足办公需求的移动设备,而是逐渐成为可以胜任复杂图形处理和游戏任务的强大工具。微软推出的Windows 11操作系统,以其全新的用户界面和改进的系统性能,为用户提供了更为流畅的操作体验。而在硬件方面,NVIDIA的RTX 4080显卡以其卓越的图形处理能力和AI支持,为笔记本电脑带来了前所未有的性能提升。本章节将带您初步了解Windows 11笔记本与NVIDIA RTX 4080显卡的基础信息,为进一步深入探讨它们的优化和调试技巧奠定基础。 ## 1.1 Win11笔记本的优势 Windows
recommend-type

windows环境举例

<think>好的,用户现在想在Windows环境下创建C函数库,需要具体的方法和示例代码。我需要结合之前的回答和用户提供的引用内容来给出合适的指导。 首先回顾之前的回答,用户已经了解了在Linux下创建静态库和动态库的方法,现在需要切换到Windows环境。根据引用[2],Windows下的C标准库和动态链接库的处理与Linux不同,比如使用dlfcn.h在Linux,而Windows可能需要其他方式。另外,引用[1]提到了在Windows下配置gcc环境(MinGW-w64),这可能是一个关键点,因为用户可能需要使用MinGW来编译库。 用户提供的引用[3]提到了使用MSVC编译器,这
recommend-type

QQ自动发送/回复系统源代码开放

根据提供的文件信息,我们可以了解到以下几点关键的知识点: ### 标题:“qqhelp” 1. **项目类型**: 标题“qqhelp”暗示这是一个与QQ相关的帮助工具或项目。QQ是中国流行的即时通讯软件,因此这个标题表明项目可能提供了对QQ客户端功能的辅助或扩展。 2. **用途**: “help”表明此项目的主要目的是提供帮助或解决问题。由于它提到了QQ,并且涉及“autosend/reply”功能,我们可以推测该项目可能用于自动化发送消息回复,或提供某种形式的自动回复机制。 ### 描述:“I put it to my web, but nobody sendmessage to got the source, now I public it. it supply qq,ticq autosend/reply ,full sourcecode use it as you like” 1. **发布情况**: 描述提到该项目原先被放置在某人的网站上,并且没有收到请求源代码的消息。这可能意味着项目不够知名或者需求不高。现在作者决定公开发布,这可能是因为希望项目能够被更多人了解和使用,或是出于开源共享的精神。 2. **功能特性**: 提到的“autosend/reply”表明该项目能够实现自动发送和回复消息。这种功能对于需要进行批量或定时消息沟通的应用场景非常有用,例如客户服务、自动化的营销通知等。 3. **代码可用性**: 作者指出提供了“full sourcecode”,意味着源代码完全开放,用户可以自由使用,无论是查看、学习还是修改,用户都有很大的灵活性。这对于希望学习编程或者有特定需求的开发者来说是一个很大的优势。 ### 标签:“综合系统类” 1. **项目分类**: 标签“综合系统类”表明这个项目可能是一个多功能的集成系统,它可能不仅限于QQ相关的功能,还可能包含了其他类型的综合服务或特性。 2. **技术范畴**: 这个标签可能表明该项目的技术实现比较全面,可能涉及到了多个技术栈或者系统集成的知识点,例如消息处理、网络编程、自动化处理等。 ### 压缩包子文件的文件名称列表: 1. **Unit1.dfm**: 这是一个Delphi或Object Pascal语言的窗体定义文件,用于定义应用程序中的用户界面布局。DFM文件通常用于存储组件的属性和位置信息,使得开发者可以快速地进行用户界面的设计和调整。 2. **qqhelp.dpr**: DPR是Delphi项目文件的扩展名,包含了Delphi项目的核心设置,如程序入口、使用的单元(Units)等。这个文件是编译和构建Delphi项目的起点,它能够帮助开发者了解项目的组织结构和编译指令。 3. **Unit1.pas**: PAS是Delphi或Object Pascal语言的源代码文件。这个文件可能包含了与QQ帮助工具相关的核心逻辑代码,例如处理自动发送和回复消息的算法等。 4. **readme.txt**: 这是一个常见的文本文件,包含项目的基本说明和使用指导,帮助用户了解如何获取、安装、运行和定制该项目。README文件通常是用户与项目首次交互时首先阅读的文件,因此它对于一个开源项目的用户友好度有着重要影响。 通过以上分析,我们可以看出“qqhelp”项目是一个针对QQ通讯工具的自动化消息发送与回复的辅助工具。项目包含完整的源代码,用户可以根据自己的需要进行查看、修改和使用。它可能包含Delphi语言编写的窗体界面和后端逻辑代码,具有一定的综合系统特性。项目作者出于某种原因将其开源,希望能够得到更广泛的使用和反馈。
recommend-type

【7步打造Win11深度学习利器】:Tensorflow-GPU与RTX4080终极优化指南

# 1. 深度学习与Windows 11的融合 在人工智能时代,深度学习已渗透到生活的方方面面,而Windows 11作为最新一代的操作系统,为深度学习提供了一个高效的工作平台。本章节将探讨深度学习技术如何与Windows 11系统融合,以及这一