@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
183 lines (182 loc) • 8.88 kB
JavaScript
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { ArrayExtensions } from '../Utilities/Extensions/ArrayExtensions';
import ObjectFactory from '../Utilities/ObjectFactory';
import { AggregatedScalarLiveValue } from '../Utilities/Services/AggregatedScalarLiveValue';
import { CellSummaryStatusPanel } from '../View/CellSummary/CellSummaryStatusPanel';
import { AdaptableModuleBase } from './AdaptableModuleBase';
/**
* Module that provides Cell Summaries on numeric columns
*/
export class CellSummaryModule extends AdaptableModuleBase {
constructor(api) {
super(ModuleConstants.CellSummaryModuleId, ModuleConstants.CellSummaryFriendlyName, 'cells', 'CellSummaryPopup', 'See summary information on a group of numeric cells using multiple summary operations', api);
this.cachedCellSummary = new WeakMap();
}
getViewAccessLevel() {
return 'Full';
}
createColumnMenuItems(column) {
if (!this.isModuleAvailable()) {
return;
}
if (column.dataType !== 'number') {
return;
}
return [
this.createMainMenuItemShowPopup({
Name: 'cell-summary-show',
Label: 'See Cell Summary',
ComponentName: this.moduleInfo.Popup,
Icon: this.moduleInfo.Glyph,
PopupParams: {
source: 'ColumnMenu',
column,
},
}),
];
}
createContextMenuItems(menuContext) {
if (!this.isModuleAvailable()) {
return;
}
if (menuContext.adaptableColumn &&
menuContext.isSelectedCell &&
menuContext.adaptableColumn.dataType === 'number') {
return [
this.createMainMenuItemShowPopup({
Name: 'cell-summary-show',
Label: 'See Cell Summary',
ComponentName: this.moduleInfo.Popup,
Icon: this.moduleInfo.Glyph,
PopupParams: {
source: 'ContextMenu',
},
}),
];
}
}
createCellSummaryInfo(selectedCellInfo) {
if (this.cachedCellSummary.has(selectedCellInfo)) {
return this.cachedCellSummary.get(selectedCellInfo);
}
let selectedCellSummary = ObjectFactory.CreateEmptyCellSummmary();
if (selectedCellInfo && ArrayExtensions.hasOneItem(selectedCellInfo.columns)) {
let selectedColumn = selectedCellInfo.columns[0];
if (selectedColumn && selectedColumn.dataType === 'number') {
const numberFormatOptions = this.getNumberFormatOptions(selectedColumn);
const rowNodes = selectedCellInfo.gridCells.map((gc) => gc.rowNode);
const handleExpression = (functionName) => {
const aggScalarValue = new AggregatedScalarLiveValue({
aggregatedScalarExpression: `${functionName}([${selectedColumn.columnId}])`,
}, ModuleConstants.CellSummaryModuleId, this.api, () => rowNodes);
return this.formatValue(numberFormatOptions, selectedColumn, aggScalarValue.getGlobalAggregatedValue(), rowNodes[0]);
};
const sumValue = handleExpression('SUM');
const avgValue = handleExpression('AVG');
const modeValue = handleExpression('MODE');
const medianValue = handleExpression('MEDIAN');
const distinctValue = handleExpression('DISTINCT');
const maxValue = handleExpression('MAX');
const minValue = handleExpression('MIN');
const countValue = selectedCellInfo.gridCells.length;
const stdDeviation = handleExpression('STD_DEVIATION');
selectedCellSummary = {
Sum: sumValue,
Average: avgValue,
Median: medianValue,
Mode: modeValue,
Distinct: distinctValue,
Max: maxValue,
Min: minValue,
Count: countValue,
Std_Deviation: stdDeviation,
Only: distinctValue == 1 ? JSON.stringify(selectedCellInfo.gridCells[0].rawValue) : undefined,
};
const weightedAverageConfig = this.getWeightedAverageConfig(selectedColumn.columnId);
if (weightedAverageConfig) {
const weightedAverage = this.getWeightedAverageCellSummary(weightedAverageConfig, selectedColumn.columnId, rowNodes);
if (weightedAverage !== null) {
selectedCellSummary.Weighted_Average = this.formatValue(numberFormatOptions, selectedColumn, weightedAverage, rowNodes[0]);
}
}
const customCellSummaryOperations = this.api.cellSummaryApi.getCustomCellSummaryOperations();
customCellSummaryOperations?.forEach((operation) => {
if (operation.operationFunction) {
const cellSummaryOperationContext = {
selectedCellInfo,
selectedColumn,
...this.api.internalApi.buildBaseContext(),
};
selectedCellSummary[operation.operationName] = operation.operationFunction(cellSummaryOperationContext);
}
});
this.cachedCellSummary.set(selectedCellInfo, selectedCellSummary);
}
}
return selectedCellSummary;
}
getNumberFormatOptions(column) {
let columnToFormat = column;
let adaptableFormat;
// first get any Display Formats applied for the column and if provided, then return those
// note: this will automatically include any custom formats
adaptableFormat = this.api.formatColumnApi.getDisplayFormatForColumn(columnToFormat);
if (adaptableFormat) {
return adaptableFormat.Options;
}
// temporary hack until we get the parent for pivot columns - just in case we dont have time...
if (columnToFormat.isGeneratedPivotResultColumn) {
const parts = columnToFormat.columnId.split('_');
const colid = parts[parts.length - 1];
columnToFormat = this.api.columnApi.getColumnWithColumnId(colid);
// check if this pivot result column has been give its own Format and if so return it
adaptableFormat = this.api.formatColumnApi.getDisplayFormatForColumn(columnToFormat);
if (adaptableFormat) {
return adaptableFormat.Options;
}
}
// otherwise get the numeric format in Cell Summary Options (either function or value)
const numericDisplayFormat = this.api.optionsApi.getCellSummaryOptions().numericDisplayFormat;
if (typeof numericDisplayFormat === 'function') {
const context = {
column: columnToFormat,
...this.api.internalApi.buildBaseContext(),
};
return numericDisplayFormat(context);
}
else {
return numericDisplayFormat;
}
}
formatValue(formatterOptions, column, valueToFormat, node) {
return isNaN(valueToFormat)
? valueToFormat
: this.api.formatColumnApi.internalApi.getNumberFormattedValue(valueToFormat, node, column, formatterOptions);
}
getWeightedAverageConfig(columnId) {
const weightedAverageConfig = (this.api.layoutApi.getCurrentLayout().TableAggregationColumns || []).find(({ ColumnId, AggFunc }) => typeof AggFunc === 'object' && AggFunc.type === 'weightedAverage' && ColumnId === columnId);
return weightedAverageConfig;
}
getWeightedAverageCellSummary(weightedAverageConfig, columnId, rowNodes) {
const weightedColumnId = weightedAverageConfig.AggFunc
.weightedColumnId;
const expression = `AVG([${columnId}], WEIGHT([${weightedColumnId}]))`;
const aggScalarValue = new AggregatedScalarLiveValue({
aggregatedScalarExpression: expression,
}, ModuleConstants.CellSummaryModuleId, this.api, () => rowNodes);
return aggScalarValue.getGlobalAggregatedValue();
}
getViewProperties() {
return {
getStatusBarPanelProps() {
/**
* This uses a custom view because it has special logic to
* trigger summary operations when the component is rendered.
*/
return {
view: CellSummaryStatusPanel,
};
},
};
}
}