Search code examples
javascriptdrag-and-dropjquery-animateeaseljs

Animate CC - Easeljs - Multiple Draggables and Multiple Target drops


I'm new to the world of stackoverflow, Javascript, Adobe Animate CC, and EaselJS. All of which I'm in the process of learning how to use. I am trying build a drag and drop activity for html5 canvas that contains 5 draggables and 5 targets. I need the each target to be able to accept and snap [into place] any of the 5 draggable. The idea is to have the user make 5 choices then check the answers once all 5 draggables have been placed.

There are several examples of EaselJS drag and drop activities around, but the closest one I've found that fits what I need is here on codepen. I noticed several other users have used this same example as a starting point too. I've created a branch on codepen from the original posting trying to show what I am aiming for.

I'm sure there is a better way to code this, but I feel I don't have the knowledge to do so yet. Especially in the branch on codepen where I just copied and pasted to create more draggers and targets. I have made multiple "draggers" and "destinations" each with their own .setBounds then pushed the "destinations" to an array. My plan was to put a for loop around the dragger.on("pressup", function(evt) section and replace all destinations with the array "destinations[i]" containing the pushed content in hopes it would allow me to place any draggable on any target.

This didn't work. I kept getting the same error, via google chrome's developer's tool, stating cannot read property 'getBounds' on undefined. It is referring to this section here, var objBounds2 = obj2.getBounds().clone(); of the intersect function near the end of the code.

If you're still reading this and are able to following along with what I'm trying to do, then thank you. I'm sure I'm making this more complicated than it really needs to be. I need all the help I can get.

Here is where the display objects are created [draggables and targets.]

//VARIABLES
//Drag Object Size
dragRadius = 40;
//Destination Size
destHeight = 100;
destWidth = 100;

//Circle Creation
var label = new createjs.Text("RED", "14px Lato", "#fff");
label.textAlign="center";
label.y -= 7;

var circle = new createjs.Shape();
circle.graphics.setStrokeStyle(2).beginStroke("black")
.beginFill("red").drawCircle(0,0, dragRadius);


//Drag Object Creation
//Placed inside a container to hold both label and shape
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
dragger.setBounds(100, 100, dragRadius*2, dragRadius*2);
//DragRadius * 2 because 2*r = width of the bounding box

var label2 = new createjs.Text("RED", "bold 14px Lato", "#000");
label2.textAlign = "center";
label2.x += 50;
label2.y += 40;


var box = new createjs.Shape();
box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
var destination = new createjs.Container();
destination.x = 350;
destination.y = 50;
destination.setBounds(350, 50, destHeight, destWidth);

destination.addChild(label2, box);

Here is the drag and drop section:

//DRAG FUNCTIONALITY =====================
dragger.on("pressmove", function(evt){
     evt.currentTarget.x = evt.stageX;
    evt.currentTarget.y = evt.stageY;
     stage.update(); //much smoother because it refreshes the screen every pixel movement instead of the FPS set on the Ticker
     if(intersect(evt.currentTarget, destination)){
       evt.currentTarget.alpha=0.2;
       box.graphics.clear();
       box.graphics.setStrokeStyle(3)
       .beginStroke("#0066A4")
       .rect(0, 0, destHeight, destWidth);

     }else{
       evt.currentTarget.alpha=1;
       box.graphics.clear();     box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
     }

});

//Mouse UP and SNAP====================
dragger.on("pressup", function(evt) {
  if(intersect(evt.currentTarget, destination)){
    dragger.x = destination.x + destWidth/2;
    dragger.y = destination.y + destHeight/2;
    dragger.alpha = 1;
    box.graphics.clear();     
    box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
    stage.update(evt);
  }
});

Here is the function that test the current draggable with the target:

//Tests if two objects are intersecting
//Sees if obj1 passes through the first and last line of its
//bounding box in the x and y sectors
//Utilizes globalToLocal to get the x and y of obj1 in relation
//to obj2
//PRE: Must have bounds set for each object
//Post: Returns true or false

  function intersect(obj1, obj2){
  var objBounds1 = obj1.getBounds().clone();
  var objBounds2 = obj2.getBounds().clone();

  var pt = obj1.globalToLocal(objBounds2.x, objBounds2.y);

  var h1 = -(objBounds1.height / 2 + objBounds2.height);
  var h2 = objBounds2.width / 2;
  var w1 = -(objBounds1.width / 2 + objBounds2.width);
  var w2 = objBounds2.width / 2;


  if(pt.x > w2 || pt.x < w1) return false;
  if(pt.y > h2 || pt.y < h1) return false;

  return true;
}


//Adds the object into stage
stage.addChild(destination, dragger, destination2, dragger2, destination3, dragger3);
stage.mouseMoveOutside = true;
stage.update();

*Sorry I don't have rep points to post more links showing other users posts or any images.


Solution

  • I was getting this error too. I'm also really new to EaselJS and Animate CC. What seems to have worked for me (I don't know if this is an actual fix, but it seems to be working for me). I tried using nominalBounds on it but that uses the original, untransformed size of the destination. so I tried this:

    desination.setBounds(desination.x, desination.y, desination.width, desination.height);
    

    I'd just stick that after you have the destination set up, but outside of the pressup, pressmove, or intersect functions.

    this * seems * to be working for me for now, let me know if it works for you. :)

    EDIT: also, I found this by the same guy. He added a few things to it for multiple destinations http://codepen.io/samualli/pen/azNroN/