Use CSS content-visibility to improve rendering performance by hiding offscreen grid cells

This commit is contained in:
Andrew Kingston 2023-10-17 11:51:42 +01:00
parent 4e703fdfcc
commit c37538d611
5 changed files with 55 additions and 1 deletions

View File

@ -21,6 +21,7 @@
export let invertX = false export let invertX = false
export let invertY = false export let invertY = false
export let contentLines = 1 export let contentLines = 1
export let hidden = false
const emptyError = writable(null) const emptyError = writable(null)
@ -78,6 +79,7 @@
{focused} {focused}
{selectedUser} {selectedUser}
{readonly} {readonly}
{hidden}
error={$error} error={$error}
on:click={() => focusedCellId.set(cellId)} on:click={() => focusedCellId.set(cellId)}
on:contextmenu={e => menu.actions.open(cellId, e)} on:contextmenu={e => menu.actions.open(cellId, e)}

View File

@ -10,6 +10,7 @@
export let defaultHeight = false export let defaultHeight = false
export let center = false export let center = false
export let readonly = false export let readonly = false
export let hidden = false
$: style = getStyle(width, selectedUser) $: style = getStyle(width, selectedUser)
@ -30,6 +31,7 @@
class:error class:error
class:center class:center
class:readonly class:readonly
class:hidden
class:default-height={defaultHeight} class:default-height={defaultHeight}
class:selected-other={selectedUser != null} class:selected-other={selectedUser != null}
class:alt={rowIdx % 2 === 1} class:alt={rowIdx % 2 === 1}
@ -81,6 +83,9 @@
.cell.center { .cell.center {
align-items: center; align-items: center;
} }
.cell.hidden {
content-visibility: hidden;
}
/* Cell border */ /* Cell border */
.cell.focused:after, .cell.focused:after,

View File

@ -19,6 +19,7 @@
isDragging, isDragging,
dispatch, dispatch,
rows, rows,
columnRenderMap,
} = getContext("grid") } = getContext("grid")
$: rowSelected = !!$selectedRows[row._id] $: rowSelected = !!$selectedRows[row._id]
@ -51,6 +52,7 @@
selectedUser={$selectedCellMap[cellId]} selectedUser={$selectedCellMap[cellId]}
width={column.width} width={column.width}
contentLines={$contentLines} contentLines={$contentLines}
hidden={!$columnRenderMap[column.name]}
/> />
{/each} {/each}
</div> </div>

View File

@ -31,6 +31,7 @@
refreshing, refreshing,
config, config,
filter, filter,
columnRenderMap,
} = getContext("grid") } = getContext("grid")
let visible = false let visible = false
@ -224,6 +225,7 @@
topRow={offset === 0} topRow={offset === 0}
invertX={columnIdx >= $columnHorizontalInversionIndex} invertX={columnIdx >= $columnHorizontalInversionIndex}
{invertY} {invertY}
hidden={!$columnRenderMap[column.name]}
> >
{#if column?.schema?.autocolumn} {#if column?.schema?.autocolumn}
<div class="readonly-overlay">Can't edit auto column</div> <div class="readonly-overlay">Can't edit auto column</div>

View File

@ -1,7 +1,8 @@
import { derived } from "svelte/store" import { derived, get } from "svelte/store"
import { import {
MaxCellRenderHeight, MaxCellRenderHeight,
MaxCellRenderWidthOverflow, MaxCellRenderWidthOverflow,
MinColumnWidth,
ScrollBarSize, ScrollBarSize,
} from "../lib/constants" } 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 // Determine the row index at which we should start vertically inverting cell
// dropdowns // dropdowns
const rowVerticalInversionIndex = derived( const rowVerticalInversionIndex = derived(
@ -87,6 +129,7 @@ export const deriveStores = context => {
scrolledRowCount, scrolledRowCount,
visualRowCapacity, visualRowCapacity,
renderedRows, renderedRows,
columnRenderMap,
rowVerticalInversionIndex, rowVerticalInversionIndex,
columnHorizontalInversionIndex, columnHorizontalInversionIndex,
} }