otsdaq_utilities  v2_05_02_indev
calculation_colums.js
1 var ColumnCalcs = function(table){
2  this.table = table; //hold Tabulator object
3  this.topCalcs = [];
4  this.botCalcs = [];
5  this.genColumn = false;
6  this.topElement = this.createElement();
7  this.botElement = this.createElement();
8  this.topRow = false;
9  this.botRow = false;
10  this.topInitialized = false;
11  this.botInitialized = false;
12 
13  this.initialize();
14 };
15 
16 ColumnCalcs.prototype.createElement = function (){
17  var el = document.createElement("div");
18  el.classList.add("tabulator-calcs-holder");
19  return el;
20 };
21 
22 ColumnCalcs.prototype.initialize = function(){
23  this.genColumn = new Column({field:"value"}, this);
24 };
25 
26 //dummy functions to handle being mock column manager
27 ColumnCalcs.prototype.registerColumnField = function(){};
28 
29 //initialize column calcs
30 ColumnCalcs.prototype.initializeColumn = function(column){
31  var def = column.definition
32 
33  var config = {
34  topCalcParams:def.topCalcParams || {},
35  botCalcParams:def.bottomCalcParams || {},
36  };
37 
38  if(def.topCalc){
39 
40  switch(typeof def.topCalc){
41  case "string":
42  if(this.calculations[def.topCalc]){
43  config.topCalc = this.calculations[def.topCalc]
44  }else{
45  console.warn("Column Calc Error - No such calculation found, ignoring: ", def.topCalc);
46  }
47  break;
48 
49  case "function":
50  config.topCalc = def.topCalc;
51  break
52 
53  }
54 
55  if(config.topCalc){
56  column.modules.columnCalcs = config;
57  this.topCalcs.push(column);
58 
59  if(this.table.options.columnCalcs != "group"){
60  this.initializeTopRow();
61  }
62  }
63 
64  }
65 
66  if(def.bottomCalc){
67  switch(typeof def.bottomCalc){
68  case "string":
69  if(this.calculations[def.bottomCalc]){
70  config.botCalc = this.calculations[def.bottomCalc]
71  }else{
72  console.warn("Column Calc Error - No such calculation found, ignoring: ", def.bottomCalc);
73  }
74  break;
75 
76  case "function":
77  config.botCalc = def.bottomCalc;
78  break
79 
80  }
81 
82  if(config.botCalc){
83  column.modules.columnCalcs = config;
84  this.botCalcs.push(column);
85 
86  if(this.table.options.columnCalcs != "group"){
87  this.initializeBottomRow();
88  }
89  }
90  }
91 
92 };
93 
94 ColumnCalcs.prototype.removeCalcs = function(){
95  var changed = false;
96 
97  if(this.topInitialized){
98  this.topInitialized = false;
99  this.topElement.parentNode.removeChild(this.topElement);
100  changed = true;
101  }
102 
103  if(this.botInitialized){
104  this.botInitialized = false;
105  this.table.footerManager.remove(this.botElement);
106  changed = true;
107  }
108 
109  if(changed){
110  this.table.rowManager.adjustTableSize();
111  }
112 };
113 
114 ColumnCalcs.prototype.initializeTopRow = function(){
115  if(!this.topInitialized){
116  // this.table.columnManager.headersElement.after(this.topElement);
117  this.table.columnManager.getElement().insertBefore(this.topElement, this.table.columnManager.headersElement.nextSibling);
118  this.topInitialized = true;
119  }
120 };
121 
122 ColumnCalcs.prototype.initializeBottomRow = function(){
123  if(!this.botInitialized){
124  this.table.footerManager.prepend(this.botElement);
125  this.botInitialized = true;
126  }
127 };
128 
129 
130 ColumnCalcs.prototype.scrollHorizontal = function(left){
131  var hozAdjust = 0,
132  scrollWidth = this.table.columnManager.getElement().scrollWidth - this.table.element.clientWidth;
133 
134  if(this.botInitialized){
135  this.botRow.getElement().style.marginLeft = (-left) + "px";
136  }
137 };
138 
139 
140 ColumnCalcs.prototype.recalc = function(rows){
141  var data, row;
142 
143  if(this.topInitialized || this.botInitialized){
144  data = this.rowsToData(rows);
145 
146  if(this.topInitialized){
147  if(this.topRow){
148  this.topRow.deleteCells();
149  }
150 
151  row = this.generateRow("top", this.rowsToData(rows))
152  this.topRow = row;
153  while(this.topElement.firstChild) this.topElement.removeChild(this.topElement.firstChild);
154  this.topElement.appendChild(row.getElement());
155  row.initialize(true);
156  }
157 
158  if(this.botInitialized){
159  if(this.botRow){
160  this.botRow.deleteCells();
161  }
162 
163  row = this.generateRow("bottom", this.rowsToData(rows))
164  this.botRow = row;
165  while(this.botElement.firstChild) this.botElement.removeChild(this.botElement.firstChild);
166  this.botElement.appendChild(row.getElement());
167  row.initialize(true);
168  }
169 
170  this.table.rowManager.adjustTableSize();
171 
172  //set resizable handles
173  if(this.table.modExists("frozenColumns")){
174  this.table.modules.frozenColumns.layout();
175  }
176  }
177 };
178 
179 ColumnCalcs.prototype.recalcRowGroup = function(row){
180  this.recalcGroup(this.table.modules.groupRows.getRowGroup(row));
181 };
182 
183 ColumnCalcs.prototype.recalcGroup = function(group){
184  var data, rowData;
185 
186  if(group){
187  if(group.calcs){
188  if(group.calcs.bottom){
189  data = this.rowsToData(group.rows);
190  rowData = this.generateRowData("bottom", data);
191 
192  group.calcs.bottom.updateData(rowData);
193  group.calcs.bottom.reinitialize();
194  }
195 
196  if(group.calcs.top){
197  data = this.rowsToData(group.rows);
198  rowData = this.generateRowData("top", data);
199 
200  group.calcs.top.updateData(rowData);
201  group.calcs.top.reinitialize();
202  }
203  }
204  }
205 };
206 
207 
208 
209 //generate top stats row
210 ColumnCalcs.prototype.generateTopRow = function(rows){
211  return this.generateRow("top", this.rowsToData(rows));
212 };
213 //generate bottom stats row
214 ColumnCalcs.prototype.generateBottomRow = function(rows){
215  return this.generateRow("bottom", this.rowsToData(rows));
216 };
217 
218 ColumnCalcs.prototype.rowsToData = function(rows){
219  var data = [];
220 
221  rows.forEach(function(row){
222  data.push(row.getData());
223  });
224 
225  return data;
226 };
227 
228 //generate stats row
229 ColumnCalcs.prototype.generateRow = function(pos, data){
230  var self = this,
231  rowData = this.generateRowData(pos, data),
232  row;
233 
234  if(self.table.modExists("mutator")){
235  self.table.modules.mutator.disable();
236  }
237 
238  row = new Row(rowData, this, "calc");
239 
240  if(self.table.modExists("mutator")){
241  self.table.modules.mutator.enable();
242  }
243 
244  row.getElement().classList.add("tabulator-calcs", "tabulator-calcs-" + pos);
245 
246  row.generateCells = function(){
247 
248  var cells = [];
249 
250  self.table.columnManager.columnsByIndex.forEach(function(column){
251 
252  //set field name of mock column
253  self.genColumn.setField(column.getField());
254  self.genColumn.hozAlign = column.hozAlign;
255 
256  if(column.definition[pos + "CalcFormatter"] && self.table.modExists("format")){
257 
258  self.genColumn.modules.format = {
259  formatter: self.table.modules.format.getFormatter(column.definition[pos + "CalcFormatter"]),
260  params: column.definition[pos + "CalcFormatterParams"]
261  };
262  }else{
263  self.genColumn.modules.format = {
264  formatter: self.table.modules.format.getFormatter("plaintext"),
265  params:{}
266  };
267  }
268 
269  //ensure css class defintion is replicated to calculation cell
270  self.genColumn.definition.cssClass = column.definition.cssClass;
271 
272  //generate cell and assign to correct column
273  var cell = new Cell(self.genColumn, row);
274  cell.column = column;
275  cell.setWidth();
276 
277  column.cells.push(cell);
278  cells.push(cell);
279 
280  if(!column.visible){
281  cell.hide();
282  }
283  });
284 
285  this.cells = cells;
286  }
287 
288  return row;
289 };
290 
291 //generate stats row
292 ColumnCalcs.prototype.generateRowData = function(pos, data){
293  var rowData = {},
294  calcs = pos == "top" ? this.topCalcs : this.botCalcs,
295  type = pos == "top" ? "topCalc" : "botCalc",
296  params, paramKey;
297 
298  calcs.forEach(function(column){
299  var values = [];
300 
301  if(column.modules.columnCalcs && column.modules.columnCalcs[type]){
302  data.forEach(function(item){
303  values.push(column.getFieldValue(item));
304  });
305 
306  paramKey = type + "Params";
307  params = typeof column.modules.columnCalcs[paramKey] === "function" ? column.modules.columnCalcs[paramKey](values, data) : column.modules.columnCalcs[paramKey];
308 
309  column.setFieldValue(rowData, column.modules.columnCalcs[type](values, data, params));
310  }
311  });
312 
313  return rowData;
314 };
315 
316 ColumnCalcs.prototype.hasTopCalcs = function(){
317  return !!(this.topCalcs.length);
318 };
319 
320 ColumnCalcs.prototype.hasBottomCalcs = function(){
321  return !!(this.botCalcs.length);
322 };
323 
324 //handle table redraw
325 ColumnCalcs.prototype.redraw = function(){
326  if(this.topRow){
327  this.topRow.normalizeHeight(true);
328  }
329  if(this.botRow){
330  this.botRow.normalizeHeight(true);
331  }
332 };
333 
334 //return the calculated
335 ColumnCalcs.prototype.getResults = function(){
336  var self = this,
337  results = {},
338  groups;
339 
340  if(this.table.options.groupBy && this.table.modExists("groupRows")){
341  groups = this.table.modules.groupRows.getGroups(true);
342 
343  groups.forEach(function(group){
344  results[group.getKey()] = self.getGroupResults(group);
345  });
346  }else{
347  results = {
348  top: this.topRow ? this.topRow.getData() : {},
349  bottom: this.botRow ? this.botRow.getData() : {},
350  }
351  }
352 
353  return results;
354 }
355 
356 //get results from a group
357 ColumnCalcs.prototype.getGroupResults = function(group){
358  var self = this,
359  groupObj = group._getSelf(),
360  subGroups = group.getSubGroups(),
361  subGroupResults = {},
362  results = {};
363 
364  subGroups.forEach(function(subgroup){
365  subGroupResults[subgroup.getKey()] = self.getGroupResults(subgroup);
366  });
367 
368  results = {
369  top: groupObj.calcs.top ? groupObj.calcs.top.getData() : {},
370  bottom: groupObj.calcs.bottom ? groupObj.calcs.bottom.getData() : {},
371  groups: subGroupResults,
372  }
373 
374  return results;
375 }
376 
377 
378 //default calculations
379 ColumnCalcs.prototype.calculations = {
380  "avg":function(values, data, calcParams){
381  var output = 0,
382  precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : 2
383 
384  if(values.length){
385  output = values.reduce(function(sum, value){
386  value = Number(value);
387  return sum + value;
388  });
389 
390  output = output / values.length;
391 
392  output = precision !== false ? output.toFixed(precision) : output;
393  }
394 
395  return parseFloat(output).toString();
396  },
397  "max":function(values, data, calcParams){
398  var output = null,
399  precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
400 
401  values.forEach(function(value){
402 
403  value = Number(value);
404 
405  if(value > output || output === null){
406  output = value;
407  }
408  });
409 
410  return output !== null ? (precision !== false ? output.toFixed(precision) : output) : "";
411  },
412  "min":function(values, data, calcParams){
413  var output = null,
414  precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
415 
416  values.forEach(function(value){
417 
418  value = Number(value);
419 
420  if(value < output || output === null){
421  output = value;
422  }
423  });
424 
425  return output !== null ? (precision !== false ? output.toFixed(precision) : output) : "";
426  },
427  "sum":function(values, data, calcParams){
428  var output = 0,
429  precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : false;
430 
431  if(values.length){
432  values.forEach(function(value){
433  value = Number(value);
434 
435  output += !isNaN(value) ? Number(value) : 0;
436  });
437  }
438 
439  return precision !== false ? output.toFixed(precision) : output;
440  },
441  "concat":function(values, data, calcParams){
442  var output = 0;
443 
444  if(values.length){
445  output = values.reduce(function(sum, value){
446  return String(sum) + String(value);
447  });
448  }
449 
450  return output;
451  },
452  "count":function(values, data, calcParams){
453  var output = 0;
454 
455  if(values.length){
456  values.forEach(function(value){
457  if(value){
458  output ++;
459  }
460  });
461  }
462 
463  return output;
464  },
465 };
466 
467 
468 
469 Tabulator.prototype.registerModule("columnCalcs", ColumnCalcs);