document.addEventListener('DOMContentLoaded', function() { // Initialize UI elements const dropArea = document.getElementById('drop-area'); const fileInput = document.getElementById('file-input'); const convertBtn = document.getElementById('convert-btn'); const convertText = document.getElementById('convert-text'); const convertSpinner = document.getElementById('convert-spinner'); const resultsSection = document.getElementById('results'); const originalContainer = document.getElementById('original-container'); const resultContainer = document.getElementById('result-container'); const svgCode = document.getElementById('svg-code'); const downloadBtn = document.getElementById('download-btn'); const copyBtn = document.getElementById('copy-btn'); const fileInfo = document.getElementById('file-info'); const zoomControls = document.getElementById('zoom-controls'); const zoomInBtn = document.getElementById('zoom-in'); const zoomOutBtn = document.getElementById('zoom-out'); const zoomResetBtn = document.getElementById('zoom-reset'); const colorModeToggle = document.getElementById('color-mode'); const colorModeLabel = document.getElementById('color-mode-label'); const colorSettings = document.getElementById('color-settings'); const colorCount = document.getElementById('color-count'); const colorCountValue = document.getElementById('color-count-value'); const detailLevel = document.getElementById('detail-level'); const smoothness = document.getElementById('smoothness'); const smoothnessValue = document.getElementById('smoothness-value'); const outputFormat = document.getElementById('output-format'); let uploadedFile = null; let scale = 1; let canvas = null; let svgPreview = null; let isDragging = false; let startPos = { x: 0, y: 0 }; let translate = { x: 0, y: 0 }; // Initialize event listeners initEventListeners(); function initEventListeners() { // Drag and drop handlers ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropArea.addEventListener(eventName, preventDefaults, false); document.body.addEventListener(eventName, preventDefaults, false); }); ['dragenter', 'dragover'].forEach(eventName => { dropArea.addEventListener(eventName, highlight, false); }); ['dragleave', 'drop'].forEach(eventName => { dropArea.addEventListener(eventName, unhighlight, false); }); dropArea.addEventListener('drop', handleDrop, false); fileInput.addEventListener('change', handleFiles, false); convertBtn.addEventListener('click', convertToSVG); downloadBtn.addEventListener('click', downloadSVG); copyBtn.addEventListener('click', copySVGCode); // Color mode toggle colorModeToggle.addEventListener('change', toggleColorMode); colorCount.addEventListener('input', updateColorCount); smoothness.addEventListener('input', updateSmoothness); // Zoom controls zoomInBtn.addEventListener('click', () => zoomImage(1.2)); zoomOutBtn.addEventListener('click', () => zoomImage(0.8)); zoomResetBtn.addEventListener('click', resetZoom); // SVG preview interactions resultContainer.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', dragImage); document.addEventListener('mouseup', endDrag); resultContainer.addEventListener('touchstart', startDrag); document.addEventListener('touchmove', dragImage); document.addEventListener('touchend', endDrag); } function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } function highlight() { dropArea.classList.add('highlight'); } function unhighlight() { dropArea.classList.remove('highlight'); } function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; handleFiles({ target: { files } }); } function handleFiles(e) { const files = e.target.files; if (files.length) { const file = files[0]; if (!file.type.match('image.*')) { alert('Please upload an image file (JPG, PNG etc.)'); return; } uploadedFile = file; displayOriginalImage(uploadedFile); } } function displayOriginalImage(file) { const reader = new FileReader(); reader.onload = function(e) { const img = document.createElement('img'); img.onload = function() { URL.revokeObjectURL(this.src); updateFileInfo(file, this.width, this.height); }; img.src = e.target.result; img.className = 'max-w-full max-h-full'; originalContainer.innerHTML = ''; originalContainer.appendChild(img); }; reader.readAsDataURL(file); } function updateFileInfo(file, width, height) { const sizeMB = (file.size / (1024 * 1024)).toFixed(2); fileInfo.innerHTML = ` ${file.name} | ${width}×${height}px | ${sizeMB}MB `; } function convertToSVG() { if (!uploadedFile) { showAlert('Please upload an image first'); return; } // Show loading state convertBtn.disabled = true; convertText.textContent = 'Processing...'; convertSpinner.classList.remove('hidden'); // Process image (simplified example - in production you would use a proper vectorization algorithm) setTimeout(() => { const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); // Get conversion settings const isColor = colorModeToggle.checked; const colorCountVal = parseInt(colorCount.value); const smoothnessVal = parseInt(smoothness.value); const detailLevelVal = detailLevel.value; // Process image based on settings (simplified) const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; if (!isColor) { // Monochrome conversion const threshold = 128; // Default threshold for (let i = 0; i < data.length; i += 4) { const avg = (data[i] + data[i + 1] + data[i + 2]) / 3; const val = avg > threshold ? 255 : 0; data[i] = data[i + 1] = data[i + 2] = val; } } else { // Color quantization (simplified) // In a real app, you would use a proper quantization algorithm const step = Math.floor(256 / colorCountVal); for (let i = 0; i < data.length; i += 4) { data[i] = Math.floor(data[i] / step) * step; // R data[i+1] = Math.floor(data[i+1] / step) * step; // G data[i+2] = Math.floor(data[i+2] / step) * step; // B } } ctx.putImageData(imageData, 0, 0); // Generate SVG (simplified - real implementation would use vector paths) const canvasDataURL = canvas.toDataURL('image/png'); const svg = ` `; // Display result displaySVGResult(svg, img.width, img.height); // Reset button state convertBtn.disabled = false; convertText.textContent = 'Convert to Vector'; convertSpinner.classList.add('hidden'); }; img.src = URL.createObjectURL(uploadedFile); }, 500); // Simulate processing time } function displaySVGResult(svg, width, height) { resultContainer.innerHTML = ''; const svgBlob = new Blob([svg], {type: 'image/svg+xml'}); const svgUrl = URL.createObjectURL(svgBlob); svgPreview = document.createElement('img'); svgPreview.src = svgUrl; svgPreview.className = 'max-w-full max-h-full transform origin-center'; svgPreview.style.transform = `scale(${scale}) translate(${translate.x}px, ${translate.y}px)`; resultContainer.appendChild(svgPreview); svgCode.textContent = svg; resultsSection.classList.remove('hidden'); zoomControls.classList.remove('hidden'); // Scroll to results resultsSection.scrollIntoView({ behavior: 'smooth' }); } function toggleColorMode() { const isColor = colorModeToggle.checked; colorModeLabel.textContent = isColor ? 'Color' : 'Monochrome'; colorSettings.style.display = isColor ? 'block' : 'none'; } function updateColorCount() { colorCountValue.textContent = colorCount.value; } function updateSmoothness() { smoothnessValue.textContent = smoothness.value; } function zoomImage(factor) { scale *= factor; updateImageTransform(); } function resetZoom() { scale = 1; translate = { x: 0, y: 0 }; updateImageTransform(); } function startDrag(e) { if (!svgPreview) return; isDragging = true; startPos = { x: e.clientX || e.touches[0].clientX, y: e.clientY || e.touches[0].clientY }; resultContainer.classList.add('dragging'); e.preventDefault(); } function dragImage(e) { if (!isDragging || !svgPreview) return; const currentPos = { x: e.clientX || e.touches[0].clientX, y: e.clientY || e.touches[0].clientY }; translate.x += (currentPos.x - startPos.x) / scale; translate.y += (currentPos.y - startPos.y) / scale; startPos = currentPos; updateImageTransform(); e.preventDefault(); } function endDrag() { isDragging = false; resultContainer.classList.remove('dragging'); } function updateImageTransform() { if (svgPreview) { svgPreview.style.transform = `scale(${scale}) translate(${translate.x}px, ${translate.y}px)`; } } function showAlert(message, type = 'error') { const bgColor = type === 'error' ? 'bg-red-100 border-red-500 text-red-700' : 'bg-green-100 border-green-500 text-green-700'; const alert = document.createElement('div'); alert.className = `fixed top-4 right-4 ${bgColor} border-l-4 p-4 rounded shadow-lg z-50`; alert.innerHTML = `
${message}
`; document.body.appendChild(alert); feather.replace(); setTimeout(() => { alert.classList.add('opacity-0', 'transition-opacity', 'duration-300'); setTimeout(() => alert.remove(), 300); }, 3000); } });