402 lines
14 KiB
HTML
402 lines
14 KiB
HTML
<!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>
|