185 lines
5.7 KiB
JavaScript
185 lines
5.7 KiB
JavaScript
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { ApplyPreMask } from '../masking';
|
|
import { addSeparators } from '../utilities';
|
|
import Tooltip from '../tooltip/index.jsx';
|
|
|
|
class DataCell extends React.PureComponent {
|
|
constructor (props) {
|
|
super(props);
|
|
this.handleSelect = this.handleSelect.bind(this);
|
|
}
|
|
|
|
handleSelect () {
|
|
const { data: { meta: { dimensionCount } }, general: { allowFilteringByClick }, measurement, qlik } = this.props;
|
|
const hasSecondDimension = dimensionCount > 1;
|
|
if (!allowFilteringByClick) {
|
|
return;
|
|
}
|
|
|
|
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
|
|
|
|
if (hasSecondDimension) {
|
|
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
|
|
}
|
|
}
|
|
|
|
render () {
|
|
const {
|
|
data,
|
|
general,
|
|
measurement,
|
|
styleBuilder,
|
|
styling
|
|
} = this.props;
|
|
|
|
let textAlignment = styling.options.textAlignment || 'Right';
|
|
|
|
let cellStyle = {
|
|
fontFamily: styling.options.fontFamily,
|
|
...styleBuilder.getStyle(),
|
|
paddingLeft: '5px',
|
|
textAlign: textAlignment
|
|
};
|
|
|
|
const isEmptyCell = measurement.displayValue === '';
|
|
const isColumnPercentageBased = (/%/).test(measurement.format);
|
|
let formattedMeasurementValue;
|
|
if (isEmptyCell) {
|
|
formattedMeasurementValue = '';
|
|
cellStyle.cursor = 'default';
|
|
} else if (styleBuilder.hasComments()) {
|
|
formattedMeasurementValue = '.';
|
|
} else {
|
|
formattedMeasurementValue = formatMeasurementValue(measurement, styling);
|
|
}
|
|
|
|
const { conditionalColoring } = styling;
|
|
if (conditionalColoring.enabled) {
|
|
const isValidConditionalColoringValue = !styleBuilder.hasComments() && !isNaN(measurement.value);
|
|
const isSpecifiedRow =
|
|
conditionalColoring.rows.indexOf(measurement.parents.dimension1.header) !== -1;
|
|
const shouldHaveConditionalColoring = conditionalColoring.colorAllRows || isSpecifiedRow;
|
|
if (isValidConditionalColoringValue && shouldHaveConditionalColoring) {
|
|
const { color, textColor } = getConditionalColor(measurement, conditionalColoring);
|
|
cellStyle.backgroundColor = color.color;
|
|
cellStyle.color = textColor.color;
|
|
}
|
|
}
|
|
|
|
let cellClass = 'grid-cells';
|
|
const hasTwoDimensions = data.headers.dimension2 && data.headers.dimension2.length > 0;
|
|
const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1 && hasTwoDimensions;
|
|
if (shouldUseSmallCells) {
|
|
cellClass = 'grid-cells-small';
|
|
}
|
|
|
|
return (
|
|
<td
|
|
className={`${cellClass}${general.cellSuffix}`}
|
|
onClick={isEmptyCell ? null : this.handleSelect}
|
|
style={cellStyle}
|
|
>
|
|
<Tooltip
|
|
styling={styling}
|
|
tooltipText={formattedMeasurementValue}
|
|
>
|
|
{formattedMeasurementValue}
|
|
</Tooltip>
|
|
</td>
|
|
);
|
|
}
|
|
}
|
|
|
|
DataCell.propTypes = {
|
|
data: PropTypes.shape({
|
|
headers: PropTypes.shape({
|
|
measurements: PropTypes.array.isRequired
|
|
}).isRequired
|
|
}).isRequired,
|
|
general: PropTypes.shape({
|
|
cellSuffix: PropTypes.string.isRequired
|
|
}).isRequired,
|
|
measurement: PropTypes.shape({
|
|
format: PropTypes.string,
|
|
name: PropTypes.string,
|
|
value: PropTypes.any
|
|
}).isRequired,
|
|
qlik: PropTypes.shape({
|
|
backendApi: PropTypes.shape({
|
|
selectValues: function (props, propName) {
|
|
if (props.isSnapshot || typeof props[propName] === 'function') {
|
|
return null;
|
|
}
|
|
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
|
}
|
|
}).isRequired
|
|
}).isRequired,
|
|
styleBuilder: PropTypes.shape({
|
|
hasComments: PropTypes.func.isRequired
|
|
}).isRequired,
|
|
styling: PropTypes.shape({
|
|
symbolForNulls: PropTypes.any.isRequired
|
|
}).isRequired
|
|
};
|
|
|
|
export default DataCell;
|
|
|
|
function formatMeasurementValue (measurement, styling) {
|
|
const isColumnPercentageBased = (/%/).test(measurement.format);
|
|
let formattedMeasurementValue = '';
|
|
if (isColumnPercentageBased) {
|
|
if (isNaN(measurement.value)) {
|
|
formattedMeasurementValue = styling.symbolForNulls;
|
|
} else {
|
|
formattedMeasurementValue = ApplyPreMask('0,00%', measurement.value);
|
|
}
|
|
} else {
|
|
let magnitudeDivider;
|
|
switch (measurement.magnitude.toLowerCase()) {
|
|
case 'k':
|
|
magnitudeDivider = 1000;
|
|
break;
|
|
case 'm':
|
|
magnitudeDivider = 1000000;
|
|
break;
|
|
default:
|
|
magnitudeDivider = 1;
|
|
}
|
|
const formattingStringWithoutMagnitude = measurement.format.replace(/k|K|m|M/gi, '');
|
|
if (isNaN(measurement.value)) {
|
|
formattedMeasurementValue = styling.symbolForNulls;
|
|
} else {
|
|
let preFormatValue = measurement.value;
|
|
if (isColumnPercentageBased) {
|
|
preFormatValue *= 100;
|
|
}
|
|
switch (formattingStringWithoutMagnitude) {
|
|
case '#.##0':
|
|
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), '.', ',', 0);
|
|
break;
|
|
case '#,##0':
|
|
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), ',', '.', 0);
|
|
break;
|
|
default:
|
|
formattedMeasurementValue = ApplyPreMask(
|
|
formattingStringWithoutMagnitude,
|
|
(preFormatValue / magnitudeDivider)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return formattedMeasurementValue;
|
|
}
|
|
|
|
function getConditionalColor (measurement, conditionalColoring) {
|
|
if (measurement.value < conditionalColoring.threshold.poor) {
|
|
return conditionalColoring.colors.poor;
|
|
}
|
|
if (measurement.value < conditionalColoring.threshold.fair) {
|
|
return conditionalColoring.colors.fair;
|
|
}
|
|
return conditionalColoring.colors.good;
|
|
}
|