View Poll Results: Was this helpful?
- Voters
- 320. You may not vote on this poll
-
Yes - Very Much
247 77.19% -
Yes - Had to tweak it
43 13.44% -
No - Maybe
14 4.38% -
Not at All!!!
16 5.00%
-
20 Dec 2007 1:42 AM #1
Grid Summary Plugin With Fixed Summary Row
Grid Summary Plugin With Fixed Summary Row
Code:[ hijacked by @mystix -- pardon me ;) ] for anyone who stumbles across this thread -- just fyi, the latest code can always be found in post #9. kudos still goes to @tinker for coming up with the initial code. --- mystix
Hi!
Some time back I found a "GroupSummary" plugin here and modified it to my need to have a table/grid level summary. I found another similar plugin here. but it does not seem to fix the summary row at the bottom. Since I had to fight a lot to get it working, thought just thought it my be helpful to make a post.
Code:Ext.grid.GridSummary = function(config){ Ext.apply(this, config); }; Ext.extend(Ext.grid.GridSummary, Ext.util.Observable, { init : function(grid){ this.grid = grid; this.cm = grid.getColumnModel(); this.view = grid.getView(); var v = this.view; v.layout = this.layout.createDelegate(this); v.afterMethod('refresh', this.refreshSummary, this); v.afterMethod('refreshRow', this.refreshSummary, this); v.afterMethod('onColumnWidthUpdated', this.doWidth, this); v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this); v.afterMethod('onColumnHiddenUpdated', this.doHidden, this); v.afterMethod('onUpdate', this.refreshSummary, this); v.afterMethod('onRemove', this.refreshSummary, this); if(!this.rowTpl){ this.rowTpl = new Ext.Template( '<div class="x-grid3-summary-row" style="{tstyle}">', '<table class="x-grid3-summary-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">', '<tbody><tr>{cells}</tr></tbody>', '</table></div>' ); this.rowTpl.disableFormats = true; } this.rowTpl.compile(); if(!this.cellTpl){ this.cellTpl = new Ext.Template( '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}">', '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on">{value}</div>', "</td>" ); this.cellTpl.disableFormats = true; } this.cellTpl.compile(); }, renderSummary : function(o, cs){ cs = cs || this.view.getColumnData(); var cfg = this.cm.config; var buf = [], c, p = {}, cf, last = cs.length-1; for(var i = 0, len = cs.length; i < len; i++){ c = cs[i]; cf = cfg[i]; p.id = c.id; p.style = c.style; p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : ''); if(cf.summaryType || cf.summaryRenderer){ p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o); }else{ p.value = ''; } if(p.value == undefined || p.value === "") p.value = "*"; buf[buf.length] = this.cellTpl.apply(p); } return this.rowTpl.apply({ tstyle: 'width:'+this.view.getTotalWidth()+';', cells: buf.join('') }); }, calculate : function(rs, cs){ var data = {}, r, c, cfg = this.cm.config, cf; for(var j = 0, jlen = rs.length; j < jlen; j++){ r = rs[j]; for(var i = 0, len = cs.length; i < len; i++){ c = cs[i]; cf = cfg[i]; if(cf && cf.summaryType){ data[c.name] = Ext.grid.GridSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data); } } } return data; }, layout : function(){ if (!this.view.summary) this.view.summary = Ext.DomHelper.insertAfter(this.view.mainBody.dom.parentNode, {tag:'div'}, true); if(!this.view.mainBody){ return; } var g = this.grid; var c = g.getGridEl(), cm = this.cm, expandCol = g.autoExpandColumn, gv = this.view; var csize = c.getSize(true); var vw = csize.width; if(!vw || !csize.height){ // display: none? return; } if(g.autoHeight){ this.view.scroller.dom.style.overflow = 'visible'; }else{ var smHeight = this.view.summary.getHeight(); var hdHeight = this.view.mainHd.getHeight(); this.view.el.setSize(csize.width, csize.height + smHeight); var vh = csize.height - (hdHeight) - (smHeight); this.view.scroller.setSize(vw, vh); this.view.innerHd.style.width = (vw)+'px'; } if(this.view.forceFit){ if(this.view.lastViewWidth != vw){ this.view.fitColumns(false, false); this.view.lastViewWidth = vw; } }else { this.view.autoExpand(); } this.view.onLayout(vw, vh); }, doWidth : function(col, w, tw){ var gs = this.view.getRows(), s; for(var i = 0, len = gs.length; i < len; i++){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; s.firstChild.rows[0].childNodes[col].style.width = w; } }, doAllWidths : function(ws, tw){ var gs = this.view.getRows(), s, cells, wlen = ws.length; for(var i = 0, len = gs.length; i < len; i++){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; cells = s.firstChild.rows[0].childNodes; for(var j = 0; j < wlen; j++){ cells[j].style.width = ws[j]; } } }, doHidden : function(col, hidden, tw){ var gs = this.view.getRows(), s, display = hidden ? 'none' : ''; for(var i = 0, len = gs.length; i < len; i++){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; s.firstChild.rows[0].childNodes[col].style.display = display; } }, // Note: requires that all (or the first) record in the // group share the same group value. Returns false if the group // could not be found. refreshSummary : function(){ var g = this.grid, cm = g.colModel, ds = g.store, stripe = g.stripeRows; var colCount = cm.getColumnCount(); if(ds.getCount() < 1){ return ""; } var cs = this.view.getColumnData(); var startRow = startRow || 0; var endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow; // records to render var rs = ds.getRange(); var buf = []; var data = this.calculate(rs, cs); buf.push('</div>', this.renderSummary({data: data}, cs), '</div>'); this.view.summary.update(buf.join('')); this.view.layout(); }, getSummaryNode : function(){ return this.view.summary }, showSummaryMsg : function(groupValue, msg){ var gid = this.view.getGroupId(groupValue); var node = this.getSummaryNode(gid); if(node){ node.innerHTML = '<div class="x-grid3-summary-msg">' + msg + '</div>'; } } }); Ext.grid.GridSummary.Calculations = { 'sum' : function(v, record, field){ return v + (record.data[field]||0); }, 'count' : function(v, record, field, data){ return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1); }, 'max' : function(v, record, field, data){ var v = record.data[field]; var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max']; return v > max ? (data[field+'max'] = v) : max; }, 'min' : function(v, record, field, data){ var v = record.data[field]; var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min']; return v < min ? (data[field+'min'] = v) : min; }, 'average' : function(v, record, field, data){ var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1); var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0))); return t === 0 ? 0 : t / c; } } Ext.grid.HybridGridSummary = Ext.extend(Ext.grid.GridSummary, { calculate : function(rs, cs){ var gcol = this.view.getGroupField(); var gvalue = rs[0].data[gcol]; var gdata = this.getSummaryData(gvalue); return gdata || Ext.grid.HybridGridSummary.superclass.calculate.call(this, rs, cs); }, updateSummaryData : function(groupValue, data, skipRefresh){ var json = this.grid.store.reader.jsonData; if(!json.summaryData){ json.summaryData = {}; } json.summaryData[groupValue] = data; if(!skipRefresh){ this.refreshSummary(groupValue); } }, getSummaryData : function(groupValue){ var json = this.grid.store.reader.jsonData; if(json && json.summaryData){ return json.summaryData[groupValue]; } return null; } });
-
21 Dec 2007 12:57 AM #2
It would be nice to have some screenshots attached? Or maybe a live example? Thanks.
"It is better to be young, pretty and rich instead old, ugly and poor."
(c) Alan Ford.
-
26 Dec 2007 5:09 PM #3
there's something wrong when you resize a column!
-
10 Jan 2008 10:48 AM #4
Examples for use would be nice too.
-
11 Jan 2008 8:19 AM #5
This looks and works almost perfectly thank you.
There are three problems and one feature that would make this summary perfect.- Resizing a header column does not change the positions of the summary row, this does work correctly in the other version that you acknowledge, however I much prefer the locked bottom position you have created.
- My summary information only seems to join numbers together for example 10,000 + 15,500 + 14,500 displays as 10,00015,50014,500 rather than 40,000 - this is most likely a stupid error or misunderstanding on my part but a pointer would be excellent. [Fixed this myself (my own stupid error) - should have set the data type for each xml column]
- When refreshing the contents of the grid the summary updates correctly using new information, however if the grid results are empty the summary shows the last set of summary information.
- New feature - Could the summary hidden/shown as a setting in JS so it could optionally be shown using a button event etc.
Again - great work.
MalcolmLast edited by mwh154; 14 Jan 2008 at 4:59 AM. Reason: First a question myself
-
14 Jan 2008 9:21 PM #6
Works great but I had to tweak the calculations in order for them to update properly
Code:Ext.grid.GridSummary.Calculations = { 'sum' : function(v, record, field){ //originally: return v + (record.data[field]||0); return parseFloat(v) + parseFloat(record.data[field]); }, 'average' : function(v, record, field, data){ var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1); var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0))); //originally: t === 0 ? 0 : t / c; return t === 0 ? 0 : parseFloat(t) / parseFloat(c); } }
-
17 Jan 2008 10:38 AM #7
how do I use this? It sounds perfect!
how do I use this? It sounds perfect!
It sounds like this is exactly what I want! But I'm not sure how to implement it.
Caveat: I'm a beginner, and I haven't been able to find an example of anyone using this within the forums.
I added it as a plugin in the form:
And I specified a summaryType in the columnModel (though I wasn't sure if I needed to use it as a renderer):Code:var grid_TargetData_tab1 = new Ext.grid.GridPanel({ ds: ds_TargetData_tab1, cm: tab1_colModel, height:'auto', width:950, anchor:'100% 100%', title:'Scores by Component', plugins: new Ext.grid.GridSummary(), stripeRows: 'true' });
What else do I need to do? Heck, am I even correct up to this point? All I know is that I'm getting no Firebug errors, and no summary row.Code:var tab1_colModel = new Ext.grid.ColumnModel([ {id:'label', header: "PACE Components", width: 200, sortable: true, dataIndex: 'label'}, {header: "Weight", width: 100, sortable: true, dataIndex: 'Weight', summaryType: 'sum'}, {header: "Overall Score", width: 100, renderer: pctChange, sortable: true, dataIndex: 'Overall', summaryType: 'average'}, {header: "Initial Call", width: 100, renderer: pctChange, sortable: true, dataIndex: 'call1', summaryType: 'average'}, {header: "Secondary Call", width: 100, renderer: pctChange, sortable: true, dataIndex: 'call2', summaryType: 'average'}, {header: "NYC_NYJ Avg", width: 100, renderer: pctChange, sortable: true, dataIndex: 'group19', summaryType: 'average'}, {header: "East Avg", width: 100, renderer: pctChange, sortable: true, dataIndex: 'group17', summaryType: 'average'}, {header: "USA Avg", width: 100, renderer: pctChange, sortable: true, dataIndex: 'group15', summaryType: 'average'} ]);
Thank you for any help you can give!
Best wishes,
Cat
-
17 Jan 2008 2:28 PM #8
interesting!
interesting!
Ok, it seems my code above *is* making the summary line show up - IF I sort a column. When the page first loads, the summary row does not display. Once I sort a column, the grid re-renders and displays the summary row. I think I can work with the rendering to figure this out.
Another thing I already figured out: unless I set a height on my grid, the summary row moves down within the tab as I sort the grid. It's hard to describe, but it is as if it floats further and further down the tab.
So, tips for others:
* be sure to have a defined height on your grid
* if you don't see it at first, try sorting the grid or re-rendering it in some way
* add math.round() to the average function
-
18 Jan 2008 5:45 AM #9
alritey, i needed to use this so i took the liberty of fixing the various bugs in this plugin.
i made the following changes:- namespaced the plugin to Ext.ux.grid.GridSummary
- removed the unused HybridGridSummary
- added a drop-in example (adapted from array-grid.js in \examples\grid)
- added css styles (taken from summary.css found in \examples\grid)
- added synchronised scrolling for the GridSummary row
- fixed various copy-paste bugs (from the GroupSummary plugin)

- fixed other rendering bugs

p.s. kudos to @tinker for an inspiring start
Plugin js:
Required css:Code:// see zip file
[update 1]Code:/* see zip file */
added toggleSummary() method
[update 2]
updated example
[update 3]
fixed bug in refreshSummary when no records are in the Store
[update 4]- fixed toggleSummary bugs
- updated example html (added more custom summary renderer examples)
- overrode Ext.util.format.usMoney to fix $NaN.00 appearing in example when no Records exist
[update 5]
refresh GridSummary row when grid's store is updated
[update 6]- added css fix to enable scrolling in IE6 (thanks to @timotti)
- fixed onLayout so it doesn't choke when height:'auto' (thanks to @thomasf)
- fixed calculate so NaN doesn't appear when there are no Records in the Grid's Store (thanks to @rtconner)
[update 7]
fixed typo in calculate method
[update 8]- added {attr} to cellTpl config (thanks to @lukas.wappler)
- fixed 2 tiny closure bugs (i think
) in the calculate and renderSummary methods - added summary row tooltips to the included example
[update 9]- fixed + refactored calculate method
- added rowIndex to parameter list of methods in Ext.ux.grid.GridSummary.Calculations
- refactored messy methods in Ext.ux.grid.GridSummary.Calculations
- updated example
[update 10]
minor update -- scoped unintentional global variable "cells"
[update 11]- updated included example to demonstrate Record insertion
- minor code cleanup
Last edited by mystix; 2 Mar 2010 at 12:09 PM. Reason: update
Sencha Docs / Ext 3.x - ( Docs | Examples )
Learning Center / Saki's Examples (for 2.x) / HOWTO - ( Report Bugs | Post Proper Code )
-
21 Jan 2008 1:09 AM #10
thankx all!
thankx all!
hey all!
thanks a lot for your responses... i have been away quite a long time and havnt been able to respond to any queries! sorry about that!
i am happy that this post has helped and inspired many - have got more stuff in my mind that i wanna put here! and pretty soon!
thanks!


Reply With Quote