/**
* 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;
}
});