222 lines
5.9 KiB
HTML
222 lines
5.9 KiB
HTML
<!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;
|
|
font-family: "Microsoft YaHei", sans-serif;
|
|
background: #f0f8ff;
|
|
}
|
|
|
|
h2 {
|
|
text-align: center;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
#map {
|
|
position: relative;
|
|
width: 90%;
|
|
max-width: 1200px;
|
|
height: 840px;
|
|
margin: 0 auto;
|
|
border: 2px solid #333;
|
|
background: url("background.jpeg") no-repeat center/cover;
|
|
overflow: hidden;
|
|
}
|
|
|
|
svg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
#redFlag {
|
|
width: 30px;
|
|
height: 30px;
|
|
background: url("hongqi.jpg") no-repeat center/contain;
|
|
position: absolute;
|
|
transform: translate(-50%, -50%); /* 使红旗中心对准路径 */
|
|
z-index: 10;
|
|
/* 添加备用背景样式,以防图片加载失败 */
|
|
background-color: red;
|
|
border-radius: 50% 0;
|
|
}
|
|
|
|
#subtitle {
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
font-size: 16px;
|
|
height: 24px;
|
|
}
|
|
|
|
#controls {
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
button {
|
|
margin: 0 5px;
|
|
padding: 6px 12px;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h2>红军长征路线动画演示</h2>
|
|
|
|
<div id="map">
|
|
<svg viewBox="0 0 900 500">
|
|
<!-- 路线 -->
|
|
<path id="route"
|
|
d="M100,350 C150,340 200,320 250,300 300,280 350,260 400,240 450,220 500,200 550,180 600,160 650,140 700,100"
|
|
stroke="red" stroke-width="2" fill="none" stroke-dasharray="4,4" />
|
|
</svg>
|
|
|
|
<!-- 小红旗 -->
|
|
<div id="redFlag"></div>
|
|
</div>
|
|
|
|
<div id="subtitle">1934年10月 从江西瑞金出发</div>
|
|
|
|
<div id="controls">
|
|
<button onclick="play()">开始</button>
|
|
<button onclick="pause()">暂停</button>
|
|
<button onclick="reset()">重播</button>
|
|
</div>
|
|
|
|
<script>
|
|
const flag = document.getElementById("redFlag");
|
|
const subtitle = document.getElementById("subtitle");
|
|
const route = document.getElementById("route");
|
|
const map = document.getElementById("map");
|
|
|
|
const timeline = [
|
|
{ p: 0, text: "1934年10月 从江西瑞金出发" },
|
|
{ p: 10, text: "1934年11月 血战湘江" },
|
|
{ p: 20, text: "1935年1月 遵义会议" },
|
|
{ p: 35, text: "四渡赤水" },
|
|
{ p: 50, text: "强渡大渡河,飞夺泸定桥" },
|
|
{ p: 65, text: "翻越夹金山" },
|
|
{ p: 80, text: "穿越草地,懋功会师" },
|
|
{ p: 95, text: "1935年10月 到达吴起镇" }
|
|
];
|
|
|
|
let animationId;
|
|
let startTime;
|
|
let pausedTime = 0;
|
|
let isPlaying = false;
|
|
const duration = 20000; // 20秒
|
|
|
|
// 获取SVG路径的总长度
|
|
const pathLength = route.getTotalLength();
|
|
|
|
// 根据进度百分比获取路径上的点
|
|
function getPointOnPath(percent) {
|
|
const distance = percent * pathLength / 100;
|
|
const point = route.getPointAtLength(distance);
|
|
|
|
// 将SVG坐标转换为页面坐标
|
|
const svgPoint = route.ownerSVGElement.createSVGPoint();
|
|
svgPoint.x = point.x;
|
|
svgPoint.y = point.y;
|
|
|
|
const matrix = route.ownerSVGElement.getScreenCTM();
|
|
const transformedPoint = svgPoint.matrixTransform(matrix);
|
|
|
|
// 转换为相对于#map容器的坐标
|
|
const mapRect = map.getBoundingClientRect();
|
|
|
|
return {
|
|
x: transformedPoint.x - mapRect.left,
|
|
y: transformedPoint.y - mapRect.top
|
|
};
|
|
}
|
|
|
|
// 更新红旗位置
|
|
function updateFlagPosition(percent) {
|
|
const point = getPointOnPath(percent);
|
|
flag.style.left = `${point.x}px`;
|
|
flag.style.top = `${point.y}px`;
|
|
}
|
|
|
|
// 动画循环
|
|
function animate(timestamp) {
|
|
if (!startTime) startTime = timestamp;
|
|
|
|
const elapsed = timestamp - startTime + pausedTime;
|
|
const progress = Math.min(elapsed / duration, 1) * 100;
|
|
|
|
updateFlagPosition(progress);
|
|
updateSubtitle(progress);
|
|
|
|
if (progress < 100) {
|
|
animationId = requestAnimationFrame(animate);
|
|
} else {
|
|
isPlaying = false;
|
|
}
|
|
}
|
|
|
|
function play() {
|
|
if (!isPlaying) {
|
|
isPlaying = true;
|
|
startTime = null;
|
|
animationId = requestAnimationFrame(animate);
|
|
}
|
|
}
|
|
|
|
function pause() {
|
|
if (isPlaying) {
|
|
isPlaying = false;
|
|
cancelAnimationFrame(animationId);
|
|
if (startTime) {
|
|
pausedTime += performance.now() - startTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
pause();
|
|
pausedTime = 0;
|
|
updateFlagPosition(0);
|
|
subtitle.textContent = timeline[0].text;
|
|
}
|
|
|
|
function updateSubtitle(percent) {
|
|
for (let i = timeline.length - 1; i >= 0; i--) {
|
|
if (percent >= timeline[i].p) {
|
|
subtitle.textContent = timeline[i].text;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 页面加载完成后初始化红旗位置
|
|
window.addEventListener('load', function() {
|
|
// 确保红旗在初始位置可见
|
|
updateFlagPosition(0);
|
|
|
|
// 检查红旗图片是否加载成功
|
|
const img = new Image();
|
|
img.onload = function() {
|
|
// 图片加载成功,使用图片作为背景
|
|
flag.style.backgroundImage = 'url("hongqi.jpg")';
|
|
flag.style.backgroundColor = 'transparent';
|
|
};
|
|
img.onerror = function() {
|
|
// 图片加载失败,使用备用样式
|
|
console.warn('红旗图片加载失败,使用备用样式');
|
|
flag.style.backgroundImage = 'none';
|
|
flag.style.backgroundColor = 'red';
|
|
};
|
|
img.src = 'hongqi.jpg';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |