UNPKG

react-mapfilter

Version:

These components are designed for viewing data in Mapeo. They share a common interface:

389 lines (322 loc) 12.4 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault"); var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property"); require("core-js/modules/es.number.constructor"); require("core-js/modules/es.regexp.exec"); require("core-js/modules/es.string.split"); _Object$defineProperty(exports, "__esModule", { value: true }); exports.default = createMemoizedStats; exports.diffArrays = diffArrays; exports.statReduce = statReduce; var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat")); var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map")); var _indexOf = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/index-of")); var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter")); var _values = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/values")); var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray")); var _forEach = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/for-each")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty")); var _map2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/map")); var _cloneDeep = _interopRequireDefault(require("clone-deep")); var _flat_object_entries = require("../../utils/flat_object_entries"); var _value_types = require("./value_types"); var valueTypes = _interopRequireWildcard(require("../../constants/value_types")); var _helpers = require("../../utils/helpers"); // @flow function defaultStats() /*: FieldStatistic*/ { var _ref; return _ref = {}, (0, _defineProperty2.default)(_ref, valueTypes.STRING, { count: 0, values: new _map2.default() }), (0, _defineProperty2.default)(_ref, valueTypes.NUMBER, { count: 0, values: new _map2.default() }), (0, _defineProperty2.default)(_ref, valueTypes.DATE, { count: 0, values: new _map2.default() }), (0, _defineProperty2.default)(_ref, valueTypes.DATETIME, { count: 0, values: new _map2.default() }), (0, _defineProperty2.default)(_ref, valueTypes.BOOLEAN, { count: 0, values: new _map2.default([[true, 0], [false, 0]]) }), (0, _defineProperty2.default)(_ref, valueTypes.URL, 0), (0, _defineProperty2.default)(_ref, valueTypes.IMAGE_URL, 0), (0, _defineProperty2.default)(_ref, valueTypes.AUDIO_URL, 0), (0, _defineProperty2.default)(_ref, valueTypes.VIDEO_URL, 0), (0, _defineProperty2.default)(_ref, valueTypes.NULL, 0), (0, _defineProperty2.default)(_ref, valueTypes.UNDEFINED, 0), (0, _defineProperty2.default)(_ref, valueTypes.LOCATION, 0), _ref; } function createMemoizedStats() { var stats /*: Statistics*/ = {}; var dataMemo = []; return function getStats(data /*: Array<JSONObject>*/ ) /*: Statistics*/ { if (data === dataMemo) return stats; var _diffArrays = diffArrays(dataMemo, data), added = _diffArrays.added, removed = _diffArrays.removed; if (!added.length && !removed.length) return (0, _cloneDeep.default)(stats); if (removed.length) { // Anything removed, calculate all the stats // TODO: more efficient stats on removal stats = {}; (0, _forEach.default)(data).call(data, function (item) { return addItemStats(item, stats); }); } else { // Only added items -> only need to process new items (0, _forEach.default)(added).call(added, function (item) { return addItemStats(item, stats); }); } dataMemo = data; return (0, _cloneDeep.default)(stats); }; } function addItemStats() { var _context; var item /*: JSONObject*/ = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var stats /*: Statistics*/ = arguments.length > 1 ? arguments[1] : undefined; (0, _forEach.default)(_context = (0, _flat_object_entries.flatObjectEntries)(item)).call(_context, function (_ref2) { var _ref3 = (0, _slicedToArray2.default)(_ref2, 2), path = _ref3[0], value = _ref3[1]; var key = (0, _stringify.default)(path); if (!stats[key]) stats[key] = defaultStats(); addFieldStats(value, stats[key]); }); } function addFieldStats(value /*: any*/ , fieldStats /*: FieldStatistic*/ ) { var type = (0, _value_types.guessValueType)(value); if (typeof fieldStats[type] === 'number') { fieldStats[type] += 1; return; } switch (type) { case valueTypes.ARRAY: var arrayStats = fieldStats[valueTypes.ARRAY]; if (arrayStats === undefined) { arrayStats = fieldStats[valueTypes.ARRAY] = { count: 0, lengthMin: +Infinity, lengthMax: -Infinity, valueStats: defaultStats() }; } addArrayStats(value, arrayStats); return; case valueTypes.STRING: addStringStats(value, fieldStats[valueTypes.STRING]); return; case valueTypes.NUMBER: addNumberStats(value, fieldStats[valueTypes.NUMBER]); return; case valueTypes.DATE: addDateStats(value, fieldStats[valueTypes.DATE]); return; case valueTypes.DATETIME: addDateTimeStats(value, fieldStats[valueTypes.DATETIME]); return; case valueTypes.BOOLEAN: fieldStats[valueTypes.BOOLEAN].count += 1; (0, _values.default)(fieldStats[valueTypes.BOOLEAN]).set(value, (0, _values.default)(fieldStats[valueTypes.BOOLEAN]).get(value) + 1); return; default: // $FlowFixMe - flow doesn't realise that type is not values above fieldStats[type].count += 1; } } function addArrayStats(value /*: []*/ , stats /*: $NonMaybeType<$ElementType<FieldStatistic, 'array'>>*/ ) { if (value.length > stats.lengthMax) stats.lengthMax = value.length; if (value.length < stats.lengthMin) stats.lengthMin = value.length; stats.count += 1; (0, _forEach.default)(value).call(value, function (item) { addFieldStats(item, stats.valueStats); }); } function addNumberStats(value /*: number*/ , stats /*: NumberStatistic*/ ) { stats.count += 1; var _statReduce = statReduce(stats, value, stats.count - 1), min = _statReduce.min, max = _statReduce.max, variance = _statReduce.variance, mean = _statReduce.mean; stats.min = min; stats.max = max; stats.variance = variance; stats.mean = mean; if ((0, _values.default)(stats).has(value)) (0, _values.default)(stats).set(value, (0, _values.default)(stats).get(value) + 1);else (0, _values.default)(stats).set(value, 1); } function addDateTimeStats(value /*: string*/ , stats /*: DateStatistic*/ ) { var dateAsNumber = +Date.parse(value); stats.count += 1; var _statReduce2 = statReduce({ mean: stats.mean !== undefined ? +Date.parse(stats.mean) : undefined }, dateAsNumber, stats.count - 1), mean = _statReduce2.mean; stats.min = stats.min === undefined ? value : value < stats.min ? value : stats.min; stats.max = stats.max === undefined ? value : value > stats.max ? value : stats.max; stats.mean = mean !== undefined ? new Date(mean).toISOString() : undefined; if ((0, _values.default)(stats).has(value)) (0, _values.default)(stats).set(value, (0, _values.default)(stats).get(value) + 1);else (0, _values.default)(stats).set(value, 1); } /** This requires slightly special treatment because date does not include time */ function addDateStats(value /*: string*/ , stats /*: DateStatistic*/ ) { var dateAsNumber = dateToNumber(value); stats.count += 1; var _statReduce3 = statReduce({ mean: stats.mean !== undefined ? dateToNumber(stats.mean) : undefined }, dateAsNumber, stats.count - 1), mean = _statReduce3.mean; stats.min = stats.min === undefined ? value : value < stats.min ? value : stats.min; stats.max = stats.max === undefined ? value : value > stats.max ? value : stats.max; stats.mean = mean !== undefined ? numberToDate(mean) : undefined; if ((0, _values.default)(stats).has(value)) (0, _values.default)(stats).set(value, (0, _values.default)(stats).get(value) + 1);else (0, _values.default)(stats).set(value, 1); } function addStringStats(value /*: string*/ , stats /*: StringStatistic*/ ) { stats.count += 1; var lengthStats = statReduce({ min: stats.lengthMin, max: stats.lengthMax, variance: stats.lengthVariance, mean: stats.lengthMean }, value.length, stats.count - 1); var wordStats = statReduce({ min: stats.wordsMin, max: stats.wordsMax, variance: stats.wordsVariance, mean: stats.wordsMean }, value.split(' ').length, stats.count - 1); stats.lengthMin = lengthStats.min; stats.lengthMax = lengthStats.max; stats.lengthVariance = lengthStats.variance; stats.lengthMean = lengthStats.mean; stats.wordsMin = wordStats.min; stats.wordsMax = wordStats.max; stats.wordsVariance = wordStats.variance; stats.wordsMean = wordStats.mean; if ((0, _values.default)(stats).has(value)) (0, _values.default)(stats).set(value, (0, _values.default)(stats).get(value) + 1);else (0, _values.default)(stats).set(value, 1); } /** * Compare two arrays of objects and return items in the second but not in the * first (added) and items in the first but not in the second (removed). * Compares using strict equality. */ function diffArrays(oldArray /*: Array<Object>*/ , newArray /*: Array<Object>*/ ) /*: { added: Array<Object>, removed: Array<Object> }*/ { var added = (0, _filter.default)(newArray).call(newArray, function (v) { return (0, _indexOf.default)(oldArray).call(oldArray, v) === -1; }); var removed = (0, _filter.default)(oldArray).call(oldArray, function (v) { return (0, _indexOf.default)(newArray).call(newArray, v) === -1; }); return { added: added, removed: removed }; } /*:: type MathStat = { mean?: number, variance?: number, min?: number, max?: number }*/ /** * Reducer that computes running mean, variance, min and max * Adapted from http://www.johndcook.com/blog/standard_deviation/ * @param {Object} p The previous value for the analysis * @param {Number} x New value to be included in analysis * @param {Number} i zero-based index of the current element being processed * @return {Object} New analysis including `x` */ function statReduce(_ref4, x /*: number*/ , i /*: number*/ ) /*: $ObjMap<MathStat, <V>(V) => $NonMaybeType<V>>*/ { var _ref4$mean = _ref4.mean, mean = _ref4$mean === void 0 ? NaN : _ref4$mean, _ref4$variance = _ref4.variance, variance = _ref4$variance === void 0 ? NaN : _ref4$variance, _ref4$min = _ref4.min, min = _ref4$min === void 0 ? +Infinity : _ref4$min, _ref4$max = _ref4.max, max = _ref4$max === void 0 ? -Infinity : _ref4$max; mean = isNaN(mean) ? 0 : mean; x = x instanceof Date ? +x : x; var newMean = mean + (x - mean) / (i + 1); return { mean: newMean, min: x < min ? x : min, max: x > max ? x : max, variance: i < 1 ? 0 : (variance * i + (x - mean) * (x - newMean)) / (i + 1) }; } /** Convert date in the format YYYY-MM-DD to a number */ function dateToNumber(value /*: string*/ ) /*: number*/ { var _context2; var _value$split$map = (0, _map.default)(_context2 = value.split('-')).call(_context2, Number), _value$split$map2 = (0, _slicedToArray2.default)(_value$split$map, 3), year = _value$split$map2[0], month = _value$split$map2[1], day = _value$split$map2[2]; // Add 12 hours -> middle of day return new Date(year, month - 1, day).getTime() + 12 * 60 * 60 * 1000; } function numberToDate(value /*: number*/ ) /*: string*/ { var _context3, _context4; var date = new Date(value); var YYYY = date.getFullYear(); var MM = (0, _helpers.leftPad)(date.getMonth() + 1 + '', 2, '0'); var DD = (0, _helpers.leftPad)(date.getDate() + '', 2, '0'); return (0, _concat.default)(_context3 = (0, _concat.default)(_context4 = "".concat(YYYY, "-")).call(_context4, MM, "-")).call(_context3, DD); } //# sourceMappingURL=statistics.js.map