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

How to detect collisions between DOM-draggables and FabricJS shapes

我想在将外部图像拖到 canvas 上并与 canvas 对象相交时立即找到 canvas 中已经存在的对象。这是我用于拖放的代码:

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.");
}

上述回调函数已相应定义。

我已经知道,当两个对象出现在 canvas 中时,我们可以找出它们之间的交集。 Link: http://fabricjs.com/intersection/

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

如有任何帮助,我们将不胜感激。谢谢

关于碰撞测试

基本形状往往有两种风格:矩形和圆形。

您将需要这些测试来查看这些基本形状是否发生碰撞:

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 系统仍然存在一些跨浏览器的不一致性。拖动 draggable 时很难获得准确的 [x,y] 位置。相反,您可以使用 jQueryUI 可拖动系统,它消除了浏览器之间的不一致。

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

  • 监听可拖动对象上的 dragmove 事件,
  • 在其当前 [x,y] 位置创建可拖动的边界框,
  • 创建 Fabric.Rect 的边界框。此边界框必须偏移 FabricJS canvas 在 window,
  • 中的位置
  • 调用rectsColliding函数来测试2个边界框是否发生碰撞,
  • 根据 DOM-draggable 和 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/Whosebug/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/Whosebug/house32x32transparent.png"><br>
<canvas id='c' width=300 height=150></canvas>