diff --git a/dragula.js b/dragula.js index 7c19fc63..809a3652 100644 --- a/dragula.js +++ b/dragula.js @@ -5,6 +5,7 @@ var crossvent = require('crossvent'); var classes = require('./classes'); var doc = document; var documentElement = doc.documentElement; +var animateDuration = 300; function dragula (initialContainers, options) { var len = arguments.length; @@ -39,6 +40,7 @@ function dragula (initialContainers, options) { if (o.direction === void 0) { o.direction = 'vertical'; } if (o.ignoreInputTextSelection === void 0) { o.ignoreInputTextSelection = true; } if (o.mirrorContainer === void 0) { o.mirrorContainer = doc.body; } + if (o.animation === void 0) { o.animation = false; } var drake = emitter({ containers: o.containers, @@ -406,7 +408,33 @@ function dragula (initialContainers, options) { reference !== nextEl(item) ) { _currentSibling = reference; + + var itemRect = item.getBoundingClientRect(); + var referenceRect = reference ? reference.getBoundingClientRect() : null; + var direct = o.direction; + // if isPositive is true, the direction is right or down + var isPositive; + if (referenceRect) { + isPositive = direct === 'horizontal' ? (itemRect.x < referenceRect.x) : (itemRect.y < referenceRect.y); + }else{ + isPositive = true; + } + // mover is the element to be exchange passively + var mover; + if (isPositive) { + mover = reference ? (reference.previousElementSibling ? reference.previousElementSibling : reference) : dropTarget.lastElementChild; + } else { + mover = reference; //upward or right + } + if (!mover) { + mover = dropTarget; + } + var moverRect = mover && mover.getBoundingClientRect(); dropTarget.insertBefore(item, reference); + if (o.animation && mover && moverRect) { + animate(moverRect, mover); + animate(itemRect, item); + } drake.emit('shadow', item, dropTarget, _source); } function moved (type) { drake.emit(type, item, _lastDropTarget, _source); } @@ -583,6 +611,31 @@ function nextEl (el) { } } +/** + * Create an animation from position before sorting to present position + * @param prevRect including element's position infomation before sorting + * @param target element after sorting + */ +function animate (prevRect, target) { + if (!prevRect || !target) { + return; + } + var currentRect = target.getBoundingClientRect(); + var originProps = {transition: target.style.transition, transform: target.style.transform}; + Object.assign(target.style, { + transition: 'none', + transform: 'translate(' + (prevRect.left - currentRect.left) + 'px,' + (prevRect.top - currentRect.top) + 'px)' + }); + target.offsetWidth; // repaint + Object.assign(target.style, {transition: 'all ' + animateDuration + 'ms', transform: 'translate(0,0)'}); + clearTimeout(target.animated); + target.animated = setTimeout(function () { + Object.assign(target.style, {originProps: originProps}); + target.animated = false; + }, animateDuration); +} + + function getEventHost (e) { // on touchend event, we have to use `e.changedTouches` // see http://stackoverflow.com/questions/7192563/touchend-event-properties diff --git a/example/example.js b/example/example.js index c94cfb2a..4297d7b1 100644 --- a/example/example.js +++ b/example/example.js @@ -36,6 +36,9 @@ dragula([$('left-copy-1tomany'), $('right-copy-1tomany')], { }); dragula([sortable]); +dragula([$('animation')], { + animation: true +}) crossvent.add(sortable, 'click', clickHandler); diff --git a/index.html b/index.html index f54b4910..6f737f71 100644 --- a/index.html +++ b/index.html @@ -204,6 +204,25 @@

Drag and drop so simple it hurts< + +
+ +
+
+
Anxious Cab Driver
+
Thriving Venture
+ +
Calm Clam
+
+
+
+      
+        dragula([document.getElementById(container)], {
+          animation: true
+        });
+      
+    
+

Who couldn't love a pun that good? — The Next Web

Get it on GitHub! bevacqua/dragula

diff --git a/readme.markdown b/readme.markdown index 4fe33e63..a895fe6a 100644 --- a/readme.markdown +++ b/readme.markdown @@ -98,6 +98,7 @@ dragula(containers, { invalid: function (el, handle) { return false; // don't prevent any drags from initiating by default }, + animation: false, // no animation by default direction: 'vertical', // Y axis is considered when determining where an element would be dropped copy: false, // elements are moved by default, not copied copySortSource: false, // elements in copy-source containers can be reordered @@ -196,6 +197,10 @@ By default, spilling an element outside of any containers will move the element By default, spilling an element outside of any containers will move the element back to the _drop position previewed by the feedback shadow_. Setting `removeOnSpill` to `true` will ensure elements dropped outside of any approved containers are removed from the DOM. Note that `remove` events won't fire if `copy` is set to `true`. +#### `options.animation` + +If the `animation` is true, there will be smooth animation after dragging finish. + #### `options.direction` When an element is dropped onto a container, it'll be placed near the point where the mouse was released. If the `direction` is `'vertical'`, the default value, the Y axis will be considered. Otherwise, if the `direction` is `'horizontal'`, the X axis will be considered.