Ext.onReady(function(){ Ext.QuickTips.init(); var Employee = Ext.data.Record.create([{ name: 'name', type: 'string' }, { name: 'email', type: 'string' }, { name: 'start', type: 'date', dateFormat: 'n/j/Y' },{ name: 'salary', type: 'float' },{ name: 'active', type: 'bool' }]); // hideous function to generate employee data var genData = function(){ var data = []; var s = new Date(2007, 0, 1); var now = new Date(), i = -1; while(s.getTime() < now.getTime()){ var ecount = Ext.ux.getRandomInt(0, 3); for(var i = 0; i < ecount; i++){ var name = Ext.ux.generateName(); data.push({ start : s.clearTime(true).add(Date.DAY, Ext.ux.getRandomInt(0, 27)), name : name, email: name.toLowerCase().replace(' ', '.') + '@exttest.com', active: true, salary: Math.floor(Ext.ux.getRandomInt(35000, 85000)/1000)*1000 }); } s = s.add(Date.MONTH, 1); } return data; } var store = new Ext.data.GroupingStore({ reader: new Ext.data.JsonReader({fields: Employee}), data: genData(), sortInfo: {field: 'start', direction: 'ASC'} }); var editor = new Ext.ux.grid.RowEditor({ saveText: 'Update' }); var grid = new Ext.grid.GridPanel({ store: store, width: 600, region:'center', margins: '0 5 5 5', autoExpandColumn: 'name', plugins: [editor], view: new Ext.grid.GroupingView({ markDirty: false }), tbar: [{ iconCls: 'icon-user-add', text: 'Add Employee', handler: function(){ var e = new Employee({ name: 'New Guy', email: 'new@exttest.com', start: (new Date()).clearTime(), salary: 50000, active: true }); editor.stopEditing(); store.insert(0, e); grid.getView().refresh(); grid.getSelectionModel().selectRow(0); editor.startEditing(0); } },{ ref: '../removeBtn', iconCls: 'icon-user-delete', text: 'Remove Employee', disabled: true, handler: function(){ editor.stopEditing(); var s = grid.getSelectionModel().getSelections(); for(var i = 0, r; r = s[i]; i++){ store.remove(r); } } }], columns: [ new Ext.grid.RowNumberer(), { id: 'name', header: 'First Name', dataIndex: 'name', width: 220, sortable: true, editor: { xtype: 'textfield', allowBlank: false } },{ header: 'Email', dataIndex: 'email', width: 150, sortable: true, editor: { xtype: 'textfield', allowBlank: false, vtype: 'email' } },{ xtype: 'datecolumn', header: 'Start Date', dataIndex: 'start', format: 'm/d/Y', width: 100, sortable: true, groupRenderer: Ext.util.Format.dateRenderer('M y'), editor: { xtype: 'datefield', allowBlank: false, minValue: '01/01/2006', minText: 'Can\'t have a start date before the company existed!', maxValue: (new Date()).format('m/d/Y') } },{ xtype: 'numbercolumn', header: 'Salary', dataIndex: 'salary', format: '$0,0.00', width: 100, sortable: true, editor: { xtype: 'numberfield', allowBlank: false, minValue: 1, maxValue: 150000 } },{ xtype: 'booleancolumn', header: 'Active', dataIndex: 'active', align: 'center', width: 50, trueText: 'Yes', falseText: 'No', editor: { xtype: 'checkbox' } }] }); var cstore = new Ext.data.JsonStore({ fields:['month', 'employees', 'salary'], data:[], refreshData: function(){ var o = {}, data = []; var s = new Date(2007, 0, 1); var now = new Date(), i = -1; while(s.getTime() < now.getTime()){ var m = { month: s.format('M y'), employees: 0, salary: 0, index: ++i } data.push(m); o[m.month] = m; s = s.add(Date.MONTH, 1); } store.each(function(r){ var m = o[r.data.start.format('M y')]; for(var i = m.index, mo; mo = data[i]; i++){ mo.employees += 10000; mo.salary += r.data.salary; } }); this.loadData(data); } }); cstore.refreshData(); store.on('add', cstore.refreshData, cstore); store.on('remove', cstore.refreshData, cstore); store.on('update', cstore.refreshData, cstore); var chart = new Ext.Panel({ width:600, height:200, layout:'fit', margins: '5 5 0', region: 'north', split: true, minHeight: 100, maxHeight: 500, items: { xtype: 'columnchart', store: cstore, url:'../../resources/charts.swf', xField: 'month', yAxis: new Ext.chart.NumericAxis({ displayName: 'Employees', labelRenderer : Ext.util.Format.numberRenderer('0,0') }), tipRenderer : function(chart, record, index, series){ if(series.yField == 'salary'){ return Ext.util.Format.number(record.data.salary, '$0,0') + ' total salary in ' + record.data.month; }else{ return Ext.util.Format.number(Math.floor(record.data.employees/10000), '0,0') + ' total employees in ' + record.data.month; } }, // style chart so it looks pretty chartStyle: { padding: 10, animationEnabled: true, font: { name: 'Tahoma', color: 0x444444, size: 11 }, dataTip: { padding: 5, border: { color: 0x99bbe8, size:1 }, background: { color: 0xDAE7F6, alpha: .9 }, font: { name: 'Tahoma', color: 0x15428B, size: 10, bold: true } }, xAxis: { color: 0x69aBc8, majorTicks: {color: 0x69aBc8, length: 4}, minorTicks: {color: 0x69aBc8, length: 2}, majorGridLines: {size: 1, color: 0xeeeeee} }, yAxis: { color: 0x69aBc8, majorTicks: {color: 0x69aBc8, length: 4}, minorTicks: {color: 0x69aBc8, length: 2}, majorGridLines: {size: 1, color: 0xdfe8f6} } }, series: [{ type: 'column', displayName: 'Salary', yField: 'salary', style: { image:'../chart/bar.gif', mode: 'stretch', color:0x99BBE8 } }] } }); var layout = new Ext.Panel({ title: 'Employee Salary by Month', layout: 'border', layoutConfig: { columns: 1 }, width:600, height: 600, items: [chart, grid] }); layout.render(Ext.getBody()); grid.getSelectionModel().on('selectionchange', function(sm){ grid.removeBtn.setDisabled(sm.getCount() < 1); }); });