@lumeer/pivot 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/lmr-pivot-table.component.mjs +12 -6
- package/esm2022/lib/lmr-pivot-table.module.mjs +12 -3
- package/esm2022/lib/lmr-simple-pivot-table.component.mjs +98 -0
- package/esm2022/lib/util/lmr-pivot-config.mjs +1 -1
- package/esm2022/lib/util/lmr-pivot-data.mjs +1 -1
- package/esm2022/lib/util/lmr-simple-pivot-config.mjs +2 -0
- package/esm2022/lib/util/pivot-data-converter.mjs +20 -15
- package/esm2022/lib/util/pivot-table-converter.mjs +237 -65
- package/esm2022/public-api.mjs +4 -2
- package/fesm2022/lumeer-pivot.mjs +370 -86
- package/fesm2022/lumeer-pivot.mjs.map +1 -1
- package/lib/lmr-pivot-table.component.d.ts +5 -3
- package/lib/lmr-pivot-table.module.d.ts +8 -6
- package/lib/lmr-simple-pivot-table.component.d.ts +32 -0
- package/lib/util/lmr-pivot-config.d.ts +26 -5
- package/lib/util/lmr-pivot-data.d.ts +23 -7
- package/lib/util/lmr-simple-pivot-config.d.ts +9 -0
- package/lib/util/pivot-data-converter.d.ts +1 -1
- package/lib/util/pivot-table-converter.d.ts +13 -3
- package/lumeer-pivot-0.0.5.tgz +0 -0
- package/package.json +3 -2
- package/public-api.d.ts +3 -1
- package/lumeer-pivot-0.0.2.tgz +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Directive, Pipe, Injectable, EventEmitter, TemplateRef, Component, ChangeDetectionStrategy, Input, Output, ContentChild, NgModule } from '@angular/core';
|
|
3
|
-
import { cleanQueryAttribute, DataAggregator, UnknownConstraint, ConstraintType, attributesResourcesAttributesMap, aggregateDataResources, AttributesResourceType, dataAggregationConstraint, DataAggregationType, PercentageConstraint, aggregateDataValues, isValueAggregation, NumberConstraint } from '@lumeer/data-filters';
|
|
3
|
+
import { cleanQueryAttribute, DataAggregator, UnknownConstraint, ConstraintType, attributesResourcesAttributesMap, aggregateDataResources, AttributesResourceType, dataAggregationConstraint, DataAggregationType, PercentageConstraint, aggregateDataValues, isValueAggregation, NumberConstraint, generateId, LanguageTag } from '@lumeer/data-filters';
|
|
4
4
|
import { deepObjectsEquals, hex2rgba, isArray, isNotNullOrUndefined, flattenMatrix, uniqueValues, flattenValues, shadeColor, deepObjectCopy, isNullOrUndefined, isNumeric, toNumber } from '@lumeer/utils';
|
|
5
5
|
import { BehaviorSubject, filter, throttleTime, asyncScheduler, map, tap } from 'rxjs';
|
|
6
6
|
import * as i1 from '@angular/common';
|
|
7
7
|
import { CommonModule } from '@angular/common';
|
|
8
|
+
import { ScrollingModule } from '@angular/cdk/scrolling';
|
|
8
9
|
|
|
9
10
|
var LmrPivotConfigVersion;
|
|
10
11
|
(function (LmrPivotConfigVersion) {
|
|
@@ -140,7 +141,8 @@ class PivotDataConverter {
|
|
|
140
141
|
const pivotConstraint = aggregatorAttribute.data && aggregatorAttribute.data;
|
|
141
142
|
const overrideConstraint = pivotConstraint && this.transform?.checkValidConstraintOverride?.(constraint, pivotConstraint);
|
|
142
143
|
const finalConstraint = overrideConstraint || constraint || new UnknownConstraint();
|
|
143
|
-
|
|
144
|
+
const serializedValue = (constraint || new UnknownConstraint()).createDataValue(value, constraintData).serialize();
|
|
145
|
+
return this.formatDataValue(finalConstraint.createDataValue(serializedValue, constraintData), finalConstraint);
|
|
144
146
|
}
|
|
145
147
|
formatDataValue(dataValue, constraint) {
|
|
146
148
|
switch (constraint.type) {
|
|
@@ -226,14 +228,14 @@ class PivotDataConverter {
|
|
|
226
228
|
const filteredValueAttributes = (config.valueAttributes || []).filter(valueAttr => !mergedValueAttributes.some(merAttr => deepObjectsEquals(valueAttr, merAttr)));
|
|
227
229
|
mergedValueAttributes.push(...filteredValueAttributes);
|
|
228
230
|
if (!additionalData) {
|
|
231
|
+
const rowSticky = this.mapStickyValues((config.rowAttributes || []).map(attr => attr.sticky));
|
|
232
|
+
const columnSticky = this.mapStickyValues((config.columnAttributes || []).map(attr => attr.sticky));
|
|
229
233
|
additionalData = {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
rowsConfig: (config.rowAttributes || []).map((attr, index) => ({ showSums: attr.showSums, sort: attr.sort, expressions: attr.expressions, sticky: rowSticky[index] })),
|
|
235
|
+
columnsConfig: (config.columnAttributes || []).map((attr, index) => ({ showSums: attr.showSums, sort: attr.sort, expressions: attr.expressions, sticky: columnSticky[index] })),
|
|
236
|
+
rowShowHeaderAttributes: (config.rowAttributes || []).map(attr => attr.showHeader),
|
|
233
237
|
rowAttributes: (config.rowAttributes || []).map(attr => this.pivotAttributeAttribute(attr)),
|
|
234
|
-
|
|
235
|
-
columnSticky: this.mapStickyValues((config.columnAttributes || []).map(attr => !!attr.sticky)),
|
|
236
|
-
columnSorts: (config.columnAttributes || []).map(attr => attr.sort),
|
|
238
|
+
columnShowHeaderAttributes: (config.columnAttributes || []).map(attr => false),
|
|
237
239
|
columnAttributes: (config.columnAttributes || []).map(attr => this.pivotAttributeAttribute(attr)),
|
|
238
240
|
};
|
|
239
241
|
}
|
|
@@ -333,19 +335,17 @@ class PivotDataConverter {
|
|
|
333
335
|
}, { titles: [], constraints: [], headers: [], values: [], dataResources: [], valueTypes: [], aggregations: [] });
|
|
334
336
|
return {
|
|
335
337
|
columnHeaders: data.headers,
|
|
338
|
+
columnHeaderAttributes: [],
|
|
336
339
|
rowHeaders: [],
|
|
340
|
+
rowHeaderAttributes: [],
|
|
337
341
|
valueTitles: data.titles,
|
|
338
342
|
values: [data.values],
|
|
339
343
|
dataResources: [data.dataResources],
|
|
340
344
|
valuesConstraints: data.constraints,
|
|
341
345
|
valueTypes: data.valueTypes,
|
|
342
346
|
valueAggregations: data.aggregations,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
rowSorts: [],
|
|
346
|
-
columnShowSums: [],
|
|
347
|
-
columnSticky: [],
|
|
348
|
-
columnSorts: [],
|
|
347
|
+
rowsConfig: [],
|
|
348
|
+
columnsConfig: [],
|
|
349
349
|
hasAdditionalColumnLevel: true,
|
|
350
350
|
};
|
|
351
351
|
}
|
|
@@ -360,8 +360,12 @@ class PivotDataConverter {
|
|
|
360
360
|
}
|
|
361
361
|
convertAggregatedData(aggregatedData, valueAttributes, pivotColors, additionalData) {
|
|
362
362
|
const rowData = this.convertMapToPivotDataHeader(aggregatedData.map, aggregatedData.rowLevels, pivotColors.rows, pivotColors.values, additionalData.rowAttributes);
|
|
363
|
+
const rowHeaderAttributes = (additionalData.rowAttributes || [])
|
|
364
|
+
.map((attribute, index) => additionalData.rowShowHeaderAttributes?.[index] ? ({ title: attribute.name, color: pivotColors.rows?.[index] }) : undefined);
|
|
363
365
|
const { titles: valueTitles, constraints: valuesConstraints } = this.createValueTitles(valueAttributes);
|
|
364
366
|
const columnData = this.convertMapToPivotDataHeader(aggregatedData.rowLevels > 0 ? aggregatedData.columnsMap : aggregatedData.map, aggregatedData.columnLevels, pivotColors.columns, pivotColors.values, additionalData.columnAttributes, valueTitles);
|
|
367
|
+
const columnHeaderAttributes = (additionalData.columnAttributes || [])
|
|
368
|
+
.map((attribute, index) => additionalData.columnShowHeaderAttributes?.[index] ? ({ title: attribute.name, color: pivotColors.columns?.[index] }) : undefined);
|
|
365
369
|
const values = this.initMatrix(rowData.maxIndex + 1, columnData.maxIndex + 1);
|
|
366
370
|
const dataResources = this.initMatrix(rowData.maxIndex + 1, columnData.maxIndex + 1);
|
|
367
371
|
if ((valueAttributes || []).length > 0) {
|
|
@@ -372,7 +376,9 @@ class PivotDataConverter {
|
|
|
372
376
|
(aggregatedData.columnLevels > 0 && valueTitles.length > 1);
|
|
373
377
|
return {
|
|
374
378
|
rowHeaders: rowData.headers,
|
|
379
|
+
rowHeaderAttributes,
|
|
375
380
|
columnHeaders: columnData.headers,
|
|
381
|
+
columnHeaderAttributes,
|
|
376
382
|
valueTitles,
|
|
377
383
|
values,
|
|
378
384
|
dataResources,
|
|
@@ -499,7 +505,7 @@ class PivotDataConverter {
|
|
|
499
505
|
}, { titles: [], constraints: [] });
|
|
500
506
|
}
|
|
501
507
|
createValueTitle(aggregation, attributeName) {
|
|
502
|
-
const valueAggregationTitle = this.transform?.
|
|
508
|
+
const valueAggregationTitle = this.transform?.formatAggregation?.(aggregation) || aggregation.toString();
|
|
503
509
|
return `${valueAggregationTitle} ${attributeName || ''}`.trim();
|
|
504
510
|
}
|
|
505
511
|
initMatrix(rows, columns) {
|
|
@@ -621,12 +627,13 @@ class PivotTableConverter {
|
|
|
621
627
|
static groupDataClass = 'pivot-data-group-cell';
|
|
622
628
|
static rowHeaderClass = 'pivot-row-header-cell';
|
|
623
629
|
static rowGroupHeaderClass = 'pivot-row-group-header-cell';
|
|
630
|
+
static rowAttributeHeaderClass = 'pivot-row-attribute-header-cell';
|
|
624
631
|
static columnHeaderClass = 'pivot-column-header-cell';
|
|
625
632
|
static columnGroupHeaderClass = 'pivot-column-group-header-cell';
|
|
626
633
|
groupColors = [COLOR_GRAY100, COLOR_GRAY200, COLOR_GRAY300, COLOR_GRAY400, COLOR_GRAY500];
|
|
627
634
|
percentageConstraint = new PercentageConstraint({ decimals: 2 });
|
|
628
635
|
data;
|
|
629
|
-
|
|
636
|
+
transform;
|
|
630
637
|
values;
|
|
631
638
|
dataResources;
|
|
632
639
|
constraintData;
|
|
@@ -636,11 +643,12 @@ class PivotTableConverter {
|
|
|
636
643
|
columnsTransformationArray;
|
|
637
644
|
valueTypeInfo;
|
|
638
645
|
nonStickyRowIndex;
|
|
639
|
-
|
|
646
|
+
nonStickyColumnIndex;
|
|
647
|
+
createTables(pivotData, transform) {
|
|
640
648
|
if (!pivotData) {
|
|
641
649
|
return [{ cells: [] }];
|
|
642
650
|
}
|
|
643
|
-
this.
|
|
651
|
+
this.transform = transform;
|
|
644
652
|
this.constraintData = pivotData.constraintData;
|
|
645
653
|
return (pivotData.data || []).map(d => {
|
|
646
654
|
if (this.dataAreEmpty(d)) {
|
|
@@ -657,11 +665,14 @@ class PivotTableConverter {
|
|
|
657
665
|
const numberOfSums = Math.max(1, (data.valueTitles || []).length);
|
|
658
666
|
this.valueTypeInfo = getValuesTypeInfo(data.values, data.valueTypes, numberOfSums);
|
|
659
667
|
this.data = preparePivotData(data, this.constraintData, this.valueTypeInfo);
|
|
660
|
-
this.nonStickyRowIndex = this.data.rowSticky?.findIndex(sticky => !sticky) || 0;
|
|
661
668
|
this.values = data.values || [];
|
|
662
669
|
this.dataResources = data.dataResources || [];
|
|
663
|
-
this.rowLevels = (data.
|
|
664
|
-
this.columnLevels = (data.
|
|
670
|
+
this.rowLevels = (data.rowsConfig || []).length;
|
|
671
|
+
this.columnLevels = (data.columnsConfig || []).length + (data.hasAdditionalColumnLevel ? 1 : 0);
|
|
672
|
+
const rowAllSticky = this.data.rowsConfig?.length && this.data.rowsConfig.every(config => !!config?.sticky);
|
|
673
|
+
this.nonStickyRowIndex = Math.max(rowAllSticky ? this.rowLevels : (this.data.rowsConfig?.findIndex(config => !config?.sticky) || 0), 0);
|
|
674
|
+
const columnAllSticky = this.data.columnsConfig?.length && this.data.columnsConfig.every(config => !!config?.sticky);
|
|
675
|
+
this.nonStickyColumnIndex = Math.max(columnAllSticky ? this.columnLevels : (this.data.columnsConfig?.findIndex(config => !config?.sticky) || 0), 0);
|
|
665
676
|
const hasValue = (data.valueTitles || []).length > 0;
|
|
666
677
|
if ((this.data.rowHeaders || []).length > 0) {
|
|
667
678
|
this.rowsTransformationArray = createTransformationMap(this.data.rowHeaders, this.rowShowSums, this.columnLevels, 1);
|
|
@@ -677,10 +688,10 @@ class PivotTableConverter {
|
|
|
677
688
|
}
|
|
678
689
|
}
|
|
679
690
|
get rowShowSums() {
|
|
680
|
-
return this.data.
|
|
691
|
+
return (this.data.rowsConfig || []).map(config => config.showSums);
|
|
681
692
|
}
|
|
682
693
|
get columnShowSums() {
|
|
683
|
-
return this.data.
|
|
694
|
+
return (this.data.columnsConfig || []).map(config => config.showSums);
|
|
684
695
|
}
|
|
685
696
|
transformData() {
|
|
686
697
|
const cells = this.initCells();
|
|
@@ -699,7 +710,7 @@ class PivotTableConverter {
|
|
|
699
710
|
for (const header of headers) {
|
|
700
711
|
const rowSpan = getDirectHeaderChildCount(header, level, showSums);
|
|
701
712
|
cells[currentIndex][level] = {
|
|
702
|
-
value: header.title,
|
|
713
|
+
value: this.formatRowHeader(header.title, level),
|
|
703
714
|
cssClass: PivotTableConverter.rowHeaderClass,
|
|
704
715
|
isHeader: true,
|
|
705
716
|
stickyStart: this.isRowLevelSticky(level),
|
|
@@ -716,41 +727,19 @@ class PivotTableConverter {
|
|
|
716
727
|
this.fillCellsForRow(cells, header.targetIndex);
|
|
717
728
|
}
|
|
718
729
|
currentIndex += getHeaderChildCount(header, level, showSums);
|
|
730
|
+
const expressions = header.expressions || [];
|
|
731
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
732
|
+
const expressionIndex = currentIndex - (expressions.length - i);
|
|
733
|
+
const background = this.getSummaryBackground(level);
|
|
734
|
+
this.splitRowGroupHeader(cells, level, expressionIndex, background, expressions[i].title);
|
|
735
|
+
this.fillCellsForExpressionRow(cells, expressions[i], expressionIndex, background);
|
|
736
|
+
}
|
|
719
737
|
}
|
|
720
738
|
if (showSums[level]) {
|
|
739
|
+
const { title, summary } = this.formatSummaryHeader(parentHeader, level);
|
|
721
740
|
const background = this.getSummaryBackground(level);
|
|
722
|
-
const summary = level === 0 ? this.strings.summaryString : this.strings.headerSummaryString;
|
|
723
741
|
const columnIndex = Math.max(level - 1, 0);
|
|
724
|
-
|
|
725
|
-
const stickyStart = this.isRowLevelSticky(columnIndex);
|
|
726
|
-
// split row group header cell because of correct sticky scroll
|
|
727
|
-
if (stickyStart && this.nonStickyRowIndex > 0 && colSpan > 1) {
|
|
728
|
-
const newColspan = this.nonStickyRowIndex - columnIndex;
|
|
729
|
-
cells[currentIndex][this.nonStickyRowIndex] = {
|
|
730
|
-
value: undefined,
|
|
731
|
-
constraint: undefined,
|
|
732
|
-
label: undefined,
|
|
733
|
-
cssClass: PivotTableConverter.rowGroupHeaderClass,
|
|
734
|
-
isHeader: true,
|
|
735
|
-
rowSpan: 1,
|
|
736
|
-
colSpan: colSpan - newColspan,
|
|
737
|
-
background,
|
|
738
|
-
summary: undefined,
|
|
739
|
-
};
|
|
740
|
-
colSpan = newColspan;
|
|
741
|
-
}
|
|
742
|
-
cells[currentIndex][columnIndex] = {
|
|
743
|
-
value: parentHeader?.title,
|
|
744
|
-
constraint: parentHeader?.constraint,
|
|
745
|
-
label: parentHeader?.attributeName,
|
|
746
|
-
cssClass: PivotTableConverter.rowGroupHeaderClass,
|
|
747
|
-
isHeader: true,
|
|
748
|
-
stickyStart,
|
|
749
|
-
rowSpan: 1,
|
|
750
|
-
colSpan,
|
|
751
|
-
background,
|
|
752
|
-
summary,
|
|
753
|
-
};
|
|
742
|
+
this.splitRowGroupHeader(cells, columnIndex, currentIndex, background, summary, title, parentHeader?.constraint, parentHeader?.attributeName);
|
|
754
743
|
const rowIndexes = getTargetIndexesForHeaders(headers);
|
|
755
744
|
const transformedRowIndexes = rowIndexes
|
|
756
745
|
.map(v => this.rowsTransformationArray[v])
|
|
@@ -759,6 +748,50 @@ class PivotTableConverter {
|
|
|
759
748
|
this.fillCellsForGroupedRow(cells, rowIndexes, currentIndex, background);
|
|
760
749
|
}
|
|
761
750
|
}
|
|
751
|
+
splitRowGroupHeader(cells, columnIndex, currentIndex, background, summary, title, constraint, label) {
|
|
752
|
+
let colSpan = this.rowLevels - columnIndex;
|
|
753
|
+
const stickyStart = this.isRowLevelSticky(columnIndex);
|
|
754
|
+
// split row group header cell because of correct sticky scroll
|
|
755
|
+
if (stickyStart && this.nonStickyRowIndex > 0 && this.nonStickyRowIndex < this.rowLevels && colSpan > 1) {
|
|
756
|
+
const newColspan = this.nonStickyRowIndex - columnIndex;
|
|
757
|
+
cells[currentIndex][this.nonStickyRowIndex] = {
|
|
758
|
+
value: undefined,
|
|
759
|
+
constraint: undefined,
|
|
760
|
+
label: undefined,
|
|
761
|
+
cssClass: PivotTableConverter.rowGroupHeaderClass,
|
|
762
|
+
isHeader: true,
|
|
763
|
+
rowSpan: 1,
|
|
764
|
+
colSpan: colSpan - newColspan,
|
|
765
|
+
background,
|
|
766
|
+
summary: undefined,
|
|
767
|
+
};
|
|
768
|
+
colSpan = newColspan;
|
|
769
|
+
}
|
|
770
|
+
cells[currentIndex][columnIndex] = {
|
|
771
|
+
value: title,
|
|
772
|
+
constraint,
|
|
773
|
+
label,
|
|
774
|
+
cssClass: PivotTableConverter.rowGroupHeaderClass,
|
|
775
|
+
isHeader: true,
|
|
776
|
+
stickyStart,
|
|
777
|
+
rowSpan: 1,
|
|
778
|
+
colSpan,
|
|
779
|
+
background,
|
|
780
|
+
summary,
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
formatSummaryHeader(header, level) {
|
|
784
|
+
return this.transform.formatSummaryHeader?.(header, level) || {
|
|
785
|
+
title: header?.title,
|
|
786
|
+
summary: '',
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
formatRowHeader(title, level) {
|
|
790
|
+
return this.transform?.formatRowHeader?.(title, level) || title;
|
|
791
|
+
}
|
|
792
|
+
formatColumnHeader(title, level) {
|
|
793
|
+
return this.transform?.formatColumnHeader?.(title, level) || title;
|
|
794
|
+
}
|
|
762
795
|
getHeaderBackground(header, level) {
|
|
763
796
|
if (header?.color) {
|
|
764
797
|
return shadeColor(header.color, this.getLevelOpacity(level));
|
|
@@ -769,11 +802,11 @@ class PivotTableConverter {
|
|
|
769
802
|
return Math.min(80, 50 + level * 5) / 100;
|
|
770
803
|
}
|
|
771
804
|
isRowLevelSticky(level) {
|
|
772
|
-
return this.data?.
|
|
805
|
+
return this.data?.rowsConfig?.[level]?.sticky;
|
|
773
806
|
}
|
|
774
807
|
isColumnLevelSticky(level) {
|
|
775
|
-
const maxLevel = Math.min(level, (this.data?.
|
|
776
|
-
return this.data?.
|
|
808
|
+
const maxLevel = Math.min(level, (this.data?.columnsConfig?.length ?? Number.MAX_SAFE_INTEGER) - 1);
|
|
809
|
+
return this.data?.columnsConfig?.[maxLevel]?.sticky;
|
|
777
810
|
}
|
|
778
811
|
getSummaryBackground(level) {
|
|
779
812
|
const index = Math.min(level, this.groupColors.length - 1);
|
|
@@ -870,6 +903,58 @@ class PivotTableConverter {
|
|
|
870
903
|
}
|
|
871
904
|
}
|
|
872
905
|
}
|
|
906
|
+
fillCellsForExpressionRow(cells, expression, rowIndexInCells, background) {
|
|
907
|
+
for (let column = 0; column < this.columnsTransformationArray.length; column++) {
|
|
908
|
+
const columnIndexInCells = this.columnsTransformationArray[column];
|
|
909
|
+
if (isNotNullOrUndefined(columnIndexInCells)) {
|
|
910
|
+
const { value, dataResources } = this.evaluateExpression(expression, column);
|
|
911
|
+
const valueIndex = column % this.data.valueTitles.length;
|
|
912
|
+
const formattedValue = this.formatValueByConstraint(value, valueIndex);
|
|
913
|
+
cells[rowIndexInCells][columnIndexInCells] = {
|
|
914
|
+
value: String(formattedValue),
|
|
915
|
+
dataResources,
|
|
916
|
+
colSpan: 1,
|
|
917
|
+
rowSpan: 1,
|
|
918
|
+
cssClass: PivotTableConverter.groupDataClass,
|
|
919
|
+
isHeader: false,
|
|
920
|
+
background,
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
evaluateExpression(expression, column) {
|
|
926
|
+
return (expression.operands || []).reduce((result, operand, index) => {
|
|
927
|
+
const { value, dataResources } = this.evaluateOperand(operand, column);
|
|
928
|
+
result.dataResources.push(...dataResources);
|
|
929
|
+
switch (expression.operation) {
|
|
930
|
+
case "add":
|
|
931
|
+
result.value += value;
|
|
932
|
+
break;
|
|
933
|
+
case "subtract":
|
|
934
|
+
result.value = (index === 0 ? value : result.value - value);
|
|
935
|
+
break;
|
|
936
|
+
case 'multiply':
|
|
937
|
+
result.value = index === 0 ? value : result.value * value;
|
|
938
|
+
break;
|
|
939
|
+
case 'divide':
|
|
940
|
+
result.value = index === 0 ? value : value ? result.value / value : result.value;
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
return result;
|
|
944
|
+
}, { value: 0, dataResources: [] });
|
|
945
|
+
}
|
|
946
|
+
evaluateOperand(operand, column) {
|
|
947
|
+
switch (operand.type) {
|
|
948
|
+
case "expression": return this.evaluateExpression(operand, column);
|
|
949
|
+
case "value": return { value: operand.value, dataResources: [] };
|
|
950
|
+
case "header": {
|
|
951
|
+
const rows = getTargetIndexesForHeaders(operand.headers);
|
|
952
|
+
const { values, dataResources } = this.getGroupedValuesForRowsAndCols(rows, [column]);
|
|
953
|
+
const { value } = this.aggregateDataValues(values, [column]);
|
|
954
|
+
return { value, dataResources };
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
873
958
|
getGroupedValuesForRowsAndCols(rows, columns) {
|
|
874
959
|
const values = [];
|
|
875
960
|
const dataResources = [];
|
|
@@ -898,7 +983,7 @@ class PivotTableConverter {
|
|
|
898
983
|
for (const header of headers) {
|
|
899
984
|
const colSpan = getDirectHeaderChildCount(header, level, showSums, numberOfSums);
|
|
900
985
|
cells[level][currentIndex] = {
|
|
901
|
-
value: header.title,
|
|
986
|
+
value: this.formatColumnHeader(header.title, level),
|
|
902
987
|
cssClass: PivotTableConverter.columnHeaderClass,
|
|
903
988
|
isHeader: true,
|
|
904
989
|
rowSpan: 1,
|
|
@@ -918,12 +1003,12 @@ class PivotTableConverter {
|
|
|
918
1003
|
}
|
|
919
1004
|
if (showSums[level]) {
|
|
920
1005
|
const background = this.getSummaryBackground(level);
|
|
921
|
-
const
|
|
1006
|
+
const { title, summary } = this.formatSummaryHeader(parentHeader, level);
|
|
922
1007
|
const numberOfValues = this.data.valueTitles.length;
|
|
923
1008
|
const rowIndex = Math.max(level - 1, 0);
|
|
924
1009
|
const shouldAddValueHeaders = numberOfValues > 1;
|
|
925
1010
|
cells[rowIndex][currentIndex] = {
|
|
926
|
-
value:
|
|
1011
|
+
value: title,
|
|
927
1012
|
constraint: parentHeader?.constraint,
|
|
928
1013
|
label: parentHeader?.attributeName,
|
|
929
1014
|
cssClass: PivotTableConverter.columnGroupHeaderClass,
|
|
@@ -982,14 +1067,17 @@ class PivotTableConverter {
|
|
|
982
1067
|
}
|
|
983
1068
|
}
|
|
984
1069
|
aggregateAndFormatDataValues(values, rows, columns) {
|
|
1070
|
+
const { value, aggregation } = this.aggregateDataValues(values, columns);
|
|
1071
|
+
return aggregation === DataAggregationType.Join ? value : this.formatGroupedValueByValueType(value, rows, columns);
|
|
1072
|
+
}
|
|
1073
|
+
aggregateDataValues(values, columns) {
|
|
985
1074
|
const aggregation = this.aggregationByColumns(columns);
|
|
986
1075
|
if (aggregation === DataAggregationType.Join) {
|
|
987
1076
|
const valueIndex = this.getValueIndexForColumns(columns);
|
|
988
1077
|
const constraint = this.data.valuesConstraints?.[valueIndex] || this.valueTypeInfo[valueIndex]?.defaultConstraint;
|
|
989
|
-
return aggregateDataValues(aggregation, values, constraint, false, this.constraintData);
|
|
1078
|
+
return { value: aggregateDataValues(aggregation, values, constraint, false, this.constraintData), aggregation };
|
|
990
1079
|
}
|
|
991
|
-
|
|
992
|
-
return this.formatGroupedValueByValueType(aggregatedValue, rows, columns);
|
|
1080
|
+
return { value: aggregateDataValues(aggregation, values), aggregation };
|
|
993
1081
|
}
|
|
994
1082
|
aggregationByColumns(columns) {
|
|
995
1083
|
const valueIndex = columns[0] % this.data.valueTitles.length;
|
|
@@ -1104,17 +1192,44 @@ class PivotTableConverter {
|
|
|
1104
1192
|
}
|
|
1105
1193
|
}
|
|
1106
1194
|
if (this.rowLevels > 0 && this.columnLevels > 0) {
|
|
1107
|
-
for (let
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1195
|
+
for (let j = 0; j < this.rowLevels; j++) {
|
|
1196
|
+
const rowHeaderAttribute = this.data.rowHeaderAttributes[j];
|
|
1197
|
+
if (rowHeaderAttribute) {
|
|
1198
|
+
const titleColSpan = this.nonStickyColumnIndex || this.columnLevels;
|
|
1199
|
+
matrix[0][j] = {
|
|
1200
|
+
value: rowHeaderAttribute.title,
|
|
1201
|
+
cssClass: PivotTableConverter.rowAttributeHeaderClass,
|
|
1202
|
+
isHeader: true,
|
|
1112
1203
|
rowSpan: 1,
|
|
1113
|
-
colSpan:
|
|
1204
|
+
colSpan: titleColSpan,
|
|
1205
|
+
stickyTop: this.isColumnLevelSticky(0),
|
|
1114
1206
|
stickyStart: this.isRowLevelSticky(j),
|
|
1115
|
-
|
|
1116
|
-
isHeader: false,
|
|
1207
|
+
background: rowHeaderAttribute.color,
|
|
1117
1208
|
};
|
|
1209
|
+
if (this.columnLevels - titleColSpan > 0) {
|
|
1210
|
+
matrix[this.nonStickyColumnIndex][j] = {
|
|
1211
|
+
value: '',
|
|
1212
|
+
cssClass: PivotTableConverter.rowAttributeHeaderClass,
|
|
1213
|
+
isHeader: true,
|
|
1214
|
+
rowSpan: 1,
|
|
1215
|
+
colSpan: this.columnLevels - titleColSpan,
|
|
1216
|
+
background: rowHeaderAttribute.color,
|
|
1217
|
+
stickyStart: this.isRowLevelSticky(j),
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
for (let i = 0; i < this.columnLevels; i++) {
|
|
1223
|
+
matrix[i][j] = {
|
|
1224
|
+
value: '',
|
|
1225
|
+
cssClass: PivotTableConverter.emptyClass,
|
|
1226
|
+
rowSpan: 1,
|
|
1227
|
+
colSpan: 1,
|
|
1228
|
+
stickyStart: this.isRowLevelSticky(j),
|
|
1229
|
+
stickyTop: this.isColumnLevelSticky(i),
|
|
1230
|
+
isHeader: false,
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1118
1233
|
}
|
|
1119
1234
|
}
|
|
1120
1235
|
}
|
|
@@ -1137,7 +1252,66 @@ class PivotTableConverter {
|
|
|
1137
1252
|
function preparePivotData(data, constraintData, valueTypeInfo) {
|
|
1138
1253
|
const numberOfSums = Math.max(1, (data.valueTitles || []).length);
|
|
1139
1254
|
const values = computeValuesByValueType(data.values, data.valueTypes, numberOfSums, valueTypeInfo);
|
|
1140
|
-
|
|
1255
|
+
const sorted = sortPivotData({ ...data, values }, constraintData);
|
|
1256
|
+
return fillExpressionsToData(sorted);
|
|
1257
|
+
}
|
|
1258
|
+
function fillExpressionsToData(data) {
|
|
1259
|
+
return {
|
|
1260
|
+
...data,
|
|
1261
|
+
rowHeaders: fillExpressionsToHeaders(data.rowHeaders, data.rowsConfig, 0),
|
|
1262
|
+
columnHeaders: fillExpressionsToHeaders(data.columnHeaders, data.columnsConfig, 0),
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function fillExpressionsToHeaders(headers, configs, index) {
|
|
1266
|
+
const expressions = configs?.[index]?.expressions || [];
|
|
1267
|
+
const headersCopy = [...(headers || [])];
|
|
1268
|
+
for (const expression of expressions) {
|
|
1269
|
+
const dataHeaderExpression = extendPivotExpression(expression, headers);
|
|
1270
|
+
if (dataHeaderExpression.lastHeaderIndex >= 0) {
|
|
1271
|
+
const lastHeaderIndex = dataHeaderExpression.lastHeaderIndex;
|
|
1272
|
+
const newHeader = { ...headersCopy[lastHeaderIndex], expressions: [...(headersCopy[lastHeaderIndex].expressions || []), dataHeaderExpression] };
|
|
1273
|
+
headersCopy.splice(lastHeaderIndex, 1, newHeader);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
if (configs?.[index + 1]) {
|
|
1277
|
+
for (let i = 0; i < headersCopy.length; i++) {
|
|
1278
|
+
headersCopy.splice(i, 1, { ...headersCopy[i], children: fillExpressionsToHeaders(headersCopy[i].children, configs, index + 1) });
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return headersCopy;
|
|
1282
|
+
}
|
|
1283
|
+
function extendPivotExpression(expression, headers) {
|
|
1284
|
+
const dataHeaderOperands = [];
|
|
1285
|
+
let lastHeaderIndex = -1;
|
|
1286
|
+
function traverse(operands) {
|
|
1287
|
+
for (const operand of operands) {
|
|
1288
|
+
if (operand.type === 'header') {
|
|
1289
|
+
const indexes = getOperandIndexesInHeaders(operand, headers);
|
|
1290
|
+
lastHeaderIndex = Math.max(lastHeaderIndex, ...indexes);
|
|
1291
|
+
const operandHeaders = indexes.map(index => headers[index]);
|
|
1292
|
+
dataHeaderOperands.push({ ...operand, headers: operandHeaders });
|
|
1293
|
+
}
|
|
1294
|
+
else if (operand.type === 'expression') {
|
|
1295
|
+
traverse(operand.operands);
|
|
1296
|
+
}
|
|
1297
|
+
else {
|
|
1298
|
+
dataHeaderOperands.push(operand);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
traverse(expression.operands);
|
|
1303
|
+
return { ...expression, lastHeaderIndex, operands: dataHeaderOperands };
|
|
1304
|
+
}
|
|
1305
|
+
function getOperandIndexesInHeaders(operand, headers) {
|
|
1306
|
+
return (headers || []).reduce((indexes, header, index) => {
|
|
1307
|
+
if (operandContainsHeader(operand, header)) {
|
|
1308
|
+
indexes.push(index);
|
|
1309
|
+
}
|
|
1310
|
+
return indexes;
|
|
1311
|
+
}, []);
|
|
1312
|
+
}
|
|
1313
|
+
function operandContainsHeader(operand, header) {
|
|
1314
|
+
return header.title.match(new RegExp(operand.value))?.length > 0;
|
|
1141
1315
|
}
|
|
1142
1316
|
function computeValuesByValueType(values, valueTypes, numValues, valueTypeInfo) {
|
|
1143
1317
|
const rowsIndexes = [...Array(values.length).keys()];
|
|
@@ -1239,6 +1413,7 @@ function iterateThroughTransformationMap(headers, additionalNum, array, level, s
|
|
|
1239
1413
|
}
|
|
1240
1414
|
else if (isNotNullOrUndefined(header.targetIndex)) {
|
|
1241
1415
|
array[header.targetIndex] = i + additional;
|
|
1416
|
+
additional += (header.expressions || []).length;
|
|
1242
1417
|
}
|
|
1243
1418
|
}
|
|
1244
1419
|
}
|
|
@@ -1261,11 +1436,12 @@ function getTargetIndexesForHeader(pivotDataHeader) {
|
|
|
1261
1436
|
function getHeadersChildCount(headers, showSums, numberOfSums = 1) {
|
|
1262
1437
|
return (headers || []).reduce((sum, header) => sum + getHeaderChildCount(header, 0, showSums, numberOfSums), showSums[0] ? numberOfSums : 0);
|
|
1263
1438
|
}
|
|
1264
|
-
function getHeaderChildCount(pivotDataHeader, level, showSums, numberOfSums = 1
|
|
1439
|
+
function getHeaderChildCount(pivotDataHeader, level, showSums, numberOfSums = 1) {
|
|
1440
|
+
const numExpressions = (pivotDataHeader.expressions || []).length;
|
|
1265
1441
|
if (pivotDataHeader.children) {
|
|
1266
|
-
return pivotDataHeader.children.reduce((sum, header) => sum + getHeaderChildCount(header, level + 1, showSums, numberOfSums
|
|
1442
|
+
return pivotDataHeader.children.reduce((sum, header) => sum + getHeaderChildCount(header, level + 1, showSums, numberOfSums), (showSums[level + 1] ? numberOfSums : 0) + numExpressions);
|
|
1267
1443
|
}
|
|
1268
|
-
return
|
|
1444
|
+
return 1 + numExpressions;
|
|
1269
1445
|
}
|
|
1270
1446
|
function getDirectHeaderChildCount(pivotDataHeader, level, showSums, numberOfSums = 1) {
|
|
1271
1447
|
if (pivotDataHeader.children) {
|
|
@@ -1274,10 +1450,12 @@ function getDirectHeaderChildCount(pivotDataHeader, level, showSums, numberOfSum
|
|
|
1274
1450
|
return 1;
|
|
1275
1451
|
}
|
|
1276
1452
|
function sortPivotData(data, constraintData) {
|
|
1453
|
+
const rowSorts = (data.rowsConfig || []).map(config => config.sort);
|
|
1454
|
+
const columnSorts = (data.columnsConfig || []).map(config => config.sort);
|
|
1277
1455
|
return {
|
|
1278
1456
|
...data,
|
|
1279
|
-
rowHeaders: sortPivotRowDataHeaders(data.rowHeaders,
|
|
1280
|
-
columnHeaders: sortPivotColumnDataHeaders(data.columnHeaders,
|
|
1457
|
+
rowHeaders: sortPivotRowDataHeaders(data.rowHeaders, rowSorts, data, constraintData),
|
|
1458
|
+
columnHeaders: sortPivotColumnDataHeaders(data.columnHeaders, columnSorts, data, constraintData),
|
|
1281
1459
|
};
|
|
1282
1460
|
}
|
|
1283
1461
|
function sortPivotRowDataHeaders(rowHeaders, rowSorts, pivotData, constraintData) {
|
|
@@ -1535,9 +1713,11 @@ class LmrPivotTableComponent {
|
|
|
1535
1713
|
constraintData;
|
|
1536
1714
|
config;
|
|
1537
1715
|
transform;
|
|
1538
|
-
|
|
1716
|
+
emptyTablesTemplateInput;
|
|
1717
|
+
tableCellTemplateInput;
|
|
1539
1718
|
cellClick = new EventEmitter();
|
|
1540
1719
|
pivotDataChange = new EventEmitter();
|
|
1720
|
+
pivotTablesChange = new EventEmitter();
|
|
1541
1721
|
emptyTablesTemplate;
|
|
1542
1722
|
tableCellTemplate;
|
|
1543
1723
|
pivotTransformer = new PivotDataConverter();
|
|
@@ -1548,7 +1728,7 @@ class LmrPivotTableComponent {
|
|
|
1548
1728
|
ngOnInit() {
|
|
1549
1729
|
const observable = this.dataSubject.pipe(filter(data => !!data));
|
|
1550
1730
|
this.pivotData$ = observable.pipe(throttleTime(200, asyncScheduler, { trailing: true, leading: true }), map(data => this.handleData(data)), tap(data => this.pivotDataChange.emit(data)));
|
|
1551
|
-
this.pivotTables$ = this.pivotData$.pipe(map(data => this.pivotTableConverter.createTables(data, this.
|
|
1731
|
+
this.pivotTables$ = this.pivotData$.pipe(map(data => this.pivotTableConverter.createTables(data, this.transform)), tap(tables => this.pivotTablesChange.emit(tables)));
|
|
1552
1732
|
}
|
|
1553
1733
|
handleData(data) {
|
|
1554
1734
|
return this.pivotTransformer.createData(data.config, data.transform, data.collections, data.linkTypes, data.data, data.query, data.constraintData);
|
|
@@ -1565,11 +1745,11 @@ class LmrPivotTableComponent {
|
|
|
1565
1745
|
});
|
|
1566
1746
|
}
|
|
1567
1747
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1568
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LmrPivotTableComponent, selector: "lmr-pivot-table", inputs: { collections: "collections", data: "data", linkTypes: "linkTypes", query: "query", constraintData: "constraintData", config: "config", transform: "transform",
|
|
1748
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LmrPivotTableComponent, selector: "lmr-pivot-table", inputs: { collections: "collections", data: "data", linkTypes: "linkTypes", query: "query", constraintData: "constraintData", config: "config", transform: "transform", emptyTablesTemplateInput: "emptyTablesTemplateInput", tableCellTemplateInput: "tableCellTemplateInput" }, outputs: { cellClick: "cellClick", pivotDataChange: "pivotDataChange", pivotTablesChange: "pivotTablesChange" }, queries: [{ propertyName: "emptyTablesTemplate", first: true, predicate: LmrEmptyTablesTemplateDirective, descendants: true, read: TemplateRef }, { propertyName: "tableCellTemplate", first: true, predicate: LmrTableCellTemplateDirective, descendants: true, read: TemplateRef }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"{pivotTables: pivotTables$ | async, pivotData: pivotData$ | async} as data\">\n <ng-container *ngIf=\"data.pivotTables?.length && !(data.pivotData | pivotDataEmpty)\">\n <table *ngFor=\"let pivotTable of data.pivotTables; let first\"\n class=\"table table-without-padding table-borderless table-md\"\n [class.mt-4]=\"!first\">\n <tr *ngFor=\"let rowCells of pivotTable.cells; let rowIndex = index\">\n\n <ng-container *ngFor=\"let cell of rowCells; let cellIndex = index\">\n <td *ngIf=\"cell && {hasValue: cell | pivotTableCellHasValue} as cellData\"\n class=\"cell {{cell.constraint ? (cell.constraint.type | lowercase) : ''}} text-truncate\"\n [style.max-width.px]=\"300\"\n [class.sticky-start]=\"cell.stickyStart\"\n [class.sticky-top]=\"cell.stickyTop\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [style.top.px]=\"cell.stickyTop ? (rowIndex * 40) : undefined\"\n [style.left.px]=\"cell.stickyStart ? (cellIndex * 150) : undefined\"\n [ngClass]=\"cell.cssClass\"\n [style.background]=\"cell.background\"\n [style.color]=\"cell.background && (cell.background | contrastColor)\">\n <ng-container *ngIf=\"cell.summary\">\n <ng-container *ngIf=\"cellData.hasValue\">\n <div class=\"d-flex align-items-center h-100\">\n <span class=\"summary me-2\">{{cell.summary}}</span>\n <ng-template #defaultTableCellTemplate>\n <span class=\"flex-grow-1 h-100 text-truncate d-inline-block\">\n {{ cell.value }}\n </span>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"tableCellTemplate || tableCellTemplateInput || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!cellData.hasValue\">\n <span class=\"d-inline-block summary\">{{cell.summary}}</span>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"!cell.summary\">\n <ng-container *ngIf=\"cellData.hasValue\">\n <ng-template #defaultTableCellTemplate>\n <span class=\"d-inline-block\">\n {{ cell.value }}\n </span>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"tableCellTemplate || tableCellTemplateInput || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"!cellData.hasValue\"> </ng-container>\n </ng-container>\n </td>\n </ng-container>\n </tr>\n </table>\n </ng-container>\n\n <ng-container *ngIf=\"!data.pivotTables?.length || (data.pivotData | pivotDataEmpty)\">\n <ng-template #defaultEmptyTablesTemplate>\n <div> </div>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"emptyTablesTemplate || emptyTablesTemplateInput || defaultEmptyTablesTemplate\"\n [ngTemplateOutletContext]=\"{ }\">\n </ng-template>\n </ng-container>\n</ng-container>\n", styles: [".table{border-spacing:0;border-collapse:separate}.pivot-data-cell,.pivot-data-group-cell,.pivot-column-header-cell,.pivot-column-group-header-cell{text-align:right}.pivot-column-header-cell,.pivot-row-attribute-header-cell,.pivot-row-header-cell,.pivot-data-group-cell,.pivot-row-group-header-cell,.pivot-column-group-header-cell{font-weight:700;border:1px #f8f9fa solid}.pivot-row-header-cell.sticky-start,.pivot-row-group-header-cell.sticky-start,.pivot-empty-cell.sticky-start{position:sticky;width:150px;min-width:150px;max-width:150px!important;z-index:9}.pivot-column-header-cell.sticky-top,.pivot-row-attribute-header-cell.sticky-top,.pivot-column-group-header-cell.sticky-top,.pivot-empty-cell.sticky-top{position:sticky;z-index:10}.pivot-row-attribute-header-cell.sticky-top,.pivot-row-attribute-header-cell.sticky-start{position:sticky;z-index:11}.pivot-empty-cell{background:white;border:1px white solid}.pivot-empty-cell.sticky-top{z-index:11}.cell.color{padding:0!important;height:30px}.cell.color .summary{padding-left:.5rem}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: PivotDataEmptyPipe, name: "pivotDataEmpty" }, { kind: "pipe", type: PivotTableCellHasValuePipe, name: "pivotTableCellHasValue" }, { kind: "pipe", type: ContrastColorPipe, name: "contrastColor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1569
1749
|
}
|
|
1570
1750
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableComponent, decorators: [{
|
|
1571
1751
|
type: Component,
|
|
1572
|
-
args: [{ selector: 'lmr-pivot-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{pivotTables: pivotTables$ | async, pivotData: pivotData$ | async} as data\">\n <ng-container *ngIf=\"data.pivotTables?.length && !(data.pivotData | pivotDataEmpty)\">\n <table *ngFor=\"let pivotTable of data.pivotTables; let first\"\n class=\"table table-without-padding table-borderless table-md\"\n [class.mt-4]=\"!first\">\n <tr *ngFor=\"let rowCells of pivotTable.cells; let rowIndex = index\">\n\n <ng-container *ngFor=\"let cell of rowCells; let cellIndex = index\">\n <td *ngIf=\"cell && {hasValue: cell | pivotTableCellHasValue} as cellData\"\n class=\"cell {{cell.constraint ? (cell.constraint.type | lowercase) : ''}} text-truncate\"\n [style.max-width.px]=\"300\"\n [class.sticky-start]=\"cell.stickyStart\"\n [class.sticky-top]=\"cell.stickyTop\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [style.top.px]=\"cell.stickyTop ? (rowIndex * 40) : undefined\"\n [style.left.px]=\"cell.stickyStart ? (cellIndex * 150) : undefined\"\n [ngClass]=\"cell.cssClass\"\n [style.background]=\"cell.background\"\n [style.color]=\"cell.background && (cell.background | contrastColor)\">\n <ng-container *ngIf=\"cell.summary\">\n <div class=\"d-flex align-items-center h-100\">\n
|
|
1752
|
+
args: [{ selector: 'lmr-pivot-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"{pivotTables: pivotTables$ | async, pivotData: pivotData$ | async} as data\">\n <ng-container *ngIf=\"data.pivotTables?.length && !(data.pivotData | pivotDataEmpty)\">\n <table *ngFor=\"let pivotTable of data.pivotTables; let first\"\n class=\"table table-without-padding table-borderless table-md\"\n [class.mt-4]=\"!first\">\n <tr *ngFor=\"let rowCells of pivotTable.cells; let rowIndex = index\">\n\n <ng-container *ngFor=\"let cell of rowCells; let cellIndex = index\">\n <td *ngIf=\"cell && {hasValue: cell | pivotTableCellHasValue} as cellData\"\n class=\"cell {{cell.constraint ? (cell.constraint.type | lowercase) : ''}} text-truncate\"\n [style.max-width.px]=\"300\"\n [class.sticky-start]=\"cell.stickyStart\"\n [class.sticky-top]=\"cell.stickyTop\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [style.top.px]=\"cell.stickyTop ? (rowIndex * 40) : undefined\"\n [style.left.px]=\"cell.stickyStart ? (cellIndex * 150) : undefined\"\n [ngClass]=\"cell.cssClass\"\n [style.background]=\"cell.background\"\n [style.color]=\"cell.background && (cell.background | contrastColor)\">\n <ng-container *ngIf=\"cell.summary\">\n <ng-container *ngIf=\"cellData.hasValue\">\n <div class=\"d-flex align-items-center h-100\">\n <span class=\"summary me-2\">{{cell.summary}}</span>\n <ng-template #defaultTableCellTemplate>\n <span class=\"flex-grow-1 h-100 text-truncate d-inline-block\">\n {{ cell.value }}\n </span>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"tableCellTemplate || tableCellTemplateInput || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!cellData.hasValue\">\n <span class=\"d-inline-block summary\">{{cell.summary}}</span>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"!cell.summary\">\n <ng-container *ngIf=\"cellData.hasValue\">\n <ng-template #defaultTableCellTemplate>\n <span class=\"d-inline-block\">\n {{ cell.value }}\n </span>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"tableCellTemplate || tableCellTemplateInput || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"!cellData.hasValue\"> </ng-container>\n </ng-container>\n </td>\n </ng-container>\n </tr>\n </table>\n </ng-container>\n\n <ng-container *ngIf=\"!data.pivotTables?.length || (data.pivotData | pivotDataEmpty)\">\n <ng-template #defaultEmptyTablesTemplate>\n <div> </div>\n </ng-template>\n\n <ng-template\n [ngTemplateOutlet]=\"emptyTablesTemplate || emptyTablesTemplateInput || defaultEmptyTablesTemplate\"\n [ngTemplateOutletContext]=\"{ }\">\n </ng-template>\n </ng-container>\n</ng-container>\n", styles: [".table{border-spacing:0;border-collapse:separate}.pivot-data-cell,.pivot-data-group-cell,.pivot-column-header-cell,.pivot-column-group-header-cell{text-align:right}.pivot-column-header-cell,.pivot-row-attribute-header-cell,.pivot-row-header-cell,.pivot-data-group-cell,.pivot-row-group-header-cell,.pivot-column-group-header-cell{font-weight:700;border:1px #f8f9fa solid}.pivot-row-header-cell.sticky-start,.pivot-row-group-header-cell.sticky-start,.pivot-empty-cell.sticky-start{position:sticky;width:150px;min-width:150px;max-width:150px!important;z-index:9}.pivot-column-header-cell.sticky-top,.pivot-row-attribute-header-cell.sticky-top,.pivot-column-group-header-cell.sticky-top,.pivot-empty-cell.sticky-top{position:sticky;z-index:10}.pivot-row-attribute-header-cell.sticky-top,.pivot-row-attribute-header-cell.sticky-start{position:sticky;z-index:11}.pivot-empty-cell{background:white;border:1px white solid}.pivot-empty-cell.sticky-top{z-index:11}.cell.color{padding:0!important;height:30px}.cell.color .summary{padding-left:.5rem}\n"] }]
|
|
1573
1753
|
}], propDecorators: { collections: [{
|
|
1574
1754
|
type: Input
|
|
1575
1755
|
}], data: [{
|
|
@@ -1584,12 +1764,109 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1584
1764
|
type: Input
|
|
1585
1765
|
}], transform: [{
|
|
1586
1766
|
type: Input
|
|
1587
|
-
}],
|
|
1767
|
+
}], emptyTablesTemplateInput: [{
|
|
1768
|
+
type: Input
|
|
1769
|
+
}], tableCellTemplateInput: [{
|
|
1588
1770
|
type: Input
|
|
1589
1771
|
}], cellClick: [{
|
|
1590
1772
|
type: Output
|
|
1591
1773
|
}], pivotDataChange: [{
|
|
1592
1774
|
type: Output
|
|
1775
|
+
}], pivotTablesChange: [{
|
|
1776
|
+
type: Output
|
|
1777
|
+
}], emptyTablesTemplate: [{
|
|
1778
|
+
type: ContentChild,
|
|
1779
|
+
args: [LmrEmptyTablesTemplateDirective, { read: TemplateRef }]
|
|
1780
|
+
}], tableCellTemplate: [{
|
|
1781
|
+
type: ContentChild,
|
|
1782
|
+
args: [LmrTableCellTemplateDirective, { read: TemplateRef }]
|
|
1783
|
+
}] } });
|
|
1784
|
+
|
|
1785
|
+
class LmrSimplePivotTableComponent {
|
|
1786
|
+
rows;
|
|
1787
|
+
attributes;
|
|
1788
|
+
color;
|
|
1789
|
+
config;
|
|
1790
|
+
transform;
|
|
1791
|
+
locale;
|
|
1792
|
+
cellClick = new EventEmitter();
|
|
1793
|
+
pivotDataChange = new EventEmitter();
|
|
1794
|
+
pivotTablesChange = new EventEmitter();
|
|
1795
|
+
emptyTablesTemplate;
|
|
1796
|
+
tableCellTemplate;
|
|
1797
|
+
collectionId = generateId();
|
|
1798
|
+
query = { stems: [{ collectionId: this.collectionId }] };
|
|
1799
|
+
collection = this.createCollection();
|
|
1800
|
+
pivotConfig = this.createConfig();
|
|
1801
|
+
data = this.createRows();
|
|
1802
|
+
constraintData;
|
|
1803
|
+
ngOnChanges(changes) {
|
|
1804
|
+
if (changes['rows']) {
|
|
1805
|
+
this.data = this.createRows();
|
|
1806
|
+
}
|
|
1807
|
+
if (changes['attributes'] || changes['color']) {
|
|
1808
|
+
this.collection = this.createCollection();
|
|
1809
|
+
}
|
|
1810
|
+
if (changes['config']) {
|
|
1811
|
+
this.pivotConfig = this.createConfig();
|
|
1812
|
+
}
|
|
1813
|
+
this.constraintData = {
|
|
1814
|
+
locale: this.locale || LanguageTag.USA,
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
createCollection() {
|
|
1818
|
+
return {
|
|
1819
|
+
id: this.collectionId,
|
|
1820
|
+
attributes: (this.attributes || []),
|
|
1821
|
+
color: this.color,
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
createConfig() {
|
|
1825
|
+
return {
|
|
1826
|
+
stemsConfigs: [{
|
|
1827
|
+
stem: this.query.stems[0],
|
|
1828
|
+
rowAttributes: (this.config?.rowAttributes || []).map(attribute => ({ ...attribute, resourceId: this.collectionId, resourceIndex: 0, resourceType: AttributesResourceType.Collection })),
|
|
1829
|
+
columnAttributes: (this.config?.columnAttributes || []).map(attribute => ({ ...attribute, resourceId: this.collectionId, resourceIndex: 0, resourceType: AttributesResourceType.Collection })),
|
|
1830
|
+
valueAttributes: (this.config?.valueAttributes || []).map(attribute => ({ ...attribute, resourceId: this.collectionId, resourceIndex: 0, resourceType: AttributesResourceType.Collection }))
|
|
1831
|
+
}]
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
createRows() {
|
|
1835
|
+
const documents = (this.rows || []).map((row, index) => ({ id: index.toString(), collectionId: this.collection.id, data: row }));
|
|
1836
|
+
return ({
|
|
1837
|
+
uniqueDocuments: documents,
|
|
1838
|
+
uniqueLinkInstances: [],
|
|
1839
|
+
dataByStems: [{
|
|
1840
|
+
stem: this.query.stems[0],
|
|
1841
|
+
linkInstances: [],
|
|
1842
|
+
documents
|
|
1843
|
+
}]
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrSimplePivotTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1847
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LmrSimplePivotTableComponent, selector: "lmr-simple-pivot-table", inputs: { rows: "rows", attributes: "attributes", color: "color", config: "config", transform: "transform", locale: "locale" }, outputs: { cellClick: "cellClick", pivotDataChange: "pivotDataChange", pivotTablesChange: "pivotTablesChange" }, queries: [{ propertyName: "emptyTablesTemplate", first: true, predicate: LmrEmptyTablesTemplateDirective, descendants: true, read: TemplateRef }, { propertyName: "tableCellTemplate", first: true, predicate: LmrTableCellTemplateDirective, descendants: true, read: TemplateRef }], usesOnChanges: true, ngImport: i0, template: "<lmr-pivot-table [transform]=\"transform\"\n [data]=\"data\"\n [config]=\"pivotConfig\"\n [query]=\"query\"\n [constraintData]=\"constraintData\"\n [collections]=\"[collection]\"\n [emptyTablesTemplateInput]=\"emptyTablesTemplate\"\n [tableCellTemplateInput]=\"tableCellTemplate\"\n (pivotDataChange)=\"pivotDataChange.emit($event)\"\n (pivotTablesChange)=\"pivotTablesChange.emit($event)\">\n</lmr-pivot-table>\n", dependencies: [{ kind: "component", type: LmrPivotTableComponent, selector: "lmr-pivot-table", inputs: ["collections", "data", "linkTypes", "query", "constraintData", "config", "transform", "emptyTablesTemplateInput", "tableCellTemplateInput"], outputs: ["cellClick", "pivotDataChange", "pivotTablesChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1848
|
+
}
|
|
1849
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrSimplePivotTableComponent, decorators: [{
|
|
1850
|
+
type: Component,
|
|
1851
|
+
args: [{ selector: 'lmr-simple-pivot-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<lmr-pivot-table [transform]=\"transform\"\n [data]=\"data\"\n [config]=\"pivotConfig\"\n [query]=\"query\"\n [constraintData]=\"constraintData\"\n [collections]=\"[collection]\"\n [emptyTablesTemplateInput]=\"emptyTablesTemplate\"\n [tableCellTemplateInput]=\"tableCellTemplate\"\n (pivotDataChange)=\"pivotDataChange.emit($event)\"\n (pivotTablesChange)=\"pivotTablesChange.emit($event)\">\n</lmr-pivot-table>\n" }]
|
|
1852
|
+
}], propDecorators: { rows: [{
|
|
1853
|
+
type: Input
|
|
1854
|
+
}], attributes: [{
|
|
1855
|
+
type: Input
|
|
1856
|
+
}], color: [{
|
|
1857
|
+
type: Input
|
|
1858
|
+
}], config: [{
|
|
1859
|
+
type: Input
|
|
1860
|
+
}], transform: [{
|
|
1861
|
+
type: Input
|
|
1862
|
+
}], locale: [{
|
|
1863
|
+
type: Input
|
|
1864
|
+
}], cellClick: [{
|
|
1865
|
+
type: Output
|
|
1866
|
+
}], pivotDataChange: [{
|
|
1867
|
+
type: Output
|
|
1868
|
+
}], pivotTablesChange: [{
|
|
1869
|
+
type: Output
|
|
1593
1870
|
}], emptyTablesTemplate: [{
|
|
1594
1871
|
type: ContentChild,
|
|
1595
1872
|
args: [LmrEmptyTablesTemplateDirective, { read: TemplateRef }]
|
|
@@ -1601,20 +1878,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1601
1878
|
class LmrPivotTableModule {
|
|
1602
1879
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1603
1880
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, declarations: [LmrPivotTableComponent,
|
|
1881
|
+
LmrSimplePivotTableComponent,
|
|
1604
1882
|
PivotDataEmptyPipe,
|
|
1605
1883
|
PivotTableCellHasValuePipe,
|
|
1606
1884
|
ContrastColorPipe,
|
|
1607
1885
|
LmrEmptyTablesTemplateDirective,
|
|
1608
|
-
LmrTableCellTemplateDirective], imports: [CommonModule
|
|
1886
|
+
LmrTableCellTemplateDirective], imports: [CommonModule,
|
|
1887
|
+
ScrollingModule], exports: [LmrPivotTableComponent,
|
|
1888
|
+
LmrSimplePivotTableComponent,
|
|
1609
1889
|
LmrEmptyTablesTemplateDirective,
|
|
1610
1890
|
LmrTableCellTemplateDirective] });
|
|
1611
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, imports: [CommonModule
|
|
1891
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, imports: [CommonModule,
|
|
1892
|
+
ScrollingModule] });
|
|
1612
1893
|
}
|
|
1613
1894
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, decorators: [{
|
|
1614
1895
|
type: NgModule,
|
|
1615
1896
|
args: [{
|
|
1616
1897
|
declarations: [
|
|
1617
1898
|
LmrPivotTableComponent,
|
|
1899
|
+
LmrSimplePivotTableComponent,
|
|
1618
1900
|
PivotDataEmptyPipe,
|
|
1619
1901
|
PivotTableCellHasValuePipe,
|
|
1620
1902
|
ContrastColorPipe,
|
|
@@ -1623,9 +1905,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1623
1905
|
],
|
|
1624
1906
|
imports: [
|
|
1625
1907
|
CommonModule,
|
|
1908
|
+
ScrollingModule,
|
|
1626
1909
|
],
|
|
1627
1910
|
exports: [
|
|
1628
1911
|
LmrPivotTableComponent,
|
|
1912
|
+
LmrSimplePivotTableComponent,
|
|
1629
1913
|
LmrEmptyTablesTemplateDirective,
|
|
1630
1914
|
LmrTableCellTemplateDirective,
|
|
1631
1915
|
]
|
|
@@ -1640,5 +1924,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1640
1924
|
* Generated bundle index. Do not edit.
|
|
1641
1925
|
*/
|
|
1642
1926
|
|
|
1643
|
-
export { LmrEmptyTablesTemplateDirective, LmrPivotConfigVersion, LmrPivotTableComponent, LmrPivotTableModule, LmrPivotValueType, LmrTableCellTemplateDirective, contrastColor, createDefaultPivotConfig, createDefaultPivotStemConfig, isPivotConfigChanged, pivotAttributesAreSame, pivotConfigIsEmpty, pivotStemConfigIsEmpty };
|
|
1927
|
+
export { LmrEmptyTablesTemplateDirective, LmrPivotConfigVersion, LmrPivotTableComponent, LmrPivotTableModule, LmrPivotValueType, LmrSimplePivotTableComponent, LmrTableCellTemplateDirective, contrastColor, createDefaultPivotConfig, createDefaultPivotStemConfig, isPivotConfigChanged, pivotAttributesAreSame, pivotConfigIsEmpty, pivotStemConfigIsEmpty };
|
|
1644
1928
|
//# sourceMappingURL=lumeer-pivot.mjs.map
|