create new data structure

This commit is contained in:
Kristoffer Lind
2019-02-07 10:19:42 +01:00
parent 2c6d978333
commit 9b682e62f8
2 changed files with 329 additions and 165 deletions

View File

@@ -0,0 +1,319 @@
import jQuery from 'jquery';
import { distinctArray } from './utilities';
// TODO: rename colors
function initializeColors ({ layout }) {
console.log(layout);
return {
vColLibBlue: layout.collibblue,
vColLibBlueP: layout.collibbluep,
vColLibClean: layout.collibclean,
vColLibCleanP: layout.collibcleanp,
vColLibCustom: layout.collibcustom,
vColLibCustomP: layout.collibcustomp,
vColLibDark: layout.collibdark,
vColLibDarkP: layout.collibdarkp,
vColLibGreen: layout.collibgreen,
vColLibGreenP: layout.collibgreenp,
vColLibNight: layout.collibnight,
vColLibNightP: layout.collibnightp,
vColLibOrange: layout.colliborange,
vColLibOrangeP: layout.colliborangep,
vColLibRed: layout.collibred,
vColLibRedP: layout.collibredp,
vColLibSoft: layout.collibsoft,
vColLibSoftP: layout.collibsoftp,
vColLibViolete: layout.collibviolete,
vColLibVioleteP: layout.collibvioletep
};
}
function getAlignment (option) {
const alignmentOptions = {
1: 'left',
2: 'center',
3: 'right'
};
return alignmentOptions[option] || 'left';
}
function getFontSizeAdjustment (option) {
const fontSizeAdjustmentOptions = {
1: -2,
2: 0,
3: 2
};
return fontSizeAdjustmentOptions[option] || 0;
}
function getCellSuffix (option) {
const cellSuffixOptions = {
1: '-s',
3: '-l'
};
return cellSuffixOptions[option] || '';
}
function getMeasurementFormat (measurement) {
if (measurement.qNumFormat.qType === 'U' || measurement.qNumFormat.qFmt === '##############') {
return '#.##0';
} else if (measurement.qNumFormat.qType === 'R') {
return measurement.qNumFormat.qFmt.replace(/(|)/gi, '');
}
return measurement.qNumFormat.qFmt;
}
function getMagnitudeLabelSuffix (magnitudeOption) {
const magnitudeLabelSuffixOptions = {
'k': ' (k)',
'm': ' (m)'
};
return magnitudeLabelSuffixOptions[magnitudeOption] || '';
}
function generateMeasurements (information) {
return information.map(measurement => {
const format = getMeasurementFormat(measurement);
const formatMagnitude = format.substr(format.length - 1).toLowerCase();
const transformedMeasurement = {
format,
magnitudeLabelSuffix: getMagnitudeLabelSuffix(formatMagnitude),
name: measurement.qFallbackTitle
};
return transformedMeasurement;
});
}
function generateDimensionEntry (information, data) {
return {
displayValue: data.qText,
name: information.qFallbackTitle,
value: data.qNum
};
}
function generateMatrixCell (information, data) {
return {
displayValue: data.qText,
elementNumber: data.qElemNumber,
format: information.format,
magnitude: information.magnitudeLabelSuffix.substring(
information.magnitudeLabelSuffix.length - 2,
information.magnitudeLabelSuffix.length - 1
),
magnitudeLabelSuffix: information.magnitudeLabelSuffix,
name: information.name,
value: data.qNum
};
}
let lastRow = 0;
function generateDataSet (component, dimensionsInformation, measurementsInformation) {
const dimension1 = [];
const dimension2 = [];
const measurements = generateMeasurements(measurementsInformation);
let matrix = [];
let previousDim1Entry;
const hasSecondDimension = dimensionsInformation.length > 1;
component.backendApi.eachDataRow((rowIndex, row) => {
lastRow += 1;
const dimension1Entry = generateDimensionEntry(dimensionsInformation[0], row[0]);
dimension1.push(dimension1Entry);
let dimension2Entry;
let firstDataCell = 1;
if (hasSecondDimension) {
dimension2Entry = generateDimensionEntry(dimensionsInformation[1], row[1]);
dimension2.push(dimension2Entry);
firstDataCell = 2;
}
const matrixRow = row
.slice(firstDataCell, row.length)
.map((cell, cellIndex) => {
const measurementInformation = measurements[cellIndex];
const generatedCell = generateMatrixCell(measurementInformation, cell);
return generatedCell;
});
if (hasSecondDimension) {
// console.log(row[0]);
const currentDim1Entry = row[0].qText;
const isSameDimension1AsPrevious = currentDim1Entry === previousDim1Entry;
if (isSameDimension1AsPrevious) {
const updatedRow = matrix[matrix.length - 1].concat(matrixRow);
matrix = [
...matrix.slice(0, matrix.length - 1),
updatedRow
];
} else {
matrix[matrix.length] = matrixRow;
}
previousDim1Entry = currentDim1Entry;
} else {
matrix[matrix.length] = matrixRow;
}
});
// filter header dimensions to only have distinct values
return {
dimension1: distinctArray(dimension1),
dimension2: distinctArray(dimension2),
matrix,
measurements
};
}
async function initializeTransformed ({ $element, layout, component }) {
const colors = initializeColors({ layout });
const dimensionsInformation = component.backendApi.getDimensionInfos();
const measurementsInformation = component.backendApi.getMeasureInfos();
const dimensionCount = layout.qHyperCube.qDimensionInfo.length;
const rowCount = component.backendApi.getRowCount();
const maxLoops = layout.maxloops;
const {
dimension1,
dimension2,
measurements,
matrix
} = generateDataSet(component, dimensionsInformation, measurementsInformation);
const customSchemaBasic = [];
const customSchemaFull = [];
let customHeadersCount = 0;
function readCustomSchema () {
const url = `/Extensions/qlik-smart-pivot/${layout.customfile}`;
return jQuery.get(url).then(response => {
const allTextLines = response.split(/\r\n|\n/);
const headers = allTextLines[0].split(';');
customHeadersCount = headers.length;
for (let lineNumber = 0; lineNumber < allTextLines.length; lineNumber += 1) {
customSchemaFull[lineNumber] = new Array(headers.length);
const data = allTextLines[lineNumber].split(';');
if (data.length === headers.length) {
for (let headerIndex = 0; headerIndex < headers.length; headerIndex += 1) {
customSchemaBasic[lineNumber] = data[0];
customSchemaFull[lineNumber][headerIndex] = data[headerIndex];
}
}
}
});
}
const hasCustomSchema = (layout.customfilebool && layout.customfile.length > 4);
const schemaPromise = hasCustomSchema ? readCustomSchema() : Promise.resolve();
await schemaPromise;
// top level properties could be reducers and then components connect to grab what they want,
// possibly with reselect for some presentational transforms (moving some of the presentational logic like formatting and such)
const transformedProperties = {
data: {
headers: {
dimension1, // column headers
dimension2, // parent row headers if exists
measurements // row headers, looped for each dimension2 if exists
},
matrix, // 2d array of all rows/cells to render in body of datatable
meta: {
dimensionCount: dimensionsInformation.length
}
},
general: {
allowExcelExport: layout.allowexportxls,
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
errorMessage: layout.errormessage,
maxLoops
},
selection: {
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
},
styling: {
colors,
customCSV: {
basic: customSchemaBasic,
count: customHeadersCount,
full: customSchemaFull
},
hasCustomFileStyle: layout.customfilebool,
headerOptions: {
alignment: getAlignment(layout.HeaderAlign),
colorSchema: colors[`vColLib${layout.HeaderColorSchema}`],
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersizeheader),
textColor: layout.HeaderTextColorSchema
},
options: {
backgroundColor: colors[`vColLib${layout.ColorSchema}`],
backgroundColorOdd: colors[`vColLib${layout.ColorSchemaP}`],
color: layout.BodyTextColorSchema,
fontFamily: layout.FontFamily,
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersize)
},
semaphoreColors: {
fieldsToApplyTo: {
applyToAll: layout.allsemaphores,
specificFields: [
layout.conceptsemaphore1,
layout.conceptsemaphore2,
layout.conceptsemaphore3,
layout.conceptsemaphore4,
layout.conceptsemaphore5,
layout.conceptsemaphore6,
layout.conceptsemaphore7,
layout.conceptsemaphore9,
layout.conceptsemaphore10
]
},
status: {
critical: layout.metricstatus1,
medium: layout.metricstatus2
},
statusColors: {
critical: {
backgroundColor: layout.colorstatus1.color,
color: layout.colorstatus1text.color
},
medium: {
backgroundColor: layout.colorstatus2.color,
color: layout.colorstatus2text.color
},
normal: {
backgroundColor: layout.colorstatus3.color,
color: layout.colorstatus3text.color
}
}
},
symbolForNulls: layout.symbolfornulls,
usePadding: layout.indentbool,
useSeparatorColumns: dimensionCount === 1 ? false : layout.separatorcols
}
};
if (rowCount > lastRow && rowCount <= (maxLoops * 1000)) {
const requestPage = [
{
qHeight: Math.min(1000, rowCount - lastRow),
qLeft: 0,
qTop: matrix.length,
qWidth: 10 // should be # of columns
}
];
component.backendApi.getData(requestPage).then(() => {
component.paint($element, layout);
});
}
return transformedProperties;
}
export default initializeTransformed;

View File

@@ -1,96 +1,30 @@
import { onlyUnique } from './utilities';
import initializeTransformed from './initialize-transformed';
function initialize ({ $element, layout, component }) {
const colors = {
vColLibClean: layout.collibclean,
vColLibSoft: layout.collibsoft,
vColLibDark: layout.collibdark,
vColLibNight: layout.collibnight,
vColLibRed: layout.collibred,
vColLibOrange: layout.colliborange,
vColLibBlue: layout.collibblue,
vColLibGreen: layout.collibgreen,
vColLibViolete: layout.collibviolete,
vColLibCustom: layout.collibcustom,
vColLibCleanP: layout.collibcleanp,
vColLibSoftP: layout.collibsoftp,
vColLibDarkP: layout.collibdarkp,
vColLibNightP: layout.collibnightp,
vColLibRedP: layout.collibredp,
vColLibOrangeP: layout.colliborangep,
vColLibBlueP: layout.collibbluep,
vColLibGreenP: layout.collibgreenp,
vColLibVioleteP: layout.collibvioletep,
vColLibCustomP: layout.collibcustomp
};
async function initialize ({ $element, layout, component }) {
const transformedProperties = await initializeTransformed({
$element,
component,
layout
});
const nMeasAux = 0;
// TODO: remove everything from here to return statement once jquery parts in paint has been refactored
const vMaxLoops = layout.maxloops;
const vErrorMessage = layout.errormessage;
const vDynamicColorHeader = `vColLib${layout.HeaderColorSchema}`;
const vHeaderColorSchema = colors[vDynamicColorHeader];
const vExportToExcel = layout.allowexportxls;
const vHeaderColorText = layout.HeaderTextColorSchema;
const vHeaderAlign = layout.HeaderAlign;
let vHeaderAlignText = '';
switch (vHeaderAlign) {
case 1:
vHeaderAlignText = 'left';
break;
case 2:
vHeaderAlignText = 'center';
break;
case 3:
vHeaderAlignText = 'right';
break;
}
let vLetterSizeHeader = 0;
switch (layout.lettersizeheader) {
case 1:
vLetterSizeHeader = -2;
break;
case 2:
vLetterSizeHeader = 0;
break;
case 3:
vLetterSizeHeader = 2;
break;
}
let vDimName = '';
const ConceptMatrixFirst = new Array();
const ConceptMatrixSecond = new Array();
let SecondHeaderLength = 0;
const LabelsArray = new Array();
const ExtraLabelsArray = new Array();
let vExtraLabel = '';
const vExcelButtonCode = '';
const ArrayGetSelectedCount = new Array();
let vNumDims = 0;
let vNumMeasures = 0;
let vNumMeasures2 = 0;
const MeasuresFormat = new Array();
let sufixCells = '';
switch (layout.columnwidthslider) {
case 1:
sufixCells += '-s';
break;
case 2:
sufixCells = String(sufixCells);
break;
case 3:
sufixCells += '-l';
break;
default:
sufixCells = String(sufixCells);
break;
}
const dim_count = layout.qHyperCube.qDimensionInfo.length;
const measure_count = layout.qHyperCube.qMeasureInfo.length;
let vSeparatorCols = layout.separatorcols;
if (dim_count == 1) {
vSeparatorCols = false;
}
const vFontFamily = layout.FontFamily;
let lastrow = 0;
const ConceptMatrix = new Array();
let ConceptMatrixRowElem = new Array();
@@ -98,18 +32,6 @@ function initialize ({ $element, layout, component }) {
const ConceptMatrixColElemTable = new Array();
const ConceptMatrixPivot = new Array();
let ConceptMatrixFirstClean = new Array();
let vLetterSize = 0;
switch (layout.lettersize) {
case 1:
vLetterSize = -2;
break;
case 2:
vLetterSize = -1;
break;
case 3:
vLetterSize = 2;
break;
}
const nRows = component.backendApi.getRowCount();
const dimensionInfos = component.backendApi.getDimensionInfos();
@@ -134,20 +56,6 @@ function initialize ({ $element, layout, component }) {
MeasuresFormat.push(mfor);
switch (mfor.substr(mfor.length - 1).toLowerCase()) {
case 'm':
vExtraLabel = ' (M)';
ExtraLabelsArray.push(' (M)');
break;
case 'k':
vExtraLabel = ' (k)';
ExtraLabelsArray.push(' (k)');
break;
default:
vExtraLabel = '';
ExtraLabelsArray.push('');
break;
}
vNumMeasures++;
});
@@ -203,9 +111,6 @@ function initialize ({ $element, layout, component }) {
}
}
SecondHeaderLength = SecondHeader.length;
vNumMeasures2 = vNumMeasures * SecondHeaderLength;
let ConceptPos = 0;
let nMeas3 = 0;
let vHeaderIndex = 0;
@@ -224,75 +129,15 @@ function initialize ({ $element, layout, component }) {
}
}
if (nRows > (lastrow + 1) && nRows <= (vMaxLoops * 1000)) {
const requestPage = [
{
qTop: lastrow + 1,
qLeft: 0,
qWidth: 10, // should be # of columns
qHeight: Math.min(1000, nRows - lastrow)
}
];
component.backendApi.getData(requestPage).then(() => {
component.paint($element);
});
}
const properties = {
ArrayGetSelectedCount,
ConceptMatrix,
ConceptMatrixColElem,
ConceptMatrixColElemTable,
ConceptMatrixRowElem,
ConceptMatrixFirstClean,
ConceptMatrixPivot,
vHeaderColorText,
vFontFamily,
vHeaderColorSchema,
vExportToExcel,
vNumDims,
nMeasAux,
dimensionInfos,
vLetterSizeHeader,
vHeaderAlignText,
MeasuresFormat,
measure_count,
vExcelButtonCode,
sufixCells,
LabelsArray,
SecondHeader,
vSeparatorCols,
nSecond: SecondHeaderLength - 1,
nSecond2: SecondHeaderLength - 1,
vLetterSize,
ExtraLabelsArray,
dim_count,
vExtraLabel,
vNumMeasures,
vNumMeasures2,
lastrow,
measureInfos
};
// TODO: figure out a reasonable datastructure and use these for component
const transformedProperties = {
dimensions: [],
headers: LabelsArray,
headerOptions: {
colorSchema: vHeaderColorSchema,
textColor: vHeaderColorText
},
options: {
fontFamily: vFontFamily
}
ConceptMatrixRowElem
};
return {
colors,
dimensionInfos,
measureInfos,
properties,
transformedProperties
...transformedProperties
};
}