Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79339a8963 | ||
|
|
a6faeeb656 | ||
|
|
c22b7f5c6b | ||
|
|
1436463f59 |
@@ -42,7 +42,7 @@ class DataCell extends React.PureComponent {
|
||||
|
||||
render () {
|
||||
const {
|
||||
general,
|
||||
cellWidth,
|
||||
measurement,
|
||||
styleBuilder,
|
||||
styling
|
||||
@@ -55,17 +55,15 @@ class DataCell extends React.PureComponent {
|
||||
...styleBuilder.getStyle(),
|
||||
paddingLeft: '5px',
|
||||
textAlign: textAlignment,
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
minWidth: cellWidth,
|
||||
maxWidth: cellWidth
|
||||
};
|
||||
|
||||
const isEmptyCell = measurement.displayValue === '';
|
||||
let formattedMeasurementValue;
|
||||
if (isEmptyCell) {
|
||||
if (isEmptyCell || styleBuilder.hasComments()) {
|
||||
formattedMeasurementValue = '';
|
||||
cellStyle.cursor = 'default';
|
||||
} else if (styleBuilder.hasComments()) {
|
||||
formattedMeasurementValue = '.';
|
||||
} else {
|
||||
formattedMeasurementValue = formatMeasurementValue(measurement, styling);
|
||||
}
|
||||
@@ -104,6 +102,7 @@ class DataCell extends React.PureComponent {
|
||||
}
|
||||
|
||||
DataCell.propTypes = {
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array.isRequired,
|
||||
@@ -114,9 +113,7 @@ DataCell.propTypes = {
|
||||
dimensionCount: PropTypes.number.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellWidth: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
measurement: PropTypes.shape({
|
||||
format: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
|
||||
@@ -5,102 +5,114 @@ import DataCell from './data-cell.jsx';
|
||||
import RowHeader from './row-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const DataTable = ({ data, general, component, renderData, styling }) => {
|
||||
const {
|
||||
headers: {
|
||||
dimension1,
|
||||
measurements
|
||||
},
|
||||
matrix
|
||||
} = data;
|
||||
class DataTable extends React.PureComponent {
|
||||
render () {
|
||||
const {
|
||||
cellWidth,
|
||||
columnSeparatorWidth,
|
||||
component,
|
||||
data,
|
||||
general,
|
||||
renderData,
|
||||
styling
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className="row-wrapper">
|
||||
<table>
|
||||
<tbody>
|
||||
{dimension1.map((dimensionEntry, dimensionIndex) => {
|
||||
const rowHeaderText = dimensionEntry.displayValue || '';
|
||||
if (rowHeaderText === '-') {
|
||||
return null;
|
||||
}
|
||||
const styleBuilder = new StyleBuilder(styling);
|
||||
if (styling.hasCustomFileStyle) {
|
||||
styleBuilder.parseCustomFileStyle(rowHeaderText);
|
||||
} else {
|
||||
styleBuilder.applyStandardAttributes(dimensionIndex);
|
||||
styleBuilder.applyCustomStyle({
|
||||
fontSize: `${14 + styling.options.fontSizeAdjustment}px`
|
||||
});
|
||||
}
|
||||
const rowStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
width: '230px',
|
||||
...styleBuilder.getStyle()
|
||||
};
|
||||
const {
|
||||
headers: {
|
||||
dimension1,
|
||||
measurements
|
||||
},
|
||||
matrix
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<tr key={dimensionEntry.displayValue}>
|
||||
{!renderData ?
|
||||
<RowHeader
|
||||
altState={data.meta.altState}
|
||||
entry={dimensionEntry}
|
||||
component={component}
|
||||
rowStyle={rowStyle}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/> : null
|
||||
}
|
||||
{renderData && injectSeparators(
|
||||
matrix[dimensionIndex],
|
||||
styling.useSeparatorColumns,
|
||||
{ atEvery: measurements.length }
|
||||
).map((measurementData, index) => {
|
||||
if (measurementData.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${12 + styling.options.fontSizeAdjustment}px`
|
||||
};
|
||||
const separatorStyle = {
|
||||
minWidth: columnSeparatorWidth,
|
||||
maxWidth: columnSeparatorWidth
|
||||
};
|
||||
|
||||
return (
|
||||
<td
|
||||
className="empty"
|
||||
key={`${dimensionEntry.displayValue}-${index}-separator`}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</td>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="row-wrapper">
|
||||
<table>
|
||||
<tbody>
|
||||
{dimension1.map((dimensionEntry, dimensionIndex) => {
|
||||
const rowHeaderText = dimensionEntry.displayValue || '';
|
||||
if (rowHeaderText === '-') {
|
||||
return null;
|
||||
}
|
||||
const styleBuilder = new StyleBuilder(styling);
|
||||
if (styling.hasCustomFileStyle) {
|
||||
styleBuilder.parseCustomFileStyle(rowHeaderText);
|
||||
} else {
|
||||
styleBuilder.applyStandardAttributes(dimensionIndex);
|
||||
styleBuilder.applyCustomStyle({
|
||||
fontSize: `${14 + styling.options.fontSizeAdjustment}px`
|
||||
});
|
||||
}
|
||||
const rowStyle = {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
width: '230px',
|
||||
...styleBuilder.getStyle()
|
||||
};
|
||||
|
||||
const { dimension1: dimension1Info, dimension2, measurement } = measurementData.parents;
|
||||
const id = `${dimension1Info.elementNumber}-${dimension2 && dimension2.elementNumber}-${measurement.header}`;
|
||||
return (
|
||||
<DataCell
|
||||
data={data}
|
||||
general={general}
|
||||
key={`${dimensionEntry.displayValue}-${id}`}
|
||||
measurement={measurementData}
|
||||
return (
|
||||
<tr key={dimensionEntry.displayValue}>
|
||||
{!renderData ?
|
||||
<RowHeader
|
||||
altState={data.meta.altState}
|
||||
component={component}
|
||||
entry={dimensionEntry}
|
||||
rowStyle={rowStyle}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
/> : null
|
||||
}
|
||||
{renderData && injectSeparators(
|
||||
matrix[dimensionIndex],
|
||||
columnSeparatorWidth,
|
||||
{ atEvery: measurements.length }
|
||||
).map((measurementData, index) => {
|
||||
if (measurementData.isSeparator) {
|
||||
return (
|
||||
<td
|
||||
className="empty"
|
||||
key={`${dimensionEntry.displayValue}-${index}-separator`}
|
||||
style={separatorStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const { dimension1: dimension1Info, dimension2, measurement } = measurementData.parents;
|
||||
const id = `${dimension1Info.elementNumber}-${dimension2 && dimension2.elementNumber}-${measurement.header}-${measurement.index}`;
|
||||
return (
|
||||
<DataCell
|
||||
cellWidth={cellWidth}
|
||||
component={component}
|
||||
data={data}
|
||||
general={general}
|
||||
key={`${dimensionEntry.displayValue}-${id}`}
|
||||
measurement={measurementData}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DataTable.defaultProps = {
|
||||
renderData: true
|
||||
};
|
||||
|
||||
DataTable.propTypes = {
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
columnSeparatorWidth: PropTypes.string.isRequired,
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array.isRequired
|
||||
|
||||
@@ -209,6 +209,23 @@ const tableFormat = {
|
||||
],
|
||||
defaultValue: 'right'
|
||||
},
|
||||
FitChartWidth: {
|
||||
ref: 'fitchartwidth',
|
||||
type: 'boolean',
|
||||
component: 'switch',
|
||||
label: 'Fill chart width',
|
||||
options: [
|
||||
{
|
||||
value: true,
|
||||
label: 'On'
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: 'Off'
|
||||
}
|
||||
],
|
||||
defaultValue: false
|
||||
},
|
||||
ColumnWidthSlider: {
|
||||
type: 'number',
|
||||
component: 'slider',
|
||||
@@ -217,7 +234,8 @@ const tableFormat = {
|
||||
min: 20,
|
||||
max: 250,
|
||||
step: 10,
|
||||
defaultValue: 50
|
||||
defaultValue: 50,
|
||||
show: data => !data.fitchartwidth
|
||||
},
|
||||
SymbolForNulls: {
|
||||
ref: 'symbolfornulls',
|
||||
|
||||
@@ -17,7 +17,7 @@ class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { baseCSS, cellWidth, colSpan, entry, styling, component } = this.props;
|
||||
const { baseCSS, cellWidth, colSpan, component, entry, styling } = this.props;
|
||||
const inEditState = component.inEditState();
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
@@ -55,7 +55,7 @@ ColumnHeader.defaultProps = {
|
||||
|
||||
ColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
cellWidth: PropTypes.string,
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
colSpan: PropTypes.number,
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired,
|
||||
|
||||
@@ -5,121 +5,124 @@ import ColumnHeader from './column-header.jsx';
|
||||
import MeasurementColumnHeader from './measurement-column-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const HeadersTable = ({ data, general, component, styling, isKpi }) => {
|
||||
const baseCSS = {
|
||||
backgroundColor: styling.headerOptions.colorSchema,
|
||||
color: styling.headerOptions.textColor,
|
||||
fontFamily: styling.options.fontFamily,
|
||||
textAlign: styling.headerOptions.alignment
|
||||
};
|
||||
class HeadersTable extends React.PureComponent {
|
||||
render () {
|
||||
const {
|
||||
cellWidth,
|
||||
columnSeparatorWidth,
|
||||
component,
|
||||
data,
|
||||
general,
|
||||
isKpi,
|
||||
styling
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
dimension1,
|
||||
dimension2,
|
||||
measurements
|
||||
} = data.headers;
|
||||
const baseCSS = {
|
||||
backgroundColor: styling.headerOptions.colorSchema,
|
||||
color: styling.headerOptions.textColor,
|
||||
fontFamily: styling.options.fontFamily,
|
||||
textAlign: styling.headerOptions.alignment
|
||||
};
|
||||
|
||||
const hasSecondDimension = dimension2.length > 0;
|
||||
const {
|
||||
dimension1,
|
||||
dimension2,
|
||||
measurements
|
||||
} = data.headers;
|
||||
|
||||
return (
|
||||
<div className="header-wrapper">
|
||||
<table className="header">
|
||||
<tbody>
|
||||
<tr>
|
||||
{isKpi ?
|
||||
<ExportColumnHeader
|
||||
component={component}
|
||||
allowExcelExport={general.allowExcelExport}
|
||||
baseCSS={baseCSS}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
styling={styling}
|
||||
title={dimension1[0].name}
|
||||
/> : null
|
||||
}
|
||||
{!isKpi && !hasSecondDimension && measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}`}
|
||||
measurement={measurementEntry}
|
||||
styling={styling}
|
||||
/>
|
||||
))}
|
||||
{!isKpi && hasSecondDimension && injectSeparators(dimension2, styling.useSeparatorColumns).map((entry, index) => {
|
||||
if (entry.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${13 + styling.headerOptions.fontSizeAdjustment}px`
|
||||
};
|
||||
const hasSecondDimension = dimension2.length > 0;
|
||||
|
||||
return (
|
||||
<th
|
||||
className="empty"
|
||||
key={index}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</th>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ColumnHeader
|
||||
altState={data.meta.altState}
|
||||
const separatorStyle = {
|
||||
minWidth: columnSeparatorWidth,
|
||||
maxWidth: columnSeparatorWidth
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="header-wrapper">
|
||||
<table className="header">
|
||||
<tbody>
|
||||
<tr>
|
||||
{isKpi ?
|
||||
<ExportColumnHeader
|
||||
allowExcelExport={general.allowExcelExport}
|
||||
baseCSS={baseCSS}
|
||||
cellWidth={general.cellWidth}
|
||||
colSpan={measurements.length}
|
||||
entry={entry}
|
||||
key={entry.displayValue}
|
||||
component={component}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
styling={styling}
|
||||
title={dimension1[0].name}
|
||||
/> : null
|
||||
}
|
||||
{!isKpi && !hasSecondDimension && measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
cellWidth={cellWidth}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}-${measurementEntry.index}`}
|
||||
measurement={measurementEntry}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
{!isKpi && hasSecondDimension && (
|
||||
<tr>
|
||||
{injectSeparators(dimension2, styling.useSeparatorColumns).map((dimensionEntry, index) => {
|
||||
if (dimensionEntry.isSeparator) {
|
||||
const separatorStyle = {
|
||||
color: 'white',
|
||||
fontFamily: styling.options.fontFamily,
|
||||
fontSize: `${12 + styling.headerOptions.fontSizeAdjustment}px`
|
||||
};
|
||||
|
||||
))}
|
||||
{!isKpi && hasSecondDimension && injectSeparators(dimension2, columnSeparatorWidth).map((entry, index) => {
|
||||
if (entry.isSeparator) {
|
||||
return (
|
||||
<th
|
||||
className="empty"
|
||||
key={index}
|
||||
style={separatorStyle}
|
||||
>
|
||||
*
|
||||
</th>
|
||||
/>
|
||||
);
|
||||
}
|
||||
return measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
return (
|
||||
<ColumnHeader
|
||||
altState={data.meta.altState}
|
||||
baseCSS={baseCSS}
|
||||
dimensionEntry={dimensionEntry}
|
||||
general={general}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}-${dimensionEntry.name}`}
|
||||
measurement={measurementEntry}
|
||||
cellWidth={cellWidth}
|
||||
colSpan={measurements.length}
|
||||
component={component}
|
||||
entry={entry}
|
||||
key={entry.displayValue}
|
||||
styling={styling}
|
||||
/>
|
||||
));
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
{!isKpi && hasSecondDimension && (
|
||||
<tr>
|
||||
{injectSeparators(dimension2, columnSeparatorWidth).map((dimensionEntry, index) => {
|
||||
if (dimensionEntry.isSeparator) {
|
||||
return (
|
||||
<th
|
||||
className="empty"
|
||||
key={index}
|
||||
style={separatorStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return measurements.map(measurementEntry => (
|
||||
<MeasurementColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
cellWidth={cellWidth}
|
||||
dimensionEntry={dimensionEntry}
|
||||
hasSecondDimension={hasSecondDimension}
|
||||
key={`${measurementEntry.displayValue}-${measurementEntry.name}-${measurementEntry.index}-${dimensionEntry.name}`}
|
||||
measurement={measurementEntry}
|
||||
styling={styling}
|
||||
/>
|
||||
));
|
||||
})}
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HeadersTable.propTypes = {
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
columnSeparatorWidth: PropTypes.string.isRequired,
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array,
|
||||
|
||||
@@ -3,25 +3,27 @@ import PropTypes from 'prop-types';
|
||||
import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measurement, styling }) => {
|
||||
const MeasurementColumnHeader = ({ baseCSS, cellWidth, hasSecondDimension, measurement, styling }) => {
|
||||
const title = `${measurement.name}`;
|
||||
const { fontSizeAdjustment } = styling.headerOptions;
|
||||
const isMediumFontSize = fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
const cellStyle = {
|
||||
...baseCSS,
|
||||
verticalAlign: 'middle',
|
||||
minWidth: cellWidth,
|
||||
maxWidth: cellWidth
|
||||
};
|
||||
|
||||
if (hasSecondDimension) {
|
||||
const isPercentageFormat = measurement.format.substring(measurement.format.length - 1) === '%';
|
||||
let baseFontSize = 14;
|
||||
if (isPercentageFormat) {
|
||||
baseFontSize = 13;
|
||||
}
|
||||
const cellStyle = {
|
||||
...baseCSS,
|
||||
fontSize: `${baseFontSize + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '45px' : '35px',
|
||||
verticalAlign: 'middle',
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
};
|
||||
cellStyle.fontSize = `${baseFontSize + fontSizeAdjustment}px`;
|
||||
cellStyle.height = isMediumFontSize ? '45px' : '35px';
|
||||
|
||||
return (
|
||||
<th
|
||||
className="grid-cells"
|
||||
@@ -37,18 +39,12 @@ const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measure
|
||||
);
|
||||
}
|
||||
|
||||
const style = {
|
||||
...baseCSS,
|
||||
fontSize: `${15 + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '90px' : '70px',
|
||||
verticalAlign: 'middle',
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
};
|
||||
cellStyle.fontSize = `${15 + fontSizeAdjustment}px`;
|
||||
cellStyle.height = isMediumFontSize ? '90px' : '70px';
|
||||
return (
|
||||
<th
|
||||
className="grid-cells"
|
||||
style={style}
|
||||
style={cellStyle}
|
||||
>
|
||||
<Tooltip
|
||||
tooltipText={title}
|
||||
@@ -66,9 +62,7 @@ MeasurementColumnHeader.defaultProps = {
|
||||
|
||||
MeasurementColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellWidth: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
cellWidth: PropTypes.string.isRequired,
|
||||
hasSecondDimension: PropTypes.bool,
|
||||
measurement: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired
|
||||
|
||||
@@ -227,6 +227,18 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
|
||||
}
|
||||
}
|
||||
|
||||
let cellWidth;
|
||||
if (layout.fitchartwidth) {
|
||||
// The widths are calculated based on the current element width. Note: this could use % to set
|
||||
// the widths as percentages of the available width. However, this often results in random
|
||||
// columns getting 1px wider than the others because of rounding necessary to fill the width.
|
||||
// This 1px causes missalignment between the data- and header tables.
|
||||
cellWidth = '';
|
||||
} else {
|
||||
// If using the previous solution just set 60px
|
||||
cellWidth = `${layout.columnwidthslider > 10 ? layout.columnwidthslider : 60}px`;
|
||||
}
|
||||
|
||||
// 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 = {
|
||||
@@ -245,13 +257,13 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
|
||||
general: {
|
||||
allowExcelExport: layout.allowexportxls,
|
||||
allowFilteringByClick: layout.filteroncellclick,
|
||||
// If using the previous solution just set 60px
|
||||
cellWidth: `${layout.columnwidthslider > 10 ? layout.columnwidthslider : 60}px`,
|
||||
cellWidth: cellWidth,
|
||||
errorMessage: layout.errormessage,
|
||||
footnote: layout.footnote,
|
||||
maxLoops,
|
||||
subtitle: layout.subtitle,
|
||||
title: layout.title
|
||||
title: layout.title,
|
||||
useColumnSeparator: layout.separatorcols && dimensionCount > 1
|
||||
},
|
||||
selection: {
|
||||
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
|
||||
@@ -305,8 +317,7 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
|
||||
}
|
||||
},
|
||||
symbolForNulls: layout.symbolfornulls,
|
||||
usePadding: layout.indentbool,
|
||||
useSeparatorColumns: dimensionCount === 1 ? false : layout.separatorcols
|
||||
usePadding: layout.indentbool
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -57,10 +57,8 @@
|
||||
}
|
||||
|
||||
.empty {
|
||||
width: 3%;
|
||||
background: #fff;
|
||||
min-width: 4px !important;
|
||||
max-width: 4px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
th.main-kpi {
|
||||
|
||||
162
src/root.jsx
162
src/root.jsx
@@ -4,61 +4,129 @@ import HeadersTable from './headers-table/index.jsx';
|
||||
import DataTable from './data-table/index.jsx';
|
||||
import { LinkedScrollWrapper, LinkedScrollSection } from './linked-scroll';
|
||||
|
||||
const Root = ({ state, component, editmodeClass }) => (
|
||||
<div className="root">
|
||||
<LinkedScrollWrapper>
|
||||
<div className={`kpi-table ${editmodeClass}`}>
|
||||
<HeadersTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
isKpi
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
<LinkedScrollSection linkVertical>
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
component={component}
|
||||
renderData={false}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
class Root extends React.PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.onDataTableRefSet = this.onDataTableRefSet.bind(this);
|
||||
this.renderedTableWidth = 0;
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
const tableWidth = this.dataTableRef.getBoundingClientRect().width;
|
||||
if (this.renderedTableWidth !== tableWidth) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
onDataTableRefSet (element) {
|
||||
this.dataTableRef = element;
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { editmodeClass, component, state } = this.props;
|
||||
const { data, general, styling } = state;
|
||||
|
||||
// Determine cell- and column separator width
|
||||
let cellWidth = '0px';
|
||||
let columnSeparatorWidth = '';
|
||||
if (this.dataTableRef) {
|
||||
const tableWidth = this.dataTableRef.getBoundingClientRect().width;
|
||||
this.renderedTableWidth = tableWidth;
|
||||
|
||||
if (general.cellWidth) {
|
||||
cellWidth = general.cellWidth;
|
||||
if (general.useColumnSeparator) {
|
||||
columnSeparatorWidth = '8px';
|
||||
}
|
||||
} else {
|
||||
const headerMarginRight = 8;
|
||||
const borderWidth = 1;
|
||||
const rowCellCount = data.matrix[0].length;
|
||||
|
||||
let separatorCount = 0;
|
||||
let separatorWidth = 0;
|
||||
if (general.useColumnSeparator) {
|
||||
separatorCount = data.headers.dimension2.length - 1;
|
||||
separatorWidth = Math.min(Math.floor(tableWidth * 0.2 / separatorCount), 8);
|
||||
columnSeparatorWidth = `${separatorWidth}px`;
|
||||
}
|
||||
|
||||
const separatorWidthSum = (separatorWidth + borderWidth) * separatorCount;
|
||||
cellWidth = `${Math.floor((tableWidth - separatorWidthSum - headerMarginRight - borderWidth)
|
||||
/ rowCellCount) - borderWidth}px`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="root">
|
||||
<LinkedScrollWrapper>
|
||||
<div className={`kpi-table ${editmodeClass}`}>
|
||||
<HeadersTable
|
||||
cellWidth={cellWidth}
|
||||
columnSeparatorWidth={columnSeparatorWidth}
|
||||
component={component}
|
||||
data={data}
|
||||
general={general}
|
||||
isKpi
|
||||
styling={styling}
|
||||
/>
|
||||
<LinkedScrollSection linkVertical>
|
||||
<DataTable
|
||||
cellWidth={cellWidth}
|
||||
columnSeparatorWidth={columnSeparatorWidth}
|
||||
component={component}
|
||||
data={data}
|
||||
general={general}
|
||||
renderData={false}
|
||||
styling={styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
</div>
|
||||
<div
|
||||
className={`data-table ${editmodeClass}`}
|
||||
style={{ width: general.cellWidth ? 'auto' : '100%' }}
|
||||
ref={this.onDataTableRefSet}
|
||||
>
|
||||
<LinkedScrollSection linkHorizontal>
|
||||
<HeadersTable
|
||||
cellWidth={cellWidth}
|
||||
columnSeparatorWidth={columnSeparatorWidth}
|
||||
component={component}
|
||||
data={data}
|
||||
general={general}
|
||||
isKpi={false}
|
||||
styling={styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
<LinkedScrollSection
|
||||
linkHorizontal
|
||||
linkVertical
|
||||
>
|
||||
<DataTable
|
||||
cellWidth={cellWidth}
|
||||
columnSeparatorWidth={columnSeparatorWidth}
|
||||
component={component}
|
||||
data={data}
|
||||
general={general}
|
||||
styling={styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
</div>
|
||||
</LinkedScrollWrapper>
|
||||
</div>
|
||||
<div className={`data-table ${editmodeClass}`}>
|
||||
<LinkedScrollSection linkHorizontal>
|
||||
<HeadersTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
isKpi={false}
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
<LinkedScrollSection
|
||||
linkHorizontal
|
||||
linkVertical
|
||||
>
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
</div>
|
||||
</LinkedScrollWrapper>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Root.propTypes = {
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
editmodeClass: PropTypes.string.isRequired,
|
||||
state: PropTypes.shape({
|
||||
data: PropTypes.object.isRequired,
|
||||
general: PropTypes.object.isRequired,
|
||||
styling: PropTypes.object.isRequired
|
||||
}).isRequired,
|
||||
editmodeClass: PropTypes.string.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default Root;
|
||||
|
||||
@@ -16,7 +16,7 @@ export function Deferred () {
|
||||
});
|
||||
}
|
||||
|
||||
export function injectSeparators (array, shouldHaveSeparator, suppliedOptions) {
|
||||
export function injectSeparators (array, columnSeparatorWidth, suppliedOptions) {
|
||||
const defaultOptions = {
|
||||
atEvery: 1,
|
||||
separator: { isSeparator: true }
|
||||
@@ -26,7 +26,7 @@ export function injectSeparators (array, shouldHaveSeparator, suppliedOptions) {
|
||||
...suppliedOptions
|
||||
};
|
||||
|
||||
if (!shouldHaveSeparator) {
|
||||
if (!columnSeparatorWidth) {
|
||||
return array;
|
||||
}
|
||||
return array.reduce((result, entry, index) => {
|
||||
|
||||
Reference in New Issue
Block a user