console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字母频率分析工具</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#f97316',
neutral: '#64748b',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.transition-smooth {
transition: all 0.3s ease;
}
.shadow-soft {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col">
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa fa-bar-chart text-primary text-2xl"></i>
<h1 class="text-xl md:text-2xl font-bold text-gray-800">字母频率分析工具</h1>
</div>
<nav>
<ul class="flex space-x-6">
<li><a href="#" class="text-gray-600 hover:text-primary transition-smooth"><i class="fa fa-home mr-1"></i>首页</a></li>
<li><a href="#" class="text-gray-600 hover:text-primary transition-smooth"><i class="fa fa-info-circle mr-1"></i>关于</a></li>
</ul>
</nav>
</div>
</header>
<main class="flex-grow container mx-auto px-4 py-8">
<div class="bg-white rounded-xl shadow-soft p-6 mb-8 transform hover:scale-[1.01] transition-smooth">
<h2 class="text-xl font-bold text-gray-800 mb-3 flex items-center">
<i class="fa fa-info-circle text-primary mr-2"></i>工具介绍
</h2>
<p class="text-gray-600 leading-relaxed">
这个工具可以帮助你分析文本文件中各个字母的出现频率。只需上传一个文本文件,系统就会自动统计每个字母(区分大小写)的出现次数,并计算其在文本中的百分比。分析结果将以图表和表格的形式展示,便于你直观了解文本的字母分布特征。
</p>
</div>
<div class="bg-white rounded-xl shadow-soft p-6 mb-8">
<h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
<i class="fa fa-upload text-primary mr-2"></i>上传文件
</h2>
<div id="file-drop-area" class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer hover:border-primary transition-smooth">
<input type="file" id="file-input" class="hidden" accept=".txt,.pdf,.docx,.rtf">
<i class="fa fa-file-text-o text-4xl text-gray-400 mb-4"></i>
<p class="text-gray-500 mb-2">拖放文件到这里,或</p>
<button id="browse-btn" class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-smooth">
<i class="fa fa-folder-open mr-2"></i>浏览文件
</button>
<p class="text-xs text-gray-400 mt-4">支持的格式:.txt, .pdf, .docx, .rtf</p>
</div>
<div id="file-info" class="hidden mt-4 p-4 bg-gray-50 rounded-lg">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fa fa-file-text-o text-primary mr-3"></i>
<div>
<p id="file-name" class="font-medium text-gray-800 truncate max-w-md"></p>
<p id="file-size" class="text-sm text-gray-500"></p>
</div>
</div>
<button id="remove-file" class="text-gray-400 hover:text-red-500 transition-smooth">
<i class="fa fa-times-circle text-xl"></i>
</button>
</div>
</div>
<button id="analyze-btn" class="mt-6 bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-smooth disabled:opacity-50 disabled:cursor-not-allowed hidden">
<i class="fa fa-bar-chart mr-2"></i>开始分析
</button>
</div>
<div id="results-section" class="hidden">
<div class="bg-white rounded-xl shadow-soft p-6 mb-8">
<h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
<i class="fa fa-line-chart text-primary mr-2"></i>分析结果概览
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="bg-gray-50 p-4 rounded-lg">
<p class="text-sm text-gray-500 mb-1">总字符数</p>
<p id="total-chars" class="text-2xl font-bold text-gray-800">0</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<p class="text-sm text-gray-500 mb-1">字母总数</p>
<p id="total-letters" class="text-2xl font-bold text-gray-800">0</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<p class="text-sm text-gray-500 mb-1">处理时间</p>
<p id="processing-time" class="text-2xl font-bold text-gray-800">0 ms</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-soft p-6 mb-8">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-4">
<h2 class="text-xl font-bold text-gray-800 flex items-center">
<i class="fa fa-pie-chart text-primary mr-2"></i>字母频率分布
</h2>
<div class="mt-2 md:mt-0 flex space-x-2">
<button id="show-all-btn" class="bg-primary/10 hover:bg-primary/20 text-primary font-medium py-1 px-3 rounded-lg text-sm transition-smooth">
全部字母
</button>
<button id="show-top10-btn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-1 px-3 rounded-lg text-sm transition-smooth">
前10个
</button>
<select id="chart-type" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-1 px-3 rounded-lg text-sm transition-smooth">
<option value="bar">柱状图</option>
<option value="pie">饼图</option>
</select>
</div>
</div>
<div class="w-full h-[400px]">
<canvas id="frequency-chart"></canvas>
</div>
</div>
<div class="bg-white rounded-xl shadow-soft p-6 mb-8">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-gray-800 flex items-center">
<i class="fa fa-table text-primary mr-2"></i>详细数据
</h2>
<div class="flex items-center">
<div class="relative mr-2">
<input type="text" id="search-input" placeholder="搜索字母..." class="pl-8 pr-4 py-1 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary">
<i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
</div>
<div class="relative">
<select id="sort-select" class="pl-3 pr-8 py-1 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary appearance-none bg-white">
<option value="letter-asc">按字母排序 (A-Z)</option>
<option value="letter-desc">按字母排序 (Z-A)</option>
<option value="frequency-asc">按频率排序 (低-高)</option>
<option value="frequency-desc">按频率排序 (高-低)</option>
</select>
<i class="fa fa-chevron-down absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 pointer-events-none"></i>
</div>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
字母
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
出现次数
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
频率 (%)
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
可视化
</th>
</tr>
</thead>
<tbody id="frequency-table-body" class="bg-white divide-y divide-gray-200">
</tbody>
</table>
</div>
<div id="no-results" class="hidden py-8 text-center text-gray-500">
<i class="fa fa-search-minus text-3xl mb-2"></i>
<p>没有找到匹配的结果</p>
</div>
<div id="loading-table" class="hidden py-8 text-center text-gray-500">
<i class="fa fa-circle-o-notch fa-spin text-3xl mb-2"></i>
<p>加载数据中...</p>
</div>
</div>
<div class="bg-white rounded-xl shadow-soft p-6 mb-8">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-gray-800 flex items-center">
<i class="fa fa-file-text-o text-primary mr-2"></i>原始文本预览
</h2>
<div class="flex space-x-2">
<button id="expand-text-btn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-1 px-3 rounded-lg text-sm transition-smooth">
<i class="fa fa-expand mr-1"></i>展开全部
</button>
<button id="copy-text-btn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-1 px-3 rounded-lg text-sm transition-smooth">
<i class="fa fa-copy mr-1"></i>复制文本
</button>
</div>
</div>
<div id="text-preview-container" class="relative">
<div id="text-preview" class="bg-gray-50 p-4 rounded-lg max-h-60 overflow-y-auto font-mono text-sm">
</div>
<div id="text-gradient" class="absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-gray-50 to-transparent pointer-events-none"></div>
</div>
</div>
</div>
</main>
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div>
<h3 class="text-lg font-bold mb-4">字母频率分析工具</h3>
<p class="text-gray-400 text-sm">
这是一个简单实用的文本分析工具,可以帮助你了解文本中各字母的分布情况,适用于语言学习、文本分析等场景。
</p>
</div>
<div>
<h3 class="text-lg font-bold mb-4">快速链接</h3>
<ul class="space-y-2 text-sm">
<li><a href="#" class="text-gray-400 hover:text-white transition-smooth">首页</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition-smooth">使用指南</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition-smooth">关于我们</a></li>
</ul>
</div>
<div>
<h3 class="text-lg font-bold mb-4">联系我们</h3>
<ul class="space-y-2 text-sm">
<li class="flex items-center">
<i class="fa fa-envelope-o text-gray-400 mr-2"></i>
<a href="mailto:contact@example.com" class="text-gray-400 hover:text-white transition-smooth">contact@example.com</a>
</li>
<li class="flex items-center">
<i class="fa fa-github text-gray-400 mr-2"></i>
<a href="#" class="text-gray-400 hover:text-white transition-smooth">GitHub</a>
</li>
</ul>
</div>
</div>
<div class="border-t border-gray-700 mt-8 pt-6 text-center text-gray-400 text-sm">
<p>© 2025 字母频率分析工具. 保留所有权利.</p>
</div>
</div>
</footer>
<div id="loading-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg p-6 max-w-sm w-full">
<div class="text-center">
<div class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-primary border-t-transparent mb-4"></div>
<h3 class="text-lg font-bold text-gray-800 mb-2">正在分析文本</h3>
<p class="text-gray-600" id="loading-message">请稍候,正在处理你的文件...</p>
</div>
</div>
</div>
<div id="success-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg p-6 max-w-sm w-full">
<div class="text-center">
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-green-100 text-green-500 mb-4">
<i class="fa fa-check text-2xl"></i>
</div>
<h3 class="text-lg font-bold text-gray-800 mb-2">操作成功</h3>
<p class="text-gray-600" id="success-message">文本已成功复制到剪贴板</p>
<button id="close-success-modal" class="mt-4 bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-smooth">
确定
</button>
</div>
</div>
</div>
<script>
let fileContent = '';
let frequencyData = [];
let chart = null;
let isTextExpanded = false;
const fileDropArea = document.getElementById('file-drop-area');
const fileInput = document.getElementById('file-input');
const browseBtn = document.getElementById('browse-btn');
const fileInfo = document.getElementById('file-info');
const fileName = document.getElementById('file-name');
const fileSize = document.getElementById('file-size');
const removeFile = document.getElementById('remove-file');
const analyzeBtn = document.getElementById('analyze-btn');
const resultsSection = document.getElementById('results-section');
const totalChars = document.getElementById('total-chars');
const totalLetters = document.getElementById('total-letters');
const processingTime = document.getElementById('processing-time');
const frequencyChart = document.getElementById('frequency-chart');
const frequencyTableBody = document.getElementById('frequency-table-body');
const textPreview = document.getElementById('text-preview');
const expandTextBtn = document.getElementById('expand-text-btn');
const copyTextBtn = document.getElementById('copy-text-btn');
const textGradient = document.getElementById('text-gradient');
const loadingModal = document.getElementById('loading-modal');
const loadingMessage = document.getElementById('loading-message');
const successModal = document.getElementById('success-modal');
const successMessage = document.getElementById('success-message');
const closeSuccessModal = document.getElementById('close-success-modal');
const searchInput = document.getElementById('search-input');
const sortSelect = document.getElementById('sort-select');
const showAllBtn = document.getElementById('show-all-btn');
const showTop10Btn = document.getElementById('show-top10-btn');
const chartType = document.getElementById('chart-type');
const noResults = document.getElementById('no-results');
const loadingTable = document.getElementById('loading-table');
function initEventListeners() {
browseBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
fileDropArea.addEventListener('dragover', handleDragOver);
fileDropArea.addEventListener('dragleave', handleDragLeave);
fileDropArea.addEventListener('drop', handleDrop);
removeFile.addEventListener('click', removeSelectedFile);
analyzeBtn.addEventListener('click', analyzeText);
expandTextBtn.addEventListener('click', toggleTextExpansion);
copyTextBtn.addEventListener('click', copyTextToClipboard);
closeSuccessModal.addEventListener('click', () => successModal.classList.add('hidden'));
searchInput.addEventListener('input', filterTable);
sortSelect.addEventListener('change', sortTable);
showAllBtn.addEventListener('click', showAllLetters);
showTop10Btn.addEventListener('click', showTop10Letters);
chartType.addEventListener('change', updateChart);
}
function handleFileSelect(e) {
const file = e.target.files[0];
if (file) {
handleFile(file);
}
}
function handleDragOver(e) {
e.preventDefault();
fileDropArea.classList.add('border-primary', 'bg-primary/5');
}
function handleDragLeave() {
fileDropArea.classList.remove('border-primary', 'bg-primary/5');
}
function handleDrop(e) {
e.preventDefault();
fileDropArea.classList.remove('border-primary', 'bg-primary/5');
const file = e.dataTransfer.files[0];
if (file) {
handleFile(file);
}
}
function handleFile(file) {
const allowedTypes = ['text/plain', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/rtf'];
if (!allowedTypes.includes(file.type) && !file.name.endsWith('.txt') && !file.name.endsWith('.pdf') && !file.name.endsWith('.docx') && !file.name.endsWith('.rtf')) {
alert('请上传有效的文本文件 (.txt, .pdf, .docx, .rtf)');
return;
}
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
fileInfo.classList.remove('hidden');
analyzeBtn.classList.remove('hidden');
const reader = new FileReader();
reader.onload = function(e) {
if (file.type === 'text/plain' || file.name.endsWith('.txt')) {
fileContent = e.target.result;
} else {
fileContent = `[${file.type === 'application/pdf' ? 'PDF文件' : file.type === 'application/msword' || file.name.endsWith('.docx') ? 'Word文档' : 'RTF文件'}] 无法直接预览内容`;
}
};
reader.readAsText(file);
}
function removeSelectedFile() {
fileInput.value = '';
fileInfo.classList.add('hidden');
analyzeBtn.classList.add('hidden');
resultsSection.classList.add('hidden');
fileContent = '';
fileDropArea.classList.remove('border-primary', 'bg-primary/5');
}
function analyzeText() {
if (!fileContent) return;
loadingMessage.textContent = '正在分析文本...';
loadingModal.classList.remove('hidden');
setTimeout(() => {
const startTime = performance.now();
frequencyData = analyzeFrequency(fileContent);
const endTime = performance.now();
updateResults(frequencyData, endTime - startTime);
loadingModal.classList.add('hidden');
resultsSection.classList.remove('hidden');
resultsSection.scrollIntoView({ behavior: 'smooth' });
}, 800);
}
function analyzeFrequency(text) {
const frequency = {};
let total = 0;
for (let char of text) {
if (/[a-zA-Z]/.test(char)) {
frequency[char] = (frequency[char] || 0) + 1;
total++;
}
}
const frequencyArray = Object.keys(frequency).map(char => ({
letter: char,
count: frequency[char],
frequency: (frequency[char] / total * 100).toFixed(2)
}));
frequencyArray.sort((a, b) => b.count - a.count);
return frequencyArray;
}
function updateResults(data, time) {
totalChars.textContent = fileContent.length;
totalLetters.textContent = data.reduce((sum, item) => sum + item.count, 0);
processingTime.textContent = `${time.toFixed(0)} ms`;
textPreview.textContent = fileContent.length > 1000 ? fileContent.substring(0, 1000) + '...' : fileContent;
isTextExpanded = false;
updateTextPreviewUI();
updateChart();
updateTable(data);
}
function updateTextPreviewUI() {
if (isTextExpanded || fileContent.length <= 1000) {
textGradient.classList.add('hidden');
expandTextBtn.innerHTML = '<i class="fa fa-compress mr-1"></i>收起';
} else {
textGradient.classList.remove('hidden');
expandTextBtn.innerHTML = '<i class="fa fa-expand mr-1"></i>展开全部';
}
}
function toggleTextExpansion() {
isTextExpanded = !isTextExpanded;
if (isTextExpanded) {
textPreview.textContent = fileContent;
} else {
textPreview.textContent = fileContent.length > 1000 ? fileContent.substring(0, 1000) + '...' : fileContent;
}
updateTextPreviewUI();
}
function copyTextToClipboard() {
navigator.clipboard.writeText(fileContent)
.then(() => {
successMessage.textContent = '文本已成功复制到剪贴板';
successModal.classList.remove('hidden');
})
.catch(err => {
console.error('复制失败: ', err);
successMessage.textContent = '复制失败,请手动复制';
successModal.classList.remove('hidden');
});
}
function updateChart() {
if (chart) {
chart.destroy();
}
let displayData = [...frequencyData];
if (showTop10Btn.classList.contains('bg-primary/10')) {
displayData = displayData.slice(0, 10);
}
const labels = displayData.map(item => item.letter);
const counts = displayData.map(item => item.count);
const frequencies = displayData.map(item => parseFloat(item.frequency));
const ctx = frequencyChart.getContext('2d');
const isBarChart = chartType.value === 'bar';
chart = new Chart(ctx, {
type: isBarChart ? 'bar' : 'pie',
data: isBarChart ? {
labels: labels,
datasets: [{
label: '出现次数',
data: counts,
backgroundColor: 'rgba(59, 130, 246, 0.7)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 1
}, {
label: '频率 (%)',
data: frequencies,
backgroundColor: 'rgba(249, 115, 22, 0.7)',
borderColor: 'rgba(249, 115, 22, 1)',
borderWidth: 1,
yAxisID: 'y1'
}]
} : {
labels: labels,
datasets: [{
data: frequencies,
backgroundColor: [
'rgba(59, 130, 246, 0.7)',
'rgba(249, 115, 22, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(139, 92, 246, 0.7)',
'rgba(236, 72, 153, 0.7)',
'rgba(245, 158, 11, 0.7)',
'rgba(220, 38, 38, 0.7)',
'rgba(37, 99, 235, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(239, 68, 68, 0.7)',
'rgba(124, 58, 237, 0.7)',
'rgba(21, 128, 61, 0.7)',
'rgba(249, 115, 22, 0.7)',
'rgba(37, 99, 235, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(239, 68, 68, 0.7)',
'rgba(124, 58, 237, 0.7)',
'rgba(21, 128, 61, 0.7)',
'rgba(249, 115, 22, 0.7)',
'rgba(37, 99, 235, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(239, 68, 68, 0.7)',
'rgba(124, 58, 237, 0.7)',
'rgba(21, 128, 61, 0.7)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: isBarChart ? 'top' : 'right',
},
tooltip: {
callbacks: {
label: function(context) {
if (isBarChart) {
const label = context.dataset.label || '';
const value = context.datasetIndex === 0 ?
context.parsed.y :
context.parsed.y.toFixed(2) + '%';
return `${label}: ${value}`;
} else {
const label = context.label || '';
const value = context.raw.toFixed(2);
return `${label}: ${value}%`;
}
}
}
}
},
scales: isBarChart ? {
y: {
beginAtZero: true,
title: {
display: true,
text: '出现次数'
}
},
y1: {
beginAtZero: true,
position: 'right',
title: {
display: true,
text: '频率 (%)'
},
grid: {
drawOnChartArea: false,
}
}
} : {}
}
});
}
function updateTable(data) {
frequencyTableBody.innerHTML = '';
noResults.classList.add('hidden');
loadingTable.classList.remove('hidden');
setTimeout(() => {
loadingTable.classList.add('hidden');
if (data.length === 0) {
noResults.classList.remove('hidden');
return;
}
data.forEach((item, index) => {
const row = document.createElement('tr');
row.className = index % 2 === 0 ? 'bg-white' : 'bg-gray-50';
const maxFrequency = Math.max(...data.map(d => parseFloat(d.frequency)));
const barWidth = (parseFloat(item.frequency) / maxFrequency * 100) + '%';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="w-8 h-8 flex items-center justify-center bg-primary/10 text-primary rounded-full mr-3">
<span class="font-medium">${item.letter}</span>
</div>
<span class="font-medium text-gray-900">${item.letter}</span>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="text-gray-900">${item.count}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="text-gray-900">${item.frequency}</span>
</td>
<td class="px-6 py-4">
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-primary h-2.5 rounded-full" style="width: ${barWidth}"></div>
</div>
</td>
`;
frequencyTableBody.appendChild(row);
});
}, 300);
}
function filterTable() {
const searchTerm = searchInput.value.toLowerCase();
const filteredData = frequencyData.filter(item =>
item.letter.toLowerCase().includes(searchTerm)
);
updateTable(filteredData);
}
function sortTable() {
const sortBy = sortSelect.value;
let sortedData = [...frequencyData];
switch (sortBy) {
case 'letter-asc':
sortedData.sort((a, b) => a.letter.localeCompare(b.letter));
break;
case 'letter-desc':
sortedData.sort((a, b) => b.letter.localeCompare(a.letter));
break;
case 'frequency-asc':
sortedData.sort((a, b) => parseFloat(a.frequency) - parseFloat(b.frequency));
break;
case 'frequency-desc':
sortedData.sort((a, b) => parseFloat(b.frequency) - parseFloat(a.frequency));
break;
}
updateTable(sortedData);
}
function showAllLetters() {
showAllBtn.classList.remove('bg-gray-100', 'hover:bg-gray-200', 'text-gray-700');
showAllBtn.classList.add('bg-primary/10', 'hover:bg-primary/20', 'text-primary');
showTop10Btn.classList.remove('bg-primary/10', 'hover:bg-primary/20', 'text-primary');
showTop10Btn.classList.add('bg-gray-100', 'hover:bg-gray-200', 'text-gray-700');
updateTable(frequencyData);
updateChart();
}
function showTop10Letters() {
showTop10Btn.classList.remove('bg-gray-100', 'hover:bg-gray-200', 'text-gray-700');
showTop10Btn.classList.add('bg-primary/10', 'hover:bg-primary/20', 'text-primary');
showAllBtn.classList.remove('bg-primary/10', 'hover:bg-primary/20', 'text-primary');
showAllBtn.classList.add('bg-gray-100', 'hover:bg-gray-200', 'text-gray-700');
const top10Data = frequencyData.slice(0, 10);
updateTable(top10Data);
updateChart();
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function initApp() {
initEventListeners();
console.log('应用已初始化');
}
document.addEventListener('DOMContentLoaded', initApp);
</script>
</body>
</html>