Improve and simplify scrolling

This commit is contained in:
Andrew Kingston 2024-06-24 13:45:37 +01:00
parent 42538e114a
commit e05c46435f
No known key found for this signature in database
4 changed files with 56 additions and 54 deletions

View File

@ -6,14 +6,14 @@
const { const {
isReordering, isReordering,
reorder, reorder,
visibleColumnLookupMap, columnLookupMap,
rowHeight, rowHeight,
renderedRows, renderedRows,
scrollLeft, scrollLeft,
bodyLeft, bodyLeft,
} = getContext("grid") } = getContext("grid")
$: targetColumn = $visibleColumnLookupMap[$reorder.targetColumn] $: targetColumn = $columnLookupMap[$reorder.targetColumn]
$: insertAfter = $reorder.insertAfter $: insertAfter = $reorder.insertAfter
$: left = getLeft(targetColumn, insertAfter, $scrollLeft) $: left = getLeft(targetColumn, insertAfter, $scrollLeft)
$: height = $rowHeight * $renderedRows.length + DefaultRowHeight $: height = $rowHeight * $renderedRows.length + DefaultRowHeight
@ -21,6 +21,7 @@
$: visible = $isReordering && left >= $bodyLeft $: visible = $isReordering && left >= $bodyLeft
const getLeft = (targetColumn, insertAfter, scrollLeft) => { const getLeft = (targetColumn, insertAfter, scrollLeft) => {
console.log(targetColumn)
if (!targetColumn) { if (!targetColumn) {
return 0 return 0
} }

View File

@ -63,7 +63,7 @@ export const createActions = context => {
rowChangeCache, rowChangeCache,
rows, rows,
focusedCellId, focusedCellId,
visibleColumnLookupMap, columnLookupMap,
allVisibleColumns, allVisibleColumns,
} = context } = context
@ -156,9 +156,9 @@ export const createActions = context => {
const $focusedCellId = get(focusedCellId) const $focusedCellId = get(focusedCellId)
const { rowId, field } = parseCellID($focusedCellId) const { rowId, field } = parseCellID($focusedCellId)
const $rowLookupMap = get(rowLookupMap) const $rowLookupMap = get(rowLookupMap)
const $visibleColumnLookupMap = get(visibleColumnLookupMap) const $columnLookupMap = get(columnLookupMap)
const rowIdx = $rowLookupMap[rowId].__idx const rowIdx = $rowLookupMap[rowId].__idx
const colIdx = $visibleColumnLookupMap[field].__idx const colIdx = $columnLookupMap[field].__idx
// Get limits of how many rows and columns we're able to paste into // Get limits of how many rows and columns we're able to paste into
const $rows = get(rows) const $rows = get(rows)

View File

@ -5,10 +5,21 @@ export const createStores = () => {
const columns = writable([]) const columns = writable([])
const enrichedColumns = derived(columns, $columns => { const enrichedColumns = derived(columns, $columns => {
return $columns.map((col, idx) => ({ let offset = GutterWidth
...col, let visibleIdx = 0
__idx: idx, return $columns.map((col, idx) => {
})) const enriched = {
...col,
__idx: idx, // Overall column index
__visibleIdx: visibleIdx, // Index within the visible columns
__left: offset, // Left offset relative to all visible columns
}
if (col.visible) {
visibleIdx++
offset += col.width
}
return enriched
})
}) })
return { return {
@ -22,11 +33,6 @@ export const createStores = () => {
export const deriveStores = context => { export const deriveStores = context => {
const { columns } = context const { columns } = context
// Derive the primary display column
const displayColumn = derived(columns, $columns => {
return $columns.find(col => col.primaryDisplay)
})
// Derive a lookup map for all columns by name // Derive a lookup map for all columns by name
const columnLookupMap = derived(columns, $columns => { const columnLookupMap = derived(columns, $columns => {
let map = {} let map = {}
@ -36,33 +42,15 @@ export const deriveStores = context => {
return map return map
}) })
// Derived list of columns which have not been explicitly hidden, and enrich // Derived list of columns which have not been explicitly hidden
// with an index so we can easily select nearby columns
const visibleColumns = derived(columns, $columns => { const visibleColumns = derived(columns, $columns => {
let offset = GutterWidth return $columns.filter(col => col.visible)
return $columns
.filter(col => col.visible)
.map((col, idx) => {
const enriched = {
...col,
__left: offset,
__idx: idx,
}
offset += col.width
return enriched
})
}) })
// Derive a lookup map for visible columns by name // Split visible columns into their discrete types
const visibleColumnLookupMap = derived(visibleColumns, $visibleColumns => { const displayColumn = derived(visibleColumns, $visibleColumns => {
let map = {} return $visibleColumns.find(col => col.primaryDisplay)
$visibleColumns.forEach(column => {
map[column.name] = column
})
return map
}) })
// Derive scrollable columns
const scrollableColumns = derived(visibleColumns, $visibleColumns => { const scrollableColumns = derived(visibleColumns, $visibleColumns => {
return $visibleColumns.filter(col => !col.primaryDisplay) return $visibleColumns.filter(col => !col.primaryDisplay)
}) })
@ -79,7 +67,6 @@ export const deriveStores = context => {
displayColumn, displayColumn,
columnLookupMap, columnLookupMap,
visibleColumns, visibleColumns,
visibleColumnLookupMap,
scrollableColumns, scrollableColumns,
hasNonAutoColumn, hasNonAutoColumn,
} }

View File

@ -30,14 +30,14 @@ export const createActions = context => {
columns, columns,
columnLookupMap, columnLookupMap,
scrollableColumns, scrollableColumns,
visibleColumnLookupMap,
scroll, scroll,
bounds, bounds,
visibleColumns, visibleColumns,
maxScrollLeft,
datasource, datasource,
bodyLeft, bodyLeft,
width, width,
scrollLeft,
maxScrollLeft,
} = context } = context
let latestX = 0 let latestX = 0
let autoScrollInterval let autoScrollInterval
@ -94,17 +94,19 @@ export const createActions = context => {
considerReorderPosition() considerReorderPosition()
// Check if we need to start auto-scrolling // Check if we need to start auto-scrolling
const $scrollLeft = get(scrollLeft)
const $maxScrollLeft = get(maxScrollLeft)
const $reorder = get(reorder) const $reorder = get(reorder)
const proximityCutoff = Math.min(140, get(width) / 6) const proximityCutoff = Math.min(140, get(width) / 6)
const speedFactor = 16 const speedFactor = 16
const rightProximity = Math.max(0, $reorder.gridLeft + $reorder.width - x) const rightProximity = Math.max(0, $reorder.gridLeft + $reorder.width - x)
const leftProximity = Math.max(0, x - $reorder.gridLeft) const leftProximity = Math.max(0, x - $reorder.gridLeft)
if (rightProximity < proximityCutoff) { if (rightProximity < proximityCutoff && $scrollLeft < $maxScrollLeft) {
const weight = proximityCutoff - rightProximity const weight = proximityCutoff - rightProximity
const increment = (weight / proximityCutoff) * speedFactor const increment = (weight / proximityCutoff) * speedFactor
reorder.update(state => ({ ...state, increment })) reorder.update(state => ({ ...state, increment }))
startAutoScroll() startAutoScroll()
} else if (leftProximity < proximityCutoff) { } else if (leftProximity < proximityCutoff && $scrollLeft > 0) {
const weight = -1 * (proximityCutoff - leftProximity) const weight = -1 * (proximityCutoff - leftProximity)
const increment = (weight / proximityCutoff) * speedFactor const increment = (weight / proximityCutoff) * speedFactor
reorder.update(state => ({ ...state, increment })) reorder.update(state => ({ ...state, increment }))
@ -180,20 +182,26 @@ export const createActions = context => {
document.removeEventListener("touchcancel", stopReordering) document.removeEventListener("touchcancel", stopReordering)
// Ensure there's actually a change before saving // Ensure there's actually a change before saving
const { sourceColumn, targetColumn } = get(reorder) const { sourceColumn, targetColumn, insertAfter } = get(reorder)
reorder.set(reorderInitialState) reorder.set(reorderInitialState)
if (sourceColumn !== targetColumn) { if (sourceColumn !== targetColumn) {
await moveColumn(sourceColumn, targetColumn) await moveColumn({ sourceColumn, targetColumn, insertAfter })
} }
} }
// Moves a column after another columns. // Moves a column after another columns.
// An undefined target column will move the source to index 0. // An undefined target column will move the source to index 0.
const moveColumn = async (sourceColumn, targetColumn) => { const moveColumn = async ({
sourceColumn,
targetColumn,
insertAfter = false,
}) => {
const $columnLookupMap = get(columnLookupMap) const $columnLookupMap = get(columnLookupMap)
let sourceIdx = $columnLookupMap[sourceColumn] let sourceIdx = $columnLookupMap[sourceColumn].__idx
let targetIdx = $columnLookupMap[targetColumn] let targetIdx = $columnLookupMap[targetColumn].__idx
targetIdx++ if (insertAfter) {
targetIdx++
}
columns.update(state => { columns.update(state => {
const removed = state.splice(sourceIdx, 1) const removed = state.splice(sourceIdx, 1)
if (--targetIdx < sourceIdx) { if (--targetIdx < sourceIdx) {
@ -214,20 +222,26 @@ export const createActions = context => {
// Moves a column one place left (as appears visually) // Moves a column one place left (as appears visually)
const moveColumnLeft = async column => { const moveColumnLeft = async column => {
const $visibleColumns = get(visibleColumns) const $visibleColumns = get(visibleColumns)
const $visibleColumnLookupMap = get(visibleColumnLookupMap) const $columnLookupMap = get(columnLookupMap)
const sourceIdx = $visibleColumnLookupMap[column] const sourceIdx = $columnLookupMap[column]
await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name) await moveColumn({
sourceColumn: column,
targetColumn: $visibleColumns[sourceIdx - 2]?.name,
})
} }
// Moves a column one place right (as appears visually) // Moves a column one place right (as appears visually)
const moveColumnRight = async column => { const moveColumnRight = async column => {
const $visibleColumns = get(visibleColumns) const $visibleColumns = get(visibleColumns)
const $visibleColumnLookupMap = get(visibleColumnLookupMap) const $columnLookupMap = get(columnLookupMap)
const sourceIdx = $visibleColumnLookupMap[column] const sourceIdx = $columnLookupMap[column]
if (sourceIdx === $visibleColumns.length - 1) { if (sourceIdx === $visibleColumns.length - 1) {
return return
} }
await moveColumn(column, $visibleColumns[sourceIdx + 1]?.name) await moveColumn({
sourceColumn: column,
targetColumn: $visibleColumns[sourceIdx + 1]?.name,
})
} }
return { return {