<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>太阳系天体模拟器</title>
<style>
body {
margin: 0;
padding: 0;
background: #000011;
font-family: 'Arial', sans-serif;
overflow: hidden;
}
#container {
position: relative;
width: 100vw;
height: 100vh;
}
#canvas {
display: block;
cursor: grab;
}
#canvas:active {
cursor: grabbing;
}
#controls {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
color: white;
font-size: 14px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.control-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
color: #aaa;
}
input, select, button {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 8px;
border-radius: 5px;
width: 100%;
box-sizing: border-box;
}
button {
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: rgba(255, 255, 255, 0.2);
}
#info {
position: absolute;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
color: white;
font-size: 12px;
max-width: 300px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.planet-name {
font-weight: bold;
color: #4CAF50;
}
.moon-name {
color: #FFC107;
margin-left: 10px;
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
<div id="controls">
<div class="control-group">
<label>时间速度:</label>
<select id="timeSpeed">
<option value="0">暂停</option>
<option value="1">实时</option>
<option value="60">1分钟/秒</option>
<option value="3600">1小时/秒</option>
<option value="86400" selected>1天/秒</option>
<option value="604800">1周/秒</option>
<option value="2592000">1月/秒</option>
<option value="31536000">1年/秒</option>
</select>
</div>
<div class="control-group">
<label>设置日期:</label>
<input type="datetime-local" id="dateInput">
<button onclick="setCurrentTime()">设为当前时间</button>
</div>
<div class="control-group">
<label>缩放:</label>
<input type="range" id="zoomSlider" min="0.1" max="3" step="0.1" value="1">
</div>
<div class="control-group">
<button onclick="toggleOrbits()">显示/隐藏轨道</button>
<button onclick="toggleMoons()">显示/隐藏卫星</button>
</div>
</div>
<div id="info">
<div id="currentTime"></div>
<div id="planetInfo"></div>
</div>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 画布设置
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 天体数据 (轨道半径按比例缩放,公转周期为地球日)
const celestialBodies = {
sun: {
name: '太阳',
radius: 20,
color: '#FDB813',
x: 0, y: 0
},
mercury: {
name: '水星',
radius: 2,
color: '#8C7853',
orbitRadius: 80,
period: 88, // 地球日
angle: 0
},
venus: {
name: '金星',
radius: 3,
color: '#FFC649',
orbitRadius: 110,
period: 225,
angle: 0
},
earth: {
name: '地球',
radius: 4,
color: '#6B93D6',
orbitRadius: 150,
period: 365.25,
angle: 0,
moons: [{
name: '月球',
radius: 1,
color: '#C0C0C0',
orbitRadius: 15,
period: 27.3,
angle: 0
}]
},
mars: {
name: '火星',
radius: 3,
color: '#CD5C5C',
orbitRadius: 200,
period: 687,
angle: 0,
moons: [
{
name: '火卫一',
radius: 0.5,
color: '#A0522D',
orbitRadius: 8,
period: 0.32,
angle: 0
},
{
name: '火卫二',
radius: 0.5,
color: '#A0522D',
orbitRadius: 12,
period: 1.26,
angle: 0
}
]
},
jupiter: {
name: '木星',
radius: 12,
color: '#D8CA9D',
orbitRadius: 300,
period: 4333,
angle: 0,
moons: [
{
name: '木卫一',
radius: 1,
color: '#FFFF99',
orbitRadius: 25,
period: 1.77,
angle: 0
},
{
name: '木卫二',
radius: 1,
color: '#87CEEB',
orbitRadius: 30,
period: 3.55,
angle: 0
},
{
name: '木卫三',
radius: 1.5,
color: '#8B4513',
orbitRadius: 40,
period: 7.15,
angle: 0
},
{
name: '木卫四',
radius: 1.2,
color: '#696969',
orbitRadius: 50,
period: 16.69,
angle: 0
}
]
},
saturn: {
name: '土星',
radius: 10,
color: '#FAD5A5',
orbitRadius: 400,
period: 10759,
angle: 0,
hasRings: true,
moons: [
{
name: '土卫六',
radius: 1.5,
color: '#CD853F',
orbitRadius: 35,
period: 15.95,
angle: 0
},
{
name: '土卫七',
radius: 0.8,
color: '#F5DEB3',
orbitRadius: 45,
period: 21.28,
angle: 0
}
]
},
uranus: {
name: '天王星',
radius: 7,
color: '#4FD0E7',
orbitRadius: 500,
period: 30687,
angle: 0,
moons: [
{
name: '天卫一',
radius: 0.8,
color: '#B0E0E6',
orbitRadius: 20,
period: 8.71,
angle: 0
},
{
name: '天卫二',
radius: 0.8,
color: '#B0E0E6',
orbitRadius: 25,
period: 13.46,
angle: 0
}
]
},
neptune: {
name: '海王星',
radius: 7,
color: '#4169E1',
orbitRadius: 600,
period: 60190,
angle: 0,
moons: [
{
name: '海卫一',
radius: 1,
color: '#FFB6C1',
orbitRadius: 22,
period: 5.88,
angle: 0
}
]
}
};
// 控制变量
let currentTime = new Date();
let timeSpeed = 86400; // 默认1天/秒
let zoom = 1;
let showOrbits = true;
let showMoons = true;
let lastTime = Date.now();
// 参考时间 (J2000.0 epoch: 2000年1月1日12:00 UTC)
const referenceTime = new Date('2000-01-01T12:00:00Z');
// 初始化
function init() {
document.getElementById('dateInput').value = formatDateForInput(currentTime);
document.getElementById('timeSpeed').value = timeSpeed;
document.getElementById('zoomSlider').value = zoom;
// 设置初始角度基于当前时间
updatePlanetPositions();
// 事件监听
document.getElementById('timeSpeed').addEventListener('change', (e) => {
timeSpeed = parseInt(e.target.value);
});
document.getElementById('dateInput').addEventListener('change', (e) => {
currentTime = new Date(e.target.value);
updatePlanetPositions();
});
document.getElementById('zoomSlider').addEventListener('input', (e) => {
zoom = parseFloat(e.target.value);
});
animate();
}
// 格式化日期为input控件格式
function formatDateForInput(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
// 设置当前时间
function setCurrentTime() {
currentTime = new Date();
document.getElementById('dateInput').value = formatDateForInput(currentTime);
updatePlanetPositions();
}
// 更新行星位置
function updatePlanetPositions() {
const daysSinceReference = (currentTime - referenceTime) / (1000 * 60 * 60 * 24);
Object.keys(celestialBodies).forEach(key => {
const body = celestialBodies[key];
if (body.period) {
// 计算当前角度 (弧度)
body.angle = (2 * Math.PI * daysSinceReference / body.period) % (2 * Math.PI);
// 更新卫星角度
if (body.moons) {
body.moons.forEach(moon => {
moon.angle = (2 * Math.PI * daysSinceReference / moon.period) % (2 * Math.PI);
});
}
}
});
}
// 切换轨道显示
function toggleOrbits() {
showOrbits = !showOrbits;
}
// 切换卫星显示
function toggleMoons() {
showMoons = !showMoons;
}
// 绘制函数
function draw() {
// 清空画布
ctx.fillStyle = '#000011';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制星空背景
//drawStars();
// 移动到画布中心
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.scale(zoom, zoom);
// 绘制轨道
if (showOrbits) {
drawOrbits();
}
// 绘制太阳
drawCelestialBody(celestialBodies.sun);
// 绘制行星和卫星
Object.keys(celestialBodies).forEach(key => {
if (key !== 'sun') {
const planet = celestialBodies[key];
// 计算行星位置
planet.x = Math.cos(planet.angle) * planet.orbitRadius;
planet.y = Math.sin(planet.angle) * planet.orbitRadius;
// 绘制行星
drawCelestialBody(planet);
// 绘制土星环
if (planet.hasRings) {
drawSaturnRings(planet);
}
// 绘制卫星
if (showMoons && planet.moons) {
planet.moons.forEach(moon => {
moon.x = planet.x + Math.cos(moon.angle) * moon.orbitRadius;
moon.y = planet.y + Math.sin(moon.angle) * moon.orbitRadius;
drawCelestialBody(moon);
// 绘制卫星轨道
if (showOrbits) {
ctx.beginPath();
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineWidth = 1;
ctx.arc(planet.x, planet.y, moon.orbitRadius, 0, 2 * Math.PI);
ctx.stroke();
}
});
}
}
});
ctx.restore();
// 更新信息显示
updateInfo();
}
// 绘制星空背景
function drawStars() {
ctx.fillStyle = 'white';
for (let i = 0; i < 200; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const size = Math.random() * 2;
ctx.beginPath();
ctx.arc(x, y, size, 0, 2 * Math.PI);
ctx.fill();
}
}
// 绘制轨道
function drawOrbits() {
Object.keys(celestialBodies).forEach(key => {
const body = celestialBodies[key];
if (body.orbitRadius) {
ctx.beginPath();
ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
ctx.lineWidth = 1;
ctx.arc(0, 0, body.orbitRadius, 0, 2 * Math.PI);
ctx.stroke();
}
});
}
// 绘制天体
function drawCelestialBody(body) {
ctx.save();
ctx.translate(body.x, body.y);
// 绘制光晕效果(太阳)
if (body.name === '太阳') {
const gradient = ctx.createRadialGradient(0, 0, body.radius, 0, 0, body.radius * 2);
gradient.addColorStop(0, body.color);
gradient.addColorStop(1, 'rgba(253, 184, 19, 0)');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(0, 0, body.radius * 2, 0, 2 * Math.PI);
ctx.fill();
}
// 绘制天体本体
ctx.fillStyle = body.color;
ctx.beginPath();
ctx.arc(0, 0, body.radius, 0, 2 * Math.PI);
ctx.fill();
// 添加边框
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
}
// 绘制土星环
function drawSaturnRings(planet) {
ctx.save();
ctx.translate(planet.x, planet.y);
ctx.strokeStyle = 'rgba(250, 213, 165, 0.6)';
ctx.lineWidth = 2;
// 内环
ctx.beginPath();
ctx.arc(0, 0, planet.radius + 3, 0, 2 * Math.PI);
ctx.stroke();
// 外环
ctx.beginPath();
ctx.arc(0, 0, planet.radius + 6, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
}
// 更新信息显示
function updateInfo() {
document.getElementById('currentTime').innerHTML = `<strong>当前时间:</strong><br>${currentTime.toLocaleString('zh-CN')}`;
let planetInfo = '<strong>天体信息:</strong><br>';
Object.keys(celestialBodies).forEach(key => {
const body = celestialBodies[key];
if (key !== 'sun') {
planetInfo += `<span class="planet-name">${body.name}</span><br>`;
if (showMoons && body.moons) {
body.moons.forEach(moon => {
planetInfo += `<span class="moon-name">├ ${moon.name}</span><br>`;
});
}
}
});
document.getElementById('planetInfo').innerHTML = planetInfo;
}
// 动画循环
function animate() {
const now = Date.now();
const deltaTime = (now - lastTime) / 1000; // 秒
lastTime = now;
if (timeSpeed > 0) {
currentTime = new Date(currentTime.getTime() + deltaTime * timeSpeed * 1000);
document.getElementById('dateInput').value = formatDateForInput(currentTime);
updatePlanetPositions();
}
draw();
requestAnimationFrame(animate);
}
// 鼠标控制缩放
canvas.addEventListener('wheel', (e) => {
e.preventDefault();
const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
zoom = Math.max(0.1, Math.min(3, zoom * zoomFactor));
document.getElementById('zoomSlider').value = zoom;
});
// 启动模拟器
init();
</script>
</body>
</html>
index.html
index.html