UNPKG

@visactor/vtable

Version:

canvas table width high performance

398 lines (380 loc) 21.6 kB
import { isValid } from "@visactor/vutils"; import { AggregationType, SortType } from ".."; export const registeredAggregators = {}; export class Aggregator { constructor(config) { var _a; this.isAggregator = !0, this.isRecord = !0, this.records = [], this.key = config.key, this.field = config.field, this.formatFun = config.formatFun, this.isRecord = null !== (_a = config.isRecord) && void 0 !== _a ? _a : this.isRecord; } clearCacheValue() { this._formatedValue = void 0; } formatValue(col, row, table) { return this._formatedValue || (this.formatFun ? this._formatedValue = this.formatFun(this.value(), col, row, table) : this._formatedValue = this.value()), this._formatedValue; } reset() { this.records = [], this.clearCacheValue(); } } export class RecordAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.RECORD, this.isRecord = !0; } push(record) { record && this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), this.clearCacheValue(); } deleteRecord(record) { record && this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.clearCacheValue()); } value() { return this.records; } reset() { this.records = []; } recalculate() {} } export class NoneAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.NONE, this.isRecord = !0; } push(record) { record && (this.isRecord && (this.records = [ record ]), this.field && (this.fieldValue = record[this.field])), this.clearCacheValue(); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.field && this.records.length && (this.fieldValue = this.records[this.records.length - 1][this.field])), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.field && this.records.length && (this.fieldValue = this.records[this.records.length - 1][this.field]), this.clearCacheValue()); } value() { return this.fieldValue; } reset() { this.records = [], this.fieldValue = void 0; } recalculate() {} } export class CustomAggregator extends Aggregator { constructor(config) { super(config), this.type = AggregationType.CUSTOM, this.isRecord = !0, this.values = [], this.aggregationFun = config.aggregationFun; } push(record) { record && (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), this.field && this.values.push(record[this.field])), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.field && this.records.length && (this.values = this.records.map((item => item[this.field]))), this.clearCacheValue()); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.field && this.records.length && (this.values = this.records.map((item => item[this.field])))), this.clearCacheValue(); } value() { var _a; return this.fieldValue || (this.fieldValue = null === (_a = this.aggregationFun) || void 0 === _a ? void 0 : _a.call(this, this.values, this.records, this.field)), this.fieldValue; } reset() { this.records = [], this.fieldValue = void 0; } recalculate() { this.fieldValue = void 0, this._formatedValue = void 0; } } export class RecalculateAggregator extends Aggregator { constructor(config) { super(config), this.type = AggregationType.RECALCULATE, this.isRecord = !0, this.calculateFun = config.calculateFun, this.dependAggregators = config.dependAggregators, this.dependIndicatorKeys = config.dependIndicatorKeys; } push(record) { record && this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), this.clearCacheValue(); } deleteRecord(record) { record && this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.clearCacheValue()); } value() { var _a; if (!this.fieldValue) { const aggregatorValue = _getDependAggregatorValues(this.dependAggregators, this.dependIndicatorKeys); this.fieldValue = null === (_a = this.calculateFun) || void 0 === _a ? void 0 : _a.call(this, aggregatorValue, this.records, this.field); } return this.fieldValue; } reset() { this.records = [], this.fieldValue = void 0; } recalculate() {} } export class SumAggregator extends Aggregator { constructor(config) { var _a; super(config), this.type = AggregationType.SUM, this.sum = 0, this.positiveSum = 0, this.nagetiveSum = 0, this.needSplitPositiveAndNegativeForSum = !1, this.needSplitPositiveAndNegativeForSum = null !== (_a = config.needSplitPositiveAndNegative) && void 0 !== _a && _a; } push(record) { if (record) if (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), record.isAggregator) { const value = record.value(); this.sum += null != value ? value : 0, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum += value : value < 0 && (this.nagetiveSum += value)); } else if (this.field && !isNaN(parseFloat(record[this.field]))) { const value = parseFloat(record[this.field]); this.sum += value, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum += value : value < 0 && (this.nagetiveSum += value)); } this.clearCacheValue(); } deleteRecord(record) { if (record) if (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), record.isAggregator) { const value = record.value(); this.sum -= null != value ? value : 0, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum -= value : value < 0 && (this.nagetiveSum -= value)); } else if (this.field && !isNaN(parseFloat(record[this.field]))) { const value = parseFloat(record[this.field]); this.sum -= value, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum -= value : value < 0 && (this.nagetiveSum -= value)); } this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { if (oldRecord && newRecord) { if (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), oldRecord.isAggregator) { const oldValue = oldRecord.value(), newValue = newRecord.value(); this.sum += newValue - oldValue, this.needSplitPositiveAndNegativeForSum && (oldValue > 0 ? this.positiveSum -= oldValue : oldValue < 0 && (this.nagetiveSum -= oldValue), newValue > 0 ? this.positiveSum += newValue : newValue < 0 && (this.nagetiveSum += newValue)); } else if (this.field && !isNaN(parseFloat(oldRecord[this.field]))) { const oldValue = parseFloat(oldRecord[this.field]), newValue = parseFloat(newRecord[this.field]); this.sum += newValue - oldValue, this.needSplitPositiveAndNegativeForSum && (oldValue > 0 ? this.positiveSum -= oldValue : oldValue < 0 && (this.nagetiveSum -= oldValue), newValue > 0 ? this.positiveSum += newValue : newValue < 0 && (this.nagetiveSum += newValue)); } this.clearCacheValue(); } } value() { var _a; return (null === (_a = this.records) || void 0 === _a ? void 0 : _a.length) >= 1 ? this.sum : void 0; } positiveValue() { return this.positiveSum; } negativeValue() { return this.nagetiveSum; } reset() { super.reset(), this.records = [], this.sum = 0; } recalculate() { if (this.sum = 0, this._formatedValue = void 0, this.records) for (let i = 0; i < this.records.length; i++) { const record = this.records[i]; if (record.isAggregator) { const value = record.value(); this.sum += null != value ? value : 0, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum += value : value < 0 && (this.nagetiveSum += value)); } else if (this.field && !isNaN(parseFloat(record[this.field]))) { const value = parseFloat(record[this.field]); this.sum += value, this.needSplitPositiveAndNegativeForSum && (value > 0 ? this.positiveSum += value : value < 0 && (this.nagetiveSum += value)); } } } } export class CountAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.COUNT, this.count = 0; } push(record) { record && (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), record.isAggregator ? this.count += record.value() : this.count++), this.clearCacheValue(); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), record.isAggregator ? this.count -= record.value() : this.count--), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), oldRecord.isAggregator && (this.count += newRecord.value() - oldRecord.value())); } value() { return this.count; } reset() { this.records = [], this.count = 0; } recalculate() { if (this.count = 0, this._formatedValue = void 0, this.records) for (let i = 0; i < this.records.length; i++) { const record = this.records[i]; record.isAggregator ? this.count += record.value() : this.count++; } } } export class AvgAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.AVG, this.sum = 0, this.count = 0; } push(record) { record && (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), record.isAggregator && record.type === AggregationType.AVG ? (this.sum += record.sum, this.count += record.count) : this.field && !isNaN(parseFloat(record[this.field])) && (this.sum += parseFloat(record[this.field]), this.count++)), this.clearCacheValue(); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), record.isAggregator && record.type === AggregationType.AVG ? (this.sum -= record.sum, this.count -= record.count) : this.field && !isNaN(parseFloat(record[this.field])) && (this.sum -= parseFloat(record[this.field]), this.count--)), this.clearCacheValue(); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), oldRecord.isAggregator && oldRecord.type === AggregationType.AVG ? (this.sum += newRecord.sum - oldRecord.sum, this.count += newRecord.count - oldRecord.count) : this.field && !isNaN(parseFloat(oldRecord[this.field])) && (this.sum += parseFloat(newRecord[this.field]) - parseFloat(oldRecord[this.field])), this.clearCacheValue()); } value() { var _a; return (null === (_a = this.records) || void 0 === _a ? void 0 : _a.length) >= 1 ? this.sum / this.count : void 0; } reset() { this.records = [], this.sum = 0, this.count = 0; } recalculate() { if (this.sum = 0, this.count = 0, this._formatedValue = void 0, this.records) for (let i = 0; i < this.records.length; i++) { const record = this.records[i]; record.isAggregator && record.type === AggregationType.AVG ? (this.sum += record.sum, this.count += record.count) : this.field && !isNaN(parseFloat(record[this.field])) && (this.sum += parseFloat(record[this.field]), this.count++); } } } export class MaxAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.MAX, this.max = Number.MIN_SAFE_INTEGER; } push(record) { record && (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), record.isAggregator ? this.max = record.max > this.max ? record.max : this.max : "number" == typeof record ? this.max = record > this.max ? record : this.max : this.field && "number" == typeof record[this.field] ? this.max = record[this.field] > this.max ? record[this.field] : this.max : this.field && !isNaN(record[this.field]) && (this.max = parseFloat(record[this.field]) > this.max ? parseFloat(record[this.field]) : this.max)), this.clearCacheValue(); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.recalculate()); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.recalculate()); } value() { var _a; return (null === (_a = this.records) || void 0 === _a ? void 0 : _a.length) >= 1 ? this.max : void 0; } reset() { this.records = [], this.max = Number.MIN_SAFE_INTEGER; } recalculate() { if (this.max = Number.MIN_SAFE_INTEGER, this._formatedValue = void 0, this.records) for (let i = 0; i < this.records.length; i++) { const record = this.records[i]; record.isAggregator ? this.max = record.max > this.max ? record.max : this.max : "number" == typeof record ? this.max = record > this.max ? record : this.max : this.field && "number" == typeof record[this.field] ? this.max = record[this.field] > this.max ? record[this.field] : this.max : this.field && !isNaN(record[this.field]) && (this.max = parseFloat(record[this.field]) > this.max ? parseFloat(record[this.field]) : this.max); } } } export class MinAggregator extends Aggregator { constructor() { super(...arguments), this.type = AggregationType.MIN, this.min = Number.MAX_SAFE_INTEGER; } push(record) { record && (this.isRecord && this.records && (record.isAggregator ? this.records.push(...record.records) : this.records.push(record)), record.isAggregator ? this.min = record.min < this.min ? record.min : this.min : "number" == typeof record ? this.min = record < this.min ? record : this.min : this.field && "number" == typeof record[this.field] ? this.min = record[this.field] < this.min ? record[this.field] : this.min : this.field && !isNaN(record[this.field]) && (this.min = parseFloat(record[this.field]) < this.min ? parseFloat(record[this.field]) : this.min)), this.clearCacheValue(); } deleteRecord(record) { record && (this.isRecord && this.records && (this.records = this.records.filter((item => item !== record))), this.recalculate()); } updateRecord(oldRecord, newRecord) { oldRecord && newRecord && (this.isRecord && this.records && (this.records = this.records.map((item => item === oldRecord ? newRecord : item))), this.recalculate()); } value() { var _a; return (null === (_a = this.records) || void 0 === _a ? void 0 : _a.length) >= 1 ? this.min : void 0; } reset() { this.records = [], this.min = Number.MAX_SAFE_INTEGER; } recalculate() { if (this.min = Number.MAX_SAFE_INTEGER, this._formatedValue = void 0, this.records) for (let i = 0; i < this.records.length; i++) { const record = this.records[i]; record.isAggregator ? this.min = record.min < this.min ? record.min : this.min : "number" == typeof record ? this.min = record < this.min ? record : this.min : this.field && "number" == typeof record[this.field] ? this.min = record[this.field] < this.min ? record[this.field] : this.min : this.field && !isNaN(record[this.field]) && (this.min = parseFloat(record[this.field]) < this.min ? parseFloat(record[this.field]) : this.min); } } } export function indicatorSort(a, b) { return a && b ? a.toString().localeCompare(b.toString(), "zh") : a ? 1 : -1; } export function typeSort(a, b, sortType) { if (sortType === SortType.NORMAL || sortType === SortType.normal) return 0; const factor = sortType === SortType.DESC || sortType === SortType.desc ? -1 : 1; return a && b ? a.toString().localeCompare(b.toString(), "zh") * factor : a ? 1 * factor : -1 * factor; } export function naturalSort(as, bs, sortType) { if (sortType === SortType.NORMAL || sortType === SortType.normal) return 0; const rx = /(\d+)|(\D+)/g, rd = /\d/, rz = /^0/; let a, a1, b, b1, nas = 0, nbs = 0; const factor = sortType === SortType.DESC || sortType === SortType.desc ? -1 : 1; if (null !== bs && null === as) return -1 * factor; if (null !== as && null === bs) return 1 * factor; if ("number" == typeof as && isNaN(as)) return -1 * factor; if ("number" == typeof bs && isNaN(bs)) return 1 * factor; if (nas = +as, nbs = +bs, nas < nbs) return -1 * factor; if (nas > nbs) return 1 * factor; if ("number" == typeof as && "number" != typeof bs) return -1 * factor; if ("number" == typeof bs && "number" != typeof as) return 1 * factor; if ("number" == typeof as && "number" == typeof bs) return 0; if (isNaN(nbs) && !isNaN(nas)) return -1 * factor; if (isNaN(nas) && !isNaN(nbs)) return 1 * factor; if (a = String(as), b = String(bs), a === b) return 0; if (!rd.test(a) || !rd.test(b)) return (a > b ? 1 : -1) * factor; for (a = a.match(rx), b = b.match(rx); a.length && b.length; ) if (a1 = a.shift(), b1 = b.shift(), a1 !== b1) return rd.test(a1) && rd.test(b1) ? (a1.replace(rz, ".0") - b1.replace(rz, ".0")) * factor : (a1 > b1 ? 1 : -1) * factor; return (a.length - b.length) * factor; } export function sortBy(order) { let x; const mapping = {}, lowercase_mapping = {}; for (let i = 0; i < order.length; i++) x = order[i], mapping[x] = i, "string" == typeof x && (lowercase_mapping[x.toLowerCase()] = i); return function(a, b, sortType) { if (sortType === SortType.NORMAL || sortType === SortType.normal) return 0; const factor = sortType === SortType.DESC || sortType === SortType.desc ? -1 : 1; let comparison; return null !== mapping[a] && void 0 !== mapping[a] && null !== mapping[b] && void 0 !== mapping[b] ? comparison = mapping[a] - mapping[b] : null !== mapping[a] && void 0 !== mapping[a] ? comparison = -1 : null !== mapping[b] && void 0 !== mapping[b] ? comparison = 1 : null !== lowercase_mapping[a] && void 0 !== mapping[a] && null !== lowercase_mapping[b] && void 0 !== mapping[b] ? comparison = lowercase_mapping[a] - lowercase_mapping[b] : null === lowercase_mapping[a] || void 0 === mapping[a] || null === lowercase_mapping[b] || void 0 === mapping[b] ? comparison = 0 : null !== lowercase_mapping[a] && void 0 !== mapping[a] ? comparison = -1 : null !== lowercase_mapping[b] && void 0 !== mapping[b] && (comparison = 1), isValid(comparison) ? comparison * factor : naturalSort(a, b, sortType); }; } function _getDependAggregatorValues(aggregators, dependIndicatorKeys) { const dependAggregatorValues = {}; for (let m = 0; m < (null == dependIndicatorKeys ? void 0 : dependIndicatorKeys.length); m++) { const aggrator = aggregators.find((aggrator => (null == aggrator ? void 0 : aggrator.key) === dependIndicatorKeys[m])); aggrator && (dependAggregatorValues[aggrator.key] = null == aggrator ? void 0 : aggrator.value()); } return dependAggregatorValues; } //# sourceMappingURL=aggregation.js.map