@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.
Files changed (56) hide show
  1. package/esm2022/lib/directives/lmr-templates.directive.mjs +27 -0
  2. package/esm2022/lib/lmr-pivot-table.component.mjs +81 -0
  3. package/esm2022/lib/lmr-pivot-table.module.mjs +42 -0
  4. package/esm2022/lib/pipes/contrast-color.pipe.mjs +41 -0
  5. package/esm2022/lib/pipes/pivot-data-empty.pipe.mjs +38 -0
  6. package/esm2022/lib/pipes/pivot-table-value.pipe.mjs +35 -0
  7. package/esm2022/lib/util/lmr-pivot-config.mjs +12 -0
  8. package/esm2022/lib/util/lmr-pivot-constants.mjs +12 -0
  9. package/esm2022/lib/util/lmr-pivot-data.mjs +2 -0
  10. package/esm2022/lib/util/lmr-pivot-table.mjs +2 -0
  11. package/esm2022/lib/util/pivot-data-converter.mjs +502 -0
  12. package/esm2022/lib/util/pivot-table-converter.mjs +803 -0
  13. package/esm2022/lib/util/pivot-util.mjs +72 -0
  14. package/esm2022/lumeer-pivot.mjs +5 -0
  15. package/esm2022/public-api.mjs +11 -0
  16. package/fesm2022/lumeer-pivot.mjs +1644 -0
  17. package/fesm2022/lumeer-pivot.mjs.map +1 -0
  18. package/index.d.ts +5 -0
  19. package/lib/directives/lmr-templates.directive.d.ts +14 -0
  20. package/lib/lmr-pivot-table.component.d.ts +31 -0
  21. package/lib/lmr-pivot-table.module.d.ts +12 -0
  22. package/lib/pipes/contrast-color.pipe.d.ts +11 -0
  23. package/lib/pipes/pivot-data-empty.pipe.d.ts +8 -0
  24. package/lib/pipes/pivot-table-value.pipe.d.ts +8 -0
  25. package/lib/util/lmr-pivot-config.d.ts +57 -0
  26. package/lib/util/lmr-pivot-constants.d.ts +11 -0
  27. package/lib/util/lmr-pivot-data.d.ts +34 -0
  28. package/lib/util/lmr-pivot-table.d.ts +18 -0
  29. package/lib/util/pivot-data-converter.d.ts +46 -0
  30. package/lib/util/pivot-table-converter.d.ts +62 -0
  31. package/lib/util/pivot-util.d.ts +12 -0
  32. package/lumeer-pivot-0.0.3.tgz +0 -0
  33. package/package.json +17 -4
  34. package/{src/public-api.ts → public-api.d.ts} +0 -4
  35. package/.eslintrc.json +0 -35
  36. package/ng-package.json +0 -7
  37. package/src/lib/directives/lmr-templates.directive.ts +0 -11
  38. package/src/lib/lmr-pivot-table.component.html +0 -69
  39. package/src/lib/lmr-pivot-table.component.scss +0 -69
  40. package/src/lib/lmr-pivot-table.component.ts +0 -108
  41. package/src/lib/lmr-pivot-table.module.ts +0 -28
  42. package/src/lib/pipes/contrast-color.pipe.ts +0 -33
  43. package/src/lib/pipes/pivot-data-empty.pipe.ts +0 -36
  44. package/src/lib/pipes/pivot-table-value.pipe.ts +0 -32
  45. package/src/lib/util/lmr-pivot-config.ts +0 -68
  46. package/src/lib/util/lmr-pivot-constants.ts +0 -13
  47. package/src/lib/util/lmr-pivot-data.ts +0 -57
  48. package/src/lib/util/lmr-pivot-table.ts +0 -38
  49. package/src/lib/util/pivot-data-converter.spec.ts +0 -647
  50. package/src/lib/util/pivot-data-converter.ts +0 -803
  51. package/src/lib/util/pivot-table-converter.spec.ts +0 -1045
  52. package/src/lib/util/pivot-table-converter.ts +0 -1118
  53. package/src/lib/util/pivot-util.ts +0 -92
  54. package/tsconfig.lib.json +0 -14
  55. package/tsconfig.lib.prod.json +0 -10
  56. 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\">&nbsp;</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>&nbsp;</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\">&nbsp;</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>&nbsp;</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