<!6012 html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>神奇的自然钟</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif;
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #fff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
overflow-x: hidden;
}
.container {
max-width: 900px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
header {
text-align: center;
margin-bottom: 20px;
width: 100%;
}
h1 {
font-size: 2.2rem;
margin-bottom: 10px;
color: #e94560;
text-shadow: 0 0 10px rgba(233, 69, 96, 0.5);
}
.subtitle {
font-size: 1.1rem;
color: #b8b8b8;
margin-bottom: 20px;
}
.clock-container {
position: relative;
width: 100%;
max-width: 700px;
margin: 0 auto 30px;
padding: 20px;
}
canvas {
display: block;
margin: 0 auto;
border-radius: 50%;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.7);
background: rgba(10, 10, 20, 0.9);
max-width: 100%;
height: auto;
}
.info-panel {
width: 100%;
max-width: 600px;
background: rgba(30, 30, 50, 0.7);
border-radius: 15px;
padding: 20px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
margin-bottom: 20px;
}
.info-section {
margin-bottom: 15px;
}
.info-title {
font-size: 1.3rem;
margin-bottom: 10px;
color: #e94560;
border-bottom: 1px solid #333;
padding-bottom: 5px;
}
.pointers-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
.pointer-item {
padding: 10px;
border-radius: 8px;
background: rgba(40, 40, 60, 0.5);
}
.pointer-name {
font-weight: bold;
margin-bottom: 5px;
}
.pointer-desc {
font-size: 0.9rem;
color: #b8b8b8;
}
.current-time {
font-size: 1.5rem;
text-align: center;
margin: 15px 0;
color: #0fccce;
font-weight: bold;
}
.legend {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
margin-top: 15px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.legend-color {
width: 15px;
height: 15px;
border-radius: 50%;
}
.time-controls {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
margin-top: 20px;
}
.time-input-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
}
.time-input-group label {
font-size: 0.9rem;
color: #b8b8b8;
}
.time-input {
width: 80px;
padding: 8px;
border: 1px solid #444;
border-radius: 5px;
background: rgba(20, 20, 30, 0.8);
color: #fff;
text-align: center;
font-size: 1rem;
}
.time-input:focus {
outline: none;
border-color: #0fccce;
}
.control-buttons {
display: flex;
gap: 10px;
margin-top: 15px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 5px;
background: #0fccce;
color: #fff;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s;
}
.btn:hover {
background: #0db9bb;
}
.btn-reset {
background: #e94560;
}
.btn-reset:hover {
background: #d8344f;
}
footer {
margin-top: 20px;
text-align: center;
color: #666;
font-size: 0.9rem;
}
@media (max-width: 700px) {
h1 {
font-size: 1.8rem;
}
.pointers-info {
grid-template-columns: 1fr;
}
.clock-container {
max-width: 95vw;
padding: 10px;
}
.time-controls {
flex-direction: column;
align-items: center;
}
.current-time {
font-size: 1.2rem;
}
}
@media (max-width: 480px) {
h1 {
font-size: 1.5rem;
}
.subtitle {
font-size: 0.9rem;
}
.current-time {
font-size: 1rem;
}
.time-input {
width: 70px;
font-size: 0.9rem;
}
.btn {
padding: 6px 12px;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>神奇的自然钟</h1>
<p class="subtitle">四指针周期时间显示系统</p>
</header>
<div class="clock-container">
<canvas id="clockCanvas" width="700" height="700"></canvas>
</div>
<div class="current-time" id="currentTime"></div>
<div class="info-panel">
<div class="info-section">
<h2 class="info-title">时间设置</h2>
<div class="time-controls">
<div class="time-input-group">
<label for="yearInput">年</label>
<input type="number" id="yearInput" class="time-input" min="1800" max="2100" value="2023">
</div>
<div class="time-input-group">
<label for="monthInput">月</label>
<input type="number" id="monthInput" class="time-input" min="1" max="12" value="10">
</div>
<div class="time-input-group">
<label for="dayInput">日</label>
<input type="number" id="dayInput" class="time-input" min="1" max="31" value="15">
</div>
<div class="time-input-group">
<label for="hourInput">时</label>
<input type="number" id="hourInput" class="time-input" min="0" max="23" value="12">
</div>
<div class="time-input-group">
<label for="minuteInput">分</label>
<input type="number" id="minuteInput" class="time-input" min="0" max="59" value="0">
</div>
</div>
<div class="control-buttons">
<button id="setTimeBtn" class="btn">设置时间</button>
<button id="resetTimeBtn" class="btn btn-reset">重置为当前时间</button>
</div>
</div>
<div class="info-section">
<h2 class="info-title">指针信息</h2>
<div class="pointers-info">
<div class="pointer-item">
<div class="pointer-name" style="color: #ff4d4d;">24小时指针</div>
<div class="pointer-desc">对应人体12经脉循环,最短的周期</div>
</div>
<div class="pointer-item">
<div class="pointer-name" style="color: #4dff4d;">60天周期指针</div>
<div class="pointer-desc">自然界无形的小手,次短周期</div>
</div>
<div class="pointer-item">
<div class="pointer-name" style="color: #4d9dff;">年周期指针</div>
<div class="pointer-desc">我们的四季,我们的轮回,次长周期</div>
</div>
<div class="pointer-item">
<div class="pointer-name" style="color: #ffdd4d;">60年周期指针</div>
<div class="pointer-desc">30年河东,30年河西,最长周期</div>
</div>
</div>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background-color: #ff4d4d;"></div>
<span>24小时指针</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #4dff4d;"></div>
<span>60天周期指针</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #4d9dff;"></div>
<span>年周期指针</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #ffdd4d;"></div>
<span>60年周期指针</span>
</div>
</div>
</div>
<footer>
<p>天人合一的自然周期钟表 © 2025张宇川</p>
</footer>
</div>
<script>
// 获取Canvas元素和上下文
const canvas = document.getElementById('clockCanvas');
const ctx = canvas.getContext('2d');
// 获取时间输入元素
const yearInput = document.getElementById('yearInput');
const monthInput = document.getElementById('monthInput');
const dayInput = document.getElementById('dayInput');
const hourInput = document.getElementById('hourInput');
const minuteInput = document.getElementById('minuteInput');
const setTimeBtn = document.getElementById('setTimeBtn');
const resetTimeBtn = document.getElementById('resetTimeBtn');
// 当前显示的时间(默认为系统时间)
let currentDisplayTime = new Date();
// 响应式调整Canvas大小
function resizeCanvas() {
const container = canvas.parentElement;
const maxSize = Math.min(container.offsetWidth, 700);
canvas.width = maxSize;
canvas.height = maxSize;
}
// 初始化时调整大小
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 颜色定义
const colors = {
hourPointer: '#ff4d4d', // 红色 - 24小时指针
dayPointer: '#4dff4d', // 绿色 - 60天周期指针
yearPointer: '#4d9dff', // 蓝色 - 年周期指针
cyclePointer: '#ffdd4d', // 黄色 - 60年周期指针
background: '#0a0a14',
face: '#1a1a2e',
tick: '#ffffff',
text: '#ffffff',
meridianText: '#a0a0ff' // 经络名称颜色
};
// 经络名称数组
const meridianNames = [
"足少阳", "足厥阴", "手太阴", "手阳明",
"足阳明", "足太阴", "手少阴", "手太阳",
"足太阳", "足少阴", "手厥阴", "手少阳"
];
// 绘制钟表表盘
function drawClockFace() {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// 减小表盘半径,为外部元素留出空间
const radius = Math.min(centerX, centerY) * 0.75;
// 绘制外圆
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.fillStyle = colors.face;
ctx.fill();
ctx.strokeStyle = colors.tick;
ctx.lineWidth = 2;
ctx.stroke();
// 绘制60个刻度
for (let i = 0; i < 60; i++) {
const angle = (i * 6 - 90) * Math.PI / 180; // -90度使0点在顶部
const tickLength = i % 5 === 0 ? 20 : 10;
const tickWidth = i % 5 === 0 ? 3 : 1;
const innerRadius = radius - tickLength;
ctx.beginPath();
ctx.moveTo(
centerX + innerRadius * Math.cos(angle),
centerY + innerRadius * Math.sin(angle)
);
ctx.lineTo(
centerX + radius * Math.cos(angle),
centerY + radius * Math.sin(angle)
);
ctx.strokeStyle = colors.tick;
ctx.lineWidth = tickWidth;
ctx.stroke();
// 绘制数字(每5个刻度)
if (i % 5 === 0) {
const textRadius = innerRadius - 15;
ctx.font = `${Math.max(14, radius * 0.04)}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
ctx.fillStyle = colors.text;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(
i.toString(),
centerX + textRadius * Math.cos(angle),
centerY + textRadius * Math.sin(angle)
);
// 绘制经络名称
const meridianIndex = i / 5;
if (meridianIndex < meridianNames.length) {
const meridianRadius = radius + 30;
ctx.font = `${Math.max(12, radius * 0.035)}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif`;
ctx.fillStyle = colors.meridianText;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(
meridianNames[meridianIndex],
centerX + meridianRadius * Math.cos(angle),
centerY + meridianRadius * Math.sin(angle)
);
}
}
}
// 绘制中心点
ctx.beginPath();
ctx.arc(centerX, centerY, 5, 0, Math.PI * 2);
ctx.fillStyle = colors.text;
ctx.fill();
}
// 计算24小时指针位置
function calculateHourPointer() {
const hours = currentDisplayTime.getHours();
const minutes = currentDisplayTime.getMinutes();
// 24小时制,转换为60刻度(24小时 = 60刻度)
// 每个小时对应 60/24 = 2.5 刻度
const hourPosition = (hours + minutes/60) * 2.5;
return hourPosition;
}
// 计算60天周期指针位置
function calculateDayPointer() {
// 基准点:1871年11月26日
const baseDate = new Date(1871, 10, 26); // 月份从0开始,所以11月是10
// 计算从基准日到当前显示时间的天数
const timeDiff = currentDisplayTime.getTime() - baseDate.getTime();
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
// 60天周期,转换为60刻度
const dayPosition = daysDiff % 60;
return dayPosition;
}
// 计算年周期指针位置(冬至为起点)
function calculateYearPointer() {
const currentYear = currentDisplayTime.getFullYear();
// 计算当前年份的冬至(12月21日)
const winterSolstice = new Date(currentYear, 11, 21); // 12月是11
// 计算从去年冬至到当前显示时间的天数
let daysFromSolstice;
if (currentDisplayTime >= winterSolstice) {
// 如果当前显示时间在冬至之后,使用今年的冬至
daysFromSolstice = Math.floor((currentDisplayTime - winterSolstice) / (1000 * 3600 * 24));
} else {
// 如果当前显示时间在冬至之前,使用去年的冬至
const lastWinter = new Date(currentYear - 1, 11, 21);
daysFromSolstice = Math.floor((currentDisplayTime - lastWinter) / (1000 * 3600 * 24));
}
// 一年365天映射到60刻度
const yearPosition = (daysFromSolstice % 365) * (60/365);
return yearPosition;
}
// 计算60年周期指针位置
function calculateCyclePointer() {
// 基准点:1871年
const baseYear = 1871;
const currentYear = currentDisplayTime.getFullYear();
// 计算从1871年至今的年数
const yearsPassed = currentYear - baseYear;
// 60年周期,转换为60刻度
const cyclePosition = yearsPassed % 60;
return cyclePosition;
}
// 绘制指针
function drawPointer(position, color, width) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = Math.min(centerX, centerY) * 0.75; // 使用与表盘相同的半径
// 所有指针使用相同长度 - 红色指针的长度 (0.85)
const length = radius * 0.85;
const angle = (position * 6 - 90) * Math.PI / 180; // 每个刻度6度
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(
centerX + length * Math.cos(angle),
centerY + length * Math.sin(angle)
);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.lineCap = 'round';
ctx.stroke();
// 在指针末端添加圆形标记
ctx.beginPath();
ctx.arc(
centerX + length * Math.cos(angle),
centerY + length * Math.sin(angle),
width * 1.5, 0, Math.PI * 2
);
ctx.fillStyle = color;
ctx.fill();
}
// 更新当前时间显示
function updateCurrentTime() {
const year = currentDisplayTime.getFullYear();
const month = String(currentDisplayTime.getMonth() + 1).padStart(2, '0');
const day = String(currentDisplayTime.getDate()).padStart(2, '0');
const hours = String(currentDisplayTime.getHours()).padStart(2, '0');
const minutes = String(currentDisplayTime.getMinutes()).padStart(2, '0');
const seconds = String(currentDisplayTime.getSeconds()).padStart(2, '0');
const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
document.getElementById('currentTime').textContent = `显示时间: ${timeString}`;
}
// 更新输入框中的时间
function updateInputFields() {
yearInput.value = currentDisplayTime.getFullYear();
monthInput.value = String(currentDisplayTime.getMonth() + 1).padStart(2, '0');
dayInput.value = String(currentDisplayTime.getDate()).padStart(2, '0');
hourInput.value = String(currentDisplayTime.getHours()).padStart(2, '0');
minuteInput.value = String(currentDisplayTime.getMinutes()).padStart(2, '0');
}
// 绘制所有指针
function drawPointers() {
const hourPos = calculateHourPointer();
const dayPos = calculateDayPointer();
const yearPos = calculateYearPointer();
const cyclePos = calculateCyclePointer();
// 绘制指针(从细到粗,避免覆盖)
drawPointer(cyclePos, colors.cyclePointer,1); // 60年周期指针 - 最细
drawPointer(yearPos, colors.yearPointer, 2); // 年周期指针
drawPointer(dayPos, colors.dayPointer, 3); // 60天周期指针
drawPointer(hourPos, colors.hourPointer, 4); // 24小时指针 - 最粗
}
// 绘制钟表
function drawClock() {
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制表盘
drawClockFace();
// 绘制指针
drawPointers();
// 更新当前时间显示
updateCurrentTime();
}
// 设置自定义时间
function setCustomTime() {
const year = parseInt(yearInput.value);
const month = parseInt(monthInput.value) - 1; // 月份从0开始
const day = parseInt(dayInput.value);
const hour = parseInt(hourInput.value);
const minute = parseInt(minuteInput.value);
// 创建新的日期对象
currentDisplayTime = new Date(year, month, day, hour, minute, 0);
// 重绘钟表
drawClock();
}
// 重置为当前系统时间
function resetToCurrentTime() {
currentDisplayTime = new Date();
updateInputFields();
drawClock();
}
// 初始化并开始动画
function init() {
// 初始化输入框为当前时间
updateInputFields();
// 绘制初始钟表
drawClock();
// 添加事件监听器
setTimeBtn.addEventListener('click', setCustomTime);
resetTimeBtn.addEventListener('click', resetToCurrentTime);
// 每秒更新一次(仅在显示系统时间时)
setInterval(() => {
// 只有当显示的是系统当前时间时才自动更新
// 如果用户设置了自定义时间,则不自动更新
const now = new Date();
if (
currentDisplayTime.getFullYear() === now.getFullYear() &&
currentDisplayTime.getMonth() === now.getMonth() &&
currentDisplayTime.getDate() === now.getDate() &&
currentDisplayTime.getHours() === now.getHours() &&
currentDisplayTime.getMinutes() === now.getMinutes()
) {
// 如果显示的时间与当前系统时间一致,则更新为最新系统时间
currentDisplayTime = now;
updateInputFields();
drawClock();
}
}, 1000);
}
// 页面加载完成后初始化
window.addEventListener('load', init);
</script>
</body>
</html>