|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Кодирование ASCII - Визуализация</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.js"></script> |
|
|
<style> |
|
|
@keyframes pulse { |
|
|
0%, 100% { opacity: 1; } |
|
|
50% { opacity: 0.5; } |
|
|
} |
|
|
.ascii-cell { |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.ascii-cell.active { |
|
|
background-color: #3b82f6; |
|
|
color: white; |
|
|
transform: scale(1.1); |
|
|
box-shadow: 0 0 10px rgba(59, 130, 246, 0.7); |
|
|
} |
|
|
.code-line { |
|
|
position: relative; |
|
|
} |
|
|
.code-line::after { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
left: 0; |
|
|
bottom: 0; |
|
|
width: 0; |
|
|
height: 2px; |
|
|
background-color: #3b82f6; |
|
|
transition: width 0.5s ease; |
|
|
} |
|
|
.code-line.animating::after { |
|
|
width: 100%; |
|
|
} |
|
|
.binary-digit { |
|
|
display: inline-block; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.binary-digit.active { |
|
|
color: #3b82f6; |
|
|
transform: translateY(-5px); |
|
|
font-weight: bold; |
|
|
} |
|
|
.progress-bar { |
|
|
height: 4px; |
|
|
background-color: #e5e7eb; |
|
|
overflow: hidden; |
|
|
} |
|
|
.progress-fill { |
|
|
height: 100%; |
|
|
background-color: #3b82f6; |
|
|
width: 0; |
|
|
transition: width 0.5s ease; |
|
|
} |
|
|
#captureContainer { |
|
|
position: fixed; |
|
|
top: -9999px; |
|
|
left: -9999px; |
|
|
width: 1000px; |
|
|
z-index: -1; |
|
|
} |
|
|
.download-btn { |
|
|
position: fixed; |
|
|
bottom: 20px; |
|
|
right: 20px; |
|
|
z-index: 100; |
|
|
opacity: 0; |
|
|
transition: opacity 0.3s; |
|
|
} |
|
|
.download-btn.show { |
|
|
opacity: 1; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 min-h-screen font-mono"> |
|
|
|
|
|
<div id="captureContainer"></div> |
|
|
|
|
|
|
|
|
<button id="downloadGifBtn" class="download-btn bg-blue-500 hover:bg-blue-600 text-white px-4 py-3 rounded-full shadow-lg transition"> |
|
|
<i class="fas fa-download mr-2"></i>Скачать GIF |
|
|
</button> |
|
|
|
|
|
<div class="container mx-auto px-4 py-8"> |
|
|
<div class="text-center mb-8"> |
|
|
<h1 class="text-3xl font-bold text-gray-800 mb-2">Визуализация процесса кодирования</h1> |
|
|
<p class="text-gray-600">Интерактивная демонстрация преобразования текста в ASCII и двоичный код</p> |
|
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8"> |
|
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-6"> |
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-800">Введите текст для кодирования</h2> |
|
|
<div class="flex items-center mb-4"> |
|
|
<input type="text" id="inputText" placeholder="Например: Hello" |
|
|
class="flex-1 border border-gray-300 rounded-l-md px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"> |
|
|
<button id="encodeBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-r-md transition"> |
|
|
<i class="fas fa-code mr-2"></i>Кодировать |
|
|
</button> |
|
|
</div> |
|
|
<div class="progress-bar mb-4"> |
|
|
<div id="progressFill" class="progress-fill"></div> |
|
|
</div> |
|
|
<div id="codeOutput" class="bg-gray-100 p-4 rounded-md min-h-32"> |
|
|
<p class="text-gray-500 italic">Здесь появится процесс кодирования...</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-6"> |
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-800">Таблица ASCII</h2> |
|
|
<div class="overflow-x-auto"> |
|
|
<table class="w-full border-collapse"> |
|
|
<thead> |
|
|
<tr class="bg-gray-100"> |
|
|
<th class="border p-2">Dec</th> |
|
|
<th class="border p-2">Hex</th> |
|
|
<th class="border p-2">Char</th> |
|
|
<th class="border p-2">Binary</th> |
|
|
</tr> |
|
|
</thead> |
|
|
<tbody id="asciiTableBody"> |
|
|
|
|
|
</tbody> |
|
|
</table> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-8"> |
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-800">Двоичное представление</h2> |
|
|
<div id="binaryVisualization" class="text-center text-2xl font-mono p-4 bg-gray-100 rounded-md"> |
|
|
<p class="text-gray-500">Введите текст для отображения двоичного кода</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-6"> |
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-800">Процесс кодирования</h2> |
|
|
<div id="encodingSteps" class="space-y-4"> |
|
|
<div class="step p-4 border-l-4 border-blue-500 bg-blue-50"> |
|
|
<h3 class="font-medium text-gray-800">1. Ввод текста</h3> |
|
|
<p class="text-gray-600">Пользователь вводит текст для кодирования</p> |
|
|
</div> |
|
|
<div class="step p-4 border-l-4 border-gray-300"> |
|
|
<h3 class="font-medium text-gray-800">2. Преобразование в ASCII</h3> |
|
|
<p class="text-gray-600">Каждый символ преобразуется в соответствующий код ASCII</p> |
|
|
</div> |
|
|
<div class="step p-4 border-l-4 border-gray-300"> |
|
|
<h3 class="font-medium text-gray-800">3. Преобразование в двоичный код</h3> |
|
|
<p class="text-gray-600">Код ASCII преобразуется в 8-битное двоичное число</p> |
|
|
</div> |
|
|
<div class="step p-4 border-l-4 border-gray-300"> |
|
|
<h3 class="font-medium text-gray-800">4. Отображение результата</h3> |
|
|
<p class="text-gray-600">Отображается полный двоичный код введённого текста</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const asciiTableBody = document.getElementById('asciiTableBody'); |
|
|
for (let i = 32; i < 128; i++) { |
|
|
const row = document.createElement('tr'); |
|
|
row.className = 'ascii-row hover:bg-gray-50'; |
|
|
row.innerHTML = ` |
|
|
<td class="border p-2 ascii-dec">${i}</td> |
|
|
<td class="border p-2 ascii-hex">${i.toString(16).toUpperCase()}</td> |
|
|
<td class="border p-2 ascii-char text-center">${String.fromCharCode(i)}</td> |
|
|
<td class="border p-2 ascii-bin">${i.toString(2).padStart(8, '0')}</td> |
|
|
`; |
|
|
asciiTableBody.appendChild(row); |
|
|
} |
|
|
|
|
|
|
|
|
let gif = null; |
|
|
let frames = []; |
|
|
let frameCount = 0; |
|
|
const downloadBtn = document.getElementById('downloadGifBtn'); |
|
|
|
|
|
|
|
|
downloadBtn.addEventListener('click', function() { |
|
|
if (frames.length > 0) { |
|
|
createGifFromFrames(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('encodeBtn').addEventListener('click', function() { |
|
|
const inputText = document.getElementById('inputText').value.trim(); |
|
|
if (!inputText) return; |
|
|
|
|
|
|
|
|
resetVisualization(); |
|
|
|
|
|
|
|
|
frames = []; |
|
|
frameCount = 0; |
|
|
|
|
|
|
|
|
animateEncoding(inputText); |
|
|
}); |
|
|
|
|
|
function resetVisualization() { |
|
|
document.querySelectorAll('.ascii-cell').forEach(cell => { |
|
|
cell.classList.remove('active'); |
|
|
}); |
|
|
document.querySelectorAll('.step').forEach((step, index) => { |
|
|
step.className = 'step p-4 border-l-4 ' + |
|
|
(index === 0 ? 'border-blue-500 bg-blue-50' : 'border-gray-300'); |
|
|
}); |
|
|
document.getElementById('binaryVisualization').innerHTML = '<p class="text-gray-500">Введите текст для отображения двоичного кода</p>'; |
|
|
document.getElementById('progressFill').style.width = '0'; |
|
|
document.getElementById('codeOutput').innerHTML = '<p class="text-gray-500 italic">Здесь появится процесс кодирования...</p>'; |
|
|
downloadBtn.classList.remove('show'); |
|
|
} |
|
|
|
|
|
function captureFrame() { |
|
|
const captureContainer = document.getElementById('captureContainer'); |
|
|
const visualElements = document.querySelector('.container').cloneNode(true); |
|
|
|
|
|
|
|
|
visualElements.querySelectorAll('.ascii-cell.active').forEach(cell => { |
|
|
cell.classList.remove('active'); |
|
|
}); |
|
|
|
|
|
captureContainer.innerHTML = ''; |
|
|
captureContainer.appendChild(visualElements); |
|
|
|
|
|
html2canvas(captureContainer).then(canvas => { |
|
|
frames.push(canvas); |
|
|
frameCount++; |
|
|
|
|
|
|
|
|
if (frameCount === 1) { |
|
|
setTimeout(() => { |
|
|
downloadBtn.classList.add('show'); |
|
|
}, 500); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
function createGifFromFrames() { |
|
|
downloadBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Создание GIF...'; |
|
|
|
|
|
|
|
|
gif = new GIF({ |
|
|
workers: 2, |
|
|
quality: 10, |
|
|
width: 1000, |
|
|
height: Math.min(1000, frames[0].height * (1000 / frames[0].width)), |
|
|
workerScript: 'https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.worker.js' |
|
|
}); |
|
|
|
|
|
|
|
|
const frameDelay = 500; |
|
|
frames.forEach((frame, index) => { |
|
|
|
|
|
if (index % 2 === 0 || index === frames.length - 1) { |
|
|
gif.addFrame(frame, {delay: frameDelay, copy: true}); |
|
|
} |
|
|
}); |
|
|
|
|
|
gif.on('finished', function(blob) { |
|
|
|
|
|
const url = URL.createObjectURL(blob); |
|
|
const a = document.createElement('a'); |
|
|
a.href = url; |
|
|
a.download = 'ascii_encoding_animation.gif'; |
|
|
a.click(); |
|
|
URL.revokeObjectURL(url); |
|
|
|
|
|
downloadBtn.innerHTML = '<i class="fas fa-download mr-2"></i>Скачать GIF'; |
|
|
}); |
|
|
|
|
|
gif.render(); |
|
|
} |
|
|
|
|
|
function animateEncoding(text) { |
|
|
const steps = document.querySelectorAll('.step'); |
|
|
const progressFill = document.getElementById('progressFill'); |
|
|
const binaryVisualization = document.getElementById('binaryVisualization'); |
|
|
const codeOutput = document.getElementById('codeOutput'); |
|
|
|
|
|
|
|
|
setTimeout(captureFrame, 300); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
steps[1].className = 'step p-4 border-l-4 border-blue-500 bg-blue-50'; |
|
|
progressFill.style.width = '25%'; |
|
|
captureFrame(); |
|
|
|
|
|
let asciiOutput = ''; |
|
|
text.split('').forEach((char, index) => { |
|
|
setTimeout(() => { |
|
|
const code = char.charCodeAt(0); |
|
|
asciiOutput += `<div class="code-line mb-2">'${char}' → ${code} (ASCII)</div>`; |
|
|
codeOutput.innerHTML = asciiOutput; |
|
|
|
|
|
|
|
|
const asciiRows = document.querySelectorAll('.ascii-row'); |
|
|
asciiRows.forEach(row => { |
|
|
const decCell = row.querySelector('.ascii-dec'); |
|
|
if (decCell && parseInt(decCell.textContent) === code) { |
|
|
row.querySelectorAll('td').forEach(cell => { |
|
|
cell.classList.add('active', 'ascii-cell'); |
|
|
}); |
|
|
setTimeout(() => { |
|
|
row.querySelectorAll('td').forEach(cell => { |
|
|
cell.classList.remove('active'); |
|
|
}); |
|
|
}, 1000); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const lines = document.querySelectorAll('.code-line'); |
|
|
lines[lines.length - 1].classList.add('animating'); |
|
|
setTimeout(() => { |
|
|
lines[lines.length - 1].classList.remove('animating'); |
|
|
}, 500); |
|
|
|
|
|
|
|
|
setTimeout(captureFrame, 100); |
|
|
|
|
|
if (index === text.length - 1) { |
|
|
setTimeout(() => { |
|
|
|
|
|
steps[2].className = 'step p-4 border-l-4 border-blue-500 bg-blue-50'; |
|
|
progressFill.style.width = '50%'; |
|
|
captureFrame(); |
|
|
|
|
|
let binaryOutput = ''; |
|
|
text.split('').forEach((char, charIndex) => { |
|
|
setTimeout(() => { |
|
|
const code = char.charCodeAt(0); |
|
|
const binary = code.toString(2).padStart(8, '0'); |
|
|
binaryOutput += `<div class="code-line mb-2">${code} → ${binary} (binary)</div>`; |
|
|
codeOutput.innerHTML = asciiOutput + binaryOutput; |
|
|
|
|
|
|
|
|
const binaryDigits = binary.split(''); |
|
|
let binaryHTML = ''; |
|
|
binaryDigits.forEach((digit, digitIndex) => { |
|
|
binaryHTML += `<span class="binary-digit">${digit}</span>`; |
|
|
}); |
|
|
|
|
|
|
|
|
if (charIndex === 0) { |
|
|
binaryVisualization.innerHTML = ''; |
|
|
} |
|
|
const charDiv = document.createElement('div'); |
|
|
charDiv.className = 'mb-2'; |
|
|
charDiv.innerHTML = `<span class="mr-2">'${char}':</span>${binaryHTML}`; |
|
|
binaryVisualization.appendChild(charDiv); |
|
|
|
|
|
|
|
|
const digits = charDiv.querySelectorAll('.binary-digit'); |
|
|
digits.forEach((digit, i) => { |
|
|
setTimeout(() => { |
|
|
digit.classList.add('active'); |
|
|
setTimeout(() => { |
|
|
digit.classList.remove('active'); |
|
|
|
|
|
if (i === digits.length - 1) { |
|
|
setTimeout(captureFrame, 100); |
|
|
} |
|
|
}, 300); |
|
|
}, i * 100); |
|
|
}); |
|
|
|
|
|
|
|
|
const lines = document.querySelectorAll('.code-line'); |
|
|
lines[lines.length - 1].classList.add('animating'); |
|
|
setTimeout(() => { |
|
|
lines[lines.length - 1].classList.remove('animating'); |
|
|
}, 500); |
|
|
|
|
|
if (charIndex === text.length - 1) { |
|
|
setTimeout(() => { |
|
|
|
|
|
steps[3].className = 'step p-4 border-l-4 border-blue-500 bg-blue-50'; |
|
|
progressFill.style.width = '100%'; |
|
|
|
|
|
|
|
|
let fullBinary = ''; |
|
|
text.split('').forEach(char => { |
|
|
fullBinary += char.charCodeAt(0).toString(2).padStart(8, '0') + ' '; |
|
|
}); |
|
|
binaryVisualization.innerHTML = ` |
|
|
<div class="text-left mb-4"> |
|
|
<p class="font-medium">Исходный текст: <span class="text-blue-500">"${text}"</span></p> |
|
|
<p class="font-medium">Двоичное представление:</p> |
|
|
</div> |
|
|
<div class="bg-gray-800 text-green-400 p-4 rounded-md text-left overflow-x-auto"> |
|
|
${fullBinary.trim()} |
|
|
</div> |
|
|
`; |
|
|
|
|
|
|
|
|
setTimeout(captureFrame, 500); |
|
|
}, 1000); |
|
|
} |
|
|
}, charIndex * 1200); |
|
|
}); |
|
|
}, 1000); |
|
|
} |
|
|
}, index * 800); |
|
|
}); |
|
|
}, 1000); |
|
|
} |
|
|
}); |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> |
|
|
</html> |