Skip to content

Commit 8171830

Browse files
committed
feat(pivotGrid): Implement initial horizontal row dimension expand and merging.
1 parent 5f3dbea commit 8171830

13 files changed

+461
-49
lines changed

projects/igniteui-angular/src/lib/data-operations/pivot-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class PivotRowDimensionsStrategy implements IPivotDimensionStrategy {
3232
rows: IPivotDimension[],
3333
values: IPivotValue[],
3434
cloneStrategy: IDataCloneStrategy,
35-
pivotKeys: IPivotKeys = DEFAULT_PIVOT_KEYS,
35+
pivotKeys: IPivotKeys = DEFAULT_PIVOT_KEYS
3636
): IPivotGridRecord[] {
3737
let hierarchies;
3838
let data: IPivotGridRecord[];

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,13 +1229,16 @@ export interface PivotGridType extends GridType {
12291229
* it includes hierarchical level, filters and sorting, dimentional level, etc.
12301230
*/
12311231
allDimensions: IPivotDimension[],
1232+
horizontalRowDimensions: boolean,
12321233
/** Specifies whether to show the pivot configuration UI in the grid. */
12331234
pivotUI: IPivotUISettings;
12341235
/** @hidden @internal */
12351236
columnDimensions: IPivotDimension[];
12361237
/** @hidden @internal */
12371238
rowDimensions: IPivotDimension[];
12381239
rowDimensionResizing: boolean;
1240+
visibleRowDimensions: IPivotDimension[];
1241+
flattenedRowDimensions: IPivotDimension[];
12391242
/** @hidden @internal */
12401243
values: IPivotValue[];
12411244
/** @hidden @internal */

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</igx-pivot-header-row>
1919

2020
<div igxGridBody (keydown.control.c)="copyHandler($event)" (copy)="copyHandler($event)" class="igx-grid__tbody" role="rowgroup">
21-
<ng-container *ngTemplateOutlet="rowDimensions.length ? defaultRowDimensionsTemplate : emptyRowDimensionsTemplate; context: this"></ng-container>
21+
<ng-container *ngTemplateOutlet="rowDimensions.length ? (horizontalRowDimensions ? horizontalRowDimensionsTemplate : defaultRowDimensionsTemplate) : emptyRowDimensionsTemplate; context: this"></ng-container>
2222
<div class="igx-grid__tbody-content" tabindex="0" [attr.role]="dataView.length ? null : 'row'" (keydown)="navigation.handleNavigation($event)" (focus)="navigation.focusTbody($event)"
2323
(dragStop)="selectionService.dragMode = $event" (scroll)="preventContainerScroll($event)"
2424
(dragScroll)="dragScroll($event)" [igxGridDragSelect]="selectionService.dragMode"
@@ -41,7 +41,7 @@
4141
[igxForContainerSize]="calcHeight"
4242
[igxForItemSize]="hasColumnLayouts ? rowHeight * multiRowLayoutRowSize + 1 : renderedRowHeight"
4343
[igxGridForOfVariableSizes]="false"
44-
#verticalScrollContainer>
44+
#verticalScrollContainer (dataChanging)="dataRebinding($event)" (dataChanged)="dataRebound($event)">
4545
<ng-template
4646
[igxTemplateOutlet]="recordTemplate"
4747
[igxTemplateOutletContext]="getContext(rowData, rowIndex)"
@@ -145,6 +145,43 @@
145145
</ng-template>
146146
</div>
147147
</ng-template>
148+
149+
<ng-template #horizontalRowDimensionsTemplate>
150+
<div tabindex="0" [style.height.px]="totalHeight" (focus)="navigation.focusTbody($event)" (keydown)="navigation.handleNavigation($event)">
151+
<ng-container *ngIf="dataView | pivotGridHorizontalRowGrouping:pivotConfiguration:pipeTrigger as groupedData">
152+
<ng-template #verticalRowDimScrollContainer role="rowgroup" igxGridFor let-rowGroup let-rowIndex="index"
153+
[igxGridForOf]="groupedData"
154+
[igxForScrollOrientation]="'vertical'"
155+
[igxForScrollContainer]="verticalScroll"
156+
[igxForContainerSize]="calcHeight"
157+
[igxForItemSize]="renderedRowHeight"
158+
[igxForSizePropName]="'height'"
159+
>
160+
<div class="igx-grid__tbody-pivot-dimension igx-grid__mrl-block" [ngStyle]="{
161+
'grid-template-rows': getRowMRLTemplate(true, rowGroup),
162+
'grid-template-columns': getRowMRLTemplate(false, rowGroup)
163+
}">
164+
<ng-template ngFor let-cell let-cellIndex="index" [ngForOf]="rowGroup
165+
| pivotGridHorizontalRowCellMerging:pivotConfiguration:pipeTrigger">
166+
<igx-pivot-row-dimension-content role="row" class="igx-grid-thead"
167+
[grid]="this"
168+
[dimension]="cell.rootDimension"
169+
[rootDimension]="cell.rootDimension"
170+
[rowIndex]="calcRowIndex(groupedData, rowIndex, cell)"
171+
[rowData]="cell.records[0]"
172+
[width]="rowDimensionWidthCombined(cell.dimensions)"
173+
[style.grid-row-start]="cell.rowStart"
174+
[style.grid-row-end]="cell.rowStart + cell.rowSpan"
175+
[style.grid-column-start]="cell.colStart"
176+
[style.grid-column-end]="cell.colStart + cell.colSpan">
177+
</igx-pivot-row-dimension-content>
178+
</ng-template>
179+
</div>
180+
</ng-template>
181+
</ng-container>
182+
</div>
183+
</ng-template>
184+
148185
<ng-template #emptyRowDimensionsTemplate>
149186
<div tabindex="0" *ngIf="columnDimensions.length > 0 || values.length > 0" #rowDimensionContainer role="rowgroup" class="igx-grid__tbody-pivot-dimension" (focus)="navigation.focusTbody($event)" (keydown)="navigation.handleNavigation($event)">
150187
<igx-pivot-row-dimension-content role="row" class="igx-grid-thead" [grid]="this"

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

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { IgxForOfSyncService, IgxForOfScrollSyncService } from '../../directives
3737
import { ColumnType, GridType, IGX_GRID_BASE, IgxColumnTemplateContext, RowType } from '../common/grid.interface';
3838
import { IgxGridCRUDService } from '../common/crud.service';
3939
import { IgxGridSummaryService } from '../summaries/grid-summary.service';
40-
import { DEFAULT_PIVOT_KEYS, IDimensionsChange, IgxPivotGridValueTemplateContext, IPivotConfiguration, IPivotConfigurationChangedEventArgs, IPivotDimension, IPivotValue, IValuesChange, PivotDimensionType, IPivotUISettings } from './pivot-grid.interface';
40+
import { DEFAULT_PIVOT_KEYS, IDimensionsChange, IgxPivotGridValueTemplateContext, IPivotConfiguration, IPivotConfigurationChangedEventArgs, IPivotDimension, IPivotValue, IValuesChange, PivotDimensionType, IPivotUISettings, IPivotGridRecord, IPivotGridHorizontalGroup } from './pivot-grid.interface';
4141
import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
4242
import { IgxColumnGroupComponent } from '../columns/column-group.component';
4343
import { IgxColumnComponent } from '../columns/column.component';
@@ -73,7 +73,7 @@ import { DataUtil } from '../../data-operations/data-util';
7373
import { IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
7474
import { IgxGridTransaction } from '../common/types';
7575
import { GridBaseAPIService } from '../api.service';
76-
import { IgxGridForOfDirective } from '../../directives/for-of/for_of.directive';
76+
import { IForOfDataChangingEventArgs, IgxGridForOfDirective } from '../../directives/for-of/for_of.directive';
7777
import { IgxPivotRowDimensionContentComponent } from './pivot-row-dimension-content.component';
7878
import { IgxPivotGridColumnResizerComponent } from '../resizing/pivot-grid/pivot-resizer.component';
7979
import { IgxActionStripToken } from '../../action-strip/token';
@@ -83,7 +83,7 @@ import { IFilteringStrategy } from '../../data-operations/filtering-strategy';
8383
import { IgxPivotRowDimensionHeaderTemplateDirective, IgxPivotValueChipTemplateDirective } from './pivot-grid.directives';
8484
import { IFilteringOperation } from '../../data-operations/filtering-condition';
8585
import { IgxGridValidationService } from '../grid/grid-validation.service';
86-
import { IgxPivotRowPipe, IgxPivotRowExpansionPipe, IgxPivotAutoTransform, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, IgxPivotCellMergingPipe } from './pivot-grid.pipes';
86+
import { IgxPivotRowPipe, IgxPivotRowExpansionPipe, IgxPivotAutoTransform, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, IgxPivotCellMergingPipe, IgxPivotGridHorizontalRowGrouping, IgxPivotGridHorizontalRowCellMerging } from './pivot-grid.pipes';
8787
import { IgxGridRowClassesPipe, IgxGridRowStylesPipe } from '../common/pipes';
8888
import { IgxExcelStyleSearchComponent } from '../filtering/excel-style/excel-style-search.component';
8989
import { IgxIconComponent } from '../../icon/icon.component';
@@ -174,7 +174,9 @@ const MINIMUM_COLUMN_WIDTH_SUPER_COMPACT = 104;
174174
IgxPivotGridFilterPipe,
175175
IgxPivotGridSortingPipe,
176176
IgxPivotGridColumnSortingPipe,
177-
IgxPivotCellMergingPipe
177+
IgxPivotCellMergingPipe,
178+
IgxPivotGridHorizontalRowGrouping,
179+
IgxPivotGridHorizontalRowCellMerging
178180
],
179181
schemas: [CUSTOM_ELEMENTS_SCHEMA]
180182
})
@@ -306,6 +308,9 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
306308
@Input()
307309
public rowDimensionHeaderTemplate: TemplateRef<IgxColumnTemplateContext>;
308310

311+
@Input()
312+
public horizontalRowDimensions = false;
313+
309314
@Input()
310315
/**
311316
* Gets/Sets the pivot configuration with all related dimensions and values.
@@ -608,7 +613,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
608613
/** @hidden @internal */
609614
public columnGroupStates = new Map<string, boolean>();
610615
/** @hidden @internal */
611-
public dimensionDataColumns;
616+
public dimensionDataColumns: any[];
612617
/** @hidden @internal */
613618
public get pivotKeys() {
614619
return this.pivotConfiguration.pivotKeys || DEFAULT_PIVOT_KEYS;
@@ -650,6 +655,8 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
650655
private _superCompactMode = false;
651656
private _pivotUI: IPivotUISettings = { showConfiguration: true, showRowHeaders: false };
652657
private _sortableColumns = true;
658+
private _visibleRowDimensions: IPivotDimension[] = [];
659+
private _flattenedRowDimensions: IPivotDimension[] = [];
653660

654661
/**
655662
* Gets/Sets the default expand state for all rows.
@@ -1062,6 +1069,14 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
10621069
return (config.rows || []).concat((config.columns || [])).concat(config.filters || []).filter(x => x !== null && x !== undefined);
10631070
}
10641071

1072+
public get allVisibleDimensions() {
1073+
const config = this._pivotConfiguration;
1074+
const uniqueVisibleRowDims = this.visibleRowDimensions.filter(dim => !config.rows.find(configRow => configRow.memberName === dim.memberName));
1075+
const rows = (config.rows || []).concat(...uniqueVisibleRowDims);
1076+
if (!config) return [];
1077+
return rows.concat((config.columns || [])).concat(config.filters || []).filter(x => x !== null && x !== undefined);
1078+
}
1079+
10651080
/** @hidden @internal */
10661081
public createFilterESF(dropdown: any, column: ColumnType, options: OverlaySettings, shouldReatach: boolean) {
10671082
options.outlet = this.outlet;
@@ -1151,7 +1166,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
11511166
* @hidden @internal
11521167
*/
11531168
public get pivotRowWidths() {
1154-
return this.rowDimensions.length ? this.rowDimensions.reduce((accumulator, dim) => accumulator + this.rowDimensionWidthToPixels(dim), 0) :
1169+
return this.visibleRowDimensions.length ? this.visibleRowDimensions.reduce((accumulator, dim) => accumulator + this.rowDimensionWidthToPixels(dim), 0) :
11551170
this.rowDimensionWidthToPixels(this.emptyRowDimension);
11561171
}
11571172

@@ -1189,6 +1204,14 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
11891204
}
11901205
}
11911206

1207+
public rowDimensionWidthCombined(dims: IPivotDimension[]) {
1208+
let resWidth = 0;
1209+
for (const dim of dims) {
1210+
resWidth += this.rowDimensionWidthToPixels(dim);
1211+
}
1212+
return resWidth;
1213+
}
1214+
11921215
/**
11931216
* @hidden @internal
11941217
*/
@@ -1219,6 +1242,22 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
12191242
return this.pivotConfiguration.rows?.filter(x => x.enabled) || [];
12201243
}
12211244

1245+
/** @hidden @internal */
1246+
public set visibleRowDimensions(value: IPivotDimension[]) {
1247+
this._visibleRowDimensions = value;
1248+
}
1249+
1250+
public get visibleRowDimensions() {
1251+
return this._visibleRowDimensions || this.rowDimensions;
1252+
}
1253+
1254+
public get flattenedRowDimensions() {
1255+
if (this.rowDimensions.length > 0 && this._flattenedRowDimensions.length === 0) {
1256+
this._flattenedRowDimensions = this.flattenRowDimensions();
1257+
}
1258+
return this._flattenedRowDimensions;
1259+
}
1260+
12221261
/** @hidden @internal */
12231262
public get columnDimensions() {
12241263
return this.pivotConfiguration.columns?.filter(x => x.enabled) || [];
@@ -1538,6 +1577,17 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
15381577
super.setupColumns();
15391578
}
15401579

1580+
/**
1581+
* @hidden @internal
1582+
*/
1583+
public override dataRebinding(event: IForOfDataChangingEventArgs) {
1584+
super.dataRebinding(event);
1585+
1586+
if (this.horizontalRowDimensions) {
1587+
this.setupColumns();
1588+
}
1589+
}
1590+
15411591
/**
15421592
* Auto-sizes row dimension cells.
15431593
*
@@ -2026,6 +2076,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
20262076
}
20272077
columns = this.generateColumnHierarchy(fieldsMap, sortedData);
20282078
this._autoGeneratedCols = columns;
2079+
this._flattenedRowDimensions = this.flattenRowDimensions();
20292080
// reset expansion states if any are stored.
20302081
this.columnGroupStates.forEach((value, key) => {
20312082
if (value) {
@@ -2046,9 +2097,21 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
20462097
}
20472098

20482099

2100+
protected flattenRowDimensions(): IPivotDimension[] {
2101+
const res = [];
2102+
for (let i = 0; i < this.rowDimensions.length; i++) {
2103+
let curLevelDim = this.rowDimensions[i];
2104+
do {
2105+
res.push(curLevelDim);
2106+
curLevelDim = curLevelDim.childLevel;
2107+
} while (curLevelDim);
2108+
};
2109+
return res;
2110+
}
2111+
20492112
protected generateDimensionColumns(): IgxColumnComponent[] {
20502113
const columns = [];
2051-
this.allDimensions.forEach((dim) => {
2114+
this.allVisibleDimensions.forEach((dim) => {
20522115
const ref = createComponent(IgxColumnComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
20532116
ref.instance.field = dim.memberName;
20542117
ref.instance.header = dim.displayName || dim.memberName;
@@ -2341,12 +2404,33 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
23412404
}
23422405

23432406
protected rowDimensionByName(memberName: string) {
2344-
return this.rowDimensions.find((rowDim) => rowDim.memberName === memberName);
2407+
return this.visibleRowDimensions.find((rowDim) => rowDim.memberName === memberName);
23452408
}
23462409

23472410
protected calculateResizerTop() {
23482411
return this.pivotUI.showRowHeaders ?
23492412
(this.theadRow.pivotFilterContainer?.nativeElement.offsetHeight || 0) + (this.theadRow.pivotRowContainer?.nativeElement.offsetHeight || 0) :
23502413
this.theadRow.nativeElement.offsetHeight;
23512414
}
2415+
2416+
protected getRowMRLTemplate(forRows: boolean, rows: IPivotGridRecord[]) {
2417+
if (forRows) {
2418+
return `repeat(${rows.length},1fr)`;
2419+
} else if (this.visibleRowDimensions && this.dimensionDataColumns) {
2420+
const res = [];
2421+
this.visibleRowDimensions.forEach(dim => {
2422+
const targetCol = this.dimensionDataColumns.find(col => col.field === dim.memberName);
2423+
res.push(targetCol.calcWidth);
2424+
});
2425+
return res.join(' ');
2426+
}
2427+
}
2428+
2429+
protected calcRowIndex(groupedData: IPivotGridRecord[][], rowIndex: number, cell: IPivotGridHorizontalGroup) {
2430+
let prevRows = 0;
2431+
for(let i = 0; i < rowIndex; i++) {
2432+
prevRows += groupedData[i].length;
2433+
}
2434+
return prevRows + (cell.rowStart - 1);
2435+
}
23522436
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ export interface IPivotDimensionStrategy {
4848
dimensions: IPivotDimension[],
4949
values: IPivotValue[],
5050
cloneStrategy: IDataCloneStrategy,
51-
pivotKeys?: IPivotKeys): any[];
51+
pivotKeys?: IPivotKeys,
52+
horizontalRendering?: boolean): any[];
5253
}
5354

5455
/**
@@ -132,6 +133,7 @@ export interface IPivotDimension {
132133
level?: number;
133134
/** hidden */
134135
autoWidth?: number;
136+
horizontalSummary? : boolean;
135137
}
136138
/**
137139
* Configuration of a pivot value aggregation.
@@ -225,6 +227,11 @@ export interface PivotRowHeaderGroupType {
225227
grid: any;
226228
}
227229

230+
export interface DimensionValueType {
231+
value: string;
232+
children: Map<string, string | DimensionValueType>;
233+
}
234+
228235
export interface IPivotGridRecord {
229236
/** Gets/Sets the group value associated with the related row dimension by its memberName. **/
230237
dimensionValues: Map<string, string>;
@@ -238,13 +245,26 @@ export interface IPivotGridRecord {
238245
level?: number;
239246
/** List of dimensions associated with the record.**/
240247
dimensions: IPivotDimension[];
248+
/** Describes if this is a total record for a dimension */
249+
totalRecord?: boolean;
241250
}
242251

243252
export interface IPivotGridGroupRecord extends IPivotGridRecord {
244253
height?: number;
245254
rowSpan?: number;
246255
}
247256

257+
export interface IPivotGridHorizontalGroup {
258+
value?: string;
259+
rootDimension?: IPivotDimension;
260+
dimensions?: IPivotDimension[];
261+
records?: IPivotGridRecord[];
262+
rowStart?: number;
263+
rowSpan?: number;
264+
colStart?: number;
265+
colSpan?: number;
266+
}
267+
248268
export interface IgxPivotGridValueTemplateContext {
249269
$implicit: IPivotValue;
250270
}

0 commit comments

Comments
 (0)