<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The source code</title> <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="../resources/prettify/prettify.js"></script> <style type="text/css"> .highlight { display: block; background-color: #ddd; } </style> <script type="text/javascript"> function highlight() { document.getElementById(location.hash.replace(/#/, "")).className = "highlight"; } </script> </head> <body onload="prettyPrint(); highlight();"> <pre class="prettyprint lang-js"><span id='Ext-grid-PivotGrid'>/** </span> * @class Ext.grid.PivotGrid * @extends Ext.grid.GridPanel * <p>The PivotGrid component enables rapid summarization of large data sets. It provides a way to reduce a large set of * data down into a format where trends and insights become more apparent. A classic example is in sales data; a company * will often have a record of all sales it makes for a given period - this will often encompass thousands of rows of * data. The PivotGrid allows you to see how well each salesperson performed, which cities generate the most revenue, * how products perform between cities and so on.</p> * <p>A PivotGrid is composed of two axes (left and top), one {@link #measure} and one {@link #aggregator aggregation} * function. Each axis can contain one or more {@link #dimension}, which are ordered into a hierarchy. Dimensions on the * left axis can also specify a width. Each dimension in each axis can specify its sort ordering, defaulting to "ASC", * and must specify one of the fields in the {@link Ext.data.Record Record} used by the PivotGrid's * {@link Ext.data.Store Store}.</p> <pre><code> // This is the record representing a single sale var SaleRecord = Ext.data.Record.create([ {name: 'person', type: 'string'}, {name: 'product', type: 'string'}, {name: 'city', type: 'string'}, {name: 'state', type: 'string'}, {name: 'year', type: 'int'}, {name: 'value', type: 'int'} ]); // A simple store that loads SaleRecord data from a url var myStore = new Ext.data.Store({ url: 'data.json', autoLoad: true, reader: new Ext.data.JsonReader({ root: 'rows', idProperty: 'id' }, SaleRecord) }); // Create the PivotGrid itself, referencing the store var pivot = new Ext.grid.PivotGrid({ store : myStore, aggregator: 'sum', measure : 'value', leftAxis: [ { width: 60, dataIndex: 'product' }, { width: 120, dataIndex: 'person', direction: 'DESC' } ], topAxis: [ { dataIndex: 'year' } ] }); </code></pre> * <p>The specified {@link #measure} is the field from SaleRecord that is extracted from each combination * of product and person (on the left axis) and year on the top axis. There may be several SaleRecords in the * data set that share this combination, so an array of measure fields is produced. This array is then * aggregated using the {@link #aggregator} function.</p> * <p>The default aggregator function is sum, which simply adds up all of the extracted measure values. Other * built-in aggregator functions are count, avg, min and max. In addition, you can specify your own function. * In this example we show the code used to sum the measures, but you can return any value you like. See * {@link #aggregator} for more details.</p> <pre><code> new Ext.grid.PivotGrid({ aggregator: function(records, measure) { var length = records.length, total = 0, i; for (i = 0; i < length; i++) { total += records[i].get(measure); } return total; }, renderer: function(value) { return Math.round(value); }, //your normal config here }); </code></pre> * <p><u>Renderers</u></p> * <p>PivotGrid optionally accepts a {@link #renderer} function which can modify the data in each cell before it * is rendered. The renderer is passed the value that would usually be placed in the cell and is expected to return * the new value. For example let's imagine we had height data expressed as a decimal - here's how we might use a * renderer to display the data in feet and inches notation:</p> <pre><code> new Ext.grid.PivotGrid({ //in each case the value is a decimal number of feet renderer : function(value) { var feet = Math.floor(value), inches = Math.round((value - feet) * 12); return String.format("{0}' {1}\"", feet, inches); }, //normal config here }); </code></pre> * <p><u>Reconfiguring</u></p> * <p>All aspects PivotGrid's configuration can be updated at runtime. It is easy to change the {@link #setMeasure measure}, * {@link #setAggregator aggregation function}, {@link #setLeftAxis left} and {@link #setTopAxis top} axes and refresh the grid.</p> * <p>In this case we reconfigure the PivotGrid to have city and year as the top axis dimensions, rendering the average sale * value into the cells:</p> <pre><code> //the left axis can also be changed pivot.topAxis.setDimensions([ {dataIndex: 'city', direction: 'DESC'}, {dataIndex: 'year', direction: 'ASC'} ]); pivot.setMeasure('value'); pivot.setAggregator('avg'); pivot.view.refresh(true); </code></pre> * <p>See the {@link Ext.grid.PivotAxis PivotAxis} documentation for further detail on reconfiguring axes.</p> */ Ext.grid.PivotGrid = Ext.extend(Ext.grid.GridPanel, { <span id='Ext-grid-PivotGrid-cfg-aggregator'> /** </span> * @cfg {String|Function} aggregator The aggregation function to use to combine the measures extracted * for each dimension combination. Can be any of the built-in aggregators (sum, count, avg, min, max). * Can also be a function which accepts two arguments (an array of Records to aggregate, and the measure * to aggregate them on) and should return a String. */ aggregator: 'sum', <span id='Ext-grid-PivotGrid-cfg-renderer'> /** </span> * @cfg {Function} renderer Optional renderer to pass values through before they are rendered to the dom. This * gives an opportunity to modify cell contents after the value has been computed. */ renderer: undefined, <span id='Ext-grid-PivotGrid-cfg-measure'> /** </span> * @cfg {String} measure The field to extract from each Record when pivoting around the two axes. See the class * introduction docs for usage */ <span id='Ext-grid-PivotGrid-cfg-leftAxis'> /** </span> * @cfg {Array|Ext.grid.PivotAxis} leftAxis Either and array of {@link #dimension} to use on the left axis, or * a {@link Ext.grid.PivotAxis} instance. If an array is passed, it is turned into a PivotAxis internally. */ <span id='Ext-grid-PivotGrid-cfg-topAxis'> /** </span> * @cfg {Array|Ext.grid.PivotAxis} topAxis Either and array of {@link #dimension} to use on the top axis, or * a {@link Ext.grid.PivotAxis} instance. If an array is passed, it is turned into a PivotAxis internally. */ <span id='Ext-grid-PivotGrid-method-initComponent'> //inherit docs </span> initComponent: function() { Ext.grid.PivotGrid.superclass.initComponent.apply(this, arguments); this.initAxes(); //no resizing of columns is allowed yet in PivotGrid this.enableColumnResize = false; this.viewConfig = Ext.apply(this.viewConfig || {}, { forceFit: true }); //TODO: dummy col model that is never used - GridView is too tightly integrated with ColumnModel //in 3.x to remove this altogether. this.colModel = new Ext.grid.ColumnModel({}); }, <span id='Ext-grid-PivotGrid-method-getAggregator'> /** </span> * Returns the function currently used to aggregate the records in each Pivot cell * @return {Function} The current aggregator function */ getAggregator: function() { if (typeof this.aggregator == 'string') { return Ext.grid.PivotAggregatorMgr.types[this.aggregator]; } else { return this.aggregator; } }, <span id='Ext-grid-PivotGrid-method-setAggregator'> /** </span> * Sets the function to use when aggregating data for each cell. * @param {String|Function} aggregator The new aggregator function or named function string */ setAggregator: function(aggregator) { this.aggregator = aggregator; }, <span id='Ext-grid-PivotGrid-method-setMeasure'> /** </span> * Sets the field name to use as the Measure in this Pivot Grid * @param {String} measure The field to make the measure */ setMeasure: function(measure) { this.measure = measure; }, <span id='Ext-grid-PivotGrid-method-setLeftAxis'> /** </span> * Sets the left axis of this pivot grid. Optionally refreshes the grid afterwards. * @param {Ext.grid.PivotAxis} axis The pivot axis * @param {Boolean} refresh True to immediately refresh the grid and its axes (defaults to false) */ setLeftAxis: function(axis, refresh) { <span id='Ext-grid-PivotGrid-property-leftAxis'> /** </span> * The configured {@link Ext.grid.PivotAxis} used as the left Axis for this Pivot Grid * @property leftAxis * @type Ext.grid.PivotAxis */ this.leftAxis = axis; if (refresh) { this.view.refresh(); } }, <span id='Ext-grid-PivotGrid-method-setTopAxis'> /** </span> * Sets the top axis of this pivot grid. Optionally refreshes the grid afterwards. * @param {Ext.grid.PivotAxis} axis The pivot axis * @param {Boolean} refresh True to immediately refresh the grid and its axes (defaults to false) */ setTopAxis: function(axis, refresh) { <span id='Ext-grid-PivotGrid-property-topAxis'> /** </span> * The configured {@link Ext.grid.PivotAxis} used as the top Axis for this Pivot Grid * @property topAxis * @type Ext.grid.PivotAxis */ this.topAxis = axis; if (refresh) { this.view.refresh(); } }, <span id='Ext-grid-PivotGrid-method-initAxes'> /** </span> * @private * Creates the top and left axes. Should usually only need to be called once from initComponent */ initAxes: function() { var PivotAxis = Ext.grid.PivotAxis; if (!(this.leftAxis instanceof PivotAxis)) { this.setLeftAxis(new PivotAxis({ orientation: 'vertical', dimensions : this.leftAxis || [], store : this.store })); }; if (!(this.topAxis instanceof PivotAxis)) { this.setTopAxis(new PivotAxis({ orientation: 'horizontal', dimensions : this.topAxis || [], store : this.store })); }; }, <span id='Ext-grid-PivotGrid-method-extractData'> /** </span> * @private * @return {Array} 2-dimensional array of cell data */ extractData: function() { var records = this.store.data.items, recCount = records.length, cells = [], record, i, j, k; if (recCount == 0) { return []; } var leftTuples = this.leftAxis.getTuples(), leftCount = leftTuples.length, topTuples = this.topAxis.getTuples(), topCount = topTuples.length, aggregator = this.getAggregator(); for (i = 0; i < recCount; i++) { record = records[i]; for (j = 0; j < leftCount; j++) { cells[j] = cells[j] || []; if (leftTuples[j].matcher(record) === true) { for (k = 0; k < topCount; k++) { cells[j][k] = cells[j][k] || []; if (topTuples[k].matcher(record)) { cells[j][k].push(record); } } } } } var rowCount = cells.length, colCount, row; for (i = 0; i < rowCount; i++) { row = cells[i]; colCount = row.length; for (j = 0; j < colCount; j++) { cells[i][j] = aggregator(cells[i][j], this.measure); } } return cells; }, <span id='Ext-grid-PivotGrid-method-getView'> /** </span> * Returns the grid's GridView object. * @return {Ext.grid.PivotGridView} The grid view */ getView: function() { if (!this.view) { this.view = new Ext.grid.PivotGridView(this.viewConfig); } return this.view; } }); Ext.reg('pivotgrid', Ext.grid.PivotGrid); Ext.grid.PivotAggregatorMgr = new Ext.AbstractManager(); Ext.grid.PivotAggregatorMgr.registerType('sum', function(records, measure) { var length = records.length, total = 0, i; for (i = 0; i < length; i++) { total += records[i].get(measure); } return total; }); Ext.grid.PivotAggregatorMgr.registerType('avg', function(records, measure) { var length = records.length, total = 0, i; for (i = 0; i < length; i++) { total += records[i].get(measure); } return (total / length) || 'n/a'; }); Ext.grid.PivotAggregatorMgr.registerType('min', function(records, measure) { var data = [], length = records.length, i; for (i = 0; i < length; i++) { data.push(records[i].get(measure)); } return Math.min.apply(this, data) || 'n/a'; }); Ext.grid.PivotAggregatorMgr.registerType('max', function(records, measure) { var data = [], length = records.length, i; for (i = 0; i < length; i++) { data.push(records[i].get(measure)); } return Math.max.apply(this, data) || 'n/a'; }); Ext.grid.PivotAggregatorMgr.registerType('count', function(records, measure) { return records.length; });</pre> </body> </html>