Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 92 additions & 118 deletions src/TableRenderers.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import {PivotData} from './Utilities';
import React from 'react';
import { PivotData } from './Utilities';

// helper function for setting row/col-span in pivotTableRenderer
const spanSize = function(arr, i, j) {
const spanSize = function (arr, i, j) {
let x;
if (i !== 0) {
let asc, end;
let noDraw = true;
for (
x = 0, end = j, asc = end >= 0;
asc ? x <= end : x >= end;
asc ? x++ : x--
) {
for (x = 0, end = j, asc = end >= 0; asc ? x <= end : x >= end; asc ? x++ : x--) {
if (arr[i - 1][x] !== arr[i][x]) {
noDraw = false;
}
Expand All @@ -25,11 +21,7 @@ const spanSize = function(arr, i, j) {
while (i + len < arr.length) {
let asc1, end1;
let stop = false;
for (
x = 0, end1 = j, asc1 = end1 >= 0;
asc1 ? x <= end1 : x >= end1;
asc1 ? x++ : x--
) {
for (x = 0, end1 = j, asc1 = end1 >= 0; asc1 ? x <= end1 : x >= end1; asc1 ? x++ : x--) {
if (arr[i][x] !== arr[i + len][x]) {
stop = true;
}
Expand All @@ -45,10 +37,10 @@ const spanSize = function(arr, i, j) {
function redColorScaleGenerator(values) {
const min = Math.min.apply(Math, values);
const max = Math.max.apply(Math, values);
return x => {
return (x) => {
// eslint-disable-next-line no-magic-numbers
const nonRed = 255 - Math.round((255 * (x - min)) / (max - min));
return {backgroundColor: `rgb(255,${nonRed},${nonRed})`};
return { backgroundColor: `rgb(255,${nonRed},${nonRed})` };
};
}

Expand All @@ -61,45 +53,38 @@ function makeRenderer(opts = {}) {
const rowKeys = pivotData.getRowKeys();
const colKeys = pivotData.getColKeys();
const grandTotalAggregator = pivotData.getAggregator([], []);
const hideRowTotals = this.props.hideRowTotals;
const hideColTotals = this.props.hideColTotals;

let valueCellColors = () => {};
let rowTotalColors = () => {};
let colTotalColors = () => {};

if (opts.heatmapMode) {
const colorScaleGenerator = this.props.tableColorScaleGenerator;
const rowTotalValues = colKeys.map(x =>
pivotData.getAggregator([], x).value()
);
const rowTotalValues = colKeys.map((x) => pivotData.getAggregator([], x).value());
rowTotalColors = colorScaleGenerator(rowTotalValues);
const colTotalValues = rowKeys.map(x =>
pivotData.getAggregator(x, []).value()
);
const colTotalValues = rowKeys.map((x) => pivotData.getAggregator(x, []).value());
colTotalColors = colorScaleGenerator(colTotalValues);

if (opts.heatmapMode === 'full') {
const allValues = [];
rowKeys.map(r =>
colKeys.map(c =>
allValues.push(pivotData.getAggregator(r, c).value())
)
rowKeys.map((r) =>
colKeys.map((c) => allValues.push(pivotData.getAggregator(r, c).value()))
);
const colorScale = colorScaleGenerator(allValues);
valueCellColors = (r, c, v) => colorScale(v);
} else if (opts.heatmapMode === 'row') {
const rowColorScales = {};
rowKeys.map(r => {
const rowValues = colKeys.map(x =>
pivotData.getAggregator(r, x).value()
);
rowKeys.map((r) => {
const rowValues = colKeys.map((x) => pivotData.getAggregator(r, x).value());
rowColorScales[r] = colorScaleGenerator(rowValues);
});
valueCellColors = (r, c, v) => rowColorScales[r](v);
} else if (opts.heatmapMode === 'col') {
const colColorScales = {};
colKeys.map(c => {
const colValues = rowKeys.map(x =>
pivotData.getAggregator(x, c).value()
);
colKeys.map((c) => {
const colValues = rowKeys.map((x) => pivotData.getAggregator(x, c).value());
colColorScales[c] = colorScaleGenerator(colValues);
});
valueCellColors = (r, c, v) => colColorScales[c](v);
Expand All @@ -122,27 +107,21 @@ function makeRenderer(opts = {}) {
filters[attr] = rowValues[i];
}
}
return e =>
this.props.tableOptions.clickCallback(
e,
value,
filters,
pivotData
);
return (e) => this.props.tableOptions.clickCallback(e, value, filters, pivotData);
}
: null;

return (
<table className="pvtTable">
<thead>
{colAttrs.map(function(c, j) {
{colAttrs.map(function (c, j) {
return (
<tr key={`colAttr${j}`}>
{j === 0 && rowAttrs.length !== 0 && (
<th colSpan={rowAttrs.length} rowSpan={colAttrs.length} />
)}
<th className="pvtAxisLabel">{c}</th>
{colKeys.map(function(colKey, i) {
{colKeys.map(function (colKey, i) {
const x = spanSize(colKeys, i, j);
if (x === -1) {
return null;
Expand All @@ -152,23 +131,17 @@ function makeRenderer(opts = {}) {
className="pvtColLabel"
key={`colKey${i}`}
colSpan={x}
rowSpan={
j === colAttrs.length - 1 && rowAttrs.length !== 0
? 2
: 1
}
rowSpan={j === colAttrs.length - 1 && rowAttrs.length !== 0 ? 2 : 1}
>
{colKey[j]}
</th>
);
})}

{j === 0 && (
{j === 0 && !hideRowTotals && (
<th
className="pvtTotalLabel"
rowSpan={
colAttrs.length + (rowAttrs.length === 0 ? 0 : 1)
}
rowSpan={colAttrs.length + (rowAttrs.length === 0 ? 0 : 1)}
>
Totals
</th>
Expand All @@ -179,26 +152,27 @@ function makeRenderer(opts = {}) {

{rowAttrs.length !== 0 && (
<tr>
{rowAttrs.map(function(r, i) {
{rowAttrs.map(function (r, i) {
return (
<th className="pvtAxisLabel" key={`rowAttr${i}`}>
{r}
</th>
);
})}

<th className="pvtTotalLabel">
{colAttrs.length === 0 ? 'Totals' : null}
{colAttrs.length === 0 ? (!hideColTotals ? 'Totals' : null) : null}
</th>
</tr>
)}
</thead>

<tbody>
{rowKeys.map(function(rowKey, i) {
{rowKeys.map(function (rowKey, i) {
const totalAggregator = pivotData.getAggregator(rowKey, []);
return (
<tr key={`rowKeyRow${i}`}>
{rowKey.map(function(txt, j) {
{rowKey.map(function (txt, j) {
const x = spanSize(rowKeys, i, j);
if (x === -1) {
return null;
Expand All @@ -208,84 +182,84 @@ function makeRenderer(opts = {}) {
key={`rowKeyLabel${i}-${j}`}
className="pvtRowLabel"
rowSpan={x}
colSpan={
j === rowAttrs.length - 1 && colAttrs.length !== 0
? 2
: 1
}
colSpan={j === rowAttrs.length - 1 && colAttrs.length !== 0 ? 2 : 1}
>
{txt}
</th>
);
})}
{colKeys.map(function(colKey, j) {
{colKeys.map(function (colKey, j) {
const aggregator = pivotData.getAggregator(rowKey, colKey);
return (
<td
className="pvtVal"
key={`pvtVal${i}-${j}`}
onClick={
getClickHandler &&
getClickHandler(aggregator.value(), rowKey, colKey)
getClickHandler && getClickHandler(aggregator.value(), rowKey, colKey)
}
style={valueCellColors(
rowKey,
colKey,
aggregator.value()
)}
style={valueCellColors(rowKey, colKey, aggregator.value())}
>
{aggregator.format(aggregator.value())}
</td>
);
})}
<td
className="pvtTotal"
onClick={
getClickHandler &&
getClickHandler(totalAggregator.value(), rowKey, [null])
}
style={colTotalColors(totalAggregator.value())}
>
{totalAggregator.format(totalAggregator.value())}
</td>

{!hideRowTotals && (
<td
className="pvtTotal"
onClick={
getClickHandler && getClickHandler(totalAggregator.value(), rowKey, [null])
}
style={colTotalColors(totalAggregator.value())}
>
{totalAggregator.format(totalAggregator.value())}
</td>
)}
</tr>
);
})}

<tr>
<th
className="pvtTotalLabel"
colSpan={rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)}
>
Totals
</th>
{!hideColTotals && (
<th
className="pvtTotalLabel"
colSpan={rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)}
>
Totals
</th>
)}

{colKeys.map(function(colKey, i) {
{colKeys.map(function (colKey, i) {
const totalAggregator = pivotData.getAggregator([], colKey);
return (
<td
className="pvtTotal"
key={`total${i}`}
onClick={
getClickHandler &&
getClickHandler(totalAggregator.value(), [null], colKey)
}
style={rowTotalColors(totalAggregator.value())}
>
{totalAggregator.format(totalAggregator.value())}
</td>
);
})}

<td
onClick={
getClickHandler &&
getClickHandler(grandTotalAggregator.value(), [null], [null])
if (hideColTotals) {
return <></>;
} else {
return (
<td
className="pvtTotal"
key={`total${i}`}
onClick={
getClickHandler && getClickHandler(totalAggregator.value(), [null], colKey)
}
style={rowTotalColors(totalAggregator.value())}
>
{totalAggregator.format(totalAggregator.value())}
</td>
);
}
className="pvtGrandTotal"
>
{grandTotalAggregator.format(grandTotalAggregator.value())}
</td>
})}

{!hideRowTotals && !hideColTotals && (
<td
onClick={
getClickHandler && getClickHandler(grandTotalAggregator.value(), [null], [null])
}
className="pvtGrandTotal"
>
{grandTotalAggregator.format(grandTotalAggregator.value())}
</td>
)}
</tr>
</tbody>
</table>
Expand Down Expand Up @@ -314,16 +288,16 @@ class TSVExportRenderer extends React.PureComponent {
colKeys.push([]);
}

const headerRow = pivotData.props.rows.map(r => r);
const headerRow = pivotData.props.rows.map((r) => r);
if (colKeys.length === 1 && colKeys[0].length === 0) {
headerRow.push(this.props.aggregatorName);
} else {
colKeys.map(c => headerRow.push(c.join('-')));
colKeys.map((c) => headerRow.push(c.join('-')));
}

const result = rowKeys.map(r => {
const row = r.map(x => x);
colKeys.map(c => {
const result = rowKeys.map((r) => {
const row = r.map((x) => x);
colKeys.map((c) => {
const v = pivotData.getAggregator(r, c).value();
row.push(v ? v : '');
});
Expand All @@ -334,8 +308,8 @@ class TSVExportRenderer extends React.PureComponent {

return (
<textarea
value={result.map(r => r.join('\t')).join('\n')}
style={{width: window.innerWidth / 2, height: window.innerHeight / 2}}
value={result.map((r) => r.join('\t')).join('\n')}
style={{ width: window.innerWidth / 2, height: window.innerHeight / 2 }}
readOnly={true}
/>
);
Expand All @@ -347,8 +321,8 @@ TSVExportRenderer.propTypes = PivotData.propTypes;

export default {
Table: makeRenderer(),
'Table Heatmap': makeRenderer({heatmapMode: 'full'}),
'Table Col Heatmap': makeRenderer({heatmapMode: 'col'}),
'Table Row Heatmap': makeRenderer({heatmapMode: 'row'}),
'Exportable TSV': TSVExportRenderer,
'Table Heatmap': makeRenderer({ heatmapMode: 'full' }),
'Table Col Heatmap': makeRenderer({ heatmapMode: 'col' }),
'Table Row Heatmap': makeRenderer({ heatmapMode: 'row' }),
'Exportable TSV': TSVExportRenderer
};