UNPKG

ag-grid-enterprise

Version:

ag-Grid Enterprise Features

231 lines (198 loc) 6.68 kB
import { IAggFuncService, IAggFunc, Bean, Utils, PostConstruct, Autowired, GridOptionsWrapper, Column, _ } from "ag-grid-community"; @Bean('aggFuncService') 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'; @Autowired('gridOptionsWrapper') gridOptionsWrapper: GridOptionsWrapper; private aggFuncsMap: {[key: string]: IAggFunc} = {}; private initialised = false; @PostConstruct 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; }