代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="format-detection" content="telephone=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>汉字一点通</title>
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/common.css" />
<style>
/* 统一所有相关元素的大小 */
.stroke,
.stroke-detector,
.tianzige {
width: 100px;
height: 100px;
}
/* 笔画容器样式 */
#strokes {
position: relative;
height: 120px;
text-align: center;
}
/* 田字格容器样式 */
.tianzige-container {
display: flex;
justify-content: flex-start;
gap: 20px;
flex-wrap: wrap;
margin: 20px 0;
padding-left: 20px;
}
.tianzige {
background-image: url("./assets/tianzige.jpeg");
background-size: cover;
border: 1px solid #000;
position: relative;
z-index: 1;
}
.stroke,
.stroke-detector {
font-size: 50px;
cursor: pointer;
display: inline-block;
transition: transform 0.2s;
touch-action: none;
user-select: none;
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
z-index: 10;
}
.stroke.dragging {
transform: scale(1.2);
opacity: 0.7;
z-index: 1000 !important;
}
.stroke-detector {
z-index: 100;
}
.stroke-detector path {
fill: transparent;
stroke: transparent;
stroke-width: 20px;
}
/* 确保内容不会重叠 */
.content {
position: relative;
}
/* 添加错误状态的样式 */
.stroke.error {
animation: shake 0.5s;
}
@keyframes shake {
0%,
100% {
transform: translateX(-50%);
}
25% {
transform: translateX(-60%);
}
75% {
transform: translateX(-40%);
}
}
.hanzi-scroll {
display: flex;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
padding: 10px;
background: #f8f9fa;
margin: 10px 0;
}
.hanzi-scroll::-webkit-scrollbar {
height: 4px;
}
.hanzi-scroll::-webkit-scrollbar-track {
background: #f1f1f1;
}
.hanzi-scroll::-webkit-scrollbar-thumb {
background: #888;
border-radius: 2px;
}
.hanzi-scroll button {
padding: 5px 10px;
margin: 0 5px;
border: 1px solid #007bff;
background: white;
color: #007bff;
border-radius: 3px;
cursor: pointer;
flex-shrink: 0;
}
.hanzi-scroll button.active {
background: #007bff;
color: white;
}
</style>
</head>
<body>
<script src="js/config.js"></script>
<h1>Break down the characters below into individual strokes</h1>
<div class="hanzi-scroll">
<script>
document.write(
Object.keys(hanziConfig)
.map(
(hanzi) =>
`<button onclick="changeHanzi('${hanzi}')" ${
hanzi === currentHanzi ? 'class="active"' : ""
}>${hanzi}</button>`
)
.join("")
);
</script>
</div>
<div class="content">
<div id="strokes" class="text-center"></div>
<div class="tianzige-container"></div>
</div>
<div class="nav-bottom">
<a href="section2.html" class="btn-link">How to write</a>
<a href="section4.html" class="btn-link">Let’s try to create HANZI</a>
</div>
<script>
let activeStroke = null; // 当前正在拖动的笔画元素
let initialX, initialY; // 触摸开始时的初始坐标
async function changeHanzi(hanzi) {
try {
// 更新 URL 参数
const url = new URL(window.location);
url.searchParams.set("hanzi", hanzi);
window.history.pushState({}, "", url);
window.currentHanzi = hanzi;
// 更新按钮状态
document.querySelectorAll(".hanzi-scroll button").forEach((btn) => {
btn.classList.toggle("active", btn.textContent === hanzi);
});
// 清空现有内容
document.getElementById("strokes").innerHTML = "";
document.querySelector(".tianzige-container").innerHTML = "";
// 加载新汉字的数据
const response = await fetch(`assets/hanzi_data/${hanzi}.json`);
if (!response.ok) {
throw new Error(`Failed to load data for ${hanzi}`);
}
const data = await response.json();
// 重新初始化笔画和田字格
initializeStrokes(data.strokes);
} catch (error) {
console.error(`Error loading ${hanzi}:`, error);
alert(
`Failed to load character ${hanzi}. Please check the console for details.`
);
}
}
// 将原来的初始化代码封装成函数
function initializeStrokes(strokes) {
const strokeContainer = document.getElementById("strokes");
const tianzigeContainer = document.querySelector(".tianzige-container");
// 创建田字格
strokes.forEach((stroke, index) => {
const tianzige = document.createElement("div");
tianzige.classList.add("tianzige");
tianzige.setAttribute("id", `tianzige-${index}`);
tianzige.setAttribute("data-index", index);
tianzigeContainer.appendChild(tianzige);
});
// 创建检测层
const detector = document.createElement("div");
detector.classList.add("stroke", "stroke-detector");
detector.innerHTML = `
<svg width="100" height="100" viewBox="0 0 1024 1024">
<g transform="scale(1, -1) translate(0, -1024)">
${strokes
.map(
(stroke, index) => `
<path d="${stroke}"
data-index="${index}"
stroke-linecap="round"
stroke-linejoin="round">
</path>`
)
.join("")}
</g>
</svg>
`;
// 创建实际的笔画元素
strokes.forEach((stroke, index) => {
const strokeElement = document.createElement("div");
strokeElement.classList.add("stroke");
strokeElement.setAttribute("id", `stroke-${index}`);
strokeElement.setAttribute("data-index", index);
strokeElement.innerHTML = `
<svg width="100" height="100" viewBox="0 0 1024 1024">
<g transform="scale(1, -1) translate(0, -1024)">
<path d="${stroke}"
stroke="black"
stroke-width="50"
fill="black">
</path>
</g>
</svg>
`;
strokeContainer.appendChild(strokeElement);
});
// 添加检测层
strokeContainer.appendChild(detector);
// 重新绑定事件监听器
bindEventListeners(detector);
}
// 修改页面加载事件
document.addEventListener("DOMContentLoaded", function () {
// 初始化显示
changeHanzi(currentHanzi);
});
// 处理触摸移动事件
document.addEventListener("touchmove", function (e) {
console.log("Document touchmove");
if (!activeStroke) {
console.log("No active stroke");
return;
}
e.preventDefault();
const touch = e.touches[0];
console.log("Moving to:", touch.clientX, touch.clientY);
// 计算新位置
let newX = touch.clientX - initialX;
let newY = touch.clientY - initialY;
// 更新笔画位置
activeStroke.style.left = `${newX}px`;
activeStroke.style.top = `${newY}px`;
console.log("Stroke moved to:", newX, newY);
});
// 处理触摸结束事件
document.addEventListener("touchend", function (e) {
console.log("Document touchend");
if (!activeStroke) {
console.log("No active stroke to end");
return;
}
const strokeIndex = parseInt(activeStroke.getAttribute("data-index"));
const targetTianzige = document.getElementById(
`tianzige-${strokeIndex}`
);
const tianzigeRect = targetTianzige.getBoundingClientRect();
const strokeRect = activeStroke.getBoundingClientRect();
// 检查笔画是否放在对应的田字格内
if (isOverlapping(strokeRect, tianzigeRect)) {
console.log("Overlapping with correct tianzige");
if (!targetTianzige.contains(activeStroke)) {
// 放入正确的田字格
targetTianzige.appendChild(activeStroke);
activeStroke.style.zIndex =
parseInt(activeStroke.getAttribute("data-index")) + 1;
activeStroke.style.left = "0";
activeStroke.style.top = "0";
activeStroke.style.transform = "none";
// 移除这个笔画的所有事件监听
const strokeDetector = document.querySelector(
`.stroke-detector path[data-index="${strokeIndex}"]`
);
if (strokeDetector) {
strokeDetector.style.display = "none"; // 隐藏检测区域
}
// 移除这个笔画的样式和事件
activeStroke.style.cursor = "default";
activeStroke.style.pointerEvents = "none";
}
} else {
// 检查是否放在了错误的田字格上
const allTianzige = document.querySelectorAll(".tianzige");
let isOnWrongTianzige = false;
allTianzige.forEach((tianzige) => {
const rect = tianzige.getBoundingClientRect();
if (isOverlapping(strokeRect, rect)) {
isOnWrongTianzige = true;
}
});
if (isOnWrongTianzige) {
// 显示错误动画
activeStroke.classList.add("error");
setTimeout(() => {
activeStroke.classList.remove("error");
}, 500);
}
// 还原到原始位置
activeStroke.style.left = "50%";
activeStroke.style.top = "0";
activeStroke.style.transform = "translateX(-50%)";
}
activeStroke.classList.remove("dragging");
activeStroke = null;
});
// 辅助函数:检查两个矩形是否重叠
function isOverlapping(rect1, rect2) {
return !(
rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom
);
}
// 添加事件绑定函数
function bindEventListeners(detector) {
// 为每个笔画路径添加触摸开始事件
detector.querySelectorAll("path").forEach((path) => {
path.addEventListener("touchstart", function (e) {
e.preventDefault();
const strokeIndex = this.getAttribute("data-index");
activeStroke = document.getElementById(`stroke-${strokeIndex}`);
if (activeStroke) {
console.log("Touch start on stroke:", strokeIndex);
activeStroke.classList.add("dragging");
const touch = e.touches[0];
const strokeRect = activeStroke.getBoundingClientRect();
// 计算触摸点相对于笔画元素的偏移
initialX = touch.clientX - strokeRect.left;
initialY = touch.clientY - strokeRect.top;
}
});
});
}
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。