PDA

View Full Version : Carousel - load images not in DOM



arthurakay
17 Jul 2009, 7:58 AM
I've been trying to search the forum for an answer to this question, but I haven't found anything that solves my issue.

The Carousel example (http://extjs.com/playpen/ext-core-latest/examples/carousel/) gets the images for its slideshow from existing DOM markup. If I understand things correctly, the DOM must physically load all the images on page load rather than only loading the images on demand. Obviously this can be a problem is (a) you have a lot of images, and/or (b) the sizes of the image files are large.

It would be ideal if the Carousel had deferred loading of its images. Has anyone been able to extend the Carousel to load images from an array (passed as a config option)?

Something like:


new Ext.ux.Carousel('html-example', {
//itemSelector: 'div.item',
images: [
{ url: 'myImg1.jpg' },
{ url: 'myImg2.jpg' },
{ url: 'myImg3.jpg' }
],
interval: 5,
autoPlay: true,
transitionEasing: 'easeIn'
});


I've seen this jQuery example (http://www.gruppo4.com/~tobia/cross-slide.shtml) which accomplishes this idea (and then some).

Another added benefit would be that you could add images after rendering with more ease.

steffenk
18 Jul 2009, 3:59 PM
Hi,

i want to do the same. i did a flickr plugin presenting pics in a DataView, but i want to have them in carousel too.

Should be possible eg using dh to append the images from given array.
This has to be changed:

this.el.select(this.itemSelector).appendTo(this.els.slidesWrap).each(function(item) {
item = item.wrap({cls: 'ux-carousel-slide'});
this.slides.push(item);
item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
}, this);
to build the correct image tags inside.

Didn't tested, but something like this could work:


for (var i = 0; i < this.images.length; i++) {
var el = dh.append(this.els.slidesWrap, {tag: 'img', cls: 'ux-carousel-slide', src: this.images[i].url}, true)
this.slides.push(el);
el.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
};

steffenk
19 Jul 2009, 1:31 PM
it's even more simple.

Here is a working version (image with array is optional)



Ext.ns('Ext.ux');

Ext.ux.Carousel = Ext.extend(Ext.util.Observable, {
interval: 3,
transitionDuration: 1,
transitionType: 'carousel',
transitionEasing: 'easeOut',
itemSelector: 'img',
activeSlide: 0,
autoPlay: false,
showPlayButton: false,
pauseOnNavigate: false,
wrap: false,
freezeOnHover: false,
navigationOnHover: false,
hideNavigation: false,
images: [],
constructor: function(elId, config) {
config = config || {};
Ext.apply(this, config);

Ext.ux.Carousel.superclass.constructor.call(this, config);

this.addEvents(
'beforeprev',
'prev',
'beforenext',
'next',
'change',
'play',
'pause',
'freeze',
'unfreeze'
);

this.el = Ext.get(elId);
this.slides = this.els = [];

if(this.autoPlay || this.showPlayButton) {
this.wrap = true;
};

if(this.autoPlay && config.showPlayButton === undefined) {
this.showPlayButton = true;
}

this.initMarkup();
this.initEvents();

if(this.carouselSize > 0) {
this.refresh();
}
},

initMarkup: function() {
var dh = Ext.DomHelper;

if (this.images.length) {
for (var i = 0; i < this.images.length; i++) {
dh.append(this.el, {tag: 'img', src: this.images[i].url, title: this.images[i].title});
};
}

this.carouselSize = 0;

this.els.container = dh.append(this.el, {cls: 'ux-carousel-container'}, true);
this.els.slidesWrap = dh.append(this.els.container, {cls: 'ux-carousel-slides-wrap'}, true);

this.els.navigation = dh.append(this.els.container, {cls: 'ux-carousel-nav'}, true).hide();
this.els.caption = dh.append(this.els.navigation, {tag: 'h2', cls: 'ux-carousel-caption'}, true);
this.els.navNext = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-next'}, true);
if(this.showPlayButton) {
this.els.navPlay = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-play'}, true)
}
this.els.navPrev = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-prev'}, true);

// set the dimensions of the container
this.slideWidth = this.el.getWidth(true);
this.slideHeight = this.el.getHeight(true);
this.els.container.setStyle({
width: this.slideWidth + 'px',
height: this.slideHeight + 'px'
});

this.els.caption.setWidth((this.slideWidth - (this.els.navNext.getWidth()*2) - (this.showPlayButton ? this.els.navPlay.getWidth() : 0) - 20) + 'px')

this.el.select(this.itemSelector).appendTo(this.els.slidesWrap).each(function(item) {
item = item.wrap({cls: 'ux-carousel-slide'});
this.slides.push(item);
item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
}, this);


this.carouselSize = this.slides.length;
if(this.navigationOnHover) {
this.els.navigation.setStyle('top', (-1*this.els.navigation.getHeight()) + 'px');
}
this.el.clip();
},

initEvents: function() {
this.els.navPrev.on('click', function(ev) {
ev.preventDefault();
var target = ev.getTarget();
target.blur();
if(Ext.fly(target).hasClass('ux-carousel-nav-disabled')) return;
this.prev();
}, this);

this.els.navNext.on('click', function(ev) {
ev.preventDefault();
var target = ev.getTarget();
target.blur();
if(Ext.fly(target).hasClass('ux-carousel-nav-disabled')) return;
this.next();
}, this);

if(this.showPlayButton) {
this.els.navPlay.on('click', function(ev){
ev.preventDefault();
ev.getTarget().blur();
if(this.playing) {
this.pause();
}
else {
this.play();
}
}, this);
};

if(this.freezeOnHover) {
this.els.container.on('mouseenter', function(){
if(this.playing) {
this.fireEvent('freeze', this.slides[this.activeSlide]);
Ext.TaskMgr.stop(this.playTask);
}
}, this);
this.els.container.on('mouseleave', function(){
if(this.playing) {
this.fireEvent('unfreeze', this.slides[this.activeSlide]);
Ext.TaskMgr.start(this.playTask);
}
}, this, {buffer: (this.interval/2)*1000});
};

if(this.navigationOnHover) {
this.els.container.on('mouseenter', function(){
if(!this.navigationShown) {
this.navigationShown = true;
this.els.navigation.stopFx(false).shift({
y: this.els.container.getY(),
duration: this.transitionDuration
})
}
}, this);

this.els.container.on('mouseleave', function(){
if(this.navigationShown) {
this.navigationShown = false;
this.els.navigation.stopFx(false).shift({
y: this.els.navigation.getHeight() - this.els.container.getY(),
duration: this.transitionDuration
})
}
}, this);
}

if(this.interval && this.autoPlay) {
this.play();
};
},

prev: function() {
if (this.fireEvent('beforeprev') === false) {
return;
}
if(this.pauseOnNavigate) {
this.pause();
}
this.setSlide(this.activeSlide - 1);

this.fireEvent('prev', this.activeSlide);
return this;
},

next: function() {
if(this.fireEvent('beforenext') === false) {
return;
}
if(this.pauseOnNavigate) {
this.pause();
}
this.setSlide(this.activeSlide + 1);

this.fireEvent('next', this.activeSlide);
return this;
},

play: function() {
if(!this.playing) {
this.playTask = this.playTask || {
run: function() {
this.playing = true;
this.setSlide(this.activeSlide+1);
},
interval: this.interval*1000,
scope: this
};

this.playTaskBuffer = this.playTaskBuffer || new Ext.util.DelayedTask(function() {
Ext.TaskMgr.start(this.playTask);
}, this);

this.playTaskBuffer.delay(this.interval*1000);
this.playing = true;
this.els.navPlay.addClass('ux-carousel-playing');
this.fireEvent('play');
}
return this;
},

pause: function() {
if(this.playing) {
Ext.TaskMgr.stop(this.playTask);
this.playTaskBuffer.cancel();
this.playing = false;
this.els.navPlay.removeClass('ux-carousel-playing');
this.fireEvent('pause');
}
return this;
},

clear: function() {
this.els.slidesWrap.update('');
this.slides = [];
this.carouselSize = 0;
this.pause();
return this;
},

add: function(el, refresh) {
var item = Ext.fly(el).appendTo(this.els.slidesWrap).wrap({cls: 'ux-carousel-slide'});
item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
this.slides.push(item);
if(refresh) {
this.refresh();
}
return this;
},

refresh: function() {
this.carouselSize = this.slides.length;
this.els.slidesWrap.setWidth((this.slideWidth * this.carouselSize) + 'px');
if(this.carouselSize > 0) {
if(!this.hideNavigation) this.els.navigation.show();
this.activeSlide = 0;
this.setSlide(0, true);
}
return this;
},

setSlide: function(index, initial) {
if(!this.wrap && !this.slides[index]) {
return;
}
else if(this.wrap) {
if(index < 0) {
index = this.carouselSize-1;
}
else if(index > this.carouselSize-1) {
index = 0;
}
}
if(!this.slides[index]) {
return;
}

this.els.caption.update(this.slides[index].child(':first-child', true).title || '');
var offset = index * this.slideWidth;
if (!initial) {
switch (this.transitionType) {
case 'fade':
this.slides[index].setOpacity(0);
this.slides[this.activeSlide].stopFx(false).fadeOut({
duration: this.transitionDuration / 2,
callback: function(){
this.els.slidesWrap.setStyle('left', (-1 * offset) + 'px');
this.slides[this.activeSlide].setOpacity(1);
this.slides[index].fadeIn({
duration: this.transitionDuration / 2
});
},
scope: this
})
break;

default:
var xNew = (-1 * offset) + this.els.container.getX();
this.els.slidesWrap.stopFx(false);
this.els.slidesWrap.shift({
duration: this.transitionDuration,
x: xNew,
easing: this.transitionEasing
});
break;
}
}
else {
this.els.slidesWrap.setStyle('left', '0');
}

this.activeSlide = index;
this.updateNav();
this.fireEvent('change', this.slides[index], index);
},

updateNav: function() {
this.els.navPrev.removeClass('ux-carousel-nav-disabled');
this.els.navNext.removeClass('ux-carousel-nav-disabled');
if(!this.wrap) {
if(this.activeSlide === 0) {
this.els.navPrev.addClass('ux-carousel-nav-disabled');
}
if(this.activeSlide === this.carouselSize-1) {
this.els.navNext.addClass('ux-carousel-nav-disabled');
}
}
}
});


and the configuration would be



Ext.onReady(function() {
new Ext.ux.Carousel('simple-example', {
images: [
{ url: 'slides/1.jpg', title: 'Picture 1' },
{ url: 'slides/2.jpg', title: 'Picture 2' },
{ url: 'slides/3.jpg', title: 'Picture 3' },
{ url: 'slides/4.jpg', title: 'Picture 4' },
{ url: 'slides/5.jpg', title: 'Picture 5' },
{ url: 'slides/6.jpg', title: 'Picture 6' }
]
});
})

arthurakay
20 Jul 2009, 5:00 AM
steffenk - I appreciate the help on this. I'll give it a shot!

steffenk
21 Jul 2009, 1:01 AM
I made an addition. Adding images from array need also possibility to add width/height property for the slides, i added them.

see http://extjs.com/forum/showthread.php?t=75092

TommyMaintz
4 Aug 2009, 12:02 PM
If you look at the combination example (http://extjs.com/playpen/ext-core-latest/examples/combo/) you see that support for dynamically adding items to the Carousel is already supported. I dont want to put an images or addImage functionality in the example since the carousel can be used for any type of html.

This is a very short example of what you could do


var img = document.createElement('img');
img.src = 'someimage.png';
img.title = 'some title';
carousel.add(img, true); // true to instantly refresh the carousel

// another way would be
carousel.clear() // remove all the current items in carousel
var img = Ext.DomHelper.append(document.body, {tag: 'img', src: 'someimage.png', title: 'some title'});
carousel.add(img);
carousel.refresh();


Using the carousel.clear, carousel.add and carousel.refresh methods you can dynamically add items to the carousel.

I did however added your changes for the 'width' and 'height' configuration options, and fixed the showPlayButton bug in SVN.

steffenk
4 Aug 2009, 2:15 PM
Hi,

thanks for the example, i wasn't aware of this way creating dynamic items. This is of course a better way doing it. And thanks for the changes you did!