Add automatic scrolling left/right when dragging to reorder columns
This commit is contained in:
parent
ba9691ee12
commit
cadd1b5a4e
|
@ -4,9 +4,10 @@ const reorderInitialState = {
|
||||||
sourceColumn: null,
|
sourceColumn: null,
|
||||||
targetColumn: null,
|
targetColumn: null,
|
||||||
breakpoints: [],
|
breakpoints: [],
|
||||||
initialMouseX: null,
|
|
||||||
scrollLeft: 0,
|
|
||||||
gridLeft: 0,
|
gridLeft: 0,
|
||||||
|
width: 0,
|
||||||
|
latestX: 0,
|
||||||
|
increment: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createStores = () => {
|
export const createStores = () => {
|
||||||
|
@ -23,14 +24,24 @@ export const createStores = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deriveStores = context => {
|
export const deriveStores = context => {
|
||||||
const { reorder, columns, visibleColumns, scroll, bounds, stickyColumn, ui } =
|
const {
|
||||||
context
|
reorder,
|
||||||
|
columns,
|
||||||
|
visibleColumns,
|
||||||
|
scroll,
|
||||||
|
bounds,
|
||||||
|
stickyColumn,
|
||||||
|
ui,
|
||||||
|
maxScrollLeft,
|
||||||
|
} = context
|
||||||
|
|
||||||
|
let autoScrollInterval
|
||||||
|
let isAutoScrolling
|
||||||
|
|
||||||
// Callback when dragging on a colum header and starting reordering
|
// Callback when dragging on a colum header and starting reordering
|
||||||
const startReordering = (column, e) => {
|
const startReordering = (column, e) => {
|
||||||
const $visibleColumns = get(visibleColumns)
|
const $visibleColumns = get(visibleColumns)
|
||||||
const $bounds = get(bounds)
|
const $bounds = get(bounds)
|
||||||
const $scroll = get(scroll)
|
|
||||||
const $stickyColumn = get(stickyColumn)
|
const $stickyColumn = get(stickyColumn)
|
||||||
ui.actions.blur()
|
ui.actions.blur()
|
||||||
|
|
||||||
|
@ -51,9 +62,8 @@ export const deriveStores = context => {
|
||||||
sourceColumn: column,
|
sourceColumn: column,
|
||||||
targetColumn: null,
|
targetColumn: null,
|
||||||
breakpoints,
|
breakpoints,
|
||||||
initialMouseX: e.clientX,
|
|
||||||
scrollLeft: $scroll.left,
|
|
||||||
gridLeft: $bounds.left,
|
gridLeft: $bounds.left,
|
||||||
|
width: $bounds.width,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add listeners to handle mouse movement
|
// Add listeners to handle mouse movement
|
||||||
|
@ -66,12 +76,44 @@ export const deriveStores = context => {
|
||||||
|
|
||||||
// Callback when moving the mouse when reordering columns
|
// Callback when moving the mouse when reordering columns
|
||||||
const onReorderMouseMove = e => {
|
const onReorderMouseMove = e => {
|
||||||
|
// Immediately handle the current position
|
||||||
|
const x = e.clientX
|
||||||
|
reorder.update(state => ({
|
||||||
|
...state,
|
||||||
|
latestX: x,
|
||||||
|
}))
|
||||||
|
considerReorderPosition()
|
||||||
|
|
||||||
|
// Check if we need to start auto-scrolling
|
||||||
const $reorder = get(reorder)
|
const $reorder = get(reorder)
|
||||||
|
const proximityCutoff = 140
|
||||||
|
const speedFactor = 8
|
||||||
|
const rightProximity = Math.max(0, $reorder.gridLeft + $reorder.width - x)
|
||||||
|
const leftProximity = Math.max(0, x - $reorder.gridLeft)
|
||||||
|
if (rightProximity < proximityCutoff) {
|
||||||
|
const weight = proximityCutoff - rightProximity
|
||||||
|
const increment = (weight / proximityCutoff) * speedFactor
|
||||||
|
reorder.update(state => ({ ...state, increment }))
|
||||||
|
startAutoScroll()
|
||||||
|
} else if (leftProximity < proximityCutoff) {
|
||||||
|
const weight = -1 * (proximityCutoff - leftProximity)
|
||||||
|
const increment = (weight / proximityCutoff) * speedFactor
|
||||||
|
reorder.update(state => ({ ...state, increment }))
|
||||||
|
startAutoScroll()
|
||||||
|
} else {
|
||||||
|
stopAutoScroll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual logic to consider the current position and determine the new order
|
||||||
|
const considerReorderPosition = () => {
|
||||||
|
const $reorder = get(reorder)
|
||||||
|
const $scroll = get(scroll)
|
||||||
|
|
||||||
// Compute the closest breakpoint to the current position
|
// Compute the closest breakpoint to the current position
|
||||||
let targetColumn
|
let targetColumn
|
||||||
let minDistance = Number.MAX_SAFE_INTEGER
|
let minDistance = Number.MAX_SAFE_INTEGER
|
||||||
const mouseX = e.clientX - $reorder.gridLeft + $reorder.scrollLeft
|
const mouseX = $reorder.latestX - $reorder.gridLeft + $scroll.left
|
||||||
$reorder.breakpoints.forEach(point => {
|
$reorder.breakpoints.forEach(point => {
|
||||||
const distance = Math.abs(point.x - mouseX)
|
const distance = Math.abs(point.x - mouseX)
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
|
@ -79,7 +121,6 @@ export const deriveStores = context => {
|
||||||
targetColumn = point.column
|
targetColumn = point.column
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (targetColumn !== $reorder.targetColumn) {
|
if (targetColumn !== $reorder.targetColumn) {
|
||||||
reorder.update(state => ({
|
reorder.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
|
@ -88,8 +129,35 @@ export const deriveStores = context => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commences auto-scrolling in a certain direction, triggered when the mouse
|
||||||
|
// approaches the edges of the grid
|
||||||
|
const startAutoScroll = () => {
|
||||||
|
if (isAutoScrolling) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isAutoScrolling = true
|
||||||
|
autoScrollInterval = setInterval(() => {
|
||||||
|
const $maxLeft = get(maxScrollLeft)
|
||||||
|
const { increment } = get(reorder)
|
||||||
|
scroll.update(state => ({
|
||||||
|
...state,
|
||||||
|
left: Math.max(0, Math.min($maxLeft, state.left + increment)),
|
||||||
|
}))
|
||||||
|
considerReorderPosition()
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops auto scrolling
|
||||||
|
const stopAutoScroll = () => {
|
||||||
|
isAutoScrolling = false
|
||||||
|
clearInterval(autoScrollInterval)
|
||||||
|
}
|
||||||
|
|
||||||
// Callback when stopping reordering columns
|
// Callback when stopping reordering columns
|
||||||
const stopReordering = async () => {
|
const stopReordering = async () => {
|
||||||
|
// Ensure auto-scrolling is stopped
|
||||||
|
stopAutoScroll()
|
||||||
|
|
||||||
// Swap position of columns
|
// Swap position of columns
|
||||||
let { sourceColumn, targetColumn } = get(reorder)
|
let { sourceColumn, targetColumn } = get(reorder)
|
||||||
moveColumn(sourceColumn, targetColumn)
|
moveColumn(sourceColumn, targetColumn)
|
||||||
|
|
Loading…
Reference in New Issue