javascript - 在 Canvas 上绘制多个矩形框,不要重叠

标签 javascript angularjs html canvas

我试图在 Canvas 图像上绘制多个(最多 6 个)矩形,但实际上并不让它们彼此重叠。这如何在 JavaScript 中完成? 我想不出可以用于此目的的逻辑..

编辑:

如何检测鼠标单击是否发生在任何一个绘制的矩形内,以便我可以再次在 Canvas 上移动矩形而不重叠?

最佳答案

要查明新的矩形是否会与任何现有的矩形重叠,您必须执行 3 项测试:

  1. 新矩形是否与任何现有矩形相交?
  2. 新矩形是否完全包含任何现有矩形?
  3. 现有的矩形是否完全包含新的矩形?

方法如下...

如果您有使用 JavaScript 对象定义的现有矩形,如下所示:

var rects=[];
rects.push({left:100,right:200,top:100,bottom:200});

然后您可以测试新矩形是否会与任何现有矩形重叠,如下所示:

var newRectangle={left:50,right:25,top:50,bottom:25};

function willOverlap(newRect){

    // shortcut to the new potential rect
    var r2=newRect;

    // test if one rect is completely inside another rect
    var isInside=function(rect1,rect2){
        return(rect2.left>=rect1.left && 
        rect2.right<=rect1.right && 
        rect2.top>=rect1.top &&
        rect2.bottom<=rect1.bottom);
    }

    // test if the new rect is overlapping any existing rect
    var isOverlapping=false;
    for(var i=0;i<rects.length;i++){
        var r1=rects[i];
        //
        var isIntersecting = !(r2.left>r1.right ||
        r2.right<r1.left ||
        r2.top>r1.bottom ||
        r2.bottom<r1.top);
        //
        var isContained= isInside(r1,r2) || isInside(r2,r1);
        //
        if(isIntersecting || isContained){
            isOverlapping=true;
        }
    }
    return(isOverlapping);
}

这里是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
  var BB=canvas.getBoundingClientRect();
  offsetX=BB.left;
  offsetY=BB.top;        
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

var isDown=false;
var startX,startY;

var rects=[];
var newRect;

$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});


function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  startX=parseInt(e.clientX-offsetX);
  startY=parseInt(e.clientY-offsetY);

  // Put your mousedown stuff here
  isDown=true;
}

function handleMouseUp(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mouseup stuff here
  isDown=false;

  if(!willOverlap(newRect)){
    rects.push(newRect);
  }
  drawAll();
}

function drawAll(){
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.lineWidth=1;
  ctx.strokeStyle='green';
  for(var i=0;i<rects.length;i++){
    var r=rects[i];
    ctx.strokeRect(r.left,r.top,r.right-r.left,r.bottom-r.top);
  }
}

function handleMouseOut(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mouseOut stuff here
  isDown=false;
}

function handleMouseMove(e){
  if(!isDown){return;}
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  newRect={
    left:Math.min(startX,mouseX),
    right:Math.max(startX,mouseX),
    top:Math.min(startY,mouseY),
    bottom:Math.max(startY,mouseY),
  }

  drawAll();
  ctx.strokeStyle = "lightgray";
  ctx.lineWidth = 3;
  ctx.strokeRect(startX,startY,mouseX-startX,mouseY-startY);

}


function willOverlap(newRect){

  // shortcut to the new potential rect
  var r2=newRect;

  // test if one rect is completely inside another rect
  var isInside=function(rect1,rect2){
    return(rect2.left>=rect1.left && 
           rect2.right<=rect1.right && 
           rect2.top>=rect1.top &&
           rect2.bottom<=rect1.bottom);
  }

  // test if the new rect is overlapping any existing rect
  var isOverlapping=false;
  for(var i=0;i<rects.length;i++){
    var r1=rects[i];
    //
    var isIntersecting = !(r2.left>r1.right ||
                           r2.right<r1.left ||
                           r2.top>r1.bottom ||
                           r2.bottom<r1.top);
    //
    var isContained= isInside(r1,r2) || isInside(r2,r1);
    //
    if(isIntersecting || isContained){
      isOverlapping=true;
    }
  }
  return(isOverlapping);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag to create a new rect.<br>New rect will be added if not overlapping.</h4>
<canvas id="canvas" width=300 height=300></canvas>

关于javascript - 在 Canvas 上绘制多个矩形框,不要重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31791152/

相关文章:

php - 将 iFrame 内容保存到 html 文件?

javascript - 在 IOS 上固定位置和倾斜

javascript - typescript / react : Module has no exported member

javascript - 组件内的组件 - VueJS

html - Angular ng-if 更改跨度文本

html - 两行之间文本的 HTML 和 CSS 代码是什么?

javascript - $watch 一个对象

javascript - 为父 div 的元素设置动态高度

javascript - 无法在 ng-repeat 中显示 ng-template

javascript - 在textarea中隐藏标签但要实现标签的效果