| |
| |
| |
| |
| |
|
|
| document.addEventListener('DOMContentLoaded', function() { |
| |
| AOS.init({ |
| duration: 800, |
| easing: 'ease-out', |
| once: false, |
| mirror: true |
| }); |
|
|
| |
| initClearButton(); |
| createParticles(); |
| createPawPrints(); |
| initFileUpload(); |
| initNavbarScroll(); |
| updateTimeDisplay(); |
| setInterval(updateTimeDisplay, 1000); |
| initSmoothScrolling(); |
| initShareButtons(); |
| |
| |
| animateProgressBar(); |
| |
| |
| hideLoading(); |
| }); |
|
|
| |
| |
| |
| function animateProgressBar() { |
| const progressBar = document.querySelector('.progress-bar'); |
| if (progressBar) { |
| |
| const confidenceElement = document.querySelector('.result-details .confidence-text'); |
| const confidenceText = confidenceElement ? confidenceElement.textContent : '0%'; |
| const match = confidenceText.match(/(\d+(\.\d+)?)%/); |
| |
| if (match) { |
| const percentage = parseFloat(match[1]); |
| progressBar.style.width = percentage + '%'; |
|
|
| |
| if (percentage >= 80) { |
| progressBar.classList.add('high-confidence'); |
| progressBar.style.background = 'linear-gradient(to right, var(--primary), var(--accent))'; |
| } else if (percentage >= 40) { |
| progressBar.classList.add('medium-confidence'); |
| progressBar.style.background = 'linear-gradient(to right, var(--primary-light), var(--accent))'; |
| } else { |
| progressBar.classList.add('low-confidence'); |
| progressBar.style.background = 'linear-gradient(to right, var(--secondary), var(--secondary-light))'; |
| } |
| } |
| } |
| } |
|
|
| |
| |
| |
| function initClearButton() { |
| const clearBtn = document.getElementById('clear-results-btn'); |
| const resultSection = document.querySelector('.result-section'); |
| const fileInput = document.querySelector('.file-input'); |
| const uploadForm = document.getElementById('upload-form'); |
| const previewContainer = document.querySelector('.preview-container'); |
| const previewImage = document.getElementById('image-preview'); |
| const previewText = document.getElementById('preview-text'); |
| const selectedFileContainer = document.querySelector('.selected-file'); |
| const submitBtn = uploadForm ? uploadForm.querySelector('button[type="submit"]') : null; |
|
|
| if (clearBtn) { |
| clearBtn.addEventListener('click', function() { |
| |
| if (resultSection) { |
| resultSection.style.display = 'none'; |
| } |
| |
| |
| if (previewContainer) { |
| previewContainer.style.display = 'none'; |
| previewImage.style.display = 'none'; |
| previewText.style.display = 'block'; |
| previewImage.src = '#'; |
| } |
| |
| |
| if (fileInput) { |
| fileInput.value = ''; |
| } |
| |
| |
| if (selectedFileContainer) { |
| selectedFileContainer.textContent = ''; |
| } |
|
|
| |
| if (submitBtn) { |
| submitBtn.innerHTML = '<i class="fas fa-search"></i> Identify Breed'; |
| submitBtn.disabled = false; |
| } |
| |
| |
| const errorAlert = document.querySelector('.upload-error'); |
| if (errorAlert && errorAlert.parentNode) { |
| errorAlert.parentNode.removeChild(errorAlert); |
| } |
| |
| |
| document.getElementById('identifier').scrollIntoView({ behavior: 'smooth' }); |
| }); |
| } |
| } |
|
|
| |
| |
| |
| function createParticles() { |
| const container = document.querySelector('.particle-container'); |
| if (!container) return; |
| |
| const colors = ['rgba(74, 111, 165, 0.3)', 'rgba(255, 139, 94, 0.3)', 'rgba(84, 209, 189, 0.3)']; |
| |
| |
| for (let i = 0; i < 30; i++) { |
| const particle = document.createElement('div'); |
| particle.classList.add('particle'); |
| |
| |
| const size = 3 + Math.random() * 8; |
| const color = colors[Math.floor(Math.random() * colors.length)]; |
| const left = Math.random() * 100; |
| const delay = Math.random() * 15; |
| const duration = 15 + Math.random() * 30; |
| |
| |
| particle.style.width = `${size}px`; |
| particle.style.height = `${size}px`; |
| particle.style.backgroundColor = color; |
| particle.style.left = `${left}vw`; |
| particle.style.top = '100vh'; |
| particle.style.animationDuration = `${duration}s`; |
| particle.style.animationDelay = `${delay}s`; |
| |
| container.appendChild(particle); |
| } |
| } |
|
|
| |
| |
| |
| function createPawPrints() { |
| const container = document.querySelector('.paw-prints'); |
| if (!container) return; |
| |
| |
| for (let i = 0; i < 15; i++) { |
| const paw = document.createElement('div'); |
| paw.classList.add('paw'); |
| |
| |
| const size = 15 + Math.random() * 15; |
| const left = Math.random() * 100; |
| const top = Math.random() * 100; |
| const rotation = Math.random() * 360; |
| |
| |
| paw.style.width = `${size}px`; |
| paw.style.height = `${size}px`; |
| paw.style.left = `${left}vw`; |
| paw.style.top = `${top}vh`; |
| paw.style.transform = `rotate(${rotation}deg)`; |
| |
| container.appendChild(paw); |
| } |
| } |
|
|
| |
| |
| |
| function initFileUpload() { |
| const fileInput = document.querySelector('.file-input'); |
| const uploadArea = document.querySelector('.upload-area'); |
| const browseBtn = document.querySelector('.browse-btn'); |
| const selectedFileContainer = document.querySelector('.selected-file'); |
| const form = document.getElementById('upload-form'); |
| |
| if (!fileInput || !uploadArea) return; |
| |
| |
| if (browseBtn) { |
| browseBtn.addEventListener('click', function() { |
| fileInput.click(); |
| }); |
| } |
| |
| |
| uploadArea.addEventListener('click', function(e) { |
| |
| if (e.target !== fileInput) { |
| fileInput.click(); |
| } |
| }); |
| |
| |
| fileInput.addEventListener('change', function() { |
| if (this.files.length > 0) { |
| const file = this.files[0]; |
| |
| if (validateFile(file)) { |
| displayFilePreview(file); |
| uploadArea.classList.add('file-selected'); |
| |
| |
| const errorAlert = document.querySelector('.upload-error'); |
| if (errorAlert && errorAlert.parentNode) { |
| errorAlert.parentNode.removeChild(errorAlert); |
| } |
| } else { |
| |
| this.value = ''; |
| uploadArea.classList.remove('file-selected'); |
| } |
| } |
| }); |
| |
| |
| ['dragover', 'dragenter'].forEach(event => { |
| uploadArea.addEventListener(event, function(e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| uploadArea.classList.add('drag-over'); |
| }); |
| }); |
| |
| ['dragleave', 'dragend'].forEach(event => { |
| uploadArea.addEventListener(event, function(e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| uploadArea.classList.remove('drag-over'); |
| }); |
| }); |
| |
| uploadArea.addEventListener('drop', function(e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| uploadArea.classList.remove('drag-over'); |
| |
| if (e.dataTransfer.files.length > 0) { |
| const file = e.dataTransfer.files[0]; |
| |
| if (validateFile(file)) { |
| fileInput.files = e.dataTransfer.files; |
| displayFilePreview(file); |
| uploadArea.classList.add('file-selected'); |
| } |
| } |
| }); |
| |
| |
| if (form) { |
| form.addEventListener('submit', function() { |
| const submitBtn = this.querySelector('button[type="submit"]'); |
| if (submitBtn) { |
| submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Processing...'; |
| submitBtn.disabled = true; |
| } |
| showLoading(); |
| }); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| function validateFile(file) { |
| |
| const validTypes = ['image/jpeg', 'image/jpg', 'image/png']; |
| if (!validTypes.includes(file.type)) { |
| showError('Please select a valid image file (JPG, JPEG, or PNG).'); |
| return false; |
| } |
| |
| |
| const maxSize = 5 * 1024 * 1024; |
| if (file.size > maxSize) { |
| showError('File size exceeds 5MB. Please choose a smaller image.'); |
| return false; |
| } |
| |
| return true; |
| } |
|
|
| |
| |
| |
| |
| function showError(message) { |
| |
| let errorAlert = document.querySelector('.upload-error'); |
| |
| if (!errorAlert) { |
| errorAlert = document.createElement('div'); |
| errorAlert.className = 'alert alert-danger mt-3 upload-error'; |
| |
| const uploadContainer = document.querySelector('.upload-container'); |
| if (uploadContainer) { |
| uploadContainer.appendChild(errorAlert); |
| } |
| } |
| |
| errorAlert.innerHTML = `<i class="fas fa-exclamation-triangle"></i> ${message}`; |
| |
| |
| setTimeout(() => { |
| if (errorAlert.parentNode) { |
| errorAlert.parentNode.removeChild(errorAlert); |
| } |
| }, 5000); |
| } |
|
|
| |
| |
| |
| |
| function displayFilePreview(file) { |
| const previewContainer = document.querySelector('.preview-container'); |
| const previewImage = document.getElementById('image-preview'); |
| const previewText = document.getElementById('preview-text'); |
| const selectedFileContainer = document.querySelector('.selected-file'); |
| |
| if (!previewContainer || !previewImage || !previewText) return; |
|
|
| |
| previewText.textContent = "Loading preview..."; |
| previewText.style.display = 'block'; |
| previewImage.style.display = 'none'; |
| previewContainer.style.display = 'block'; |
|
|
| |
| const reader = new FileReader(); |
| |
| reader.onload = function(e) { |
| previewImage.src = e.target.result; |
| previewImage.style.display = 'block'; |
| previewText.style.display = 'none'; |
| |
| |
| if (selectedFileContainer) { |
| selectedFileContainer.textContent = `Selected: ${file.name} (${formatFileSize(file.size)})`; |
| } |
| }; |
| |
| reader.onerror = function() { |
| previewText.textContent = "Error loading preview"; |
| }; |
| |
| reader.readAsDataURL(file); |
| } |
|
|
| |
| |
| |
| |
| |
| function formatFileSize(bytes) { |
| if (bytes < 1024) return bytes + " bytes"; |
| else if (bytes < 1048576) return (bytes / 1024).toFixed(1) + " KB"; |
| else return (bytes / 1048576).toFixed(1) + " MB"; |
| } |
|
|
| |
| |
| |
| function showLoading() { |
| const overlay = document.getElementById('loading-overlay'); |
| if (overlay) { |
| overlay.classList.add('active'); |
| } |
| } |
|
|
| |
| |
| |
| function hideLoading() { |
| const overlay = document.getElementById('loading-overlay'); |
| if (overlay) { |
| overlay.classList.remove('active'); |
| } |
| } |
|
|
| |
| |
| |
| function initNavbarScroll() { |
| const navbar = document.querySelector('.app-header'); |
| if (!navbar) return; |
| |
| window.addEventListener('scroll', function() { |
| if (window.scrollY > 10) { |
| navbar.classList.add('scrolled'); |
| navbar.style.padding = '10px 0'; |
| navbar.style.boxShadow = '0 5px 20px rgba(0, 0, 0, 0.08)'; |
| } else { |
| navbar.classList.remove('scrolled'); |
| navbar.style.padding = '15px 0'; |
| navbar.style.boxShadow = '0 2px 15px rgba(0, 0, 0, 0.05)'; |
| } |
| }); |
| } |
|
|
| |
| |
| |
| function updateTimeDisplay() { |
| const timeDisplay = document.getElementById('current-time'); |
| if (!timeDisplay) return; |
| |
| const now = new Date(); |
| const year = now.getUTCFullYear(); |
| const month = String(now.getUTCMonth() + 1).padStart(2, '0'); |
| const day = String(now.getUTCDate()).padStart(2, '0'); |
| const hours = String(now.getUTCHours()).padStart(2, '0'); |
| const minutes = String(now.getUTCMinutes()).padStart(2, '0'); |
| const seconds = String(now.getUTCSeconds()).padStart(2, '0'); |
| |
| timeDisplay.textContent = `${year}-${month}-${day} ${hours}:${minutes}:${seconds} UTC`; |
| } |
|
|
| |
| |
| |
| function initSmoothScrolling() { |
| const navLinks = document.querySelectorAll('a[href^="#"]'); |
| |
| navLinks.forEach(link => { |
| link.addEventListener('click', function(e) { |
| e.preventDefault(); |
| |
| const targetId = this.getAttribute('href'); |
| if (targetId === '#') return; |
| |
| const targetElement = document.querySelector(targetId); |
| if (!targetElement) return; |
| |
| |
| const navbar = document.querySelector('.app-header'); |
| const navbarHeight = navbar ? navbar.offsetHeight : 0; |
| |
| |
| const targetPosition = targetElement.getBoundingClientRect().top + window.scrollY - navbarHeight; |
| |
| |
| window.scrollTo({ |
| top: targetPosition, |
| behavior: 'smooth' |
| }); |
| |
| |
| const navbarToggler = document.querySelector('.navbar-toggler'); |
| const navbarCollapse = document.querySelector('.navbar-collapse'); |
| |
| if (navbarCollapse && navbarCollapse.classList.contains('show')) { |
| navbarToggler.click(); |
| } |
| |
| |
| navLinks.forEach(link => link.classList.remove('active')); |
| this.classList.add('active'); |
| }); |
| }); |
| |
| |
| window.addEventListener('scroll', function() { |
| const scrollPosition = window.scrollY; |
| const navbar = document.querySelector('.app-header'); |
| const navbarHeight = navbar ? navbar.offsetHeight : 0; |
| |
| document.querySelectorAll('section').forEach(section => { |
| const sectionTop = section.offsetTop - navbarHeight - 10; |
| const sectionBottom = sectionTop + section.offsetHeight; |
| |
| if (scrollPosition >= sectionTop && scrollPosition < sectionBottom) { |
| const sectionId = section.getAttribute('id'); |
| |
| navLinks.forEach(link => { |
| link.classList.remove('active'); |
| if (link.getAttribute('href') === `#${sectionId}`) { |
| link.classList.add('active'); |
| } |
| }); |
| } |
| }); |
| }); |
| } |
|
|
| |
| |
| |
| function initShareButtons() { |
| const shareButtons = document.querySelectorAll('.share-btn'); |
| |
| shareButtons.forEach(button => { |
| button.addEventListener('click', function() { |
| const platform = this.getAttribute('data-platform'); |
| const resultImg = document.querySelector('.result-image img'); |
| const resultText = document.querySelector('.item-value .prediction-tag'); |
| |
| if (!resultImg || !resultText) return; |
| |
| const imageUrl = resultImg.src; |
| const breedText = resultText.textContent; |
| const shareText = `I just identified a ${breedText} using the Dog Breed Identifier!`; |
| const siteUrl = window.location.href; |
| |
| let shareUrl = ''; |
| |
| switch(platform) { |
| case 'facebook': |
| shareUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(siteUrl)}`; |
| break; |
| case 'twitter': |
| shareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(siteUrl)}`; |
| break; |
| case 'pinterest': |
| shareUrl = `https://pinterest.com/pin/create/button/?url=${encodeURIComponent(siteUrl)}&media=${encodeURIComponent(imageUrl)}&description=${encodeURIComponent(shareText)}`; |
| break; |
| case 'email': |
| shareUrl = `mailto:?subject=Dog Breed Identification&body=${encodeURIComponent(shareText + '\n\n' + siteUrl)}`; |
| break; |
| } |
| |
| if (shareUrl) { |
| window.open(shareUrl, '_blank', 'width=600,height=400'); |
| } |
| }); |
| }); |
| } |