Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
Allowing to not render cells outside of viewport
Browse files Browse the repository at this point in the history
  • Loading branch information
wlis committed Jun 2, 2015
1 parent afd9a4b commit 9936c5b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 54 deletions.
45 changes: 15 additions & 30 deletions src/FixedDataTableCell.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

var ImmutableObject = require('ImmutableObject');
var React = require('React');

var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
var cloneWithProps = require('cloneWithProps');
var cx = require('cx');
var joinClasses = require('joinClasses');
Expand All @@ -27,6 +27,7 @@ var DEFAULT_PROPS = new ImmutableObject({
});

var FixedDataTableCell = React.createClass({
mixins: [ReactComponentWithPureRenderMixin],

propTypes: {
align: PropTypes.oneOf(['left', 'center', 'right']),
Expand Down Expand Up @@ -80,7 +81,7 @@ var FixedDataTableCell = React.createClass({
* to initialize resizing. Please note this is only on the cells
* in the header.
* @param number combinedWidth
* @param number leftOffset
* @param number left
* @param number width
* @param number minWidth
* @param number maxWidth
Expand All @@ -89,37 +90,12 @@ var FixedDataTableCell = React.createClass({
*/
onColumnResize: PropTypes.func,

/**
* Width of the all the cells preceding this cell that
* are in its column group.
*/
widthOffset: PropTypes.number,

/**
* The left offset in pixels of the cell.
*/
left: PropTypes.number,
},

shouldComponentUpdate(/*object*/ nextProps) /*boolean*/ {
var props = this.props;
var key;
for (key in props) {
if (props[key] !== nextProps[key] &&
key !== 'left') {
return true;
}
}
for (key in nextProps) {
if (props[key] !== nextProps[key] &&
key !== 'left') {
return true;
}
}

return false;
},

getDefaultProps() /*object*/ {
return DEFAULT_PROPS;
},
Expand All @@ -128,8 +104,9 @@ var FixedDataTableCell = React.createClass({
var props = this.props;

var style = {
height: props.height,
left: props.left,
width: props.width,
height: props.height
};

var className = joinClasses(
Expand Down Expand Up @@ -190,10 +167,18 @@ var FixedDataTableCell = React.createClass({
</div>
);
}

var innerStyle = {
height: props.height,
width: props.width,
};

return (
<div className={className} style={style}>
{columnResizerComponent}
<div className={cx('public/fixedDataTableCell/wrap1')} style={style}>
<div
className={cx('public/fixedDataTableCell/wrap1')}
style={innerStyle}>
<div className={cx('public/fixedDataTableCell/wrap2')}>
<div className={cx('public/fixedDataTableCell/wrap3')}>
{content}
Expand All @@ -206,7 +191,7 @@ var FixedDataTableCell = React.createClass({

_onColumnResizerMouseDown(/*object*/ event) {
this.props.onColumnResize(
this.props.widthOffset,
this.props.left,
this.props.width,
this.props.minWidth,
this.props.maxWidth,
Expand Down
58 changes: 38 additions & 20 deletions src/FixedDataTableCellGroup.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,42 +45,52 @@ var FixedDataTableCellGroupImpl = React.createClass({
PropTypes.array
]),

left: PropTypes.number,

onColumnResize: PropTypes.func,

rowHeight: PropTypes.number.isRequired,

rowIndex: PropTypes.number.isRequired,

width: PropTypes.number.isRequired,

zIndex: PropTypes.number.isRequired,
},

render() /*object*/ {
var props = this.props;
var columns = props.columns;
var cells = [];
var width = 0;
var cells = new Array(columns.length);

var currentPosition = 0;
for (var i = 0, j = columns.length; i < j; i++) {
var columnProps = columns[i].props;
width += columnProps.width;
var key = 'cell_' + i;
cells.push(
this._renderCell(
if (!columnProps.allowCellsRecycling || (
currentPosition - props.left <= props.width &&
currentPosition - props.left + columnProps.width >= 0)) {
var key = 'cell_' + i;
cells[i] = this._renderCell(
props.data,
props.rowIndex,
props.rowHeight,
columnProps,
width,
currentPosition,
key
)
);
);
}
currentPosition += columnProps.width;
}

var contentWidth = this._getColumnsWidth(columns);

var style = {
width: width,
height: props.height,
zIndex: props.zIndex
position: 'absolute',
width: contentWidth,
zIndex: props.zIndex,
};
translateDOMPositionXY(style, -1 * props.left, 0);

return (
<div className={cx('fixedDataTableCellGroup/cellGroup')} style={style}>
Expand All @@ -94,7 +104,7 @@ var FixedDataTableCellGroupImpl = React.createClass({
/*number*/ rowIndex,
/*number*/ height,
/*object*/ columnProps,
/*?number*/ widthOffset,
/*number*/ left,
/*string*/ key
) /*object*/ {
var cellRenderer = columnProps.cellRenderer || renderToString;
Expand Down Expand Up @@ -135,10 +145,18 @@ var FixedDataTableCellGroupImpl = React.createClass({
rowData={rowData}
rowIndex={rowIndex}
width={columnProps.width}
widthOffset={widthOffset}
left={left}
/>
);
},

_getColumnsWidth(columns: array): number {
var width = 0;
for (var i = 0; i < columns.length; ++i) {
width += columns[i].props.width;
}
return width;
},
});

var FixedDataTableCellGroup = React.createClass({
Expand All @@ -150,7 +168,7 @@ var FixedDataTableCellGroup = React.createClass({
*/
height: PropTypes.number.isRequired,

left: PropTypes.number,
offsetLeft: PropTypes.number,

/**
* Z-index on which the row will be displayed. Used e.g. for keeping
Expand All @@ -160,14 +178,14 @@ var FixedDataTableCellGroup = React.createClass({
},

render() /*object*/ {
var {left, ...props} = this.props;
var {offsetLeft, ...props} = this.props;

var style = {
height: props.height,
};

if (left) {
translateDOMPositionXY(style, left, 0);
if (offsetLeft) {
translateDOMPositionXY(style, offsetLeft, 0);
}

var onColumnResize = props.onColumnResize ? this._onColumnResize : null;
Expand All @@ -185,16 +203,16 @@ var FixedDataTableCellGroup = React.createClass({
},

_onColumnResize(
/*number*/ widthOffset,
/*number*/ left,
/*number*/ width,
/*?number*/ minWidth,
/*?number*/ maxWidth,
/*string|number*/ cellDataKey,
/*object*/ event
) {
this.props.onColumnResize && this.props.onColumnResize(
widthOffset,
this.props.left,
this.props.offsetLeft,
left - this.props.left + width,
width,
minWidth,
maxWidth,
Expand Down
14 changes: 14 additions & 0 deletions src/FixedDataTableColumn.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,24 @@ var FixedDataTableColumn = React.createClass({
* has a flex grow, once you resize the column this will be set to 0.
*/
isResizable: PropTypes.bool,

/**
* Experimental feature
* Whether cells in this column can be removed from document when outside
* of viewport as a result of horizontal scrolling.
* Setting this property to true allows the table to not render cells in
* particular column that are outside of viewport for visible rows. This
* allows to create table with many columns and not have vertical scrolling
* performance drop.
* Setting the property to false will keep previous behaviour and keep
* cell rendered if the row it belongs to is visible.
*/
allowCellsRecycling: PropTypes.bool,
},

getDefaultProps() /*object*/ {
return {
allowCellsRecycling: false,
fixed: false,
};
},
Expand Down
7 changes: 5 additions & 2 deletions src/FixedDataTableRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,28 @@ var FixedDataTableRowImpl = React.createClass({
);
}

var fixedColumnsWidth = this._getColumnsWidth(this.props.fixedColumns);
var fixedColumns =
<FixedDataTableCellGroup
key="fixed_cells"
height={this.props.height}
left={0}
width={fixedColumnsWidth}
zIndex={2}
columns={this.props.fixedColumns}
data={this.props.data}
onColumnResize={this.props.onColumnResize}
rowHeight={this.props.height}
rowIndex={this.props.index}
/>;
var fixedColumnsWidth = this._getColumnsWidth(this.props.fixedColumns);
var columnsShadow = this._renderColumnsShadow(fixedColumnsWidth);
var scrollableColumns =
<FixedDataTableCellGroup
key="scrollable_cells"
height={this.props.height}
left={(fixedColumnsWidth - this.props.scrollLeft) * DIR_SIGN}
left={this.props.scrollLeft * DIR_SIGN}
offsetLeft={fixedColumnsWidth * DIR_SIGN}
width={this.props.width - fixedColumnsWidth}
zIndex={0}
columns={this.props.scrollableColumns}
data={this.props.data}
Expand Down
3 changes: 1 addition & 2 deletions src/css/fixedDataTableCell.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
box-sizing: border-box;
display: block;
overflow: hidden;
position: relative;
position: absolute;
white-space: normal;
}

Expand All @@ -38,7 +38,6 @@

.public/fixedDataTableCell/wrap1 {
display: table;
overflow: hidden;
}

.public/fixedDataTableCell/wrap2 {
Expand Down

0 comments on commit 9936c5b

Please sign in to comment.