@hrforte/react-pivottable 1.0.1 → 2.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/Utilities.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.PivotData = exports.createSorterByType = exports.detectDataType = exports.builtInSorters = exports.sortAs = exports.getSort = exports.numberFormat = exports.naturalSort = exports.locales = exports.derivers = exports.aggregators = exports.aggregatorTemplates = undefined;
6
+ exports.PivotData = exports.sortersHaveFunctions = exports.createSorterByType = exports.detectDataType = exports.builtInSorters = exports.sortAs = exports.getSort = exports.numberFormat = exports.naturalSort = exports.locales = exports.derivers = exports.aggregators = exports.aggregatorTemplates = undefined;
7
7
 
8
8
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
9
9
 
@@ -391,6 +391,25 @@ var usFmtPct = numberFormat({
391
391
  suffix: '%'
392
392
  });
393
393
 
394
+ // Emit a progress callback every N processed records without adding
395
+ // measurable overhead to the per-record loop.
396
+ var RECORD_PROGRESS_BATCH_SIZE = 25000;
397
+
398
+ // Returns true when the sorters prop itself, or any of its entries, is a
399
+ // function. Function-based sorters cannot be transferred to a Web Worker, so
400
+ // PivotData re-applies them on the main thread after worker hydration.
401
+ var sortersHaveFunctions = function sortersHaveFunctions(sorters) {
402
+ if (typeof sorters === 'function') {
403
+ return true;
404
+ }
405
+ if (!sorters || (typeof sorters === 'undefined' ? 'undefined' : _typeof(sorters)) !== 'object') {
406
+ return false;
407
+ }
408
+ return Object.keys(sorters).some(function (attr) {
409
+ return typeof sorters[attr] === 'function';
410
+ });
411
+ };
412
+
394
413
  var aggregatorTemplates = {
395
414
  count: function count() {
396
415
  var formatter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : usFmtInt;
@@ -855,15 +874,103 @@ var PivotData = function () {
855
874
  this.allTotal = this.createAggregatorCell([], []);
856
875
  this.sorted = false;
857
876
 
858
- // iterate through input, accumulating data for cells
859
- PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, function (record) {
877
+ if (this.props.precomputedData) {
878
+ // Results computed by the Web Worker (or any previous pass) are
879
+ // hydrated instead of re-scanning every record on the main thread.
880
+ this.hydrateFromPrecomputed(this.props.precomputedData);
881
+ return;
882
+ }
883
+
884
+ var progressHook = this.props.onRecordProcessed;
885
+ var recordHandler = function recordHandler(record) {
860
886
  if (_this2.filter(record)) {
861
887
  _this2.processRecord(record);
862
888
  }
863
- });
889
+ };
890
+ if (typeof progressHook === 'function') {
891
+ var recordsProcessed = 0;
892
+ PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, function (record) {
893
+ recordHandler(record);
894
+ recordsProcessed++;
895
+ if (recordsProcessed % RECORD_PROGRESS_BATCH_SIZE === 0) {
896
+ progressHook(recordsProcessed);
897
+ }
898
+ });
899
+ } else {
900
+ PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, recordHandler);
901
+ }
864
902
  }
865
903
 
904
+ /*
905
+ * Rebuilds tree/totals from a serialized PivotData payload (as produced by
906
+ * `serializePivotData` inside the worker). Aggregated values are final, so
907
+ * only lightweight stub aggregators with the correct `value()` and
908
+ * `format()` behavior are created per cell.
909
+ */
910
+
911
+
866
912
  _createClass(PivotData, [{
913
+ key: 'hydrateFromPrecomputed',
914
+ value: function hydrateFromPrecomputed(precomputed) {
915
+ var _this3 = this;
916
+
917
+ // One real aggregator instance per aggregation provides `format()` and
918
+ // `numInputs` for every hydrated stub cell.
919
+ var formatSources = {};
920
+ this.aggregations.forEach(function (agg) {
921
+ formatSources[agg.key] = _this3.aggregatorFactories[agg.key](_this3, [], []);
922
+ });
923
+
924
+ var makeCell = function makeCell(serializedCell) {
925
+ var values = serializedCell && serializedCell.values || {};
926
+ var instances = {};
927
+ _this3.aggregations.forEach(function (agg) {
928
+ var source = formatSources[agg.key];
929
+ var _value = values[agg.key];
930
+ instances[agg.key] = {
931
+ push: function push() {},
932
+ value: function value() {
933
+ return _value;
934
+ },
935
+ format: function format(x) {
936
+ return source.format(x);
937
+ },
938
+
939
+ numInputs: source.numInputs,
940
+ outlet: source.outlet
941
+ };
942
+ });
943
+ return new AggregatorCell(instances, _this3.primaryAggregation.key);
944
+ };
945
+
946
+ var hydrateTotals = function hydrateTotals(source, target) {
947
+ Object.keys(source || {}).forEach(function (flatKey) {
948
+ target[flatKey] = makeCell(source[flatKey]);
949
+ });
950
+ };
951
+
952
+ this.rowKeys = (precomputed.rowKeys || []).map(function (key) {
953
+ return key.slice();
954
+ });
955
+ this.colKeys = (precomputed.colKeys || []).map(function (key) {
956
+ return key.slice();
957
+ });
958
+ this.rowTotals = {};
959
+ hydrateTotals(precomputed.rowTotals, this.rowTotals);
960
+ this.colTotals = {};
961
+ hydrateTotals(precomputed.colTotals, this.colTotals);
962
+ this.tree = {};
963
+ Object.keys(precomputed.tree || {}).forEach(function (flatRowKey) {
964
+ _this3.tree[flatRowKey] = {};
965
+ hydrateTotals(precomputed.tree[flatRowKey], _this3.tree[flatRowKey]);
966
+ });
967
+ this.allTotal = makeCell(precomputed.allTotal);
968
+
969
+ // Keys were already sorted inside the worker; only re-sort on the main
970
+ // thread when a sorter could not cross the worker boundary (functions).
971
+ this.sorted = !sortersHaveFunctions(this.props.sorters);
972
+ }
973
+ }, {
867
974
  key: 'filter',
868
975
  value: function filter(record) {
869
976
  for (var k in this.props.valueFilter) {
@@ -876,10 +983,10 @@ var PivotData = function () {
876
983
  }, {
877
984
  key: 'forEachMatchingRecord',
878
985
  value: function forEachMatchingRecord(criteria, callback) {
879
- var _this3 = this;
986
+ var _this4 = this;
880
987
 
881
988
  return PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, function (record) {
882
- if (!_this3.filter(record)) {
989
+ if (!_this4.filter(record)) {
883
990
  return;
884
991
  }
885
992
  for (var k in criteria) {
@@ -894,7 +1001,7 @@ var PivotData = function () {
894
1001
  }, {
895
1002
  key: 'arrSort',
896
1003
  value: function arrSort(attrs) {
897
- var _this4 = this;
1004
+ var _this5 = this;
898
1005
 
899
1006
  var a = void 0;
900
1007
  var sortersArr = function () {
@@ -907,7 +1014,7 @@ var PivotData = function () {
907
1014
  for (var _iterator2 = Array.from(attrs)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
908
1015
  a = _step2.value;
909
1016
 
910
- result.push(getSort(_this4.props.sorters, a));
1017
+ result.push(getSort(_this5.props.sorters, a));
911
1018
  }
912
1019
  } catch (err) {
913
1020
  _didIteratorError2 = true;
@@ -962,12 +1069,12 @@ var PivotData = function () {
962
1069
  }, {
963
1070
  key: 'sortKeys',
964
1071
  value: function sortKeys() {
965
- var _this5 = this;
1072
+ var _this6 = this;
966
1073
 
967
1074
  if (!this.sorted) {
968
1075
  this.sorted = true;
969
1076
  var v = function v(r, c) {
970
- return _this5.getAggregator(r, c).value();
1077
+ return _this6.getAggregator(r, c).value();
971
1078
  };
972
1079
 
973
1080
  // Handle per-row sorting
@@ -975,11 +1082,11 @@ var PivotData = function () {
975
1082
  var rowSorts = this.props.rowSorts;
976
1083
  this.rowKeys.sort(function (a, b) {
977
1084
  // First, check if any sorted attribute has a difference
978
- for (var i = 0; i < _this5.props.rows.length; i++) {
979
- var attr = _this5.props.rows[i];
1085
+ for (var i = 0; i < _this6.props.rows.length; i++) {
1086
+ var attr = _this6.props.rows[i];
980
1087
  if (attr && rowSorts[attr]) {
981
1088
  var sortDir = rowSorts[attr] === 'ASC' ? 1 : -1;
982
- var sorter = getSort(_this5.props.sorters, attr);
1089
+ var sorter = getSort(_this6.props.sorters, attr);
983
1090
  var comparison = sorter(a[i] || '', b[i] || '');
984
1091
  if (comparison !== 0) {
985
1092
  return sortDir * comparison;
@@ -987,7 +1094,7 @@ var PivotData = function () {
987
1094
  }
988
1095
  }
989
1096
  // If sorted attributes are equal, use default sorting for remaining attributes
990
- return _this5.arrSort(_this5.props.rows)(a, b);
1097
+ return _this6.arrSort(_this6.props.rows)(a, b);
991
1098
  });
992
1099
  } else {
993
1100
  // Use global row order
@@ -1012,11 +1119,11 @@ var PivotData = function () {
1012
1119
  var colSorts = this.props.colSorts;
1013
1120
  this.colKeys.sort(function (a, b) {
1014
1121
  // First, check if any sorted attribute has a difference
1015
- for (var i = 0; i < _this5.props.cols.length; i++) {
1016
- var attr = _this5.props.cols[i];
1122
+ for (var i = 0; i < _this6.props.cols.length; i++) {
1123
+ var attr = _this6.props.cols[i];
1017
1124
  if (attr && colSorts[attr]) {
1018
1125
  var sortDir = colSorts[attr] === 'ASC' ? 1 : -1;
1019
- var sorter = getSort(_this5.props.sorters, attr);
1126
+ var sorter = getSort(_this6.props.sorters, attr);
1020
1127
  var comparison = sorter(a[i] || '', b[i] || '');
1021
1128
  if (comparison !== 0) {
1022
1129
  return sortDir * comparison;
@@ -1024,7 +1131,7 @@ var PivotData = function () {
1024
1131
  }
1025
1132
  }
1026
1133
  // If sorted attributes are equal, use default sorting for remaining attributes
1027
- return _this5.arrSort(_this5.props.cols)(a, b);
1134
+ return _this6.arrSort(_this6.props.cols)(a, b);
1028
1135
  });
1029
1136
  } else {
1030
1137
  // Use global col order
@@ -1268,25 +1375,25 @@ var PivotData = function () {
1268
1375
  }, {
1269
1376
  key: 'buildAggregatorFactories',
1270
1377
  value: function buildAggregatorFactories() {
1271
- var _this6 = this;
1378
+ var _this7 = this;
1272
1379
 
1273
1380
  var factories = {};
1274
1381
  this.aggregations.forEach(function (agg) {
1275
- if (!(agg.aggregatorName in _this6.props.aggregators)) {
1382
+ if (!(agg.aggregatorName in _this7.props.aggregators)) {
1276
1383
  throw new Error('unknown aggregator ' + agg.aggregatorName);
1277
1384
  }
1278
- factories[agg.key] = _this6.props.aggregators[agg.aggregatorName](agg.vals);
1385
+ factories[agg.key] = _this7.props.aggregators[agg.aggregatorName](agg.vals);
1279
1386
  });
1280
1387
  return factories;
1281
1388
  }
1282
1389
  }, {
1283
1390
  key: 'createAggregatorCell',
1284
1391
  value: function createAggregatorCell(rowKey, colKey) {
1285
- var _this7 = this;
1392
+ var _this8 = this;
1286
1393
 
1287
1394
  var instances = {};
1288
1395
  this.aggregations.forEach(function (agg) {
1289
- instances[agg.key] = _this7.aggregatorFactories[agg.key](_this7, rowKey, colKey);
1396
+ instances[agg.key] = _this8.aggregatorFactories[agg.key](_this8, rowKey, colKey);
1290
1397
  });
1291
1398
  return new AggregatorCell(instances, this.primaryAggregation.key);
1292
1399
  }
@@ -1453,8 +1560,10 @@ PivotData.propTypes = {
1453
1560
  rows: _propTypes2.default.arrayOf(_propTypes2.default.string),
1454
1561
  vals: _propTypes2.default.arrayOf(_propTypes2.default.string),
1455
1562
  valueFilter: _propTypes2.default.objectOf(_propTypes2.default.objectOf(_propTypes2.default.bool)),
1456
- sorters: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.objectOf(_propTypes2.default.func)]),
1563
+ sorters: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.objectOf(_propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.string, _propTypes2.default.array]))]),
1457
1564
  derivedAttributes: _propTypes2.default.objectOf(_propTypes2.default.func),
1565
+ precomputedData: _propTypes2.default.object,
1566
+ onRecordProcessed: _propTypes2.default.func,
1458
1567
  rowOrder: _propTypes2.default.oneOf(['key_a_to_z', 'value_a_to_z', 'value_z_to_a']),
1459
1568
  colOrder: _propTypes2.default.oneOf(['key_a_to_z', 'value_a_to_z', 'value_z_to_a']),
1460
1569
  rowSorts: _propTypes2.default.objectOf(_propTypes2.default.oneOf(['ASC', 'DESC'])),
@@ -1472,5 +1581,6 @@ exports.sortAs = sortAs;
1472
1581
  exports.builtInSorters = builtInSorters;
1473
1582
  exports.detectDataType = detectDataType;
1474
1583
  exports.createSorterByType = createSorterByType;
1584
+ exports.sortersHaveFunctions = sortersHaveFunctions;
1475
1585
  exports.PivotData = PivotData;
1476
1586
  //# sourceMappingURL=Utilities.js.map