PDA

View Full Version : Ext.layout.SlideLayout - Sliding Card Layout (Shift Fx)



NeonMonk
4 Aug 2008, 8:30 AM
Hey guys,

I had a need for a card panel layout that used slide effects.

See: Live Demo (http://slidelayout.freehostia.com/).

Shift fX config can be set through layoutConfig eg:


layoutConfig: {
easing: 'easeOut',
duration: 1,
opacity: .1
}The code:


Ext.layout.SlideLayout = Ext.extend(Ext.layout.FitLayout, {

deferredRender : false,


renderHidden : false,
easing: 'none',
duration: .5,
opacity: 1,


setActiveItem : function(itemInt){
if (typeof(itemInt) == 'string') { itemInt = this.container.items.keys.indexOf(itemInt); }
else if (typeof(itemInt) == 'object') { itemInt = this.container.items.items.indexOf(itemInt); }
var item = this.container.getComponent(itemInt);
if(this.activeItem != item){
if(this.activeItem){
if(item && (!item.rendered || !this.isValidParent(item, this.container))){
this.renderItem(item, itemInt, this.container.getLayoutTarget()); item.show();
}
var s = [this.container.body.getX() - this.container.body.getWidth(), this.container.body.getX() + this.container.body.getWidth()];
this.activeItem.el.shift({ duration: this.duration, easing: this.easing, opacity: this.opacity, x:(this.activeItemNo < itemInt ? s[0] : s[1] )});
item.el.setY(this.container.body.getY());
item.el.setX((this.activeItemNo < itemInt ? s[1] : s[0] ));
item.el.shift({ duration: this.duration, easing: this.easing, opacity: 1, x:this.container.body.getX()});
}
this.activeItemNo = itemInt;
this.activeItem = item;
this.layout();
}
},


renderAll : function(ct, target){
if(this.deferredRender){
this.renderItem(this.activeItem, undefined, target);
}else{
Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
}
}
});
Ext.Container.LAYOUTS['slide'] = Ext.layout.SlideLayout;

mystix
4 Aug 2008, 9:42 AM
neat. =D>

i tried swapping out TabPanel's CardLayout for a SlideLayout though, and it only worked for the first tab, after which the following error was thrown:


item.el is undefined
...
...
[Break on this error] item.el.setY(this.container.body.getY());


any example / recommended usage?

NeonMonk
4 Aug 2008, 4:33 PM
SlideLayout wasn't originally compatible with deferredRendering..
Code has now been updated so if you try it again mystic it should work fine. :)

mystix
4 Aug 2008, 6:16 PM
alritey. works fine now. good stuff :)

ckr
4 Oct 2008, 1:31 PM
Well Done NeonMonk!

Another silly demo here (http://clan.homelinux.com:8080/ext-samples/cardslide.html).

angelko
6 Oct 2008, 12:19 PM
ckr very nice.

ckr
6 Oct 2008, 7:13 PM
Updated the demo, so that you can select the type of easing to use, and adjust the duration with the slider.

Took me a few to find all the easing types, but then found a post where Animal said, Use console in firebug, type in Ext.lib.Easing.... Then look at the object. I 'll be damned if I can find that post again. Anyway, just an addition to the silly demo.

wm003
7 Oct 2008, 12:07 AM
Very very nice stuff!=P~

ApocalypseCow
7 Oct 2008, 12:39 AM
nice work - what would be pretty neat now is a plugin for it which displays a "paging" toolbar so you can show the user how many cards there are and how far through the sequence they are and allow them to 'jump' to any card in the sequence etc.

fangzhouxing
7 Oct 2008, 1:28 AM
http://slidelayout.freehostia.com/ (live demo) is down?

stever
8 Oct 2008, 2:08 PM
My contribution adds vertical sliding as well. I needed it to vertically shrink to the size of the current item so that became the option resizeHeight. After going several rounds with various easing settings we realized that the easing setting for the animation should not be the same the easing for the opacity change, so we hard coded opacity easing. Results below:



/* http://extjs.com/forum/showthread.php?t=43120 */

Ext.layout.SlideLayout = Ext.extend(Ext.layout.FitLayout, {
deferredRender : true,
renderHidden : false,
easing: 'easeBoth',
duration: 0.5,
opacity: 0.1,
direction:'horizontal',
resizeHeight: false,
setActiveItem : function(itemInt){
if (typeof(itemInt) == 'string') { itemInt = this.container.items.keys.indexOf(itemInt); }
else if (typeof(itemInt) == 'object') { itemInt = this.container.items.items.indexOf(itemInt); }
var item = this.container.getComponent(itemInt);
if(this.activeItem != item){
if(this.activeItem){
if(item && (!item.rendered || !this.isValidParent(item, this.container))){
this.renderItem(item, itemInt, this.container.getLayoutTarget());
item.show();
}
var isHorizontal = this.direction=='horizontal',
direction = this.activeItemNo < itemInt,
y= this.container.body.getY(),
h= this.container.body.getHeight(),
x= this.container.body.getX(),
w= this.container.body.getWidth(),
ai = this.activeItem.el,
newX= isHorizontal ? (direction ? -w:w) : 0,
newY=!isHorizontal ? (direction ? -h:h) : 0;
ai.setOpacity(this.opacity,{duration:this.duration,easing:'easeOut'}).shift({ duration: this.duration, easing: this.easing, x: x+newX, y: y+newY, callback:function(){ai.setVisible(false)}});
item.el.setY(y-newY).setX(x-newX).setVisible(true).shift({ duration: this.duration, easing: this.easing, opacity: 1, x: x, y: y});
if (this.resizeHeight){
(function(){
this.container.body.setHeight(item.el.getHeight(),{duration:this.duration/4});
}).defer(1,this);
}
}
this.activeItemNo = itemInt;
this.activeItem = item;
this.layout();
}
},

renderAll : function(ct, target){
if(this.deferredRender){
this.renderItem(this.activeItem, undefined, target);
}else{
Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
}
(function(){
this.container.body.setHeight(this.activeItem.el.getHeight());
}).defer(1,this);
}
});
Ext.Container.LAYOUTS['slide'] = Ext.layout.SlideLayout;

ckr
8 Oct 2008, 6:17 PM
I was also thinking, that the card layout should actually look like they were stacking one on top of another. Here (http://clan.homelinux.com:8080/ext-samples/cardstack.html) is a variation of that idea, inside a Window. I played around with another where you shifted both X and Y (diagonally).

Maybe combine all these ideas into a new extension, where you can specify the type of slide animation, add maybe a timer (if you wanted to automatically step to the next), and a navbar that automatically adjusts to the number of panels you add (like what ApocalypseCow suggested). :-?

Anyway, fun to play around with. :D

pokerking400
19 Oct 2008, 5:39 AM
I have problem...i am sliding panel with lots of text fields...it messes up screen when it slides ..outside the window....

it is ok for all other things.

pokerking400
19 Oct 2008, 2:55 PM
Sliding layout is not working well when if it is on a window , it workd well if it rendered toa div.

Anyone solved this problem?..

It takes background image and messes up as it slides out when it is on a window.

pokerking400
20 Oct 2008, 1:37 PM
As i see more , it happens only if panels have controls like radio button and text fields..

pokerking400
20 Oct 2008, 2:43 PM
testslide.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
<script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext/ext-all.js"></script>
<script type="text/javascript" src="cardslideexample.js"></script>

<!-- A Localization Script File comes here -->
<script type="text/javascript">
Ext.onReady(testLayout.app.init, testLayout.app);
</script>


<title>Slider Layout Samples</title>
</head>

<body style="background: url( ../../../assets/media/images/welcome/redspring.jpg); ">
<div id="myDiv" style="position:absolute;left:300px;top:200px;">

</div>
</body>

</html>

cardslideexample.js

////////////////////////////////////////////////////////////////////////////////
//
// reference local blank image
//
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';

// create namespace
Ext.namespace('testLayout');

// create application
testLayout.app = function() {
// do NOT access DOM from here; elements don't exist yet

// private variables

// private functions

// public space
return {
// public properties, e.g. strings to translate

// public methods
init: function() {

var easingType = new Array(16);
easingType[0] = "none";
easingType[1] = "easeIn";
easingType[2] = "easeOut";
easingType[3] = "easeBoth";
easingType[4] = "easeInStrong";
easingType[5] = "easeOutStrong";
easingType[6] = "easeBothStrong";
easingType[7] = "elasticIn";
easingType[8] = "elasticOut";
easingType[9] = "elasticBoth";
easingType[10] = "backIn";
easingType[11] = "backOut";
easingType[12] = "backBoth";
easingType[13] = "bounceIn";
easingType[14] = "bounceOut";
easingType[15] = "bounceBoth";

Ext.layout.SlideLayout = Ext.extend(Ext.layout.FitLayout,
{
deferredRender : false,
renderHidden : false,
easing: 'none',
duration: .5,
opacity: 1,

setActiveItem : function(itemInt)
{
if (typeof(itemInt) == 'string')
{
itemInt = this.container.items.keys.indexOf(itemInt);
}
else if (typeof(itemInt) == 'object')
{
itemInt = this.container.items.items.indexOf(itemInt);
}

var item = this.container.getComponent(itemInt);

if(this.activeItem != item)
{
if(this.activeItem)
{
if(item && (!item.rendered || !this.isValidParent(item, this.container)))
{
this.renderItem(item, itemInt, this.container.getLayoutTarget());
item.show();
}

alert(this.container.body.getX() );
var s = [this.container.body.getX() - this.container.body.getWidth(),
this.container.body.getX() + this.container.body.getWidth()];

this.activeItem.el.shift(
{
duration: this.duration,
easing: this.easing,
opacity: this.opacity,
x:(this.activeItemNo < itemInt ? s[0] : s[1] )
});
item.el.setY(this.container.body.getY());
item.el.setX((this.activeItemNo < itemInt ? s[1] : s[0] ));
item.el.shift(
{
duration: this.duration,
easing: this.easing,
opacity: 1,
x:this.container.body.getX()
});
}
this.activeItemNo = itemInt;
this.activeItem = item;
this.layout();
}
},

renderAll : function(ct, target)
{
if(this.deferredRender)
{
this.renderItem(this.activeItem, undefined, target);
}
else
{
Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
}
}
});
Ext.Container.LAYOUTS['slide'] = Ext.layout.SlideLayout;



var rgEasing = new Ext.form.RadioGroup(
{
fieldLabel: 'Sliding Effects',
inputType: 'radio',
columns:2,
vertical: true,
items:
[
{
boxLabel: 'none',
name: 'rb-auto',
inputValue:0,
checked: true,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 0);}}
}
},{
boxLabel: 'easeIn',
name: 'rb-auto',
inputValue:1,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 1);}}
}
},{
boxLabel: 'easeOut',
name: 'rb-auto',
inputValue:2,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 2);}}
}
},{
boxLabel: 'easeBoth',
name: 'rb-auto',
inputValue:3,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 3);}}
}
},{
boxLabel: 'easeInStrong',
name: 'rb-auto',
inputValue:4,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 4);}}
}
},{
boxLabel: 'easeOutStrong',
name: 'rb-auto',
inputValue:5,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 5);}}
}
},{
boxLabel: 'easeBothStrong',
name: 'rb-auto',
inputValue:6,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 6);}}
}
},{
boxLabel: 'elasticIn',
name: 'rb-auto',
inputValue:7,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 7);}}
}
},{
boxLabel: 'elasticOut',
name: 'rb-auto',
inputValue:8,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 8);}}
}
},{
boxLabel: 'elasticBoth',
name: 'rb-auto',
inputValue:9,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 9);}}
}
},{
boxLabel: 'backIn',
name: 'rb-auto',
inputValue:10,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 10);}}
}
},{
boxLabel: 'backOut',
name: 'rb-auto',
inputValue:11,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 11);}}
}
},{
boxLabel: 'backBoth',
name: 'rb-auto',
inputValue:12,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 12);}}
}
},{
boxLabel: 'bounceIn',
name: 'rb-auto',
inputValue:13,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 13);}}
}
},{
boxLabel: 'bounceOut',
name: 'rb-auto',
inputValue:14,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 14);}}
}
},{
boxLabel: 'bounceBoth',
name: 'rb-auto',
inputValue:15,
listeners:
{
'check': function(cbName, checked){if (checked){setEasing(cbName, checked, 15);}}
}
}
]
});
//
//// Card Stuff ///////////////////////////////////////////////////////////////
//
var panCARD0 = new Ext.TabPanel(
{
id:'card-0',
frame: false,
border:false,
activeTab: 0,
bodyStyle: 'background-color: #FFF8Dc',
items: [
{
title: 'Tab 1',
border: false,
frame: false,
bodyStyle: 'background-color: #FFF8Dc;padding:10px 10px 0;',
items: [
new Ext.FormPanel(
{
items:rgEasing
})
]
},{
title: 'Tab 2',
border: false,
frame: false,
bodyStyle: 'background-color: #EEDCC3',
html: 'Another one'
}]
});


sliderTEXT = new Ext.form.Label(
{
x: 10,
y: 50,
text: 'Adjust duration (N*0.1)'
});

sliderUpdate = new Ext.form.TextField(
{
x: 10,
y: 20,
value: 1
});

var panCARD1 = new Ext.Panel(
{
id:'card-1',
hidden: true,
frame: false,
bodyStyle: 'background-color: #EAEAEA',
layout: 'absolute',
items: [
new Ext.Slider({
width: 150,
x: 10,
value: 7,
increment: 1,
minValue: 1,
maxValue: 15,
listeners:
{
'change':function(slide, newValue)
{
sliderUpdate.setValue(newValue);
panCARDS.getLayout().duration=newValue*0.1;
}
}
}),
sliderUpdate,
sliderTEXT
],
border:false
});



var panCARD2 = new Ext.Panel(
{
id:'card-2',
hidden: true,
frame: false,
border:false,
bodyStyle: 'background-color: #FFC77F',
layout:'accordion',
defaults: {
// applied to each contained panel
//bodyStyle: 'padding:15px',
border: false,
frame: false
},
layoutConfig: {
// layout-specific configs go here
titleCollapse: false,
animate: true,
activeOnTop: false
},
items: [{
title: 'Panel 1',
bodyStyle: 'background-color: #003EBA',
html: '<p>Panel content!</p>'
},{
title: 'Panel 2',
bodyStyle: 'background-color: #5D7CBA',
html: '<p>Panel content!</p>'
},{
title: 'Panel 3',
bodyStyle: 'background-color: #FF9000',
html: '<p>Panel content!</p>'
}]
});

var navHandler = function(direction)
{

startIndex = 0;
endIndex = 2;
myItem = Ext.getCmp('panCARDS').getLayout().activeItem;
myItemString = myItem.id.split('-');

myIndex = parseInt(myItemString[1])+direction;

if (myIndex == startIndex){ Ext.getCmp('move-prev').disable();}

if (myIndex > startIndex){ Ext.getCmp('move-prev').enable();}

if (myIndex == endIndex){ Ext.getCmp('move-next').disable();}

if (myIndex < endIndex){ Ext.getCmp('move-next').enable();}

nextItem = 'card-'+myIndex;
panCARDS.getLayout().setActiveItem(nextItem);

}

var panCARDS = new Ext.Panel(
{
title:'Container Panel',
id:'panCARDS',
frame: false,
border:true,
width: 400,
height: 400,
layout:'slide',
layoutConfig:
{
easing: 'none',
duration: 1,
opacity: .1
},
activeItem:0,
bbar:
[
{
id:'move-prev',
text: 'Prev Card',
handler: navHandler.createDelegate(this, [-1]),
disabled:true
},'->',{
id:'move-next',
text:'Next Card',
disabled:false,
handler: navHandler.createDelegate(this, [1])
}
]
});

var win=new Ext.Window(
{
x:300,
y:200,
width:400,
height:400,
layout:'fit',
modal:true,
items:panCARDS
});

win.show();
// panCARDS.render('myDiv');
// Add cards

panCARDS.add(panCARD0);
panCARDS.add(panCARD1);
panCARDS.add(panCARD2);
panCARDS.getLayout().setActiveItem(0);
panCARDS.doLayout();


function setEasing(cbName, isChecked, Value)
{
if (isChecked)
{
panCARDS.getLayout().easing=easingType[Value];
}
}

} // end of init
};
}(); // end of app

// end of file


it is messing up mainly if there is a formpanel inside in one of those cards

pokerking400
21 Oct 2008, 12:59 PM
anyone?
http://farm4.static.flickr.com/3249/2961947757_caaf1de62a_o.jpg

pokerking400
22 Oct 2008, 6:37 AM
anyone?

pokerking400
23 Oct 2008, 3:24 AM
anyone?

Condor
23 Oct 2008, 4:33 AM
It's a nasty bug (http://extjs.com/forum/showthread.php?t=31743) in Firefox.

Quick & dirty workaround:

<style type="text/css">
.ext-gecko .x-form-item {overflow: hidden!important;}
</style>

ckr
24 Oct 2008, 6:21 AM
I changed the demo (http://clan.homelinux.com:8080/ext-samples/cardslide.html) so that it was in a window like yours pokerking400, and I indeed saw your issue.

To resolve, I added:



cls: 'x-panel-animated'


To the window configuration. Seems to have fixed the issue.

pokerking400
27 Oct 2008, 5:01 AM
ckr,

Super!. Thanks!. It works now.

Now i can make that as a base and build other animation.

Thanks to condor also.

:)

pokerking400
27 Oct 2008, 6:07 AM
It works but form layout become columnlayout with textfield become right justified. have to change to left justified or looks too much gap between label and field.

Condor
27 Oct 2008, 7:32 AM
You could use:

cls: 'fix-animation'
with:

.ext-gecko .fix-animation .x-form-item {overflow: hidden!important;}

pokerking400
29 Oct 2008, 7:04 PM
condor,

I am not getting what you are saying . Explain.

pokerking400
29 Oct 2008, 7:10 PM
Ok i added that in css. It fixed...so main css will have that line added to the next build?.

nelius
30 Oct 2008, 1:22 AM
Hi NeonMonk

it would be great if you could add a licence header to the code. BSD new would be ideal ;-)

chrizz_msweb
3 Nov 2008, 12:15 PM
Amazing!! Looks like flash

fangzhouxing
28 Dec 2008, 7:18 PM
I have problem using Ext.layout.SlideLayout in IE7, but ok in FF3.



panel.xf.CorpInfoDisplayPanel = Ext.extend(Ext.Panel, {
initComponent : function() {
Ext.apply(this, {
autoScroll : true,
layout : "slide",
layoutConfig:
{
easing: 'none', //none,easeIn
duration: .2,
opacity: .1
},
activeItem : 0,
items : [{
id : this.myId('checker'),
xtype : "form.xf.CheckerInfoDisplayForm"
}, {
id : this.myId('mainter'),
xtype : "form.xf.MainterInfoDisplayForm"
}, {
id : this.myId('projecter'),
xtype : "form.xf.ProjecterInfoDisplayForm"
}, {
id : this.myId('producer'),
xtype : "form.xf.ProducerInfoDisplayForm"
}, {
id : this.myId('advisor'),
xtype : "form.xf.AdvisorInfoDisplayForm"
}, {
id : this.myId('seller'),
xtype : "form.xf.SellerInfoDisplayForm"
}]
})
panel.xf.CorpInfoDisplayPanel.superclass.initComponent.call(this)
}

Condor
28 Dec 2008, 10:37 PM
I have problem using Ext.layout.SlideLayout in IE7, but ok in FF3.

1. What exactly is the problem? Your code contains custom components, so I can't use it to test anything.
2. A layout:'slide' can't be autoScroll:true (or did you want defaults:{autoScroll:true}?).
3. A layout:'slide' with easing:'none' is the same as a layout:'card', so why would you want to use it.

fangzhouxing
29 Dec 2008, 10:18 PM
@Condor,thank you for reply!

My code in FF3 has all the effect what I need.

1)My form.xf.CheckerInfoDisplayForm is a custome component that show plain html table, in IE7 the form is not display sometimes or leave the display area blank!

2)But why in FF3 it is ok?

3)A layout:'slide' with easing:'none' still has the slide effect!

ckr
30 Dec 2008, 9:30 AM
So are you saying your form does not show up? The slide layout is working but your form is not showing up in IE7?

NeonMonk
1 Jan 2009, 9:46 PM
(Belated reply!)

Anything I release on the forums is always under the WTFPL. (http://sam.zoy.org/wtfpl/)

Keeping in mind the licensing issues with Ext public extensions of course. But if anyone is going to be knocking at your door with the copyright police it won't be me.

Peace.

NeonMonk
1 Jan 2009, 9:51 PM
Well Done NeonMonk!

Another silly demo here (http://clan.homelinux.com:8080/ext-samples/cardslide.html).

That was awesome, thanks ckr. Demonstrated it really well. :)

jasonb885
4 Feb 2009, 11:02 AM
Works in Firefox for me, but Opera 9.62 animates the outgoing panel and the inbound one never appears.



layoutConfig:{
renderHidden:true,
deferredRender:false
}


Without renderHidden, a TreePanel nested within fails.

TopKatz
13 Jul 2009, 10:29 AM
Im playing with this in 3.0.0, and after you slide a card in then out, if you resize the browser the hidden panel is displayed a little.

jerrybrown5
29 Sep 2009, 9:07 PM
This is a nice extension but the latest version of Opera isn't supported. It is an Opera float/clear bug/issue. The subsequent cards are being stacked.

Here is the quick, dirty, simple downgrade fix.



...
if (this.activeItem != item) {
if (this.activeItem) {

if (this.compatMode || Ext.isOpera){ //opera downgrade fix
this.activeItem.el.setStyle('display','none');
item.el.setStyle('display','block');
}else{
...
}
...

lopezdonaque
8 Mar 2012, 12:05 PM
Is this extension compatible Ext JS 3?