最新产品
This commit is contained in:
438
index.html
Normal file
438
index.html
Normal file
@ -0,0 +1,438 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cesium 多资源整合加载平台</title>
|
||||
<!-- 引入Cesium库(使用1.116稳定版本) -->
|
||||
<script src="https://cesium.com/downloads/cesiumjs/releases/1.116/Build/Cesium/Cesium.js"></script>
|
||||
<link href="https://cesium.com/downloads/cesiumjs/releases/1.116/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
html, body, #cesiumContainer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 控制面板样式 */
|
||||
.control-panel {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.15);
|
||||
z-index: 100;
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
/* 表单标题 */
|
||||
.panel-title {
|
||||
margin: 0 0 15px;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 表单分组样式 */
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
/* 输入框、选择框样式 */
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: #0070f3;
|
||||
box-shadow: 0 0 0 2px rgba(0, 112, 243, 0.1);
|
||||
}
|
||||
|
||||
/* 经纬度输入行布局 */
|
||||
.coord-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.coord-group .form-group {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #0070f3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0051aa;
|
||||
}
|
||||
|
||||
.btn-locate {
|
||||
background-color: #22c55e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-locate:hover {
|
||||
background-color: #16a34a;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
background-color: #f37000;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-clear:hover {
|
||||
background-color: #d96000;
|
||||
}
|
||||
|
||||
/* 状态提示样式 */
|
||||
.status {
|
||||
margin-top: 12px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
display: none; /* 默认隐藏 */
|
||||
}
|
||||
|
||||
.status-success {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
display: block; /* 成功时显示 */
|
||||
}
|
||||
|
||||
.status-error {
|
||||
background-color: #fdecea;
|
||||
color: #d32f2f;
|
||||
display: block; /* 错误时显示 */
|
||||
}
|
||||
|
||||
/* 鼠标经纬度提示框样式 */
|
||||
.latlng-tooltip {
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
pointer-events: none; /* 避免遮挡鼠标事件 */
|
||||
z-index: 1000; /* 确保在最上层显示 */
|
||||
opacity: 0; /* 默认透明 */
|
||||
transition: opacity 0.2s; /* 淡入淡出效果 */
|
||||
white-space: nowrap; /* 防止文本换行 */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Cesium 容器 -->
|
||||
<div id="cesiumContainer"></div>
|
||||
|
||||
<!-- 鼠标经纬度提示框 -->
|
||||
<div id="latlngTooltip" class="latlng-tooltip"></div>
|
||||
|
||||
<!-- 控制表单面板 -->
|
||||
<div class="control-panel">
|
||||
<h3 class="panel-title">Cesium 资源加载与定位</h3>
|
||||
|
||||
<!-- 基础地址输入项 -->
|
||||
<div class="form-group">
|
||||
<label for="baseUrl">基础地址(服务器根地址)</label>
|
||||
<input type="text" id="baseUrl" class="form-control"
|
||||
placeholder="例: http://192.168.110.25:8848"
|
||||
value="http://192.168.110.25:8848">
|
||||
</div>
|
||||
|
||||
<!-- 资源地址输入 -->
|
||||
<div class="form-group">
|
||||
<label for="resourceUrl">资源相对路径</label>
|
||||
<input type="text" id="resourceUrl" class="form-control"
|
||||
placeholder="例: 1.倾斜模型: data/clt/.../tileset.json 2.高程: terrain_pak 3.瓦片: tiles/{z}/{x}/{y}.png"
|
||||
value="/data/pak/8870a7a573dc621d7347457a5497df3b/{z}/{x}/{y}.png">
|
||||
</div>
|
||||
|
||||
<!-- 经纬度定位输入 -->
|
||||
<div class="coord-group">
|
||||
<div class="form-group">
|
||||
<label for="longitude">经度</label>
|
||||
<input type="text" id="longitude" class="form-control"
|
||||
placeholder="范围: -180 ~ 180" value="106.253200504443">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="latitude">纬度</label>
|
||||
<input type="text" id="latitude" class="form-control"
|
||||
placeholder="范围: -90 ~ 90" value="29.8500521523625">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮组 -->
|
||||
<div class="btn-group">
|
||||
<button id="loadBtn" class="btn btn-primary">加载资源</button>
|
||||
<button id="locateBtn" class="btn btn-locate">定位到经纬度</button>
|
||||
<button id="clearBtn" class="btn btn-clear">清除所有资源</button>
|
||||
</div>
|
||||
|
||||
<!-- 状态提示 -->
|
||||
<div id="status" class="status"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 1. 初始化Cesium核心配置
|
||||
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MGU0NGMwYS00ZDBkLTQzMDItYjc5Zi0zYTM1NDcwZGVjMmEiLCJpZCI6MTU1MTk5LCJpYXQiOjE2ODk4MTgzNTF9.V_eZ5KlAI9qmxsDivT6pMC3Pq6qLk0mXpBoe5C0Mm4g';
|
||||
|
||||
// 2. 创建Cesium Viewer(基础配置)
|
||||
const viewer = new Cesium.Viewer('cesiumContainer', {
|
||||
animation: false,
|
||||
timeline: false,
|
||||
vrButton: false,
|
||||
infoBox: false,
|
||||
selectionIndicator: false,
|
||||
homeButton: true,
|
||||
sceneModePicker: true,
|
||||
navigationHelpButton: true,
|
||||
fullscreenButton: true,
|
||||
imageryProvider: false
|
||||
});
|
||||
|
||||
// 隐藏Cesium版权信息
|
||||
viewer._cesiumWidget._creditContainer.style.display = 'none';
|
||||
|
||||
// 3. 全局变量
|
||||
let loadedResource = { type: null, instance: null };
|
||||
const statusEl = document.getElementById('status');
|
||||
const latlngTooltip = document.getElementById('latlngTooltip');
|
||||
|
||||
// 4. 工具函数: 拼接资源URL
|
||||
function getFullResourceUrl() {
|
||||
const baseUrl = document.getElementById('baseUrl').value.trim();
|
||||
const resourceUrl = document.getElementById('resourceUrl').value.trim();
|
||||
if (!resourceUrl) return '';
|
||||
if (!baseUrl) return resourceUrl;
|
||||
const baseUrlWithSlash = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
const cleanResourceUrl = resourceUrl.startsWith('/') ? resourceUrl.slice(1) : resourceUrl;
|
||||
return `${baseUrlWithSlash}${cleanResourceUrl}`;
|
||||
}
|
||||
|
||||
// 5. 工具函数: 识别资源类型
|
||||
function getResourceTypeByUrl(fullUrl) {
|
||||
const lowerUrl = fullUrl.toLowerCase();
|
||||
if (lowerUrl.includes('.png') || lowerUrl.includes('.jpg')) return 'imagery';
|
||||
if (lowerUrl.includes('tileset.json')) return 'tileset';
|
||||
if (lowerUrl.includes('pak')) return 'terrain';
|
||||
return null;
|
||||
}
|
||||
|
||||
// 6. 状态提示函数
|
||||
function showStatus(message, isSuccess = true) {
|
||||
statusEl.textContent = message;
|
||||
statusEl.className = 'status';
|
||||
statusEl.classList.add(isSuccess ? 'status-success' : 'status-error');
|
||||
if (isSuccess) {
|
||||
setTimeout(() => {
|
||||
statusEl.classList.remove('status-success');
|
||||
statusEl.style.display = 'none';
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 清除资源函数
|
||||
function clearLoadedResource() {
|
||||
if (!loadedResource.instance) return;
|
||||
switch (loadedResource.type) {
|
||||
case 'tileset':
|
||||
viewer.scene.primitives.remove(loadedResource.instance);
|
||||
showStatus('倾斜模型已清除');
|
||||
break;
|
||||
case 'imagery':
|
||||
viewer.imageryLayers.remove(loadedResource.instance);
|
||||
showStatus('二维瓦片已清除');
|
||||
break;
|
||||
case 'terrain':
|
||||
viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();
|
||||
viewer.scene.globe.depthTestAgainstTerrain = false;
|
||||
showStatus('高程模型已清除');
|
||||
break;
|
||||
}
|
||||
loadedResource = { type: null, instance: null };
|
||||
}
|
||||
|
||||
// 8. 资源加载函数
|
||||
async function loadResource() {
|
||||
const fullUrl = getFullResourceUrl();
|
||||
if (!fullUrl) {
|
||||
showStatus('请输入有效的资源相对路径', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const resourceType = getResourceTypeByUrl(fullUrl);
|
||||
if (!resourceType) {
|
||||
showStatus('无法识别资源类型、请检查路径是否包含tileset.json/pak/.png/.jpg', false);
|
||||
return;
|
||||
}
|
||||
|
||||
clearLoadedResource();
|
||||
|
||||
try {
|
||||
let instance;
|
||||
switch (resourceType) {
|
||||
case 'tileset':
|
||||
showStatus('正在加载倾斜模型...');
|
||||
instance = await Cesium.Cesium3DTileset.fromUrl(fullUrl);
|
||||
viewer.scene.primitives.add(instance);
|
||||
viewer.zoomTo(instance);
|
||||
showStatus('倾斜模型加载成功');
|
||||
break;
|
||||
case 'imagery':
|
||||
showStatus('正在加载二维瓦片...');
|
||||
const fileExtension = fullUrl.toLowerCase().includes('.png') ? 'png' : 'jpg';
|
||||
const provider = new Cesium.UrlTemplateImageryProvider({
|
||||
url: fullUrl,
|
||||
fileExtension: fileExtension,
|
||||
minimumLevel: 0,
|
||||
maximumLevel: 18,
|
||||
credit: '自定义二维瓦片'
|
||||
});
|
||||
instance = viewer.imageryLayers.addImageryProvider(provider);
|
||||
showStatus('二维瓦片加载成功');
|
||||
break;
|
||||
case 'terrain':
|
||||
showStatus('正在加载高程模型...');
|
||||
instance = await Cesium.CesiumTerrainProvider.fromUrl(fullUrl);
|
||||
viewer.terrainProvider = instance;
|
||||
viewer.scene.globe.depthTestAgainstTerrain = true;
|
||||
showStatus('高程模型加载成功');
|
||||
break;
|
||||
}
|
||||
loadedResource = { type: resourceType, instance: instance };
|
||||
} catch (error) {
|
||||
console.error('资源加载失败: ', error);
|
||||
const errorMsg = error.message.includes('404') ? '资源地址不存在(404)' :
|
||||
error.message.includes('CORS') ? '跨域访问被拒绝(CORS)' :
|
||||
'服务器连接失败或资源格式错误';
|
||||
showStatus(`资源加载失败: ${errorMsg}`, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 9. 经纬度定位函数
|
||||
function flyToCoordinate() {
|
||||
const lng = parseFloat(document.getElementById('longitude').value.trim());
|
||||
const lat = parseFloat(document.getElementById('latitude').value.trim());
|
||||
if (isNaN(lng) || isNaN(lat) || lng < -180 || lng > 180 || lat < -90 || lat > 90) {
|
||||
showStatus('请输入有效的经纬度(经度: -180~180、纬度: -90~90)', false);
|
||||
return;
|
||||
}
|
||||
viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromDegrees(lng, lat, 10000),
|
||||
duration: 2,
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(0),
|
||||
pitch: Cesium.Math.toRadians(-30),
|
||||
roll: 0
|
||||
}
|
||||
});
|
||||
showStatus(`已定位到经纬度: (${lng.toFixed(4)}, ${lat.toFixed(4)})`);
|
||||
}
|
||||
|
||||
// 10. 修复: 鼠标悬浮显示经纬度(支持地球+地形表面、避免NaN)
|
||||
function initLatlngTooltip() {
|
||||
const canvas = viewer.scene.canvas;
|
||||
|
||||
// 鼠标移动事件
|
||||
canvas.addEventListener('mousemove', (e) => {
|
||||
// 1. 先尝试获取地形表面坐标(优先、因为加载高程后更准确)
|
||||
const windowPosition = new Cesium.Cartesian2(e.clientX, e.clientY);
|
||||
let cartographic = null;
|
||||
|
||||
// 方法1: 从地形表面获取坐标(适用于加载了高程模型的场景)
|
||||
const ray = viewer.camera.getPickRay(windowPosition);
|
||||
if (ray) {
|
||||
const hitResult = viewer.scene.pickFromRay(ray);
|
||||
if (hitResult && hitResult.position) {
|
||||
cartographic = Cesium.Cartographic.fromCartesian(hitResult.position);
|
||||
}
|
||||
}
|
||||
|
||||
// 方法2: 如果地形获取失败、从椭球面获取(适用于无高程的场景)
|
||||
if (!cartographic) {
|
||||
cartographic = viewer.scene.camera.pickEllipsoid(windowPosition);
|
||||
}
|
||||
|
||||
// 3. 计算并显示经纬度(增加异常处理)
|
||||
if (cartographic && !isNaN(cartographic.longitude) && !isNaN(cartographic.latitude)) {
|
||||
const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
|
||||
const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
|
||||
// 显示经纬度(避免NaN)
|
||||
latlngTooltip.textContent = `经度: ${longitude} | 纬度: ${latitude}`;
|
||||
// 调整提示框位置(防止超出屏幕)
|
||||
const tooltipWidth = latlngTooltip.offsetWidth || 150; // 预估宽度
|
||||
const left = e.clientX + 10 > window.innerWidth - tooltipWidth
|
||||
? e.clientX - tooltipWidth - 10
|
||||
: e.clientX + 10;
|
||||
const top = e.clientY + 10 > window.innerHeight - 30
|
||||
? e.clientY - 30
|
||||
: e.clientY + 10;
|
||||
latlngTooltip.style.left = `${left}px`;
|
||||
latlngTooltip.style.top = `${top}px`;
|
||||
latlngTooltip.style.opacity = '1';
|
||||
} else {
|
||||
// 非地球表面时隐藏提示框
|
||||
latlngTooltip.style.opacity = '0';
|
||||
}
|
||||
});
|
||||
|
||||
// 鼠标离开画布时隐藏
|
||||
canvas.addEventListener('mouseleave', () => {
|
||||
latlngTooltip.style.opacity = '0';
|
||||
});
|
||||
}
|
||||
|
||||
// 11. 绑定按钮事件
|
||||
document.getElementById('loadBtn').addEventListener('click', loadResource);
|
||||
document.getElementById('locateBtn').addEventListener('click', flyToCoordinate);
|
||||
document.getElementById('clearBtn').addEventListener('click', () => {
|
||||
clearLoadedResource();
|
||||
if (viewer.imageryLayers.length > 0) {
|
||||
viewer.imageryLayers.removeAll();
|
||||
showStatus('所有影像图层已清除');
|
||||
}
|
||||
});
|
||||
|
||||
// 12. 初始化鼠标经纬度提示
|
||||
initLatlngTooltip();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user