Imagery Layers.html

本文介绍如何使用Cesium JavaScript库叠加多种影像图层,包括基础地图、夜间地球灯光效果及特定区域的logo图层。通过调整图层属性如透明度、亮度,实现丰富的视觉效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Use correct character set. -->
    <meta charset="utf-8">
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <!-- Make the app on mobile take up the full browser screen and disable user scaling. -->
    <meta name="viewport"
          content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>Imagery Layers</title>

    <!-- The Cesium library. -->
    <script src="../ThirdParty/Cesium/Cesium.js"></script>
    <!-- Style our app. -->
    <style>
        @import url(../ThirdParty/Cesium/Widgets/widgets.css);
        html, body, #cesiumContainer {
            width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="cesiumContainer"></div>
    <script>
        Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzNDhhYmQxOC1mYzMwLTRhYmEtOTI5Ny1iNGExNTQ3ZTZhODkiLCJpZCI6NTQ1NCwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0MzM3Mzc0NH0.RU6ynAZcwQvdfygt_N_j2rb2lpsuyyROzdaLQg0emAg';
        let viewer = new Cesium.Viewer('cesiumContainer', {
            // 要使用的图像提供者。
            imageryProvider : new Cesium.ArcGisMapServerImageryProvider({
                // ArcGIS地图服务器服务的url。
                url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
            }),
            // 基层拾取器。
            baseLayerPicker : false
        });
        // 获取将在全球呈现的图像层的集合。
        let layers = viewer.imageryLayers;
        // 后添加的图层在已有的图层的上边展示(后来居上)。
        let earthAtNight = layers.addImageryProvider(new Cesium.IonImageryProvider({ assetId: 3812 }));
        // layers.lower(earthAtNight);
        earthAtNight.alpha = 0.5; // 0.0 透明  1.0 不透明。
        earthAtNight.brightness = 2.0; // > 1.0 增加灯的亮度  < 1.0 降低亮度

        layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
            // 瓷砖的url。
            url : '../images/Cesium_Logo_overlay.png',
            // 矩形,以弧度表示,由图像覆盖。
            // Cesium.Rectangle.fromDegrees(west, south, east, north, result) → Rectangle
            // 创建以度为单位的给定边界经度和纬度的矩形。
            rectangle : Cesium.Rectangle.fromDegrees(-75.0, 28.0, -67.0, 29.75)
        }));
    </script>
</body>

</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>通过属性查询地图服务中的信息</title> <link rel="stylesheet" href="https://js.arcgis.com/3.39/esri/css/esri.css"> <!-- <link rel="stylesheet" type="text/css" href="./css/esri.css" /> --> <link rel="stylesheet" href="https://js.arcgis.com/3.40/esri/themes/calcite/dijit/calcite.css"> <script src="https://js.arcgis.com/3.41/"></script> <script> require(["esri/map", //加载地图组件 "dojo/dom", "dojo/on", "esri/InfoTemplate", "esri/graphic", "esri/geometry/Point",//加载点对象组件 "esri/symbols/SimpleMarkerSymbol", "esri/geometry/Extent",//加载范围组件 "esri/layers/FeatureLayer", //加载FeatureLayer地图组件 // "esri/dijit/FeatureTable", "esri/layers/WebTiledLayer", //加载切片地图组件 "esri/layers/ArcGISDynamicMapServiceLayer",//加载动态地图组件 "esri/symbols/SimpleFillSymbol", "esri/renderers/UniqueValueRenderer", "esri/tasks/query", "esri/tasks/QueryTask", "esri/Color", "dojo/domReady!" ], function (Map, dom, on, InfoTemplate, Graphic, Point, SimpleMarkerSymbol,Extent, FeatureLayer, WebTiledLayer, ArcGISDynamicMapServiceLayer, SimpleFillSymbol, UniqueValueRenderer, Query, QueryTask, Color, GeoJsonLayer) { //初始化地图容器 // map = new Map("map", { logo: false, slider: false }, {zoom: 8}); map = new Map("map", { center: [109.33789 , 29.57985], basemap: "satellite", zoom: 10, sliderStyle: "small", logo: false }); // 创建底图 var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"); map.addLayer(basemap,0); // 创建动态图层 var dynamicLayer = new ArcGISDynamicMapServiceLayer("http://116.62.63.94:6080/arcgis/rest/services/sanhuxiangtest/MapServer"); map.addLayer(dynamicLayer,99); }) </script> </head> <body class="tundra"> <div id="map" style="width:900px; height:580px; border:1px solid #000;"></div> 类别名称:<input class="nm" type="text"> </body> </html>
07-15
<div ref=“miniMapContainer” class=“mini-map” @click=“handleMiniMapClick”> <button class=“collapse-button” @click=“togglePanel”> {{ panelCollapsed ? ‘☰’ : ‘×’ }} 专题图层选择 <input v-model=“searchQuery” placeholder=“搜索图层…” @input=“filterLayers” /> 🔍 <div class=“category-header” @click=“toggleCategory(category.id)”> {{ category.name }} {{ category.expanded ? ‘▼’ : ‘►’ }} <div v-for=“layer in category.layers” :key=“layer.id” class=“layer-item” @mouseover=“hoverLayer = layer.id” @mouseleave=“hoverLayer = null” :class=“{ ‘layer-hover’: hoverLayer === layer.id }” > <input type=“checkbox” v-model=“layer.visible” @change=“toggleLayer(layer)” > {{ layer.name }} ⏳ <script setup lang="ts"> import { computed, ref, onMounted, onUnmounted, watch } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 引入景区分布组件 import ThematicLayers from './Thematic Layer/Distribution_sp/ThematicLayers.vue'; // ===== 添加面板折叠状态变量 ===== const panelCollapsed = ref(false); // ===== 添加面板折叠/展开方法 ===== const togglePanel = () => { panelCollapsed.value = !panelCollapsed.value; }; // 在现有变量声明之后添加图层相关变量 const searchQuery = ref(''); const hoverLayer = ref<string | null>(null); const scenicLayerRef = ref<InstanceType<typeof ThematicLayers> | null>(null); const scenicLayerVisible = ref(false); const layerCategories = ref([ { id: 'population', name: '人口信息', expanded: true, layers: [ { id: 'pop-density', name: '人口密度热力图', visible: false, loading: false } ] }, { id: 'talent', name: '人才分布', expanded: true, layers: [ { id: 'talent-points', name: '高端人才分布', visible: false, loading: false } ] }, { id: 'base', name: '基础图层', expanded: true, layers: [ { id: 'boundary', name: '行政边界', visible: false, loading: false }, { id: 'road-network', name: '道路网络', visible: false, loading: false }, { id: 'scenic-spots', name: '旅游景区', visible: false, loading: false } ] } ]); // 计算过滤后的分类 const filteredCategories = computed(() => { if (!searchQuery.value) return layerCategories.value; return layerCategories.value.map(category => ({ ...category, layers: category.layers.filter(layer => layer.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ) })).filter(category => category.layers.length > 0); }); // 切换分类展开状态 const toggleCategory = (categoryId: string) => { const category = layerCategories.value.find(c => c.id === categoryId); if (category) category.expanded = !category.expanded; }; // 切换图层显示状态 const toggleLayer = (layer: any) => { layer.loading = true; // 模拟图层加载延迟 setTimeout(() => { layer.loading = false; console.log(`切换图层: ${layer.name} - ${layer.visible ? '显示' : '隐藏'}`); // 当切换"旅游景区"图层时,控制景区分布组件 if (layer.id === 'scenic-spots') { scenicLayerVisible.value = layer.visible; } }, 500); }; // 搜索过滤 const filterLayers = () => { // 搜索时自动展开所有分类 layerCategories.value.forEach(cat => { cat.expanded = true; }); }; // 株洲市范围定义 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; } /* ===== 面板容器和折叠按钮样式 ===== */ .layer-control-panel-wrapper { position: absolute; top: 100px; left: 20px; z-index: 1000; } .collapse-button { position: absolute; top: 10px; right: 10px; width: 32px; height: 32px; background: #0d3a67; border: none; border-radius: 4px; color: white; font-size: 18px; cursor: pointer; z-index: 1001; display: flex; align-items: center; justify-content: center; transition: background-color 0.3s; } .collapse-button:hover { background: #1a5a9a; } /* 专题图层控制面板 */ .layer-control-panel { width: 280px; background: #062b54; /* 半透明深蓝色背景 */ border-radius: 10px; padding: 15px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); backdrop-filter: blur(5px); /* 毛玻璃效果 */ color: #e6f7ff; font-family: 'Microsoft YaHei', sans-serif; font-size: 14px; } .panel-header { border-bottom: 1px solid rgba(255, 255, 255, 0.1); padding-bottom: 12px; margin-bottom: 15px; } .panel-header h3 { margin: 0; font-size: 18px; color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } .search-box { position: relative; margin-bottom: 15px; } .search-box input { width: 82%; padding: 10px 15px 10px 35px; border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.2); background: rgba(0, 0, 0, 0.25); color: white; outline: none; transition: all 0.3s; } .search-box input:focus { border-color: #40a9ff; box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); } .search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: rgba(255, 255, 255, 0.6); } .category-header { padding: 10px 15px; background: rgba(0, 21, 41, 0.5); border-radius: 6px; margin-bottom: 8px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; transition: background 0.3s; } .category-header:hover { background: rgba(24, 144, 255, 0.3); } .toggle-icon { font-size: 12px; } .layer-list { padding-left: 10px; margin-bottom: 15px; } .layer-item { display: flex; align-items: center; padding: 8px 10px; border-radius: 4px; margin: 5px 0; transition: all 0.2s; } .layer-hover { background: rgba(24, 144, 255, 0.15); } .layer-name { margin-left: 12px; flex-grow: 1; } .loading-indicator { margin-left: 8px; font-size: 14px; color: #69c0ff; } /* 开关控件样式 */ .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: #434343; 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: #1890ff; } input:checked + .slider:before { transform: translateX(20px); } /* 隐藏版权信息 */ :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> 如图所示代码,其中左侧图层控制面板中只要控件还没有添加功能,如果我要添加功能应该在哪里添加,告诉我,同时你为我完成那个行政边界功能的添加,为图层加入株洲市个区矢量边界,可以覆盖遥感影像,点击控件还可以取消,基于此修改代码发我,同时减少对其他代码的影响
07-11
<template> <template v-if="videoPlayList.length"> <template v-for="(item, index) in videoPlayList"> <VideosPlay :data="item" :index="index" /> </template> </template> <div class="box"> <div class="top-select"> <el-select v-model="selectedLayer" placeholder="影像图层" class="select-1" :show-arrow="false" clearable @change="handleLayerChange" @clear="clearLayer" > <el-option v-for="(item, index) in layers" :key="item.id" :label="item.title" :value="item.id" /> </el-select> <el-select v-model="baseMap" placeholder="矢量地图" :show-arrow="false" class="select-2" @change="handleBaseMapChange" value-key="id" multiple collapse-tags > <el-option v-for="item in baseMapList" :key="item.name" :label="item.name" :value="item" /> </el-select> <el-select v-model="selectedTile" placeholder="实景三维" class="select-2" @change="handle3dSwitchChange" multiple collapse-tags :show-arrow="false" value-key="id" > <el-option v-for="tile in tileList" :key="tile.id" :label="tile.title" :value="tile" /> </el-select> <el-select v-model="selectedCommunity" placeholder="动态监测" class="select-3" @change="handleCommunityChange" :show-arrow="false" > <el-option v-for="community in communityList" :key="community.name" :label="community.name" :value="community.name" /> </el-select> </div> </div> <!-- 坐标系转换弹窗 --> <el-dialog v-model="showCoordinateModal" title="坐标系转换" width="400px" @close="resetCoordinateForm" > <el-form :model="coordForm" label-width="100px"> <!-- 源坐标系下拉菜单 --> <el-form-item label="源坐标系"> <el-select v-model="coordForm.source" placeholder="请选择源坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <!-- 目标坐标系下拉菜单 --> <el-form-item label="目标坐标系"> <el-select v-model="coordForm.target" placeholder="请选择目标坐标系" clearable class="coord-select" > <el-option label="WGS84" value="WGS84"></el-option> <el-option label="GCJ02(火星)" value="GCJ02"></el-option> <el-option label="BD09(百度)" value="BD09"></el-option> </el-select> </el-form-item> <el-form-item label="经度"> <el-input v-model.number="coordForm.lng" placeholder="输入经度" clearable ></el-input> </el-form-item> <el-form-item label="纬度"> <el-input v-model.number="coordForm.lat" placeholder="输入纬度" clearable ></el-input> </el-form-item> <el-form-item label="转换结果"> <el-input :value="coordForm.result" readonly placeholder="转换结果将显示在这里" ></el-input> </el-form-item> </el-form> <template #footer> <el-button @click="showCoordinateModal = false">取消</el-button> <el-button type="primary" @click="convertCoordinates">转换</el-button> </template> </el-dialog> </template> <script setup lang="ts"> import { onMounted, ref, onUnmounted } from "vue"; import { $prototype } from "../../main.ts"; import { getVeidoDetail } from "@/service/index"; import { ElMessage } from "element-plus"; import MVTImageryProvider from "mvt-imagery-provider"; import "/public/lib/video/mpegts/mpegts.js"; import "/public/img/div-graphic/divGraphic.css"; import { vectorLayes } from "@/config/index.ts"; import VideosPlay from "@/components/video/index.vue"; import { RefreshLeft } from "@element-plus/icons-vue"; var viewer: any; const selectedLayer = ref("baseImagery"); const selectedTile = ref([]); const selectedCommunity = ref(""); const baseMap = ref([]); const videoPlayList = ref([]); const addedTilesets = ref<Record<string, Cesium.Cesium3DTileset[]>>({}); const addedMvtLayers = ref<Record<string, Cesium.ImageryLayer[]>>({}); // 坐标系转换相关 const showCoordinateModal = ref(false); const coordForm = ref({ source: "", // 源坐标系 target: "", // 目标坐标系 lng: 0, // 经度 lat: 0, // 纬度 result: "" // 转换结果 }); const layers = [ { id: "baseImagery", title: "卫星" }, { id: "zhuzhou_beidou:GF01", title: "高分1号卫星遥感影像" }, { id: "zhuzhou_beidou:GF02", title: "高分2号卫星遥感影像" }, { id: "zhuzhou_beidou:GF06", title: "高分6号卫星遥感影像" }, { id: "zhuzhou_beidou:GF07", title: "高分7号卫星遥感影像" }, { id: "zhuzhou_beidou:lkyx", title: "渌口区影像" }, ]; const tileList = [ { id: "tile1", url: [ "http://124.232.190.30:9000/proxy/pk1725973637070/map/3dmode/20220312-1302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973591120/map/3dmode/20220312-1301/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973529125/map/3dmode/2022022101/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973404863/map/3dmode/2022011302/tileset.json", "http://124.232.190.30:9000/proxy/pk1725973226672/map/3dmode/20220312/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952405569/map/3dmode/20220221/tileset.json", "http://124.232.190.30:9000/proxy/pk1725952315227/map/3dmode/20220220/tileset.json", ], title: "会展中心", }, { id: "tile2", url: [ "http://124.232.190.30:9000/proxy/pk1725804650206/map/3dmode/hhhg/tileset.json", ], title: "园区", }, ]; const communityList = [ { name: "铁塔视频" }, ]; const baseMapList = [ { id: "geomeg", name: "基础地图", url: "http://124.232.190.30:3011//yjy_pbf/{z}/{x}/{y}.pbf", type: "fill" }, { id: "lukou_farmland", name: "耕地", url: "http://124.232.190.30:9059/lukou_farmland/{z}/{x}/{y}", type: "fill" }, { id: "lukou_ecology", name: "生态", url: "http://124.232.190.30:9059/lukou_ecology/{z}/{x}/{y}", type: "fill" }, { id: "natural_", name: "自然区", url: "http://124.232.190.30:9059/natural_/{z}/{x}/{y}", type: "fill" }, { id: "lushui_river", name: "渌水流", url: "http://124.232.190.30:9059/lushui_river/{z}/{x}/{y}", type: "fill" }, { id: "mishui_river", name: "洣水流", url: "http://124.232.190.30:9059/mishui_river/{z}/{x}/{y}", type: "fill" }, ]; const sprite = "http://124.232.190.67:5432/sprite/sprite"; const glyphs = "http://124.232.190.67:5432/font/mapbox_glyphs/{fontstack}/{range}.pbf"; const baseMapUrl = "http://124.232.190.30:3011//yjy_pbf/layers.json"; // 坐标系转换工具类 const CoordinateConverter = { a: 6378245.0, ee: 0.006693421622965943, // 判断是否在国内 outOfChina(lng: number, lat: number): boolean { return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271); }, // 纬度转换 transformLat(x: number, y: number): number { let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; return ret; }, // 经度转换 transformLng(x: number, y: number): number { let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; return ret; }, // WGS84转GCJ02 wgs84ToGcj02(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); return [lng + dLng, lat + dLat]; }, // GCJ02转WGS84 gcj02ToWgs84(lng: number, lat: number): [number, number] { if (this.outOfChina(lng, lat)) return [lng, lat]; let dLat = this.transformLat(lng - 105.0, lat - 35.0); let dLng = this.transformLng(lng - 105.0, lat - 35.0); const radLat = lat / 180.0 * Math.PI; let magic = Math.sin(radLat); magic = 1 - this.ee * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); const mgLat = lat + dLat; const mgLng = lng + dLng; return [lng * 2 - mgLng, lat * 2 - mgLat]; }, // GCJ02转BD09 gcj02ToBd09(lng: number, lat: number): [number, number] { const x = lng; const y = lat; const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006]; }, // BD09转GCJ02 bd09ToGcj02(lng: number, lat: number): [number, number] { const x = lng - 0.0065; const y = lat - 0.006; const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI * 3000.0 / 180.0); const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI * 3000.0 / 180.0); return [z * Math.cos(theta), z * Math.sin(theta)]; }, // WGS84转BD09 wgs84ToBd09(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.wgs84ToGcj02(lng, lat); return this.gcj02ToBd09(gcjLng, gcjLat); }, // BD09转WGS84 bd09ToWgs84(lng: number, lat: number): [number, number] { const [gcjLng, gcjLat] = this.bd09ToGcj02(lng, lat); return this.gcj02ToWgs84(gcjLng, gcjLat); } }; // 执行坐标系转换 function convertCoordinates() { const { source, target, lng, lat } = coordForm.value; // 验证输入 if (!source || !target) { ElMessage.warning('请选择源坐标系和目标坐标系'); return; } if (source === target) { ElMessage.info('源坐标系与目标坐标系相同,无需转换'); coordForm.value.result = `经度: ${lng.toFixed(6)}, 纬度: ${lat.toFixed(6)}`; return; } if (!lng || !lat || isNaN(lng) || isNaN(lat)) { ElMessage.warning('请输入有效的经纬度'); return; } if (lng < -180 || lng > 180 || lat < -90 || lat > 90) { ElMessage.warning('经纬度超出有效范围'); return; } // 执行转换 let result: [number, number] = [0, 0]; switch (true) { case source === "WGS84" && target === "GCJ02": result = CoordinateConverter.wgs84ToGcj02(lng, lat); break; case source === "GCJ02" && target === "WGS84": result = CoordinateConverter.gcj02ToWgs84(lng, lat); break; case source === "GCJ02" && target === "BD09": result = CoordinateConverter.gcj02ToBd09(lng, lat); break; case source === "BD09" && target === "GCJ02": result = CoordinateConverter.bd09ToGcj02(lng, lat); break; case source === "WGS84" && target === "BD09": const gcj = CoordinateConverter.wgs84ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToBd09(gcj[0], gcj[1]); break; case source === "BD09" && target === "WGS84": const gcj2 = CoordinateConverter.bd09ToGcj02(lng, lat); result = CoordinateConverter.gcj02ToWgs84(gcj2[0], gcj2[1]); break; default: ElMessage.error("不支持的转换类型"); return; } coordForm.value.result = `经度: ${result[0].toFixed(6)}, 纬度: ${result[1].toFixed(6)}`; } // 重置转换表单 function resetCoordinateForm() { coordForm.value = { source: "", target: "", lng: 0, lat: 0, result: "" }; } // 基础地图切换处理 function handleBaseMapChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const mvtsToRemove = Object.keys(addedMvtLayers.value).filter( (mvtId) => !currentSelectedIds.includes(mvtId) ); mvtsToRemove.forEach((mvtId) => { const layersToRemove = addedMvtLayers.value[mvtId]; if (layersToRemove && layersToRemove.length > 0) { layersToRemove.forEach((layer) => { try { const layers = viewer.imageryLayers._layers; for (let i = layers.length - 1; i >= 0; i--) { if (layers[i]._imageryProvider?.id === mvtId) { viewer.imageryLayers.remove(layers[i]); } } } catch (e) { console.error("Error removing MVT layer:", e); } }); delete addedMvtLayers.value[mvtId]; } }); items.forEach((item: any) => { if (!addedMvtLayers.value[item.id] || addedMvtLayers.value[item.id].length === 0) { addedMvtLayers.value[item.id] = []; loadVectorMvt(item.url, item.id, item.type); } }); } // 视频关闭事件监听 $prototype.emitter.on("video-list-play-close", (_id) => { videoPlayList.value = videoPlayList.value.filter((v) => v.id != _id); }); // 加载矢量地图 async function loadVectorMvt(data, layerName, type) { var tt = { name: "maplibres_yw", type: "vector", tiles: [data], bounds: [-180, -85.051129, 180, 85.051129], scheme: "xyz", }; var layersMapbox = []; const sourcesMapbox: any = {}; if (layerName == "geomeg") { await fetch(baseMapUrl) .then((response) => response.json()) .then((data) => { layersMapbox = JSON.parse(JSON.stringify(data.layers)); }); } else if (vectorLayes[layerName] == undefined) { const currentLayers = JSON.parse(JSON.stringify(vectorLayes[layerName])); currentLayers["id"] = currentLayers["id"] + layerName; currentLayers["source-layer"] = layerName; currentLayers["source"] = layerName; layersMapbox.push(currentLayers); } else { layersMapbox = JSON.parse(JSON.stringify(vectorLayes[layerName])); } sourcesMapbox[layerName] = tt; var exampleStyle = { id: data.id, name: "MapLibre", zoom: 10, layers: layersMapbox, bearing: 0, sources: sourcesMapbox, version: 8, metadata: { "maptiler:copyright": "cxwl" }, }; exampleStyle.glyphs = glyphs; exampleStyle.sprite = sprite; let provider = new MVTImageryProvider({ style: exampleStyle }); provider.id = layerName; viewer.imageryLayers.addImageryProvider(provider); addedMvtLayers.value[layerName].push(provider); if (layerName === "lukou_farmland" || layerName === "lukou_ecology") { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.159047, 27.721148, 3270), duration: 3, }); } else { viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.490927, 27.048641, 406000), duration: 3, }); } } // 动态监测处理 var videoData = [113.182301, 27.971201]; async function handleCommunityChange(item: any) { if (item == "铁塔视频") { var data = await getVeidoDetail(); if (data.data != null) { addRandomGraphicByCount(videoData, data.data); } else { ElMessage.error(data.message); } } } // 添加铁塔标记 function addRandomGraphicByCount(position, url) { viewer.entities.add({ id: "tietaId", beof: "铁塔视频", name: "铁塔视频001", position: Cesium.Cartesian3.fromDegrees(position[0], position[1]), billboard: { image: "img/marker/mark-spjk.png", width: 30, height: 115, scale: 1.0, color: Cesium.Color.WHITE, eyeOffset: new Cesium.Cartesian3(0, 0, -10), }, label: { text: "铁塔视频", font: "14px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -30), }, properties: { capacityResourceName: "铁塔视频", url: url, name: "铁塔视频", id: "tieta_001", }, }); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(position[0], position[1], 10000), duration: 3, }); } // 3D模型切换处理 function handle3dSwitchChange(items: any) { const currentSelectedIds = items.map((item: any) => item.id); const tilesToRemove = Object.keys(addedTilesets.value).filter( (tileId) => !currentSelectedIds.includes(tileId) ); tilesToRemove.forEach((tileId) => { addedTilesets.value[tileId].forEach((tileset) => { try { if (tileset && !tileset.isDestroyed()) { tileset.destroy(); } viewer.scene.primitives.remove(tileset); } catch (e) { console.error("Error removing tileset:", e); } }); delete addedTilesets.value[tileId]; }); items.forEach((item: any) => { if (!addedTilesets.value[item.id]) { addedTilesets.value[item.id] = []; item.url.forEach((url: string) => { const tileset = new Cesium.Cesium3DTileset({ url: url, skipLevelOfDetail: true, skipScreenSpaceErrorFactor: 16, baseScreenSpaceError: 1024, maximumScreenSpaceError: 10, immediatelyLoadDesiredLevelOfDetail: false, loadSiblings: false, cullWithChildrenBounds: true, cullRequestsWhileMoving: true, cullRequestsWhileMovingMultiplier: 10, preloadWhenHidden: true, preferLeaves: true, maximumMemoryUsage: 2048, progressiveResolutionHeightFraction: 0.5, dynamicScreenSpaceErrorDensity: 0.5, dynamicScreenSpaceErrorFactor: 1, dynamicScreenSpaceError: false, }); var heightOffset = 0; if (url.indexOf("20220220") >= 0) heightOffset = -32; else if (url.indexOf("2022022101") >= 0) heightOffset = -50.4; tileset.readyPromise .then((palaceTileset) => { viewer.scene.primitives.add(palaceTileset); addedTilesets.value[item.id].push(palaceTileset); const boundingSphere = palaceTileset.boundingSphere; const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0); const offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset); const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3()); palaceTileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, heightOffset + 10000 ), duration: 3, }); }) .catch((error) => { console.error("Error loading tileset:", error); }); }); } }); } // 影像图层切换处理 var currentImageryLayer: Cesium.ImageryLayer | null = null; var src; function handleLayerChange(val: any) { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } if (!val) return; if (val === "baseImagery") { addImage(val); } if (val === "zhuzhou_beidou:GF07" || val === "zhuzhou_beidou:lkyx") { src = "EPSG:4326"; } else if (val !== "baseImagery") { src = "EPSG:4326x2"; } var imageryProvider = new Cesium.WebMapTileServiceImageryProvider({ url: "http://124.232.190.14:3013/geoserver/gwc/service/wmts", layer: val, format: "image/png", style: "", tileMatrixSetID: src, maximumLevel: 18, tilingScheme: new Cesium.GeographicTilingScheme({ numberOfLevelZeroTilesX: 2, numberOfLevelZeroTilesY: 1, }), tileMatrixLabels: [...Array(18).keys()].map((level) => (src + ":" + level).toString() ), }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider); currentImageryLayer.id = val; } // 添加基础影像 async function addImage(val: any) { var rightImageProvider = new Cesium.UrlTemplateImageryProvider({ name: "影像图", type: "xyz", layer: val, url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png", minimumLevel: 1, maximumLevel: 17, crs: "EPSG:3857", }); currentImageryLayer = viewer.imageryLayers.addImageryProvider(rightImageProvider); currentImageryLayer.id = val; rightImageProvider.splitDirection = Cesium.SplitDirection.right; } // 清除影像图层 function clearLayer() { if (currentImageryLayer) { viewer.imageryLayers.remove(currentImageryLayer); currentImageryLayer = null; } selectedLayer.value = ""; } // 组件挂载 onMounted(async () => { viewer = $prototype.$map; await addImage("baseImagery"); const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); const scene = $prototype.$map.scene; const ellipsoid = scene.globe.ellipsoid; handler.setInputAction(function (click) { const pick = $prototype.$map.scene.pick(click.position); const cartesians = $prototype.$map.camera.pickEllipsoid(click.position, ellipsoid); var data = null; if (cartesians) { const cartographic = ellipsoid.cartesianToCartographic(cartesians); const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6); const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6); data = { longitude: longitude, latitude: latitude }; console.log(longitude + "," + latitude); } if (pick && pick.primitive._imageId != undefined && pick.primitive._imageId.indexOf("mark-spjk") >= 0) { var obj = pick.id._properties; videoPlayList.value.push({ name: obj.name, url: obj.url, id: obj.id }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }); // 组件卸载 onUnmounted(() => { Object.values(addedTilesets.value).forEach((tilesets) => { tilesets.forEach((tileset) => { viewer.scene.primitives.remove(tileset); }); }); addedTilesets.value = {}; }); </script> <style lang="scss" scoped> .box { position: absolute; top: 15%; right: 80px; overflow: hidden; } .top-select { display: flex; align-items: center; justify-content: center; gap: 0px; } .select-1, .select-2, .select-3 { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border-radius: 2px; border: 1px solid #00f0f87f; } .select-1 { width: 110px; border-radius: 5px 0 0 5px; } .select-2 { flex: 1; width: 90px; } .select-3 { flex: 1; width: 180px; } /* 坐标系转换按钮样式 */ .coordinate-btn { background: linear-gradient(180deg, #00f0f87f 10%, #173c6a 100%); border: 1px solid #00f0f87f; color: #b4fdff; border-radius: 0 5px 5px 0; padding: 0 15px; display: flex; align-items: center; gap: 5px; &:hover { background: linear-gradient(180deg, #00f0f8 10%, #173c6a 100%); color: #fff; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); } } /* 自定义Element组件样式 */ :deep(.el-select__wrapper) { background: transparent !important; box-shadow: none !important; } :deep(.el-select__caret) { color: #3cffff; } :deep(.el-select__placeholder), :deep(.el-select__selected-item), :deep(.el-select-dropdown__item) { color: #b4fdff !important; } :deep(.el-tag.el-tag--info) { --el-tag-bg-color: #3cffff96 !important; } /* 确保下拉菜单正常显示 */ :deep(.el-select-dropdown) { display: block !important; background: rgba(1, 28, 82, 0.8) !important; border: 1px solid #00f0f87f !important; z-index: 9999 !important; } :deep(.el-select-dropdown__item) { color: #b4fdff !important; &:hover { background: rgba(0, 240, 248, 0.2) !important; } &.selected { background: rgba(0, 240, 248, 0.3) !important; } } </style> <style lang="scss"> /* 全局样式保持不变 */ .el-select-dropdown__item { color: #b4fdff !important; } .el-select__popper.el-popper { border: 1px solid #3f3f41 !important; background: rgba(1, 28, 82, 0.8) !important; } .el-select-dropdown { border: none !important; background: rgba(1, 28, 82, 0.8) !important; &::-webkit-scrollbar { width: 6px; height: 6px; } &::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 3px; } &::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.3); border-radius: 3px; &:hover { background: rgba(255, 255, 255, 0.4); } } } .el-select-dropdown__item.is-hovering { border: none !important; background: rgba(1, 28, 82, 0.8) !important; } .is-focus .el-select__wrapper { box-shadow: none !important; } /* ================= 坐标系转换弹窗样式优化 ================= */ .coordinate-dialog { .el-dialog__headerbtn .el-dialog__close { color: #b4fdff !important; &:hover { color: #fff !important; } } /* 内容区样式 */ .el-dialog__body { padding: 20px; background: transparent; } /* 表单样式 */ .coord-form { .el-form-item { margin-bottom: 20px; } .el-form-item__label { color: #b4fdff; font-weight: bold; } /* 输入框样式 */ .el-input { .el-input__wrapper { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(0, 240, 248, 0.5); box-shadow: 0 0 5px rgba(0, 240, 248, 0.2) inset; color: #b4fdff; border-radius: 4px; transition: all 0.3s; &:hover { border-color: #00f0f8; box-shadow: 0 0 8px rgba(0, 240, 248, 0.4) inset; } &.is-focus { border-color: #00f0f8; box-shadow: 0 0 12px rgba(0, 240, 248, 0.6) inset; } } .el-input__inner { color: #b4fdff; &::placeholder { color: rgba(180, 253, 255, 0.6); } } } /* 结果输入框特殊样式 */ .el-form-item:last-child .el-input__wrapper { background: rgba(0, 240, 248, 0.1) !important; border: 1px solid rgba(0, 240, 248, 0.8) !important; } } /* 底部按钮区 */ .el-dialog__footer { padding: 15px 20px; background: linear-gradient(90deg, rgba(23, 60, 106, 0.5), rgba(0, 240, 248, 0.2)); border-top: 1px solid rgba(0, 240, 248, 0.3); border-radius: 0 0 8px 8px; } /* 按钮样式 */ .cancel-btn { background: transparent; border: 1px solid rgba(0, 240, 248, 0.5); color: #b4fdff; &:hover { background: rgba(0, 240, 248, 0.2); border-color: #00f0f8; color: #fff; } } .convert-btn { background: linear-gradient(90deg, rgba(0, 240, 248, 0.7), rgba(23, 60, 106, 0.9)); border: none; color: #fff; font-weight: bold; box-shadow: 0 0 10px rgba(0, 240, 248, 0.5); &:hover { background: linear-gradient(90deg, rgba(0, 240, 248, 0.9), rgba(23, 60, 106, 1)); box-shadow: 0 0 15px rgba(0, 240, 248, 0.7); transform: translateY(-1px); } &:active { transform: translateY(1px); } } } </style>如上所示代码,其中我想知道卫星,矢量地图这些是使用了element的哪些组件布局,
最新发布
07-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值