From c37538d61125734a32aeb0a178843c61f5b63e25 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 17 Oct 2023 11:51:42 +0100 Subject: [PATCH] Use CSS content-visibility to improve rendering performance by hiding offscreen grid cells --- .../src/components/grid/cells/DataCell.svelte | 2 + .../src/components/grid/cells/GridCell.svelte | 5 +++ .../src/components/grid/layout/GridRow.svelte | 2 + .../src/components/grid/layout/NewRow.svelte | 2 + .../src/components/grid/stores/viewport.js | 45 ++++++++++++++++++- 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/cells/DataCell.svelte b/packages/frontend-core/src/components/grid/cells/DataCell.svelte index f9cdef3756..cdaf28978a 100644 --- a/packages/frontend-core/src/components/grid/cells/DataCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/DataCell.svelte @@ -21,6 +21,7 @@ export let invertX = false export let invertY = false export let contentLines = 1 + export let hidden = false const emptyError = writable(null) @@ -78,6 +79,7 @@ {focused} {selectedUser} {readonly} + {hidden} error={$error} on:click={() => focusedCellId.set(cellId)} on:contextmenu={e => menu.actions.open(cellId, e)} diff --git a/packages/frontend-core/src/components/grid/cells/GridCell.svelte b/packages/frontend-core/src/components/grid/cells/GridCell.svelte index fe4bd70ba4..dcc76b9c75 100644 --- a/packages/frontend-core/src/components/grid/cells/GridCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/GridCell.svelte @@ -10,6 +10,7 @@ export let defaultHeight = false export let center = false export let readonly = false + export let hidden = false $: style = getStyle(width, selectedUser) @@ -30,6 +31,7 @@ class:error class:center class:readonly + class:hidden class:default-height={defaultHeight} class:selected-other={selectedUser != null} class:alt={rowIdx % 2 === 1} @@ -81,6 +83,9 @@ .cell.center { align-items: center; } + .cell.hidden { + content-visibility: hidden; + } /* Cell border */ .cell.focused:after, diff --git a/packages/frontend-core/src/components/grid/layout/GridRow.svelte b/packages/frontend-core/src/components/grid/layout/GridRow.svelte index 93dc11f6ed..4a0db40ee8 100644 --- a/packages/frontend-core/src/components/grid/layout/GridRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/GridRow.svelte @@ -19,6 +19,7 @@ isDragging, dispatch, rows, + columnRenderMap, } = getContext("grid") $: rowSelected = !!$selectedRows[row._id] @@ -51,6 +52,7 @@ selectedUser={$selectedCellMap[cellId]} width={column.width} contentLines={$contentLines} + hidden={!$columnRenderMap[column.name]} /> {/each} diff --git a/packages/frontend-core/src/components/grid/layout/NewRow.svelte b/packages/frontend-core/src/components/grid/layout/NewRow.svelte index cc2d76f536..980f86326d 100644 --- a/packages/frontend-core/src/components/grid/layout/NewRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewRow.svelte @@ -31,6 +31,7 @@ refreshing, config, filter, + columnRenderMap, } = getContext("grid") let visible = false @@ -224,6 +225,7 @@ topRow={offset === 0} invertX={columnIdx >= $columnHorizontalInversionIndex} {invertY} + hidden={!$columnRenderMap[column.name]} > {#if column?.schema?.autocolumn}
Can't edit auto column
diff --git a/packages/frontend-core/src/components/grid/stores/viewport.js b/packages/frontend-core/src/components/grid/stores/viewport.js index 3a1b65e2b9..0890792989 100644 --- a/packages/frontend-core/src/components/grid/stores/viewport.js +++ b/packages/frontend-core/src/components/grid/stores/viewport.js @@ -1,7 +1,8 @@ -import { derived } from "svelte/store" +import { derived, get } from "svelte/store" import { MaxCellRenderHeight, MaxCellRenderWidthOverflow, + MinColumnWidth, ScrollBarSize, } from "../lib/constants" @@ -44,6 +45,47 @@ export const deriveStores = context => { [] ) + // Derive visible columns + const scrollLeftRounded = derived(scrollLeft, $scrollLeft => { + const interval = MinColumnWidth + return Math.round($scrollLeft / interval) * interval + }) + const columnRenderMap = derived( + [visibleColumns, scrollLeftRounded, width], + ([$visibleColumns, $scrollLeft, $width]) => { + if (!$visibleColumns.length) { + return {} + } + let startColIdx = 0 + let rightEdge = $visibleColumns[0].width + while ( + rightEdge < $scrollLeft && + startColIdx < $visibleColumns.length - 1 + ) { + startColIdx++ + rightEdge += $visibleColumns[startColIdx].width + } + let endColIdx = startColIdx + 1 + let leftEdge = rightEdge + while ( + leftEdge < $width + $scrollLeft && + endColIdx < $visibleColumns.length + ) { + leftEdge += $visibleColumns[endColIdx].width + endColIdx++ + } + + // Only update the store if different + let next = {} + $visibleColumns + .slice(Math.max(0, startColIdx), endColIdx) + .forEach(col => { + next[col.name] = true + }) + return next + } + ) + // Determine the row index at which we should start vertically inverting cell // dropdowns const rowVerticalInversionIndex = derived( @@ -87,6 +129,7 @@ export const deriveStores = context => { scrolledRowCount, visualRowCapacity, renderedRows, + columnRenderMap, rowVerticalInversionIndex, columnHorizontalInversionIndex, }