From fdef7ae9fe64a7249b7d0fa6ba50d1057554924b Mon Sep 17 00:00:00 2001 From: Alex Reardon Date: Thu, 14 Jun 2018 11:35:29 +1000 Subject: [PATCH] correctly shifting draggable post update --- src/state/create-store.js | 2 +- src/state/get-page-item-positions.js | 11 +++ src/state/middleware/hooks.js | 12 ++-- src/state/publish/get-dimension-map.js | 8 +-- src/state/publish/get-drag-positions.js | 96 +++++++++++++++++++++++++ src/state/publish/index.js | 30 ++++++-- src/state/reducer.js | 8 +-- stories/src/dynamic/with-controls.jsx | 2 +- 8 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 src/state/get-page-item-positions.js create mode 100644 src/state/publish/get-drag-positions.js diff --git a/src/state/create-store.js b/src/state/create-store.js index 6264350848..aaa080a963 100644 --- a/src/state/create-store.js +++ b/src/state/create-store.js @@ -41,7 +41,7 @@ export default ({ // > uncomment to use // debugging logger - require('./debug-middleware/log-middleware').default, + // require('./debug-middleware/log-middleware').default, // debugging timer // require('./debug-middleware/action-timing-middleware').default, // average action timer diff --git a/src/state/get-page-item-positions.js b/src/state/get-page-item-positions.js new file mode 100644 index 0000000000..7a43144ba0 --- /dev/null +++ b/src/state/get-page-item-positions.js @@ -0,0 +1,11 @@ +// @flow +import type { Position } from 'css-box-model'; +import type { ItemPositions } from '../types'; +import { add } from './position'; + +export default (client: ItemPositions, windowScroll: Position): ItemPositions => ({ + selection: add(client.selection, windowScroll), + borderBoxCenter: add(client.borderBoxCenter, windowScroll), + offset: add(client.offset, windowScroll), +}); + diff --git a/src/state/middleware/hooks.js b/src/state/middleware/hooks.js index 9400bb0fc9..0cd62caef3 100644 --- a/src/state/middleware/hooks.js +++ b/src/state/middleware/hooks.js @@ -147,18 +147,22 @@ export default (getHooks: () => Hooks, announce: Announce) => { const move = (critical: Critical, location: ?DraggableLocation) => { invariant(isDragStartPublished && lastCritical, 'Cannot fire onDragMove when onDragStart has not been called'); + // Our critical has changed - this can happen if the index of the draggable changes + // due to a draggable addition or removal + if (!isCriticalEqual(critical, lastCritical)) { + lastCritical = critical; + } + // No change to publish - if (isCriticalEqual(critical, lastCritical) && - areLocationsEqual(lastLocation, location)) { + if (areLocationsEqual(lastLocation, location)) { return; } + lastLocation = location; const data: DragUpdate = { ...getDragStart(critical), destination: location, }; - lastLocation = location; - lastCritical = critical; withTimings('onDragUpdate', () => execute(getHooks().onDragUpdate, data, messagePreset.onDragUpdate)); }; diff --git a/src/state/publish/get-dimension-map.js b/src/state/publish/get-dimension-map.js index 0ff95482d5..ab01215741 100644 --- a/src/state/publish/get-dimension-map.js +++ b/src/state/publish/get-dimension-map.js @@ -73,7 +73,7 @@ const getRecord = (draggable: DraggableDimension, home: DroppableDimension) => { return record; }; -const timingKey: string = 'Dynamic dimension change processing'; +const timingKey: string = 'Dynamic dimension change processing (just math)'; export default ({ existing, @@ -81,7 +81,6 @@ export default ({ windowScroll, }: Args): DimensionMap => { timings.start(timingKey); - // TODO: everything const partitioned: Partitioned = Object.keys(publish.additions.draggables) .map((id: DraggableId): DraggableDimension => publish.additions.draggables[id]) .reduce((previous: Partitioned, draggable: DraggableDimension) => { @@ -129,7 +128,6 @@ export default ({ }); // ## Adjust draggables based on changes - const shifted: DraggableDimensionMap = Object.keys(existing.draggables) .map((id: DraggableId): DraggableDimension => { const draggable: DraggableDimension = existing.draggables[id]; @@ -160,7 +158,7 @@ export default ({ const additionSize: number = getTotal(additions); const removalSize: number = getTotal(removals); const deltaShift: number = additionSize - removalSize; - console.log('DELTA SHIFT', deltaShift); + // console.log('DELTA SHIFT', deltaShift); const change: Position = patch(droppable.axis.line, deltaShift); const client: BoxModel = offset(draggable.client, change); @@ -168,7 +166,7 @@ export default ({ const page: BoxModel = withScroll(client, windowScroll); const indexChange: number = additions.length - removals.length; - console.log('INDEX SHIFT', indexChange); + // console.log('INDEX SHIFT', indexChange); const index: number = startIndex + indexChange; const moved: DraggableDimension = { diff --git a/src/state/publish/get-drag-positions.js b/src/state/publish/get-drag-positions.js new file mode 100644 index 0000000000..a75c0f908a --- /dev/null +++ b/src/state/publish/get-drag-positions.js @@ -0,0 +1,96 @@ +// @flow +import invariant from 'invariant'; +import type { Position } from 'css-box-model'; +import { isEqual, subtract, add, negate } from '../position'; +import getPageItemPositions from '../get-page-item-positions'; +import type { + DragPositions, + Viewport, + ItemPositions, +} from '../../types'; + +type Args = {| + initial: DragPositions, + current: DragPositions, + oldClientBorderBoxCenter: Position, + newClientBorderBoxCenter: Position, + viewport: Viewport, +|} + +type Result = {| + initial: DragPositions, + current: DragPositions, +|} + +const origin: Position = { x: 0, y: 0 }; + +export default ({ + initial: oldInitial, + current: oldCurrent, + oldClientBorderBoxCenter, + newClientBorderBoxCenter, + viewport, +}: Args): Result => { + // Nothing needs to be changed + if (isEqual(oldClientBorderBoxCenter, newClientBorderBoxCenter)) { + return { initial: oldInitial, current: oldCurrent }; + } + + // how much the dragging item has shifted + const centerDiff: Position = subtract(newClientBorderBoxCenter, oldClientBorderBoxCenter); + // const displacement: Position = negate(centerDiff); + + console.log('center offset', centerDiff); + + const clientSelection: Position = add( + oldInitial.client.selection, centerDiff + ); + console.log('old client selection', oldInitial.client.selection); + console.log('new client selection', clientSelection); + + const initial: DragPositions = (() => { + const client: ItemPositions = { + selection: clientSelection, + borderBoxCenter: newClientBorderBoxCenter, + offset: origin, + }; + + return { + client, + page: getPageItemPositions(client, viewport.scroll.initial), + }; + })(); + + const offset: Position = subtract( + // The offset before the update + oldCurrent.client.offset, + // The change caused by the update + centerDiff, + ); + + const current: DragPositions = (() => { + const client: ItemPositions = { + selection: add(initial.client.selection, offset), + // this should be the same as the previous client borderBox center + borderBoxCenter: add(initial.client.borderBoxCenter, offset), + offset, + }; + + invariant( + isEqual(oldCurrent.client.borderBoxCenter, client.borderBoxCenter), + ` + Incorrect new client center position. + Expected ${JSON.stringify(oldCurrent.client.borderBoxCenter)} + to equal ${JSON.stringify(client.borderBoxCenter)} + ` + ); + + return { + client, + page: getPageItemPositions(client, viewport.scroll.current), + }; + })(); + + return { current, initial }; +}; + diff --git a/src/state/publish/index.js b/src/state/publish/index.js index d766c432e5..fe20590a2e 100644 --- a/src/state/publish/index.js +++ b/src/state/publish/index.js @@ -7,12 +7,14 @@ import type { CollectingState, DropPendingState, Publish, + Critical, DraggableId, DraggableDimension, } from '../../types'; import getDragImpact from '../get-drag-impact'; import getHomeImpact from '../get-home-impact'; import getDimensionMap from './get-dimension-map'; +import getDragPositions from './get-drag-positions'; type Args = {| state: CollectingState | DropPendingState, @@ -52,17 +54,26 @@ export default ({ windowScroll: state.viewport.scroll.initial, }); - // TODO: need to update initial and current positions to reflect any change in starting const dragging: DraggableId = state.critical.draggable.id; const original: DraggableDimension = state.dimensions.draggables[dragging]; const updated: DraggableDimension = dimensions.draggables[dragging]; - const centerDiff: Position = subtract( - updated.client.borderBox.center, - original.client.borderBox.center - ); + + const critical: Critical = { + droppable: state.critical.droppable, + // draggable index can change during a drag + draggable: updated.descriptor, + }; + + const { initial, current } = getDragPositions({ + initial: state.initial, + current: state.current, + oldClientBorderBoxCenter: original.client.borderBox.center, + newClientBorderBoxCenter: updated.client.borderBox.center, + viewport: state.viewport, + }); const impact: DragImpact = getDragImpact({ - pageBorderBoxCenter: state.current.page.borderBoxCenter, + pageBorderBoxCenter: current.page.borderBoxCenter, draggable: dimensions.draggables[state.critical.draggable.id], draggables: dimensions.draggables, droppables: dimensions.droppables, @@ -75,9 +86,14 @@ export default ({ phase: 'DRAGGING', ...state, // eslint-disable-next-line - phase: 'DRAGGING', + phase: 'DRAGGING', + critical, + current, + initial, impact, dimensions, + // not animating this movement + shouldAnimate: false, }; if (state.phase === 'COLLECTING') { diff --git a/src/state/reducer.js b/src/state/reducer.js index 6b4ec30786..e2d452f9da 100644 --- a/src/state/reducer.js +++ b/src/state/reducer.js @@ -10,6 +10,7 @@ import publish from './publish'; import { add, isEqual, subtract } from './position'; import scrollViewport from './scroll-viewport'; import getHomeImpact from './get-home-impact'; +import getPageItemPositions from './get-page-item-positions'; import type { Action, State, @@ -79,11 +80,8 @@ const moveWithPositionUpdates = ({ }; })(); - const page: ItemPositions = { - selection: add(client.selection, currentWindowScroll), - borderBoxCenter: add(client.borderBoxCenter, currentWindowScroll), - offset: add(client.offset, currentWindowScroll), - }; + const page: ItemPositions = getPageItemPositions(client, currentWindowScroll); + const current: DragPositions = { client, page, }; diff --git a/stories/src/dynamic/with-controls.jsx b/stories/src/dynamic/with-controls.jsx index 919ebc24b7..5b994e2682 100644 --- a/stories/src/dynamic/with-controls.jsx +++ b/stories/src/dynamic/with-controls.jsx @@ -144,7 +144,7 @@ export default class WithControls extends React.Component<*, State> { } onDragUpdate = (update: DragUpdate) => { - console.log('current index:', update.destination ? update.destination.index : null); + console.log('Update: current index =>', update.destination ? update.destination.index : null); } onDragEnd = (result: DropResult) => {