/* lazyload.js =========== https://docs.google.com/document/d/1QjE8BaIA1pxVMXJzsBVR3dVMcq2bHHa-aUpIsGj_c4A/edit# This file uses IntersectionObserver to load images when they reach a specific point in the viewport. PLEASE READ ME !!!! PLEASE READ ME !!!! PLEASE READ ME !!!! PLEASE READ ME !!!! PLEASE READ ME !!!! PLEASE READ ME !!!! =================== There are bits in this file that are AB / MZ specific, please remove the AB / MZ specific stuff to have this work on other platforms, you might want to download the Pure White Lines repo and take a look at the lazyload there if in doubt If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php If you make any changes here you'll need to minify and put IN lazyload.min.php WHY LAZY LOAD? ============== Everytime we want to load an image a request goes out and the image is loaded. This can significantly make loading times of websites poor, so we use a technique called lazyload. Simply put it just makes the images load when the specified viewport goes into a certain range of the image. In the case of PH9 we load images when they reach viewport height + ( viewport height / 2 ) meaning when the image is half of the screens height away from coming in to view, we load the image. HOW TO USE ========== 1) Include this file 2) Give an image the require class A) If you want to modify a HTML img tag use the class "lazy-img" B) If you want to modify the CSS background-image property use "lazy-img-bg" 3) Set the 'data-src' attribute to the actual image src, and remove the 'src' from the image 4) Include IntersectionObserver polyfill Want different image on mobile compared to desktop? simply -: add src-desktop-size onto the image (where size is the pic size suffix for desktop (EG size2)) add src-mobile-size onto the image (where size is the pic size suffix for mobile (EG size3)) Make sure that the data-src is the high resolution / desktop version EXAMPLE ======= BACKGROUND IMAGE EXAMPLE ========================
NORMAL IMAGE EXAMPLE ==================== My Image */ // Store if masonary has loaded or not var bHasMasonaryLoaded = false; // Store if we need to load mobile version of image instead var bLoadMobileImageInstead = false; // Store all images that have the mobile version of the image // loaded if applicable var aImageElementsThatHaveMobileImageLoaded = []; /* ON DOCUMENT LOAD ================ */ $( document ).ready(function() { // On window resize $(window).resize( function() { // Store the last state var bWasLoadingOnMobile = bLoadMobileImageInstead; // Store if we need to load the mobile versions of the image instead (if present) bLoadMobileImageInstead = $(window).width() <= 760; // If we were loading mobile device images, but we no longer are loading mobile device images if( bWasLoadingOnMobile && !bLoadMobileImageInstead ) { // Loop through all the images that we have loaded for mobile devices for( var i = 0; i < aImageElementsThatHaveMobileImageLoaded.length; i++ ) { // Store the image reference var oImage = aImageElementsThatHaveMobileImageLoaded[i]; // Store the image source that we want to laod var sImageSource = oImage.data("src"); // Set the image src to the data-src oImage.attr('src', sImageSource); // Antiques Boutique only, when the image has loaded oImage.on( "load", function() { // Call the on image load function fOnImageLoad( $(this) ); }); } // Remove all elements from array aImageElementsThatHaveMobileImageLoaded = []; } }); $(window).resize(); // Call the lazyloader fInitLazyLoad(); // If there is a grid if( $('.grid').length ) { // When the images in the grid have been loaded (Realistically this should be called instantly) $('.grid').imagesLoaded( function() { // Antiques Boutique only // Set a timeout to refresh the masonary layout after 200ms // This is so when users hit the back button the masonary doesn't look poop setTimeout( function () { // Force the masonry to resize $(".grid").masonry("layout"); }, 200); // Log that the masonary has loaded bHasMasonaryLoaded = true; }); } }); /* fInitLazyLoad() =============== Handles the lazy load IN/OUT ====== PARAM 1 - NOTHING(VOID) RETURNS - NOTHING(VOID) FLOW ==== 1) CREATE CONFIG 2) CREATE OBSERVER 3) INITIALISE OBSERVER */ function fInitLazyLoad() { /* 1) CREATE CONFIG ================ */ // Set the inital margin value for the lazy load var nMargin = $(window).height() / 1.25; // If the user is on mobile, or the screen width is a certain width (In mobile range) if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || $(window).width() <= 760 ) { // Set the margin as a bigger ratio than inital, to ensure images load in time for the image to reach viewport nMargin = $(window).height() * 1.5; } // Set the default config for IntersectionObserver var oConfig = { // Set the root to null so the viewport is used instead of a DOM element root : null, // Set the root margin, so we can start loading ahead of time rootMargin : nMargin + 'px 0px', // Set the threshold threshold : 0.01 }; /* 2) CREATE OBSERVER ================== This is where we actually do the image loading */ // Create an instance of IntersectionObserver var oObserver = new IntersectionObserver( function(aEntries, oSelf) { // Loop through all elements we are observing for( var nIndex = 0; nIndex < aEntries.length; nIndex++ ) { // Store this instance of the entry var oEntry = aEntries[nIndex]; // If the entry is intersecting if( oEntry.intersectionRatio > 0) { // Store a jquery instance of this image var oImage = $(oEntry.target); // If the image is a lazy image if( oImage.hasClass("lazy-img") ) { // Store the image source that we want to laod var sImageSource = oImage.data("src"); // If we are instead wanting to load the mobile version of the image // as we are on a mobile device if( bLoadMobileImageInstead ) { // If the required data in order to handle the different image sizes is set if( oImage.data("src-desktop-size") != undefined && oImage.data("src-mobile-size") != undefined ) { // Replace the image source wiht the mobile size (EG desktop size is size2, replace with size3) sImageSource = sImageSource.replace( oImage.data("src-desktop-size"), oImage.data("src-mobile-size")); // Add the item to the array aImageElementsThatHaveMobileImageLoaded.push(oImage); } } // Set the image src to the data-src oImage.attr('src', sImageSource); // Antiques Boutique only, when the image has loaded oImage.on( "load", function() { // Call the on image load function fOnImageLoad( $(this) ); }); // Remove the lazy-image class oImage.removeClass("lazy-img"); } else // If the image is a lazy image background if( oImage.hasClass("lazy-img-bg") ) { // Store the image source that we want to laod var sImageSource = oImage.data("src"); // If we are instead wanting to load the mobile version of the image // as we are on a mobile device if( bLoadMobileImageInstead ) { // If the required data in order to handle the different image sizes is set if( oImage.data("src-desktop-size") != undefined && oImage.data("src-mobile-size") != undefined ) { // Replace the image source wiht the mobile size (EG desktop size is size2, replace with size3) sImageSource = sImageSource.replace( oImage.data("src-desktop-size"), oImage.data("src-mobile-size")); // Add the item to the array aImageElementsThatHaveMobileImageLoaded.push(oImage); } } // Set the image src to the data-src oImage.css('background-image', "url('" + oImage.data("src") + "')" ); // Remove the lazy-image class oImage.removeClass("lazy-img-bg"); } // Stop observing this image oSelf.unobserve(oEntry.target); } }; }, oConfig); /* 3) INITIALISE OBSERVER ====================== */ // Grab all the images with a class of lazy-img var aImages = document.querySelectorAll('.lazy-img'); // Grab all background images var aBackgroundImages = document.querySelectorAll('.lazy-img-bg'); // Itterate over all images for( var nIndex = 0; nIndex < aImages.length; nIndex++ ) { // If the IntersectionObserver isn't supported then just load the image if( !('IntersectionObserver' in window) ) { // Store a jquery instance of this image var oImage = $( aImages[nIndex] ); // Set the image src to the data-src oImage.attr('src', oImage.data("src") ); // Remove the lazy-image class oImage.removeClass("lazy-img"); // Remove the filter blur if it has it oImage.removeClass("blur-image"); } // If the IntersectionObserver is supported else { // Call the observer to observe oObserver.observe( aImages[nIndex] ); } } // Itterate over all background images for( var nIndex = 0; nIndex < aBackgroundImages.length; nIndex++ ) { // If the IntersectionObserver isn't supported then just load the background image if( !('IntersectionObserver' in window) ) { // Store a jquery instance of this background image var oImage = $( aBackgroundImages[nIndex] ); // Set the background image src to the data-src oImage.css('background-image', 'url(' + oImage.data("src") + ')' ); // Remove the lazy-image class oImage.removeClass("lazy-img-bg"); // Remove the filter blur if it has it oImage.removeClass("blur-image"); } // If the IntersectionObserver is supported else { // Call the observer to observe oObserver.observe( aBackgroundImages[nIndex] ); } } } /* fOnImageLoad() ============== This function is called when the lazyload has finished loading an image. Is it required for AntiquesBoutique as we use masonry javascript plugin. This means that when the image is loaded we need to tell the masonry script that the window needs to be resized as something has changed. We do this by calling "layout" All this function needs to do (AS of writing) is check if the parent has the class item-i to test if it is a masonary item. Then if it is we just call the "layout" function of the masonry object to resize it for us. IN/OUT ====== PARAM 1 : Jquery image DOM object (JQuery Image DOM) RETURNS : Nothing! (Void) */ function fOnImageLoad( oImage ) { // If the image is a masonary element if( oImage.parent().hasClass("item-i") && bHasMasonaryLoaded ) { // If there is a grid if( $('.grid').length ) { // Force the masonry to resize $(".grid").masonry("layout"); } } // Remove the filter blur if it has it oImage.removeClass("blur-image"); }