@hrforte/react-pivottable 2.2.2 → 3.0.0
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/dist/PivotDataWorker.js +219 -13
- package/dist/PivotDataWorker.js.map +1 -1
- package/dist/PivotTable.js +2 -1
- package/dist/PivotTable.js.map +1 -1
- package/dist/PivotTableUI.js +39 -66
- package/dist/PivotTableUI.js.map +1 -1
- package/dist/TableRenderers.js +568 -106
- package/dist/TableRenderers.js.map +1 -1
- package/dist/Utilities.js +104 -179
- package/dist/Utilities.js.map +1 -1
- package/dist/__tests__/PivotDataWorker-test.js +437 -7
- package/dist/__tests__/PivotDataWorker-test.js.map +1 -1
- package/dist/__tests__/PivotTableUI-processing-test.js +41 -2
- package/dist/__tests__/PivotTableUI-processing-test.js.map +1 -1
- package/dist/__tests__/TableRenderers-showNumericalOrder-test.js +449 -0
- package/dist/__tests__/TableRenderers-showNumericalOrder-test.js.map +1 -1
- package/dist/__tests__/pivotCompute-test.js +137 -0
- package/dist/__tests__/pivotCompute-test.js.map +1 -1
- package/dist/pivot-worker.js +509 -201
- package/dist/pivotCompute.js +237 -12
- package/dist/pivotCompute.js.map +1 -1
- package/dist/pivotWorker.js +165 -9
- package/dist/pivotWorker.js.map +1 -1
- package/dist/pivottable.css +274 -266
- package/package.json +1 -1
package/dist/pivotCompute.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.WORKER_DEBOUNCE_MS = exports.DEFAULT_WORKER_THRESHOLD = undefined;
|
|
6
|
+
exports.WORKER_DEBOUNCE_MS = exports.VIRTUAL_COLUMN_THRESHOLD = exports.VIRTUAL_ROW_THRESHOLD = exports.DEFAULT_WORKER_THRESHOLD = undefined;
|
|
7
7
|
|
|
8
8
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /* eslint-disable no-console */
|
|
9
9
|
/* eslint-disable valid-jsdoc */
|
|
@@ -22,6 +22,11 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
|
|
22
22
|
exports.materializeData = materializeData;
|
|
23
23
|
exports.computePivotState = computePivotState;
|
|
24
24
|
exports.serializePivotData = serializePivotData;
|
|
25
|
+
exports.getPivotViewportRowCount = getPivotViewportRowCount;
|
|
26
|
+
exports.getPivotViewportColumnCount = getPivotViewportColumnCount;
|
|
27
|
+
exports.alignSparseColumnsToRows = alignSparseColumnsToRows;
|
|
28
|
+
exports.createVirtualPivotSummary = createVirtualPivotSummary;
|
|
29
|
+
exports.computePivotViewport = computePivotViewport;
|
|
25
30
|
exports.sortersHaveFunctions = sortersHaveFunctions;
|
|
26
31
|
exports.sanitizeSorters = sanitizeSorters;
|
|
27
32
|
exports.createWorkerConfig = createWorkerConfig;
|
|
@@ -34,21 +39,34 @@ var _Utilities = require('./Utilities');
|
|
|
34
39
|
// larger ones are handed off to the Web Worker.
|
|
35
40
|
var DEFAULT_WORKER_THRESHOLD = exports.DEFAULT_WORKER_THRESHOLD = 200;
|
|
36
41
|
|
|
42
|
+
// Keep this in the computation module so the worker and renderer make the
|
|
43
|
+
// same decision about when a compact, viewport-backed result can be used.
|
|
44
|
+
var VIRTUAL_ROW_THRESHOLD = exports.VIRTUAL_ROW_THRESHOLD = 300;
|
|
45
|
+
var VIRTUAL_COLUMN_THRESHOLD = exports.VIRTUAL_COLUMN_THRESHOLD = 100;
|
|
46
|
+
|
|
47
|
+
var FLAT_KEY_SEPARATOR = String.fromCharCode(0);
|
|
48
|
+
var SPARSE_CELL_FACTOR = 4;
|
|
49
|
+
|
|
37
50
|
// Trailing debounce before a worker computation is dispatched, so rapid
|
|
38
51
|
// interactions do not queue one full computation per single change.
|
|
39
52
|
var WORKER_DEBOUNCE_MS = exports.WORKER_DEBOUNCE_MS = 100;
|
|
40
53
|
|
|
41
54
|
/*
|
|
42
55
|
* Walks the raw input once and computes the attribute-value inventory plus a
|
|
43
|
-
*
|
|
56
|
+
* materialized view of the records (with derived attributes applied). Object
|
|
57
|
+
* arrays without derived attributes are reused to avoid a second pointer
|
|
58
|
+
* array for large datasets.
|
|
44
59
|
* This is an exact extraction of the historical PivotTableUI behavior.
|
|
45
60
|
*/
|
|
46
61
|
function materializeData(data, derivedAttributes) {
|
|
47
62
|
var attrValues = {};
|
|
48
|
-
var
|
|
63
|
+
var canReuseInput = Array.isArray(data) && !Array.isArray(data[0]) && Object.keys(derivedAttributes || {}).length === 0;
|
|
64
|
+
var materializedInput = canReuseInput ? data : [];
|
|
49
65
|
var recordsProcessed = 0;
|
|
50
66
|
_Utilities.PivotData.forEachRecord(data, derivedAttributes || {}, function (record) {
|
|
51
|
-
|
|
67
|
+
if (!canReuseInput) {
|
|
68
|
+
materializedInput.push(record);
|
|
69
|
+
}
|
|
52
70
|
var _iteratorNormalCompletion = true;
|
|
53
71
|
var _didIteratorError = false;
|
|
54
72
|
var _iteratorError = undefined;
|
|
@@ -114,14 +132,10 @@ function computePivotState(materialized, config) {
|
|
|
114
132
|
*/
|
|
115
133
|
function serializePivotData(pivotData, materialized) {
|
|
116
134
|
var serializeCell = function serializeCell(cell) {
|
|
117
|
-
|
|
118
|
-
pivotData.aggregations.forEach(function (agg) {
|
|
135
|
+
return pivotData.aggregations.map(function (agg) {
|
|
119
136
|
var instance = cell.getInstance(agg.key);
|
|
120
|
-
|
|
121
|
-
values[agg.key] = instance.value();
|
|
122
|
-
}
|
|
137
|
+
return instance ? instance.value() : null;
|
|
123
138
|
});
|
|
124
|
-
return { values: values };
|
|
125
139
|
};
|
|
126
140
|
|
|
127
141
|
var tree = {};
|
|
@@ -157,11 +171,203 @@ function serializePivotData(pivotData, materialized) {
|
|
|
157
171
|
return Object.assign({}, agg);
|
|
158
172
|
}),
|
|
159
173
|
attrValues: materialized.attrValues,
|
|
160
|
-
materializedInput: materialized.materializedInput,
|
|
161
174
|
totalRecords: materialized.totalRecords
|
|
162
175
|
};
|
|
163
176
|
}
|
|
164
177
|
|
|
178
|
+
function getPivotViewportRowCount(precomputed, columnMode) {
|
|
179
|
+
var aggregations = precomputed.aggregations || [];
|
|
180
|
+
var expandAggregations = aggregations.length > 1 && !columnMode;
|
|
181
|
+
var rowKeyCount = precomputed.rowKeys.length || (expandAggregations ? 1 : 0);
|
|
182
|
+
return rowKeyCount * (expandAggregations ? aggregations.length : 1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getPivotViewportColumnCount(precomputed, columnMode) {
|
|
186
|
+
var colKeys = precomputed.colKeys || [];
|
|
187
|
+
if (!columnMode) {
|
|
188
|
+
return colKeys.length;
|
|
189
|
+
}
|
|
190
|
+
var aggregations = precomputed.aggregations || [];
|
|
191
|
+
var baseColumnCount = colKeys.length || 1;
|
|
192
|
+
return baseColumnCount * aggregations.length;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// A high-cardinality field on both axes creates a sparse matrix. Natural row
|
|
196
|
+
// and column sorting can put every populated cell outside the first viewport,
|
|
197
|
+
// making a correctly computed table look empty. For extremely sparse virtual
|
|
198
|
+
// tables, keep every column but order it by the first sorted row that contains
|
|
199
|
+
// a value. Dense pivots keep their normal column order.
|
|
200
|
+
function alignSparseColumnsToRows(precomputed) {
|
|
201
|
+
var rowKeys = precomputed.rowKeys || [];
|
|
202
|
+
var colKeys = precomputed.colKeys || [];
|
|
203
|
+
if (rowKeys.length <= VIRTUAL_ROW_THRESHOLD || colKeys.length <= VIRTUAL_COLUMN_THRESHOLD) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
var maxSparseCells = Math.max(rowKeys.length, colKeys.length) * SPARSE_CELL_FACTOR;
|
|
208
|
+
var nonEmptyCells = 0;
|
|
209
|
+
var columnIndexByFlatKey = {};
|
|
210
|
+
colKeys.forEach(function (colKey, index) {
|
|
211
|
+
columnIndexByFlatKey[colKey.join(FLAT_KEY_SEPARATOR)] = index;
|
|
212
|
+
});
|
|
213
|
+
var seenColumnIndexes = {};
|
|
214
|
+
var orderedColumnIndexes = [];
|
|
215
|
+
|
|
216
|
+
var _loop = function _loop(rowIndex) {
|
|
217
|
+
var flatRowKey = rowKeys[rowIndex].join(FLAT_KEY_SEPARATOR);
|
|
218
|
+
var rowBranch = (precomputed.tree || {})[flatRowKey] || {};
|
|
219
|
+
var rowColumnIndexes = [];
|
|
220
|
+
var flatColumnKeys = Object.keys(rowBranch);
|
|
221
|
+
nonEmptyCells += flatColumnKeys.length;
|
|
222
|
+
if (nonEmptyCells > maxSparseCells) {
|
|
223
|
+
return {
|
|
224
|
+
v: false
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
flatColumnKeys.forEach(function (flatColumnKey) {
|
|
228
|
+
var columnIndex = columnIndexByFlatKey[flatColumnKey];
|
|
229
|
+
if (typeof columnIndex === 'number' && !seenColumnIndexes[columnIndex]) {
|
|
230
|
+
seenColumnIndexes[columnIndex] = true;
|
|
231
|
+
rowColumnIndexes.push(columnIndex);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
rowColumnIndexes.sort(function (a, b) {
|
|
235
|
+
return a - b;
|
|
236
|
+
});
|
|
237
|
+
rowColumnIndexes.forEach(function (columnIndex) {
|
|
238
|
+
return orderedColumnIndexes.push(columnIndex);
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
for (var rowIndex = 0; rowIndex < rowKeys.length; rowIndex++) {
|
|
243
|
+
var _ret = _loop(rowIndex);
|
|
244
|
+
|
|
245
|
+
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (nonEmptyCells === 0) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
colKeys.forEach(function (colKey, index) {
|
|
252
|
+
if (!seenColumnIndexes[index]) {
|
|
253
|
+
orderedColumnIndexes.push(index);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
precomputed.colKeys = orderedColumnIndexes.map(function (index) {
|
|
257
|
+
return colKeys[index];
|
|
258
|
+
});
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/*
|
|
263
|
+
* Creates the small result kept on the main thread for a virtualized table.
|
|
264
|
+
* Cell and row-total values stay in the worker and are transferred only for
|
|
265
|
+
* the visible viewport. Column totals remain here because the totals footer
|
|
266
|
+
* is always visible.
|
|
267
|
+
*/
|
|
268
|
+
function createVirtualPivotSummary(precomputed, columnMode) {
|
|
269
|
+
return {
|
|
270
|
+
rowKeys: [],
|
|
271
|
+
colKeys: precomputed.colKeys,
|
|
272
|
+
tree: {},
|
|
273
|
+
rowTotals: {},
|
|
274
|
+
colTotals: {},
|
|
275
|
+
allTotal: precomputed.allTotal,
|
|
276
|
+
aggregations: precomputed.aggregations,
|
|
277
|
+
attrValues: precomputed.attrValues,
|
|
278
|
+
totalRecords: precomputed.totalRecords,
|
|
279
|
+
totalRows: getPivotViewportRowCount(precomputed, columnMode),
|
|
280
|
+
totalColumns: getPivotViewportColumnCount(precomputed, columnMode),
|
|
281
|
+
virtualized: true
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Build only the rows requested by a virtualized table. The result contains
|
|
286
|
+
// plain data and can cross the worker boundary without cloning the full pivot.
|
|
287
|
+
function computePivotViewport(precomputed, start, end, columnMode) {
|
|
288
|
+
var columnStart = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
|
|
289
|
+
var columnEnd = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : Number.MAX_SAFE_INTEGER;
|
|
290
|
+
|
|
291
|
+
var aggregations = precomputed.aggregations || [];
|
|
292
|
+
var expandAggregations = aggregations.length > 1 && !columnMode;
|
|
293
|
+
var rowKeys = expandAggregations && precomputed.rowKeys.length === 0 ? [[]] : precomputed.rowKeys;
|
|
294
|
+
var totalRows = getPivotViewportRowCount(precomputed, columnMode);
|
|
295
|
+
var first = Math.max(0, Math.min(totalRows, Math.floor(start)));
|
|
296
|
+
var last = Math.max(first, Math.min(totalRows, Math.floor(end)));
|
|
297
|
+
var colKeys = precomputed.colKeys || [];
|
|
298
|
+
var baseColKeys = columnMode && colKeys.length === 0 ? [[]] : colKeys;
|
|
299
|
+
var totalColumns = getPivotViewportColumnCount(precomputed, columnMode);
|
|
300
|
+
var firstColumn = Math.max(0, Math.min(totalColumns, Math.floor(columnStart)));
|
|
301
|
+
var lastColumn = Math.max(firstColumn, Math.min(totalColumns, Math.floor(columnEnd)));
|
|
302
|
+
var visibleFlatColumnKeys = {};
|
|
303
|
+
for (var column = firstColumn; column < lastColumn; column++) {
|
|
304
|
+
var baseColumnIndex = columnMode ? Math.floor(column / aggregations.length) : column;
|
|
305
|
+
var colKey = baseColKeys[baseColumnIndex];
|
|
306
|
+
if (colKey) {
|
|
307
|
+
visibleFlatColumnKeys[colKey.join(FLAT_KEY_SEPARATOR)] = true;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
var selectVisibleCells = function selectVisibleCells(source) {
|
|
311
|
+
if (!source) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
var selected = {};
|
|
315
|
+
Object.keys(visibleFlatColumnKeys).forEach(function (flatColKey) {
|
|
316
|
+
if (flatColKey in source) {
|
|
317
|
+
selected[flatColKey] = source[flatColKey];
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
return selected;
|
|
321
|
+
};
|
|
322
|
+
var rows = [];
|
|
323
|
+
|
|
324
|
+
for (var index = first; index < last; index++) {
|
|
325
|
+
var rowIndex = expandAggregations ? Math.floor(index / aggregations.length) : index;
|
|
326
|
+
var rowKey = rowKeys[rowIndex];
|
|
327
|
+
var aggregation = expandAggregations ? aggregations[index % aggregations.length] : aggregations[0];
|
|
328
|
+
var flatRowKey = rowKey.join(FLAT_KEY_SEPARATOR);
|
|
329
|
+
rows.push({
|
|
330
|
+
displayKey: expandAggregations ? rowKey.concat([aggregation.label || aggregation.aggregatorName]) : rowKey,
|
|
331
|
+
actualKey: rowKey,
|
|
332
|
+
aggregationKey: aggregation.key,
|
|
333
|
+
spans: [],
|
|
334
|
+
cells: precomputed.tree ? selectVisibleCells(precomputed.tree[flatRowKey] || {}) : null,
|
|
335
|
+
rowTotal: precomputed.rowTotals ? precomputed.rowTotals[flatRowKey] || null : null
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Merge repeated row labels inside this window. Doing it here keeps the
|
|
340
|
+
// prefix comparisons off the main thread for worker-backed tables.
|
|
341
|
+
var columns = rows.length > 0 ? rows[0].displayKey.length : 0;
|
|
342
|
+
for (var _column = 0; _column < columns; _column++) {
|
|
343
|
+
var runStart = 0;
|
|
344
|
+
for (var _index = 1; _index <= rows.length; _index++) {
|
|
345
|
+
var samePrefix = _index < rows.length;
|
|
346
|
+
for (var part = 0; samePrefix && part <= _column; part++) {
|
|
347
|
+
samePrefix = rows[_index - 1].displayKey[part] === rows[_index].displayKey[part];
|
|
348
|
+
}
|
|
349
|
+
if (!samePrefix) {
|
|
350
|
+
rows[runStart].spans[_column] = _index - runStart;
|
|
351
|
+
for (var merged = runStart + 1; merged < _index; merged++) {
|
|
352
|
+
rows[merged].spans[_column] = -1;
|
|
353
|
+
}
|
|
354
|
+
runStart = _index;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
start: first,
|
|
361
|
+
end: last,
|
|
362
|
+
totalRows: totalRows,
|
|
363
|
+
columnStart: firstColumn,
|
|
364
|
+
columnEnd: lastColumn,
|
|
365
|
+
totalColumns: totalColumns,
|
|
366
|
+
colTotals: selectVisibleCells(precomputed.colTotals || {}),
|
|
367
|
+
rows: rows
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
165
371
|
/*
|
|
166
372
|
* Sorters containing functions cannot be structured-cloned into a worker.
|
|
167
373
|
* Returns true when the sorters prop itself, or any of its entries, is a
|
|
@@ -215,7 +421,11 @@ function createWorkerConfig(props) {
|
|
|
215
421
|
rowOrder: props.rowOrder,
|
|
216
422
|
colOrder: props.colOrder,
|
|
217
423
|
rowSorts: props.rowSorts,
|
|
218
|
-
colSorts: props.colSorts
|
|
424
|
+
colSorts: props.colSorts,
|
|
425
|
+
virtualizeRows: Boolean(props.virtualizeRows),
|
|
426
|
+
rendererName: props.rendererName,
|
|
427
|
+
aggregationDisplayMode: props.tableOptions && props.tableOptions.aggregationDisplayMode,
|
|
428
|
+
sortersRequireMainThread: sortersHaveFunctions(props.sorters)
|
|
219
429
|
};
|
|
220
430
|
}
|
|
221
431
|
|
|
@@ -249,6 +459,21 @@ function canComputeInWorker(props) {
|
|
|
249
459
|
return false;
|
|
250
460
|
}
|
|
251
461
|
|
|
462
|
+
if (Object.keys(props.derivedAttributes || {}).length > 0) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
var requestedAggregatorNames = Array.isArray(props.aggregations) ? props.aggregations.map(function (aggregation) {
|
|
467
|
+
return aggregation.aggregatorName;
|
|
468
|
+
}) : [props.aggregatorName || 'Count'];
|
|
469
|
+
var aggregatorMap = props.aggregators || _Utilities.PivotData.defaultProps.aggregators;
|
|
470
|
+
var usesCustomAggregator = requestedAggregatorNames.some(function (name) {
|
|
471
|
+
return typeof aggregatorMap[name] !== 'undefined' && aggregatorMap[name] !== _Utilities.PivotData.defaultProps.aggregators[name];
|
|
472
|
+
});
|
|
473
|
+
if (usesCustomAggregator) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
|
|
252
477
|
return true;
|
|
253
478
|
}
|
|
254
479
|
//# sourceMappingURL=pivotCompute.js.map
|
package/dist/pivotCompute.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pivotCompute.js"],"names":["materializeData","computePivotState","serializePivotData","sortersHaveFunctions","sanitizeSorters","createWorkerConfig","createComputeSignature","canComputeInWorker","DEFAULT_WORKER_THRESHOLD","WORKER_DEBOUNCE_MS","data","derivedAttributes","attrValues","materializedInput","recordsProcessed","PivotData","forEachRecord","record","push","Object","keys","attr","null","value","totalRecords","materialized","config","pivotData","assign","getRowKeys","getColKeys","serializeCell","values","aggregations","forEach","instance","cell","getInstance","agg","key","tree","rowBranch","flatRowKey","serializedRow","flatColKey","serializeTotals","serialized","totals","flatKey","rowKeys","map","slice","colKeys","rowTotals","colTotals","allTotal","sorters","some","clean","sorter","Array","isArray","props","rows","cols","aggregatorName","vals","valueFilter","rowOrder","colOrder","rowSorts","colSorts","JSON","stringify","options","enabled","Worker","threshold","length"],"mappings":"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","file":"pivotCompute.js","sourcesContent":["/* eslint-disable no-console */\n/* eslint-disable valid-jsdoc */\n/*\n * Shared pivot-computation logic.\n *\n * This module contains the pure, DOM-free parts of the pivot computation so\n * that the exact same code paths can run:\n * - on the main thread (classic synchronous rendering path), and\n * - inside a Web Worker (src/pivotWorker.js) for large datasets.\n *\n * It must stay free of React and of any `window`/`document` references.\n */\nimport {PivotData} from './Utilities';\n\n// Datasets smaller than this are computed synchronously on the main thread;\n// larger ones are handed off to the Web Worker.\nexport const DEFAULT_WORKER_THRESHOLD = 200;\n\n// Trailing debounce before a worker computation is dispatched, so rapid\n// interactions do not queue one full computation per single change.\nexport const WORKER_DEBOUNCE_MS = 100;\n\n/*\n * Walks the raw input once and computes the attribute-value inventory plus a\n * \"materialized\" copy of the records (with derived attributes applied).\n * This is an exact extraction of the historical PivotTableUI behavior.\n */\nexport function materializeData(data, derivedAttributes) {\n const attrValues = {};\n const materializedInput = [];\n let recordsProcessed = 0;\n PivotData.forEachRecord(data, derivedAttributes || {}, function(record) {\n materializedInput.push(record);\n for (const attr of Object.keys(record)) {\n if (!(attr in attrValues)) {\n attrValues[attr] = {};\n if (recordsProcessed > 0) {\n attrValues[attr].null = recordsProcessed;\n }\n }\n }\n for (const attr in attrValues) {\n const value = attr in record ? record[attr] : 'null';\n if (!(value in attrValues[attr])) {\n attrValues[attr][value] = 0;\n }\n attrValues[attr][value]++;\n }\n recordsProcessed++;\n });\n return {attrValues, materializedInput, totalRecords: recordsProcessed};\n}\n\n/*\n * Aggregates an already-materialized dataset into a PivotData instance and\n * serializes the result into a plain (structured-cloneable) object that can\n * cross the worker boundary and later hydrate PivotData on the main thread.\n */\nexport function computePivotState(materialized, config) {\n const pivotData = new PivotData(\n Object.assign({}, config, {\n data: materialized.materializedInput,\n derivedAttributes: {},\n })\n );\n // Force key sorting to happen while we are (possibly) inside the worker.\n pivotData.getRowKeys();\n pivotData.getColKeys();\n return serializePivotData(pivotData, materialized);\n}\n\n/*\n * Serializes a fully-built PivotData instance into plain data. Only the final\n * aggregated value of every cell is kept; `value()` and `format()` behavior\n * are reconstructed on the main thread by the PivotData hydration step.\n */\nexport function serializePivotData(pivotData, materialized) {\n const serializeCell = cell => {\n const values = {};\n pivotData.aggregations.forEach(agg => {\n const instance = cell.getInstance(agg.key);\n if (instance) {\n values[agg.key] = instance.value();\n }\n });\n return {values};\n };\n\n const tree = {};\n Object.keys(pivotData.tree).forEach(flatRowKey => {\n const rowBranch = pivotData.tree[flatRowKey];\n const serializedRow = {};\n Object.keys(rowBranch).forEach(flatColKey => {\n serializedRow[flatColKey] = serializeCell(rowBranch[flatColKey]);\n });\n tree[flatRowKey] = serializedRow;\n });\n\n const serializeTotals = totals => {\n const serialized = {};\n Object.keys(totals).forEach(flatKey => {\n serialized[flatKey] = serializeCell(totals[flatKey]);\n });\n return serialized;\n };\n\n return {\n rowKeys: pivotData.rowKeys.map(key => key.slice()),\n colKeys: pivotData.colKeys.map(key => key.slice()),\n tree,\n rowTotals: serializeTotals(pivotData.rowTotals),\n colTotals: serializeTotals(pivotData.colTotals),\n allTotal: serializeCell(pivotData.allTotal),\n aggregations: pivotData.aggregations.map(agg => Object.assign({}, agg)),\n attrValues: materialized.attrValues,\n materializedInput: materialized.materializedInput,\n totalRecords: materialized.totalRecords,\n };\n}\n\n/*\n * Sorters containing functions cannot be structured-cloned into a worker.\n * Returns true when the sorters prop itself, or any of its entries, is a\n * function. In that case PivotData re-sorts on the main thread after\n * hydration (distinct keys are few, so this stays cheap).\n */\nexport function sortersHaveFunctions(sorters) {\n if (typeof sorters === 'function') {\n return true;\n }\n if (!sorters || typeof sorters !== 'object') {\n return false;\n }\n return Object.keys(sorters).some(attr => typeof sorters[attr] === 'function');\n}\n\n/*\n * Returns a structured-cloneable subset of the sorters prop: data-type names\n * and sample-value arrays survive the worker boundary, functions do not.\n */\nexport function sanitizeSorters(sorters) {\n if (\n !sorters ||\n typeof sorters !== 'object' ||\n typeof sorters === 'function'\n ) {\n return {};\n }\n const clean = {};\n Object.keys(sorters).forEach(attr => {\n const sorter = sorters[attr];\n if (typeof sorter === 'string' || Array.isArray(sorter)) {\n clean[attr] = sorter;\n }\n });\n return clean;\n}\n\n/*\n * Extracts exactly the props PivotData needs to compute results, with\n * everything non-serializable stripped, so the object can be posted to the\n * worker and fed straight into PivotData.\n */\nexport function createWorkerConfig(props) {\n return {\n rows: props.rows,\n cols: props.cols,\n aggregatorName: props.aggregatorName,\n aggregations: props.aggregations,\n vals: props.vals,\n valueFilter: props.valueFilter,\n sorters: sanitizeSorters(props.sorters),\n rowOrder: props.rowOrder,\n colOrder: props.colOrder,\n rowSorts: props.rowSorts,\n colSorts: props.colSorts,\n };\n}\n\n/*\n * Stable string signature of everything that influences a worker computation.\n * Data identity is NOT part of it; callers append their own data version.\n */\nexport function createComputeSignature(props) {\n return JSON.stringify(createWorkerConfig(props));\n}\n\n/*\n * Decides whether the current props can be computed inside the Web Worker.\n * Anything that cannot be structured-cloned (function data sources, custom\n * derivedAttributes, custom aggregator maps) forces the classic path.\n * Function-based sorters are allowed: they are re-applied on the main thread.\n */\nexport function canComputeInWorker(props, options = {}) {\n if (options.enabled === false) {\n return false;\n }\n if (typeof Worker === 'undefined') {\n return false;\n }\n const threshold =\n typeof options.threshold === 'number'\n ? options.threshold\n : DEFAULT_WORKER_THRESHOLD;\n\n const data = props.data;\n if (!Array.isArray(data) || data.length < threshold) {\n return false;\n }\n\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pivotCompute.js"],"names":["materializeData","computePivotState","serializePivotData","getPivotViewportRowCount","getPivotViewportColumnCount","alignSparseColumnsToRows","createVirtualPivotSummary","computePivotViewport","sortersHaveFunctions","sanitizeSorters","createWorkerConfig","createComputeSignature","canComputeInWorker","DEFAULT_WORKER_THRESHOLD","VIRTUAL_ROW_THRESHOLD","VIRTUAL_COLUMN_THRESHOLD","FLAT_KEY_SEPARATOR","String","fromCharCode","SPARSE_CELL_FACTOR","WORKER_DEBOUNCE_MS","data","derivedAttributes","attrValues","canReuseInput","Array","isArray","Object","keys","length","materializedInput","recordsProcessed","PivotData","forEachRecord","record","push","attr","null","value","totalRecords","materialized","config","pivotData","assign","getRowKeys","getColKeys","serializeCell","aggregations","map","instance","cell","getInstance","agg","key","tree","forEach","rowBranch","flatRowKey","serializedRow","flatColKey","serializeTotals","serialized","totals","flatKey","rowKeys","slice","colKeys","rowTotals","colTotals","allTotal","precomputed","columnMode","expandAggregations","rowKeyCount","baseColumnCount","maxSparseCells","Math","max","nonEmptyCells","columnIndexByFlatKey","colKey","index","join","seenColumnIndexes","orderedColumnIndexes","rowIndex","rowColumnIndexes","flatColumnKeys","columnIndex","flatColumnKey","sort","a","b","totalRows","totalColumns","virtualized","start","end","columnStart","columnEnd","Number","MAX_SAFE_INTEGER","first","min","floor","last","baseColKeys","firstColumn","lastColumn","visibleFlatColumnKeys","column","baseColumnIndex","selectVisibleCells","source","selected","rows","rowKey","aggregation","displayKey","concat","label","aggregatorName","actualKey","aggregationKey","spans","cells","rowTotal","columns","runStart","samePrefix","part","merged","sorters","some","clean","sorter","props","cols","vals","valueFilter","rowOrder","colOrder","rowSorts","colSorts","virtualizeRows","Boolean","rendererName","aggregationDisplayMode","tableOptions","sortersRequireMainThread","JSON","stringify","options","enabled","Worker","threshold","requestedAggregatorNames","aggregatorMap","aggregators","defaultProps","usesCustomAggregator","name"],"mappings":"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","file":"pivotCompute.js","sourcesContent":["/* eslint-disable no-console */\n/* eslint-disable valid-jsdoc */\n/*\n * Shared pivot-computation logic.\n *\n * This module contains the pure, DOM-free parts of the pivot computation so\n * that the exact same code paths can run:\n * - on the main thread (classic synchronous rendering path), and\n * - inside a Web Worker (src/pivotWorker.js) for large datasets.\n *\n * It must stay free of React and of any `window`/`document` references.\n */\nimport {PivotData} from './Utilities';\n\n// Datasets smaller than this are computed synchronously on the main thread;\n// larger ones are handed off to the Web Worker.\nexport const DEFAULT_WORKER_THRESHOLD = 200;\n\n// Keep this in the computation module so the worker and renderer make the\n// same decision about when a compact, viewport-backed result can be used.\nexport const VIRTUAL_ROW_THRESHOLD = 300;\nexport const VIRTUAL_COLUMN_THRESHOLD = 100;\n\nconst FLAT_KEY_SEPARATOR = String.fromCharCode(0);\nconst SPARSE_CELL_FACTOR = 4;\n\n// Trailing debounce before a worker computation is dispatched, so rapid\n// interactions do not queue one full computation per single change.\nexport const WORKER_DEBOUNCE_MS = 100;\n\n/*\n * Walks the raw input once and computes the attribute-value inventory plus a\n * materialized view of the records (with derived attributes applied). Object\n * arrays without derived attributes are reused to avoid a second pointer\n * array for large datasets.\n * This is an exact extraction of the historical PivotTableUI behavior.\n */\nexport function materializeData(data, derivedAttributes) {\n const attrValues = {};\n const canReuseInput =\n Array.isArray(data) &&\n !Array.isArray(data[0]) &&\n Object.keys(derivedAttributes || {}).length === 0;\n const materializedInput = canReuseInput ? data : [];\n let recordsProcessed = 0;\n PivotData.forEachRecord(data, derivedAttributes || {}, function(record) {\n if (!canReuseInput) {\n materializedInput.push(record);\n }\n for (const attr of Object.keys(record)) {\n if (!(attr in attrValues)) {\n attrValues[attr] = {};\n if (recordsProcessed > 0) {\n attrValues[attr].null = recordsProcessed;\n }\n }\n }\n for (const attr in attrValues) {\n const value = attr in record ? record[attr] : 'null';\n if (!(value in attrValues[attr])) {\n attrValues[attr][value] = 0;\n }\n attrValues[attr][value]++;\n }\n recordsProcessed++;\n });\n return {attrValues, materializedInput, totalRecords: recordsProcessed};\n}\n\n/*\n * Aggregates an already-materialized dataset into a PivotData instance and\n * serializes the result into a plain (structured-cloneable) object that can\n * cross the worker boundary and later hydrate PivotData on the main thread.\n */\nexport function computePivotState(materialized, config) {\n const pivotData = new PivotData(\n Object.assign({}, config, {\n data: materialized.materializedInput,\n derivedAttributes: {},\n })\n );\n // Force key sorting to happen while we are (possibly) inside the worker.\n pivotData.getRowKeys();\n pivotData.getColKeys();\n return serializePivotData(pivotData, materialized);\n}\n\n/*\n * Serializes a fully-built PivotData instance into plain data. Only the final\n * aggregated value of every cell is kept; `value()` and `format()` behavior\n * are reconstructed on the main thread by the PivotData hydration step.\n */\nexport function serializePivotData(pivotData, materialized) {\n const serializeCell = cell =>\n pivotData.aggregations.map(agg => {\n const instance = cell.getInstance(agg.key);\n return instance ? instance.value() : null;\n });\n\n const tree = {};\n Object.keys(pivotData.tree).forEach(flatRowKey => {\n const rowBranch = pivotData.tree[flatRowKey];\n const serializedRow = {};\n Object.keys(rowBranch).forEach(flatColKey => {\n serializedRow[flatColKey] = serializeCell(rowBranch[flatColKey]);\n });\n tree[flatRowKey] = serializedRow;\n });\n\n const serializeTotals = totals => {\n const serialized = {};\n Object.keys(totals).forEach(flatKey => {\n serialized[flatKey] = serializeCell(totals[flatKey]);\n });\n return serialized;\n };\n\n return {\n rowKeys: pivotData.rowKeys.map(key => key.slice()),\n colKeys: pivotData.colKeys.map(key => key.slice()),\n tree,\n rowTotals: serializeTotals(pivotData.rowTotals),\n colTotals: serializeTotals(pivotData.colTotals),\n allTotal: serializeCell(pivotData.allTotal),\n aggregations: pivotData.aggregations.map(agg => Object.assign({}, agg)),\n attrValues: materialized.attrValues,\n totalRecords: materialized.totalRecords,\n };\n}\n\nexport function getPivotViewportRowCount(precomputed, columnMode) {\n const aggregations = precomputed.aggregations || [];\n const expandAggregations = aggregations.length > 1 && !columnMode;\n const rowKeyCount =\n precomputed.rowKeys.length || (expandAggregations ? 1 : 0);\n return rowKeyCount * (expandAggregations ? aggregations.length : 1);\n}\n\nexport function getPivotViewportColumnCount(precomputed, columnMode) {\n const colKeys = precomputed.colKeys || [];\n if (!columnMode) {\n return colKeys.length;\n }\n const aggregations = precomputed.aggregations || [];\n const baseColumnCount = colKeys.length || 1;\n return baseColumnCount * aggregations.length;\n}\n\n// A high-cardinality field on both axes creates a sparse matrix. Natural row\n// and column sorting can put every populated cell outside the first viewport,\n// making a correctly computed table look empty. For extremely sparse virtual\n// tables, keep every column but order it by the first sorted row that contains\n// a value. Dense pivots keep their normal column order.\nexport function alignSparseColumnsToRows(precomputed) {\n const rowKeys = precomputed.rowKeys || [];\n const colKeys = precomputed.colKeys || [];\n if (\n rowKeys.length <= VIRTUAL_ROW_THRESHOLD ||\n colKeys.length <= VIRTUAL_COLUMN_THRESHOLD\n ) {\n return false;\n }\n\n const maxSparseCells =\n Math.max(rowKeys.length, colKeys.length) * SPARSE_CELL_FACTOR;\n let nonEmptyCells = 0;\n const columnIndexByFlatKey = {};\n colKeys.forEach((colKey, index) => {\n columnIndexByFlatKey[colKey.join(FLAT_KEY_SEPARATOR)] = index;\n });\n const seenColumnIndexes = {};\n const orderedColumnIndexes = [];\n\n for (let rowIndex = 0; rowIndex < rowKeys.length; rowIndex++) {\n const flatRowKey = rowKeys[rowIndex].join(FLAT_KEY_SEPARATOR);\n const rowBranch = (precomputed.tree || {})[flatRowKey] || {};\n const rowColumnIndexes = [];\n const flatColumnKeys = Object.keys(rowBranch);\n nonEmptyCells += flatColumnKeys.length;\n if (nonEmptyCells > maxSparseCells) {\n return false;\n }\n flatColumnKeys.forEach(flatColumnKey => {\n const columnIndex = columnIndexByFlatKey[flatColumnKey];\n if (typeof columnIndex === 'number' && !seenColumnIndexes[columnIndex]) {\n seenColumnIndexes[columnIndex] = true;\n rowColumnIndexes.push(columnIndex);\n }\n });\n rowColumnIndexes.sort((a, b) => a - b);\n rowColumnIndexes.forEach(columnIndex =>\n orderedColumnIndexes.push(columnIndex)\n );\n }\n\n if (nonEmptyCells === 0) {\n return false;\n }\n colKeys.forEach((colKey, index) => {\n if (!seenColumnIndexes[index]) {\n orderedColumnIndexes.push(index);\n }\n });\n precomputed.colKeys = orderedColumnIndexes.map(index => colKeys[index]);\n return true;\n}\n\n/*\n * Creates the small result kept on the main thread for a virtualized table.\n * Cell and row-total values stay in the worker and are transferred only for\n * the visible viewport. Column totals remain here because the totals footer\n * is always visible.\n */\nexport function createVirtualPivotSummary(precomputed, columnMode) {\n return {\n rowKeys: [],\n colKeys: precomputed.colKeys,\n tree: {},\n rowTotals: {},\n colTotals: {},\n allTotal: precomputed.allTotal,\n aggregations: precomputed.aggregations,\n attrValues: precomputed.attrValues,\n totalRecords: precomputed.totalRecords,\n totalRows: getPivotViewportRowCount(precomputed, columnMode),\n totalColumns: getPivotViewportColumnCount(precomputed, columnMode),\n virtualized: true,\n };\n}\n\n// Build only the rows requested by a virtualized table. The result contains\n// plain data and can cross the worker boundary without cloning the full pivot.\nexport function computePivotViewport(\n precomputed,\n start,\n end,\n columnMode,\n columnStart = 0,\n columnEnd = Number.MAX_SAFE_INTEGER\n) {\n const aggregations = precomputed.aggregations || [];\n const expandAggregations = aggregations.length > 1 && !columnMode;\n const rowKeys =\n expandAggregations && precomputed.rowKeys.length === 0\n ? [[]]\n : precomputed.rowKeys;\n const totalRows = getPivotViewportRowCount(precomputed, columnMode);\n const first = Math.max(0, Math.min(totalRows, Math.floor(start)));\n const last = Math.max(first, Math.min(totalRows, Math.floor(end)));\n const colKeys = precomputed.colKeys || [];\n const baseColKeys = columnMode && colKeys.length === 0 ? [[]] : colKeys;\n const totalColumns = getPivotViewportColumnCount(precomputed, columnMode);\n const firstColumn = Math.max(\n 0,\n Math.min(totalColumns, Math.floor(columnStart))\n );\n const lastColumn = Math.max(\n firstColumn,\n Math.min(totalColumns, Math.floor(columnEnd))\n );\n const visibleFlatColumnKeys = {};\n for (let column = firstColumn; column < lastColumn; column++) {\n const baseColumnIndex = columnMode\n ? Math.floor(column / aggregations.length)\n : column;\n const colKey = baseColKeys[baseColumnIndex];\n if (colKey) {\n visibleFlatColumnKeys[colKey.join(FLAT_KEY_SEPARATOR)] = true;\n }\n }\n const selectVisibleCells = source => {\n if (!source) {\n return null;\n }\n const selected = {};\n Object.keys(visibleFlatColumnKeys).forEach(flatColKey => {\n if (flatColKey in source) {\n selected[flatColKey] = source[flatColKey];\n }\n });\n return selected;\n };\n const rows = [];\n\n for (let index = first; index < last; index++) {\n const rowIndex = expandAggregations\n ? Math.floor(index / aggregations.length)\n : index;\n const rowKey = rowKeys[rowIndex];\n const aggregation = expandAggregations\n ? aggregations[index % aggregations.length]\n : aggregations[0];\n const flatRowKey = rowKey.join(FLAT_KEY_SEPARATOR);\n rows.push({\n displayKey: expandAggregations\n ? rowKey.concat([aggregation.label || aggregation.aggregatorName])\n : rowKey,\n actualKey: rowKey,\n aggregationKey: aggregation.key,\n spans: [],\n cells: precomputed.tree\n ? selectVisibleCells(precomputed.tree[flatRowKey] || {})\n : null,\n rowTotal: precomputed.rowTotals\n ? precomputed.rowTotals[flatRowKey] || null\n : null,\n });\n }\n\n // Merge repeated row labels inside this window. Doing it here keeps the\n // prefix comparisons off the main thread for worker-backed tables.\n const columns = rows.length > 0 ? rows[0].displayKey.length : 0;\n for (let column = 0; column < columns; column++) {\n let runStart = 0;\n for (let index = 1; index <= rows.length; index++) {\n let samePrefix = index < rows.length;\n for (let part = 0; samePrefix && part <= column; part++) {\n samePrefix =\n rows[index - 1].displayKey[part] === rows[index].displayKey[part];\n }\n if (!samePrefix) {\n rows[runStart].spans[column] = index - runStart;\n for (let merged = runStart + 1; merged < index; merged++) {\n rows[merged].spans[column] = -1;\n }\n runStart = index;\n }\n }\n }\n\n return {\n start: first,\n end: last,\n totalRows,\n columnStart: firstColumn,\n columnEnd: lastColumn,\n totalColumns,\n colTotals: selectVisibleCells(precomputed.colTotals || {}),\n rows,\n };\n}\n\n/*\n * Sorters containing functions cannot be structured-cloned into a worker.\n * Returns true when the sorters prop itself, or any of its entries, is a\n * function. In that case PivotData re-sorts on the main thread after\n * hydration (distinct keys are few, so this stays cheap).\n */\nexport function sortersHaveFunctions(sorters) {\n if (typeof sorters === 'function') {\n return true;\n }\n if (!sorters || typeof sorters !== 'object') {\n return false;\n }\n return Object.keys(sorters).some(attr => typeof sorters[attr] === 'function');\n}\n\n/*\n * Returns a structured-cloneable subset of the sorters prop: data-type names\n * and sample-value arrays survive the worker boundary, functions do not.\n */\nexport function sanitizeSorters(sorters) {\n if (\n !sorters ||\n typeof sorters !== 'object' ||\n typeof sorters === 'function'\n ) {\n return {};\n }\n const clean = {};\n Object.keys(sorters).forEach(attr => {\n const sorter = sorters[attr];\n if (typeof sorter === 'string' || Array.isArray(sorter)) {\n clean[attr] = sorter;\n }\n });\n return clean;\n}\n\n/*\n * Extracts exactly the props PivotData needs to compute results, with\n * everything non-serializable stripped, so the object can be posted to the\n * worker and fed straight into PivotData.\n */\nexport function createWorkerConfig(props) {\n return {\n rows: props.rows,\n cols: props.cols,\n aggregatorName: props.aggregatorName,\n aggregations: props.aggregations,\n vals: props.vals,\n valueFilter: props.valueFilter,\n sorters: sanitizeSorters(props.sorters),\n rowOrder: props.rowOrder,\n colOrder: props.colOrder,\n rowSorts: props.rowSorts,\n colSorts: props.colSorts,\n virtualizeRows: Boolean(props.virtualizeRows),\n rendererName: props.rendererName,\n aggregationDisplayMode:\n props.tableOptions && props.tableOptions.aggregationDisplayMode,\n sortersRequireMainThread: sortersHaveFunctions(props.sorters),\n };\n}\n\n/*\n * Stable string signature of everything that influences a worker computation.\n * Data identity is NOT part of it; callers append their own data version.\n */\nexport function createComputeSignature(props) {\n return JSON.stringify(createWorkerConfig(props));\n}\n\n/*\n * Decides whether the current props can be computed inside the Web Worker.\n * Anything that cannot be structured-cloned (function data sources, custom\n * derivedAttributes, custom aggregator maps) forces the classic path.\n * Function-based sorters are allowed: they are re-applied on the main thread.\n */\nexport function canComputeInWorker(props, options = {}) {\n if (options.enabled === false) {\n return false;\n }\n if (typeof Worker === 'undefined') {\n return false;\n }\n const threshold =\n typeof options.threshold === 'number'\n ? options.threshold\n : DEFAULT_WORKER_THRESHOLD;\n\n const data = props.data;\n if (!Array.isArray(data) || data.length < threshold) {\n return false;\n }\n\n if (Object.keys(props.derivedAttributes || {}).length > 0) {\n return false;\n }\n\n const requestedAggregatorNames = Array.isArray(props.aggregations)\n ? props.aggregations.map(aggregation => aggregation.aggregatorName)\n : [props.aggregatorName || 'Count'];\n const aggregatorMap = props.aggregators || PivotData.defaultProps.aggregators;\n const usesCustomAggregator = requestedAggregatorNames.some(\n name =>\n typeof aggregatorMap[name] !== 'undefined' &&\n aggregatorMap[name] !== PivotData.defaultProps.aggregators[name]\n );\n if (usesCustomAggregator) {\n return false;\n }\n\n return true;\n}\n"]}
|
package/dist/pivotWorker.js
CHANGED
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
var _pivotCompute = require('./pivotCompute');
|
|
4
4
|
|
|
5
|
-
var MAX_CACHED_DATASETS =
|
|
5
|
+
var MAX_CACHED_DATASETS = 2;
|
|
6
|
+
var MAX_CACHED_PIVOTS = 2;
|
|
6
7
|
|
|
7
8
|
var datasetCache = new Map();
|
|
9
|
+
var pendingDatasets = new Map();
|
|
10
|
+
var pivotCache = new Map();
|
|
11
|
+
var pivotDataKeys = new Map();
|
|
12
|
+
var pivotOwners = new Map();
|
|
8
13
|
|
|
9
14
|
var debugEnabled = false;
|
|
10
15
|
|
|
11
|
-
var cacheDataset = function cacheDataset(dataKey, dataset) {
|
|
16
|
+
var cacheDataset = function cacheDataset(dataKey, dataset, ownerKey) {
|
|
17
|
+
if (ownerKey) {
|
|
18
|
+
datasetCache.forEach(function (cached, cachedKey) {
|
|
19
|
+
if (cached.ownerKey === ownerKey && cachedKey !== dataKey) {
|
|
20
|
+
datasetCache.delete(cachedKey);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
dataset.ownerKey = ownerKey || null;
|
|
12
25
|
datasetCache.delete(dataKey);
|
|
13
26
|
datasetCache.set(dataKey, dataset);
|
|
14
27
|
while (datasetCache.size > MAX_CACHED_DATASETS) {
|
|
@@ -45,7 +58,7 @@ self.addEventListener('message', function (event) {
|
|
|
45
58
|
var startedAt = Date.now();
|
|
46
59
|
log('#' + message.id + ' setData received: ' + (message.data || []).length + ' records (dataKey=' + message.dataKey + ')');
|
|
47
60
|
try {
|
|
48
|
-
var dataset = cacheDataset(message.dataKey, (0, _pivotCompute.materializeData)(message.data, {}));
|
|
61
|
+
var dataset = cacheDataset(message.dataKey, (0, _pivotCompute.materializeData)(message.data, {}), message.ownerKey);
|
|
49
62
|
log('#' + message.id + ' materialized ' + dataset.totalRecords + ' records in ' + (Date.now() - startedAt + 'ms (attributes: ' + Object.keys(dataset.attrValues).join(', ') + ')'));
|
|
50
63
|
} catch (error) {
|
|
51
64
|
log('#' + message.id + ' setData failed: ' + toErrorMessage(error));
|
|
@@ -58,20 +71,78 @@ self.addEventListener('message', function (event) {
|
|
|
58
71
|
return;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
|
-
if (message.type === 'pivot:
|
|
74
|
+
if (message.type === 'pivot:setDataStart') {
|
|
75
|
+
pendingDatasets.set(message.dataKey, {
|
|
76
|
+
records: [],
|
|
77
|
+
ownerKey: message.ownerKey
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (message.type === 'pivot:setDataChunk') {
|
|
83
|
+
var pending = pendingDatasets.get(message.dataKey);
|
|
84
|
+
if (pending) {
|
|
85
|
+
(message.data || []).forEach(function (record) {
|
|
86
|
+
return pending.records.push(record);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (message.type === 'pivot:setDataEnd') {
|
|
62
93
|
var _startedAt = Date.now();
|
|
94
|
+
try {
|
|
95
|
+
var _pending = pendingDatasets.get(message.dataKey);
|
|
96
|
+
if (!_pending) {
|
|
97
|
+
throw new Error('no dataset staging buffer for key ' + message.dataKey);
|
|
98
|
+
}
|
|
99
|
+
pendingDatasets.delete(message.dataKey);
|
|
100
|
+
var _dataset = cacheDataset(message.dataKey, (0, _pivotCompute.materializeData)(_pending.records, {}), _pending.ownerKey);
|
|
101
|
+
log('#' + message.id + ' materialized ' + _dataset.totalRecords + ' chunked records ' + ('in ' + (Date.now() - _startedAt) + 'ms'));
|
|
102
|
+
} catch (error) {
|
|
103
|
+
pendingDatasets.delete(message.dataKey);
|
|
104
|
+
postToMain({
|
|
105
|
+
type: 'pivot:error',
|
|
106
|
+
id: message.id,
|
|
107
|
+
message: toErrorMessage(error)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (message.type === 'pivot:compute') {
|
|
114
|
+
var _startedAt2 = Date.now();
|
|
63
115
|
var config = message.config || {};
|
|
64
116
|
try {
|
|
65
|
-
var
|
|
66
|
-
if (!
|
|
117
|
+
var _dataset2 = datasetCache.get(message.dataKey);
|
|
118
|
+
if (!_dataset2) {
|
|
67
119
|
throw new Error('no dataset staged for key ' + message.dataKey);
|
|
68
120
|
}
|
|
69
121
|
log('#' + message.id + ' compute received (rows=[' + (config.rows || []).join(', ') + '] cols=[' + (config.cols || []).join(', ') + '])');
|
|
70
|
-
var result = (0, _pivotCompute.computePivotState)(
|
|
71
|
-
|
|
122
|
+
var result = (0, _pivotCompute.computePivotState)(_dataset2, message.config);
|
|
123
|
+
var columnMode = config.aggregationDisplayMode === 'column';
|
|
124
|
+
var totalRows = (0, _pivotCompute.getPivotViewportRowCount)(result, columnMode);
|
|
125
|
+
var totalColumns = (0, _pivotCompute.getPivotViewportColumnCount)(result, columnMode);
|
|
126
|
+
var useVirtualSummary = config.virtualizeRows && (config.rendererName || 'Table') === 'Table' && !config.sortersRequireMainThread && (totalRows > _pivotCompute.VIRTUAL_ROW_THRESHOLD || totalColumns > _pivotCompute.VIRTUAL_COLUMN_THRESHOLD);
|
|
127
|
+
var sparseColumnsAligned = useVirtualSummary && (0, _pivotCompute.alignSparseColumnsToRows)(result);
|
|
128
|
+
var resultForMain = useVirtualSummary ? (0, _pivotCompute.createVirtualPivotSummary)(result, columnMode) : result;
|
|
129
|
+
resultForMain.viewportKey = message.id;
|
|
130
|
+
pivotCache.set(message.id, useVirtualSummary ? result : {
|
|
131
|
+
rowKeys: result.rowKeys,
|
|
132
|
+
aggregations: result.aggregations
|
|
133
|
+
});
|
|
134
|
+
pivotDataKeys.set(message.id, message.dataKey);
|
|
135
|
+
pivotOwners.set(message.id, message.ownerKey || null);
|
|
136
|
+
while (pivotCache.size > MAX_CACHED_PIVOTS) {
|
|
137
|
+
var oldestKey = pivotCache.keys().next().value;
|
|
138
|
+
pivotCache.delete(oldestKey);
|
|
139
|
+
pivotDataKeys.delete(oldestKey);
|
|
140
|
+
pivotOwners.delete(oldestKey);
|
|
141
|
+
}
|
|
142
|
+
log('#' + message.id + ' computed in ' + (Date.now() - _startedAt2) + 'ms (rowKeys: ' + result.rowKeys.length + ', colKeys: ' + result.colKeys.length + ', sparse columns aligned: ' + sparseColumnsAligned + ', aggregations: ' + result.aggregations.map(function (agg) {
|
|
72
143
|
return agg.key;
|
|
73
144
|
}).join(', ') + ')');
|
|
74
|
-
postToMain({ type: 'pivot:result', id: message.id, result:
|
|
145
|
+
postToMain({ type: 'pivot:result', id: message.id, result: resultForMain });
|
|
75
146
|
} catch (error) {
|
|
76
147
|
log('#' + message.id + ' compute failed: ' + toErrorMessage(error));
|
|
77
148
|
postToMain({
|
|
@@ -80,6 +151,91 @@ self.addEventListener('message', function (event) {
|
|
|
80
151
|
message: toErrorMessage(error)
|
|
81
152
|
});
|
|
82
153
|
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (message.type === 'pivot:viewport') {
|
|
158
|
+
try {
|
|
159
|
+
var pivot = pivotCache.get(message.viewportKey);
|
|
160
|
+
if (!pivot) {
|
|
161
|
+
throw new Error('Pivot viewport cache is unavailable');
|
|
162
|
+
}
|
|
163
|
+
var _result = (0, _pivotCompute.computePivotViewport)(pivot, message.start, message.end, message.columnMode, message.columnStart, message.columnEnd);
|
|
164
|
+
postToMain({ type: 'pivot:viewportResult', id: message.id, result: _result });
|
|
165
|
+
log('#' + message.id + ' viewport released after postMessage', {
|
|
166
|
+
rows: _result.rows.length,
|
|
167
|
+
datasets: datasetCache.size,
|
|
168
|
+
pivots: pivotCache.size
|
|
169
|
+
});
|
|
170
|
+
} catch (error) {
|
|
171
|
+
postToMain({
|
|
172
|
+
type: 'pivot:error',
|
|
173
|
+
id: message.id,
|
|
174
|
+
message: toErrorMessage(error)
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (message.type === 'pivot:release') {
|
|
181
|
+
pivotCache.delete(message.viewportKey);
|
|
182
|
+
pivotDataKeys.delete(message.viewportKey);
|
|
183
|
+
pivotOwners.delete(message.viewportKey);
|
|
184
|
+
log('released pivot ' + message.viewportKey, {
|
|
185
|
+
datasets: datasetCache.size,
|
|
186
|
+
pivots: pivotCache.size
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (message.type === 'pivot:releaseData') {
|
|
192
|
+
var _dataset3 = datasetCache.get(message.dataKey);
|
|
193
|
+
if (_dataset3) {
|
|
194
|
+
if (Array.isArray(_dataset3.materializedInput)) {
|
|
195
|
+
_dataset3.materializedInput.length = 0;
|
|
196
|
+
}
|
|
197
|
+
_dataset3.attrValues = null;
|
|
198
|
+
}
|
|
199
|
+
datasetCache.delete(message.dataKey);
|
|
200
|
+
pendingDatasets.delete(message.dataKey);
|
|
201
|
+
pivotCache.forEach(function (pivot, viewportKey) {
|
|
202
|
+
if (pivotDataKeys.get(viewportKey) === message.dataKey) {
|
|
203
|
+
pivot.attrValues = null;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
log('released dataset ' + message.dataKey, {
|
|
207
|
+
datasets: datasetCache.size,
|
|
208
|
+
pivots: pivotCache.size
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (message.type === 'pivot:releaseOwner') {
|
|
214
|
+
pendingDatasets.forEach(function (pending, dataKey) {
|
|
215
|
+
if (pending.ownerKey === message.ownerKey) {
|
|
216
|
+
pending.records.length = 0;
|
|
217
|
+
pendingDatasets.delete(dataKey);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
datasetCache.forEach(function (dataset, dataKey) {
|
|
221
|
+
if (dataset.ownerKey === message.ownerKey) {
|
|
222
|
+
if (Array.isArray(dataset.materializedInput)) {
|
|
223
|
+
dataset.materializedInput.length = 0;
|
|
224
|
+
}
|
|
225
|
+
datasetCache.delete(dataKey);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
pivotCache.forEach(function (pivot, viewportKey) {
|
|
229
|
+
if (pivotOwners.get(viewportKey) === message.ownerKey) {
|
|
230
|
+
pivotCache.delete(viewportKey);
|
|
231
|
+
pivotDataKeys.delete(viewportKey);
|
|
232
|
+
pivotOwners.delete(viewportKey);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
log('released owner ' + message.ownerKey, {
|
|
236
|
+
datasets: datasetCache.size,
|
|
237
|
+
pivots: pivotCache.size
|
|
238
|
+
});
|
|
83
239
|
}
|
|
84
240
|
});
|
|
85
241
|
//# sourceMappingURL=pivotWorker.js.map
|