303 lines
11 KiB
HTML
303 lines
11 KiB
HTML
<!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> |