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 newRows = writable([])
const visibleRows = writable([0, 0]) const visibleRows = writable([0, 0])
const visibleColumns = 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 // Build up spreadsheet context and additional stores
const context = { const context = {
@ -52,6 +62,8 @@
cellHeight, cellHeight,
visibleRows, visibleRows,
visibleColumns, visibleColumns,
bounds,
scroll,
} }
const { reorder, reorderPlaceholder } = createReorderStores(context) const { reorder, reorderPlaceholder } = createReorderStores(context)
const resize = createResizeStore(context) const resize = createResizeStore(context)

View File

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

View File

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