Fix columnn reordering

This commit is contained in:
Andrew Kingston 2023-02-25 17:09:08 +00:00
parent 0eadca9acb
commit e9b801e205
3 changed files with 57 additions and 25 deletions

View File

@ -37,6 +37,16 @@
const newRows = writable([])
const visibleRows = writable([0, 0])
const visibleColumns = writable([0, 0])
const scroll = writable({
left: 0,
top: 0,
})
const bounds = writable({
left: 0,
top: 0,
width: 0,
height: 0,
})
// Build up spreadsheet context and additional stores
const context = {
@ -52,6 +62,8 @@
cellHeight,
visibleRows,
visibleColumns,
bounds,
scroll,
}
const { reorder, reorderPlaceholder } = createReorderStores(context)
const resize = createResizeStore(context)

View File

@ -10,18 +10,18 @@
visibleColumns,
cellHeight,
rows,
bounds,
scroll,
} = getContext("spreadsheet")
const padding = 180
let ref
let width
let height
let scrollLeft = 0
let scrollTop = 0
$: updateVisibleRows($columns, scrollTop, height)
$: updateVisibleColumns($columns, scrollLeft, width)
$: updateVisibleRows($columns, scrollTop, $bounds.height)
$: updateVisibleColumns($columns, scrollLeft, $bounds.width)
$: contentHeight = ($rows.length + 2) * cellHeight + padding
$: contentWidth = computeContentWidth($columns)
$: horizontallyScrolled = scrollLeft > 0
@ -57,12 +57,16 @@
const handleScroll = domDebounce(
({ left, top }) => {
// 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 })
)
@ -81,6 +85,7 @@
if (!columns.length) {
return
}
// Compute column visibility
let startColIdx = 1
let rightEdge = columns[1].width
@ -99,9 +104,8 @@
onMount(() => {
// Observe and record the height of the body
const observer = new ResizeObserver(entries => {
width = entries[0].contentRect.width
height = entries[0].contentRect.height
const observer = new ResizeObserver(() => {
bounds.set(ref.getBoundingClientRect())
})
observer.observe(ref)
return () => {

View File

@ -1,7 +1,7 @@
import { get, writable } from "svelte/store"
export const createReorderStores = context => {
const { columns, rand, rows } = context
const { columns, bounds, rows, scroll } = context
const reorderInitialState = {
columnIdx: null,
swapColumnIdx: null,
@ -23,22 +23,20 @@ export const createReorderStores = context => {
// Callback when dragging on a colum header and starting reordering
const startReordering = (columnIdx, e) => {
const $columns = get(columns)
const $bounds = get(bounds)
const $rows = get(rows)
const $scroll = get(scroll)
// Generate new breakpoints for the current columns
let breakpoints = []
const cols = get(columns)
cols.forEach((col, idx) => {
$columns.forEach((col, idx) => {
breakpoints.push(col.left)
if (idx === cols.length - 1) {
if (idx === $columns.length - 1) {
breakpoints.push(col.left + col.width)
}
})
console.log(breakpoints, e.clientX)
// Get bounds of the selected header and sheet body
const self = cols[columnIdx]
const body = document.getElementById(`sheet-${rand}-body`)
const bodyBounds = body.getBoundingClientRect()
const self = $columns[columnIdx]
// Update state
reorder.set({
@ -48,10 +46,13 @@ export const createReorderStores = context => {
initialMouseX: e.clientX,
})
placeholder.set({
initialX: self.left - bodyBounds.x,
x: self.left - bodyBounds.x,
initialX: self.left,
x: self.left,
width: self.width,
height: (get(rows).length + 2) * 32,
height: ($rows.length + 2) * 32,
sheetLeft: $bounds.left,
maxX: $bounds.width - self.width,
scrollLeft: $scroll.left,
})
// Add listeners to handle mouse movement
@ -71,14 +72,21 @@ export const createReorderStores = context => {
// Compute new placeholder position
const $placeholder = get(placeholder)
let newX = e.clientX - $reorder.initialMouseX + $placeholder.initialX
let newX =
e.clientX -
$reorder.initialMouseX +
$placeholder.initialX -
$placeholder.scrollLeft
newX = Math.max(0, newX)
newX = Math.min($placeholder.maxX, newX)
// Compute the closest breakpoint to the current position
let swapColumnIdx
let minDistance = Number.MAX_SAFE_INTEGER
$reorder.breakpoints.forEach((point, idx) => {
const distance = Math.abs(point - e.clientX)
const distance = Math.abs(
point - e.clientX + $placeholder.sheetLeft - $placeholder.scrollLeft
)
if (distance < minDistance) {
minDistance = distance
swapColumnIdx = idx
@ -108,8 +116,16 @@ export const createReorderStores = context => {
swapColumnIdx++
}
state.splice(swapColumnIdx, 0, removed[0])
state = state.map((col, idx) => ({ ...col, idx }))
return state
let offset = 40
return state.map((col, idx) => {
const newCol = {
...col,
idx,
left: offset,
}
offset += col.width
return newCol
})
})
// Reset state