diff options
author | Mario <mario@mariovavti.com> | 2021-08-03 07:12:35 +0000 |
---|---|---|
committer | Mario <mario@mariovavti.com> | 2021-08-03 07:12:35 +0000 |
commit | cddc0217724f1a7661014d50e4c940e623a0c2dc (patch) | |
tree | f24595d659adbb7d1e5d2e8e6dcd829b093887bb /library/Sortable/src/Animation.js | |
parent | 571bae9d1c07bb08270163a314c91c138b42e62f (diff) | |
download | volse-hubzilla-cddc0217724f1a7661014d50e4c940e623a0c2dc.tar.gz volse-hubzilla-cddc0217724f1a7661014d50e4c940e623a0c2dc.tar.bz2 volse-hubzilla-cddc0217724f1a7661014d50e4c940e623a0c2dc.zip |
Apps drag and drop feature
Diffstat (limited to 'library/Sortable/src/Animation.js')
-rw-r--r-- | library/Sortable/src/Animation.js | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/library/Sortable/src/Animation.js b/library/Sortable/src/Animation.js new file mode 100644 index 000000000..6aa8e3ef8 --- /dev/null +++ b/library/Sortable/src/Animation.js @@ -0,0 +1,175 @@ +import { getRect, css, matrix, isRectEqual, indexOfObject } from './utils.js'; +import Sortable from './Sortable.js'; + +export default function AnimationStateManager() { + let animationStates = [], + animationCallbackId; + + return { + captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + let children = [].slice.call(this.el.children); + + children.forEach(child => { + if (css(child, 'display') === 'none' || child === Sortable.ghost) return; + animationStates.push({ + target: child, + rect: getRect(child) + }); + let fromRect = { ...animationStates[animationStates.length - 1].rect }; + + // If animating: compensate for current animation + if (child.thisAnimationDuration) { + let childMatrix = matrix(child, true); + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + child.fromRect = fromRect; + }); + }, + + addAnimationState(state) { + animationStates.push(state); + }, + + removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { target }), 1); + }, + + animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof(callback) === 'function') callback(); + return; + } + + let animating = false, + animationTime = 0; + + animationStates.forEach((state) => { + let time = 0, + animatingThis = false, + target = state.target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = state.rect, + targetMatrix = matrix(target, true); + + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if ( + isRectEqual(prevFromRect, toRect) && + !isRectEqual(fromRect, toRect) && + // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / + (animatingRect.left - toRect.left) === + (fromRect.top - toRect.top) / + (fromRect.left - toRect.left) + ) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } + + // if fromRect != toRect: animate + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + this.animate( + target, + animatingRect, + toRect, + time + ); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout(function() { + target.animationTime = 0; + target.prevFromRect = null; + target.fromRect = null; + target.prevToRect = null; + target.thisAnimationDuration = null; + }, time); + target.thisAnimationDuration = time; + } + }); + + + clearTimeout(animationCallbackId); + if (!animating) { + if (typeof(callback) === 'function') callback(); + } else { + animationCallbackId = setTimeout(function() { + if (typeof(callback) === 'function') callback(); + }, animationTime); + } + animationStates = []; + }, + + animate(target, currentRect, toRect, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + let elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (currentRect.left - toRect.left) / (scaleX || 1), + translateY = (currentRect.top - toRect.top) / (scaleY || 1); + + target.animatingX = !!translateX; + target.animatingY = !!translateY; + + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + + this.forRepaintDummy = repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + (typeof target.animated === 'number') && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; +} + +function repaint(target) { + return target.offsetWidth; +} + + +function calculateRealTime(animatingRect, fromRect, toRect, options) { + return ( + Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / + Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) + ) * options.animation; +} |