@lumeer/pivot 0.0.1 → 0.0.3
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/directives/lmr-templates.directive.mjs +27 -0
- package/esm2022/lib/lmr-pivot-table.component.mjs +81 -0
- package/esm2022/lib/lmr-pivot-table.module.mjs +42 -0
- package/esm2022/lib/pipes/contrast-color.pipe.mjs +41 -0
- package/esm2022/lib/pipes/pivot-data-empty.pipe.mjs +38 -0
- package/esm2022/lib/pipes/pivot-table-value.pipe.mjs +35 -0
- package/esm2022/lib/util/lmr-pivot-config.mjs +12 -0
- package/esm2022/lib/util/lmr-pivot-constants.mjs +12 -0
- package/esm2022/lib/util/lmr-pivot-data.mjs +2 -0
- package/esm2022/lib/util/lmr-pivot-table.mjs +2 -0
- package/esm2022/lib/util/pivot-data-converter.mjs +502 -0
- package/esm2022/lib/util/pivot-table-converter.mjs +803 -0
- package/esm2022/lib/util/pivot-util.mjs +72 -0
- package/esm2022/lumeer-pivot.mjs +5 -0
- package/esm2022/public-api.mjs +11 -0
- package/fesm2022/lumeer-pivot.mjs +1644 -0
- package/fesm2022/lumeer-pivot.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/directives/lmr-templates.directive.d.ts +14 -0
- package/lib/lmr-pivot-table.component.d.ts +31 -0
- package/lib/lmr-pivot-table.module.d.ts +12 -0
- package/lib/pipes/contrast-color.pipe.d.ts +11 -0
- package/lib/pipes/pivot-data-empty.pipe.d.ts +8 -0
- package/lib/pipes/pivot-table-value.pipe.d.ts +8 -0
- package/lib/util/lmr-pivot-config.d.ts +57 -0
- package/lib/util/lmr-pivot-constants.d.ts +11 -0
- package/lib/util/lmr-pivot-data.d.ts +34 -0
- package/lib/util/lmr-pivot-table.d.ts +18 -0
- package/lib/util/pivot-data-converter.d.ts +46 -0
- package/lib/util/pivot-table-converter.d.ts +62 -0
- package/lib/util/pivot-util.d.ts +12 -0
- package/lumeer-pivot-0.0.3.tgz +0 -0
- package/package.json +17 -4
- package/{src/public-api.ts → public-api.d.ts} +0 -4
- package/.eslintrc.json +0 -35
- package/ng-package.json +0 -7
- package/src/lib/directives/lmr-templates.directive.ts +0 -11
- package/src/lib/lmr-pivot-table.component.html +0 -69
- package/src/lib/lmr-pivot-table.component.scss +0 -69
- package/src/lib/lmr-pivot-table.component.ts +0 -108
- package/src/lib/lmr-pivot-table.module.ts +0 -28
- package/src/lib/pipes/contrast-color.pipe.ts +0 -33
- package/src/lib/pipes/pivot-data-empty.pipe.ts +0 -36
- package/src/lib/pipes/pivot-table-value.pipe.ts +0 -32
- package/src/lib/util/lmr-pivot-config.ts +0 -68
- package/src/lib/util/lmr-pivot-constants.ts +0 -13
- package/src/lib/util/lmr-pivot-data.ts +0 -57
- package/src/lib/util/lmr-pivot-table.ts +0 -38
- package/src/lib/util/pivot-data-converter.spec.ts +0 -647
- package/src/lib/util/pivot-data-converter.ts +0 -803
- package/src/lib/util/pivot-table-converter.spec.ts +0 -1045
- package/src/lib/util/pivot-table-converter.ts +0 -1118
- package/src/lib/util/pivot-util.ts +0 -92
- package/tsconfig.lib.json +0 -14
- package/tsconfig.lib.prod.json +0 -10
- package/tsconfig.spec.json +0 -14
|
@@ -0,0 +1,1644 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
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';
|
|
4
|
+
import { deepObjectsEquals, hex2rgba, isArray, isNotNullOrUndefined, flattenMatrix, uniqueValues, flattenValues, shadeColor, deepObjectCopy, isNullOrUndefined, isNumeric, toNumber } from '@lumeer/utils';
|
|
5
|
+
import { BehaviorSubject, filter, throttleTime, asyncScheduler, map, tap } from 'rxjs';
|
|
6
|
+
import * as i1 from '@angular/common';
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
|
|
9
|
+
var LmrPivotConfigVersion;
|
|
10
|
+
(function (LmrPivotConfigVersion) {
|
|
11
|
+
LmrPivotConfigVersion["V1"] = "1";
|
|
12
|
+
})(LmrPivotConfigVersion || (LmrPivotConfigVersion = {}));
|
|
13
|
+
var LmrPivotValueType;
|
|
14
|
+
(function (LmrPivotValueType) {
|
|
15
|
+
LmrPivotValueType["Default"] = "default";
|
|
16
|
+
LmrPivotValueType["ColumnPercentage"] = "column";
|
|
17
|
+
LmrPivotValueType["RowPercentage"] = "row";
|
|
18
|
+
LmrPivotValueType["AllPercentage"] = "all";
|
|
19
|
+
})(LmrPivotValueType || (LmrPivotValueType = {}));
|
|
20
|
+
|
|
21
|
+
const COLOR_GRAY100 = '#f8f9fa';
|
|
22
|
+
const COLOR_GRAY200 = '#ecf0f1';
|
|
23
|
+
const COLOR_GRAY300 = '#dee2e6';
|
|
24
|
+
const COLOR_GRAY400 = '#ced4da';
|
|
25
|
+
const COLOR_GRAY500 = '#b4bcc2';
|
|
26
|
+
const COLOR_GRAY600 = '#95a5a6';
|
|
27
|
+
const COLOR_GRAY700 = '#7b8a8b';
|
|
28
|
+
const COLOR_GRAY800 = '#343a40';
|
|
29
|
+
const COLOR_GRAY900 = '#212529';
|
|
30
|
+
const COLOR_PRIMARY = '#253746';
|
|
31
|
+
const COLOR_LIGHT = COLOR_GRAY200;
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
35
|
+
*
|
|
36
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
37
|
+
*
|
|
38
|
+
* This program is free software: you can redistribute it and/or modify
|
|
39
|
+
* it under the terms of the GNU General Public License as published by
|
|
40
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
41
|
+
* (at your option) any later version.
|
|
42
|
+
*
|
|
43
|
+
* This program is distributed in the hope that it will be useful,
|
|
44
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
45
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
46
|
+
* GNU General Public License for more details.
|
|
47
|
+
*
|
|
48
|
+
* You should have received a copy of the GNU General Public License
|
|
49
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
50
|
+
*/
|
|
51
|
+
function pivotAttributesAreSame(a1, a2) {
|
|
52
|
+
return deepObjectsEquals(cleanQueryAttribute(a1), cleanQueryAttribute(a2));
|
|
53
|
+
}
|
|
54
|
+
function isPivotConfigChanged(viewConfig, currentConfig) {
|
|
55
|
+
if (!!viewConfig.mergeTables !== !!currentConfig.mergeTables && (currentConfig.stemsConfigs || []).length > 1) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return pivotStemConfigsHasChanged(viewConfig.stemsConfigs || [], currentConfig.stemsConfigs || []);
|
|
59
|
+
}
|
|
60
|
+
function pivotStemConfigsHasChanged(s1, s2) {
|
|
61
|
+
if (s1.length !== s2.length) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return s1.some((stemConfig, index) => pivotStemConfigHasChanged(stemConfig, s2[index]));
|
|
65
|
+
}
|
|
66
|
+
function pivotStemConfigHasChanged(s1, s2) {
|
|
67
|
+
return (!deepObjectsEquals(s1.rowAttributes || [], s2.rowAttributes || []) ||
|
|
68
|
+
!deepObjectsEquals(s1.columnAttributes || [], s2.columnAttributes || []) ||
|
|
69
|
+
!deepObjectsEquals(s1.valueAttributes || [], s2.valueAttributes || []));
|
|
70
|
+
}
|
|
71
|
+
function createDefaultPivotConfig(query) {
|
|
72
|
+
const stems = (query && query.stems) || [];
|
|
73
|
+
const stemsConfigs = stems.map(stem => createDefaultPivotStemConfig(stem));
|
|
74
|
+
return { version: LmrPivotConfigVersion.V1, stemsConfigs: stemsConfigs, mergeTables: true };
|
|
75
|
+
}
|
|
76
|
+
function createDefaultPivotStemConfig(stem) {
|
|
77
|
+
return { stem, rowAttributes: [], columnAttributes: [], valueAttributes: [] };
|
|
78
|
+
}
|
|
79
|
+
function pivotConfigIsEmpty(config) {
|
|
80
|
+
return (config.stemsConfigs || []).every(stemConfig => pivotStemConfigIsEmpty(stemConfig));
|
|
81
|
+
}
|
|
82
|
+
function pivotStemConfigIsEmpty(config) {
|
|
83
|
+
return (((config && config.rowAttributes) || []).length === 0 &&
|
|
84
|
+
((config && config.columnAttributes) || []).length === 0 &&
|
|
85
|
+
((config && config.valueAttributes) || []).length === 0);
|
|
86
|
+
}
|
|
87
|
+
function contrastColor(color, returnCodes, opacity) {
|
|
88
|
+
if (!color) {
|
|
89
|
+
return returnCodes ? returnCodes.dark : COLOR_PRIMARY;
|
|
90
|
+
}
|
|
91
|
+
const f = parseInt(color.indexOf('#') === 0 ? color.slice(1) : color, 16), R = f >> 16, G = (f >> 8) & 0x00ff, B = f & 0x0000ff;
|
|
92
|
+
const luminance = (0.299 * R + 0.587 * G + 0.114 * B) / 255;
|
|
93
|
+
if (luminance > 0.5) {
|
|
94
|
+
return returnCodes ? returnCodes.dark : hex2rgba(COLOR_PRIMARY, opacity || 1);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return returnCodes ? returnCodes.light : hex2rgba(COLOR_LIGHT, opacity || 1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
103
|
+
*
|
|
104
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
105
|
+
*
|
|
106
|
+
* This program is free software: you can redistribute it and/or modify
|
|
107
|
+
* it under the terms of the GNU General Public License as published by
|
|
108
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
109
|
+
* (at your option) any later version.
|
|
110
|
+
*
|
|
111
|
+
* This program is distributed in the hope that it will be useful,
|
|
112
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
113
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
114
|
+
* GNU General Public License for more details.
|
|
115
|
+
*
|
|
116
|
+
* You should have received a copy of the GNU General Public License
|
|
117
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
118
|
+
*/
|
|
119
|
+
var PivotConfigType;
|
|
120
|
+
(function (PivotConfigType) {
|
|
121
|
+
PivotConfigType[PivotConfigType["Values"] = 0] = "Values";
|
|
122
|
+
PivotConfigType[PivotConfigType["Rows"] = 1] = "Rows";
|
|
123
|
+
PivotConfigType[PivotConfigType["Columns"] = 2] = "Columns";
|
|
124
|
+
PivotConfigType[PivotConfigType["RowsAndColumns"] = 3] = "RowsAndColumns";
|
|
125
|
+
})(PivotConfigType || (PivotConfigType = {}));
|
|
126
|
+
class PivotDataConverter {
|
|
127
|
+
collections;
|
|
128
|
+
linkTypes;
|
|
129
|
+
collectionsAttributesMap;
|
|
130
|
+
linkTypesAttributesMap;
|
|
131
|
+
data;
|
|
132
|
+
config;
|
|
133
|
+
transform;
|
|
134
|
+
constraintData;
|
|
135
|
+
dataAggregator;
|
|
136
|
+
constructor() {
|
|
137
|
+
this.dataAggregator = new DataAggregator((value, constraint, data, aggregatorAttribute) => this.formatPivotValue(value, constraint, data, aggregatorAttribute));
|
|
138
|
+
}
|
|
139
|
+
formatPivotValue(value, constraint, constraintData, aggregatorAttribute) {
|
|
140
|
+
const pivotConstraint = aggregatorAttribute.data && aggregatorAttribute.data;
|
|
141
|
+
const overrideConstraint = pivotConstraint && this.transform?.checkValidConstraintOverride?.(constraint, pivotConstraint);
|
|
142
|
+
const finalConstraint = overrideConstraint || constraint || new UnknownConstraint();
|
|
143
|
+
return this.formatDataValue(finalConstraint.createDataValue(value, constraintData), finalConstraint);
|
|
144
|
+
}
|
|
145
|
+
formatDataValue(dataValue, constraint) {
|
|
146
|
+
switch (constraint.type) {
|
|
147
|
+
case ConstraintType.DateTime:
|
|
148
|
+
return dataValue.format();
|
|
149
|
+
default:
|
|
150
|
+
return dataValue.serialize();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
updateData(config, transform, collections, linkTypes, data, constraintData) {
|
|
154
|
+
this.config = config;
|
|
155
|
+
this.transform = transform;
|
|
156
|
+
this.collections = collections;
|
|
157
|
+
this.linkTypes = linkTypes;
|
|
158
|
+
this.collectionsAttributesMap = attributesResourcesAttributesMap(collections);
|
|
159
|
+
this.linkTypesAttributesMap = attributesResourcesAttributesMap(linkTypes);
|
|
160
|
+
this.data = data;
|
|
161
|
+
this.constraintData = constraintData;
|
|
162
|
+
}
|
|
163
|
+
createData(config, transform, collections, linkTypes, data, query, constraintData) {
|
|
164
|
+
this.updateData(config, transform, collections, linkTypes, data, constraintData);
|
|
165
|
+
const { stemsConfigs, stems } = this.filterEmptyConfigs(config, query);
|
|
166
|
+
const mergeData = this.createPivotMergeData(config.mergeTables, stemsConfigs, stems);
|
|
167
|
+
const ableToMerge = mergeData.length <= 1;
|
|
168
|
+
const pivotData = this.mergePivotData(mergeData);
|
|
169
|
+
return { data: pivotData, constraintData, ableToMerge, mergeTables: config.mergeTables };
|
|
170
|
+
}
|
|
171
|
+
filterEmptyConfigs(config, query) {
|
|
172
|
+
return (config.stemsConfigs || []).reduce(({ stemsConfigs, stems }, stemConfig, index) => {
|
|
173
|
+
if (!pivotStemConfigIsEmpty(stemConfig)) {
|
|
174
|
+
const stem = (query.stems || [])[index];
|
|
175
|
+
stemsConfigs.push(stemConfig);
|
|
176
|
+
stems.push(stem);
|
|
177
|
+
}
|
|
178
|
+
return { stemsConfigs, stems };
|
|
179
|
+
}, { stemsConfigs: [], stems: [] });
|
|
180
|
+
}
|
|
181
|
+
createPivotMergeData(mergeTables, stemsConfigs, stems) {
|
|
182
|
+
return stemsConfigs.reduce((mergeData, stemConfig, index) => {
|
|
183
|
+
const configType = getPivotStemConfigType(stemConfig);
|
|
184
|
+
const mergeDataIndex = mergeData.findIndex(data => data.type === configType && canMergeConfigsByType(data.type, data.configs[0], stemConfig));
|
|
185
|
+
if (mergeTables && mergeDataIndex >= 0) {
|
|
186
|
+
mergeData[mergeDataIndex].configs.push(stemConfig);
|
|
187
|
+
mergeData[mergeDataIndex].stems.push(stems[index]);
|
|
188
|
+
mergeData[mergeDataIndex].stemsIndexes.push(index);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
mergeData.push({ configs: [stemConfig], stems: [stems[index]], stemsIndexes: [index], type: configType });
|
|
192
|
+
}
|
|
193
|
+
return mergeData;
|
|
194
|
+
}, []);
|
|
195
|
+
}
|
|
196
|
+
mergePivotData(mergeData) {
|
|
197
|
+
return mergeData.reduce((stemData, data) => {
|
|
198
|
+
if (data.type === PivotConfigType.Values) {
|
|
199
|
+
stemData.push(this.convertValueAttributes(data.configs, data.stems, data.stemsIndexes));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
stemData.push(this.transformStems(data.configs, data.stems, data.stemsIndexes));
|
|
203
|
+
}
|
|
204
|
+
return stemData;
|
|
205
|
+
}, []);
|
|
206
|
+
}
|
|
207
|
+
transformStems(configs, queryStems, stemsIndexes) {
|
|
208
|
+
const pivotColors = { rows: [], columns: [], values: [] };
|
|
209
|
+
const mergedValueAttributes = [];
|
|
210
|
+
let mergedAggregatedData = null;
|
|
211
|
+
let additionalData;
|
|
212
|
+
for (let i = 0; i < configs.length; i++) {
|
|
213
|
+
const config = configs[i];
|
|
214
|
+
const queryStem = queryStems[i];
|
|
215
|
+
const stemIndex = stemsIndexes[i];
|
|
216
|
+
const stemData = this.data?.dataByStems?.[stemIndex];
|
|
217
|
+
this.dataAggregator.updateData(this.collections, stemData?.documents || [], this.linkTypes, stemData?.linkInstances || [], queryStem, this.constraintData);
|
|
218
|
+
const rowAttributes = (config.rowAttributes || []).map(attribute => this.convertPivotRowColumnAttribute(attribute));
|
|
219
|
+
const columnAttributes = (config.columnAttributes || []).map(attribute => this.convertPivotRowColumnAttribute(attribute));
|
|
220
|
+
const valueAttributes = (config.valueAttributes || []).map(attribute => this.convertPivotAttribute(attribute));
|
|
221
|
+
pivotColors.rows.push(...this.getAttributesColors(config.rowAttributes));
|
|
222
|
+
pivotColors.columns.push(...this.getAttributesColors(config.columnAttributes));
|
|
223
|
+
pivotColors.values.push(...this.getAttributesColors(config.valueAttributes));
|
|
224
|
+
const aggregatedData = this.dataAggregator.aggregate(rowAttributes, columnAttributes, valueAttributes);
|
|
225
|
+
mergedAggregatedData = this.mergeAggregatedData(mergedAggregatedData, aggregatedData);
|
|
226
|
+
const filteredValueAttributes = (config.valueAttributes || []).filter(valueAttr => !mergedValueAttributes.some(merAttr => deepObjectsEquals(valueAttr, merAttr)));
|
|
227
|
+
mergedValueAttributes.push(...filteredValueAttributes);
|
|
228
|
+
if (!additionalData) {
|
|
229
|
+
additionalData = {
|
|
230
|
+
rowShowSums: (config.rowAttributes || []).map(attr => attr.showSums),
|
|
231
|
+
rowSticky: this.mapStickyValues((config.rowAttributes || []).map(attr => !!attr.sticky)),
|
|
232
|
+
rowSorts: (config.rowAttributes || []).map(attr => attr.sort),
|
|
233
|
+
rowAttributes: (config.rowAttributes || []).map(attr => this.pivotAttributeAttribute(attr)),
|
|
234
|
+
columnShowSums: (config.columnAttributes || []).map(attr => attr.showSums),
|
|
235
|
+
columnSticky: this.mapStickyValues((config.columnAttributes || []).map(attr => !!attr.sticky)),
|
|
236
|
+
columnSorts: (config.columnAttributes || []).map(attr => attr.sort),
|
|
237
|
+
columnAttributes: (config.columnAttributes || []).map(attr => this.pivotAttributeAttribute(attr)),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return this.convertAggregatedData(mergedAggregatedData, mergedValueAttributes, pivotColors, additionalData);
|
|
242
|
+
}
|
|
243
|
+
mapStickyValues(values) {
|
|
244
|
+
// we support only sticky rows/columns in a row
|
|
245
|
+
return values.reduce((stickyValues, sticky, index) => {
|
|
246
|
+
stickyValues.push(sticky && (index === 0 || stickyValues[index - 1]));
|
|
247
|
+
return stickyValues;
|
|
248
|
+
}, []);
|
|
249
|
+
}
|
|
250
|
+
pivotAttributeConstraint(pivotAttribute) {
|
|
251
|
+
const attribute = this.findAttributeByPivotAttribute(pivotAttribute);
|
|
252
|
+
const constraint = attribute && attribute.constraint;
|
|
253
|
+
const overrideConstraint = pivotAttribute.constraint &&
|
|
254
|
+
this.transform?.checkValidConstraintOverride?.(constraint, pivotAttribute.constraint);
|
|
255
|
+
return overrideConstraint || constraint;
|
|
256
|
+
}
|
|
257
|
+
pivotAttributeAttribute(pivotAttribute) {
|
|
258
|
+
const attribute = this.findAttributeByPivotAttribute(pivotAttribute);
|
|
259
|
+
if (attribute) {
|
|
260
|
+
const constraint = attribute?.constraint;
|
|
261
|
+
const overrideConstraint = pivotAttribute.constraint &&
|
|
262
|
+
this.transform?.checkValidConstraintOverride?.(constraint, pivotAttribute.constraint);
|
|
263
|
+
return { ...attribute, constraint: overrideConstraint || constraint || new UnknownConstraint() };
|
|
264
|
+
}
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
mergeAggregatedData(a1, a2) {
|
|
268
|
+
if (!a1 || !a2) {
|
|
269
|
+
return a1 || a2;
|
|
270
|
+
}
|
|
271
|
+
this.mergeMaps(a1.map, a2.map);
|
|
272
|
+
this.mergeMaps(a1.columnsMap, a2.columnsMap);
|
|
273
|
+
return {
|
|
274
|
+
map: a1.map,
|
|
275
|
+
columnsMap: a1.columnsMap,
|
|
276
|
+
rowLevels: Math.max(a1.rowLevels, a2.rowLevels),
|
|
277
|
+
columnLevels: Math.max(a1.columnLevels, a2.columnLevels),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
mergeMaps(m1, m2) {
|
|
281
|
+
Object.keys(m2).forEach(key => {
|
|
282
|
+
if (m1[key]) {
|
|
283
|
+
if (isArray(m1[key]) && isArray(m2[key])) {
|
|
284
|
+
m1[key].push(...m2[key]);
|
|
285
|
+
}
|
|
286
|
+
else if (!isArray(m1[key]) && !isArray(m2[key])) {
|
|
287
|
+
this.mergeMaps(m1[key], m2[key]);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
m1[key] = m2[key];
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
getAttributesColors(attributes) {
|
|
296
|
+
return (attributes || []).map(attribute => {
|
|
297
|
+
const resource = this.dataAggregator.getNextCollectionResource(attribute.resourceIndex);
|
|
298
|
+
return resource && resource.color;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
convertPivotRowColumnAttribute(pivotAttribute) {
|
|
302
|
+
return { ...this.convertPivotAttribute(pivotAttribute), data: pivotAttribute.constraint };
|
|
303
|
+
}
|
|
304
|
+
convertPivotAttribute(pivotAttribute) {
|
|
305
|
+
return { resourceIndex: pivotAttribute.resourceIndex, attributeId: pivotAttribute.attributeId };
|
|
306
|
+
}
|
|
307
|
+
convertValueAttributes(configs, stems, stemsIndexes) {
|
|
308
|
+
const data = configs.reduce((allData, config, index) => {
|
|
309
|
+
const stem = stems[index];
|
|
310
|
+
const stemIndex = stemsIndexes[index];
|
|
311
|
+
const stemData = this.data?.dataByStems?.[stemIndex];
|
|
312
|
+
this.dataAggregator.updateData(this.collections, stemData?.documents || [], this.linkTypes, stemData?.linkInstances || [], stem, this.constraintData);
|
|
313
|
+
const valueAttributes = config.valueAttributes || [];
|
|
314
|
+
allData.valueTypes.push(...valueAttributes.map(attr => attr.valueType));
|
|
315
|
+
const valueColors = this.getAttributesColors(valueAttributes);
|
|
316
|
+
const { titles, constraints } = this.createValueTitles(valueAttributes);
|
|
317
|
+
allData.titles.push(...titles);
|
|
318
|
+
allData.constraints.push(...constraints);
|
|
319
|
+
const { headers } = this.convertMapToPivotDataHeader({}, 0, [], valueColors, [], titles, allData.headers.length);
|
|
320
|
+
allData.headers.push(...headers);
|
|
321
|
+
allData.aggregations = [...(valueAttributes || []).map(valueAttribute => valueAttribute.aggregation)];
|
|
322
|
+
const { values, dataResources } = (valueAttributes || []).reduce((aggregator, valueAttribute, index) => {
|
|
323
|
+
const dataResources = this.findDataResourcesByPivotAttribute(valueAttribute);
|
|
324
|
+
const attribute = this.findAttributeByPivotAttribute(valueAttribute);
|
|
325
|
+
const value = aggregateDataResources(valueAttribute.aggregation, dataResources, attribute, true);
|
|
326
|
+
aggregator.values.push(value);
|
|
327
|
+
aggregator.dataResources.push(dataResources);
|
|
328
|
+
return aggregator;
|
|
329
|
+
}, { values: [], dataResources: [] });
|
|
330
|
+
allData.values.push(...values);
|
|
331
|
+
allData.dataResources.push(...dataResources);
|
|
332
|
+
return allData;
|
|
333
|
+
}, { titles: [], constraints: [], headers: [], values: [], dataResources: [], valueTypes: [], aggregations: [] });
|
|
334
|
+
return {
|
|
335
|
+
columnHeaders: data.headers,
|
|
336
|
+
rowHeaders: [],
|
|
337
|
+
valueTitles: data.titles,
|
|
338
|
+
values: [data.values],
|
|
339
|
+
dataResources: [data.dataResources],
|
|
340
|
+
valuesConstraints: data.constraints,
|
|
341
|
+
valueTypes: data.valueTypes,
|
|
342
|
+
valueAggregations: data.aggregations,
|
|
343
|
+
rowShowSums: [],
|
|
344
|
+
rowSticky: [],
|
|
345
|
+
rowSorts: [],
|
|
346
|
+
columnShowSums: [],
|
|
347
|
+
columnSticky: [],
|
|
348
|
+
columnSorts: [],
|
|
349
|
+
hasAdditionalColumnLevel: true,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
findDataResourcesByPivotAttribute(pivotAttribute) {
|
|
353
|
+
if (pivotAttribute.resourceType === AttributesResourceType.Collection) {
|
|
354
|
+
return (this.data?.uniqueDocuments || []).filter(document => document.collectionId === pivotAttribute.resourceId);
|
|
355
|
+
}
|
|
356
|
+
else if (pivotAttribute.resourceType === AttributesResourceType.LinkType) {
|
|
357
|
+
return (this.data?.uniqueLinkInstances || []).filter(link => link.linkTypeId === pivotAttribute.resourceId);
|
|
358
|
+
}
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
convertAggregatedData(aggregatedData, valueAttributes, pivotColors, additionalData) {
|
|
362
|
+
const rowData = this.convertMapToPivotDataHeader(aggregatedData.map, aggregatedData.rowLevels, pivotColors.rows, pivotColors.values, additionalData.rowAttributes);
|
|
363
|
+
const { titles: valueTitles, constraints: valuesConstraints } = this.createValueTitles(valueAttributes);
|
|
364
|
+
const columnData = this.convertMapToPivotDataHeader(aggregatedData.rowLevels > 0 ? aggregatedData.columnsMap : aggregatedData.map, aggregatedData.columnLevels, pivotColors.columns, pivotColors.values, additionalData.columnAttributes, valueTitles);
|
|
365
|
+
const values = this.initMatrix(rowData.maxIndex + 1, columnData.maxIndex + 1);
|
|
366
|
+
const dataResources = this.initMatrix(rowData.maxIndex + 1, columnData.maxIndex + 1);
|
|
367
|
+
if ((valueAttributes || []).length > 0) {
|
|
368
|
+
this.fillValues(values, dataResources, rowData.headers, columnData.headers, valueAttributes, aggregatedData);
|
|
369
|
+
}
|
|
370
|
+
const valueAggregations = (valueAttributes || []).map(valueAttribute => valueAttribute.aggregation);
|
|
371
|
+
const hasAdditionalColumnLevel = (aggregatedData.columnLevels === 0 && valueTitles.length > 0) ||
|
|
372
|
+
(aggregatedData.columnLevels > 0 && valueTitles.length > 1);
|
|
373
|
+
return {
|
|
374
|
+
rowHeaders: rowData.headers,
|
|
375
|
+
columnHeaders: columnData.headers,
|
|
376
|
+
valueTitles,
|
|
377
|
+
values,
|
|
378
|
+
dataResources,
|
|
379
|
+
valuesConstraints,
|
|
380
|
+
valueAggregations,
|
|
381
|
+
...additionalData,
|
|
382
|
+
valueTypes: valueAttributes.map(attr => attr.valueType),
|
|
383
|
+
hasAdditionalColumnLevel,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
convertMapToPivotDataHeader(map, levels, colors, valueColors, attributes, valueTitles, additionalNum = 0) {
|
|
387
|
+
const headers = [];
|
|
388
|
+
const data = { maxIndex: 0 };
|
|
389
|
+
if (levels === 0) {
|
|
390
|
+
if ((valueTitles || []).length > 0) {
|
|
391
|
+
headers.push(...valueTitles.map((title, index) => ({
|
|
392
|
+
title,
|
|
393
|
+
targetIndex: index + additionalNum,
|
|
394
|
+
color: valueColors[index],
|
|
395
|
+
isValueHeader: true,
|
|
396
|
+
})));
|
|
397
|
+
data.maxIndex = valueTitles.length - 1 + additionalNum;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
let currentIndex = additionalNum;
|
|
402
|
+
Object.keys(map).forEach((title, index) => {
|
|
403
|
+
const attribute = attributes && attributes[0];
|
|
404
|
+
if (levels === 1 && (valueTitles || []).length <= 1) {
|
|
405
|
+
headers.push({
|
|
406
|
+
title,
|
|
407
|
+
targetIndex: currentIndex,
|
|
408
|
+
color: colors[0],
|
|
409
|
+
constraint: attribute?.constraint || new UnknownConstraint(),
|
|
410
|
+
isValueHeader: false,
|
|
411
|
+
attributeName: attribute?.name,
|
|
412
|
+
});
|
|
413
|
+
data.maxIndex = Math.max(data.maxIndex, currentIndex);
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
headers.push({
|
|
417
|
+
title,
|
|
418
|
+
color: colors[0],
|
|
419
|
+
constraint: attribute?.constraint || new UnknownConstraint(),
|
|
420
|
+
isValueHeader: false,
|
|
421
|
+
attributeName: attribute?.name,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
this.iterateThroughPivotDataHeader(map[title], headers[index], currentIndex, 1, levels, colors, valueColors, valueTitles || [], attributes, data);
|
|
425
|
+
currentIndex += this.numChildren(map[title], levels - 1, (valueTitles && valueTitles.length) || 1);
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
return { headers, maxIndex: data.maxIndex };
|
|
429
|
+
}
|
|
430
|
+
iterateThroughPivotDataHeader(currentMap, header, headerIndex, level, maxLevels, colors, valueColors, valueTitles, attributes, additionalData) {
|
|
431
|
+
if (level === maxLevels) {
|
|
432
|
+
if ((valueTitles || []).length > 1) {
|
|
433
|
+
header.children = valueTitles.map((title, index) => ({
|
|
434
|
+
title,
|
|
435
|
+
targetIndex: headerIndex + index,
|
|
436
|
+
color: valueColors[index],
|
|
437
|
+
isValueHeader: true,
|
|
438
|
+
}));
|
|
439
|
+
additionalData.maxIndex = Math.max(additionalData.maxIndex, headerIndex + valueTitles.length - 1);
|
|
440
|
+
}
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
header.children = [];
|
|
444
|
+
let currentIndex = headerIndex;
|
|
445
|
+
Object.keys(currentMap).forEach((title, index) => {
|
|
446
|
+
const attribute = attributes && attributes[level];
|
|
447
|
+
if (level + 1 === maxLevels && (valueTitles || []).length <= 1) {
|
|
448
|
+
header.children.push({
|
|
449
|
+
title,
|
|
450
|
+
targetIndex: currentIndex,
|
|
451
|
+
color: colors[level],
|
|
452
|
+
constraint: attribute?.constraint || new UnknownConstraint(),
|
|
453
|
+
isValueHeader: false,
|
|
454
|
+
attributeName: attribute?.name,
|
|
455
|
+
});
|
|
456
|
+
additionalData.maxIndex = Math.max(additionalData.maxIndex, currentIndex);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
header.children.push({
|
|
460
|
+
title,
|
|
461
|
+
color: colors[level],
|
|
462
|
+
constraint: attribute?.constraint || new UnknownConstraint(),
|
|
463
|
+
isValueHeader: false,
|
|
464
|
+
attributeName: attribute?.name,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
this.iterateThroughPivotDataHeader(currentMap[title], header.children?.[index], currentIndex, level + 1, maxLevels, colors, valueColors, valueTitles, attributes, additionalData);
|
|
468
|
+
currentIndex += this.numChildren(currentMap[title], maxLevels - (level + 1), (valueTitles && valueTitles.length) || 1);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
numChildren(map, maxLevels, numTitles) {
|
|
472
|
+
if (maxLevels === 0) {
|
|
473
|
+
return numTitles;
|
|
474
|
+
}
|
|
475
|
+
const keys = Object.keys(map || {});
|
|
476
|
+
if (maxLevels === 1) {
|
|
477
|
+
return keys.length * numTitles;
|
|
478
|
+
}
|
|
479
|
+
const count = keys.reduce((sum, key) => sum + this.numChildrenRecursive(map[key], 1, maxLevels), 0);
|
|
480
|
+
return count * numTitles;
|
|
481
|
+
}
|
|
482
|
+
numChildrenRecursive(map, level, maxLevels) {
|
|
483
|
+
if (level >= maxLevels) {
|
|
484
|
+
return 0;
|
|
485
|
+
}
|
|
486
|
+
const keys = Object.keys(map || {});
|
|
487
|
+
if (level + 1 === maxLevels) {
|
|
488
|
+
return keys.length;
|
|
489
|
+
}
|
|
490
|
+
return keys.reduce((sum, key) => sum + this.numChildrenRecursive(map[key], level + 1, maxLevels), 0);
|
|
491
|
+
}
|
|
492
|
+
createValueTitles(valueAttributes) {
|
|
493
|
+
return (valueAttributes || []).reduce(({ titles, constraints }, pivotAttribute) => {
|
|
494
|
+
const attribute = this.findAttributeByPivotAttribute(pivotAttribute);
|
|
495
|
+
constraints.push(dataAggregationConstraint(pivotAttribute.aggregation) || this.pivotAttributeConstraint(pivotAttribute));
|
|
496
|
+
const title = this.createValueTitle(pivotAttribute.aggregation, attribute?.name || '');
|
|
497
|
+
titles.push(title);
|
|
498
|
+
return { titles, constraints };
|
|
499
|
+
}, { titles: [], constraints: [] });
|
|
500
|
+
}
|
|
501
|
+
createValueTitle(aggregation, attributeName) {
|
|
502
|
+
const valueAggregationTitle = this.transform?.translateAggregation?.(aggregation) || aggregation.toString();
|
|
503
|
+
return `${valueAggregationTitle} ${attributeName || ''}`.trim();
|
|
504
|
+
}
|
|
505
|
+
initMatrix(rows, columns) {
|
|
506
|
+
const matrix = [];
|
|
507
|
+
for (let i = 0; i < rows; i++) {
|
|
508
|
+
matrix[i] = [];
|
|
509
|
+
for (let j = 0; j < columns; j++) {
|
|
510
|
+
matrix[i][j] = undefined;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return matrix;
|
|
514
|
+
}
|
|
515
|
+
fillValues(values, dataResources, rowHeaders, columnHeaders, valueAttributes, aggregatedData) {
|
|
516
|
+
if (rowHeaders.length > 0) {
|
|
517
|
+
this.iterateThroughRowHeaders(values, dataResources, rowHeaders, columnHeaders, valueAttributes, aggregatedData.map);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
this.iterateThroughColumnHeaders(values, dataResources, columnHeaders, 0, valueAttributes, aggregatedData.map);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
iterateThroughRowHeaders(values, dataResources, rowHeaders, columnHeaders, valueAttributes, currentMap) {
|
|
524
|
+
for (const rowHeader of rowHeaders) {
|
|
525
|
+
const rowHeaderMap = currentMap[rowHeader.title] || {};
|
|
526
|
+
if (rowHeader.children) {
|
|
527
|
+
this.iterateThroughRowHeaders(values, dataResources, rowHeader.children, columnHeaders, valueAttributes, rowHeaderMap);
|
|
528
|
+
}
|
|
529
|
+
else if (isNotNullOrUndefined(rowHeader.targetIndex) && columnHeaders.length > 0) {
|
|
530
|
+
this.iterateThroughColumnHeaders(values, dataResources, columnHeaders, rowHeader.targetIndex, valueAttributes, rowHeaderMap);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
iterateThroughColumnHeaders(values, dataResources, columnHeaders, rowIndex, valueAttributes, currentMap) {
|
|
535
|
+
for (const columnHeader of columnHeaders) {
|
|
536
|
+
if (columnHeader.children) {
|
|
537
|
+
this.iterateThroughColumnHeaders(values, dataResources, columnHeader.children, rowIndex, valueAttributes, currentMap[columnHeader.title] || {});
|
|
538
|
+
}
|
|
539
|
+
else if (isNotNullOrUndefined(columnHeader.targetIndex)) {
|
|
540
|
+
const aggregatedDataValues = isArray(currentMap) ? currentMap : currentMap[columnHeader.title];
|
|
541
|
+
if (valueAttributes.length) {
|
|
542
|
+
const valueIndex = columnHeader.targetIndex % valueAttributes.length;
|
|
543
|
+
const { value, dataResources: aggregatedDataResources } = this.aggregateValue(valueAttributes[valueIndex], aggregatedDataValues);
|
|
544
|
+
values[rowIndex][columnHeader.targetIndex] = value;
|
|
545
|
+
dataResources[rowIndex][columnHeader.targetIndex] = aggregatedDataResources || [];
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
aggregateValue(valueAttribute, aggregatedDataValues) {
|
|
551
|
+
const resourceAggregatedDataValues = (aggregatedDataValues || []).filter(agg => agg.resourceId === valueAttribute.resourceId && agg.type === valueAttribute.resourceType);
|
|
552
|
+
if (resourceAggregatedDataValues.length) {
|
|
553
|
+
const dataResources = flattenMatrix(resourceAggregatedDataValues.map(val => val.objects));
|
|
554
|
+
const attribute = this.pivotAttributeAttribute(valueAttribute);
|
|
555
|
+
if (valueAttribute.aggregation === DataAggregationType.Join) {
|
|
556
|
+
// values will be joined in pivot-table-converter
|
|
557
|
+
const values = (dataResources || []).map((resource) => resource.data?.[attribute?.id || '']);
|
|
558
|
+
return { value: uniqueValues(flattenValues(values)), dataResources };
|
|
559
|
+
}
|
|
560
|
+
const value = attribute && aggregateDataResources(valueAttribute.aggregation, dataResources, attribute, true);
|
|
561
|
+
return { value, dataResources };
|
|
562
|
+
}
|
|
563
|
+
return {};
|
|
564
|
+
}
|
|
565
|
+
findAttributeByPivotAttribute(valueAttribute) {
|
|
566
|
+
if (valueAttribute.resourceType === AttributesResourceType.Collection) {
|
|
567
|
+
return this.collectionsAttributesMap?.[valueAttribute.resourceId]?.[valueAttribute.attributeId];
|
|
568
|
+
}
|
|
569
|
+
else if (valueAttribute.resourceType === AttributesResourceType.LinkType) {
|
|
570
|
+
return this.linkTypesAttributesMap?.[valueAttribute.resourceId]?.[valueAttribute.attributeId];
|
|
571
|
+
}
|
|
572
|
+
return undefined;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function getPivotStemConfigType(stemConfig) {
|
|
576
|
+
const rowLength = (stemConfig.rowAttributes || []).length;
|
|
577
|
+
const columnLength = (stemConfig.columnAttributes || []).length;
|
|
578
|
+
if (rowLength > 0 && columnLength > 0) {
|
|
579
|
+
return PivotConfigType.RowsAndColumns;
|
|
580
|
+
}
|
|
581
|
+
else if (rowLength > 0) {
|
|
582
|
+
return PivotConfigType.Rows;
|
|
583
|
+
}
|
|
584
|
+
else if (columnLength > 0) {
|
|
585
|
+
return PivotConfigType.Columns;
|
|
586
|
+
}
|
|
587
|
+
return PivotConfigType.Values;
|
|
588
|
+
}
|
|
589
|
+
function canMergeConfigsByType(type, c1, c2) {
|
|
590
|
+
if (type === PivotConfigType.Rows) {
|
|
591
|
+
return (c1.rowAttributes || []).length === (c2.rowAttributes || []).length;
|
|
592
|
+
}
|
|
593
|
+
else if (type === PivotConfigType.Columns) {
|
|
594
|
+
return (c1.columnAttributes || []).length === (c2.columnAttributes || []).length;
|
|
595
|
+
}
|
|
596
|
+
return ((c1.rowAttributes || []).length === (c2.rowAttributes || []).length &&
|
|
597
|
+
(c1.columnAttributes || []).length === (c2.columnAttributes || []).length);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/*
|
|
601
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
602
|
+
*
|
|
603
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
604
|
+
*
|
|
605
|
+
* This program is free software: you can redistribute it and/or modify
|
|
606
|
+
* it under the terms of the GNU General Public License as published by
|
|
607
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
608
|
+
* (at your option) any later version.
|
|
609
|
+
*
|
|
610
|
+
* This program is distributed in the hope that it will be useful,
|
|
611
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
612
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
613
|
+
* GNU General Public License for more details.
|
|
614
|
+
*
|
|
615
|
+
* You should have received a copy of the GNU General Public License
|
|
616
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
617
|
+
*/
|
|
618
|
+
class PivotTableConverter {
|
|
619
|
+
static emptyClass = 'pivot-empty-cell';
|
|
620
|
+
static dataClass = 'pivot-data-cell';
|
|
621
|
+
static groupDataClass = 'pivot-data-group-cell';
|
|
622
|
+
static rowHeaderClass = 'pivot-row-header-cell';
|
|
623
|
+
static rowGroupHeaderClass = 'pivot-row-group-header-cell';
|
|
624
|
+
static columnHeaderClass = 'pivot-column-header-cell';
|
|
625
|
+
static columnGroupHeaderClass = 'pivot-column-group-header-cell';
|
|
626
|
+
groupColors = [COLOR_GRAY100, COLOR_GRAY200, COLOR_GRAY300, COLOR_GRAY400, COLOR_GRAY500];
|
|
627
|
+
percentageConstraint = new PercentageConstraint({ decimals: 2 });
|
|
628
|
+
data;
|
|
629
|
+
strings;
|
|
630
|
+
values;
|
|
631
|
+
dataResources;
|
|
632
|
+
constraintData;
|
|
633
|
+
rowLevels;
|
|
634
|
+
rowsTransformationArray;
|
|
635
|
+
columnLevels;
|
|
636
|
+
columnsTransformationArray;
|
|
637
|
+
valueTypeInfo;
|
|
638
|
+
nonStickyRowIndex;
|
|
639
|
+
createTables(pivotData, strings) {
|
|
640
|
+
if (!pivotData) {
|
|
641
|
+
return [{ cells: [] }];
|
|
642
|
+
}
|
|
643
|
+
this.strings = strings;
|
|
644
|
+
this.constraintData = pivotData.constraintData;
|
|
645
|
+
return (pivotData.data || []).map(d => {
|
|
646
|
+
if (this.dataAreEmpty(d)) {
|
|
647
|
+
return { cells: [] };
|
|
648
|
+
}
|
|
649
|
+
this.updateData(d);
|
|
650
|
+
return this.transformData();
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
dataAreEmpty(data) {
|
|
654
|
+
return (data.rowHeaders || []).length === 0 && (data.columnHeaders || []).length === 0;
|
|
655
|
+
}
|
|
656
|
+
updateData(data) {
|
|
657
|
+
const numberOfSums = Math.max(1, (data.valueTitles || []).length);
|
|
658
|
+
this.valueTypeInfo = getValuesTypeInfo(data.values, data.valueTypes, numberOfSums);
|
|
659
|
+
this.data = preparePivotData(data, this.constraintData, this.valueTypeInfo);
|
|
660
|
+
this.nonStickyRowIndex = this.data.rowSticky?.findIndex(sticky => !sticky) || 0;
|
|
661
|
+
this.values = data.values || [];
|
|
662
|
+
this.dataResources = data.dataResources || [];
|
|
663
|
+
this.rowLevels = (data.rowShowSums || []).length;
|
|
664
|
+
this.columnLevels = (data.columnShowSums || []).length + (data.hasAdditionalColumnLevel ? 1 : 0);
|
|
665
|
+
const hasValue = (data.valueTitles || []).length > 0;
|
|
666
|
+
if ((this.data.rowHeaders || []).length > 0) {
|
|
667
|
+
this.rowsTransformationArray = createTransformationMap(this.data.rowHeaders, this.rowShowSums, this.columnLevels, 1);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
this.rowsTransformationArray = hasValue ? [this.columnLevels] : [];
|
|
671
|
+
}
|
|
672
|
+
if ((this.data.columnHeaders || []).length > 0) {
|
|
673
|
+
this.columnsTransformationArray = createTransformationMap(this.data.columnHeaders, this.columnShowSums, this.rowLevels, numberOfSums);
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
this.columnsTransformationArray = hasValue ? [this.rowLevels] : [];
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
get rowShowSums() {
|
|
680
|
+
return this.data.rowShowSums;
|
|
681
|
+
}
|
|
682
|
+
get columnShowSums() {
|
|
683
|
+
return this.data.columnShowSums;
|
|
684
|
+
}
|
|
685
|
+
transformData() {
|
|
686
|
+
const cells = this.initCells();
|
|
687
|
+
const rowGroups = this.fillCellsByRows(cells);
|
|
688
|
+
const columnGroups = this.fillCellsByColumns(cells);
|
|
689
|
+
this.fillCellsByGroupIntersection(cells, rowGroups, columnGroups);
|
|
690
|
+
return { cells };
|
|
691
|
+
}
|
|
692
|
+
fillCellsByRows(cells) {
|
|
693
|
+
const rowGroups = [];
|
|
694
|
+
this.iterateAndFillCellsByRows(cells, rowGroups, this.data.rowHeaders, this.columnLevels, this.rowShowSums, 0);
|
|
695
|
+
return rowGroups;
|
|
696
|
+
}
|
|
697
|
+
iterateAndFillCellsByRows(cells, rowGroupsInfo, headers, startIndex, showSums, level, parentHeader) {
|
|
698
|
+
let currentIndex = startIndex;
|
|
699
|
+
for (const header of headers) {
|
|
700
|
+
const rowSpan = getDirectHeaderChildCount(header, level, showSums);
|
|
701
|
+
cells[currentIndex][level] = {
|
|
702
|
+
value: header.title,
|
|
703
|
+
cssClass: PivotTableConverter.rowHeaderClass,
|
|
704
|
+
isHeader: true,
|
|
705
|
+
stickyStart: this.isRowLevelSticky(level),
|
|
706
|
+
rowSpan,
|
|
707
|
+
colSpan: 1,
|
|
708
|
+
background: this.getHeaderBackground(header, level),
|
|
709
|
+
constraint: header.constraint,
|
|
710
|
+
label: header.attributeName,
|
|
711
|
+
};
|
|
712
|
+
if (header.children) {
|
|
713
|
+
this.iterateAndFillCellsByRows(cells, rowGroupsInfo, header.children, currentIndex, showSums, level + 1, header);
|
|
714
|
+
}
|
|
715
|
+
else if (isNotNullOrUndefined(header.targetIndex)) {
|
|
716
|
+
this.fillCellsForRow(cells, header.targetIndex);
|
|
717
|
+
}
|
|
718
|
+
currentIndex += getHeaderChildCount(header, level, showSums);
|
|
719
|
+
}
|
|
720
|
+
if (showSums[level]) {
|
|
721
|
+
const background = this.getSummaryBackground(level);
|
|
722
|
+
const summary = level === 0 ? this.strings.summaryString : this.strings.headerSummaryString;
|
|
723
|
+
const columnIndex = Math.max(level - 1, 0);
|
|
724
|
+
let colSpan = this.rowLevels - columnIndex;
|
|
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
|
+
};
|
|
754
|
+
const rowIndexes = getTargetIndexesForHeaders(headers);
|
|
755
|
+
const transformedRowIndexes = rowIndexes
|
|
756
|
+
.map(v => this.rowsTransformationArray[v])
|
|
757
|
+
.filter(v => isNotNullOrUndefined(v));
|
|
758
|
+
rowGroupsInfo[currentIndex] = { background, indexes: transformedRowIndexes, level };
|
|
759
|
+
this.fillCellsForGroupedRow(cells, rowIndexes, currentIndex, background);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
getHeaderBackground(header, level) {
|
|
763
|
+
if (header?.color) {
|
|
764
|
+
return shadeColor(header.color, this.getLevelOpacity(level));
|
|
765
|
+
}
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
getLevelOpacity(level) {
|
|
769
|
+
return Math.min(80, 50 + level * 5) / 100;
|
|
770
|
+
}
|
|
771
|
+
isRowLevelSticky(level) {
|
|
772
|
+
return this.data?.rowSticky?.[level];
|
|
773
|
+
}
|
|
774
|
+
isColumnLevelSticky(level) {
|
|
775
|
+
const maxLevel = Math.min(level, (this.data?.columnSticky?.length ?? Number.MAX_SAFE_INTEGER) - 1);
|
|
776
|
+
return this.data?.columnSticky?.[maxLevel];
|
|
777
|
+
}
|
|
778
|
+
getSummaryBackground(level) {
|
|
779
|
+
const index = Math.min(level, this.groupColors.length - 1);
|
|
780
|
+
return this.groupColors[index];
|
|
781
|
+
}
|
|
782
|
+
fillCellsForRow(cells, row) {
|
|
783
|
+
const rowIndexInCells = this.rowsTransformationArray[row];
|
|
784
|
+
if (isNotNullOrUndefined(rowIndexInCells)) {
|
|
785
|
+
for (let column = 0; column < this.columnsTransformationArray.length; column++) {
|
|
786
|
+
const columnIndexInCells = this.columnsTransformationArray[column];
|
|
787
|
+
if (isNotNullOrUndefined(columnIndexInCells)) {
|
|
788
|
+
const value = this.data.values[row][column];
|
|
789
|
+
const dataResources = this.dataResources?.[row]?.[column] || [];
|
|
790
|
+
const formattedValue = this.aggregateOrFormatSingleValue(value, column);
|
|
791
|
+
const stringValue = isNotNullOrUndefined(formattedValue) ? String(formattedValue) : '';
|
|
792
|
+
cells[rowIndexInCells][columnIndexInCells] = {
|
|
793
|
+
value: stringValue,
|
|
794
|
+
dataResources,
|
|
795
|
+
rowSpan: 1,
|
|
796
|
+
colSpan: 1,
|
|
797
|
+
cssClass: PivotTableConverter.dataClass,
|
|
798
|
+
isHeader: false,
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
getValueIndexForColumns(columns) {
|
|
805
|
+
return columns[0] % this.data.valueTitles.length;
|
|
806
|
+
}
|
|
807
|
+
formatValueByValueType(value, valueIndex) {
|
|
808
|
+
const valueType = (this.data.valueTypes || [])[valueIndex];
|
|
809
|
+
if (!valueType || valueType === LmrPivotValueType.Default) {
|
|
810
|
+
return this.formatValueByConstraint(value, valueIndex);
|
|
811
|
+
}
|
|
812
|
+
if ([LmrPivotValueType.AllPercentage, LmrPivotValueType.ColumnPercentage, LmrPivotValueType.RowPercentage].includes(valueType)) {
|
|
813
|
+
return this.formatValueByPercentage(value);
|
|
814
|
+
}
|
|
815
|
+
return this.formatValueByConstraint(value, valueIndex);
|
|
816
|
+
}
|
|
817
|
+
formatGroupedValueByValueType(value, rows, columns) {
|
|
818
|
+
const valueIndex = columns[0] % this.data.valueTitles.length;
|
|
819
|
+
const valueType = this.data.valueTypes && this.data.valueTypes[valueIndex];
|
|
820
|
+
const valueTypeInfo = this.valueTypeInfo[valueIndex];
|
|
821
|
+
if (!valueTypeInfo || !valueType || valueType === LmrPivotValueType.Default) {
|
|
822
|
+
return this.formatValueByConstraint(value, valueIndex);
|
|
823
|
+
}
|
|
824
|
+
if (valueType === LmrPivotValueType.AllPercentage) {
|
|
825
|
+
return this.formatValueByPercentage(divideValues(value, valueTypeInfo.sum));
|
|
826
|
+
}
|
|
827
|
+
else if (valueType === LmrPivotValueType.ColumnPercentage) {
|
|
828
|
+
const columnsDividers = columns.reduce((dividers, column) => {
|
|
829
|
+
dividers.push(valueTypeInfo.sumsColumns[column]);
|
|
830
|
+
return dividers;
|
|
831
|
+
}, []);
|
|
832
|
+
const columnsDivider = aggregateDataValues(DataAggregationType.Sum, columnsDividers);
|
|
833
|
+
return this.formatValueByPercentage(divideValues(value, columnsDivider));
|
|
834
|
+
}
|
|
835
|
+
else if (valueType === LmrPivotValueType.RowPercentage) {
|
|
836
|
+
const rowsDividers = rows.reduce((dividers, row) => {
|
|
837
|
+
dividers.push(valueTypeInfo.sumsRows[row]);
|
|
838
|
+
return dividers;
|
|
839
|
+
}, []);
|
|
840
|
+
const rowsDivider = aggregateDataValues(DataAggregationType.Sum, rowsDividers);
|
|
841
|
+
return this.formatValueByPercentage(divideValues(value, rowsDivider));
|
|
842
|
+
}
|
|
843
|
+
return this.formatValueByConstraint(value, valueIndex);
|
|
844
|
+
}
|
|
845
|
+
formatValueByPercentage(value) {
|
|
846
|
+
return this.percentageConstraint.createDataValue(value).format();
|
|
847
|
+
}
|
|
848
|
+
formatValueByConstraint(value, valueIndex) {
|
|
849
|
+
const constraint = this.data.valuesConstraints?.[valueIndex] || this.valueTypeInfo[valueIndex]?.defaultConstraint;
|
|
850
|
+
if (constraint) {
|
|
851
|
+
return constraint.createDataValue(value, this.constraintData).preview();
|
|
852
|
+
}
|
|
853
|
+
return value;
|
|
854
|
+
}
|
|
855
|
+
fillCellsForGroupedRow(cells, rows, rowIndexInCells, background) {
|
|
856
|
+
for (let column = 0; column < this.columnsTransformationArray.length; column++) {
|
|
857
|
+
const columnIndexInCells = this.columnsTransformationArray[column];
|
|
858
|
+
if (isNotNullOrUndefined(columnIndexInCells)) {
|
|
859
|
+
const { values, dataResources } = this.getGroupedValuesForRowsAndCols(rows, [column]);
|
|
860
|
+
const formattedValue = this.aggregateAndFormatDataValues(values, rows, [column]);
|
|
861
|
+
cells[rowIndexInCells][columnIndexInCells] = {
|
|
862
|
+
value: String(formattedValue),
|
|
863
|
+
dataResources,
|
|
864
|
+
colSpan: 1,
|
|
865
|
+
rowSpan: 1,
|
|
866
|
+
cssClass: PivotTableConverter.groupDataClass,
|
|
867
|
+
isHeader: false,
|
|
868
|
+
background,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
getGroupedValuesForRowsAndCols(rows, columns) {
|
|
874
|
+
const values = [];
|
|
875
|
+
const dataResources = [];
|
|
876
|
+
for (const row of rows) {
|
|
877
|
+
for (const column of columns) {
|
|
878
|
+
const rowColumnValue = this.values[row][column];
|
|
879
|
+
if (isArray(rowColumnValue)) {
|
|
880
|
+
values.push(...rowColumnValue);
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
values.push(rowColumnValue);
|
|
884
|
+
}
|
|
885
|
+
dataResources.push(...(this.dataResources?.[row]?.[column] || []));
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return { values, dataResources };
|
|
889
|
+
}
|
|
890
|
+
fillCellsByColumns(cells) {
|
|
891
|
+
const columnGroups = [];
|
|
892
|
+
this.iterateAndFillCellsByColumns(cells, columnGroups, this.data.columnHeaders, this.rowLevels, this.columnShowSums, 0);
|
|
893
|
+
return columnGroups;
|
|
894
|
+
}
|
|
895
|
+
iterateAndFillCellsByColumns(cells, columnGroupsInfo, headers, startIndex, showSums, level, parentHeader) {
|
|
896
|
+
let currentIndex = startIndex;
|
|
897
|
+
const numberOfSums = Math.max(1, this.data.valueTitles.length);
|
|
898
|
+
for (const header of headers) {
|
|
899
|
+
const colSpan = getDirectHeaderChildCount(header, level, showSums, numberOfSums);
|
|
900
|
+
cells[level][currentIndex] = {
|
|
901
|
+
value: header.title,
|
|
902
|
+
cssClass: PivotTableConverter.columnHeaderClass,
|
|
903
|
+
isHeader: true,
|
|
904
|
+
rowSpan: 1,
|
|
905
|
+
colSpan,
|
|
906
|
+
stickyTop: this.isColumnLevelSticky(level),
|
|
907
|
+
background: this.getHeaderBackground(header, level),
|
|
908
|
+
constraint: header.constraint,
|
|
909
|
+
label: header.attributeName,
|
|
910
|
+
};
|
|
911
|
+
if (header.children) {
|
|
912
|
+
this.iterateAndFillCellsByColumns(cells, columnGroupsInfo, header.children, currentIndex, showSums, level + 1, header);
|
|
913
|
+
}
|
|
914
|
+
else if (isNotNullOrUndefined(header.targetIndex)) {
|
|
915
|
+
this.fillCellsForColumn(cells, header.targetIndex);
|
|
916
|
+
}
|
|
917
|
+
currentIndex += getHeaderChildCount(header, level, showSums, numberOfSums);
|
|
918
|
+
}
|
|
919
|
+
if (showSums[level]) {
|
|
920
|
+
const background = this.getSummaryBackground(level);
|
|
921
|
+
const summary = level === 0 ? this.strings.summaryString : this.strings.headerSummaryString;
|
|
922
|
+
const numberOfValues = this.data.valueTitles.length;
|
|
923
|
+
const rowIndex = Math.max(level - 1, 0);
|
|
924
|
+
const shouldAddValueHeaders = numberOfValues > 1;
|
|
925
|
+
cells[rowIndex][currentIndex] = {
|
|
926
|
+
value: parentHeader?.title,
|
|
927
|
+
constraint: parentHeader?.constraint,
|
|
928
|
+
label: parentHeader?.attributeName,
|
|
929
|
+
cssClass: PivotTableConverter.columnGroupHeaderClass,
|
|
930
|
+
isHeader: true,
|
|
931
|
+
stickyTop: this.isColumnLevelSticky(level),
|
|
932
|
+
rowSpan: this.columnLevels - rowIndex - (shouldAddValueHeaders ? 1 : 0),
|
|
933
|
+
colSpan: numberOfSums,
|
|
934
|
+
background,
|
|
935
|
+
summary,
|
|
936
|
+
};
|
|
937
|
+
if (numberOfValues > 0) {
|
|
938
|
+
for (let i = 0; i < numberOfValues; i++) {
|
|
939
|
+
const columnIndexInCells = currentIndex + i;
|
|
940
|
+
if (shouldAddValueHeaders) {
|
|
941
|
+
const valueTitle = this.data.valueTitles[i];
|
|
942
|
+
cells[this.columnLevels - 1][columnIndexInCells] = {
|
|
943
|
+
value: valueTitle,
|
|
944
|
+
cssClass: PivotTableConverter.columnGroupHeaderClass,
|
|
945
|
+
isHeader: true,
|
|
946
|
+
stickyTop: this.isColumnLevelSticky(level),
|
|
947
|
+
rowSpan: 1,
|
|
948
|
+
colSpan: 1,
|
|
949
|
+
background,
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
const columnsIndexes = getTargetIndexesForHeaders(headers);
|
|
953
|
+
const valueColumnsIndexes = columnsIndexes.filter(index => index % numberOfValues === i);
|
|
954
|
+
const transformedColumnIndexes = valueColumnsIndexes
|
|
955
|
+
.map(v => this.columnsTransformationArray[v])
|
|
956
|
+
.filter(v => isNotNullOrUndefined(v));
|
|
957
|
+
columnGroupsInfo[columnIndexInCells] = { background, indexes: transformedColumnIndexes, level };
|
|
958
|
+
this.fillCellsForGroupedColumn(cells, valueColumnsIndexes, columnIndexInCells, background);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
else {
|
|
962
|
+
columnGroupsInfo[currentIndex] = { background, indexes: [], level };
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
fillCellsForGroupedColumn(cells, columns, columnIndexInCells, background) {
|
|
967
|
+
for (let row = 0; row < this.rowsTransformationArray.length; row++) {
|
|
968
|
+
const rowIndexInCells = this.rowsTransformationArray[row];
|
|
969
|
+
if (isNotNullOrUndefined(rowIndexInCells)) {
|
|
970
|
+
const { values, dataResources } = this.getGroupedValuesForRowsAndCols([row], columns);
|
|
971
|
+
const formattedValue = this.aggregateAndFormatDataValues(values, [row], columns);
|
|
972
|
+
cells[rowIndexInCells][columnIndexInCells] = {
|
|
973
|
+
value: String(formattedValue),
|
|
974
|
+
dataResources,
|
|
975
|
+
colSpan: 1,
|
|
976
|
+
rowSpan: 1,
|
|
977
|
+
cssClass: PivotTableConverter.groupDataClass,
|
|
978
|
+
isHeader: false,
|
|
979
|
+
background,
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
aggregateAndFormatDataValues(values, rows, columns) {
|
|
985
|
+
const aggregation = this.aggregationByColumns(columns);
|
|
986
|
+
if (aggregation === DataAggregationType.Join) {
|
|
987
|
+
const valueIndex = this.getValueIndexForColumns(columns);
|
|
988
|
+
const constraint = this.data.valuesConstraints?.[valueIndex] || this.valueTypeInfo[valueIndex]?.defaultConstraint;
|
|
989
|
+
return aggregateDataValues(aggregation, values, constraint, false, this.constraintData);
|
|
990
|
+
}
|
|
991
|
+
const aggregatedValue = aggregateDataValues(aggregation, values);
|
|
992
|
+
return this.formatGroupedValueByValueType(aggregatedValue, rows, columns);
|
|
993
|
+
}
|
|
994
|
+
aggregationByColumns(columns) {
|
|
995
|
+
const valueIndex = columns[0] % this.data.valueTitles.length;
|
|
996
|
+
const aggregation = this.data.valueAggregations?.[valueIndex];
|
|
997
|
+
return isValueAggregation(aggregation) ? aggregation : DataAggregationType.Sum;
|
|
998
|
+
}
|
|
999
|
+
fillCellsForColumn(cells, column) {
|
|
1000
|
+
const columnIndexInCells = this.columnsTransformationArray[column];
|
|
1001
|
+
if (isNotNullOrUndefined(columnIndexInCells)) {
|
|
1002
|
+
for (let row = 0; row < this.rowsTransformationArray.length; row++) {
|
|
1003
|
+
const rowIndexInCells = this.rowsTransformationArray[row];
|
|
1004
|
+
if (isNotNullOrUndefined(rowIndexInCells)) {
|
|
1005
|
+
const value = this.data.values[row][column];
|
|
1006
|
+
const dataResources = this.dataResources?.[row]?.[column] || [];
|
|
1007
|
+
const formattedValue = this.aggregateOrFormatSingleValue(value, column);
|
|
1008
|
+
const stringValue = isNotNullOrUndefined(formattedValue) ? String(formattedValue) : '';
|
|
1009
|
+
cells[rowIndexInCells][columnIndexInCells] = {
|
|
1010
|
+
value: stringValue,
|
|
1011
|
+
dataResources,
|
|
1012
|
+
rowSpan: 1,
|
|
1013
|
+
colSpan: 1,
|
|
1014
|
+
cssClass: PivotTableConverter.dataClass,
|
|
1015
|
+
isHeader: false,
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
aggregateOrFormatSingleValue(value, column) {
|
|
1022
|
+
const aggregation = this.aggregationByColumns([column]);
|
|
1023
|
+
const valueIndex = this.getValueIndexForColumns([column]);
|
|
1024
|
+
if (aggregation === DataAggregationType.Join) {
|
|
1025
|
+
const constraint = this.data.valuesConstraints?.[valueIndex] || this.valueTypeInfo[valueIndex]?.defaultConstraint;
|
|
1026
|
+
return aggregateDataValues(aggregation, [value], constraint, false, this.constraintData);
|
|
1027
|
+
}
|
|
1028
|
+
return this.formatValueByValueType(value, valueIndex);
|
|
1029
|
+
}
|
|
1030
|
+
fillCellsByGroupIntersection(cells, rowGroupsInfo, columnGroupsInfo) {
|
|
1031
|
+
const rowsCount = cells.length;
|
|
1032
|
+
const columnsCount = (cells[0] && cells[0].length) || 0;
|
|
1033
|
+
for (let i = 0; i < rowGroupsInfo.length; i++) {
|
|
1034
|
+
const rowGroupInfo = rowGroupsInfo[i];
|
|
1035
|
+
if (rowGroupInfo) {
|
|
1036
|
+
for (let j = 0; j < columnGroupsInfo.length; j++) {
|
|
1037
|
+
if (columnGroupsInfo[j]) {
|
|
1038
|
+
// it's enough to fill group values only from row side
|
|
1039
|
+
const { rowsIndexes, columnsIndexes } = this.getValuesIndexesFromCellsIndexes(rowGroupInfo.indexes, columnGroupsInfo[j].indexes);
|
|
1040
|
+
const { values, dataResources } = this.getGroupedValuesForRowsAndCols(rowsIndexes, columnsIndexes);
|
|
1041
|
+
const formattedValue = this.aggregateAndFormatDataValues(values, rowsIndexes, columnsIndexes);
|
|
1042
|
+
cells[i][j] = {
|
|
1043
|
+
value: String(formattedValue),
|
|
1044
|
+
dataResources,
|
|
1045
|
+
colSpan: 1,
|
|
1046
|
+
rowSpan: 1,
|
|
1047
|
+
cssClass: PivotTableConverter.groupDataClass,
|
|
1048
|
+
isHeader: false,
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
this.fillRowWithColor(cells, i, rowGroupInfo, columnsCount);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
for (let j = 0; j < columnGroupsInfo.length; j++) {
|
|
1056
|
+
if (columnGroupsInfo[j]) {
|
|
1057
|
+
this.fillColumnWithColor(cells, j, columnGroupsInfo[j], rowGroupsInfo, rowsCount);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
getValuesIndexesFromCellsIndexes(rows, columns) {
|
|
1062
|
+
const rowsIndexes = rows
|
|
1063
|
+
.map(row => this.rowsTransformationArray.findIndex(tRow => tRow === row))
|
|
1064
|
+
.filter(index => index >= 0);
|
|
1065
|
+
const columnsIndexes = columns
|
|
1066
|
+
.map(column => this.columnsTransformationArray.findIndex(tColumn => tColumn === column))
|
|
1067
|
+
.filter(index => index >= 0);
|
|
1068
|
+
return { rowsIndexes, columnsIndexes };
|
|
1069
|
+
}
|
|
1070
|
+
fillRowWithColor(cells, row, rowGroupInfo, columnsCount) {
|
|
1071
|
+
for (let i = this.rowLevels; i < columnsCount; i++) {
|
|
1072
|
+
cells[row][i] && (cells[row][i].background = rowGroupInfo.background);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
fillColumnWithColor(cells, column, columnGroupInfo, rowGroupsInfo, rowCount) {
|
|
1076
|
+
for (let i = this.columnLevels; i < rowCount; i++) {
|
|
1077
|
+
const rowGroupInfo = rowGroupsInfo[i];
|
|
1078
|
+
if (!rowGroupInfo || rowGroupInfo.level > columnGroupInfo.level) {
|
|
1079
|
+
cells[i][column] && (cells[i][column].background = columnGroupInfo.background);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
initCells() {
|
|
1084
|
+
const rows = this.getRowsCount() + this.columnLevels;
|
|
1085
|
+
const columns = this.getColumnsCount() + this.rowLevels;
|
|
1086
|
+
const matrix = [];
|
|
1087
|
+
for (let i = 0; i < rows; i++) {
|
|
1088
|
+
matrix[i] = [];
|
|
1089
|
+
for (let j = 0; j < columns; j++) {
|
|
1090
|
+
if (i >= this.columnLevels && j >= this.rowLevels) {
|
|
1091
|
+
const isDataClass = this.rowsTransformationArray.includes(i) && this.columnsTransformationArray.includes(j);
|
|
1092
|
+
matrix[i][j] = {
|
|
1093
|
+
value: '',
|
|
1094
|
+
dataResources: [],
|
|
1095
|
+
cssClass: isDataClass ? PivotTableConverter.dataClass : PivotTableConverter.groupDataClass,
|
|
1096
|
+
rowSpan: 1,
|
|
1097
|
+
colSpan: 1,
|
|
1098
|
+
isHeader: false,
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
matrix[i][j] = undefined;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (this.rowLevels > 0 && this.columnLevels > 0) {
|
|
1107
|
+
for (let i = 0; i < this.columnLevels; i++) {
|
|
1108
|
+
for (let j = 0; j < this.rowLevels; j++) {
|
|
1109
|
+
matrix[i][j] = {
|
|
1110
|
+
value: '',
|
|
1111
|
+
cssClass: PivotTableConverter.emptyClass,
|
|
1112
|
+
rowSpan: 1,
|
|
1113
|
+
colSpan: 1,
|
|
1114
|
+
stickyStart: this.isRowLevelSticky(j),
|
|
1115
|
+
stickyTop: this.isColumnLevelSticky(i),
|
|
1116
|
+
isHeader: false,
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return matrix;
|
|
1122
|
+
}
|
|
1123
|
+
getRowsCount() {
|
|
1124
|
+
if (this.data.rowHeaders.length === 0 && (this.data.valueTitles || []).length > 0) {
|
|
1125
|
+
return 1;
|
|
1126
|
+
}
|
|
1127
|
+
return getHeadersChildCount(this.data.rowHeaders, this.rowShowSums);
|
|
1128
|
+
}
|
|
1129
|
+
getColumnsCount() {
|
|
1130
|
+
if (this.data.columnHeaders.length === 0 && (this.data.valueTitles || []).length > 0) {
|
|
1131
|
+
return 1;
|
|
1132
|
+
}
|
|
1133
|
+
const numberOfSums = Math.max(1, (this.data.valueTitles || []).length);
|
|
1134
|
+
return getHeadersChildCount(this.data.columnHeaders, this.columnShowSums, numberOfSums);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
function preparePivotData(data, constraintData, valueTypeInfo) {
|
|
1138
|
+
const numberOfSums = Math.max(1, (data.valueTitles || []).length);
|
|
1139
|
+
const values = computeValuesByValueType(data.values, data.valueTypes, numberOfSums, valueTypeInfo);
|
|
1140
|
+
return sortPivotData({ ...data, values }, constraintData);
|
|
1141
|
+
}
|
|
1142
|
+
function computeValuesByValueType(values, valueTypes, numValues, valueTypeInfo) {
|
|
1143
|
+
const rowsIndexes = [...Array(values.length).keys()];
|
|
1144
|
+
const modifiedValues = deepObjectCopy(values);
|
|
1145
|
+
for (let i = 0; i < numValues; i++) {
|
|
1146
|
+
const valueType = valueTypes && valueTypes[i];
|
|
1147
|
+
if (!valueType || valueType === LmrPivotValueType.Default) {
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
const columnsCount = (values[0] && values[0].length) || 0;
|
|
1151
|
+
const columnIndexes = [...Array(columnsCount).keys()].filter(key => key % numValues === i);
|
|
1152
|
+
const info = valueTypeInfo[i];
|
|
1153
|
+
for (const row of rowsIndexes) {
|
|
1154
|
+
for (const column of columnIndexes) {
|
|
1155
|
+
if (valueType === LmrPivotValueType.AllPercentage) {
|
|
1156
|
+
modifiedValues[row][column] = divideValues(values[row][column], info.sum);
|
|
1157
|
+
}
|
|
1158
|
+
else if (valueType === LmrPivotValueType.RowPercentage) {
|
|
1159
|
+
modifiedValues[row][column] = divideValues(values[row][column], info.sumsRows[row]);
|
|
1160
|
+
}
|
|
1161
|
+
else if (valueType === LmrPivotValueType.ColumnPercentage) {
|
|
1162
|
+
modifiedValues[row][column] = divideValues(values[row][column], info.sumsColumns[column]);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return modifiedValues;
|
|
1168
|
+
}
|
|
1169
|
+
function getValuesTypeInfo(values, valueTypes, numValues) {
|
|
1170
|
+
const valueTypeInfo = [];
|
|
1171
|
+
const rowsIndexes = [...Array(values.length).keys()];
|
|
1172
|
+
for (let i = 0; i < numValues; i++) {
|
|
1173
|
+
const valueType = valueTypes && valueTypes[i];
|
|
1174
|
+
const columnsCount = (values[0] && values[0].length) || 0;
|
|
1175
|
+
const columnIndexes = [...Array(columnsCount).keys()].filter(key => key % numValues === i);
|
|
1176
|
+
valueTypeInfo[i] = getValueTypeInfo(values, valueType, rowsIndexes, columnIndexes);
|
|
1177
|
+
}
|
|
1178
|
+
return valueTypeInfo;
|
|
1179
|
+
}
|
|
1180
|
+
function getValueTypeInfo(values, type, rows, columns) {
|
|
1181
|
+
const containsDecimal = containsDecimalValue(values, rows, columns);
|
|
1182
|
+
const valueTypeInfo = {
|
|
1183
|
+
defaultConstraint: containsDecimal ? new NumberConstraint({ decimals: 2 }) : null,
|
|
1184
|
+
};
|
|
1185
|
+
if (type === LmrPivotValueType.AllPercentage) {
|
|
1186
|
+
return { ...valueTypeInfo, sum: getNumericValuesSummary(values, rows, columns) };
|
|
1187
|
+
}
|
|
1188
|
+
else if (type === LmrPivotValueType.RowPercentage) {
|
|
1189
|
+
return {
|
|
1190
|
+
...valueTypeInfo,
|
|
1191
|
+
sumsRows: rows.reduce((arr, row) => {
|
|
1192
|
+
arr[row] = getNumericValuesSummary(values, [row], columns);
|
|
1193
|
+
return arr;
|
|
1194
|
+
}, []),
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
else if (type === LmrPivotValueType.ColumnPercentage) {
|
|
1198
|
+
return {
|
|
1199
|
+
...valueTypeInfo,
|
|
1200
|
+
sumsColumns: columns.reduce((arr, column) => {
|
|
1201
|
+
arr[column] = getNumericValuesSummary(values, rows, [column]);
|
|
1202
|
+
return arr;
|
|
1203
|
+
}, []),
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
return { ...valueTypeInfo };
|
|
1207
|
+
}
|
|
1208
|
+
function containsDecimalValue(values, rows, columns) {
|
|
1209
|
+
for (const row of rows) {
|
|
1210
|
+
for (const column of columns) {
|
|
1211
|
+
if (isValueDecimal(values[row][column])) {
|
|
1212
|
+
return true;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return false;
|
|
1217
|
+
}
|
|
1218
|
+
function isValueDecimal(value) {
|
|
1219
|
+
if (isNullOrUndefined(value)) {
|
|
1220
|
+
return false;
|
|
1221
|
+
}
|
|
1222
|
+
if (isNumeric(value)) {
|
|
1223
|
+
return toNumber(value) % 1 !== 0;
|
|
1224
|
+
}
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
function createTransformationMap(headers, showSums, additionalNum, numberOfSums) {
|
|
1228
|
+
const array = [];
|
|
1229
|
+
iterateThroughTransformationMap(headers, additionalNum, array, 0, showSums, numberOfSums);
|
|
1230
|
+
return array;
|
|
1231
|
+
}
|
|
1232
|
+
function iterateThroughTransformationMap(headers, additionalNum, array, level, showSums, numberOfSums) {
|
|
1233
|
+
let additional = additionalNum;
|
|
1234
|
+
for (let i = 0; i < headers.length; i++) {
|
|
1235
|
+
const header = headers[i];
|
|
1236
|
+
if (header.children) {
|
|
1237
|
+
iterateThroughTransformationMap(header.children, additional, array, level + 1, showSums, numberOfSums);
|
|
1238
|
+
additional += getHeaderChildCount(header, level, showSums, numberOfSums);
|
|
1239
|
+
}
|
|
1240
|
+
else if (isNotNullOrUndefined(header.targetIndex)) {
|
|
1241
|
+
array[header.targetIndex] = i + additional;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function getTargetIndexesForHeaders(headers) {
|
|
1246
|
+
const allRows = (headers || []).reduce((rows, header) => {
|
|
1247
|
+
rows.push(...getTargetIndexesForHeader(header));
|
|
1248
|
+
return rows;
|
|
1249
|
+
}, []);
|
|
1250
|
+
return uniqueValues(allRows);
|
|
1251
|
+
}
|
|
1252
|
+
function getTargetIndexesForHeader(pivotDataHeader) {
|
|
1253
|
+
if (pivotDataHeader.children) {
|
|
1254
|
+
return pivotDataHeader.children.reduce((rows, header) => {
|
|
1255
|
+
rows.push(...getTargetIndexesForHeader(header));
|
|
1256
|
+
return rows;
|
|
1257
|
+
}, []);
|
|
1258
|
+
}
|
|
1259
|
+
return [pivotDataHeader.targetIndex];
|
|
1260
|
+
}
|
|
1261
|
+
function getHeadersChildCount(headers, showSums, numberOfSums = 1) {
|
|
1262
|
+
return (headers || []).reduce((sum, header) => sum + getHeaderChildCount(header, 0, showSums, numberOfSums), showSums[0] ? numberOfSums : 0);
|
|
1263
|
+
}
|
|
1264
|
+
function getHeaderChildCount(pivotDataHeader, level, showSums, numberOfSums = 1, includeChild = true) {
|
|
1265
|
+
if (pivotDataHeader.children) {
|
|
1266
|
+
return pivotDataHeader.children.reduce((sum, header) => sum + getHeaderChildCount(header, level + 1, showSums, numberOfSums, includeChild), showSums[level + 1] ? numberOfSums : 0);
|
|
1267
|
+
}
|
|
1268
|
+
return includeChild ? 1 : 0;
|
|
1269
|
+
}
|
|
1270
|
+
function getDirectHeaderChildCount(pivotDataHeader, level, showSums, numberOfSums = 1) {
|
|
1271
|
+
if (pivotDataHeader.children) {
|
|
1272
|
+
return pivotDataHeader.children.reduce((sum, header) => sum + getHeaderChildCount(header, level + 1, showSums, numberOfSums), 0);
|
|
1273
|
+
}
|
|
1274
|
+
return 1;
|
|
1275
|
+
}
|
|
1276
|
+
function sortPivotData(data, constraintData) {
|
|
1277
|
+
return {
|
|
1278
|
+
...data,
|
|
1279
|
+
rowHeaders: sortPivotRowDataHeaders(data.rowHeaders, data.rowSorts, data, constraintData),
|
|
1280
|
+
columnHeaders: sortPivotColumnDataHeaders(data.columnHeaders, data.columnSorts, data, constraintData),
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
function sortPivotRowDataHeaders(rowHeaders, rowSorts, pivotData, constraintData) {
|
|
1284
|
+
return sortPivotDataHeadersRecursive(rowHeaders, 0, rowSorts, pivotData.columnHeaders, pivotData.values, pivotData.valueTitles || [], true, constraintData);
|
|
1285
|
+
}
|
|
1286
|
+
function sortPivotColumnDataHeaders(columnHeaders, columnSorts, pivotData, constraintData) {
|
|
1287
|
+
return sortPivotDataHeadersRecursive(columnHeaders, 0, columnSorts, pivotData.rowHeaders, pivotData.values, pivotData.valueTitles || [], false, constraintData);
|
|
1288
|
+
}
|
|
1289
|
+
function sortPivotDataHeadersRecursive(headers, index, sorts, otherSideHeaders, values, valueTitles, isRows, constraintData) {
|
|
1290
|
+
// we don't want to sort values headers
|
|
1291
|
+
if (!isRows && isValuesHeaders(headers, valueTitles)) {
|
|
1292
|
+
return headers;
|
|
1293
|
+
}
|
|
1294
|
+
const sort = sorts && sorts[index];
|
|
1295
|
+
const constraint = getConstraintForSort(sort, headers);
|
|
1296
|
+
const valuesMap = createHeadersValuesMap(headers, sort, otherSideHeaders, values, valueTitles, isRows);
|
|
1297
|
+
return headers
|
|
1298
|
+
.map(header => ({
|
|
1299
|
+
...header,
|
|
1300
|
+
children: header.children &&
|
|
1301
|
+
sortPivotDataHeadersRecursive(header.children, index + 1, sorts, otherSideHeaders, values, valueTitles, isRows, constraintData),
|
|
1302
|
+
}))
|
|
1303
|
+
.sort((r1, r2) => {
|
|
1304
|
+
const r1Value = constraint.createDataValue(valuesMap[r1.title], constraintData);
|
|
1305
|
+
const r2Value = constraint.createDataValue(valuesMap[r2.title], constraintData);
|
|
1306
|
+
const multiplier = !sort || sort.asc ? 1 : -1;
|
|
1307
|
+
return r1Value.compareTo(r2Value) * multiplier;
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
function getConstraintForSort(sort, headers) {
|
|
1311
|
+
if ((sort?.list?.values || []).length > 0) {
|
|
1312
|
+
// sort is done by values in columns
|
|
1313
|
+
return new NumberConstraint({});
|
|
1314
|
+
}
|
|
1315
|
+
return ((headers || [])[0] && (headers || [])[0].constraint) || new UnknownConstraint();
|
|
1316
|
+
}
|
|
1317
|
+
function isValuesHeaders(headers, valueTitles) {
|
|
1318
|
+
return (valueTitles.length > 1 &&
|
|
1319
|
+
(headers || []).every((header, index) => isNotNullOrUndefined(header.targetIndex) && header.title === valueTitles[index]));
|
|
1320
|
+
}
|
|
1321
|
+
function createHeadersValuesMap(headers, sort, otherSideHeaders, values, valueTitles, isRows) {
|
|
1322
|
+
const sortTargetIndexes = sortValueTargetIndexes(sort, otherSideHeaders, valueTitles);
|
|
1323
|
+
if (!sortTargetIndexes) {
|
|
1324
|
+
return (headers || []).reduce((valuesMap, header) => {
|
|
1325
|
+
valuesMap[header.title] = header.title;
|
|
1326
|
+
return valuesMap;
|
|
1327
|
+
}, {});
|
|
1328
|
+
}
|
|
1329
|
+
return (headers || []).reduce((valuesMap, header) => {
|
|
1330
|
+
const rows = isRows ? getTargetIndexesForHeader(header) : sortTargetIndexes;
|
|
1331
|
+
const columns = isRows ? sortTargetIndexes : getTargetIndexesForHeader(header);
|
|
1332
|
+
valuesMap[header.title] = getNumericValuesSummary(values, rows, columns);
|
|
1333
|
+
return valuesMap;
|
|
1334
|
+
}, {});
|
|
1335
|
+
}
|
|
1336
|
+
function getNumericValuesSummary(values, rows, columns) {
|
|
1337
|
+
let sum = 0;
|
|
1338
|
+
for (const row of rows) {
|
|
1339
|
+
for (const column of columns) {
|
|
1340
|
+
const value = values[row][column];
|
|
1341
|
+
if (isNotNullOrUndefined(value) && isNumeric(value)) {
|
|
1342
|
+
sum += toNumber(value);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return sum;
|
|
1347
|
+
}
|
|
1348
|
+
function sortValueTargetIndexes(sort, otherSideHeaders, valueTitles) {
|
|
1349
|
+
if (sort && sort.list) {
|
|
1350
|
+
let valueIndex = valueTitles.findIndex(title => title === sort.list.valueTitle);
|
|
1351
|
+
if (valueIndex === -1) {
|
|
1352
|
+
if (valueTitles.length === 1) {
|
|
1353
|
+
valueIndex = 0;
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
return null;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
let pivotHeader = null;
|
|
1360
|
+
let currentOtherSideHeaders = otherSideHeaders;
|
|
1361
|
+
for (const value of sort.list.values || []) {
|
|
1362
|
+
if (value.isSummary) {
|
|
1363
|
+
const indexes = getTargetIndexesForHeaders(currentOtherSideHeaders || []) || [];
|
|
1364
|
+
return filterIndexesByMod(indexes, valueTitles.length, valueIndex);
|
|
1365
|
+
}
|
|
1366
|
+
pivotHeader = (currentOtherSideHeaders || []).find(header => header.title === value.title);
|
|
1367
|
+
if (!pivotHeader) {
|
|
1368
|
+
break;
|
|
1369
|
+
}
|
|
1370
|
+
currentOtherSideHeaders = pivotHeader.children || [];
|
|
1371
|
+
}
|
|
1372
|
+
if (pivotHeader) {
|
|
1373
|
+
const targetIndexes = isNotNullOrUndefined(pivotHeader.targetIndex)
|
|
1374
|
+
? [pivotHeader.targetIndex]
|
|
1375
|
+
: getTargetIndexesForHeaders(currentOtherSideHeaders);
|
|
1376
|
+
return filterIndexesByMod(targetIndexes, valueTitles.length, valueIndex);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return null;
|
|
1380
|
+
}
|
|
1381
|
+
function filterIndexesByMod(indexes, mod, value) {
|
|
1382
|
+
return (indexes || []).filter(index => index % mod === value);
|
|
1383
|
+
}
|
|
1384
|
+
function divideValues(value, divider) {
|
|
1385
|
+
if (isNullOrUndefined(value)) {
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
if (isNumeric(value) && isNumeric(divider)) {
|
|
1389
|
+
if (divider !== 0) {
|
|
1390
|
+
return value / divider;
|
|
1391
|
+
}
|
|
1392
|
+
else {
|
|
1393
|
+
return 0;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
class LmrEmptyTablesTemplateDirective {
|
|
1400
|
+
template;
|
|
1401
|
+
constructor(template) {
|
|
1402
|
+
this.template = template;
|
|
1403
|
+
}
|
|
1404
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrEmptyTablesTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1405
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LmrEmptyTablesTemplateDirective, selector: "[lmr-empty-tables-tmp]", ngImport: i0 });
|
|
1406
|
+
}
|
|
1407
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrEmptyTablesTemplateDirective, decorators: [{
|
|
1408
|
+
type: Directive,
|
|
1409
|
+
args: [{ selector: '[lmr-empty-tables-tmp]' }]
|
|
1410
|
+
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
|
|
1411
|
+
class LmrTableCellTemplateDirective {
|
|
1412
|
+
template;
|
|
1413
|
+
constructor(template) {
|
|
1414
|
+
this.template = template;
|
|
1415
|
+
}
|
|
1416
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrTableCellTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1417
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LmrTableCellTemplateDirective, selector: "[lmr-table-cell-tmp]", ngImport: i0 });
|
|
1418
|
+
}
|
|
1419
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrTableCellTemplateDirective, decorators: [{
|
|
1420
|
+
type: Directive,
|
|
1421
|
+
args: [{ selector: '[lmr-table-cell-tmp]' }]
|
|
1422
|
+
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
|
|
1423
|
+
|
|
1424
|
+
/*
|
|
1425
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
1426
|
+
*
|
|
1427
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
1428
|
+
*
|
|
1429
|
+
* This program is free software: you can redistribute it and/or modify
|
|
1430
|
+
* it under the terms of the GNU General Public License as published by
|
|
1431
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
1432
|
+
* (at your option) any later version.
|
|
1433
|
+
*
|
|
1434
|
+
* This program is distributed in the hope that it will be useful,
|
|
1435
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1436
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1437
|
+
* GNU General Public License for more details.
|
|
1438
|
+
*
|
|
1439
|
+
* You should have received a copy of the GNU General Public License
|
|
1440
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
1441
|
+
*/
|
|
1442
|
+
class PivotDataEmptyPipe {
|
|
1443
|
+
transform(value) {
|
|
1444
|
+
let anythingToDisplay = false;
|
|
1445
|
+
value?.data?.forEach(d => {
|
|
1446
|
+
anythingToDisplay = anythingToDisplay || d.columnHeaders?.length > 0 || d.rowHeaders?.length > 0;
|
|
1447
|
+
});
|
|
1448
|
+
return !anythingToDisplay;
|
|
1449
|
+
}
|
|
1450
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PivotDataEmptyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1451
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: PivotDataEmptyPipe, name: "pivotDataEmpty" });
|
|
1452
|
+
}
|
|
1453
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PivotDataEmptyPipe, decorators: [{
|
|
1454
|
+
type: Pipe,
|
|
1455
|
+
args: [{
|
|
1456
|
+
name: 'pivotDataEmpty',
|
|
1457
|
+
}]
|
|
1458
|
+
}] });
|
|
1459
|
+
|
|
1460
|
+
/*
|
|
1461
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
1462
|
+
*
|
|
1463
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
1464
|
+
*
|
|
1465
|
+
* This program is free software: you can redistribute it and/or modify
|
|
1466
|
+
* it under the terms of the GNU General Public License as published by
|
|
1467
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
1468
|
+
* (at your option) any later version.
|
|
1469
|
+
*
|
|
1470
|
+
* This program is distributed in the hope that it will be useful,
|
|
1471
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1472
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1473
|
+
* GNU General Public License for more details.
|
|
1474
|
+
*
|
|
1475
|
+
* You should have received a copy of the GNU General Public License
|
|
1476
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
1477
|
+
*/
|
|
1478
|
+
class PivotTableCellHasValuePipe {
|
|
1479
|
+
transform(cell) {
|
|
1480
|
+
return isNotNullOrUndefined(cell.value) && String(cell.value).trim() !== '';
|
|
1481
|
+
}
|
|
1482
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PivotTableCellHasValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1483
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: PivotTableCellHasValuePipe, name: "pivotTableCellHasValue" });
|
|
1484
|
+
}
|
|
1485
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PivotTableCellHasValuePipe, decorators: [{
|
|
1486
|
+
type: Pipe,
|
|
1487
|
+
args: [{
|
|
1488
|
+
name: 'pivotTableCellHasValue',
|
|
1489
|
+
}]
|
|
1490
|
+
}] });
|
|
1491
|
+
|
|
1492
|
+
/*
|
|
1493
|
+
* Lumeer: Modern Data Definition and Processing Platform
|
|
1494
|
+
*
|
|
1495
|
+
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
|
|
1496
|
+
*
|
|
1497
|
+
* This program is free software: you can redistribute it and/or modify
|
|
1498
|
+
* it under the terms of the GNU General Public License as published by
|
|
1499
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
1500
|
+
* (at your option) any later version.
|
|
1501
|
+
*
|
|
1502
|
+
* This program is distributed in the hope that it will be useful,
|
|
1503
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1504
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1505
|
+
* GNU General Public License for more details.
|
|
1506
|
+
*
|
|
1507
|
+
* You should have received a copy of the GNU General Public License
|
|
1508
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
1509
|
+
*/
|
|
1510
|
+
class ContrastColorPipe {
|
|
1511
|
+
transform(color, returnCodes, opacity) {
|
|
1512
|
+
return contrastColor(color, returnCodes, opacity);
|
|
1513
|
+
}
|
|
1514
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ContrastColorPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1515
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: ContrastColorPipe, name: "contrastColor" });
|
|
1516
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ContrastColorPipe, providedIn: 'root' });
|
|
1517
|
+
}
|
|
1518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ContrastColorPipe, decorators: [{
|
|
1519
|
+
type: Pipe,
|
|
1520
|
+
args: [{
|
|
1521
|
+
name: 'contrastColor',
|
|
1522
|
+
}]
|
|
1523
|
+
}, {
|
|
1524
|
+
type: Injectable,
|
|
1525
|
+
args: [{
|
|
1526
|
+
providedIn: 'root',
|
|
1527
|
+
}]
|
|
1528
|
+
}] });
|
|
1529
|
+
|
|
1530
|
+
class LmrPivotTableComponent {
|
|
1531
|
+
collections;
|
|
1532
|
+
data;
|
|
1533
|
+
linkTypes;
|
|
1534
|
+
query;
|
|
1535
|
+
constraintData;
|
|
1536
|
+
config;
|
|
1537
|
+
transform;
|
|
1538
|
+
strings;
|
|
1539
|
+
cellClick = new EventEmitter();
|
|
1540
|
+
pivotDataChange = new EventEmitter();
|
|
1541
|
+
emptyTablesTemplate;
|
|
1542
|
+
tableCellTemplate;
|
|
1543
|
+
pivotTransformer = new PivotDataConverter();
|
|
1544
|
+
pivotTableConverter = new PivotTableConverter();
|
|
1545
|
+
dataSubject = new BehaviorSubject(null);
|
|
1546
|
+
pivotData$;
|
|
1547
|
+
pivotTables$;
|
|
1548
|
+
ngOnInit() {
|
|
1549
|
+
const observable = this.dataSubject.pipe(filter(data => !!data));
|
|
1550
|
+
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.strings)));
|
|
1552
|
+
}
|
|
1553
|
+
handleData(data) {
|
|
1554
|
+
return this.pivotTransformer.createData(data.config, data.transform, data.collections, data.linkTypes, data.data, data.query, data.constraintData);
|
|
1555
|
+
}
|
|
1556
|
+
ngOnChanges(changes) {
|
|
1557
|
+
this.dataSubject.next({
|
|
1558
|
+
config: this.config,
|
|
1559
|
+
transform: this.transform,
|
|
1560
|
+
collections: this.collections,
|
|
1561
|
+
linkTypes: this.linkTypes,
|
|
1562
|
+
data: this.data,
|
|
1563
|
+
query: this.query,
|
|
1564
|
+
constraintData: this.constraintData,
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
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", strings: "strings" }, outputs: { cellClick: "cellClick", pivotDataChange: "pivotDataChange" }, 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 <div class=\"d-flex align-items-center h-100\">\n <span class=\"summary\" [class.me-2]=\"cellData.hasValue\">{{cell.summary}}</span>\n <ng-container *ngIf=\"cellData.hasValue\">\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 || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </ng-container>\n </div>\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 || 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 || 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{text-align:right}.pivot-column-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-column-group-header-cell.sticky-top,.pivot-empty-cell.sticky-top{position:sticky;z-index:10}.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
|
+
}
|
|
1570
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableComponent, decorators: [{
|
|
1571
|
+
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 <span class=\"summary\" [class.me-2]=\"cellData.hasValue\">{{cell.summary}}</span>\n <ng-container *ngIf=\"cellData.hasValue\">\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 || defaultTableCellTemplate\"\n [ngTemplateOutletContext]=\"{ value: cell.value, cell: cell }\">\n </ng-template>\n </ng-container>\n </div>\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 || 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 || 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{text-align:right}.pivot-column-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-column-group-header-cell.sticky-top,.pivot-empty-cell.sticky-top{position:sticky;z-index:10}.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
|
+
}], propDecorators: { collections: [{
|
|
1574
|
+
type: Input
|
|
1575
|
+
}], data: [{
|
|
1576
|
+
type: Input
|
|
1577
|
+
}], linkTypes: [{
|
|
1578
|
+
type: Input
|
|
1579
|
+
}], query: [{
|
|
1580
|
+
type: Input
|
|
1581
|
+
}], constraintData: [{
|
|
1582
|
+
type: Input
|
|
1583
|
+
}], config: [{
|
|
1584
|
+
type: Input
|
|
1585
|
+
}], transform: [{
|
|
1586
|
+
type: Input
|
|
1587
|
+
}], strings: [{
|
|
1588
|
+
type: Input
|
|
1589
|
+
}], cellClick: [{
|
|
1590
|
+
type: Output
|
|
1591
|
+
}], pivotDataChange: [{
|
|
1592
|
+
type: Output
|
|
1593
|
+
}], emptyTablesTemplate: [{
|
|
1594
|
+
type: ContentChild,
|
|
1595
|
+
args: [LmrEmptyTablesTemplateDirective, { read: TemplateRef }]
|
|
1596
|
+
}], tableCellTemplate: [{
|
|
1597
|
+
type: ContentChild,
|
|
1598
|
+
args: [LmrTableCellTemplateDirective, { read: TemplateRef }]
|
|
1599
|
+
}] } });
|
|
1600
|
+
|
|
1601
|
+
class LmrPivotTableModule {
|
|
1602
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1603
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, declarations: [LmrPivotTableComponent,
|
|
1604
|
+
PivotDataEmptyPipe,
|
|
1605
|
+
PivotTableCellHasValuePipe,
|
|
1606
|
+
ContrastColorPipe,
|
|
1607
|
+
LmrEmptyTablesTemplateDirective,
|
|
1608
|
+
LmrTableCellTemplateDirective], imports: [CommonModule], exports: [LmrPivotTableComponent,
|
|
1609
|
+
LmrEmptyTablesTemplateDirective,
|
|
1610
|
+
LmrTableCellTemplateDirective] });
|
|
1611
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, imports: [CommonModule] });
|
|
1612
|
+
}
|
|
1613
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LmrPivotTableModule, decorators: [{
|
|
1614
|
+
type: NgModule,
|
|
1615
|
+
args: [{
|
|
1616
|
+
declarations: [
|
|
1617
|
+
LmrPivotTableComponent,
|
|
1618
|
+
PivotDataEmptyPipe,
|
|
1619
|
+
PivotTableCellHasValuePipe,
|
|
1620
|
+
ContrastColorPipe,
|
|
1621
|
+
LmrEmptyTablesTemplateDirective,
|
|
1622
|
+
LmrTableCellTemplateDirective,
|
|
1623
|
+
],
|
|
1624
|
+
imports: [
|
|
1625
|
+
CommonModule,
|
|
1626
|
+
],
|
|
1627
|
+
exports: [
|
|
1628
|
+
LmrPivotTableComponent,
|
|
1629
|
+
LmrEmptyTablesTemplateDirective,
|
|
1630
|
+
LmrTableCellTemplateDirective,
|
|
1631
|
+
]
|
|
1632
|
+
}]
|
|
1633
|
+
}] });
|
|
1634
|
+
|
|
1635
|
+
/*
|
|
1636
|
+
* Public API Surface of lmr-pivot-table
|
|
1637
|
+
*/
|
|
1638
|
+
|
|
1639
|
+
/**
|
|
1640
|
+
* Generated bundle index. Do not edit.
|
|
1641
|
+
*/
|
|
1642
|
+
|
|
1643
|
+
export { LmrEmptyTablesTemplateDirective, LmrPivotConfigVersion, LmrPivotTableComponent, LmrPivotTableModule, LmrPivotValueType, LmrTableCellTemplateDirective, contrastColor, createDefaultPivotConfig, createDefaultPivotStemConfig, isPivotConfigChanged, pivotAttributesAreSame, pivotConfigIsEmpty, pivotStemConfigIsEmpty };
|
|
1644
|
+
//# sourceMappingURL=lumeer-pivot.mjs.map
|