Clean up more sheet state and increase performance
This commit is contained in:
parent
fae24276f9
commit
efca3eef4f
|
@ -2,7 +2,7 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
const { columns, rand, visibleColumns } = getContext("spreadsheet")
|
const { columns, rand, scroll, visibleColumns } = getContext("spreadsheet")
|
||||||
const MinColumnWidth = 100
|
const MinColumnWidth = 100
|
||||||
|
|
||||||
let initialMouseX = null
|
let initialMouseX = null
|
||||||
|
@ -48,56 +48,7 @@
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
// let newStyle = `--col-${columnIdx}-width:${newWidth}px;`
|
|
||||||
//
|
|
||||||
// let offset = left + newWidth
|
|
||||||
// for (let i = columnIdx + 1; i < columnCount; i++) {
|
|
||||||
// const colWidth = parseInt(styles.getPropertyValue(`--col-${i}-width`))
|
|
||||||
// newStyle += `--col-${i}-left:${offset}px;`
|
|
||||||
// offset += colWidth
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// sheet.style.cssText += newStyle
|
|
||||||
|
|
||||||
// let cells = sheet.querySelectorAll(`[data-col="${columnIdx}"]`)
|
|
||||||
// let left
|
|
||||||
// cells.forEach(cell => {
|
|
||||||
// cell.style.width = `${newWidth}px`
|
|
||||||
// cell.dataset.width = newWidth
|
|
||||||
// if (!left) {
|
|
||||||
// left = parseInt(cell.dataset.left)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// let offset = left + newWidth
|
|
||||||
// for (let i = columnIdx + 1; i < columnCount; i++) {
|
|
||||||
// cells = sheet.querySelectorAll(`[data-col="${i}"]`)
|
|
||||||
// let colWidth
|
|
||||||
// cells.forEach(cell => {
|
|
||||||
// cell.style.transform = `translateX(${offset}px)`
|
|
||||||
// cell.dataset.left = offset
|
|
||||||
// if (!colWidth) {
|
|
||||||
// colWidth = parseInt(cell.dataset.width)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// offset += colWidth
|
|
||||||
// }
|
|
||||||
|
|
||||||
width = newWidth
|
width = newWidth
|
||||||
|
|
||||||
// Update width of column
|
|
||||||
// columns.update(state => {
|
|
||||||
// state[$resize.columnIdx].width = Math.round(newWidth)
|
|
||||||
//
|
|
||||||
// // Update left offset of other columns
|
|
||||||
// let offset = 40
|
|
||||||
// state.forEach(col => {
|
|
||||||
// col.left = offset
|
|
||||||
// offset += col.width
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// return state
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopResizing = () => {
|
const stopResizing = () => {
|
||||||
|
@ -108,12 +59,14 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each $columns as col}
|
{#each $visibleColumns as col}
|
||||||
<div
|
<div
|
||||||
class="resize-slider"
|
class="resize-slider"
|
||||||
class:visible={columnIdx === col.idx}
|
class:visible={columnIdx === col.idx}
|
||||||
on:mousedown={e => startResizing(col.idx, e)}
|
on:mousedown={e => startResizing(col.idx, e)}
|
||||||
style="--left:{col.left + col.width}px;"
|
style="--left:{col.left +
|
||||||
|
col.width -
|
||||||
|
(col.idx === 0 ? 0 : $scroll.left)}px;"
|
||||||
>
|
>
|
||||||
<div class="resize-indicator" />
|
<div class="resize-indicator" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import { LuceneUtils } from "../../utils"
|
import { LuceneUtils } from "../../utils"
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon } from "@budibase/bbui"
|
||||||
import { createReorderStores } from "./stores/reorder"
|
import { createReorderStores } from "./stores/reorder"
|
||||||
|
import { createViewportStores } from "./stores/viewport"
|
||||||
import SpreadsheetHeader from "./SheetHeader.svelte"
|
import SpreadsheetHeader from "./SheetHeader.svelte"
|
||||||
import SpreadsheetBody from "./SheetBody.svelte"
|
import SpreadsheetBody from "./SheetBody.svelte"
|
||||||
import SpreadsheetCell from "./SheetCell.svelte"
|
import SpreadsheetCell from "./SheetCell.svelte"
|
||||||
|
@ -31,8 +32,6 @@
|
||||||
const selectedRows = writable({})
|
const selectedRows = writable({})
|
||||||
const changeCache = writable({})
|
const changeCache = writable({})
|
||||||
const newRows = writable([])
|
const newRows = writable([])
|
||||||
const visibleRows = writable([0, 0])
|
|
||||||
const visibleColumns = writable([0, 0])
|
|
||||||
const scroll = writable({
|
const scroll = writable({
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
|
@ -57,12 +56,11 @@
|
||||||
changeCache,
|
changeCache,
|
||||||
newRows,
|
newRows,
|
||||||
cellHeight,
|
cellHeight,
|
||||||
visibleRows,
|
|
||||||
visibleColumns,
|
|
||||||
bounds,
|
bounds,
|
||||||
scroll,
|
scroll,
|
||||||
}
|
}
|
||||||
const { reorder, reorderPlaceholder } = createReorderStores(context)
|
const { reorder, reorderPlaceholder } = createReorderStores(context)
|
||||||
|
const { visibleRows, visibleColumns } = createViewportStores(context)
|
||||||
|
|
||||||
$: query = LuceneUtils.buildLuceneQuery(filter)
|
$: query = LuceneUtils.buildLuceneQuery(filter)
|
||||||
$: fetch = createFetch(tableId)
|
$: fetch = createFetch(tableId)
|
||||||
|
@ -76,7 +74,6 @@
|
||||||
$: rowCount = $rows.length
|
$: rowCount = $rows.length
|
||||||
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
|
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
|
||||||
$: updateSortedRows($fetch, $newRows)
|
$: updateSortedRows($fetch, $newRows)
|
||||||
$: renderedRows = $rows.slice($visibleRows[0], $visibleRows[1])
|
|
||||||
|
|
||||||
const createFetch = tableId => {
|
const createFetch = tableId => {
|
||||||
return fetchData({
|
return fetchData({
|
||||||
|
@ -192,7 +189,7 @@
|
||||||
const bIndex = newRows.indexOf(b._id)
|
const bIndex = newRows.indexOf(b._id)
|
||||||
return aIndex < bIndex ? -1 : 1
|
return aIndex < bIndex ? -1 : 1
|
||||||
})
|
})
|
||||||
$rows = sortedRows
|
$rows = sortedRows.map((x, idx) => ({ ...x, __idx: idx }))
|
||||||
}
|
}
|
||||||
|
|
||||||
// API for children to consume
|
// API for children to consume
|
||||||
|
@ -206,6 +203,8 @@
|
||||||
...context,
|
...context,
|
||||||
reorder,
|
reorder,
|
||||||
reorderPlaceholder,
|
reorderPlaceholder,
|
||||||
|
visibleRows,
|
||||||
|
visibleColumns,
|
||||||
spreadsheetAPI,
|
spreadsheetAPI,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -221,31 +220,31 @@
|
||||||
checked={rowCount && selectedRowCount === rowCount}
|
checked={rowCount && selectedRowCount === rowCount}
|
||||||
/>
|
/>
|
||||||
</SpreadsheetCell>
|
</SpreadsheetCell>
|
||||||
{#each $columns as field, fieldIdx}
|
{#each $visibleColumns as column}
|
||||||
<SpreadsheetCell
|
<SpreadsheetCell
|
||||||
header
|
header
|
||||||
sticky={fieldIdx === 0}
|
sticky={column.idx === 0}
|
||||||
reorderSource={$reorder.columnIdx === fieldIdx}
|
reorderSource={$reorder.columnIdx === column.idx}
|
||||||
reorderTarget={$reorder.swapColumnIdx === fieldIdx}
|
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
||||||
on:mousedown={e => reorder.actions.startReordering(fieldIdx, e)}
|
on:mousedown={e => reorder.actions.startReordering(column.idx, e)}
|
||||||
width={field.width}
|
width={column.width}
|
||||||
left={field.left}
|
left={column.left}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
size="S"
|
size="S"
|
||||||
name={getIconForField(field)}
|
name={getIconForField(column)}
|
||||||
color="var(--spectrum-global-color-gray-600)"
|
color="var(--spectrum-global-color-gray-600)"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
{field.name}
|
{column.name}
|
||||||
</span>
|
</span>
|
||||||
</SpreadsheetCell>
|
</SpreadsheetCell>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- All real rows -->
|
<!-- All real rows -->
|
||||||
{#each renderedRows as row, rowIdx (row._id)}
|
{#each $visibleRows as row (row._id)}
|
||||||
<SpreadsheetRow {row} rowIdx={rowIdx + $visibleRows[0]} />
|
<SpreadsheetRow {row} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- New row placeholder -->
|
<!-- New row placeholder -->
|
||||||
|
@ -260,16 +259,16 @@
|
||||||
>
|
>
|
||||||
<Icon hoverable name="Add" size="S" />
|
<Icon hoverable name="Add" size="S" />
|
||||||
</SpreadsheetCell>
|
</SpreadsheetCell>
|
||||||
{#each $columns as field, fieldIdx}
|
{#each $visibleColumns as column}
|
||||||
<SpreadsheetCell
|
<SpreadsheetCell
|
||||||
sticky={fieldIdx === 0}
|
sticky={column.idx === 0}
|
||||||
rowHovered={$hoveredRowId === "new"}
|
rowHovered={$hoveredRowId === "new"}
|
||||||
reorderSource={$reorder.columnIdx === fieldIdx}
|
reorderSource={$reorder.columnIdx === column.idx}
|
||||||
reorderTarget={$reorder.swapColumnIdx === fieldIdx}
|
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
||||||
on:click={() => addRow(field)}
|
on:click={() => addRow(column)}
|
||||||
on:mouseenter={() => ($hoveredRowId = "new")}
|
on:mouseenter={() => ($hoveredRowId = "new")}
|
||||||
width={field.width}
|
width={column.width}
|
||||||
left={field.left}
|
left={column.left}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,104 +2,30 @@
|
||||||
import { getContext, onMount } from "svelte"
|
import { getContext, onMount } from "svelte"
|
||||||
import { Utils } from "../../utils"
|
import { Utils } from "../../utils"
|
||||||
|
|
||||||
const {
|
const { columns, selectedCellId, rand, cellHeight, rows, bounds, scroll } =
|
||||||
columns,
|
getContext("spreadsheet")
|
||||||
selectedCellId,
|
|
||||||
rand,
|
|
||||||
visibleRows,
|
|
||||||
visibleColumns,
|
|
||||||
cellHeight,
|
|
||||||
rows,
|
|
||||||
bounds,
|
|
||||||
scroll,
|
|
||||||
} = getContext("spreadsheet")
|
|
||||||
|
|
||||||
const padding = 180
|
const padding = 180
|
||||||
|
|
||||||
let ref
|
let ref
|
||||||
let scrollLeft = 0
|
|
||||||
let scrollTop = 0
|
|
||||||
|
|
||||||
$: updateVisibleRows($columns, scrollTop, $bounds.height)
|
$: contentHeight = ($rows.length + 2) * cellHeight
|
||||||
$: updateVisibleColumns($columns, scrollLeft, $bounds.width)
|
|
||||||
$: contentHeight = ($rows.length + 2) * cellHeight + padding
|
|
||||||
$: contentWidth = computeContentWidth($columns)
|
$: contentWidth = computeContentWidth($columns)
|
||||||
$: horizontallyScrolled = scrollLeft > 0
|
|
||||||
|
|
||||||
const computeContentWidth = columns => {
|
const computeContentWidth = columns => {
|
||||||
let total = 40 + padding
|
if (!columns.length) {
|
||||||
columns.forEach(col => {
|
return 0
|
||||||
total += col.width
|
}
|
||||||
})
|
const last = columns[columns.length - 1]
|
||||||
return total
|
return last.left + last.width
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the current scroll position
|
const updateScrollStore = Utils.domDebounce((left, top) => {
|
||||||
// let lastTop
|
scroll.set({ left, top })
|
||||||
// let lastLeft
|
})
|
||||||
// let ticking = false
|
|
||||||
// const handleScroll = e => {
|
|
||||||
// lastTop = e.target.scrollTop
|
|
||||||
// lastLeft = e.target.scrollLeft
|
|
||||||
// if (!ticking) {
|
|
||||||
// ticking = true
|
|
||||||
// requestAnimationFrame(() => {
|
|
||||||
// if (Math.abs(lastTop - scrollTop) > 100) {
|
|
||||||
// scrollTop = lastTop
|
|
||||||
// }
|
|
||||||
// if (lastLeft === 0 || Math.abs(lastLeft - scrollLeft) > 100) {
|
|
||||||
// scrollLeft = lastLeft
|
|
||||||
// }
|
|
||||||
// ticking = false
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
const handleScroll = Utils.domDebounce(
|
const handleScroll = e => {
|
||||||
({ left, top }) => {
|
updateScrollStore(e.target.scrollLeft, e.target.scrollTop)
|
||||||
// Only update local state when big changes occur
|
|
||||||
if (Math.abs(top - scrollTop) > 100) {
|
|
||||||
scrollTop = top
|
|
||||||
}
|
|
||||||
if (left === 0 || Math.abs(left - scrollLeft) > 100) {
|
|
||||||
scrollLeft = left
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always update store
|
|
||||||
scroll.set({ left, top })
|
|
||||||
},
|
|
||||||
e => ({ left: e.target.scrollLeft, top: e.target.scrollTop })
|
|
||||||
)
|
|
||||||
|
|
||||||
const updateVisibleRows = (columns, scrollTop, height) => {
|
|
||||||
if (!columns.length) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Compute row visibility
|
|
||||||
const rows = Math.ceil(height / cellHeight) + 8
|
|
||||||
const firstRow = Math.max(0, Math.floor(scrollTop / cellHeight) - 4)
|
|
||||||
visibleRows.set([firstRow, firstRow + rows])
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateVisibleColumns = (columns, scrollLeft, width) => {
|
|
||||||
if (!columns.length) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute column visibility
|
|
||||||
let startColIdx = 1
|
|
||||||
let rightEdge = columns[1].width
|
|
||||||
while (rightEdge < scrollLeft) {
|
|
||||||
startColIdx++
|
|
||||||
rightEdge += columns[startColIdx].width
|
|
||||||
}
|
|
||||||
let endColIdx = startColIdx + 1
|
|
||||||
let leftEdge = columns[0].width + 40 + rightEdge
|
|
||||||
while (leftEdge < width + scrollLeft) {
|
|
||||||
leftEdge += columns[endColIdx]?.width
|
|
||||||
endColIdx++
|
|
||||||
}
|
|
||||||
visibleColumns.set([Math.max(1, startColIdx - 2), endColIdx + 2])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -117,16 +43,22 @@
|
||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
class="sheet-body"
|
class="sheet-body"
|
||||||
class:horizontally-scrolled={horizontallyScrolled}
|
class:horizontally-scrolled={$scroll.left > 0}
|
||||||
on:click|self={() => ($selectedCellId = null)}
|
on:click|self={() => ($selectedCellId = null)}
|
||||||
id={`sheet-${rand}-body`}
|
id={`sheet-${rand}-body`}
|
||||||
on:scroll={handleScroll}
|
on:scroll={handleScroll}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="content"
|
class="content"
|
||||||
style="height:{contentHeight}px; width:{contentWidth}px;"
|
style="height:{contentHeight + padding}px; width:{contentWidth +
|
||||||
|
padding}px;"
|
||||||
>
|
>
|
||||||
<slot />
|
<div
|
||||||
|
class="data-content"
|
||||||
|
style="height:{contentHeight}px; width:{contentWidth}px;"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -140,11 +72,19 @@
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
.sheet-body::-webkit-scrollbar-track {
|
.sheet-body::-webkit-scrollbar-track {
|
||||||
background: var(--cell-background);
|
background: transparent;
|
||||||
|
}
|
||||||
|
.content,
|
||||||
|
.data-content {
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
background: var(--background-alt);
|
||||||
|
}
|
||||||
|
.data-content {
|
||||||
|
background: var(--cell-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add shadow to sticky cells when horizontally scrolled */
|
/* Add shadow to sticky cells when horizontally scrolled */
|
||||||
|
|
|
@ -9,13 +9,11 @@
|
||||||
import TextCell from "./cells/TextCell.svelte"
|
import TextCell from "./cells/TextCell.svelte"
|
||||||
|
|
||||||
export let row
|
export let row
|
||||||
export let rowIdx
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
selectedCellId,
|
selectedCellId,
|
||||||
reorder,
|
reorder,
|
||||||
hoveredRowId,
|
hoveredRowId,
|
||||||
columns,
|
|
||||||
selectedRows,
|
selectedRows,
|
||||||
changeCache,
|
changeCache,
|
||||||
spreadsheetAPI,
|
spreadsheetAPI,
|
||||||
|
@ -26,10 +24,6 @@
|
||||||
$: rowSelected = !!$selectedRows[row._id]
|
$: rowSelected = !!$selectedRows[row._id]
|
||||||
$: rowHovered = $hoveredRowId === row._id
|
$: rowHovered = $hoveredRowId === row._id
|
||||||
$: data = { ...row, ...$changeCache[row._id] }
|
$: data = { ...row, ...$changeCache[row._id] }
|
||||||
$: renderedColumns = [
|
|
||||||
$columns[0],
|
|
||||||
...$columns.slice($visibleColumns[0], $visibleColumns[1]),
|
|
||||||
]
|
|
||||||
$: containsSelectedCell = $selectedCellId?.split("-")[0] === row._id
|
$: containsSelectedCell = $selectedCellId?.split("-")[0] === row._id
|
||||||
|
|
||||||
const getCellForField = field => {
|
const getCellForField = field => {
|
||||||
|
@ -58,7 +52,7 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="row"
|
class="row"
|
||||||
style="--top:{(rowIdx + 1) * cellHeight}px;"
|
style="--top:{(row.__idx + 1) * cellHeight}px;"
|
||||||
class:contains-selected-cell={containsSelectedCell}
|
class:contains-selected-cell={containsSelectedCell}
|
||||||
>
|
>
|
||||||
<SpreadsheetCell
|
<SpreadsheetCell
|
||||||
|
@ -72,11 +66,11 @@
|
||||||
<input type="checkbox" checked={rowSelected} />
|
<input type="checkbox" checked={rowSelected} />
|
||||||
{:else}
|
{:else}
|
||||||
<span>
|
<span>
|
||||||
{rowIdx + 1}
|
{row.__idx + 1}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</SpreadsheetCell>
|
</SpreadsheetCell>
|
||||||
{#each renderedColumns as column (column.name)}
|
{#each $visibleColumns as column (column.name)}
|
||||||
{@const cellIdx = `${row._id}-${column.name}`}
|
{@const cellIdx = `${row._id}-${column.name}`}
|
||||||
<SpreadsheetCell
|
<SpreadsheetCell
|
||||||
{rowSelected}
|
{rowSelected}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { writable, derived } from "svelte/store"
|
||||||
|
|
||||||
|
export const createViewportStores = context => {
|
||||||
|
const { cellHeight, columns, rows, scroll, bounds } = context
|
||||||
|
|
||||||
|
// Use local variables to avoid needing to invoke 2 svelte getters each time
|
||||||
|
// scroll state changes, but also use stores to allow use of derived stores
|
||||||
|
let scrollTop = 0
|
||||||
|
let scrollLeft = 0
|
||||||
|
const scrollTopStore = writable(0)
|
||||||
|
const scrollLeftStore = writable(0)
|
||||||
|
|
||||||
|
// Derive height and width as primitives to avoid wasted computation
|
||||||
|
const width = derived(bounds, $bounds => $bounds.width)
|
||||||
|
const height = derived(bounds, $bounds => $bounds.height)
|
||||||
|
|
||||||
|
// Debounce scroll updates so we can slow down visible row computation
|
||||||
|
scroll.subscribe(({ left, top }) => {
|
||||||
|
// Only update local state when big changes occur
|
||||||
|
if (Math.abs(top - scrollTop) > cellHeight * 2) {
|
||||||
|
scrollTop = top
|
||||||
|
scrollTopStore.set(top)
|
||||||
|
}
|
||||||
|
if (Math.abs(left - scrollLeft) > 100) {
|
||||||
|
scrollLeft = left
|
||||||
|
scrollLeftStore.set(left)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Derive visible rows
|
||||||
|
const visibleRows = derived(
|
||||||
|
[rows, scrollTopStore, height],
|
||||||
|
([$rows, $scrollTop, $height]) => {
|
||||||
|
console.log("new rows")
|
||||||
|
const maxRows = Math.ceil($height / cellHeight) + 8
|
||||||
|
const firstRow = Math.max(0, Math.floor($scrollTop / cellHeight) - 4)
|
||||||
|
return $rows.slice(firstRow, firstRow + maxRows)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Derive visible columns
|
||||||
|
const visibleColumns = derived(
|
||||||
|
[columns, scrollLeftStore, width],
|
||||||
|
([$columns, $scrollLeft, $width]) => {
|
||||||
|
console.log("new columns")
|
||||||
|
if (!$columns.length) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
let startColIdx = 1
|
||||||
|
let rightEdge = $columns[1].width
|
||||||
|
while (rightEdge < $scrollLeft) {
|
||||||
|
startColIdx++
|
||||||
|
rightEdge += $columns[startColIdx].width
|
||||||
|
}
|
||||||
|
let endColIdx = startColIdx + 1
|
||||||
|
let leftEdge = $columns[0].width + 40 + rightEdge
|
||||||
|
while (leftEdge < $width + $scrollLeft) {
|
||||||
|
leftEdge += $columns[endColIdx]?.width
|
||||||
|
endColIdx++
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
$columns[0],
|
||||||
|
...$columns.slice(Math.max(1, startColIdx - 2), endColIdx + 2),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return { visibleRows, visibleColumns }
|
||||||
|
}
|
|
@ -90,18 +90,17 @@ export const throttle = (callback, minDelay = 1000) => {
|
||||||
/**
|
/**
|
||||||
* Utility to debounce DOM activities using requestAnimationFrame
|
* Utility to debounce DOM activities using requestAnimationFrame
|
||||||
* @param callback the function to run
|
* @param callback the function to run
|
||||||
* @param extractParams
|
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export const domDebounce = (callback, extractParams = x => x) => {
|
export const domDebounce = callback => {
|
||||||
let active = false
|
let active = false
|
||||||
let lastParams
|
let lastParams
|
||||||
return (...params) => {
|
return (...params) => {
|
||||||
lastParams = extractParams(...params)
|
lastParams = params
|
||||||
if (!active) {
|
if (!active) {
|
||||||
active = true
|
active = true
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
callback(lastParams)
|
callback(...lastParams)
|
||||||
active = false
|
active = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue