Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy load and cell size #1

Open
glafarge opened this issue Feb 27, 2015 · 1 comment
Open

Lazy load and cell size #1

glafarge opened this issue Feb 27, 2015 · 1 comment
Labels

Comments

@glafarge
Copy link
Owner

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 :

  • Set the width of images on <img> tag itself to get it before loading.
  • If width of all cells is equal, simply add a new configuration parameter like : cellWidth
@glafarge glafarge added the bug label Feb 27, 2015
@RatGit
Copy link

RatGit commented Jun 4, 2015

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:

  1. All code changes have been commented with "KCW:"
  2. The mods currently require jQuery.
  3. Apologies in advance for using Allman style indentation, (I parse it better)

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;

}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants