如何检测DOM-draggables和FabricJS形状之间的碰撞

时间:2015-05-27 06:48:49

标签: javascript html5 drag-and-drop fabricjs

我想在画布上拖动外部图像并且它与该画布对象相交时,找到画布中已存在的对象。这是我用于拖放的代码:

if (Modernizr.draganddrop) {
    // Browser supports HTML5 DnD.
    // Bind the event listeners for the image elements
    var images = document.querySelectorAll('#images img');
    [].forEach.call(images, function (img) {
        img.addEventListener('dragstart', handleDragStart, false);
        img.addEventListener('dragend', handleDragEnd, false);
    });
    // Bind the event listeners for the canvas
    var canvasContainer = document.getElementById('canvas-container');
    canvasContainer.addEventListener('dragenter', handleDragEnter, false);
    canvasContainer.addEventListener('dragover', handleDragOver, false);
    canvasContainer.addEventListener('dragleave', handleDragLeave, false);
    canvasContainer.addEventListener('drop', handleDrop, false);
} else {
    // Replace with a fallback to a library solution.
    alert("This browser doesn't support the HTML5 Drag and Drop API.");
}

上面提到的回调函数是相应定义的。

我已经知道的是,当两个对象存在于画布中时,我们可以找到它们之间的交集。链接:http://fabricjs.com/intersection/

但我的问题是,当我将画布从画布外部拖到画布区域并且它与画布对象相交时,我需要捕捉对象。

非常感谢任何帮助。感谢。

1 个答案:

答案 0 :(得分:6)

关于碰撞测试

基本形状往往有两种形式:矩形和圆形的。

您需要进行这些测试,看看是否有任何这些基本形状发生碰撞:

function rectsColliding(r1,r2){
    return(!(
        r1.x           > r2.x+r2.width  ||
        r1.x+r1.width  < r2.x           ||
        r1.y           > r2.y+r2.height ||
        r1.y+r1.height < r2.y
    ));
}

function circlesColliding(c1,c2){
    var dx=c2.x-c1.x;
    var dy=c2.y-c1.y;
    var sumR=c1.radius+c2.radius;
    return( dx*dx+dy*dy <= sumR*sumR );
}


function rectCircleColliding(circle,rect){
    var distX = Math.abs(circle.x - rect.x-rect.w/2);
    var distY = Math.abs(circle.y - rect.y-rect.h/2);
    if (distX > (rect.w/2 + circle.r)) { return false; }
    if (distY > (rect.h/2 + circle.r)) { return false; }
    if (distX <= (rect.w/2)) { return true; } 
    if (distY <= (rect.h/2)) { return true; }
    var dx=distX-rect.w/2;
    var dy=distY-rect.h/2;
    return (dx*dx+dy*dy<=(circle.r*circle.r));
}

有关draggable

的重要通知

原生html5 draggable系统仍然存在一些跨浏览器的不一致性。当拖动拖拽时,很难获得准确的[x,y]位置。相反,您可以使用jQueryUI可拖动系统来平滑浏览器之间的不一致。

测试拖动的DOM元素是否与FabricJS形状碰撞的计划

  • 在draggable上收听dragmove事件,
  • 在当前[x,y]位置创建一个draggable的边界框,
  • 创建Fabric.Rect的边界框。此边界框必须由窗口中FabricJS画布的位置
  • 偏移
  • 调用rectsColliding函数来测试2个边界框是否发生碰撞,
  • 做任何你需要的东西,取决于DOM-draggable&amp; Fabric.Rect正在碰撞。

以下是示例代码和演示:

// attach the canvas's bounding box to itself
var canvasElement=document.getElementById("c");
canvasElement.bb=canvasElement.getBoundingClientRect();

// create a wrapper around native canvas element (with id="c")
var canvas = new fabric.Canvas('c');
var rect;

// load an image and begin...
var image1=new Image();
image1.onload=function(){
  createFabrics();
  createDraggables();
}
image1.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";

// create a fabric rect and add it to the stage
function createFabrics(){
  // create a rectangle object
  rect = new fabric.Rect({
    left: 100,
    top: 20,
    fill: 'green',
    width: 100,
    height: 75,
    lockMovementX:true,
    lockMovementY:true,
    lockScalingX:true,
    lockScalingY:true,
    lockRotation:true,
    hasControls:false,
  });
  rect.bb=rect.getBoundingRect();

  // "add" rectangle onto canvas
  canvas.add(rect);
  canvas.renderAll();
}

// Make the previously created image draggable
// Detect collisions between the image and the FabricJS rect
function createDraggables(){

  var $house=$("#house");
  var $canvas=$("#c");

  // make the canvas element a dropzone
  $canvas.droppable({ drop:dragDrop, hoverClass:'drop-hover' });

  // make the house draggable
  $house.draggable({
    helper:'clone',
    // optional event handlers are...
    start:dragstart,
    drag:dragmove,
    stop:dragend,
  });

  // set the data payload
  $house.data("image",image1); // key-value pair

  function dragstart(e,ui){}
  function dragend(e,ui){}
  function dragDrop(e,ui){}
  function dragmove(e,ui){
      var target=e.target;
      var tbb={
        left:ui.offset.left-canvasElement.bb.left,
        top:ui.offset.top-canvasElement.bb.top,
        width:target.width,
        height:target.height
      }
      if( rectsColliding(tbb,rect.bb) ){
        rect.fill='red';
        canvas.renderAll();
      }else{
        rect.fill='green';
        canvas.renderAll();
      }
  }


  function rectsColliding(r1,r2){
    return(!(
      r1.left          > r2.left+r2.width  ||
      r1.left+r1.width < r2.left           ||
      r1.top           > r2.top+r2.height  ||
      r1.top+r1.height < r2.top
    ));
  }


}  // end createDraggables
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>

<script src="http://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>

<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>

<h4 id=hit>Drag house over green FabricJS rect.<br>Rect will turn red during collisions.</h4>
<img id="house" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png"><br>
<canvas id='c' width=300 height=150></canvas>