mleibman / SlickGrid

A lightning fast JavaScript grid/spreadsheet
http://wiki.github.com/mleibman/SlickGrid
MIT License
6.82k stars 1.98k forks source link

Multiple Aggregators on same column of grouping? #1058

Open h4nk2013 opened 9 years ago

h4nk2013 commented 9 years ago

I am not sure if this is a right place to post this, but I am going to go forward with it anyway

I am trying to apply multiple Aggregators on same columns, but I don't think so slick grid currently supoorts it. is there any solution for it ?. Can there be multiple rows for groupTotalsFormatter.

6pac commented 9 years ago

It is supported. Check out http://mleibman.github.io/SlickGrid/examples/example-grouping example source:

function groupByDurationEffortDriven() {
dataView.setGrouping([
{
  getter: "duration",
  formatter :function (g) {
    return "Duration:  " + g.value + "  <span style='color:green'>(" + g.count + " items)</span>";
  },
  aggregators: [
    new Slick.Data.Aggregators.Sum("duration"),
    new Slick.Data.Aggregators.Sum("cost")
  ],
  aggregateCollapsed: true,
  lazyTotalsCalculation: true
},
{
  getter: "effortDriven",
  formatter :function (g) {
    return "Effort-Driven:  " + (g.value ? "True" : "False") + "  <span style='color:green'>(" + g.count + " items)</span>";
  },
  aggregators: [
    new Slick.Data.Aggregators.Avg("percentComplete"),
    new Slick.Data.Aggregators.Sum("cost")
  ],
  collapsed: true,
  lazyTotalsCalculation: true
}
]);

Then use, for example, groupTotalsFormatter: sumTotalsFormatter in the column definition and something like

function sumTotalsFormatter(totals, columnDef) {
  var val = totals.sum && totals.sum[columnDef.field];
  if (val != null) {
    return "total: " + ((Math.round(parseFloat(val)*100)/100));
  }
  return "";
}

to extract and format the aggregator values

h4nk2013 commented 9 years ago

@6pac the sumTotalsFormatter function will just calculate the totals.sum and place 1 row for aggregator for duration. What about the totals.avg ? look at this fiddle http://jsfiddle.net/icoxfog417/Tdha8/

Thanks, for your help.

Adding more details...

I wanted two more different aggregators for same column on the same level.

function groupByDurationEffortDriven() { dataView.setGrouping([ { getter: "duration", formatter :function (g) { return "Duration: " + g.value + " (" + g.count + " items)"; }, aggregators: [ new Slick.Data.Aggregators.Sum("duration"), new Slick.Data.Aggregators.Avg("duration"), new Slick.Data.Aggregators.Min("duration"), new Slick.Data.Aggregators.Max("duration") ], aggregateCollapsed: true, lazyTotalsCalculation: true }, { getter: "effortDriven", formatter :function (g) { return "Effort-Driven: " + (g.value ? "True" : "False") + " (" + g.count + " items)"; }, aggregators: [ new Slick.Data.Aggregators.Avg("percentComplete"), new Slick.Data.Aggregators.Sum("percentComplete") ], collapsed: true, lazyTotalsCalculation: true } ]);

Something like this in case of your example.

Thanks.

6pac commented 9 years ago

BTW, this should probably be asked on StackOverflow (issues are for bugs or feature requests, although I appreciate that it may not be known if this is the case before asking). I think I understand your problem. SlickGrid only gives you one aggregate row per group. You can defined multiple aggregates, but you only have the space in the one column of that row to render the result using the column groupTotalsFormatter property. You may be able to hack something up to 'hijack' other columns in that row for the other aggregate results, but at present multiple aggregate rows is something SlickGrid doesn't offer.

6pac commented 9 years ago

http://jsfiddle.net/Tdha8/106/

h4nk2013 commented 9 years ago

Yes, I thought of that, but it can have many aggregates and in that case the cell may not big enough. So the best solution I think would be have additional row for each aggregate and each column can have this aggregates.

6pac commented 9 years ago

This is not supported out of the box. You could hack slick.dataview.js, the flattenGroupedRows() function. the part that adds the totals row is:

    if (g.totals && gi.displayTotalsRow && (!g.collapsed || gi.aggregateCollapsed)) {
      groupedRows[gl++] = g.totals;
    }

See the calculateTotals() function for an example of getting the GroupInfo.aggregates.length from the Group. You could add a row per aggregate, but then you'd still have the issue of linking a group formatting function to each aggregate-associated row (assuming you wouldn't want to use the same function for each, which would be brittle). It's not a trivial enhancement.

h4nk2013 commented 9 years ago

Thanks @6pac, I will definitely look into that and update it here and there is another solution I thought of is to use tree view but is there any way to ignore sorting for certain rows ? (in this case the aggregate rows that I will be adding) like the aggregate rows behave in case grouping, where they always stay at the bottom of the group.

Thanks, really appreciate your help

6pac commented 9 years ago

Have a look at flattenGroupedRows(). That is responsible for converting the 'tree' view derived from the nested groups' row arrays into the flat view you see on the screen.