| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>3D 地形标记点测试</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- background: #1a1a2e;
- color: #eee;
- min-height: 100vh;
- }
- .container {
- display: flex;
- height: 100vh;
- }
- .sidebar {
- width: 320px;
- background: #16213e;
- padding: 20px;
- display: flex;
- flex-direction: column;
- gap: 16px;
- border-right: 1px solid #0f3460;
- overflow-y: auto;
- }
- .iframe-wrapper {
- flex: 1;
- background: #000;
- }
- iframe {
- width: 100%;
- height: 100%;
- border: none;
- }
- h2 {
- font-size: 18px;
- color: #00d9ff;
- margin-bottom: 8px;
- }
- .section {
- background: #1a1a2e;
- border-radius: 8px;
- padding: 16px;
- }
- .section h3 {
- font-size: 14px;
- color: #00d9ff;
- margin-bottom: 12px;
- text-transform: uppercase;
- letter-spacing: 1px;
- }
- .btn {
- display: block;
- width: 100%;
- padding: 10px 16px;
- margin-bottom: 8px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-size: 13px;
- font-weight: 500;
- transition: all 0.2s;
- }
- .btn-primary {
- background: #00d9ff;
- color: #1a1a2e;
- }
- .btn-primary:hover {
- background: #00b8d9;
- }
- .btn-success {
- background: #00c853;
- color: #fff;
- }
- .btn-success:hover {
- background: #00a043;
- }
- .btn-danger {
- background: #ff5252;
- color: #fff;
- }
- .btn-danger:hover {
- background: #d32f2f;
- }
- .btn-warning {
- background: #ffab00;
- color: #1a1a2e;
- }
- .btn-warning:hover {
- background: #ff8f00;
- }
- .btn-secondary {
- background: #5c6bc0;
- color: #fff;
- }
- .btn-secondary:hover {
- background: #3f51b5;
- }
- .form-group {
- margin-bottom: 12px;
- }
- .form-group label {
- display: block;
- font-size: 12px;
- color: #888;
- margin-bottom: 4px;
- }
- .form-group input {
- width: 100%;
- padding: 8px 12px;
- border: 1px solid #0f3460;
- border-radius: 4px;
- background: #0f3460;
- color: #eee;
- font-size: 13px;
- }
- .form-group input:focus {
- outline: none;
- border-color: #00d9ff;
- }
- .log-section {
- flex: 1;
- min-height: 200px;
- }
- .log-container {
- background: #0a0a15;
- border-radius: 4px;
- padding: 10px;
- height: 200px;
- overflow-y: auto;
- font-family: 'Monaco', 'Menlo', monospace;
- font-size: 11px;
- }
- .log-entry {
- padding: 4px 0;
- border-bottom: 1px solid #1a1a2e;
- word-break: break-all;
- }
- .log-entry.send {
- color: #00c853;
- }
- .log-entry.receive {
- color: #00d9ff;
- }
- .log-entry.click {
- color: #ffab00;
- }
- .log-entry.error {
- color: #ff5252;
- }
- .color-picker {
- display: flex;
- gap: 8px;
- flex-wrap: wrap;
- }
- .color-btn {
- width: 28px;
- height: 28px;
- border-radius: 4px;
- border: 2px solid transparent;
- cursor: pointer;
- }
- .color-btn.active {
- border-color: #fff;
- }
- </style>
- </head>
- <body>
- <div class="container">
- <div class="sidebar">
- <div class="section">
- <h2>3D 地形标记测试</h2>
- <p style="font-size: 12px; color: #888;">通过 iframe 消息控制地形标记点</p>
- </div>
- <div class="section">
- <h3>添加标记点</h3>
- <div class="form-group">
- <label>经度 (lon)</label>
- <input type="number" id="lon" value="113.725" step="0.001">
- </div>
- <div class="form-group">
- <label>纬度 (lat)</label>
- <input type="number" id="lat" value="24.570" step="0.001">
- </div>
- <div class="form-group">
- <label>高度 (alt)</label>
- <input type="number" id="alt" value="100" step="10">
- </div>
- <div class="form-group">
- <label>标题</label>
- <input type="text" id="title" value="测试点">
- </div>
- <div class="form-group">
- <label>类型</label>
- <select id="markerType" onchange="onTypeChange()" style="width: 100%; padding: 8px 12px; border: 1px solid #0f3460; border-radius: 4px; background: #0f3460; color: #eee; font-size: 13px;">
- <option value="">普通标记</option>
- <option value="video">视频 (video)</option>
- <option value="html">HTML (html)</option>
- <option value="device">设备 (device)</option>
- </select>
- </div>
- <!-- 通用字段 -->
- <div class="form-group">
- <label>内容</label>
- <input type="text" id="content" value="这是一个测试标记点">
- </div>
- <!-- video 字段 -->
- <div class="type-fields" id="videoFields" style="display:none">
- <div class="form-group">
- <label>视频 URL (videoUrl)</label>
- <input type="text" id="videoUrl" value="https://www.w3schools.com/html/mov_bbb.mp4">
- </div>
- <div class="form-group">
- <label>iframe URL (iframeUrl,优先级低于 videoUrl)</label>
- <input type="text" id="iframeUrl" value="">
- </div>
- </div>
- <!-- html 字段 -->
- <div class="type-fields" id="htmlFields" style="display:none">
- <div class="form-group">
- <label>HTML 内容 (htmlContent)</label>
- <input type="text" id="htmlContent" value="<div style='color:#22c55e'>自定义 HTML</div>">
- </div>
- <div class="form-group">
- <label>HTML 页面 URL (htmlUrl,优先级低于 htmlContent)</label>
- <input type="text" id="htmlUrl" value="">
- </div>
- </div>
- <!-- device 字段 -->
- <div class="type-fields" id="deviceFields" style="display:none">
- <div class="form-group">
- <label>状态 (status)</label>
- <input type="text" id="status" value="正常">
- </div>
- <div class="form-group">
- <label>指标 (metrics JSON)</label>
- <input type="text" id="metrics" value='[{"label":"温度","value":24,"unit":"°C"},{"label":"湿度","value":62,"unit":"%"}]'>
- </div>
- </div>
- <div class="form-group">
- <label>颜色</label>
- <div class="color-picker">
- <div class="color-btn active" style="background: #ff4444" data-color="#ff4444"></div>
- <div class="color-btn" style="background: #44ff88" data-color="#44ff88"></div>
- <div class="color-btn" style="background: #4488ff" data-color="#4488ff"></div>
- <div class="color-btn" style="background: #ffaa44" data-color="#ffaa44"></div>
- <div class="color-btn" style="background: #aa44ff" data-color="#aa44ff"></div>
- <div class="color-btn" style="background: #ffffff" data-color="#ffffff"></div>
- </div>
- </div>
- <button class="btn btn-primary" onclick="addMarker()">添加标记点</button>
- <button class="btn btn-success" onclick="addRandomMarker()">添加随机标记</button>
- </div>
- <div class="section">
- <h3>标记点管理</h3>
- <button class="btn btn-warning" onclick="flyToMarker()">飞行到标记点</button>
- <button class="btn btn-danger" onclick="clearMarkers()">清空所有标记</button>
- </div>
- <div class="section log-section">
- <h3>消息日志</h3>
- <button class="btn btn-secondary" onclick="clearLog()">清空日志</button>
- <div class="log-container" id="logContainer"></div>
- </div>
- </div>
- <div class="iframe-wrapper">
- <iframe id="terrainFrame" src="http://192.168.8.48:5173" allow="fullscreen"></iframe>
- </div>
- </div>
- <script>
- const iframe = document.getElementById('terrainFrame')
- let selectedColor = '#ff4444'
- // 颜色选择
- document.querySelectorAll('.color-btn').forEach(btn => {
- btn.addEventListener('click', () => {
- document.querySelectorAll('.color-btn').forEach(b => b.classList.remove('active'))
- btn.classList.add('active')
- selectedColor = btn.dataset.color
- })
- })
- // 类型切换
- function onTypeChange() {
- const type = document.getElementById('markerType').value
- document.querySelectorAll('.type-fields').forEach(el => el.style.display = 'none')
- if (type) document.getElementById(type + 'Fields').style.display = 'block'
- }
- // 添加标记点
- function addMarker() {
- const markerType = document.getElementById('markerType').value
- const data = {
- type: 'addMarker',
- lon: parseFloat(document.getElementById('lon').value),
- lat: parseFloat(document.getElementById('lat').value),
- alt: parseFloat(document.getElementById('alt').value),
- title: document.getElementById('title').value,
- content: document.getElementById('content').value,
- color: selectedColor,
- markerType: markerType
- }
- if (markerType === 'video') {
- const videoUrl = document.getElementById('videoUrl').value.trim()
- const iframeUrl = document.getElementById('iframeUrl').value.trim()
- if (videoUrl) data.videoUrl = videoUrl
- if (iframeUrl) data.iframeUrl = iframeUrl
- } else if (markerType === 'html') {
- const htmlContent = document.getElementById('htmlContent').value.trim()
- const htmlUrl = document.getElementById('htmlUrl').value.trim()
- if (htmlContent) data.htmlContent = htmlContent
- if (htmlUrl) data.htmlUrl = htmlUrl
- } else if (markerType === 'device') {
- data.status = document.getElementById('status').value
- try {
- const metricsStr = document.getElementById('metrics').value.trim()
- if (metricsStr) data.metrics = JSON.parse(metricsStr)
- } catch (e) {
- log('error', '指标 JSON 解析失败: ' + e.message)
- return
- }
- }
- iframe.contentWindow.postMessage(data, '*')
- log('send', `添加标记 [${markerType || '默认'}]: ${data.title} (${data.lon}, ${data.lat})`)
- }
- // 添加随机标记
- function addRandomMarker() {
- const lon = 113.720 + Math.random() * 0.015
- const lat = 24.565 + Math.random() * 0.015
- const colors = ['#ff4444', '#44ff88', '#4488ff', '#ffaa44', '#aa44ff']
- const types = ['video', 'device', 'html', '']
- const type = types[Math.floor(Math.random() * types.length)]
- const titles = {
- video: '视频监控',
- device: '设备监测',
- html: 'HTML面板',
- '': '普通标记'
- }
- const data = {
- type: 'addMarker',
- lon: lon,
- lat: lat,
- alt: Math.floor(Math.random() * 200),
- title: titles[type] + ' #' + Math.floor(Math.random() * 100),
- content: `随机标记点 #${Math.floor(Math.random() * 1000)}`,
- color: colors[Math.floor(Math.random() * colors.length)],
- markerType: type
- }
- if (type === 'video') {
- data.videoUrl = 'https://www.w3schools.com/html/mov_bbb.mp4'
- } else if (type === 'html') {
- data.htmlContent = '<div style="color:#22c55e;font-weight:600">随机 HTML 内容</div>'
- } else if (type === 'device') {
- data.status = Math.random() > 0.5 ? '正常' : '警告'
- data.metrics = [
- { label: '温度', value: Math.floor(Math.random() * 40), unit: '°C' },
- { label: '湿度', value: Math.floor(Math.random() * 100), unit: '%' }
- ]
- }
- iframe.contentWindow.postMessage(data, '*')
- log('send', `添加随机标记 [${type || '默认'}]: ${data.title} (${data.lon.toFixed(4)}, ${data.lat.toFixed(4)})`)
- }
- // 飞行到标记点
- function flyToMarker() {
- const data = {
- type: 'flyTo',
- lon: parseFloat(document.getElementById('lon').value),
- lat: parseFloat(document.getElementById('lat').value)
- }
- iframe.contentWindow.postMessage(data, '*')
- log('send', `飞行到: (${data.lon}, ${data.lat})`)
- }
- // 清空所有标记
- function clearMarkers() {
- iframe.contentWindow.postMessage({ type: 'clearMarkers' }, '*')
- log('send', '清空所有标记')
- }
- // 日志
- function log(type, message) {
- const container = document.getElementById('logContainer')
- const entry = document.createElement('div')
- entry.className = `log-entry ${type}`
- const time = new Date().toLocaleTimeString()
- entry.textContent = `[${time}] ${message}`
- container.insertBefore(entry, container.firstChild)
- }
- // 清空日志
- function clearLog() {
- document.getElementById('logContainer').innerHTML = ''
- }
- // 监听来自 iframe 的消息
- window.addEventListener('message', (event) => {
- const data = event.data
- if (data.type === 'markerClick') {
- log('click', `点击标记 [${data.markerType || '默认'}]: ${data.title} (${data.lon}, ${data.lat})`)
- }
- })
- </script>
- </body>
- </html>
|