import * as d3 from "d3"; export function createAggregateGroupTransform(groupKeyArray: string[], valueKey, operation) : Function { let operator = function (dArray) { let n = d3.nest(), aggregator; switch (operation) { case "count": aggregator = function (v) { return v.length; }; break; case "max": aggregator = function (v) { return d3.max(v, function (d) { return d[valueKey]; }); }; break; case "mean": aggregator = function (v) { return d3.mean(v, function (d) { return d[valueKey]; }); }; break; case "median": aggregator = function (v) { return d3.median(v, function (d) { return d[valueKey]; }); }; break; case "min": aggregator = function (v) { return d3.min(v, function (d) { return d[valueKey]; }); }; break; case "sum": aggregator = function (v) { return d3.sum(v, function (d) { return d[valueKey]; }); }; break; default: throw `Unknown aggregate operation ${operation}`; } for (let k of groupKeyArray) { n.key(function (d) { return d[k]; }) } return n.rollup(aggregator).entries(dArray); }; return (dataArray) => { return operator(dataArray); }; } export function transformCategorizeNested(dataArray){ let categorizedDataArray = []; for(let d of dataArray){ for(let d1 of d.values){ categorizedDataArray.push({ key: d.key, category: d1.key, value: d1.value }); } } return categorizedDataArray; } export function createCategorizeNestedTransform() : Function { return (dataArray) => { return transformCategorizeNested(dataArray); }; } export function transformConvert(dataArray, conversionMap){ for (let k in conversionMap) { if (conversionMap.hasOwnProperty(k)) { for (let d of dataArray) { d[k] = conversionMap[k](d[k]); } } } return dataArray; } export function createConvertTransform(conversionMap) : Function { return (dataArray) => { return transformConvert(dataArray, conversionMap); }; } export function createFilterTransform(filter: Function): Function { return (dataArray) => { return dataArray.filter(filter); }; } export function createOperationTransform(operation: Function): Function { let oppTransform: any = (dataArray) => { return operation(dataArray); }; oppTransform.operation = operation; return oppTransform; } export function transformOperateEach(dataArray, operation: Function) { let i, newDataArray = []; for (i = 0; i < dataArray.length; i++) { newDataArray.push(operation(dataArray[i])); } return newDataArray; } export function createOperateEachTransform(operation: Function) : Function { return (dataArray) => { return transformOperateEach(dataArray, operation); }; } export function createSortTransform(comparator: Function): Function { return (dataArray) => { dataArray.sort(comparator); return dataArray; }; } export function transformSortByAttribute(dataArray, attribute, config: any = {}) { let isAsc = (config.hasOwnProperty('asc') && config.asc === false) ? false : true, doIgnoreCase = (config.hasOwnProperty('ignoreCase') && config.ignoreCase) ? true : false ; dataArray.sort((a, b) => { let result = 0, attr, aValue, aIsMissing, aIsNone, aIsEmpty = false, aIsString = false, bValue, bIsMissing, bIsNone, bIsEmpty = false, bIsString = false ; // located nested attributes if (Array.isArray(attribute)) { aValue = a; bValue = b; for (attr of attribute) { aValue = aValue[attr]; bValue = bValue[attr]; } } else { aValue = a[attribute]; bValue = b[attribute]; } aIsNone = (aValue === undefined || aValue === null); if(!aIsNone) { aIsString = (typeof aValue === "string" || aValue instanceof String); if(aIsString){ aIsEmpty = (aValue.toString().trim() === ""); } } aIsMissing = (aIsNone || aIsEmpty); bIsNone = (bValue === undefined || bValue === null); if (!bIsNone) { bIsString = (typeof bValue === "string" || bValue instanceof String); if(bIsString){ bIsEmpty = (bValue.toString().trim() === ""); } } bIsMissing = (bIsNone || bIsEmpty); if (doIgnoreCase && aIsString && bIsString){ aValue = aValue.toLowerCase(); bValue = bValue.toLowerCase(); } if(aIsMissing && bIsMissing){ return 0; } else if(aIsMissing || bIsMissing){ if(config.emptyLocation === "always_top"){ return (aIsMissing) ? -1 : 1; } else if(config.emptyLocation === "always_bottom"){ return (aIsMissing) ? 1 : -1; } else if(config.emptyLocation === "bottom"){ if(aIsMissing){ return (isAsc) ? 1 : -1; } else if(bIsMissing){ return (isAsc) ? -1 : 1; } } else { if(aIsMissing){ return (isAsc) ? -1 : 1; } else if(bIsMissing){ return (isAsc) ? 1 : -1; } } } if (aValue < bValue) { result = (isAsc) ? -1 : 1; } else if (aValue > bValue) { result = (isAsc) ? 1 : -1; } return result; }); return dataArray; } /** * Recursively sort all children * @param data - data Object * @param recursiveAttribute - attribute of Object to indicate childDataArray to recursively sort on * @param attribute - Object attribute to sort on * @param asc - whether to sort ascending or decending * @param ignoreCase - whether to ignore case when comparing values */ function recursiveSortByAttribute(data, recursiveAttribute, attribute, config: any){ const childDataArray = data[recursiveAttribute]; if (childDataArray){ data[recursiveAttribute] = transformSortByAttribute(childDataArray, attribute, config); for (const childData of childDataArray){ recursiveSortByAttribute(childData, recursiveAttribute, attribute, config); } } } /** * Creates a sort by attribute transform function * @param attribute - Object attribute to sort on * @param asc - whether to sort ascending or decending * @param ignoreCase - whether to ignore case when comparing values * @param recursiveAttribute - attribute of Object to indicate childDataArray to recursively sort on */ export function createSortByAttributeTransform(attribute, config: any, recursiveAttribute = "children"): Function { return (dataArray: any[]) => { const sortedDataArray = transformSortByAttribute(dataArray, attribute, config); if (recursiveAttribute){ for (const data of sortedDataArray) { recursiveSortByAttribute(data, recursiveAttribute, attribute, config); } } return sortedDataArray; }; } export function transformSortByValue(dataArray, valueMap: Function, asc = true) { dataArray.sort((a, b) => { let result = 0; if (valueMap(a) < valueMap(b)) { result = (asc) ? -1 : 1; } else if (valueMap(a) > valueMap(b)) { result = (asc) ? 1 : -1; } return result; }); return dataArray; } export function createSortByValueTransform(valueMap: Function, asc = true): Function { return (dataArray) => { return transformSortByValue(dataArray, valueMap, asc); }; }