ag-grid-enterprise
Version:
ag-Grid Enterprise Features
231 lines (198 loc) • 6.68 kB
text/typescript
import {
IAggFuncService, IAggFunc, Bean, Utils, PostConstruct, Autowired, GridOptionsWrapper, Column, _
} from "ag-grid-community";
export class AggFuncService implements IAggFuncService {
private static AGG_SUM = 'sum';
private static AGG_FIRST = 'first';
private static AGG_LAST = 'last';
private static AGG_MIN = 'min';
private static AGG_MAX = 'max';
private static AGG_COUNT = 'count';
private static AGG_AVG = 'avg';
gridOptionsWrapper: GridOptionsWrapper;
private aggFuncsMap: {[key: string]: IAggFunc} = {};
private initialised = false;
private init() {
if (this.initialised) { return; }
this.initialised = true;
this.initialiseWithDefaultAggregations();
this.addAggFuncs(this.gridOptionsWrapper.getAggFuncs());
}
private initialiseWithDefaultAggregations(): void {
this.aggFuncsMap[AggFuncService.AGG_SUM] = aggSum;
this.aggFuncsMap[AggFuncService.AGG_FIRST] = aggFirst;
this.aggFuncsMap[AggFuncService.AGG_LAST] = aggLast;
this.aggFuncsMap[AggFuncService.AGG_MIN] = aggMin;
this.aggFuncsMap[AggFuncService.AGG_MAX] = aggMax;
this.aggFuncsMap[AggFuncService.AGG_COUNT] = aggCount;
this.aggFuncsMap[AggFuncService.AGG_AVG] = aggAvg;
}
public getDefaultAggFunc(column: Column): string {
let allKeys = this.getFuncNames(column);
// use 'sum' if it's a) allowed for the column and b) still registered
// (ie not removed by user)
let sumInKeysList = allKeys.indexOf(AggFuncService.AGG_SUM) >= 0;
let sumInFuncs = _.exists(this.aggFuncsMap[AggFuncService.AGG_SUM]);
let useSum = sumInKeysList && sumInFuncs;
if (useSum) {
return AggFuncService.AGG_SUM;
} else {
if (Utils.existsAndNotEmpty(allKeys)) {
return allKeys[0];
} else {
return null;
}
}
}
public addAggFuncs(aggFuncs: {[key: string]: IAggFunc}): void {
Utils.iterateObject(aggFuncs, this.addAggFunc.bind(this));
}
public addAggFunc(key: string, aggFunc: IAggFunc): void {
this.init();
this.aggFuncsMap[key] = aggFunc;
}
public getAggFunc(name: string): IAggFunc {
this.init();
return this.aggFuncsMap[name];
}
public getFuncNames(column: Column): string[] {
let userAllowedFuncs = column.getColDef().allowedAggFuncs;
if (_.exists(userAllowedFuncs)) {
return userAllowedFuncs;
} else {
return Object.keys(this.aggFuncsMap).sort();
}
}
public clear(): void {
this.aggFuncsMap = {};
}
}
function aggSum(input: any[]): any {
let result: number = null;
let length = input.length;
for (let i = 0; i<length; i++) {
if (typeof input[i] === 'number') {
if (result === null) {
result = input[i];
} else {
result += input[i];
}
}
}
return result;
}
function aggFirst(input: any[]): any {
if (input.length>=0) {
return input[0];
} else {
return null;
}
}
function aggLast(input: any[]): any {
if (input.length>=0) {
return input[input.length-1];
} else {
return null;
}
}
function aggMin(input: any[]): any {
let result: number = null;
let length = input.length;
for (let i = 0; i<length; i++) {
if (typeof input[i] === 'number') {
if (result === null) {
result = input[i];
} else if (result > input[i]) {
result = input[i];
}
}
}
return result;
}
function aggMax(input: any[]): any {
let result: number = null;
let length = input.length;
for (let i = 0; i<length; i++) {
if (typeof input[i] === 'number') {
if (result === null) {
result = input[i];
} else if (result < input[i]) {
result = input[i];
}
}
}
return result;
}
function aggCount(input: any[]): any {
let result = {
value: 0,
toString: function() {
return this.value.toString();
},
// used for sorting
toNumber: function() {
return this.value;
}
};
let length = input.length;
for (let i = 0; i<length; i++) {
let isGroupAgg = Utils.exists(input[i]) && typeof input[i].value === 'number';
if (isGroupAgg) {
result.value += input[i].value;
} else {
result.value++;
}
}
return result;
}
// the average function is tricky as the multiple levels require weighted averages
// for the non-leaf node aggregations.
function aggAvg(input: any[]): any {
// the average will be the sum / count
let sum = 0;
let count = 0;
let length = input.length;
for (let i = 0; i<length; i++) {
let currentItem = input[i];
let itemIsGroupResult = Utils.exists(currentItem) && typeof currentItem.value === 'number' && typeof currentItem.count === 'number';
// skip values that are not numbers (ie skip empty values)
if (typeof currentItem === 'number') {
sum += currentItem;
count++;
// check if it's a group (ie value is a wrapper object)
} else if (itemIsGroupResult) {
// we are aggregating groups, so we take the
// aggregated values to calculated a weighted average
sum += currentItem.value * currentItem.count;
count += currentItem.count;
}
}
// avoid divide by zero error
let value: number = null;
if (count!==0) {
value = sum / count;
}
// the result will be an object. when this cell is rendered, only the avg is shown.
// however when this cell is part of another aggregation, the count is also needed
// to create a weighted average for the next level.
let result = {
count: count,
value: value,
// the grid by default uses toString to render values for an object, so this
// is a trick to get the default cellRenderer to display the avg value
toString: function() {
if (typeof this.value === 'number') {
return this.value.toString();
} else {
return '';
}
},
// used for sorting
toNumber: function() {
return this.value;
}
};
return result;
}