Open glafarge opened 9 years ago
I've modified the code to fix a couple of bugs and also added functionality to calculate the number of preloaded images based on a new "imgWidth" Flickity option, (if undefined, default=640), and taking into account the "wrapAround" and "cellAlign" options. It has been tested for all combinations of these options in the "ondemand" mode.
Notes:
START OF CODE BLOCK
/*!
* Flickity lazyLoad v1.0.0
* enables lazyLoad option for Flickity
* based on slick approach
*/
/*jshint browser: true, strict: true, undef: true, unused: true */
( function( window, factory ) {
/*global define: false, module: false, require: false */
'use strict';
// universal module definition
if ( typeof define == 'function' && define.amd ) {
// AMD
define( [
'flickity/js/index',
'fizzy-ui-utils/utils',
], function( Flickity, utils ) {
return factory( window, Flickity, utils );
});
}
else if ( typeof exports == 'object' ) {
// CommonJS
module.exports = factory(
window,
require('flickity'),
require('fizzy-ui-utils')
);
}
else {
// browser global
window.Flickity = factory(
window,
window.Flickity,
window.fizzyUIUtils
);
}
}( window, function factory( window, Flickity, utils ) {
'use strict';
Flickity.createMethods.push('_createLazyLoad');
Flickity.prototype._createLazyLoad = function() {
this.on( 'activate', this.activateLazyLoad );
}
Flickity.prototype.activateLazyLoad = function() {
if ( !this.options.lazyLoad ) {
return;
}
this.previousIndex = null; // Keep it to avoid bad behavior
this.lazyLoad();
this.previousIndex = this.selectedIndex;
function onSelect() {
if(this.selectedIndex==this.previousIndex)
return;
this.lazyLoad();
this.previousIndex = this.selectedIndex;
}
this.on('cellSelect', onSelect);
}
Flickity.prototype.lazyLoad = function() {
var _this = this;
function imageLoaded(img) {
img.removeAttribute('data-lazy');
classie.remove(img, 'flickity-loading');
var cell = _this.getParentCell( img );
_this.cellSizeChange( cell && cell.element );
}
function onImageLoaded(e) {
var img = e.target;
eventie.unbind(img, 'load', onImageLoaded);
imageLoaded(img);
}
function onImageLoadedProgressive(e) {
var img = e.target;
eventie.unbind(img, 'load', onImageLoadedProgressive);
imageLoaded(img);
_this.lazyLoad();
}
function loadImage(img, callback) {
if(img.hasAttribute('data-lazy')) {
var url = img.getAttribute('data-lazy');
eventie.bind(img, 'load', callback);
img.src = url;
}
}
function loadImages(rangeStart, rangeEnd) {
// var images = utils.filterFindElements(_this.slider.children);
var images = utils.filterFindElements(_this.slider.children, 'img'); // KCW: Modifed to select images not their div wrappers
// KCW: Modifed to remove uneccessary, (and invalid) slice operation
for (var i=rangeStart; i <= rangeEnd; i++)
{
var img = images[i];
loadImage(img, onImageLoaded);
}
}
// ==========================================
// INITIALIZATION
// ==========================================
// Apply loading class on images that don't have src attribute but data-lazy
var images = utils.filterFindElements(_this.slider.children, 'img[data-lazy]');
for( var i=0, len = images.length; i < len; i++ ) {
var img = images[i];
if(!img.hasAttribute('src')) {
classie.add(img, 'flickity-loading');
}
}
// ==========================================
// LAZY LOAD ON DEMAND
// ==========================================
// KCW: Modifed to calculate number of preloaded images based on a new "imgWidth" option and the "cellAlign" option, (currently requires jQuery)
if(_this.options.lazyLoad == 'ondemand') {
if (this.cells.length == 0 || jQuery(this.element).width() == 0) {return;}
var imgWidth = (this.options.imgWidth ? this.options.imgWidth : 640); // Default Image Width = 640px
var cellWidth = imgWidth + jQuery(this.cells[0].element).children('img').outerWidth(true);
var wrapNum = Math.ceil(jQuery(this.element).width() / cellWidth) + 1; // Add 1 in case there's room for two halves in a centered view
var rangeStart = _this.selectedIndex, rangeEnd;
switch (this.options.cellAlign)
{
case 'right':
rangeEnd = rangeStart;
rangeStart = rangeStart - wrapNum;
if (rangeStart < 0) {rangeStart = 0;}
break;
case 'center':
rangeEnd = rangeStart + Math.ceil(wrapNum/2)
rangeStart = rangeStart - Math.ceil(wrapNum/2);
if (rangeStart < 0) {rangeStart = 0;}
if (rangeEnd >= this.cells.length) {rangeEnd = this.cells.length-1;}
break;
default: // 'left'
rangeEnd = rangeStart + wrapNum;
if (rangeEnd >= this.cells.length) {rangeEnd = this.cells.length-1;}
break;
}
loadImages(rangeStart, rangeEnd); // load next imgs
if(_this.options.wrapAround === true) // Preload wrapped images if "wrapAround" option is true
{
// Using "naive" approach here, (essentially applying the "right" and "left" cases consecutively for the "center" alignment)... Could be optimised
rangeStart = _this.selectedIndex;
if (this.options.cellAlign == 'right' || this.options.cellAlign == 'center')
{
rangeEnd = rangeStart + ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : 0);
rangeStart = rangeStart - ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : wrapNum);
if (rangeStart < 0)
{
rangeStart = this.cells.length - ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : wrapNum) - 1;
rangeEnd = this.cells.length - 1;
loadImages(rangeStart, rangeEnd);
}
}
rangeStart = _this.selectedIndex;
if (this.options.cellAlign == 'left' || this.options.cellAlign == 'center')
{
rangeEnd = rangeStart + ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : wrapNum);
rangeStart = rangeStart - ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : 0);
if (rangeEnd >= this.cells.length)
{
rangeStart = 0;
rangeEnd = rangeEnd - this.cells.length;
loadImages(rangeStart, rangeEnd);
}
}
}
else // Preload additional images if number is less than container element width
{
rangeStart = _this.selectedIndex;
if (this.options.cellAlign == 'right' || this.options.cellAlign == 'center')
{
rangeEnd = rangeStart + ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : 0);
rangeStart = rangeStart - ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : wrapNum);
if (rangeStart < 0)
{
rangeEnd = rangeEnd - rangeStart;
rangeStart = 0;
if (rangeEnd >= this.cells.length) {rangeEnd = this.cells.length-1;}
loadImages(rangeStart, rangeEnd);
}
}
rangeStart = _this.selectedIndex;
if (this.options.cellAlign == 'left' || this.options.cellAlign == 'center')
{
rangeEnd = rangeStart + ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : wrapNum);
rangeStart = rangeStart - ((this.options.cellAlign == 'center') ? Math.ceil(wrapNum/2) : 0);
if (rangeEnd >= this.cells.length)
{
rangeStart = rangeStart - (rangeEnd - this.cells.length);
if (rangeStart < 0) {rangeStart = 0;}
rangeEnd = this.cells.length -1;
loadImages(rangeStart, rangeEnd);
}
}
}
}
// ==========================================
// PROGRESSIVE WAY
// ==========================================
else if(_this.options.lazyLoad == 'progressive') {
var images = utils.filterFindElements(_this.slider.children, 'img[data-lazy]');
if(images.length > 0) {
var img = images[0]; // get first child
loadImage(img, onImageLoadedProgressive);
}
}
};
return Flickity;
}));
Cells overlap and some layout problems occurs before images are loaded.
As the images are not loaded at the beginning but on a progressive way or on-demand, the slide is not able to position cells properly.
How to correctly set the size of cells before image load ?
Possible answers :
<img>
tag itself to get it before loading.cellWidth