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 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)}

View File

@ -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,

View File

@ -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}
</div>

View File

@ -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}
<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 {
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,
}