Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Issue 649 - Fix mismatched row height for fixed columns #722

Merged
merged 50 commits into from
Apr 14, 2020

Conversation

Marc-Andre-Rivet
Copy link
Contributor

@Marc-Andre-Rivet Marc-Andre-Rivet commented Mar 17, 2020

Closes #649

This PR proposes to fix the misaligned rows issue by adding invisible cells in both the fixed columns and unfixed columns sections of the table. With some tweaks, this allows both fixed and unfixed cells to calculate their size based on the entire table's content, making sure that both size have the same size/height.

Afterwards the fixed rows can be coerced into having the correct width. With some extra tweaks for Firefox.

Percy browser versions have been updated for both dash-table and dash-table-python-v0 in order for the snapshots to match local behavior.

A lot of the changes in the PR is fixing the test logic to handle the added phantom-cell.


Current implementation slows down rendering for fixed table significantly (about 2.5x slower) but is significantly better than previous attempts (about 10-20x slower). Still investigating what can be done to reduce the overhead.

Possible secondary strategies:

  • Changing the default page_size from 250 to 100 would provide significant performance mitigation for default usage while not impacting usability significantly.

@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 16:19 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 16:36 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 17:19 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 18:05 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 18:18 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 18:28 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 18:46 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 19:56 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 20:26 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 21:06 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 21:56 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 17, 2020 22:56 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 18, 2020 01:30 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 18, 2020 01:52 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 18, 2020 15:50 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 18, 2020 19:43 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 18, 2020 21:07 Inactive
@chriddyp chriddyp temporarily deployed to dash-table-review-pr-722 March 19, 2020 00:29 Inactive
'console.log("logging things")',
'console.warn("this is a markdown cell")'
]
),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the mock to have variable height Markdown rows

@@ -48,6 +48,9 @@ const INNER_STYLE = {
minWidth: '100%'
};

const WIDTH_EPSILON = 0.5;
const MAX_WIDTH_ITERATIONS = 30;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

30 is a very high number but most of the time it takes 2-6 iterations for the table's column width to settle.

@@ -146,7 +149,7 @@ export default class ControlledTable extends PureComponent<ControlledTableProps>

componentDidUpdate() {
this.updateStylesheet();
this.applyStyle();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyStyle is removed / replaced by new code to handle the fixed rows

r0c1.style.marginLeft = `-${width2}`;
r0c1.style.marginRight = `${width2}`;
r1c1.style.marginLeft = `-${width2}`;
r1c1.style.marginRight = `${width2}`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are fixed columns, align the cell's table in such a way as to make the first visible column left-aligned with the cell.

@@ -718,7 +700,10 @@ export default class ControlledTable extends PureComponent<ControlledTableProps>
const { r0c1 } = this.refs as { [key: string]: HTMLElement };

Logger.trace(`ControlledTable fragment scrolled to (left,top)=(${ev.target.scrollLeft},${ev.target.scrollTop})`);
r0c1.style.marginLeft = `${-ev.target.scrollLeft}px`;

const margin = parseFloat(ev.target.scrollLeft) + parseFloat(getComputedStyle(r0c1).marginRight);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

margin-left and margin-right match in dimension, if not sign. Scroll adds to the initial offset.

columnId,
isValid,
style,
value
} = this.props;

return (<th
className={classes + (isValid ? '' : ' invalid')}
className={className + (isValid ? '' : ' invalid')}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Standardizing prop name across all components simplifies manipulation elsewhere.

color: graytext
}
}
display: inline-block;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation here was all weirded out - fixed. Lots of noise.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like some got fixed and some other parts got mucked up. Mostly lines 507+ but there are a few before that that look weird as well. Is there an auto-formatter for .less?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OIC you have some hard tabs mixed in with spaces here - this file looks funny in #728 as well as a result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll double check to make sure this file has been cleaned up.. but yes, at some point it became a mix of tabs/spaces

const getFirstPhantom = (cell: JSX.Element) => React.cloneElement(cell, {
...cell.props,
style: { ...cell.props.style, borderLeft: 'transparent' }
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various component cloning / manipulations.

getHiddenCell makes a phantom version of a cell - will be invisible
getFirstPhantom solves a doubled border issue

@@ -25,27 +25,35 @@ export class DashTableHelper {
}

public getCell(row: number, column: number, editable: State = State.Ready) {
return cy.get(`#${this.id} ${getSelector(editable)} tbody tr td.column-${column}`).eq(row);
return cy.get(`#${this.id} ${getSelector(editable)} tbody tr td.column-${column}:not(.phantom-cell)`).eq(row);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update test helper to ignore phantom cells

]}
columns={columnFormats}
/>))
const variants: ITest[] = [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Markdown visual tests with both fixed an no fixed columns

style_data_conditional={[{
if: { column_id: 'Region' },
whiteSpace: 'normal'
}]}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the standard prop to do this


Array.from<HTMLElement>(
r0c1.querySelectorAll('table.cell-table > tbody > tr:last-of-type > *')
).forEach((c, i) => this.setCellWidth(c, r1c1CellWidths[i]));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this replaces and adds to the previous applyStyle method

@Marc-Andre-Rivet Marc-Andre-Rivet changed the title Fix mismatched row height for fixed columns Issue 649 - Fix mismatched row height for fixed columns Apr 6, 2020
) {
break;
}
} while (true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal, but given that ultimately there's a known limit (MAX_WIDTH_ITERATIONS) I'd have probably written this as a for loop, with only the width test down here breaking the loop early.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to keep both exit conditions together, that's why I opted for a while instead of a for loop. Did some clean up so the exit condition is now in the while condition instead of the body. 207c90a

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also removed the it % 2 == 0 check which is no longer necessary

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, makes sense. Glad the it % 2 === 0 can be avoided!

@@ -1,6 +1,7 @@
import * as R from 'ramda';
import React from 'react';
import { memoizeOneFactory } from 'core/memoizer';
import isNil from 'ramda/es/isNil';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just the one in import * as R from 'ramda'; above? In fact you use both copies...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird.. fixed with 33db6f3

},
{ cells: 0, count: 0 },
row as any
).cells;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌴const pivot = ... looks identical to above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌴 3d0b8c8

Copy link
Collaborator

@alexcjohnson alexcjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just a few small comments, then this is ready to go! 💃

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using DataTable row_selectable and row_deletable with fixed columns results in mismatched row heights
3 participants