tabulator-tables
Version:
Interactive table generation JavaScript library
471 lines (363 loc) • 11.5 kB
JavaScript
var ColumnCalcs = function(table){
this.table = table; //hold Tabulator object
this.topCalcs = [];
this.botCalcs = [];
this.genColumn = false;
this.topElement = this.createElement();
this.botElement = this.createElement();
this.topRow = false;
this.botRow = false;
this.topInitialized = false;
this.botInitialized = false;
this.initialize();
};
ColumnCalcs.prototype.createElement = function (){
var el = document.createElement("div");
el.classList.add("tabulator-calcs-holder");
return el;
};
ColumnCalcs.prototype.initialize = function(){
this.genColumn = new Column({field:"value"}, this);
};
//dummy functions to handle being mock column manager
ColumnCalcs.prototype.registerColumnField = function(){};
//initialize column calcs
ColumnCalcs.prototype.initializeColumn = function(column){
var def = column.definition
var config = {
topCalcParams:def.topCalcParams || {},
botCalcParams:def.bottomCalcParams || {},
};
if(def.topCalc){
switch(typeof def.topCalc){
case "string":
if(this.calculations[def.topCalc]){
config.topCalc = this.calculations[def.topCalc]
}else{
console.warn("Column Calc Error - No such calculation found, ignoring: ", def.topCalc);
}
break;
case "function":
config.topCalc = def.topCalc;
break
}
if(config.topCalc){
column.modules.columnCalcs = config;
this.topCalcs.push(column);
if(this.table.options.columnCalcs != "group"){
this.initializeTopRow();
}
}
}
if(def.bottomCalc){
switch(typeof def.bottomCalc){
case "string":
if(this.calculations[def.bottomCalc]){
config.botCalc = this.calculations[def.bottomCalc]
}else{
console.warn("Column Calc Error - No such calculation found, ignoring: ", def.bottomCalc);
}
break;
case "function":
config.botCalc = def.bottomCalc;
break
}
if(config.botCalc){
column.modules.columnCalcs = config;
this.botCalcs.push(column);
if(this.table.options.columnCalcs != "group"){
this.initializeBottomRow();
}
}
}
};
ColumnCalcs.prototype.removeCalcs = function(){
var changed = false;
if(this.topInitialized){
this.topInitialized = false;
this.topElement.parentNode.removeChild(this.topElement);
changed = true;
}
if(this.botInitialized){
this.botInitialized = false;
this.table.footerManager.remove(this.botElement);
changed = true;
}
if(changed){
this.table.rowManager.adjustTableSize();
}
};
ColumnCalcs.prototype.initializeTopRow = function(){
if(!this.topInitialized){
// this.table.columnManager.headersElement.after(this.topElement);
this.table.columnManager.getElement().insertBefore(this.topElement, this.table.columnManager.headersElement.nextSibling);
this.topInitialized = true;
}
};
ColumnCalcs.prototype.initializeBottomRow = function(){
if(!this.botInitialized){
this.table.footerManager.prepend(this.botElement);
this.botInitialized = true;
}
};
ColumnCalcs.prototype.scrollHorizontal = function(left){
var hozAdjust = 0,
scrollWidth = this.table.columnManager.getElement().scrollWidth - this.table.element.clientWidth;
if(this.botInitialized){
this.botRow.getElement().style.marginLeft = (-left) + "px";
}
};
ColumnCalcs.prototype.recalc = function(rows){
var data, row;
if(this.topInitialized || this.botInitialized){
data = this.rowsToData(rows);
if(this.topInitialized){
if(this.topRow){
this.topRow.deleteCells();
}
row = this.generateRow("top", this.rowsToData(rows))
this.topRow = row;
while(this.topElement.firstChild) this.topElement.removeChild(this.topElement.firstChild);
this.topElement.appendChild(row.getElement());
row.initialize(true);
}
if(this.botInitialized){
if(this.botRow){
this.botRow.deleteCells();
}
row = this.generateRow("bottom", this.rowsToData(rows))
this.botRow = row;
while(this.botElement.firstChild) this.botElement.removeChild(this.botElement.firstChild);
this.botElement.appendChild(row.getElement());
row.initialize(true);
}
this.table.rowManager.adjustTableSize();
//set resizable handles
if(this.table.modExists("frozenColumns")){
this.table.modules.frozenColumns.layout();
}
}
};
ColumnCalcs.prototype.recalcRowGroup = function(row){
this.recalcGroup(this.table.modules.groupRows.getRowGroup(row));
};
ColumnCalcs.prototype.recalcGroup = function(group){
var data, rowData;
if(group){
if(group.calcs){
if(group.calcs.bottom){
data = this.rowsToData(group.rows);
rowData = this.generateRowData("bottom", data);
group.calcs.bottom.updateData(rowData);
group.calcs.bottom.reinitialize();
}
if(group.calcs.top){
data = this.rowsToData(group.rows);
rowData = this.generateRowData("top", data);
group.calcs.top.updateData(rowData);
group.calcs.top.reinitialize();
}
}
}
};
//generate top stats row
ColumnCalcs.prototype.generateTopRow = function(rows){
return this.generateRow("top", this.rowsToData(rows));
};
//generate bottom stats row
ColumnCalcs.prototype.generateBottomRow = function(rows){
return this.generateRow("bottom", this.rowsToData(rows));
};
ColumnCalcs.prototype.rowsToData = function(rows){
var data = [];
rows.forEach(function(row){
data.push(row.getData());
});
return data;
};
//generate stats row
ColumnCalcs.prototype.generateRow = function(pos, data){
var self = this,
rowData = this.generateRowData(pos, data),
row;
if(self.table.modExists("mutator")){
self.table.modules.mutator.disable();
}
row = new Row(rowData, this);
if(self.table.modExists("mutator")){
self.table.modules.mutator.enable();
}
row.getElement().classList.add("tabulator-calcs", "tabulator-calcs-" + pos);
row.type = "calc";
row.generateCells = function(){
var cells = [];
self.table.columnManager.columnsByIndex.forEach(function(column){
//set field name of mock column
self.genColumn.setField(column.getField());
self.genColumn.hozAlign = column.hozAlign;
if(column.definition[pos + "CalcFormatter"] && self.table.modExists("format")){
self.genColumn.modules.format = {
formatter: self.table.modules.format.getFormatter(column.definition[pos + "CalcFormatter"]),
params: column.definition[pos + "CalcFormatterParams"]
};
}else{
self.genColumn.modules.format = {
formatter: self.table.modules.format.getFormatter("plaintext"),
params:{}
};
}
//ensure css class defintion is replicated to calculation cell
self.genColumn.definition.cssClass = column.definition.cssClass;
//generate cell and assign to correct column
var cell = new Cell(self.genColumn, row);
cell.column = column;
cell.setWidth();
column.cells.push(cell);
cells.push(cell);
if(!column.visible){
cell.hide();
}
});
this.cells = cells;
}
return row;
};
//generate stats row
ColumnCalcs.prototype.generateRowData = function(pos, data){
var rowData = {},
calcs = pos == "top" ? this.topCalcs : this.botCalcs,
type = pos == "top" ? "topCalc" : "botCalc",
params, paramKey;
calcs.forEach(function(column){
var values = [];
if(column.modules.columnCalcs && column.modules.columnCalcs[type]){
data.forEach(function(item){
values.push(column.getFieldValue(item));
});
paramKey = type + "Params";
params = typeof column.modules.columnCalcs[paramKey] === "function" ? column.modules.columnCalcs[paramKey](values, data) : column.modules.columnCalcs[paramKey];
column.setFieldValue(rowData, column.modules.columnCalcs[type](values, data, params));
}
});
return rowData;
};
ColumnCalcs.prototype.hasTopCalcs = function(){
return !!(this.topCalcs.length);
},
ColumnCalcs.prototype.hasBottomCalcs = function(){
return !!(this.botCalcs.length);
},
//handle table redraw
ColumnCalcs.prototype.redraw = function(){
if(this.topRow){
this.topRow.normalizeHeight(true);
}
if(this.botRow){
this.botRow.normalizeHeight(true);
}
};
//return the calculated
ColumnCalcs.prototype.getResults = function(){
var self = this,
results = {},
groups;
if(this.table.options.groupBy && this.table.modExists("groupRows")){
groups = this.table.modules.groupRows.getGroups(true);
groups.forEach(function(group){
results[group.getKey()] = self.getGroupResults(group);
});
}else{
results = {
top: this.topRow ? this.topRow.getData() : {},
bottom: this.botRow ? this.botRow.getData() : {},
}
}
return results;
}
//get results from a group
ColumnCalcs.prototype.getGroupResults = function(group){
var self = this,
groupObj = group._getSelf(),
subGroups = group.getSubGroups(),
subGroupResults = {},
results = {};
subGroups.forEach(function(subgroup){
subGroupResults[subgroup.getKey()] = self.getGroupResults(subgroup);
});
results = {
top: groupObj.calcs.top ? groupObj.calcs.top.getData() : {},
bottom: groupObj.calcs.bottom ? groupObj.calcs.bottom.getData() : {},
groups: subGroupResults,
}
return results;
}
//default calculations
ColumnCalcs.prototype.calculations = {
"avg":function(values, data, calcParams){
var output = 0,
precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : 2
if(values.length){
output = values.reduce(function(sum, value){
value = Number(value);
return sum + value;
});
output = output / values.length;
output = precision !== false ? output.toFixed(precision) : output;
}
return parseFloat(output).toString();
},
"max":function(values, data, calcParams){
var output = null,
precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
values.forEach(function(value){
value = Number(value);
if(value > output || output === null){
output = value;
}
});
return output !== null ? (precision !== false ? output.toFixed(precision) : output) : "";
},
"min":function(values, data, calcParams){
var output = null,
precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
values.forEach(function(value){
value = Number(value);
if(value < output || output === null){
output = value;
}
});
return output !== null ? (precision !== false ? output.toFixed(precision) : output) : "";
},
"sum":function(values, data, calcParams){
var output = 0,
precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
if(values.length){
values.forEach(function(value){
value = Number(value);
output += !isNaN(value) ? Number(value) : 0;
});
}
return precision !== false ? output.toFixed(precision) : output;
},
"concat":function(values, data, calcParams){
var output = 0;
if(values.length){
output = values.reduce(function(sum, value){
return String(sum) + String(value);
});
}
return output;
},
"count":function(values, data, calcParams){
var output = 0;
if(values.length){
values.forEach(function(value){
if(value){
output ++;
}
});
}
return output;
},
};
Tabulator.prototype.registerModule("columnCalcs", ColumnCalcs);