QDAirPortTestSystemBackend/tools/map.html
2026-01-27 15:24:05 +08:00

303 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>机场路口地图</title>
<style>
body {
margin: 0;
padding: 20px;
background: #f0f0f0;
font-family: Arial, sans-serif;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
canvas {
border: 1px solid #ddd;
margin: 20px 0;
}
.legend {
margin-top: 20px;
padding: 10px;
background: #f8f8f8;
border-radius: 4px;
}
.legend-item {
margin: 5px 0;
display: flex;
align-items: center;
}
.legend-color {
width: 20px;
height: 20px;
margin-right: 10px;
border: 1px solid #999;
}
</style>
</head>
<body>
<div class="container">
<h1>机场路口地图</h1>
<canvas id="mapCanvas" width="1000" height="800"></canvas>
<div class="legend">
<h3>图例</h3>
<div class="legend-item">
<div class="legend-color" style="background: #666;"></div>
<span>道路</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #f00;"></div>
<span>路口</span>
</div>
</div>
</div>
<script>
// 路口坐标数据
const intersections = [
{point: "T1", longitude: 120.0868853, latitude: 36.35496367},
{point: "T2", longitude: 120.08502054, latitude: 36.35448347},
{point: "T3", longitude: 120.08341044, latitude: 36.35406879},
{point: "T4", longitude: 120.08558121, latitude: 36.35305878},
{point: "T5", longitude: 120.08400957, latitude: 36.35265197},
{point: "T6", longitude: 120.08649105, latitude: 36.35074527},
{point: "T7", longitude: 120.08562915, latitude: 36.35052372},
{point: "T8", longitude: 120.08676664, latitude: 36.35004529},
{point: "T9", longitude: 120.08520616, latitude: 36.34964473},
{point: "T10", longitude: 120.08710569, latitude: 36.34917893},
{point: "T11", longitude: 120.0873865, latitude: 36.3509885},
{point: "T12", longitude: 120.08603613, latitude: 36.35190217}
];
// 参考点
const referencePoint = {
latitude: 36.34807893,
longitude: 120.08201044
};
// 获取 Canvas 上下文
const canvas = document.getElementById('mapCanvas');
const ctx = canvas.getContext('2d');
// 计算坐标范围
let minLat = Math.min(...intersections.map(p => p.latitude));
let maxLat = Math.max(...intersections.map(p => p.latitude));
let minLon = Math.min(...intersections.map(p => p.longitude));
let maxLon = Math.max(...intersections.map(p => p.longitude));
// 添加边距
const margin = 0.0001;
minLat -= margin;
maxLat += margin;
minLon -= margin;
maxLon += margin;
// 计算中心纬度
const centerLat = (minLat + maxLat) / 2;
// 地球半径(米)
const EARTH_RADIUS = 6378137.0;
// 计算1度经度和纬度对应的实际距离
const metersPerLatDegree = (Math.PI / 180) * EARTH_RADIUS;
const metersPerLonDegree = metersPerLatDegree * Math.cos(centerLat * Math.PI / 180);
// 计算实际距离范围(米)
const totalWidthMeters = (maxLon - minLon) * metersPerLonDegree;
const totalHeightMeters = (maxLat - minLat) * metersPerLatDegree;
// 计算画布缩放比例,保持宽高比
const scale = Math.min(canvas.width / totalWidthMeters, canvas.height / totalHeightMeters);
// 坐标转换函数
function convertToCanvas(lon, lat) {
// 将经纬度转换为实际距离(米)
const x = (lon - minLon) * metersPerLonDegree;
const y = (lat - minLat) * metersPerLatDegree;
// 使用统一的缩放比例转换为画布坐标
const canvasX = x * scale;
const canvasY = canvas.height - (y * scale);
// 居中显示
const offsetX = (canvas.width - totalWidthMeters * scale) / 2;
const offsetY = (canvas.height - totalHeightMeters * scale) / 2;
return {
x: canvasX + offsetX,
y: canvasY - offsetY
};
}
// 绘制道路
function drawRoad(start, end) {
const startPos = convertToCanvas(start.longitude, start.latitude);
const endPos = convertToCanvas(end.longitude, end.latitude);
ctx.beginPath();
ctx.moveTo(startPos.x, startPos.y);
ctx.lineTo(endPos.x, endPos.y);
ctx.strokeStyle = '#666';
ctx.lineWidth = 3;
ctx.stroke();
}
// 绘制路口
function drawIntersection(intersection) {
const pos = convertToCanvas(intersection.longitude, intersection.latitude);
// 绘制圆点
ctx.beginPath();
ctx.arc(pos.x, pos.y, 5, 0, Math.PI * 2);
ctx.fillStyle = '#f00';
ctx.fill();
// 绘制标签
ctx.font = '12px Arial';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.fillText(intersection.point, pos.x, pos.y - 10);
}
// 计算 T2-T6 的旋转角度
const t2 = intersections.find(p => p.point === "T2");
const t6 = intersections.find(p => p.point === "T6");
const angle = Math.atan2(
convertToCanvas(t6.longitude, t6.latitude).y - convertToCanvas(t2.longitude, t2.latitude).y,
convertToCanvas(t6.longitude, t6.latitude).x - convertToCanvas(t2.longitude, t2.latitude).x
);
// 设置画布中心点
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// 清空画布
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制网格
const gridSize = 25; // 网格大小为25像素
ctx.beginPath();
ctx.strokeStyle = '#ccc';
ctx.lineWidth = 1;
// 绘制垂直线
for(let x = 0; x <= canvas.width; x += gridSize) {
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
}
// 绘制水平线
for(let y = 0; y <= canvas.height; y += gridSize) {
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
}
ctx.stroke();
// 保存当前状态
ctx.save();
// 将原点移到画布中心
ctx.translate(centerX, centerY);
// 旋转画布
ctx.rotate(-angle);
// 将原点移回去
ctx.translate(-centerX, -centerY);
// 计算并显示道路的偏离角度
function calculateRoadAngle(start, end) {
const startPos = convertToCanvas(start.longitude, start.latitude);
const endPos = convertToCanvas(end.longitude, end.latitude);
// 将坐标点转换到旋转后的坐标系
const rotatedStartX = (startPos.x - centerX) * Math.cos(-angle) - (startPos.y - centerY) * Math.sin(-angle);
const rotatedStartY = (startPos.x - centerX) * Math.sin(-angle) + (startPos.y - centerY) * Math.cos(-angle);
const rotatedEndX = (endPos.x - centerX) * Math.cos(-angle) - (endPos.y - centerY) * Math.sin(-angle);
const rotatedEndY = (endPos.x - centerX) * Math.sin(-angle) + (endPos.y - centerY) * Math.cos(-angle);
// 计算在旋转坐标系中的方向向量(从起点指向终点)
const dx = rotatedEndX - rotatedStartX;
const dy = rotatedEndY - rotatedStartY;
// 计算与垂直方向的夹角(弧度)
const angleRad = Math.atan2(-dx, dy);
// 转换为角度并取绝对值
const deviationAngle = Math.abs(angleRad * 180 / Math.PI);
// 显示角度(文字方向跟随旋转后的坐标系)
ctx.save();
// 将文字位置移到终点附近
ctx.translate(endPos.x, endPos.y + 15);
ctx.rotate(angle);
ctx.font = '12px Arial';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillText(deviationAngle.toFixed(1) + '°', 0, 0);
ctx.restore();
}
// 绘制道路网络
// 计算指定道路的角度
drawRoad(intersections[0], intersections[2]); // T1-T3
calculateRoadAngle(intersections[0], intersections[2]);
drawRoad(intersections[3], intersections[4]); // T4-T5
calculateRoadAngle(intersections[3], intersections[4]);
drawRoad(intersections[10], intersections[6]); // T11-T7 (修改顺序)
calculateRoadAngle(intersections[10], intersections[6]);
drawRoad(intersections[7], intersections[8]); // T8-T9
calculateRoadAngle(intersections[7], intersections[8]);
// 绘制其他道路
drawRoad(intersections[1], intersections[9]); // T2-T10
drawRoad(intersections[5], intersections[7]); // T6-T8
drawRoad(intersections[11], intersections[3]); // T12-T4
// 绘制所有路口
intersections.forEach(drawIntersection);
// 恢复画布状态
ctx.restore();
// 绘制比例尺
ctx.beginPath();
ctx.moveTo(gridSize * 2, canvas.height - 20);
ctx.lineTo(gridSize * 5, canvas.height - 20);
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.stroke();
// 绘制刻度
ctx.beginPath();
ctx.moveTo(gridSize * 2, canvas.height - 15);
ctx.lineTo(gridSize * 2, canvas.height - 25);
ctx.moveTo(gridSize * 3, canvas.height - 15);
ctx.lineTo(gridSize * 3, canvas.height - 25);
ctx.moveTo(gridSize * 4, canvas.height - 15);
ctx.lineTo(gridSize * 4, canvas.height - 25);
ctx.moveTo(gridSize * 5, canvas.height - 15);
ctx.lineTo(gridSize * 5, canvas.height - 25);
ctx.lineWidth = 1;
ctx.stroke();
// 计算两个网格单位代表的实际距离(米)
const gridMeters = gridSize / scale;
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
// 在刻度处显示距离
ctx.fillText('0', gridSize * 2, canvas.height - 5);
ctx.fillText(Math.round(gridMeters) + '', gridSize * 3, canvas.height - 5);
ctx.fillText(Math.round(gridMeters * 1) + '', gridSize * 4, canvas.height - 5);
ctx.fillText(Math.round(gridMeters * 2) + '米', gridSize * 5, canvas.height - 5);
</script>
</body>
</html>