Files
recommend/static/js/recitation.js

286 lines
8.7 KiB
JavaScript
Raw Normal View History

// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܽű<DCBD>
let extractedItems = [];
let sortedItems = [];
let currentSpinIndex = 0;
let isSpinning = false;
// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD> - ת<><D7AA>ʹ<EFBFBD>ò<EFBFBD>ͬ<EFBFBD><CDAC>ɫ
const colors = [
'#667eea', '#764ba2', '#f093fb', '#f5576c',
'#4facfe', '#00f2fe', '#43e97b', '#38f9d7',
'#fa709a', '#fee140', '#30cfd0', '#330867'
];
// DOMԪ<4D><D4AA>
const textInput = document.getElementById('textInput');
const extractBtn = document.getElementById('extractBtn');
const extractedSection = document.getElementById('extractedSection');
const itemsList = document.getElementById('itemsList');
const itemCount = document.getElementById('itemCount');
const sortBtn = document.getElementById('sortBtn');
const wheelSection = document.getElementById('wheelSection');
const wheel = document.getElementById('wheel');
const spinBtn = document.getElementById('spinBtn');
const currentItem = document.getElementById('currentItem');
const resultSection = document.getElementById('resultSection');
const sortedList = document.getElementById('sortedList');
const resetBtn = document.getElementById('resetBtn');
// <20><>ȡ֪ʶ<D6AA><CAB6>
extractBtn.addEventListener('click', async () => {
const text = textInput.value.trim();
if (!text) {
alert('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>');
return;
}
extractBtn.disabled = true;
extractBtn.textContent = <><CAB6><EFBFBD><EFBFBD>...';
try {
const response = await fetch('/api/extract', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text })
});
const data = await response.json();
if (data.success) {
extractedItems = data.items;
displayExtractedItems(extractedItems);
extractedSection.style.display = 'block';
textInput.disabled = true;
} else {
alert(data.message || '<27><>ȡʧ<C8A1><CAA7>');
}
} catch (error) {
console.error('<27><>ȡʧ<C8A1><CAA7>:', error);
alert('<27><>ȡʧ<C8A1>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
} finally {
extractBtn.disabled = false;
extractBtn.textContent = <><CAB6>֪ʶ<D6AA><CAB6>';
}
});
// <20><>ʾ<EFBFBD><CABE>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ŀ
function displayExtractedItems(items) {
itemCount.textContent = items.length;
itemsList.innerHTML = '';
items.forEach((item, index) => {
const tag = document.createElement('span');
tag.className = 'item-tag';
tag.textContent = `${index + 1}. ${item}`;
itemsList.appendChild(tag);
});
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
sortBtn.addEventListener('click', async () => {
if (extractedItems.length === 0) {
alert('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ֪ʶ<D6AA><CAB6>');
return;
}
sortBtn.disabled = true;
sortBtn.textContent = '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...';
try {
const response = await fetch('/api/sort', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ items: extractedItems })
});
const data = await response.json();
if (data.success) {
sortedItems = data.items;
displaySortedItems(sortedItems);
createWheel(sortedItems);
wheelSection.style.display = 'block';
resultSection.style.display = 'block';
currentSpinIndex = 0;
} else {
alert(data.message || '<27><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>');
}
} catch (error) {
console.error('<27><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>:', error);
alert('<27><><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
} finally {
sortBtn.disabled = false;
sortBtn.textContent = '<27><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>';
}
});
// <20><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA> - ʹ<><CAB9>SVGʵ<47>ָ<EFBFBD><D6B8><EFBFBD>ʵ<EFBFBD><CAB5>ת<EFBFBD><D7AA>Ч<EFBFBD><D0A7>
function createWheel(items) {
wheel.innerHTML = '';
if (items.length === 0) return;
const anglePerItem = 360 / items.length;
const radius = 190; // ת<>̰뾶<CCB0><EBBEB6><EFBFBD><EFBFBD><EFBFBD>DZ߿<C7B1><DFBF><EFBFBD>
const centerX = 200;
const centerY = 200;
// <20><><EFBFBD><EFBFBD>SVGת<47><D7AA>
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('width', '400');
svg.setAttribute('height', '400');
svg.setAttribute('viewBox', '0 0 400 400');
svg.style.position = 'absolute';
svg.style.top = '0';
svg.style.left = '0';
svg.style.width = '100%';
svg.style.height = '100%';
items.forEach((item, index) => {
const startAngle = (index * anglePerItem - 90) * Math.PI / 180;
const endAngle = ((index + 1) * anglePerItem - 90) * Math.PI / 180;
const x1 = centerX + radius * Math.cos(startAngle);
const y1 = centerY + radius * Math.sin(startAngle);
const x2 = centerX + radius * Math.cos(endAngle);
const y2 = centerY + radius * Math.sin(endAngle);
const largeArcFlag = anglePerItem > 180 ? 1 : 0;
const pathData = [
`M ${centerX} ${centerY}`,
`L ${x1} ${y1}`,
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2}`,
'Z'
].join(' ');
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d', pathData);
const colorIndex = index % colors.length;
path.setAttribute('fill', colors[colorIndex]);
path.setAttribute('stroke', '#fff');
path.setAttribute('stroke-width', '2');
svg.appendChild(path);
// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>
const midAngle = (startAngle + endAngle) / 2;
const textRadius = radius * 0.7;
const textX = centerX + textRadius * Math.cos(midAngle);
const textY = centerY + textRadius * Math.sin(midAngle);
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', textX);
text.setAttribute('y', textY);
text.setAttribute('text-anchor', 'middle');
text.setAttribute('fill', 'white');
text.setAttribute('font-size', items.length > 8 ? '12' : '14');
text.setAttribute('font-weight', 'bold');
text.setAttribute('transform', `rotate(${(midAngle * 180 / Math.PI + 90)}, ${textX}, ${textY})`);
const displayText = item.length > 12 ? item.substring(0, 12) + '...' : item;
text.textContent = displayText;
svg.appendChild(text);
});
wheel.appendChild(svg);
}
// ת<><D7AA>ת<EFBFBD><D7AA>
spinBtn.addEventListener('click', () => {
if (isSpinning || sortedItems.length === 0) return;
isSpinning = true;
spinBtn.disabled = true;
currentItem.textContent = <><D7AA><EFBFBD><EFBFBD>...';
// <20><><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD>Ȧ<EFBFBD><C8A6>תЧ<D7AA><D0A7><EFBFBD><EFBFBD>
const randomIndex = Math.floor(Math.random() * sortedItems.length);
const spins = 3; // ת3Ȧ
const anglePerItem = 360 / sortedItems.length;
// <20><><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD>Ƕȣ<C7B6><C8A3><EFBFBD>ת<EFBFBD><D7AA>Ȧ + ָ<><D6B8>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>
const targetAngle = spins * 360 + (360 - (randomIndex * anglePerItem) - anglePerItem / 2);
// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD>Ƕ<EFBFBD>
const svg = wheel.querySelector('svg');
const currentAngle = getCurrentRotation(svg);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD>Ƕȣ<C7B6><C8A3><EFBFBD><EFBFBD>ǵ<EFBFBD>ǰ<EFBFBD>Ƕȣ<C7B6>
const totalRotation = currentAngle + targetAngle;
svg.style.transform = `rotate(${totalRotation}deg)`;
// ת<><D7AA>ֹͣ<CDA3><D6B9><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>
setTimeout(() => {
currentItem.textContent = `${randomIndex + 1}. ${sortedItems[randomIndex]}`;
currentSpinIndex = randomIndex;
isSpinning = false;
spinBtn.disabled = false;
}, 3000);
});
// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0>ת<EFBFBD>Ƕ<EFBFBD>
function getCurrentRotation(element) {
const style = window.getComputedStyle(element);
const transform = style.transform;
if (transform === 'none') return 0;
const matrix = new DOMMatrix(transform);
const angle = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
return angle;
}
// <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
function displaySortedItems(items) {
sortedList.innerHTML = '';
items.forEach((item, index) => {
const itemDiv = document.createElement('div');
itemDiv.className = 'sorted-item';
const numberSpan = document.createElement('span');
numberSpan.className = 'sorted-item-number';
numberSpan.textContent = index + 1;
const textSpan = document.createElement('span');
textSpan.className = 'sorted-item-text';
textSpan.textContent = item;
itemDiv.appendChild(numberSpan);
itemDiv.appendChild(textSpan);
sortedList.appendChild(itemDiv);
});
}
// <20><><EFBFBD><EFBFBD>
resetBtn.addEventListener('click', () => {
extractedItems = [];
sortedItems = [];
currentSpinIndex = 0;
textInput.value = '';
textInput.disabled = false;
extractedSection.style.display = 'none';
wheelSection.style.display = 'none';
resultSection.style.display = 'none';
wheel.innerHTML = '';
const svg = wheel.querySelector('svg');
if (svg) {
svg.style.transform = 'rotate(0deg)';
}
currentItem.textContent = '';
isSpinning = false;
spinBtn.disabled = false;
});