/** * Pivot Simlet does remote pivot calculations. * Filtering the pivot results doesn't work. */Ext.define('Ext.ux.ajax.PivotSimlet', { extend: 'Ext.ux.ajax.JsonSimlet', alias: 'simlet.pivot', lastPost: null, // last Ajax params sent to this simlet lastResponse: null, // last JSON response produced by this simlet keysSeparator: '', grandTotalKey: '', doPost: function(ctx) { var me = this, ret = me.callParent(arguments); // pick up status/statusText me.lastResponse = me.processData(me.getData(ctx), Ext.decode(ctx.xhr.body)); ret.responseText = Ext.encode(me.lastResponse); return ret; }, processData: function(data, params) { var me = this, len = data.length, response = { success: true, leftAxis: [], topAxis: [], results: [] }, leftAxis = new Ext.util.MixedCollection(), topAxis = new Ext.util.MixedCollection(), results = new Ext.util.MixedCollection(), i, j, k, leftKeys, topKeys, item, agg; me.lastPost = params; me.keysSeparator = params.keysSeparator; me.grandTotalKey = params.grandTotalKey; for (i = 0; i < len; i++) { leftKeys = me.extractValues(data[i], params.leftAxis, leftAxis); topKeys = me.extractValues(data[i], params.topAxis, topAxis); // add record to grand totals me.addResult(data[i], me.grandTotalKey, me.grandTotalKey, results); for (j = 0; j < leftKeys.length; j++) { // add record to col grand totals me.addResult(data[i], leftKeys[j], me.grandTotalKey, results); // add record to left/top keys pair for (k = 0; k < topKeys.length; k++) { me.addResult(data[i], leftKeys[j], topKeys[k], results); } } // add record to row grand totals for (j = 0; j < topKeys.length; j++) { me.addResult(data[i], me.grandTotalKey, topKeys[j], results); } } // extract items from their left/top collections and build the json response response.leftAxis = leftAxis.getRange(); response.topAxis = topAxis.getRange(); len = results.getCount(); for (i = 0; i < len; i++) { item = results.getAt(i); item.values = {}; for (j = 0; j < params.aggregate.length; j++) { agg = params.aggregate[j]; item.values[agg.id] = me[agg.aggregator]( item.records, agg.dataIndex, item.leftKey, item.topKey ); } delete(item.records); response.results.push(item); } leftAxis.clear(); topAxis.clear(); results.clear(); return response; }, getKey: function(value) { var me = this; me.keysMap = me.keysMap || {}; if (!Ext.isDefined(me.keysMap[value])) { me.keysMap[value] = Ext.id(); } return me.keysMap[value]; }, extractValues: function(record, dimensions, col) { var len = dimensions.length, keys = [], j, key, item, dim; key = ''; for (j = 0; j < len; j++) { dim = dimensions[j]; key += (j > 0 ? this.keysSeparator : '') + this.getKey(record[dim.dataIndex]); item = col.getByKey(key); if (!item) { item = col.add(key, { key: key, value: record[dim.dataIndex], dimensionId: dim.id }); } keys.push(key); } return keys; }, addResult: function(record, leftKey, topKey, results) { var item = results.getByKey(leftKey + '/' + topKey); if (!item) { item = results.add(leftKey + '/' + topKey, { leftKey: leftKey, topKey: topKey, records: [] }); } item.records.push(record); }, sum: function(records, measure, rowGroupKey, colGroupKey) { var length = records.length, total = 0, i; for (i = 0; i < length; i++) { total += Ext.Number.from(records[i][measure], 0); } return total; }, avg: function(records, measure, rowGroupKey, colGroupKey) { var length = records.length, total = 0, i; for (i = 0; i < length; i++) { total += Ext.Number.from(records[i][measure], 0); } return length > 0 ? (total / length) : 0; }, min: function(records, measure, rowGroupKey, colGroupKey) { var data = [], length = records.length, i, v; for (i = 0; i < length; i++) { data.push(records[i][measure]); } v = Ext.Array.min(data); return v; }, max: function(records, measure, rowGroupKey, colGroupKey) { var data = [], length = records.length, i, v; for (i = 0; i < length; i++) { data.push(records[i][measure]); } v = Ext.Array.max(data); return v; }, count: function(records, measure, rowGroupKey, colGroupKey) { return records.length; }, variance: function(records, measure, rowGroupKey, colGroupKey) { var me = Ext.pivot.Aggregators, length = records.length, avg = me.avg.apply(me, arguments), total = 0, i; if (avg > 0) { for (i = 0; i < length; i++) { total += Math.pow(Ext.Number.from(records[i][measure], 0) - avg, 2); } } return (total > 0 && length > 1) ? (total / (length - 1)) : 0; }, varianceP: function(records, measure, rowGroupKey, colGroupKey) { var me = Ext.pivot.Aggregators, length = records.length, avg = me.avg.apply(me, arguments), total = 0, i; if (avg > 0) { for (i = 0; i < length; i++) { total += Math.pow(Ext.Number.from(records[i][measure], 0) - avg, 2); } } return (total > 0 && length > 0) ? (total / length) : 0; }, stdDev: function(records, measure, rowGroupKey, colGroupKey) { var me = Ext.pivot.Aggregators, v = me.variance.apply(me, arguments); return v > 0 ? Math.sqrt(v) : 0; }, stdDevP: function(records, measure, rowGroupKey, colGroupKey) { var me = Ext.pivot.Aggregators, v = me.varianceP.apply(me, arguments); return v > 0 ? Math.sqrt(v) : 0; } });