Drag & Drop: Animated Drop Targets
This example will show you how to make an animated node a Drop target.
Setting up the HTML
First we will create our HTML.
<div id="dock"></div> <div id="drag">Drag #1</div> <div id="anim1" class="anim">Anim #1</div> <div id="anim2" class="anim">Anim #2</div> <div id="anim3" class="anim">Anim #3</div> <div id="anim4" class="anim">Anim #4</div> <div id="anim5" class="anim">Anim #5</div>
<div id="dock"></div> <div id="drag">Drag #1</div> <div id="anim1" class="anim">Anim #1</div> <div id="anim2" class="anim">Anim #2</div> <div id="anim3" class="anim">Anim #3</div> <div id="anim4" class="anim">Anim #4</div> <div id="anim5" class="anim">Anim #5</div>
Now we give that HTML some CSS to make it visible.
.anim { position: relative; height: 50px; width: 100px; border: 1px solid black; background-color: #00B8BF; top: 100px; } #drag { height: 50px; width: 50px; border: 1px solid black; background-color: #004C6D; color: white; cursor: move; z-index: 5; } #dock { height: 600px; width: 75px; background-color: #D00050; border: 1px solid black; position: absolute; top: 5px; right: 0px; } .anim.yui-dd-drop-over { background-color: #EDFF9F; } .anim.done { background-color: white; } #drag1.yui-dd-drag-over { opacity: .5; filter: alpha(opacity=50); }
.anim { position: relative; height: 50px; width: 100px; border: 1px solid black; background-color: #00B8BF; top: 100px; } #drag { height: 50px; width: 50px; border: 1px solid black; background-color: #004C6D; color: white; cursor: move; z-index: 5; } #dock { height: 600px; width: 75px; background-color: #D00050; border: 1px solid black; position: absolute; top: 5px; right: 0px; } .anim.yui-dd-drop-over { background-color: #EDFF9F; } .anim.done { background-color: white; } #drag1.yui-dd-drag-over { opacity: .5; filter: alpha(opacity=50); }
Setting up the YUI Instance
Now we need to create our YUI instance and tell it to load the dd-drop
, dd-plugin
, dd-drop-plugin
and anim
modules.
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin');
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin');
Making the Node draggable
Now that we have a YUI instance with the modules loaded, we need to instantiate the Drag
instance on this Node.
In this example we will be using Node plugins to accomplish our tasks.
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin', function(Y) { //Get the node #drag var d = Y.Node.get('#drag'); d.plug(Y.Plugin.Drag, { dragMode: 'intersect' }); });
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin', function(Y) { //Get the node #drag var d = Y.Node.get('#drag'); d.plug(Y.Plugin.Drag, { dragMode: 'intersect' }); });
Animating the Nodes
Now we will setup the Animation sequence that we want to run.
//Get all the div's with the class anim var anims = Y.Node.all('div.anim'); var counter = 0; anims.each(function(v, k, items) { //Get a reference to the Node instance var a = v; counter++; //Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop); //Set the attributes on the animation a.fx.setAttrs({ from: { left: 0 }, to: { curve: function() { var points = [], n = 10; for (var i = 0; i < n; ++i) { points.push([ Math.floor(Math.random()*Y.DOM.winWidth() - 60 - a.get('offsetWidth')), Math.floor(Math.random()*Y.DOM.winHeight() - a.get('offsetHeight')) ]); } return points; } }, //Do the animation 20 times iterations: 20, //Alternate it so it "bounces" across the screen direction: 'alternate', //Give all of them a different duration so we get different speeds. duration: ((counter * 1.75) + 1) }); });
//Get all the div's with the class anim var anims = Y.Node.all('div.anim'); var counter = 0; anims.each(function(v, k, items) { //Get a reference to the Node instance var a = v; counter++; //Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop); //Set the attributes on the animation a.fx.setAttrs({ from: { left: 0 }, to: { curve: function() { var points = [], n = 10; for (var i = 0; i < n; ++i) { points.push([ Math.floor(Math.random()*Y.DOM.winWidth() - 60 - a.get('offsetWidth')), Math.floor(Math.random()*Y.DOM.winHeight() - a.get('offsetHeight')) ]); } return points; } }, //Do the animation 20 times iterations: 20, //Alternate it so it "bounces" across the screen direction: 'alternate', //Give all of them a different duration so we get different speeds. duration: ((counter * 1.75) + 1) }); });
Making the Node A Target
Using the dd-drop-plugin
, we now need to make this animated Node a Drop Target.
To do that, we need to add the plugin after the fx plugin.
//Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop);
//Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop);
Syncing the Target with the Animation
The Drop Target needs to be in sync with the animation, since we are changing the height, width, top and left style.
We do this by adding a listener to the tween
event on the animation instance.
//on tween of the original anim, we need to sync the drop's shim. a.fx.on('tween', function() { //Do we have an active Drag? if (Y.DD.DDM.activeDrag) { //Size this shim this.drop.sizeShim(); //Force an over target check since we might not be moving the mouse. Y.Lang.later(0, a, function() { this.drop._handleTargetOver(); }); } }, a);
//on tween of the original anim, we need to sync the drop's shim. a.fx.on('tween', function() { //Do we have an active Drag? if (Y.DD.DDM.activeDrag) { //Size this shim this.drop.sizeShim(); //Force an over target check since we might not be moving the mouse. Y.Lang.later(0, a, function() { this.drop._handleTargetOver(); }); } }, a);
Full example source
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin', function(Y) { //Get the node #drag var d = Y.Node.get('#drag'); d.plug(Y.plugin.Drag, { dragMode: 'intersect' }); //Get all the div's with the class anim var anims = Y.Node.all('div.anim'); var counter = 0; anims.each(function(v, k) { //Get a reference to the Node instance var a = v; //Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop); //Set the attributes on the animation a.fx.setAttrs({ from: { left: 0 }, to: { curve: function() { var points = [], n = 10; for (var i = 0; i < n; ++i) { points.push([ Math.floor(Math.random()*Y.DOM.winWidth() - 60 - a.get('offsetWidth')), Math.floor(Math.random()*Y.DOM.winHeight() - a.get('offsetHeight')) ]); } return points; } }, //Do the animation 20 times iterations: 20, //Alternate it so it "bounces" across the screen direction: 'alternate', //Give all of them a different duration so we get different speeds. duration: ((counter * 1.75) + 1) }); //When this drop is entered, pause the fx a.drop.on('drop:enter', function() { this.fx.pause(); }, a); //When the drop is exited, run the fx again a.drop.on('drop:exit', function() { this.fx.run(); }, a); //When a drop is on the node, do something special a.drop.on('drop:hit', function(e) { //Stop the animation this.fx.stop(); //remove the tween listener this.fx.unsubscribeAll('tween'); //move it to the dock this.fx.setAttrs({ from: { opacity: 1 }, to: { height: 50, width: 50, left: function() { var dW = Y.Node.get('body').get('viewportRegion').right; return ((dW - 60)); //Minus 60 for the dock }, top: 15, opacity: .5 }, direction: 'normal', iterations: 1, duration: .5, //We are using reverse above for the "bouncing", reset it here. reverse: false }); //On end, add a class and destroy the target this.fx.on('end', function() { this.drop.get('node').addClass('done'); this.drop.destroy(); }, this); //Run this animation this.fx.run(); //others that were dropped on. Y.each(e.others, function(v, k) { var node = v.get('node'); node.fx.run(); }); }, a); //on tween of the original anim, we need to sync the drop's shim. a.fx.on('tween', function() { //Do we have an active Drag? if (Y.DD.DDM.activeDrag) { //Size this shim this.drop.sizeShim(); //Force an over target check since we might not be moving the mouse. Y.Lang.later(0, a, function() { this.drop._handleTargetOver(); }); } }, a); a.fx.run(); }); });
YUI().use('dd-drop', 'anim', 'dd-plugin', 'dd-drop-plugin', function(Y) { //Get the node #drag var d = Y.Node.get('#drag'); d.plug(Y.plugin.Drag, { dragMode: 'intersect' }); //Get all the div's with the class anim var anims = Y.Node.all('div.anim'); var counter = 0; anims.each(function(v, k) { //Get a reference to the Node instance var a = v; //Add the FX plugin a.plug(Y.Plugin.NodeFX); //Add the Drop plugin a.plug(Y.Plugin.Drop); //Set the attributes on the animation a.fx.setAttrs({ from: { left: 0 }, to: { curve: function() { var points = [], n = 10; for (var i = 0; i < n; ++i) { points.push([ Math.floor(Math.random()*Y.DOM.winWidth() - 60 - a.get('offsetWidth')), Math.floor(Math.random()*Y.DOM.winHeight() - a.get('offsetHeight')) ]); } return points; } }, //Do the animation 20 times iterations: 20, //Alternate it so it "bounces" across the screen direction: 'alternate', //Give all of them a different duration so we get different speeds. duration: ((counter * 1.75) + 1) }); //When this drop is entered, pause the fx a.drop.on('drop:enter', function() { this.fx.pause(); }, a); //When the drop is exited, run the fx again a.drop.on('drop:exit', function() { this.fx.run(); }, a); //When a drop is on the node, do something special a.drop.on('drop:hit', function(e) { //Stop the animation this.fx.stop(); //remove the tween listener this.fx.unsubscribeAll('tween'); //move it to the dock this.fx.setAttrs({ from: { opacity: 1 }, to: { height: 50, width: 50, left: function() { var dW = Y.Node.get('body').get('viewportRegion').right; return ((dW - 60)); //Minus 60 for the dock }, top: 15, opacity: .5 }, direction: 'normal', iterations: 1, duration: .5, //We are using reverse above for the "bouncing", reset it here. reverse: false }); //On end, add a class and destroy the target this.fx.on('end', function() { this.drop.get('node').addClass('done'); this.drop.destroy(); }, this); //Run this animation this.fx.run(); //others that were dropped on. Y.each(e.others, function(v, k) { var node = v.get('node'); node.fx.run(); }); }, a); //on tween of the original anim, we need to sync the drop's shim. a.fx.on('tween', function() { //Do we have an active Drag? if (Y.DD.DDM.activeDrag) { //Size this shim this.drop.sizeShim(); //Force an over target check since we might not be moving the mouse. Y.Lang.later(0, a, function() { this.drop._handleTargetOver(); }); } }, a); a.fx.run(); }); });