casmopedia / static /js /performance.js
aradhyapavan's picture
CospmoPedia
7e3b585 verified
/* Performance Optimization & Lazy Loading */
class PerformanceOptimizer {
constructor() {
this.init();
}
init() {
this.setupLazyLoading();
this.optimizeAnimations();
this.setupImageLoadingStates();
this.optimizeScrollEvents();
this.preloadCriticalAssets();
}
// Lazy Loading with Intersection Observer
setupLazyLoading() {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
// Add loading state
img.classList.add('loading');
// Load the image
if (img.dataset.src) {
img.src = img.dataset.src;
img.removeAttribute('data-src');
}
// Handle load completion
img.onload = () => {
img.classList.remove('loading');
img.classList.add('loaded');
};
// Handle errors
img.onerror = () => {
img.classList.remove('loading');
img.classList.add('error');
// Set fallback image
img.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDQwMCAzMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSI0MDAiIGhlaWdodD0iMzAwIiBmaWxsPSIjMWExYTJlIi8+CjxwYXRoIGQ9Ik0yMDAgMTAwQzIyMi4wOTEgMTAwIDI0MCA4Mi4wOTE0IDI0MCA2MEM2MCAzNy45MDg2IDIyMi4wOTEgMjAgMjAwIDIwQzE3Ny45MDkgMjAgMTYwIDM3LjkwODYgMTYwIDYwQzE2MCA4Mi4wOTE0IDE3Ny45MDkgMTAwIDIwMCAxMDBaIiBmaWxsPSIjNjY2NjY2Ii8+CjxyZWN0IHg9IjEwMCIgeT0iMTUwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwIiByeD0iMTAiIGZpbGw9IiM2NjY2NjYiLz4KPHJlY3QgeD0iMTMwIiB5PSIxOTAiIHdpZHRoPSIxNDAiIGhlaWdodD0iMTUiIHJ4PSI3LjUiIGZpbGw9IiM0NDQ0NDQiLz4KPC9zdmc+';
};
observer.unobserve(img);
}
});
}, {
rootMargin: '50px 0px',
threshold: 0.01
});
// Observe all images with data-src attribute
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
// Also setup for dynamically loaded images
this.setupDynamicImageObserver(imageObserver);
}
setupDynamicImageObserver(observer) {
// Watch for new images added to the DOM
const mutationObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // Element node
const images = node.querySelectorAll ? node.querySelectorAll('img[data-src]') : [];
images.forEach(img => observer.observe(img));
// If the node itself is an image
if (node.tagName === 'IMG' && node.hasAttribute('data-src')) {
observer.observe(node);
}
}
});
});
});
mutationObserver.observe(document.body, {
childList: true,
subtree: true
});
}
// Optimize animations using requestAnimationFrame
optimizeAnimations() {
let ticking = false;
function updateAnimations() {
// Batch DOM updates here
ticking = false;
}
function requestTick() {
if (!ticking) {
requestAnimationFrame(updateAnimations);
ticking = true;
}
}
// Throttle scroll events
window.addEventListener('scroll', requestTick, { passive: true });
}
// Add loading states for images
setupImageLoadingStates() {
// Add CSS for loading states if not already present
if (!document.getElementById('lazy-loading-styles')) {
const style = document.createElement('style');
style.id = 'lazy-loading-styles';
style.textContent = `
img.loading {
background: linear-gradient(90deg, #1a1a2e 25%, #2d2d4a 50%, #1a1a2e 75%);
background-size: 200% 100%;
animation: loading-shimmer 1.5s infinite;
min-height: 200px;
}
img.loaded {
animation: fadeIn 0.3s ease-in-out;
}
img.error {
background: #333;
color: #999;
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
}
@keyframes loading-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.card-img-top {
transition: transform 0.3s ease;
}
.card:hover .card-img-top {
transform: scale(1.05);
}
`;
document.head.appendChild(style);
}
}
// Optimize scroll events
optimizeScrollEvents() {
let scrollTimeout;
window.addEventListener('scroll', () => {
// Clear existing timeout
clearTimeout(scrollTimeout);
// Set a new timeout
scrollTimeout = setTimeout(() => {
// Update scroll progress
this.updateScrollProgress();
}, 10);
}, { passive: true });
}
updateScrollProgress() {
const scrollProgress = document.getElementById('scrollProgress');
if (scrollProgress) {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const docHeight = document.body.scrollHeight - window.innerHeight;
const scrollPercent = (scrollTop / docHeight) * 100;
scrollProgress.style.width = Math.min(scrollPercent, 100) + '%';
}
}
// Preload critical assets
preloadCriticalAssets() {
const criticalAssets = [
'static/css/space-theme.css',
'static/js/space-theme.js'
];
criticalAssets.forEach(asset => {
const link = document.createElement('link');
link.rel = 'preload';
link.href = asset;
link.as = asset.endsWith('.css') ? 'style' : 'script';
document.head.appendChild(link);
});
}
// Convert existing images to lazy loading
static convertToLazyLoading() {
document.querySelectorAll('img:not([data-src])').forEach(img => {
if (img.src && !img.src.startsWith('data:')) {
img.dataset.src = img.src;
img.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSIjMWExYTJlIi8+CjwvZXZnPg==';
img.classList.add('lazy-load');
}
});
}
// Debounce function for performance
static debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Throttle function for performance
static throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
}
// Initialize performance optimizations when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
new PerformanceOptimizer();
});
} else {
new PerformanceOptimizer();
}
// Export for use in other scripts
window.PerformanceOptimizer = PerformanceOptimizer;