Skip to content

Commit 774f235

Browse files
committed
feat(pivot-pipes): Add row pipe and pivot data utils
1 parent 27ae40e commit 774f235

File tree

4 files changed

+144
-64
lines changed

4 files changed

+144
-64
lines changed

projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
2222
IgxGridModule,
2323
IgxPivotGridComponent,
2424
IgxPivotRowComponent,
25-
IgxPivotHeaderRowComponent
25+
IgxPivotHeaderRowComponent,
26+
IgxPivotRowPipe,
27+
IgxPivotColumnPipe,
28+
IgxPivotGridFilterPipe
2629
],
2730
imports: [
2831
IgxGridModule,
Lines changed: 122 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import { Pipe, PipeTransform } from '@angular/core';
2-
import { cloneArray } from '../../core/utils';
2+
import { cloneArray, cloneValue } from '../../core/utils';
33
import { DataUtil } from '../../data-operations/data-util';
44
import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
55
import { IFilteringStrategy } from '../../data-operations/filtering-strategy';
6-
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
7-
import { SortingDirection } from '../../data-operations/sorting-expression.interface';
8-
import { DefaultSortingStrategy } from '../../data-operations/sorting-strategy';
9-
import { GridBaseAPIService } from '../api.service';
10-
import { IgxPivotGridComponent } from './pivot-grid.component';
116
import { IPivotDimension, IPivotValue } from './pivot-grid.interface';
127

138
/**
@@ -19,60 +14,22 @@ import { IPivotDimension, IPivotValue } from './pivot-grid.interface';
1914
})
2015
export class IgxPivotRowPipe implements PipeTransform {
2116

22-
constructor(private gridAPI: GridBaseAPIService<IgxPivotGridComponent>) { }
17+
constructor() { }
2318

2419
public transform(
2520
collection: any,
2621
rows: IPivotDimension[],
2722
values?: IPivotValue[]
2823
): any[] {
2924

30-
const result: any[] = collection.slice();
31-
let groupingExpressions: IGroupingExpression[] = [];
3225

33-
// group the data in a way using the rows.member declarations in a groupingComparer
34-
for (const row of rows) {
35-
groupingExpressions = groupingExpressions.concat(this.buildGroupingExpressions(row));
36-
}
37-
38-
// need to extend the grouping and improve the groupingComparer function capabilities
39-
const sorted = DataUtil.sort(result, groupingExpressions);
40-
const groupResult = DataUtil
41-
.group(sorted, { defaultExpanded: true, expansion: [], expressions: groupingExpressions });
42-
43-
// go around the data and aggregate by the specified values, aggregations should be
44-
// stored into the groups
45-
for (const val of values) {
46-
this.applyAggregation(groupResult.data, val);
47-
}
48-
49-
return groupResult.data;
50-
}
51-
52-
private buildGroupingExpressions(row: IPivotDimension): IGroupingExpression[] {
53-
let groupingExpressions: IGroupingExpression[] = [{
54-
fieldName: row.name,
55-
dir: SortingDirection.Asc,
56-
groupingComparer: (a, b) => DefaultSortingStrategy.instance()
57-
.compareValues(row.member.call(this, a), row.member.call(this, b))
58-
}];
59-
if (row.childLevels) {
60-
for (const childRow of row.childLevels) {
61-
groupingExpressions = groupingExpressions.concat(this.buildGroupingExpressions(childRow));
62-
}
63-
}
64-
return groupingExpressions;
65-
}
66-
67-
private applyAggregation(data: any[], val: IPivotValue): void {
68-
for (const record of data) {
69-
if (record.groups) {
70-
this.applyAggregation(record.groups, val);
71-
record[val.member] = val.aggregate(record.records.map(r => r[val.member]));
72-
} else if (record.records) {
73-
record[val.member] = val.aggregate(record.records.map(r => r[val.member]));
74-
}
75-
}
26+
// build hierarchies - groups and subgroups
27+
const hierarchies = PivotUtil.getFieldsHierarchy(collection, rows);
28+
// apply aggregations based on the created groups
29+
PivotUtil.applyAggregations(hierarchies, values);
30+
// generate flat data from the hierarchies
31+
const data = PivotUtil.flattenHierarchy(hierarchies, collection[0] ?? []);
32+
return data;
7633
}
7734
}
7835

@@ -85,15 +42,21 @@ export class IgxPivotRowPipe implements PipeTransform {
8542
})
8643
export class IgxPivotColumnPipe implements PipeTransform {
8744

88-
constructor(private gridAPI: GridBaseAPIService<IgxPivotGridComponent>) { }
89-
9045
public transform(
9146
collection: any,
9247
columns: IPivotDimension[],
9348
values?: IPivotValue[]
9449
): any[] {
95-
return collection;
50+
// build hierarchies - groups and subgroups
51+
const hierarchies = PivotUtil.getFieldsHierarchy(collection, columns);
52+
// apply aggregations based on the created groups
53+
PivotUtil.applyAggregations(hierarchies, values);
54+
// generate column fields based on the hierarchies
55+
56+
return [];
9657
}
58+
59+
9760
}
9861

9962
/**
@@ -105,8 +68,6 @@ export class IgxPivotColumnPipe implements PipeTransform {
10568
})
10669
export class IgxPivotGridFilterPipe implements PipeTransform {
10770

108-
constructor(private gridAPI: GridBaseAPIService<IgxPivotGridComponent>) { }
109-
11071
public transform(collection: any[],
11172
expressionsTree: IFilteringExpressionsTree,
11273
filterStrategy: IFilteringStrategy,
@@ -127,3 +88,107 @@ export class IgxPivotGridFilterPipe implements PipeTransform {
12788
return result;
12889
}
12990
}
91+
92+
export class PivotUtil {
93+
public static getFieldsHierarchy(data: any[], columns: IPivotDimension[]): Map<string, any> {
94+
const hierarchy = new Map<string, any>();
95+
for (const rec of data) {
96+
const vals = this.extractValuesFromDimension(columns, rec);
97+
for (const val of vals) { // this should go in depth also vals.children
98+
if (hierarchy.get(val.value) != null && val.children) {
99+
this.applyHierarchyChildren(hierarchy, val, rec);
100+
} else {
101+
hierarchy.set(val.value, cloneValue(val));
102+
hierarchy.get(val.value).children = new Map<string, any>();
103+
this.applyHierarchyChildren(hierarchy, val, rec);
104+
}
105+
}
106+
}
107+
return hierarchy;
108+
}
109+
110+
public static extractValueFromDimension(dim: IPivotDimension, recData: any) {
111+
return typeof dim.member === 'string' ? recData[dim.member] : dim.member.call(this, recData);
112+
}
113+
114+
public static extractValuesFromDimension(dims: IPivotDimension[], recData: any){
115+
const vals = [];
116+
let i = 0;
117+
for (const col of dims) {
118+
const value = this.extractValueFromDimension(col, recData);
119+
vals.push({ value });
120+
if (col.childLevels != null && col.childLevels.length > 0) {
121+
const childValues = this.extractValuesFromDimension(col.childLevels, recData);
122+
vals[i].children = childValues;
123+
}
124+
i++;
125+
}
126+
return vals;
127+
}
128+
129+
public static applyAggregations(hierarchies, values) {
130+
hierarchies.forEach((hierarchy) => {
131+
const children = hierarchy['children'];
132+
if (children) {
133+
this.applyAggregations(children, values);
134+
const childrenAggregations = this.collectAggregations(children);
135+
hierarchy['aggregations'] = this.aggregate(childrenAggregations, values);
136+
} else if (hierarchy['records']) {
137+
hierarchy['aggregations'] = this.aggregate(hierarchy['records'], values);
138+
}
139+
});
140+
}
141+
142+
public static aggregate(records, values: IPivotValue[]) {
143+
const result = {};
144+
for (const pivotValue of values) {
145+
result[pivotValue.member] = pivotValue.aggregate(records.map(r => r[pivotValue.member]));
146+
}
147+
148+
return result;
149+
}
150+
151+
public static flattenHierarchy(hierarchies, rec) {
152+
let flatData = [];
153+
const field = this.generateFieldValue(rec);
154+
hierarchies.forEach((h, key) => {
155+
let obj = {};
156+
obj[field] = key;
157+
obj['records'] = h['records'];
158+
obj = {...obj, ...h['aggregations']};
159+
flatData.push(obj);
160+
if (h['children']) {
161+
flatData = [...flatData, ...this.flattenHierarchy(h['children'], rec)];
162+
}
163+
});
164+
165+
return flatData;
166+
}
167+
168+
private static generateFieldValue(rec) {
169+
let i = 0;
170+
while (Object.keys(rec).indexOf('field' + ++i) !== -1) {}
171+
return 'field' + i;
172+
}
173+
174+
private static collectAggregations(children) {
175+
const result = [];
176+
children.forEach(value => result.push(value['aggregations']));
177+
178+
return result;
179+
}
180+
181+
private static applyHierarchyChildren(hierarchy, val, rec, recordsKey = 'records') {
182+
for (const child of val.children) {
183+
if (!hierarchy.get(val.value).children.get(child.value)) {
184+
hierarchy.get(val.value).children.set(child.value, child);
185+
}
186+
187+
if (hierarchy.get(val.value).children.get(child.value)[recordsKey]) {
188+
hierarchy.get(val.value).children.get(child.value)[recordsKey].push(rec);
189+
} else {
190+
hierarchy.get(val.value).children.get(child.value)[recordsKey] = [rec];
191+
}
192+
}
193+
}
194+
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<div class="sample-column">
2-
<igx-pivot-grid #grid1 [data]="data" [pivotConfiguration]="pivotConfig">
3-
</igx-pivot-grid>
2+
<!-- <igx-pivot-grid #grid1 [data]="data" [pivotConfiguration]="pivotConfig">
3+
</igx-pivot-grid> -->
4+
5+
<pre>{{origData | gridPivotRow:pivotConfig.rows:pivotConfig.values | json}}</pre>
46
</div>

src/app/pivot-grid/pivot-grid.sample.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,24 @@ export class PivotGridSampleComponent {
1414

1515
public pivotConfig: IPivotConfiguration = {
1616
columns: [{
17-
member: 'Country',
17+
member: () => 'All',
1818
enabled: true,
19-
childLevels:[]
19+
childLevels: [{
20+
member: 'Country',
21+
enabled: true,
22+
childLevels:[]
23+
}]
2024
}],
2125
rows: [{
22-
member: 'ProductCategory',
26+
member: () => 'All',
2327
enabled: true,
24-
childLevels:[]
28+
childLevels:[
29+
{
30+
member: (data) => data.ProductCategory,
31+
enabled: true,
32+
childLevels:[]
33+
}
34+
]
2535
}],
2636
values: [
2737
{

0 commit comments

Comments
 (0)