From e9b801e2056d2841a1acbecfbeb4642940df7c1a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Sat, 25 Feb 2023 17:09:08 +0000 Subject: [PATCH] Fix columnn reordering --- .../app/spreadsheet/Spreadsheet.svelte | 12 +++++ .../app/spreadsheet/SpreadsheetBody.svelte | 18 ++++--- .../app/spreadsheet/stores/reorder.js | 52 ++++++++++++------- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte b/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte index 2808b2c572..ee1d75d0af 100644 --- a/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte +++ b/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte @@ -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) diff --git a/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte b/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte index a8a5985f4c..b6fd5e94ae 100644 --- a/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte +++ b/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte @@ -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 () => { diff --git a/packages/client/src/components/app/spreadsheet/stores/reorder.js b/packages/client/src/components/app/spreadsheet/stores/reorder.js index db6d1831ec..74bb9b63b0 100644 --- a/packages/client/src/components/app/spreadsheet/stores/reorder.js +++ b/packages/client/src/components/app/spreadsheet/stores/reorder.js @@ -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