Skip to content

Commit 238fcc4

Browse files
authored
Merge pull request #10230 from IgniteUI/dkamburov/pivot-multi-row-dimensions
feat(pivot): Initial implementation of multi row dimensions
2 parents 0d6cd12 + eabb79c commit 238fcc4

File tree

7 files changed

+258
-136
lines changed

7 files changed

+258
-136
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { GridType } from '../common/grid.interface';
1818
import { IgxGridNavigationService } from '../grid-navigation.service';
1919
import { IgxGridCRUDService } from '../common/crud.service';
2020
import { IgxGridSummaryService } from '../summaries/grid-summary.service';
21-
import { IPivotConfiguration, IPivotDimension } from './pivot-grid.interface';
21+
import { IPivotConfiguration, PivotDimensionType } from './pivot-grid.interface';
2222
import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
2323
import { IgxColumnGroupComponent } from '../columns/column-group.component';
2424
import { IgxColumnComponent } from '../columns/column.component';
@@ -252,6 +252,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
252252
const fieldsMap = PivotUtil.getFieldsHierarchy(
253253
data,
254254
this.pivotConfiguration.columns,
255+
PivotDimensionType.Column,
255256
{aggregations: 'aggregations', records: 'records', children: 'children', level: 'level'}
256257
);
257258
const columns = this.generateColumnHierarchy(fieldsMap, data);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ export interface IPivotKeys {
3333
aggregations: string;
3434
level: string;
3535
}
36+
37+
export enum PivotDimensionType {
38+
Row,
39+
Column
40+
}

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

Lines changed: 112 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ describe('Pivot pipes', () => {
5353
const columnPipeResult = columnPipe.transform(rowPipeResult, pivotConfigHierarchy.columns, pivotConfigHierarchy.values);
5454
expect(columnPipeResult).toEqual([
5555
{
56-
field1: 'All', All: 2127, Bulgaria: 774, USA: 829, Uruguay: 524, level: 0, records: [
57-
{ field1: 'Clothing', All: 1526, Bulgaria: 774, USA: 296, Uruguay: 456, level: 1 },
58-
{ field1: 'Bikes', All: 68, Uruguay: 68, level: 1 },
59-
{ field1: 'Accessories', All: 293, USA: 293, level: 1 },
60-
{ field1: 'Components', All: 240, USA: 240, level: 1 }
56+
field1: 'All', All: 2127, 'All-Bulgaria': 774, 'All-USA': 829, 'All-Uruguay': 524, level: 0, records: [
57+
{ field1: 'Clothing', All: 1526, 'All-Bulgaria': 774,'All-USA': 296,'All-Uruguay': 456, level: 1 },
58+
{ field1: 'Bikes', All: 68, 'All-Uruguay': 68, level: 1 },
59+
{ field1: 'Accessories', All: 293, 'All-USA': 293, level: 1 },
60+
{ field1: 'Components', All: 240, 'All-USA': 240, level: 1 }
6161
]
6262
},
63-
{ field1: 'Clothing', All: 1526, Bulgaria: 774, USA: 296, Uruguay: 456, level: 1 },
64-
{ field1: 'Bikes', All: 68, Uruguay: 68, level: 1 },
65-
{ field1: 'Accessories', All: 293, USA: 293, level: 1 },
66-
{ field1: 'Components', All: 240, USA: 240, level: 1 }
63+
{ field1: 'Clothing', All: 1526, 'All-Bulgaria': 774,'All-USA': 296,'All-Uruguay': 456, level: 1 },
64+
{ field1: 'Bikes', All: 68, 'All-Uruguay': 68, level: 1 },
65+
{ field1: 'Accessories', All: 293, 'All-USA': 293, level: 1 },
66+
{ field1: 'Components', All: 240, 'All-USA': 240, level: 1 }
6767
]);
6868
});
6969

@@ -99,10 +99,10 @@ describe('Pivot pipes', () => {
9999
]);
100100
const columnPipeResult = columnPipe.transform(rowPipeResult, pivotConfigHierarchy.columns, pivotConfigHierarchy.values);
101101
expect(columnPipeResult).toEqual([
102-
{ ProductCategory: 'Clothing', All: 1526, Bulgaria: 774, USA: 296, Uruguay: 456, level: 0 },
103-
{ ProductCategory: 'Bikes', All: 68, Uruguay: 68, level: 0 },
104-
{ ProductCategory: 'Accessories', All: 293, USA: 293, level: 0 },
105-
{ ProductCategory: 'Components', All: 240, USA: 240, level: 0 }
102+
{ ProductCategory: 'Clothing', All: 1526, 'All-Bulgaria': 774, 'All-USA': 296, 'All-Uruguay': 456, level: 0 },
103+
{ ProductCategory: 'Bikes', All: 68, 'All-Uruguay': 68, level: 0 },
104+
{ ProductCategory: 'Accessories', All: 293, 'All-USA': 293, level: 0 },
105+
{ ProductCategory: 'Components', All: 240, 'All-USA': 240, level: 0 }
106106
]);
107107
});
108108

@@ -212,65 +212,123 @@ describe('Pivot pipes', () => {
212212
]);
213213
});
214214

215-
xit('transforms flat data to pivot data multiple row dimensions', () => {
215+
it('transforms flat data to pivot data multiple row dimensions', () => {
216216
const rowPipeResult = rowPipe.transform(data, [{
217217
member: 'ProductCategory',
218218
enabled: true,
219219
childLevels: []
220220
},
221221
{
222-
member: Date,
222+
member: 'Date',
223223
enabled: true,
224224
childLevels: []
225225
}], expansionStates, pivotConfigHierarchy.values);
226226

227227
expect(rowPipeResult).toEqual([
228228
{
229-
ProductCategory: 'Clothing', level: 0, children: [
230-
{ Date: '01/01/2021', records: [
231-
{ ProductCategory: 'Clothing', UnitPrice: 12.81, SellerName: 'Stanley', Country: 'Bulgaria', Date: '01/01/2021', UnitsSold: 282 }
232-
]},
233-
{ Date: '01/05/2019', records: [
234-
{ ProductCategory: 'Clothing', UnitPrice: 49.57, SellerName: 'Elisa', Country: 'USA', Date: '01/05/2019', UnitsSold: 296 }
235-
]},
236-
{ Date: '05/12/2020', records: [
237-
{ ProductCategory: 'Clothing', UnitPrice: 68.33, SellerName: 'Larry', Country: 'Uruguay', Date: '05/12/2020', UnitsSold: 456 }
238-
]},
239-
{ Date: '02/19/2020', records: [
240-
{ ProductCategory: 'Clothing', UnitPrice: 16.05, SellerName: 'Walter', Country: 'Bulgaria', Date: '02/19/2020', UnitsSold: 492 }
241-
]},
242-
], records: [
243-
{ ProductCategory: 'Clothing', UnitPrice: 12.81, SellerName: 'Stanley', Country: 'Bulgaria', Date: '01/01/2021', UnitsSold: 282 },
244-
{ ProductCategory: 'Clothing', UnitPrice: 49.57, SellerName: 'Elisa', Country: 'USA', Date: '01/05/2019', UnitsSold: 296 },
245-
{ ProductCategory: 'Clothing', UnitPrice: 68.33, SellerName: 'Larry', Country: 'Uruguay', Date: '05/12/2020', UnitsSold: 456 },
246-
{ ProductCategory: 'Clothing', UnitPrice: 16.05, SellerName: 'Walter', Country: 'Bulgaria', Date: '02/19/2020', UnitsSold: 492 }]
229+
Date: '01/01/2021',
230+
records: [
231+
{
232+
ProductCategory: 'Clothing',
233+
UnitPrice: 12.81,
234+
SellerName: 'Stanley',
235+
Country: 'Bulgaria',
236+
Date: '01/01/2021',
237+
UnitsSold: 282
238+
}
239+
],
240+
level: 0,
241+
ProductCategory: 'Clothing'
247242
},
248243
{
249-
ProductCategory: 'Bikes', level: 0, children: [
250-
{Date: '01/06/2020', records: [
251-
{ ProductCategory: 'Bikes', UnitPrice: 3.56, SellerName: 'Lydia', Country: 'Uruguay', Date: '01/06/2020', UnitsSold: 68 }
252-
]}
253-
], records: [
254-
{ ProductCategory: 'Bikes', UnitPrice: 3.56, SellerName: 'Lydia', Country: 'Uruguay', Date: '01/06/2020', UnitsSold: 68 }
255-
]
244+
Date: '01/05/2019',
245+
records: [
246+
{
247+
ProductCategory: 'Clothing',
248+
UnitPrice: 49.57,
249+
SellerName: 'Elisa',
250+
Country: 'USA',
251+
Date: '01/05/2019',
252+
UnitsSold: 296
253+
}
254+
],
255+
level: 0,
256+
ProductCategory: 'Clothing'
256257
},
257258
{
258-
ProductCategory: 'Accessories', level: 0, children: [
259-
{ Date: '04/07/2021', records: [
260-
{ ProductCategory: 'Accessories', UnitPrice: 85.58, SellerName: 'David', Country: 'USA', Date: '04/07/2021', UnitsSold: 293 }
261-
]}
262-
], records: [
263-
{ ProductCategory: 'Accessories', UnitPrice: 85.58, SellerName: 'David', Country: 'USA', Date: '04/07/2021', UnitsSold: 293 }
264-
]
259+
Date: '05/12/2020',
260+
records: [
261+
{
262+
ProductCategory: 'Clothing',
263+
UnitPrice: 68.33,
264+
SellerName: 'Larry',
265+
Country: 'Uruguay',
266+
Date: '05/12/2020',
267+
UnitsSold: 456
268+
}
269+
],
270+
level: 0,
271+
ProductCategory: 'Clothing'
265272
},
266273
{
267-
ProductCategory: 'Components', level: 0, children: [
268-
{ Date: '12/08/2021', records: [
269-
{ ProductCategory: 'Components', UnitPrice: 18.13, SellerName: 'John', Country: 'USA', Date: '12/08/2021', UnitsSold: 240 }
270-
]}
271-
], records: [
272-
{ ProductCategory: 'Components', UnitPrice: 18.13, SellerName: 'John', Country: 'USA', Date: '12/08/2021', UnitsSold: 240 }
273-
]
274+
Date: '02/19/2020',
275+
records: [
276+
{
277+
ProductCategory: 'Clothing',
278+
UnitPrice: 16.05,
279+
SellerName: 'Walter',
280+
Country: 'Bulgaria',
281+
Date: '02/19/2020',
282+
UnitsSold: 492
283+
}
284+
],
285+
level: 0,
286+
ProductCategory: 'Clothing'
287+
},
288+
{
289+
Date: '01/06/2020',
290+
records: [
291+
{
292+
ProductCategory: 'Bikes',
293+
UnitPrice: 3.56,
294+
SellerName: 'Lydia',
295+
Country: 'Uruguay',
296+
Date: '01/06/2020',
297+
UnitsSold: 68
298+
}
299+
],
300+
level: 0,
301+
ProductCategory: 'Bikes'
302+
},
303+
{
304+
Date: '04/07/2021',
305+
records: [
306+
{
307+
ProductCategory: 'Accessories',
308+
UnitPrice: 85.58,
309+
SellerName: 'David',
310+
Country: 'USA',
311+
Date: '04/07/2021',
312+
UnitsSold: 293
313+
}
314+
],
315+
level: 0,
316+
ProductCategory: 'Accessories'
317+
},
318+
{
319+
Date: '12/08/2021',
320+
records: [
321+
{
322+
ProductCategory: 'Components',
323+
UnitPrice: 18.13,
324+
SellerName: 'John',
325+
Country: 'USA',
326+
Date: '12/08/2021',
327+
UnitsSold: 240
328+
}
329+
],
330+
level: 0,
331+
ProductCategory: 'Components'
274332
}
275333
]);
276334
});

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

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { cloneArray } 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 { IPivotDimension, IPivotKeys, IPivotValue } from './pivot-grid.interface';
6+
import { IPivotDimension, IPivotKeys, IPivotValue, PivotDimensionType } from './pivot-grid.interface';
77
import { PivotUtil } from './pivot-util';
88

99
/**
@@ -22,14 +22,39 @@ export class IgxPivotRowPipe implements PipeTransform {
2222
rows: IPivotDimension[],
2323
expansionStates: Map<any, boolean>,
2424
values?: IPivotValue[],
25-
pivotKeys: IPivotKeys = {aggregations: 'aggregations', records: 'records', children: 'children', level: 'level'}
25+
pivotKeys: IPivotKeys =
26+
{ aggregations: 'aggregations', records: 'records', children: 'children', level: 'level'}
2627
): any[] {
27-
// build hierarchies - groups and subgroups
28-
const hierarchies = PivotUtil.getFieldsHierarchy(collection, rows, pivotKeys);
29-
// apply aggregations based on the created groups
30-
// PivotUtil.applyAggregations(hierarchies, values, pivotKeys);
31-
// generate flat data from the hierarchies
32-
const data = PivotUtil.flattenHierarchy(hierarchies, collection[0] ?? [], rows, pivotKeys, 0, expansionStates, true);
28+
let hierarchies;
29+
let data;
30+
for (const row of rows) {
31+
if (!data) {
32+
// build hierarchies - groups and subgroups
33+
hierarchies = PivotUtil.getFieldsHierarchy(collection, [row], PivotDimensionType.Row, pivotKeys);
34+
// generate flat data from the hierarchies
35+
data = PivotUtil.flattenHierarchy(hierarchies, collection[0] ?? [], pivotKeys, 0, expansionStates, true);
36+
} else {
37+
const newData = [...data];
38+
for (let i = 0; i < newData.length; i++) {
39+
const hierarchyFields = PivotUtil
40+
.getFieldsHierarchy(newData[i][pivotKeys.records], [row], PivotDimensionType.Row, pivotKeys);
41+
const siblingData = PivotUtil
42+
.flattenHierarchy(hierarchyFields, newData[i] ?? [], pivotKeys, 0, expansionStates, true);
43+
for (const property in newData[i]) {
44+
if (newData[i].hasOwnProperty(property) &&
45+
Object.keys(pivotKeys).indexOf(property) === -1) {
46+
siblingData.forEach(s => {
47+
s[property] = newData[i][property];
48+
s[pivotKeys.level] = newData[i][pivotKeys.level];
49+
});
50+
}
51+
}
52+
newData.splice(i , 1, ...siblingData);
53+
i += siblingData.length - 1;
54+
}
55+
data = newData;
56+
}
57+
}
3358
return data;
3459
}
3560
}
@@ -47,7 +72,8 @@ export class IgxPivotColumnPipe implements PipeTransform {
4772
collection: any,
4873
columns: IPivotDimension[],
4974
values?: IPivotValue[],
50-
pivotKeys: IPivotKeys = {aggregations: 'aggregations', records: 'records', children: 'children', level: 'level'}
75+
pivotKeys: IPivotKeys =
76+
{ aggregations: 'aggregations', records: 'records', children: 'children', level: 'level' }
5177
): any[] {
5278
// build hierarchies - groups and subgroups by columns
5379
const result = [];
@@ -58,7 +84,7 @@ export class IgxPivotColumnPipe implements PipeTransform {
5884
let flatCols = {};
5985
PivotUtil.flattenColumnHierarchy(hierarchy[pivotKeys.children], values, pivotKeys).forEach(o => {
6086
delete o[pivotKeys.records];
61-
flatCols = {...flatCols, ...o};
87+
flatCols = { ...flatCols, ...o };
6288
});
6389
delete hierarchy[pivotKeys.children]; /* or we can keep it
6490
and use when creating the columns in pivot grid instead of recreating it */
@@ -84,7 +110,7 @@ export class IgxPivotColumnPipe implements PipeTransform {
84110
this.groupColumns(children, columns, values, pivotKeys);
85111
} else if (hierarchy[pivotKeys.records]) {
86112
const leafRecords = this.getLeafs(hierarchy[pivotKeys.records], pivotKeys);
87-
hierarchy[pivotKeys.children] = PivotUtil.getFieldsHierarchy(leafRecords, columns, pivotKeys);
113+
hierarchy[pivotKeys.children] = PivotUtil.getFieldsHierarchy(leafRecords, columns, PivotDimensionType.Column, pivotKeys);
88114
PivotUtil.applyAggregations(hierarchy[pivotKeys.children], values, pivotKeys);
89115
}
90116
}

0 commit comments

Comments
 (0)