PDA

View Full Version : tree.ColumnTree column width declaration using %



salaccosmin
15 Oct 2009, 6:00 AM
Hi
I have a ‘Ext.ux.tree.ColumnTree’ with a declared width = ‘100%’. Inside, I define 3 columns and I would like to declare width for this columns in ‘%’( something like ‘30%’,’30%’ and ‘40%’). If I use ‘%’ in width declaration, it won’t work (both IE and FF) and I am forced to declare width in px.
Do you have any idée for my problem?
Thanks

emily
22 Oct 2009, 3:01 AM
Hiya,

I now have the same requirement (column widths as percentages), so I am going to have a look at the code for grids and see how they do it.

If I come up with a good solution I will post it back.

Let me know if you have already done this though :)

Em

silve69
4 Nov 2009, 2:57 PM
Hello friends,

Did you find some solution???
Bets regards,

Silver

emily
5 Nov 2009, 3:24 AM
Kinda, but it isn't very nice. I have done it so that the ColumnTree can be set to fill its container. I set it up so that you have to put an 'autoExpand' config attribute in, then it takes whatever dimensions you have given your columns and keeps their ratio. This means you can give them in %, but you can also use px and not have it expand.

Basically getting the header to resize was ok, but for the tree nodes, I had to edit renderElements in ColumnNodeUI to give them another class 'depth-' + i where i is the column id, then go through and resize the element widths.

This is my resize callback:


'resize': {
fn: function(ob, adjWidth, adjHeight, rawWidth, rawHeight) {
if (adjWidth && adjHeight) {
if (this.autoExpand) {
this.setSize(ob.getInnerWidth());
this.headers.setWidth(ob.getInnerWidth());
this.innerCt.setWidth(ob.getInnerWidth() - 19);
var totalWidth = 0;
for (var i = 0; i < this.columns.length; i++) {
totalWidth += this.columns[i].width;
}
var availWidth = adjWidth;
var multiplier = (availWidth - 19) / totalWidth;
for (var i = 0; i < this.columns.length; i++) {
this.columns[i].width = this.columns[i].width * multiplier;
}
var headerCols = this.headers.dom.children;
for (var i =0; i < headerCols.length; i++) {
if (i < this.columns.length) {
if (i == 0) {
headerCols[i].style.width = (this.columns[i].width - 2 * this.borderWidth) + 'px';
} else {
headerCols[i].style.width = (this.columns[i].width - this.borderWidth) + 'px';
}
}
}
if (this.root.childNodes.length > 0) {
var cols = Ext.select('div.x-tree-col').elements;
var depth_re = /depth-(\d+)/;
for (var data_i = 0; data_i < cols.length; data_i++) {
if (cols[data_i].className) {
match = depth_re.exec(cols[data_i].className)
if (!!match) {
var i = match[1];
if (i == '0') {
cols[data_i].style.width = this.columns[i].width - 2 * this.borderWidth + 'px';
} else {
cols[data_i].style.width = this.columns[i].width - this.borderWidth + 'px';
}
}
}
}
}
}
}
}
}

I don't think it is a good solution which is why I hadn't posted it back yet.

What I think ought to happen is that you create CSS classes ('depth-' +coulmn_index) when you are creating the elements, then change the width attribute in those css classes. I don't think I know how to do this (although I haven't really researched it).

Anyone got any better ideas?

dommellenny
5 Nov 2009, 3:52 AM
i haven't worked it out myself
but it should be easy enough by using anchorlayout


var viewport = new Ext.Viewport({
layout:'anchor',
anchorSize: {width:800, height:600},
items:[{
title:'Item 1',
html:'Content 1',
width:800,
anchor:'right 20%'
},{
title:'Item 2',
html:'Content 2',
width:300,
anchor:'50% 30%'
},{
title:'Item 3',
html:'Content 3',
width:600,
anchor:'-100 50%'
}]
});

emily
5 Nov 2009, 3:56 AM
i haven't worked it out myself
but it should be easy enough by using anchorlayout


var viewport = new Ext.Viewport({
layout:'anchor',
anchorSize: {width:800, height:600},
items:[{
title:'Item 1',
html:'Content 1',
width:800,
anchor:'right 20%'
},{
title:'Item 2',
html:'Content 2',
width:300,
anchor:'50% 30%'
},{
title:'Item 3',
html:'Content 3',
width:600,
anchor:'-100 50%'
}]
});

Really? I don't think I understand how you would do this. Please can you provide a bit of context?

dommellenny
5 Nov 2009, 4:36 AM
it should work fine when you give your columntree the layout anchor
and then define for eacht column the anchor like below

anchor (http://10.100.1.109/Extjs/docs/source/AnchorLayout.html#cfg-Ext.layout.AnchorLayout-anchor) : String

This configuation option is to be applied to child items of a container managed by this layout (ie. configured with layout:'anchor').



This value is what tells the layout how an item should be anchored to the container. items added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%'). The following types of anchor values are supported:

Percentage : Any value between 1 and 100, expressed as a percentage. The first anchor is the percentage width that the item should take up within the container, and the second is the percentage height. For example:// two values specified
anchor: '100% 50%'
// render item complete width of the container and
// 1/2 height of the container// one value specified
anchor: '100%'
// the width value; the height will default to auto
Offsets : Any positive or negative integer value. This is a raw adjustment where the first anchor is the offset from the right edge of the container, and the second is the offset from the bottom edge. For example:
// two values specified
anchor: '-50 -100'
// render item the complete width of the container
// minus 50 pixels and
// the complete height minus 100 pixels.
// one value specified
anchor: '-50'
// anchor value is assumed to be the right offset value
// bottom offset will default to 0
Sides : Valid values are 'right' (or 'r') and 'bottom' (or 'b'). Either the container must have a fixed size or an anchorSize config value defined at render time in order for these to have any effect.
Mixed : Anchor values can also be mixed as needed. For example, to render the width offset from the container right edge by 50 pixels and 75% of the container's height use: anchor: '-50 75%'

emily
5 Nov 2009, 6:27 AM
it should work fine when you give your columntree the layout anchor
and then define for eacht column the anchor like below

anchor (http://10.100.1.109/Extjs/docs/source/AnchorLayout.html#cfg-Ext.layout.AnchorLayout-anchor) : String

This configuation option is to be applied to child items of a container managed by this layout (ie. configured with layout:'anchor').



This value is what tells the layout how an item should be anchored to the container. items added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%'). The following types of anchor values are supported:

Percentage : Any value between 1 and 100, expressed as a percentage. The first anchor is the percentage width that the item should take up within the container, and the second is the percentage height. For example:// two values specified
anchor: '100% 50%'
// render item complete width of the container and
// 1/2 height of the container// one value specified
anchor: '100%'
// the width value; the height will default to auto
Offsets : Any positive or negative integer value. This is a raw adjustment where the first anchor is the offset from the right edge of the container, and the second is the offset from the bottom edge. For example:
// two values specified
anchor: '-50 -100'
// render item the complete width of the container
// minus 50 pixels and
// the complete height minus 100 pixels.
// one value specified
anchor: '-50'
// anchor value is assumed to be the right offset value
// bottom offset will default to 0
Sides : Valid values are 'right' (or 'r') and 'bottom' (or 'b'). Either the container must have a fixed size or an anchorSize config value defined at render time in order for these to have any effect.
Mixed : Anchor values can also be mixed as needed. For example, to render the width offset from the container right edge by 50 pixels and 75% of the container's height use: anchor: '-50 75%'




I will have a play, but I really don't think this will work at all. It is a tree with columns, not a grid.

dommellenny
5 Nov 2009, 6:50 AM
it will work fine because anchor can be applied to every item as long as the component where this item is on has been extended by container,
just give the container
layout :'anchor' and you will be on your way

emily
5 Nov 2009, 6:55 AM
it will work fine because anchor can be applied to every item as long as the component where this item is on has been extended by container,
just give the container
layout :'anchor' and you will be on your way

So what are you suggesting goes in the items of the ColumnTree?

Do you want to give us some example code?

dommellenny
5 Nov 2009, 7:41 AM
this should do the trick...
haven't tested it but should work


var tree = new Ext.ux.tree.ColumnTree({
layout:'anchor',
anchorSize: {width:800, height:600},
rootVisible:false,
autoScroll:true,
title: 'Example Tasks',
renderTo: Ext.getBody(),
columns:[{
header:'Task',
width:800,
dataIndex:'task',
anchor:'right 20%'
},{
header:'Duration',
dataIndex:'duration',
width:300,
anchor:'50% 30%'

},{
header:'Assigned To',
dataIndex:'user',
width:600,
anchor:'-100 50%'
}],
loader: new Ext.tree.TreeLoader({
dataUrl:'column-data.json',
uiProviders:{
'col': Ext.ux.tree.ColumnNodeUI
}
}),
root: new Ext.tree.AsyncTreeNode({
text:'Tasks'
})
});

emily
6 Nov 2009, 6:43 AM
Hi,

So I couldn't get dommellenny's example working (I am not sure anchor layout will work in this case because it is a tree which is in one 'item', not an item per 'column'), but I have redone my original fix using CSS which is much better than looping through and changing the style attributes for each node:

So, the Ext.ux.tree.ColumnNodeUI.renderElements method you want to override to stop it from setting the 'style="width: blah;"' for the columns, and add in a 'depth-' + i class (where i = column index):



renderElements : function(n, a, targetNode, bulkRender) {
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
var t = n.getOwnerTree();
var cols = t.columns;
var bw = t.borderWidth;
var c = cols[0];
var buf = [
'<li class="x-tree-node"><div ext:tree-node-id="', n.id, '" class="x-tree-node-el x-tree-node-leaf ', a.cls, '">',
'<div class="x-tree-col depth-0', (c.cls ? ' ' + c.cls : ''), '">',
'<span class="x-tree-node-indent">', this.indentMarkup, "</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon', (a.icon ? " x-tree-node-inline-icon" : ""), (a.iconCls ? " " + a.iconCls : ""), '" unselectable="on">',
'<a hidefocus="on" class="x-tree-node-anchor" href="', a.href ? a.href : "#", '" tabIndex="1" ',
a.hrefTarget ? ' target="' + a.hrefTarget + '"' : "", '>',
'<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]), "</span></a>",
"</div>"];
for (var i = 1, len = cols.length; i < len; i++) {
c = cols[i];
buf.push('<div class="x-tree-col depth-', i, (c.cls ? ' ' + c.cls : ''), '">',
'<div class="x-tree-col-text">', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]), "</div>",
"</div>");
}
buf.push(
'<div class="x-clear"></div></div>',
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
"</li>");

if (bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()) {
this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
n.nextSibling.ui.getEl(), buf.join(""));
} else {
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
}

this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1];
var cs = this.elNode.firstChild.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
this.iconNode = cs[2];
this.anchor = cs[3];
this.textNode = cs[3].firstChild;
}


Then you want to override Ext.ux.tree.ColumnTree.onRender to create a stylesheet on the fly with the appropriate widths (the same ratio as those specified in columns):



onRender : function() {
Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
this.headers = this.header.createChild({cls:'x-tree-headers'});
var cols = this.columns, c;
var totalWidth = 0;
var scrollOffset = 19;
Ext.util.CSS.removeStyleSheet('columns');
var col_css = ""
for (var i = 0, len = cols.length; i < len; i++){
c = cols[i];
totalWidth += c.width;
if (i == 0) {
col_css += '.depth-' + i + ' {width: ' + (this.columns[i].width - 2 * this.borderWidth) + 'px;} ';
} else {
col_css += '.depth-' + i + ' {width: ' + (this.columns[i].width - this.borderWidth) + 'px;} ';
}
this.headers.createChild({
cls:'x-tree-hd depth-' + i + (c.cls ? ' ' + c.cls + '-hd' : ''),
cn: {
cls:'x-tree-hd-text',
html: c.header
}
});
}
Ext.util.CSS.createStyleSheet(col_css, 'columns');
Ext.util.CSS.refreshCache();
this.headers.createChild({cls: 'x-clear'});
// prevent floats from wrapping when clipped
this.headers.setWidth(totalWidth + scrollOffset);
this.innerCt.setWidth(totalWidth);
}


Then you want to add a resize listener to the the Ext.ux.tree.ColumnTree, with a callback that optionally expands widths in ratio to fill the container by changing the CSS on the fly:



'resize': {
fn: function(ob, adjWidth, adjHeight, rawWidth, rawHeight) {
if (adjWidth && adjHeight) {
if (this.autoExpand) {
this.setSize(ob.getInnerWidth());
this.headers.setWidth(ob.getInnerWidth());
this.innerCt.setWidth(ob.getInnerWidth() - 19);
var totalWidth = 0;
for (var i = 0; i < this.columns.length; i++) {
totalWidth += this.columns[i].width;
}
var availWidth = adjWidth;
var multiplier = (availWidth - 19) / totalWidth;
var col_css = ""
Ext.util.CSS.removeStyleSheet('columns');
for (var i = 0; i < this.columns.length; i++) {
this.columns[i].width = this.columns[i].width * multiplier;
if (i == 0) {
col_css += '.depth-' + i + ' {width: ' + (this.columns[i].width - 2 * this.borderWidth) + 'px;} ';
} else {
col_css += '.depth-' + i + ' {width: ' + (this.columns[i].width - this.borderWidth) + 'px;} ';
}
}
Ext.util.CSS.createStyleSheet(col_css, 'columns');
Ext.util.CSS.refreshCache();
}
}
}
}


I think this is a better way than my previous post.

I haven't actually altered the ColumNodeUI.js script, just extended it in my app. If you think these changes are worth going into the ColumnNodeUI ux, please shout and I wil attach an updated version of this user extension.

Em

kotovsky
14 Nov 2009, 9:41 AM
Hi, can'll show how to make
tree.ColumnTree fit on all area
thanks

wm003
8 Jan 2010, 2:34 AM
I think this is a better way than my previous post.

Thanks for this great idea. i also used


Ext.util.CSS.updateRule('.depth-' + i, "width", this.columns[i].width+"px")
instead of recreating a new stylesheet, because the link tag is inserted on the top of the domtree and on huge domtrees (like in my case) it leaks (at least on IE as always...) performance.