aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx138
1 files changed, 72 insertions, 66 deletions
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index edf0ea4c7..b8f65cb7d 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,7 +1,6 @@
import { Button, Type } from 'browndash-components';
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { actionFieldDecorator } from 'mobx/lib/internal';
import * as React from 'react';
import { Doc, Field, NumListCast } from '../../../../../fields/Doc';
import { List } from '../../../../../fields/List';
@@ -32,18 +31,18 @@ interface TableBoxProps {
@observer
export class TableBox extends React.Component<TableBoxProps> {
- @observable startID: number = 0;
- @observable endID: number = 0;
- _tableContainerRef: HTMLDivElement | null = null;
- _tableRef = React.createRef<HTMLTableElement>();
-
_inputChangedDisposer?: IReactionDisposer;
+ _containerRef: HTMLDivElement | null = null;
+
+ @observable _scrollTop = -1;
+ @observable _tableHeight = 0;
+ @observable _tableContainerHeight = 0;
+
componentDidMount() {
// if the tableData changes (ie., when records are selected by the parent (input) visulization),
// then we need to remove any selected rows that are no longer part of the visualized dataset.
this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true });
-
- this._tableContainerRef && this.handleScroll();
+ this.handleScroll();
}
componentWillUnmount() {
this._inputChangedDisposer?.();
@@ -79,14 +78,17 @@ export class TableBox extends React.Component<TableBoxProps> {
return this.props.docView?.()?.props.ScreenToLocalTransform().Scale || 1;
}
@computed get rowHeight() {
- const tableHeight = this._tableRef.current?.getBoundingClientRect().height;
- return !tableHeight ? 1 : (this.viewScale * tableHeight) / this._tableDataIds.length;
+ return (this.viewScale * this._tableHeight) / this._tableDataIds.length;
+ }
+ @computed get startID() {
+ return this.rowHeight ? Math.floor(this._scrollTop / this.rowHeight) : 0;
+ }
+ @computed get endID() {
+ return Math.ceil(this.startID + (this._tableContainerHeight * this.viewScale) / (this.rowHeight || 1));
}
-
@action handleScroll = () => {
- if (this._tableContainerRef) {
- this.startID = Math.floor(this._tableContainerRef.scrollTop / this.rowHeight);
- this.endID = this.startID + (this._tableContainerRef.getBoundingClientRect().height * this.viewScale) / this.rowHeight;
+ if (!this.props.docView?.()?.ContentDiv?.hidden) {
+ this._scrollTop = this._containerRef?.scrollTop ?? 0;
}
};
@action
@@ -175,66 +177,70 @@ export class TableBox extends React.Component<TableBoxProps> {
className={`table-container ${this.columns[0]}`}
style={{ height: '100%', overflow: 'auto' }}
onScroll={this.handleScroll}
- ref={r => {
- this._tableContainerRef = r;
- r?.addEventListener(
- 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
- (e: WheelEvent) => {
- if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
- e.stopPropagation();
- },
- { passive: false }
- );
- }}>
- <table className="table" ref={this._tableRef}>
+ ref={action((r: HTMLDivElement | null) => {
+ this._containerRef = r;
+ if (!this.props.docView?.()?.ContentDiv?.hidden && r) {
+ this._tableContainerHeight = r.getBoundingClientRect().height ?? 0;
+ r.addEventListener(
+ 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
+ (e: WheelEvent) => {
+ if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
+ e.stopPropagation();
+ },
+ { passive: false }
+ );
+ }
+ })}>
+ <table
+ className="table"
+ ref={action((r: HTMLTableElement | null) => {
+ if (!this.props.docView?.()?.ContentDiv?.hidden && r) {
+ this._tableHeight = r?.getBoundingClientRect().height ?? 0;
+ }
+ })}>
+ <div style={{ height: this.startID * 40 }} />
<thead>
<tr>
- {this.columns.map(col =>
- this.startID > 0 ? null : (
- <th
- key={this.columns.indexOf(col)}
- style={{
- color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined,
- background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
- fontWeight: 'bolder',
- border: '3px solid black',
- }}
- onPointerDown={e => this.columnPointerDown(e, col)}>
- {col}
- </th>
- )
- )}
+ {this.columns.map(col => (
+ <th
+ key={this.columns.indexOf(col)}
+ style={{
+ color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined,
+ background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
+ fontWeight: 'bolder',
+ border: '3px solid black',
+ }}
+ onPointerDown={e => this.columnPointerDown(e, col)}>
+ {col}
+ </th>
+ ))}
</tr>
</thead>
<tbody>
{this._tableDataIds
+ .filter(rowId => this.startID <= rowId && rowId <= this.endID)
?.map(rowId => ({ record: this.props.records[rowId], rowId }))
- .map(({ record, rowId }) =>
- this.startID > rowId || rowId > this.endID ? (
- <tr>
- <td /> {/* empty row data for out-of-view items needed to give row the default row height so that scrolling works */}
- </tr>
- ) : (
- <tr
- key={rowId}
- className={`table-row ${this.columns[0]}`}
- onClick={e => this.tableRowClick(e, rowId)}
- style={{
- background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
- width: '110%',
- }}>
- {this.columns.map(col => {
- const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false;
- return (
- <td key={this.columns.indexOf(col)} style={{ border: colSelected ? '3px solid black' : '1px solid black', fontWeight: colSelected ? 'bolder' : 'normal' }}>
- <div style={{ textOverflow: 'ellipsis', width: '100%', whiteSpace: 'pre', maxWidth: 150, overflow: 'hidden' }}>{record[col]}</div>
- </td>
- );
- })}
- </tr>
- )
- )}
+ .map(({ record, rowId }) => (
+ <tr
+ key={rowId}
+ className={`table-row ${this.columns[0]}`}
+ onClick={e => this.tableRowClick(e, rowId)}
+ style={{
+ background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
+ width: '110%',
+ }}>
+ {this.columns.map(col => {
+ const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false;
+ return (
+ <td key={this.columns.indexOf(col)} style={{ border: colSelected ? '3px solid black' : '1px solid black', fontWeight: colSelected ? 'bolder' : 'normal' }}>
+ <div style={{ textOverflow: 'ellipsis', width: '100%', whiteSpace: 'pre', maxWidth: 150, overflow: 'hidden' }}>{record[col]}</div>
+ </td>
+ );
+ })}
+ </tr>
+ ))}
</tbody>
+ <div style={{ height: (this._tableDataIds.length - this.endID) * 40 }} />
</table>
</div>
</div>