1. #1
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default Reengineered Image Carousel for Ext2.0

    Reengineered Image Carousel for Ext2.0


    I sorely needed an image carousel for my 2.x app so I started with the 1.x Carousel component from Matthew Hazlett. As Jack would say--two skipped meals and moderate amounts of caffeine later, it is working. The general look and feel remains the same from the 1.x app-- however even that can be customized through css.

    Things it doesn't have (a. because I didn't need it for my projects -- b. I got lazy)
    *Doesn't scroll vertically even though that would be pretty easy to do
    *The image from the right comes in and leaves choppy, especially pronounced on larger images
    *It doesn't have a scroll automatically mode
    *It doesn't patch the beginning onto the end when you scroll to the end
    *It doesn't handle re-positioning after render.
    *The image wrap is not an ext container. I would have liked to allow the scrolling of non-images and then set up an xtype for viewing images but... my dog needed a walk.

    Things it does:
    *It is written more like an Ext component with much less code and much more customizable. This means easier upgrades.
    *It only display whole pictures like the YUI image carousel. Each arrow click scrolls to the next page of images.

    New CSS Options
    Code:
            .x-carousel-inner {
       border: 1px solid black;
       margin-bottom:5px;
            }
            .x-carousel-handle-right {
       background:gray url(handle-right.png) repeat-y;
       float:right;
       cursor:pointer;
       width:10px
            }
            .x-carousel-handle-left {
       background:gray url(handle-left.png) repeat-y;
       float:left;
       cursor:pointer;
       width:10px
            }
    Here is a sample implementation.

    Code:
    {
                 xtype:'carousel',
                 wrapMarginY:3,
                 wrapMarginX:15,
                 imageHeight:48, 
                 imageWidth:48, 
                 width:300, /*auto width would be nice but not supported*/
                    listeners:{
         selected: function(carousel, image, e, ele){ 
          Ext.get("LargeImage").dom.innerHTML = '<img src="' + (image.fullSrc||image.src) + '" width=300 height=300>';
         }              
                    },
                 images:[ /*notice how you can load images different ways..and even attach an event to a particular image*/
                     {fullSrc:"images/DSC00213.jpg", src:"images/DSC00213_tn.jpg", onSelected: function(){alert('stopped the display'); return false} },
                     {fullSrc:"images/DSC00220.jpg", src:"images/DSC00220_tn.jpg"},
                     "images/DSC00215.jpg",
                     "images/DSC00217_tn.jpg",
                     ...
                 ]
             },{
              xtype:'panel',
              id: 'LargeImage',
              width:300,
              height:300

    And here is the code if you want to peruse it before downloading the zip file.

    Code:
    Ext.namespace('Ext.ux');
    Ext.ux.Carousel = function(config){
        Ext.ux.Carousel.superclass.constructor.call(this, config);    
        Ext.apply(this, config);        
    };
    Ext.extend(Ext.ux.Carousel, Ext.Component, {
     baseCls : 'x-carousel',
        setSize : Ext.emptyFn,
        setWidth : Ext.emptyFn,
        setHeight : Ext.emptyFn,
        setPosition : Ext.emptyFn,
        setPagePosition : Ext.emptyFn,
        initComponent : function(){
            Ext.ux.Carousel.superclass.initComponent.call(this);
         this.addEvents({'selected' : true});
            if (typeof(this.imageGap)=='undefined') { this.imageGap = 5 }
            if (!this.noPreload) {
             this.preload.defer(1,this);
            }
     
        },
     
        preload: function(){
            var preload = Ext.get(document.body).createChild({tag:"div", style:"display:none"});
     
            Ext.each(this.images, function(image){
                if (typeof(image)=='string'){
                 image={src:image}
                }
                if (image.src){
                    preload.createChild({tag:"img", src:image.src});
                }
                if (image.fullSrc){
                    preload.createChild({tag:"img", src:image.fullSrc});
                }
            }, this);
        },
        onRender : function(ct, position){
     
            var tpl = new Ext.Template(
                '<div class="{cls}-wrap">',
                    '<div class="{cls}-inner">',
                     '<div class="{cls}-images-wrap">',
                         '<div class="{cls}-images"></div>',
                     '</div>',
                 '</div>',
                '</div>'
            );
            if(position){
                this.el = tpl.insertBefore(position, {cls: this.baseCls}, true);
            }else{
                this.el = tpl.append(ct, {cls: this.baseCls}, true);
            }
            if(this.id){
                this.el.dom.id = this.id;
            }
     
            var inner= Ext.get(this.el.dom.firstChild);
            var imagesWrap = Ext.get(inner.dom.firstChild);
            this.divImages = Ext.get(imagesWrap.dom.firstChild);
      inner.setStyle({
       height:(this.imageHeight + (2*this.wrapMarginY)) + 'px',
       width:this.width+'px'
      });
     
      var totalImageWidth=this.imageWidth+this.imageGap;
      var usableWidth=this.width-(this.wrapMarginX*2);
      var maxPicsOnce=Math.floor(usableWidth/totalImageWidth);
      var usedWidth=maxPicsOnce*totalImageWidth-this.imageGap;
      var offsetLeft=Math.floor((usableWidth-usedWidth)/2);
      this.pageSize=usedWidth+this.imageGap;
      this.maxPages=Math.round(this.images.length/maxPicsOnce+.4999);
      this.curPage=0;
      if (!Ext.isIE){
       offsetLeft+=this.wrapMarginX;
      }
     
      imagesWrap.setStyle({
       position: 'absolute',
       clip:'rect(0,'+(usedWidth*1)+','+(this.imageHeight)+',0)',
       'margin-top':this.wrapMarginY+'px',
       width:this.width+'px',
       height:this.imageHeight+'px',
       'margin-left':offsetLeft+'px'
      });
      this.divImages.setStyle({
       position: 'absolute'
      });  
            Ext.each(this.images, function(image){            
                if (typeof(image)=='string'){
                 image={src:image}
                }
                thisImage = this.divImages.createChild({tag:"img", src:image.src, style:{
                 'margin-right': this.imageGap+'px',
                 width:  this.imageWidth+'px',
                 height: this.imageHeight+'px'             
                }});
     
                thisImage.on("click", function(e, ele){
                 if (!image.onSelected || !(image.onSelected.call(this, image, e, ele )===false)){
                     this.fireEvent('selected', this, image, e, ele);                
                 }
                },this);
            },this);
     
            var styleArrows={};
      if (!this.dontResizeArrows){
       styleArrows.height=(this.imageHeight+(2*this.wrapMarginY)) + 'px'; 
      }
     
            var divLeftButton   = inner.createChild({tag:"div", cls:this.baseCls + '-handle-right', style:styleArrows});
            divLeftButton.on("mousedown", function(){
       this.shiftImages('right');   
            },this);
         var divRightButton  = inner.createChild({tag:"div", cls:this.baseCls + '-handle-left', style:styleArrows});
            divRightButton.on("mousedown", function(){
       this.shiftImages('left');
            },this);
     
     
         },
        shiftImages: function(direction){
      if (!this.curPage){
       this.offsetLeft=this.divImages.getLeft();
      }
      var newPage=(direction=='right' ? this.curPage+1 : this.curPage-1 );
      if (newPage<0 || newPage >= this.maxPages){
       return;
      }
      this.curPage=newPage;
      var newLocation=(this.pageSize*this.curPage)*-1+this.offsetLeft;
      this.divImages.shift({ x:newLocation, duration: this.duration || .7 });
        }
    });
    Ext.reg('carousel', Ext.ux.Carousel);
    Attached Files

  2. #2
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,523
    Vote Rating
    378
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Is there any chance to see it in action? Live Demo?
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  3. #3
    Sencha User galdaka's Avatar
    Join Date
    Mar 2007
    Location
    Spain
    Posts
    1,166
    Vote Rating
    -1
    galdaka is an unknown quantity at this point

      0  

    Default


    Live example please!!

    Thanks in advance,

  4. #4
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,502
    Vote Rating
    47
    Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    There is an example of a Layout class which implements left/right scrolling of any added Components hre: http://extjs.com/forum/showthread.php?p=73802#post73802

    Drop the code from there into examples/layout

    You can add any Component in (And usually, it would be just a Panel containing an image as in the demo), and it lays them out side by side and lets you scroll them.

  5. #5
    Ext User jerrybrown5's Avatar
    Join Date
    Sep 2007
    Location
    Port St Lucie, FL
    Posts
    185
    Vote Rating
    0
    jerrybrown5 is on a distinguished road

      0  

    Default


    Animal,
    I must admit that I like your carousel layout more than my carousel component. Although mine is simpler to implement for pure image scrolling, it doesn't hold up as well when you need something more complicated. I think you chose the better way to program this feature set. Nice work!

    PS, I wish I saw this before

    Best regards,
    Jerry

Thread Participants: 3