Skip to content

Commit

Permalink
add additional examples for performance testing, html tables (#677)
Browse files Browse the repository at this point in the history
* add additional examples for performance testing, html tables

* add row-utils

* add row-utils to index

* add vuu row generator
  • Loading branch information
heswell authored May 7, 2023
1 parent cbbdf9b commit 2c4a9b3
Show file tree
Hide file tree
Showing 28 changed files with 1,678 additions and 155 deletions.
1 change: 1 addition & 0 deletions vuu-ui/packages/vuu-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export * from "./nanoid";
export * from "./round-decimal";
export * from "./perf-utils";
export * from "./range-utils";
export * from "./row-utils";
export * from "./selection-utils";
export * from "./sort-utils";
export * from "./text-utils";
Expand Down
37 changes: 37 additions & 0 deletions vuu-ui/packages/vuu-utils/src/row-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DataSourceRow } from "@finos/vuu-data";
import { MutableRefObject } from "react";
import { metadataKeys } from "@finos/vuu-utils";

const { IDX } = metadataKeys;

export type RowOffsetFunc = (
row: DataSourceRow,
pctScrollTop?: number
) => number;
export type RowAtPositionFunc = (position: number) => number;

export type RowPositioning = [RowOffsetFunc, RowAtPositionFunc];

export const actualRowPositioning = (rowHeight: number): RowPositioning => [
(row) => row[IDX] * rowHeight,
(position) => Math.floor(position / rowHeight),
];

export const virtualRowPositioning = (
rowHeight: number,
additionalPixelsNeeded: number,
pctScrollTop: MutableRefObject<number>
): RowPositioning => [
(row) => {
const rowOffset = pctScrollTop.current * additionalPixelsNeeded;
return row[IDX] * rowHeight - rowOffset;
},
(position) => {
const rowOffset = pctScrollTop.current * additionalPixelsNeeded;
const result = Math.floor((position + rowOffset) / rowHeight);
console.log(
`get row at position ${position} = ${result} (scrollTop = ${pctScrollTop.current})`
);
return result;
},
];
175 changes: 158 additions & 17 deletions vuu-ui/showcase/src/examples/html/HtmlTable.examples.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { memo, useEffect } from "react";
import { TableElementWithSizers } from "./html-table-components";
import { ArrayProxy, VuuRowGenerator } from "../utils";

import "./HtmlTable.examples.css";
import { CSSProperties, HTMLAttributes, memo } from "react";
import {
DivElementWithSizers,
DivElementWithTranslate,
DivElementKeyedWithTranslate,
TableElementWithSizers,
DivElementKeyedWithTranslateInlineScrollbars,
} from "./html-table-components";
import { ArrayProxy, VuuColumnGenerator, VuuRowGenerator } from "../utils";

import { VuuRowDataItemType } from "@finos/vuu-protocol-types";
import { RowProps } from "@finos/vuu-table/src/TableRow";
const dataRowCount = 1000;
const columnCount = 10;

let displaySequence = 1;

const columns = VuuColumnGenerator(columnCount);

const data = new ArrayProxy<VuuRowDataItemType[]>(
dataRowCount,
VuuRowGenerator(columnCount)
Expand All @@ -23,33 +31,92 @@ const visibleRowCount = 20;
export type ComponentTypeNoChildren<T = unknown> = (props: T) => JSX.Element;
export type RowType = ComponentTypeNoChildren<RowProps>;
export type HtmlRowProps = {
cellWidth?: number;
className?: string;
data: VuuRowDataItemType[];
offset?: number;
style?: CSSProperties;
};

const makeCells = (
data: unknown[],
Element: "td" | "div" = "td",
attributes?: HTMLAttributes<HTMLElement>
) => {
const cells = [];
for (let i = 0; i < data.length; i++) {
if (i > 0) {
cells.push(
<Element key={i} {...attributes}>
{data[i]}
</Element>
);
}
}
return cells;
};

const Row = memo(({ data }: HtmlRowProps) => {
useEffect(() => {
console.log("row mounted");
return () => {
console.log("row unmounted");
};
}, []);
const Row = memo(({ className, data }: HtmlRowProps) => {
// useEffect(() => {
// console.log("row mounted");
// return () => {
// console.log("row unmounted");
// };
// }, []);

return (
<tr key={`row-${data[0]}`}>
{data.map((item, i) => (
<td key={i}>{item}</td>
))}
<tr key={`row-${data[0]}`} className={className}>
{makeCells(data)}
</tr>
);
});
Row.displayName = "Row";

export const Table = () => {
const DivRow = memo(
({
cellWidth = 145,
className,
data,
offset,
...htmlAttributes
}: HtmlRowProps) => {
// useEffect(() => {
// console.log("row mounted");
// return () => {
// console.log("row unmounted");
// };
// }, []);

const style =
typeof offset === "number"
? { transform: `translate3d(0px, ${offset}px, 0px)` }
: undefined;

return (
<div
{...htmlAttributes}
key={`row-${data[0]}`}
role="row"
className={className}
style={style}
>
{makeCells(data, "div", {
role: "cell",
style: { width: cellWidth },
})}
</div>
);
}
);
DivRow.displayName = "Row";

export const DefaultTableElementWithSizers = () => {
const contentHeight = data.length * rowHeight;

return (
<TableElementWithSizers
bufferCount={bufferCount}
columns={columns}
contentHeight={contentHeight}
data={data}
headerHeight={headerHeight}
Expand All @@ -59,3 +126,77 @@ export const Table = () => {
/>
);
};
DefaultTableElementWithSizers.displaySequence = displaySequence++;

export const DefaultDivElementWithSizers = () => {
const contentHeight = data.length * rowHeight;

return (
<DivElementWithSizers
bufferCount={bufferCount}
columns={columns}
contentHeight={contentHeight}
data={data}
headerHeight={headerHeight}
Row={DivRow}
viewportHeight={viewportHeight}
visibleRowCount={visibleRowCount}
/>
);
};
DefaultDivElementWithSizers.displaySequence = displaySequence++;

export const DefaultDivElementWithTranslate = () => {
const contentHeight = data.length * rowHeight;

return (
<DivElementWithTranslate
bufferCount={bufferCount}
columns={columns}
contentHeight={contentHeight}
data={data}
headerHeight={headerHeight}
Row={DivRow}
viewportHeight={viewportHeight}
visibleRowCount={visibleRowCount}
/>
);
};
DefaultDivElementWithTranslate.displaySequence = displaySequence++;

export const DefaultDivElementKeyedWithTranslate = () => {
const contentHeight = data.length * rowHeight;

return (
<DivElementKeyedWithTranslate
bufferCount={bufferCount}
columns={columns}
contentHeight={contentHeight}
data={data}
headerHeight={headerHeight}
Row={DivRow}
viewportHeight={viewportHeight}
visibleRowCount={visibleRowCount}
/>
);
};
DefaultDivElementKeyedWithTranslate.displaySequence = displaySequence++;

export const DefaultDivElementKeyedWithTranslateInlineScrollbars = () => {
const contentHeight = data.length * rowHeight;

return (
<DivElementKeyedWithTranslateInlineScrollbars
bufferCount={bufferCount}
columns={columns}
contentHeight={contentHeight}
data={data}
headerHeight={headerHeight}
Row={DivRow}
viewportHeight={viewportHeight}
visibleRowCount={visibleRowCount}
/>
);
};
DefaultDivElementKeyedWithTranslateInlineScrollbars.displaySequence =
displaySequence++;
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
.DivElementKeyedWithTranslateInlineScrollbars {
position: absolute;
left: 95px;
top: 45px;
width: 715px;
height: 645px;
background-color: red;
position: relative;
}

.DivElementKeyedWithTranslateInlineScrollbars-scrollbarContainer {
--scroll-content-width: 1100px;
border-bottom: none !important;
border-top: none !important;
border-left: solid 1px var(--salt-container-primary-borderColor);
/* a top border */
box-shadow: 0px -1px 0px 0px var(--salt-container-primary-borderColor);
height: 615px;
left: 0px;
overflow: auto;
position: absolute;
top: 30px;
width: calc(715px + 1px);
}

.DivElementKeyedWithTranslateInlineScrollbars-scrollbarContent {
height: calc(30000px + 15px);
position: absolute;
width: 1150px;
}

.DivElementKeyedWithTranslateInlineScrollbars-contentContainer {
--vuuTableHeaderHeight: 30px;
background-color: var(--salt-container-primary-background);
height: calc(645px - 15px);
position: relative;
overflow: auto;
overscroll-behavior: none;
width: calc(715px - 15px);
}

.DivElementKeyedWithTranslateInlineScrollbars-contentContainer::-webkit-scrollbar {
display: none;
}


.DivElementKeyedWithTranslateInlineScrollbars-table {
position: absolute;
top: 0;
left: 0;
table-layout: fixed;
width: 1100px;
margin: 0;
border: none;
background-color: #fff;
border-collapse: separate;
border-spacing: 0;
border-left: 1px solid #ccc;

}

.DivElementKeyedWithTranslateInlineScrollbars-table [role="cell"] {
display: inline-block;
}

.DivElementKeyedWithTranslateInlineScrollbars-col-headings {
position: sticky;
top: 0;
/* ensure header row sits atop everything else when scrolling down */
z-index: 1;
}

.DivElementKeyedWithTranslateInlineScrollbars-col-headers {
white-space: nowrap;
}

.DivElementKeyedWithTranslateInlineScrollbars-col-header {
border-bottom: 1px solid #ccc;
box-sizing: border-box;
line-height: 29px;
background: #777;
border-right: 1px solid #999;
color: #fff;
padding: 0 3px;
}

.DivElementKeyedWithTranslateInlineScrollbarsRow {
background: #fff;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
box-sizing: border-box;
height: 30px;
line-height: 29px;
position: absolute;
top:0;
white-space: nowrap;
}

/* make first column sticky when scrolling right */
.DivElementKeyedWithTranslateInlineScrollbars-table [role="cell"]:first-child {
position: sticky;
left: 0;
border-right-color: #aaa;
background-color: white;
}

/* ensure first header cell sits atop everything else when scrolling right */
.DivElementKeyedWithTranslateInlineScrollbars-table .DivElementKeyedWithTranslateInlineScrollbars-col-header:first-child {
background-color: #777;
position: sticky;
left: 0;
z-index: 2;
}

.sizer-cell {
background-color: green !important;
border: none !important;
height: 0px;
}

Loading

0 comments on commit 2c4a9b3

Please sign in to comment.