Spaces:
Running
Running
| // Main Image Magnifier Class | |
| class ImageMagnifier { | |
| constructor(containerId, previewId, options = {}) { | |
| this.container = document.getElementById(containerId); | |
| this.preview = document.getElementById(previewId); | |
| this.img = this.container.querySelector('img'); | |
| this.lens = document.getElementById('lens'); | |
| this.zoom = options.zoom || 2; | |
| this.lensSize = options.lensSize || 150; | |
| this.init(); | |
| } | |
| init() { | |
| if (this.img.complete) { | |
| this.setupMagnifier(); | |
| } else { | |
| this.img.addEventListener('load', () => this.setupMagnifier()); | |
| } | |
| } | |
| setupMagnifier() { | |
| // Update preview background | |
| this.updatePreviewBackground(); | |
| // Mouse events | |
| this.container.addEventListener('mouseenter', () => this.showMagnifier()); | |
| this.container.addEventListener('mouseleave', () => this.hideMagnifier()); | |
| this.container.addEventListener('mousemove', (e) => this.moveMagnifier(e)); | |
| // Touch events for mobile | |
| this.container.addEventListener('touchstart', (e) => { | |
| e.preventDefault(); | |
| this.showMagnifier(); | |
| this.moveMagnifier(e.touches[0]); | |
| }); | |
| this.container.addEventListener('touchmove', (e) => { | |
| e.preventDefault(); | |
| this.moveMagnifier(e.touches[0]); | |
| }); | |
| this.container.addEventListener('touchend', () => this.hideMagnifier()); | |
| } | |
| updatePreviewBackground() { | |
| this.preview.style.backgroundImage = `url('${this.img.src}')`; | |
| this.preview.style.backgroundSize = `${this.img.width * this.zoom}px ${this.img.height * this.zoom}px`; | |
| } | |
| showMagnifier() { | |
| this.lens.style.opacity = '1'; | |
| this.lens.classList.add('active'); | |
| this.preview.classList.add('active'); | |
| // Clear the placeholder content | |
| const placeholder = this.preview.querySelector('.absolute'); | |
| if (placeholder) placeholder.style.display = 'none'; | |
| } | |
| hideMagnifier() { | |
| this.lens.style.opacity = '0'; | |
| this.lens.classList.remove('active'); | |
| this.preview.classList.remove('active'); | |
| } | |
| moveMagnifier(e) { | |
| const rect = this.img.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| let lensX = x - (this.lensSize / 2); | |
| let lensY = y - (this.lensSize / 2); | |
| // Boundary checks | |
| lensX = Math.max(0, Math.min(lensX, this.img.width - this.lensSize)); | |
| lensY = Math.max(0, Math.min(lensY, this.img.height - this.lensSize)); | |
| // Position lens | |
| this.lens.style.left = `${lensX}px`; | |
| this.lens.style.top = `${lensY}px`; | |
| this.lens.style.width = `${this.lensSize}px`; | |
| this.lens.style.height = `${this.lensSize}px`; | |
| // Calculate background position for preview | |
| const bgX = (lensX / this.img.width) * 100; | |
| const bgY = (lensY / this.img.height) * 100; | |
| this.preview.style.backgroundPosition = `${bgX}% ${bgY}%`; | |
| } | |
| updateZoom(newZoom) { | |
| this.zoom = newZoom; | |
| this.updatePreviewBackground(); | |
| } | |
| updateLensSize(newSize) { | |
| this.lensSize = newSize; | |
| } | |
| changeImage(newSrc) { | |
| this.img.src = newSrc; | |
| this.img.onload = () => { | |
| this.updatePreviewBackground(); | |
| }; | |
| } | |
| } | |
| // Inline Magnifier | |
| class InlineMagnifier { | |
| constructor() { | |
| this.container = document.getElementById('inline-magnifier'); | |
| this.img = this.container.querySelector('img'); | |
| this.lens = document.getElementById('inline-lens'); | |
| this.zoom = 2; | |
| this.init(); | |
| } | |
| init() { | |
| this.lens.style.backgroundImage = `url('${this.img.src}')`; | |
| this.lens.style.backgroundSize = `${this.img.width * this.zoom}px ${this.img.height * this.zoom}px`; | |
| this.container.addEventListener('mouseenter', () => this.lens.style.opacity = '1'); | |
| this.container.addEventListener('mouseleave', () => this.lens.style.opacity = '0'); | |
| this.container.addEventListener('mousemove', (e) => this.moveLens(e)); | |
| } | |
| moveLens(e) { | |
| const rect = this.img.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| const lensWidth = 200; | |
| const lensHeight = 200; | |
| let lensX = x - (lensWidth / 2); | |
| let lensY = y - (lensHeight / 2); | |
| lensX = Math.max(0, Math.min(lensX, this.img.width - lensWidth)); | |
| lensY = Math.max(0, Math.min(lensY, this.img.height - lensHeight)); | |
| this.lens.style.left = `${lensX}px`; | |
| this.lens.style.top = `${lensY}px`; | |
| const bgX = (lensX / this.img.width) * 100; | |
| const bgY = (lensY / this.img.height) * 100; | |
| this.lens.style.backgroundPosition = `${bgX}% ${bgY}%`; | |
| } | |
| } | |
| // Corner Magnifier | |
| class CornerMagnifier { | |
| constructor() { | |
| this.container = document.getElementById('corner-magnifier'); | |
| this.img = this.container.querySelector('img'); | |
| this.zoom = document.getElementById('corner-zoom'); | |
| this.content = document.getElementById('corner-zoom-content'); | |
| this.zoomLevel = 3; | |
| this.init(); | |
| } | |
| init() { | |
| this.content.style.backgroundImage = `url('${this.img.src}')`; | |
| this.content.style.backgroundSize = `${this.img.width * this.zoomLevel}px ${this.img.height * this.zoomLevel}px`; | |
| this.container.addEventListener('mouseenter', () => this.zoom.style.opacity = '1'); | |
| this.container.addEventListener('mouseleave', () => this.zoom.style.opacity = '0'); | |
| this.container.addEventListener('mousemove', (e) => this.updateZoom(e)); | |
| } | |
| updateZoom(e) { | |
| const rect = this.img.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| const bgX = (x / this.img.width) * 100; | |
| const bgY = (y / this.img.height) * 100; | |
| this.content.style.backgroundPosition = `${bgX}% ${bgY}%`; | |
| } | |
| } | |
| // Glass Magnifier | |
| class GlassMagnifier { | |
| constructor() { | |
| this.container = document.getElementById('glass-magnifier'); | |
| this.img = this.container.querySelector('img'); | |
| this.lens = document.getElementById('glass-lens'); | |
| this.zoom = 2.5; | |
| this.init(); | |
| } | |
| init() { | |
| this.lens.style.backgroundImage = `url('${this.img.src}')`; | |
| this.lens.style.backgroundSize = `${this.img.width * this.zoom}px ${this.img.height * this.zoom}px`; | |
| this.container.addEventListener('mouseenter', () => this.lens.style.opacity = '1'); | |
| this.container.addEventListener('mouseleave', () => this.lens.style.opacity = '0'); | |
| this.container.addEventListener('mousemove', (e) => this.moveLens(e)); | |
| } | |
| moveLens(e) { | |
| const rect = this.img.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| const lensSize = 120; | |
| let lensX = x - (lensSize / 2); | |
| let lensY = y - (lensSize / 2); | |
| lensX = Math.max(0, Math.min(lensX, this.img.width - lensSize)); | |
| lensY = Math.max(0, Math.min(lensY, this.img.height - lensSize)); | |
| this.lens.style.left = `${lensX}px`; | |
| this.lens.style.top = `${lensY}px`; | |
| const bgX = (lensX / this.img.width) * 100; | |
| const bgY = (lensY / this.img.height) * 100; | |
| this.lens.style.backgroundPosition = `${bgX}% ${bgY}%`; | |
| } | |
| } | |
| // Initialize all magnifiers when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Main magnifier | |
| const mainMagnifier = new ImageMagnifier('magnifier-container', 'zoom-preview'); | |
| // Zoom controls | |
| const zoomSlider = document.getElementById('zoom-slider'); | |
| const zoomValue = document.getElementById('zoom-value'); | |
| const lensSizeSlider = document.getElementById('lens-size'); | |
| const lensSizeValue = document.getElementById('lens-size-value'); | |
| zoomSlider.addEventListener('input', (e) => { | |
| const value = e.target.value; | |
| zoomValue.textContent = `${value}x`; | |
| mainMagnifier.updateZoom(parseFloat(value)); | |
| }); | |
| lensSizeSlider.addEventListener('input', (e) => { | |
| const value = e.target.value; | |
| lensSizeValue.textContent = `${value}px`; | |
| mainMagnifier.updateLensSize(parseInt(value)); | |
| }); | |
| // Thumbnail switching | |
| const thumbnails = document.querySelectorAll('.thumbnail-card'); | |
| thumbnails.forEach(thumb => { | |
| thumb.addEventListener('click', () => { | |
| // Remove active class from all thumbnails | |
| thumbnails.forEach(t => { | |
| t.classList.remove('active'); | |
| t.classList.remove('border-purple-500'); | |
| t.classList.add('border-gray-200'); | |
| }); | |
| // Add active class to clicked thumbnail | |
| thumb.classList.add('active'); | |
| thumb.classList.remove('border-gray-200'); | |
| thumb.classList.add('border-purple-500'); | |
| // Change main image | |
| const imageSrc = thumb.dataset.image; | |
| mainMagnifier.changeImage(imageSrc); | |
| }); | |
| }); | |
| // Initialize alternative magnifiers | |
| new InlineMagnifier(); | |
| new CornerMagnifier(); | |
| new GlassMagnifier(); | |
| }); |