杜甫的一生,恰似盛唐向中唐过渡的史诗画卷
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="沉浸式体验杜甫一生的行迹与诗歌创作历程">
<title>诗圣杜甫一生行迹 - 沉浸式文化体验</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet-ant-path@1.3.0/dist/leaflet-ant-path.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
background-color: #f5f5f5;
line-height: 1.6;
color: #333;
overflow-x: hidden;
}
header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.95);
padding: 15px;
text-align: center;
font-size: 24px;
font-weight: bold;
color: #333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
backdrop-filter: blur(5px);
}
#mapLoader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: white;
z-index: 9999;
transition: opacity 0.5s ease-out;
}
.loader-spinner {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #8B4513;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#map {
width: 100vw;
height: 100vh;
position: relative;
margin-top: 60px;
}
/* 信息卡片样式 - 优化透明度和布局以避免遮挡路径 */
.info-card {
position: fixed;
bottom: 40px;
left: 50%;
transform: translateX(-50%) translateY(100%);
width: 80%;
max-width: 1200px;
background-color: rgba(255, 255, 255, 0.5); /* 增加透明度到50% */
backdrop-filter: blur(12px);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
transition: transform 0.5s ease, max-height 0.5s ease, opacity 0.5s ease;
z-index: 900;
display: flex;
flex-direction: row;
overflow: hidden;
cursor: pointer;
opacity: 0;
}
.info-card.active {
opacity: 1;
}
/* 折叠按钮样式 */
.collapse-btn {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 20px;
background-color: rgba(255, 255, 255, 0.8);
border: none;
border-radius: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
z-index: 10;
}
.collapse-btn:hover {
background-color: rgba(255, 255, 255, 1);
}
.collapse-btn::before {
content: '⌄';
transition: transform 0.3s ease;
}
.info-card.collapsed .collapse-btn::before {
transform: rotate(180deg);
}
/* 折叠状态的信息卡片 */
.info-card.collapsed {
max-height: 100px;
}
.info-card.collapsed .info-content {
max-height: 60px;
}
/* 马标志样式 */
.horse-marker {
font-size: 40px !important; /* 增加马标志的尺寸,使其更加醒目 */
text-shadow: 0 3px 6px rgba(0, 0, 0, 0.4);
transform-origin: center center;
transition: transform 0.3s ease;
animation: horseFloat 3s ease-in-out infinite;
}
@keyframes horseFloat {
0% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
100% { transform: translateY(0px); }
}
.horse-marker:hover {
transform: scale(1.3) rotate(5deg);
}
.info-card.active {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
/* 独立的图片区域 */
.info-image {
width: 25%;
min-width: 150px;
height: 300px; /* 增加图片高度 */
object-fit: cover;
position: relative;
border-radius: 15px 0 0 15px;
transition: filter 0.3s ease;
}
.info-image:hover {
filter: brightness(1.1);
}
/* 图片加载动画 */
.image-loading::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 50%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
to {
left: 100%;
}
}
/* 独立的内容区域 */
.info-content {
padding: 20px;
width: 75%;
overflow-y: auto;
max-height: 300px;
position: relative;
transition: max-height 0.5s ease;
}
/* 内容滚动条样式优化 */
.info-content::-webkit-scrollbar {
width: 8px;
}
.info-content::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.info-content::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
}
.info-content::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.3);
}
/* 滚动内容容器 */
.scroll-container {
height: 100%;
overflow-y: auto;
}
/* 滚动控制按钮 */
.scroll-control {
position: absolute;
bottom: 10px;
right: 10px;
display: flex;
gap: 5px;
}
.scroll-btn {
width: 30px;
height: 30px;
border-radius: 50%;
border: none;
background-color: rgba(255, 255, 255, 0.8);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: background-color 0.3s;
}
.scroll-btn:hover {
background-color: rgba(255, 255, 255, 1);
}
.info-title {
font-size: 36px;
margin-bottom: 12px;
color: #333;
text-align: center;
font-weight: bold;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
letter-spacing: 0.5px;
}
.info-year {
font-size: 16px;
color: #666;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
text-align: center;
font-style: italic;
}
.info-description {
margin-bottom: 20px;
line-height: 2.0;
font-size: 25px;
color: #333;
text-indent: 2em;
letter-spacing: 0.8px;
}
/* 优化诗句样式 */
.info-poem {
color: #8B4513;
margin-bottom: 15px;
padding: 15px;
background-color: #FFF8DC;
border-radius: 10px;
font-style: italic;
border-left: 4px solid #8B4513;
box-shadow: 0 2px 8px rgba(139, 69, 19, 0.1);
}
/* 双语文字样式优化 */
.bilingual-text {
margin-bottom: 10px;
}
.chinese-text {
font-family: 'Microsoft YaHei', 'PingFang SC', serif;
font-size: 25px;
color: #333;
line-height: 2.0;
margin-bottom: 12px;
letter-spacing: 0.8px;
}
.english-text {
font-family: 'Times New Roman', serif;
font-size: 20px;
color: #555;
line-height: 1.8;
font-style: italic;
letter-spacing: 0.5px;
}
.bilingual-item {
margin-bottom: 15px;
}
.lang-label {
font-weight: bold;
color: #8B4513;
margin-bottom: 5px;
font-size: 14px;
}
/* 标题动画效果 */
.title-animation {
animation: fadeInScale 1s ease-out;
}
@keyframes fadeInScale {
0% { opacity: 0; transform: scale(0.9); }
100% { opacity: 1; transform: scale(1); }
}
/* 高亮诗句样式 */
.poem-highlight {
background-color: rgba(139, 69, 19, 0.05);
padding: 10px;
border-radius: 8px;
border-left: 4px solid #8B4513;
}
.info-close {
position: absolute;
top: 10px;
right: 10px;
width: 30px;
height: 30px;
background-color: rgba(0, 0, 0, 0.2);
color: white;
border: none;
border-radius: 50%;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s;
}
.info-close:hover {
background-color: rgba(0, 0, 0, 0.4);
}
/* 控制按钮 */
.controls {
position: fixed;
top: 100px;
right: 20px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 1050;
transition: transform 0.3s ease;
}
/* 控制按钮提示 */
.control-btn::after {
content: attr(data-tooltip);
position: absolute;
right: 100%;
margin-right: 10px;
background-color: rgba(0, 0, 0, 0.8);
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
}
.control-btn:hover::after {
opacity: 1;
visibility: visible;
}
.control-btn {
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
background-color: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 20px;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
position: relative;
backdrop-filter: blur(5px);
}
.control-btn:hover {
background-color: #fff;
transform: translateY(-3px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
}
/* 阶段颜色指示器 */
.stage-indicator {
position: fixed;
top: 100px;
left: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.95);
padding: 10px 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
z-index: 800;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 15px;
backdrop-filter: blur(5px);
transition: transform 0.3s ease;
}
.stage-title {
font-weight: bold;
color: #333;
margin-right: 15px;
}
.stage-colors {
display: flex;
flex-wrap: wrap;
gap: 15px;
justify-content: center;
}
.stage-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
.stage-color {
width: 20px;
height: 20px;
border-radius: 4px;
border: 1px solid #ddd;
}
/* 语言显示区域 - 调整为同时显示双语 */
.lang-label {
text-align: right;
font-size: 12px;
color: #999;
margin-bottom: 5px;
}
.bilingual-item {
margin-bottom: 15px;
}
.bilingual-text {
display: flex;
flex-direction: column;
gap: 5px;
}
.chinese-text {
font-size: 16px;
color: #333;
}
.english-text {
font-size: 14px;
color: #666;
font-style: italic;
}
/* 移除语言切换按钮 */
.lang-switch {
display: none;
}
/* 回到顶部按钮 */
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.9);
color: #333;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s, transform 0.3s;
z-index: 950;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(5px);
}
.back-to-top.visible {
opacity: 1;
visibility: visible;
}
.back-to-top:hover {
transform: translateY(-3px);
background-color: white;
}
/* 加载进度条 */
.progress-bar {
position: fixed;
top: 60px;
left: 0;
height: 4px;
background: linear-gradient(90deg, #8B4513, #A0522D, #CD853F, #DEB887);
width: 0%;
z-index: 1001;
transition: width 0.3s ease;
}
/* 适配移动端 */
@media(max-width:768px){
header {
font-size: 20px;
padding: 12px;
}
.info-card {flex-direction:column; left: 5%; right: 5%;}
.info-image {width:100%;height:200px}
.info-content {max-height:40vh; width: 100%;}
.controls {top: auto; bottom: 150px; right: 20px; flex-direction: row;}
.stage-indicator {top: auto; bottom: 220px; left: 20px; right: 20px;}
.stage-colors {flex-direction: row; flex-wrap: wrap;}
/* 移动端触摸优化 */
.control-btn {
width: 60px;
height: 60px;
font-size: 24px;
}
}
</style>
</head>
<body>
<header>
<div style="font-size: 36px; font-weight: bold; color: #333; margin-bottom: 5px; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);">
诗圣杜甫,致君尧舜,笔底波澜写尽人间沧桑
</div>
<div style="font-size: 14px; color: #666; font-style: italic;
浏览器搜索"唐诗.中国"中文域名查看完整版
</div>
</header>
<div class="progress-bar" id="progressBar"></div>
<div id="mapLoader">
<div class="loader-spinner"></div>
<span>加载中…</span>
<div style="margin-top: 10px; font-size: 14px; color: #666;">正在准备杜甫的精彩人生旅程</div>
</div>
<div id="map"></div>
<!-- 信息卡片 -->
<div id="infoCard" class="info-card">
<img id="infoImage" class="info-image" src="" alt="" loading="lazy">
<div class="info-content">
<!-- 语言切换按钮 -->
<div class="lang-switch">
<button id="btnZh" class="lang-btn active">中文</button>
<button id="btnEn" class="lang-btn">English</button>
</div>
<h3 id="infoTitle" class="info-title"></h3>
<div id="infoYear" class="info-year"></div>
<div id="infoDescription" class="info-description"></div>
<div id="infoPoem" class="info-poem"></div>
<div id="infoAnecdote" class="info-description"></div>
</div>
<button class="info-close" onclick="hideInfoCard()">×</button>
<div class="scroll-control">
<button id="pauseScrollBtn" class="scroll-btn" onclick="toggleScroll()">❚❚</button>
</div>
<!-- 折叠按钮 -->
<button class="collapse-btn" onclick="toggleCardCollapse()"></button>
</div>
<!-- 控制按钮 -->
<div class="controls">
<button class="control-btn" id="playBtn" onclick="toggleAnimation()" data-tooltip="自动播放/暂停">▶</button>
<button class="control-btn" id="prevBtn" onclick="prevPoint()" data-tooltip="上一个地点">◀</button>
<button class="control-btn" id="nextBtn" onclick="nextPoint()" data-tooltip="下一个地点">▶</button>
</div>
<!-- 回到顶部按钮 -->
<div class="back-to-top" id="backToTop" onclick="scrollToTop()">
<i class="fas fa-arrow-up"></i>
</div>
<!-- 阶段颜色指示器 -->
<div class="stage-indicator">
<div class="stage-title">人生阶段</div>
<div class="stage-colors" id="stageColors"></div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-ant-path@1.3.0/dist/leaflet-ant-path.js"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<script>
// 全局变量定义
let map;
let allPoints = [];
let currentPointIndex = 0;
let markers = [];
let pathLines = [];
let horseMarker = null;
let isAnimating = false;
let animationInterval = null;
let isEn = false;
let isScrolling = true;
let scrollAnimationId = null;
let lastScrollY = 0;
const scrollSpeed = 0.5; // 滚动速度(像素/毫秒)- 减慢为原来的一半
const animationDelay = 20000; // 动画延迟(毫秒)- 延长至20秒,让用户有更多时间欣赏内容
// 定义杜甫人生阶段名称和对应的古典风颜色
const stageNames = [
{ stage: 1, name: "出生与童年", color: "#8B4513" }, // 棕色
{ stage: 2, name: "漫游求仕", color: "#A0522D" }, // 红棕色
{ stage: 3, name: "困居长安", color: "#CD853F" }, // 秘鲁色
{ stage: 4, name: "安史之乱", color: "#DEB887" }, // 原木色
{ stage: 5, name: "蜀中漂泊", color: "#BC8F8F" }, // 玫瑰棕色
{ stage: 6, name: "夔州流寓", color: "#D2B48C" }, // 棕褐色
{ stage: 7, name: "荆湘漂泊", color: "#F5DEB3" }, // 小麦色
{ stage: 8, name: "舟中长逝", color: "#7D4F24" } // 深棕色
];
const stageNamesEn = [
{ stage: 1, name: "Birth & Childhood", color: "#8B4513" },
{ stage: 2, name: "Wandering & Seeking Office", color: "#A0522D" },
{ stage: 3, name: "Struggling in Chang'an", color: "#CD853F" },
{ stage: 4, name: "An Lushan Rebellion", color: "#DEB887" },
{ stage: 5, name: "Wandering in Shu", color: "#BC8F8F" },
{ stage: 6, name: "Exile in Kuizhou", color: "#D2B48C" },
{ stage: 7, name: "Wandering in Jing & Xiang", color: "#F5DEB3" },
{ stage: 8, name: "Final Years on Boat", color: "#7D4F24" }
];
/* 杜甫足迹数据 */
allPoints = [
{
"name": "巩县",
"nameEn": "Gongxian County",
"year": 712,
"stage": 1,
"coord": [34.7, 112.9],
"event": "出生于河南巩县(今河南巩义市)",
"eventEn": "Born in Gongxian County, Henan (now Gongyi City, Henan)",
"poem": "国破山河在,城春草木深",
"poemEn": "The country shattered, mountains and rivers remain; the city in spring, grass and trees grow thick",
"image": "./images/gongxian.jpg",
"fallbackImage": "https://picsum.photos/id/1015/800/600",
"culture": {
"lines": ["国破山河在,城春草木深", "感时花溅泪,恨别鸟惊心"],
"linesEn": ["The country shattered, mountains and rivers remain; the city in spring, grass and trees grow thick", "Saddened by the times, flowers shed tears; hating separation, birds alarm the heart"],
"anecdote": "杜甫出生于官宦世家,祖父杜审言是初唐著名诗人。据《旧唐书》记载,杜甫七岁能诗,曾作《咏凤凰》一诗,被时人赞为神童。巩县是杜甫的祖籍地,这里的山水风光和家族文化对他的诗歌创作产生了深远影响。",
"anecdoteEn": "Du Fu was born into an official family. His grandfather Du Shenyan was a famous poet in the early Tang Dynasty. According to 'Old Book of Tang', Du Fu could write poetry at the age of seven and once composed a poem 'Ode to the Phoenix', which was praised by contemporaries as a child prodigy. Gongxian was Du Fu's ancestral home, and the landscape and family culture here had a profound impact on his poetic creation."
}
},
{
"name": "洛阳",
"nameEn": "Luoyang",
"year": 731,
"stage": 2,
"coord": [34.6, 112.4],
"event": "漫游至洛阳,结交文人雅士",
"eventEn": "Wandered to Luoyang, making friends with scholars and refined gentlemen",
"poem": "露从今夜白,月是故乡明",
"poemEn": "Dew turns white from tonight; the moon is brighter in my hometown",
"image": "./images/luoyang.jpg",
"fallbackImage": "https://picsum.photos/id/1036/800/600",
"culture": {
"lines": ["露从今夜白,月是故乡明", "有弟皆分散,无家问死生"],
"linesEn": ["Dew turns white from tonight; the moon is brighter in my hometown", "All younger brothers are scattered; no home to ask about life and death"],
"anecdote": "青年时期的杜甫漫游洛阳,与李白、高适等诗人相识相交,结下深厚友谊。他们一同漫游梁、宋(今河南开封、商丘一带),饮酒赋诗,谈古论今。这段经历不仅丰富了杜甫的人生阅历,也为他后来的诗歌创作积累了素材。",
"anecdoteEn": "In his youth, Du Fu wandered to Luoyang and became acquainted with poets like Li Bai and Gao Shi, forming deep friendships. They roamed together in Liang and Song (now Kaifeng and Shangqiu areas in Henan), drinking wine, composing poetry, and discussing ancient and modern affairs. This experience not only enriched Du Fu's life experience but also accumulated material for his later poetic creation."
}
},
{
"name": "泰山",
"nameEn": "Mount Tai",
"year": 736,
"stage": 2,
"coord": [36.2, 117.1],
"event": "北游齐赵,登泰山,作《望岳》",
"eventEn": "Traveled north to Qi and Zhao, climbed Mount Tai, composing 'Viewing the Summit'",
"poem": "会当凌绝顶,一览众山小",
"poemEn": "I must climb to the very peak, to see all mountains as small",
"image": "./images/taishan.jpg",
"fallbackImage": "https://picsum.photos/id/1039/800/600",
"culture": {
"lines": ["岱宗夫如何?齐鲁青未了", "造化钟神秀,阴阳割昏晓", "会当凌绝顶,一览众山小"],
"linesEn": ["What's Mount Tai like? Green continues across Qi and Lu", "Nature converges its divine beauty; yin and yang divide dawn and dusk", "I must climb to the very peak, to see all mountains as small"],
"anecdote": "25岁的杜甫北游齐赵(今山东、河北一带),登上东岳泰山,写下了千古名篇《望岳》。诗中'会当凌绝顶,一览众山小'一句,表达了诗人青年时期的壮志豪情和积极进取的精神。这首诗被后人誉为'咏泰山的绝唱',也奠定了杜甫在诗坛的地位。",
"anecdoteEn": "At the age of 25, Du Fu traveled north to Qi and Zhao (now Shandong and Hebei areas), climbed Mount Tai, the eastern sacred mountain, and wrote the timeless masterpiece 'Viewing the Summit'. The line 'I must climb to the very peak, to see all mountains as small' expresses the poet's ambition and enterprising spirit in his youth. This poem is praised by later generations as 'the best poem on Mount Tai' and also established Du Fu's position in the poetry world."
}
},
{
"name": "长安",
"nameEn": "Chang'an",
"year": 744,
"stage": 3,
"coord": [34.3, 108.8],
"event": "初到长安求仕,开始十年困居生涯",
"eventEn": "First arrival in Chang'an seeking official position, beginning ten years of struggling life",
"poem": "朱门酒肉臭,路有冻死骨",
"poemEn": "In vermilion gates, wine and meat rot; on the road, frozen bones lie",
"image": "./images/changan.jpg",
"fallbackImage": "https://picsum.photos/id/1043/800/600",
"culture": {
"lines": ["朱门酒肉臭,路有冻死骨", "荣枯咫尺异,惆怅难再述"],
"linesEn": ["In vermilion gates, wine and meat rot; on the road, frozen bones lie", "Prosperity and decline differ within inches; sorrow is hard to recount"],
"anecdote": "杜甫怀着'致君尧舜上,再使风俗淳'的政治理想来到长安,但仕途不顺,一直未能得到重用。在长安的十年间,他目睹了上层社会的奢侈腐化和底层人民的苦难生活,思想发生了深刻变化,诗歌创作也从早期的浪漫主义转向现实主义,写下了许多反映社会现实的优秀诗篇。",
"anecdoteEn": "Du Fu came to Chang'an with the political ideal of 'assisting the emperor to be like Yao and Shun, and making the customs pure again', but his official career was not smooth, and he was never重用. During his ten years in Chang'an, he witnessed the luxury and corruption of the upper class and the苦难 of the底层 people, his thoughts underwent profound changes, and his poetic creation also shifted from early romanticism to realism, writing many excellent poems reflecting social reality."
}
},
{
"name": "奉先",
"nameEn": "Fengxian",
"year": 755,
"stage": 3,
"coord": [35.0, 109.3],
"event": "回家省亲,途经骊山,作《自京赴奉先县咏怀五百字》",
"eventEn": "Returned home to visit relatives, passing through Mount Li, composing 'Five Hundred Words of Chanting Thoughts on the Journey from the Capital to Fengxian County'",
"poem": "入门闻号啕,幼子饥已卒",
"poemEn": "Entering the door, I heard wailing; my youngest son had died of hunger",
"image": "./images/lishan.jpg",
"fallbackImage": "https://picsum.photos/id/1057/800/600",
"culture": {
"lines": ["入门闻号啕,幼子饥已卒", "所愧为人父,无食致夭折"],
"linesEn": ["Entering the door, I heard wailing; my youngest son had died of hunger", "Ashamed to be a father, having no food leading to early death"],
"anecdote": "杜甫从长安回家省亲,途经骊山,看到唐玄宗和杨贵妃在华清宫寻欢作乐,而沿途百姓却处于水深火热之中。到家后,他发现小儿子已经饿死。这一系列的遭遇,使他写出了长诗《自京赴奉先县咏怀五百字》,其中'朱门酒肉臭,路有冻死骨'一句,成为千古名句,深刻揭露了封建社会的阶级矛盾。",
"anecdoteEn": "Du Fu returned home from Chang'an to visit relatives, passing through Mount Li, where he saw Emperor Xuanzong and Consort Yang enjoying themselves in Huaqing Palace, while the people along the way were suffering deeply. When he arrived home, he found that his youngest son had starved to death. These experiences inspired him to write the long poem 'Five Hundred Words of Chanting Thoughts on the Journey from the Capital to Fengxian County', in which the line 'In vermilion gates, wine and meat rot; on the road, frozen bones lie' became an immortal quote, profoundly exposing the class contradictions in feudal society."
}
},
{
"name": "灵武",
"nameEn": "Lingwu",
"year": 756,
"stage": 4,
"coord": [37.9, 106.3],
"event": "安史之乱爆发,前往灵武投奔唐肃宗",
"eventEn": "An Lushan Rebellion broke out, traveling to Lingwu to join Emperor Suzong",
"poem": "国破山河在,城春草木深",
"poemEn": "The country shattered, mountains and rivers remain; the city in spring, grass and trees grow thick",
"image": "./images/fenjie.jpg",
"fallbackImage": "https://picsum.photos/id/1067/800/600",
"culture": {
"lines": ["国破山河在,城春草木深", "感时花溅泪,恨别鸟惊心", "烽火连三月,家书抵万金"],
"linesEn": ["The country shattered, mountains and rivers remain; the city in spring, grass and trees grow thick", "Saddened by the times, flowers shed tears; hating separation, birds alarm the heart", "Beacon fires have lasted three months; a letter from home is worth ten thousand gold"],
"anecdote": "755年,安史之乱爆发,唐玄宗逃往蜀地,长安沦陷。杜甫听到唐肃宗在灵武即位的消息后,立即前往投奔,但途中被叛军俘获,押回长安。在长安期间,他写下了《春望》等反映战乱中百姓苦难的诗篇。后来他设法逃出长安,继续前往灵武,被唐肃宗任命为左拾遗。",
"anecdoteEn": "In 755, the An Lushan Rebellion broke out, Emperor Xuanzong fled to Shu region, and Chang'an fell. After hearing that Emperor Suzong had ascended the throne in Lingwu, Du Fu immediately went to join him, but was captured by rebel forces on the way and taken back to Chang'an. During his time in Chang'an, he wrote poems like 'Spring View' reflecting the suffering of the people during the war. Later, he managed to escape from Chang'an and continued to Lingwu, where he was appointed as Left Remonstrant by Emperor Suzong."
}
},
{
"name": "华州",
"nameEn": "Huazhou",
"year": 758,
"stage": 4,
"coord": [34.5, 109.7],
"event": "因疏救房琯被贬华州司功参军,作'三吏'、'三别'",
"eventEn": "Demoted to Huazhou for defending Fang Guan, composing 'Three Official Poems' and 'Three Farewell Poems'",
"poem": "暮投石壕村,有吏夜捉人",
"poemEn": "At dusk, I lodge in Shihao Village; officials come at night to seize people",
"image": "./images/huazhou.jpg",
"fallbackImage": "https://picsum.photos/id/1081/800/600",
"culture": {
"lines": ["暮投石壕村,有吏夜捉人", "老翁逾墙走,老妇出门看"],
"linesEn": ["At dusk, I lodge in Shihao Village; officials come at night to seize people", "The old man climbs over the wall to flee; the old woman goes out to see"],
"anecdote": "杜甫因上书疏救房琯,触怒唐肃宗,被贬为华州司功参军。在华州期间,他目睹了战乱给人民带来的深重灾难,写下了著名的'三吏'(《新安吏》、《石壕吏》、《潼关吏》)和'三别'(《新婚别》、《垂老别》、《无家别》)。这些诗篇真实地反映了安史之乱中劳动人民的苦难生活,具有深刻的人民性和强烈的现实主义精神,被称为'诗史'。",
"anecdoteEn": "Du Fu was demoted to Huazhou for submitting a memorial to defend Fang Guan, which angered Emperor Suzong. During his time in Huazhou, he witnessed the深重灾难 brought to the people by the war, and wrote the famous 'Three Official Poems' (Xin'an Official, Shihao Official, Tongguan Official) and 'Three Farewell Poems' (Newlywed Farewell, Old Age Farewell, Homeless Farewell). These poems truthfully reflect the suffering of working people during the An Lushan Rebellion, with profound people's character and strong realistic spirit, and are called 'historical poetry'."
}
},
{
"name": "成都",
"nameEn": "Chengdu",
"year": 759,
"stage": 5,
"coord": [30.6, 104.0],
"event": "弃官入蜀,在成都西郊建草堂定居",
"eventEn": "Abandoned official position and entered Shu, building Thatched Cottage in western suburbs of Chengdu to settle",
"poem": "安得广厦千万间,大庇天下寒士俱欢颜",
"poemEn": "How I wish I could get ten thousand spacious houses, to shelter all the poor scholars under heaven with happy faces",
"image": "./images/chengdu.jpg",
"fallbackImage": "https://picsum.photos/id/1036/800/600",
"culture": {
"lines": ["安得广厦千万间,大庇天下寒士俱欢颜", "风雨不动安如山。呜呼!何时眼前突兀见此屋,吾庐独破受冻死亦足"],
"linesEn": ["How I wish I could get ten thousand spacious houses, to shelter all the poor scholars under heaven with happy faces", "Safe and secure like mountains amid wind and rain. Alas! When will such houses suddenly appear before my eyes? Even if my own cottage is destroyed and I freeze to death, I would be satisfied"],
"anecdote": "759年,杜甫因战乱和饥荒,放弃官职,携家带口入蜀避难,最终在成都西郊浣花溪畔建了一座草堂定居下来。在成都的四年间,他得到了严武等朋友的帮助,生活相对安定,创作了大量优秀诗篇,如《茅屋为秋风所破歌》、《春夜喜雨》等。成都草堂后来成为纪念杜甫的重要场所,被誉为'诗圣故居'。",
"anecdoteEn": "In 759, due to war and famine, Du Fu abandoned his official position, took his family to Shu region to take refuge, and finally built a thatched cottage by Huanhua Stream in the western suburbs of Chengdu to settle down. During his four years in Chengdu, he received help from friends like Yan Wu, lived a relatively stable life, and created many excellent poems, such as 'Song of the Thatched Cottage Broken by Autumn Wind' and 'Happy Rain on a Spring Night'. Chengdu Thatched Cottage later became an important place to commemorate Du Fu, known as 'Former Residence of the Poet Saint'."
}
},
{
"name": "梓州",
"nameEn": "Zizhou",
"year": 762,
"stage": 5,
"coord": [31.4, 105.6],
"event": "严武去世,离开成都,流寓梓州",
"eventEn": "After Yan Wu's death, left Chengdu, wandering to Zizhou",
"poem": "细草微风岸,危樯独夜舟",
"poemEn": "Tender grass on微风 shore; dangerous mast, lonely boat at night",
"image": "./images/jiangxinsi.jpg",
"fallbackImage": "https://picsum.photos/id/1045/800/600",
"culture": {
"lines": ["细草微风岸,危樯独夜舟", "星垂平野阔,月涌大江流"],
"linesEn": ["Tender grass on微风 shore; dangerous mast, lonely boat at night", "Stars hang low over vast plain; moon surges with great river flow"],
"anecdote": "762年,杜甫的好友严武去世,失去依靠的杜甫不得不离开成都,开始了在川东一带的漂泊生活。他先后来到梓州、阆州等地,期间他听闻安史之乱结束的消息,写下了《闻官军收河南河北》,诗中'剑外忽传收蓟北,初闻涕泪满衣裳'一句,表达了他听到平叛胜利消息时的激动心情。",
"anecdoteEn": "In 762, Du Fu's good friend Yan Wu died, and Du Fu, who had lost his support, had to leave Chengdu and began a wandering life in eastern Sichuan. He came to Zizhou, Langzhou and other places successively. During this period, he heard the news that the An Lushan Rebellion had ended, and wrote 'Hearing That Government Troops Recovered Henan and Hebei'. The line 'Suddenly came news from beyond Jianmen that Jibei was recovered; on first hearing, tears filled my clothes' expresses his excitement when hearing the news of the victory in suppressing the rebellion."
}
},
{
"name": "夔州",
"nameEn": "Kuizhou",
"year": 765,
"stage": 6,
"coord": [31.0, 109.6],
"event": "到达夔州(今重庆奉节),开始两年多的寓居生活",
"eventEn": "Arrived in Kuizhou (now Fengjie, Chongqing), beginning more than two years of exile life",
"poem": "无边落木萧萧下,不尽长江滚滚来",
"poemEn": "Boundless falling leaves rustle down; endless Yangtze River rolls on",
"image": "./images/kuizhou.jpg",
"fallbackImage": "https://picsum.photos/id/1085/800/600",
"culture": {
"lines": ["风急天高猿啸哀,渚清沙白鸟飞回", "无边落木萧萧下,不尽长江滚滚来", "万里悲秋常作客,百年多病独登台"],
"linesEn": ["Wind urgent, sky high, gibbons wail mournfully; islet clear, sand white, birds fly back", "Boundless falling leaves rustle down; endless Yangtze River rolls on", "Ten thousand miles of sad autumn, always a traveler; hundred years of many illnesses, alone climbing the terrace"],
"anecdote": "765年,杜甫到达夔州,在这里度过了两年多相对稳定的寓居生活。期间,他得到了柏茂琳的帮助,经管一些公田,生活有所改善。在夔州期间,杜甫的诗歌创作达到了新的高峰,写下了《登高》、《秋兴八首》、《阁夜》等大量优秀诗篇。这些诗篇不仅艺术成就很高,而且思想深刻,被后人誉为杜甫诗歌的巅峰之作。",
"anecdoteEn": "In 765, Du Fu arrived in Kuizhou, where he spent more than two years of relatively stable exile life. During this period, he received help from Bai Maolin, managed some public fields, and his life improved somewhat. During his stay in Kuizhou, Du Fu's poetic creation reached a new peak, writing many excellent poems such as 'Climbing High', 'Eight Poems of Autumn Hues', and 'Night in the Pavilion'. These poems not only have high artistic achievements but also profound thoughts, and are praised by later generations as the pinnacle of Du Fu's poetry."
}
},
{
"name": "江陵",
"nameEn": "Jiangling",
"year": 768,
"stage": 7,
"coord": [30.3, 112.2],
"event": "离开夔州,顺江而下,到达江陵",
"eventEn": "Left Kuizhou, traveled downstream along the river, arrived in Jiangling",
"poem": "白日放歌须纵酒,青春作伴好还乡",
"poemEn": "In broad daylight, singing and drinking to my heart's content; with spring as companion, it's good to return home",
"image": "./images/jiangling.jpg",
"fallbackImage": "https://picsum.photos/id/1043/800/600",
"culture": {
"lines": ["剑外忽传收蓟北,初闻涕泪满衣裳", "却看妻子愁何在,漫卷诗书喜欲狂", "白日放歌须纵酒,青春作伴好还乡"],
"linesEn": ["Suddenly came news from beyond Jianmen that Jibei was recovered; on first hearing, tears filled my clothes", "Looking back at my wife and children, where is their sorrow? I casually roll up poems and books, wild with joy", "In broad daylight, singing and drinking to my heart's content; with spring as companion, it's good to return home"],
"anecdote": "768年,杜甫离开夔州,打算返回河南老家。他顺长江而下,先后来到江陵、公安、岳阳等地。在江陵期间,他受到了当地官员的礼遇,但由于年老体衰,加上路途遥远,他最终未能实现返回河南老家的愿望。在江陵,他写下了《登岳阳楼》等著名诗篇,表达了他晚年漂泊的凄凉和对国家命运的忧虑。",
"anecdoteEn": "In 768, Du Fu left Kuizhou, intending to return to his hometown in Henan. He traveled downstream along the Yangtze River, coming to Jiangling, Gongan, Yueyang and other places successively. During his stay in Jiangling, he was treated courteously by local officials, but due to old age and poor health, plus the long journey, he ultimately failed to realize his wish to return to his hometown in Henan. In Jiangling, he wrote famous poems like 'Climbing Yueyang Tower', expressing his desolation of wandering in his later years and his worry about the fate of the country."
}
},
{
"name": "岳阳",
"nameEn": "Yueyang",
"year": 769,
"stage": 7,
"coord": [29.3, 113.1],
"event": "登岳阳楼,作《登岳阳楼》",
"eventEn": "Climbed Yueyang Tower, composing 'Climbing Yueyang Tower'",
"poem": "吴楚东南坼,乾坤日夜浮",
"poemEn": "Wu and Chu split in southeast; heaven and earth float day and night",
"image": "./images/yueyang.jpg",
"fallbackImage": "https://picsum.photos/id/1048/800/600",
"culture": {
"lines": ["昔闻洞庭水,今上岳阳楼", "吴楚东南坼,乾坤日夜浮", "亲朋无一字,老病有孤舟"],
"linesEn": ["I heard of Dongting Lake before, now I climb Yueyang Tower", "Wu and Chu split in southeast; heaven and earth float day and night", "No word from relatives and friends; old, ill, with a lonely boat"],
"anecdote": "769年,杜甫到达岳阳,登上了著名的岳阳楼,写下了《登岳阳楼》一诗。诗中'吴楚东南坼,乾坤日夜浮'一句,以雄奇的笔触描绘了洞庭湖的壮阔景象,被誉为'古今绝唱'。同时,诗中也流露出诗人晚年漂泊无依的凄凉处境和对国家动荡不安的忧虑之情。",
"anecdoteEn": "In 769, Du Fu arrived in Yueyang and climbed the famous Yueyang Tower, writing the poem 'Climbing Yueyang Tower'. The line 'Wu and Chu split in southeast; heaven and earth float day and night' depicts the magnificent scenery of Dongting Lake with bold strokes, praised as 'the best poem through the ages'. At the same time, the poem also reveals the poet's desolate situation of wandering without support in his later years and his worry about the country's turbulence."
}
},
{
"name": "潭州",
"nameEn": "Tanzhou",
"year": 770,
"stage": 8,
"coord": [28.2, 112.9],
"event": "漂泊至潭州(今湖南长沙),抱病在身",
"eventEn": "Wandered to Tanzhou (now Changsha, Hunan), ill in body",
"poem": "岁暮阴阳催短景,天涯霜雪霁寒宵",
"poemEn": "At year's end, yin and yang hasten short days; at world's end, frost and snow clear cold night",
"image": "./images/hengyang.jpg",
"fallbackImage": "https://picsum.photos/id/1089/800/600",
"culture": {
"lines": ["岁暮阴阳催短景,天涯霜雪霁寒宵", "五更鼓角声悲壮,三峡星河影动摇"],
"linesEn": ["At year's end, yin and yang hasten short days; at world's end, frost and snow clear cold night", "At fifth watch, drum and horn sounds mournful; Three Gorges star river shadows sway"],
"anecdote": "770年,杜甫漂泊至潭州,此时他已经59岁,年老体衰,贫病交加。在潭州,他得到了当地官员和朋友的一些帮助,但病情日益加重。这一年冬天,杜甫在从潭州前往岳阳的船上逝世,结束了他颠沛流离的一生。杜甫的诗歌深刻反映了唐朝由盛转衰的历史过程,被后人尊称为'诗史',他本人也被尊称为'诗圣'。",
"anecdoteEn": "In 770, Du Fu wandered to Tanzhou, at the age of 59, old, frail, poor and ill. In Tanzhou, he received some help from local officials and friends, but his condition deteriorated day by day. That winter, Du Fu passed away on a boat traveling from Tanzhou to Yueyang, ending his wandering life. Du Fu's poems profoundly reflect the historical process of the Tang Dynasty from prosperity to decline, and are respected by later generations as 'historical poetry', and he himself is also respected as 'Poet Saint'."
}
}
];
/* 初始化地图 */
function initMap() {
// 创建地图实例
map = L.map('map', {
preferCanvas: true,
zoomControl: false,
minZoom: 3,
maxZoom: 14
}).setView([34, 110], 5);
// 添加底图图层(使用高德地图服务)
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: '1234',
crossOrigin: true,
reuseTiles: true,
maxZoom: 14
}).addTo(map);
// 添加缩放控件
L.control.zoom({position: 'bottomright'}).addTo(map);
// 绘制阶段颜色指示器
initStageIndicators();
// 绘制路线和点位
drawPathSegments();
createPointMarkers();
// 创建骑马标记
createHorseMarker();
// 隐藏加载器
setTimeout(() => {
document.getElementById('mapLoader').style.opacity = '0';
document.getElementById('mapLoader').style.pointerEvents = 'none';
setTimeout(() => {
document.getElementById('mapLoader').style.display = 'none';
}, 500);
}, 1000);
}
/* 绘制路线分段 */
function drawPathSegments() {
// 清除已有路线
pathLines.forEach(line => map.removeLayer(line));
pathLines = [];
// 绘制每段路线(直接连接相邻两点)
for (let i = 0; i < allPoints.length - 1; i++) {
const startPoint = allPoints[i];
const endPoint = allPoints[i + 1];
// 使用起点的阶段颜色
const stageInfo = stageNames.find(s => s.stage === startPoint.stage);
const color = stageInfo ? stageInfo.color : '#000000';
// 使用蚂蚁线绘制路线
const antPath = L.polyline.antPath(
[startPoint.coord, endPoint.coord],
{
"paused": false,
"reverse": false,
"delay": 1000,
"dashArray": [10, 20],
"weight": 3,
"color": color,
"pulseColor": '#ffffff',
"opacity": 0.7
}
).addTo(map);
pathLines.push(antPath);
}
}
/* 创建点位标记 */
function createPointMarkers() {
// 初始化加载进度
const progressBar = document.getElementById('progressBar');
allPoints.forEach((point, index) => {
// 更新加载进度
progressBar.style.width = `${(index / allPoints.length) * 100}%`;
// 获取阶段对应的颜色
const stageInfo = stageNames.find(s => s.stage === point.stage);
const color = stageInfo ? stageInfo.color : '#000000';
// 创建圆形标记
const marker = L.circleMarker(point.coord, {
radius: 10,
fillColor: color,
color: '#ffffff',
weight: 2,
opacity: 1,
fillOpacity: 0.8
}).addTo(map);
// 存储原始样式,用于后续加亮效果
marker.originalStyle = {
radius: 10,
fillColor: color,
color: '#ffffff',
weight: 2,
opacity: 1,
fillOpacity: 0.8
};
// 加亮样式 - 颜色加深、尺寸更大
// 生成深色版本的颜色
const darkenColor = (color) => {
// 简单的颜色加深方法:移除透明度并稍微加深颜色值
let hex = color.replace('#', '');
// 转换为RGB
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// 深色处理(减少亮度20%)
r = Math.max(0, Math.floor(r * 0.8));
g = Math.max(0, Math.floor(g * 0.8));
b = Math.max(0, Math.floor(b * 0.8));
// 转回十六进制
return '#' + [r, g, b].map(x => {
const hex = x.toString(16);
return hex.length === 1 ? '0' + hex : hex;
}).join('');
};
const darkColor = darkenColor(color);
marker.highlightStyle = {
radius: 18, // 更大的半径
fillColor: darkColor, // 使用加深后的颜色
color: '#ffd700', // 金色边框
weight: 4, // 更粗的边框
opacity: 1,
fillOpacity: 1,
className: 'highlight-marker' // 添加类名用于可能的CSS动画
};
// 添加点击事件
marker.on('click', () => {
currentPointIndex = index;
showPointInfo(point);
moveHorseToPoint(index);
});
// 添加悬停效果
marker.on('mouseover', () => {
marker.setStyle(marker.highlightStyle);
});
marker.on('mouseout', () => {
// 只有当不是当前选中的点时才恢复样式
if (index !== currentPointIndex) {
marker.setStyle(marker.originalStyle);
}
});
// 添加弹出信息 - 中英文并行显示
marker.bindPopup(`<div class="bilingual-text">
<div><b>${point.name}</b></div>
<div style="font-size: 14px;">${point.year}年 | ${point.event}</div>
<div><b>${point.nameEn}</b></div>
<div style="font-size: 12px;">${point.year} A.D. | ${point.eventEn}</div>
</div>`, {
className: 'custom-popup',
closeButton: true,
minWidth: 200
});
markers.push(marker);
});
}
/* 创建骑马标记 */
function createHorseMarker() {
// 创建自定义图标
const horseIcon = L.divIcon({
html: '🐎',
className: 'horse-marker',
iconSize: [30, 30],
iconAnchor: [15, 15]
});
// 创建标记
horseMarker = L.marker(allPoints[0].coord, {
icon: horseIcon,
zIndexOffset: 1000
}).addTo(map);
// 添加轻微的上下浮动动画
const markerElement = horseMarker.getElement();
markerElement.style.animation = 'horseFloat 3s ease-in-out infinite';
}
/* 移动骑马标记到指定点位 */
function moveHorseToPoint(index) {
const point = allPoints[index];
// 平滑移动效果
if (horseMarker) {
// 获取当前位置和目标位置
const currentLatLng = horseMarker.getLatLng();
const targetLatLng = L.latLng(point.coord);
// 创建路径线段数组,使马能够沿着路径移动
const pathPoints = [];
const numSteps = 50; // 路径上的点数量,越多路径越平滑
// 计算两点之间的路径点
for (let i = 0; i <= numSteps; i++) {
const progress = i / numSteps;
// 增加一些随机性,使路径看起来更自然
const randomFactor = 0.1 * (Math.sin(progress * Math.PI * 4) + Math.random() * 0.5);
const easedProgress = easeInOutCubic(progress);
// 计算中间位置,添加一些曲线效果
const lat = currentLatLng.lat +
(targetLatLng.lat - currentLatLng.lat) * easedProgress +
randomFactor * 0.1;
const lng = currentLatLng.lng +
(targetLatLng.lng - currentLatLng.lng) * easedProgress +
randomFactor * 0.1;
pathPoints.push({ lat, lng, progress });
}
// 创建马蹄印动画效果
createHorseTracks(currentLatLng, targetLatLng, numSteps);
// 移动到新位置 - 平滑过渡
const duration = 3000; // 动画持续时间,增加到3秒使移动更自然
const startTime = performance.now();
function moveHorse(timestamp) {
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);
// 使用缓动函数使动画更自然
const easedProgress = easeInOutCubic(progress);
// 找到当前进度对应的路径点
let currentPathPoint;
for (let i = 0; i < pathPoints.length; i++) {
if (pathPoints[i].progress >= easedProgress) {
currentPathPoint = pathPoints[i];
break;
}
}
if (currentPathPoint) {
// 更新骑马标记的位置
horseMarker.setLatLng(L.latLng(currentPathPoint.lat, currentPathPoint.lng));
if (progress < 1) {
requestAnimationFrame(moveHorse);
} else {
// 动画完成后更新点位状态
updateMarkerStates();
}
}
}
// 开始动画
requestAnimationFrame(moveHorse);
}
}
/* 创建马蹄印效果 */
function createHorseTracks(startPoint, endPoint, numSteps) {
// 计算每步之间的距离
const latStep = (endPoint.lat - startPoint.lat) / numSteps;
const lngStep = (endPoint.lng - startPoint.lng) / numSteps;
// 创建马蹄印标记
for (let i = 0; i < numSteps; i += 5) { // 每隔5步创建一个马蹄印
const lat = startPoint.lat + latStep * i;
const lng = startPoint.lng + lngStep * i;
// 随机偏移,使马蹄印看起来更自然
const randomLat = lat + (Math.random() - 0.5) * 0.01;
const randomLng = lng + (Math.random() - 0.5) * 0.01;
// 创建临时的马蹄印标记
const trackIcon = L.divIcon({
html: '👣',
className: 'horse-track',
iconSize: [30, 30],
iconAnchor: [15, 15]
});
const trackMarker = L.marker([randomLat, randomLng], {
icon: trackIcon,
zIndexOffset: 500
}).addTo(map);
// 设置淡出动画
setTimeout(() => {
let opacity = 1;
const fadeInterval = setInterval(() => {
opacity -= 0.1;
trackMarker.setOpacity(opacity);
if (opacity <= 0) {
clearInterval(fadeInterval);
map.removeLayer(trackMarker);
}
}, 100);
}, 1000);
}
}
/* 缓动函数 - 使动画更自然 */
function easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
/* 显示点位信息 */
function showPointInfo(point) {
const card = document.getElementById('infoCard');
const title = document.getElementById('infoTitle');
const year = document.getElementById('infoYear');
const description = document.getElementById('infoDescription');
const poem = document.getElementById('infoPoem');
const anecdote = document.getElementById('infoAnecdote');
const image = document.getElementById('infoImage');
// 设置内容 - 中英文并行显示
title.innerHTML = `<div class="bilingual-text">
<div class="chinese-text">${point.name}</div>
<div class="english-text">${point.nameEn}</div>
</div>`;
year.innerHTML = `<div class="bilingual-text">
<div class="chinese-text">${point.year}年 | ${point.event}</div>
<div class="english-text">${point.year} A.D. | ${point.eventEn}</div>
</div>`;
// 检查是否有文化信息
if (point.culture && point.culture.lines) {
// 显示诗句题目和内容,中英文并行显示
const poemTitle = point.culture.title || '诗句'; // 默认题目
const poemTitleEn = point.culture.titleEn || 'Verse'; // 默认英文题目
const poemHtml = `
<div class="bilingual-text poem-title">
<div class="chinese-text">${poemTitle}</div>
<div class="english-text">${poemTitleEn}</div>
</div>
<div class="bilingual-text">
<div class="chinese-text poem-highlight">${point.culture.lines.join('<br>')}</div>
<div class="english-text">${point.culture.linesEn.join('<br>')}</div>
</div>`;
poem.innerHTML = poemHtml;
// 显示文化轶事,中英文并行显示
if (point.culture.anecdote) {
anecdote.innerHTML = `<div class="bilingual-text">
<div class="chinese-text">${point.culture.anecdote}</div>
<div class="english-text">${point.culture.anecdoteEn}</div>
</div>`;
anecdote.style.display = 'block';
} else {
anecdote.style.display = 'none';
}
} else {
poem.innerHTML = `<div class="bilingual-text">
<div class="chinese-text poem-highlight">${point.poem}</div>
<div class="english-text">${point.poemEn}</div>
</div>`;
anecdote.style.display = 'none';
}
// 设置图片
image.onload = function() {
image.classList.remove('image-loading');
};
image.onerror = function() {
// 如果加载失败,使用备用图片
image.src = point.fallbackImage || 'https://picsum.photos/id/1000/800/600';
image.classList.remove('image-loading');
};
// 开始加载图片
image.classList.add('image-loading');
image.src = point.image;
// 显示卡片
setTimeout(() => {
card.classList.add('active');
}, 100);
// 滚动到顶部
card.querySelector('.info-content').scrollTop = 0;
// 启动自动滚动
startAutoScroll();
}
/* 初始化阶段颜色指示器 - 中英文并行显示 */
function initStageIndicators() {
const container = document.getElementById('stageColors');
container.innerHTML = '';
// 同时显示中文和英文的阶段名称
stageNames.forEach((stage, index) => {
const item = document.createElement('div');
item.className = 'stage-item';
const colorBox = document.createElement('div');
colorBox.className = 'stage-color';
colorBox.style.backgroundColor = stage.color;
const nameContainer = document.createElement('div');
nameContainer.className = 'bilingual-text';
const nameZhSpan = document.createElement('div');
nameZhSpan.className = 'chinese-text';
nameZhSpan.textContent = stage.name;
const nameEnSpan = document.createElement('div');
nameEnSpan.className = 'english-text';
nameEnSpan.textContent = stageNamesEn[index]?.name || '';
nameContainer.appendChild(nameZhSpan);
nameContainer.appendChild(nameEnSpan);
item.appendChild(colorBox);
item.appendChild(nameContainer);
container.appendChild(item);
});
}
/* 更新标记状态 */
function updateMarkerStates() {
markers.forEach((marker, index) => {
if (index === currentPointIndex) {
// 当前点使用高亮样式
marker.setStyle(marker.highlightStyle);
marker.openPopup(); // 打开当前点的弹出信息
} else {
// 其他点使用原始样式
marker.setStyle(marker.originalStyle);
marker.closePopup(); // 关闭其他点的弹出信息
}
});
}
/* 显示前一个点位 */
function prevPoint() {
currentPointIndex = (currentPointIndex - 1 + allPoints.length) % allPoints.length;
const point = allPoints[currentPointIndex];
showPointInfo(point);
moveHorseToPoint(currentPointIndex);
}
/* 显示下一个点位 */
function nextPoint() {
currentPointIndex = (currentPointIndex + 1) % allPoints.length;
const point = allPoints[currentPointIndex];
showPointInfo(point);
moveHorseToPoint(currentPointIndex);
}
/* 切换自动播放 */
function toggleAnimation() {
const playBtn = document.getElementById('playBtn');
if (isAnimating) {
// 停止动画
clearInterval(animationInterval);
playBtn.textContent = '▶';
playBtn.setAttribute('data-tooltip', '自动播放');
} else {
// 开始动画
animationInterval = setInterval(nextPoint, animationDelay);
playBtn.textContent = '⏸';
playBtn.setAttribute('data-tooltip', '暂停自动播放');
}
isAnimating = !isAnimating;
}
/* 隐藏信息卡片 */
function hideInfoCard() {
const card = document.getElementById('infoCard');
card.classList.remove('active');
// 停止自动滚动
stopAutoScroll();
}
/* 切换卡片折叠状态 */
function toggleCardCollapse() {
const card = document.getElementById('infoCard');
card.classList.toggle('collapsed');
}
/* 开始自动滚动 */
function startAutoScroll() {
if (!isScrolling) return;
const content = document.querySelector('.info-content');
function scrollContent() {
if (!isScrolling) return;
// 检查是否到达底部
if (content.scrollTop + content.clientHeight >= content.scrollHeight) {
// 回到顶部
content.scrollTop = 0;
} else {
// 继续滚动
content.scrollTop += scrollSpeed;
}
scrollAnimationId = requestAnimationFrame(scrollContent);
}
// 先清除之前的动画
stopAutoScroll();
// 开始新的动画
scrollAnimationId = requestAnimationFrame(scrollContent);
}
/* 停止自动滚动 */
function stopAutoScroll() {
if (scrollAnimationId) {
cancelAnimationFrame(scrollAnimationId);
scrollAnimationId = null;
}
}
/* 切换自动滚动状态 */
function toggleScroll() {
const pauseBtn = document.getElementById('pauseScrollBtn');
if (isScrolling) {
// 暂停滚动
isScrolling = false;
pauseBtn.textContent = '▶';
stopAutoScroll();
} else {
// 继续滚动
isScrolling = true;
pauseBtn.textContent = '⏸';
startAutoScroll();
}
}
/* 中英文并行显示后,不再需要语言切换功能 */
function toggleLanguage() {
// 函数保留但不执行任何操作
console.log('中英文已并行显示,无需切换语言');
}
/* 回到顶部 */
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
/* 处理滚动事件 */
function handleScroll() {
const backToTopBtn = document.getElementById('backToTop');
const currentScrollY = window.scrollY;
// 显示/隐藏回到顶部按钮
if (currentScrollY > 300) {
backToTopBtn.classList.add('visible');
} else {
backToTopBtn.classList.remove('visible');
}
// 保存滚动位置
lastScrollY = currentScrollY;
}
/* 页面加载完成后执行 */
window.addEventListener('load', function() {
// 初始化地图
initMap();
// 显示第一个点的信息
if (allPoints.length > 0) {
setTimeout(() => {
showPointInfo(allPoints[currentPointIndex]);
}, 1500);
}
// 添加滚动事件监听
window.addEventListener('scroll', handleScroll);
// 初始检查滚动位置
handleScroll();
// 添加信息卡片点击事件,展开/折叠卡片
const infoCard = document.getElementById('infoCard');
infoCard.addEventListener('click', function(e) {
// 如果点击的不是关闭按钮或折叠按钮,不执行操作
if (e.target === document.querySelector('.info-close') || e.target === document.querySelector('.collapse-btn')) {
return;
}
// 如果卡片已折叠,则展开
if (infoCard.classList.contains('collapsed')) {
infoCard.classList.remove('collapsed');
}
});
// 点击地图区域隐藏信息卡片(可选功能)
map.on('click', function(e) {
// 检查点击是否在信息卡片外
const cardRect = infoCard.getBoundingClientRect();
const clickX = e.originalEvent.clientX;
const clickY = e.originalEvent.clientY;
if (clickX < cardRect.left || clickX > cardRect.right ||
clickY < cardRect.top || clickY > cardRect.bottom) {
// 点击在卡片外,保持卡片状态不变
}
});
// 防止信息卡片中的链接点击事件冒泡到地图
infoCard.addEventListener('click', function(e) {
e.stopPropagation();
});
// 添加键盘事件监听
document.addEventListener('keydown', function(e) {
if (e.key === 'ArrowLeft') {
prevPoint();
} else if (e.key === 'ArrowRight') {
nextPoint();
} else if (e.key === ' ') {
e.preventDefault(); // 防止空格键滚动页面
toggleAnimation();
}
});
});
</script>
</body>
</html>
请先 登录后发表评论 ~