如何限制透明矩形区域内的对象 - FabricJS?

How to Limit Object inside Transparent Rectangle Area - FabricJS?

我正在使用 FabricJS in my side. My Idea is to set the background image using setBackgroundImage from fabric, also i add specific area of transparent rectangle with size and position fetch from JCrop 实现设计器功能。现在来问我的问题,我想限制透明矩形特定区域内的对象放置。假设我想添加应该在那个有限区域内的 text/image/shapes,我能够实现背景图像、透明矩形的位置甚至圆形对象,但我无法找到限制对象的细节将其放置在透明矩形内并且只在那个地区。

这是我的下面的代码和工作 fiddle,如果你在 fiddle 图像中看到它,你需要 select 裁剪部分和下面 canvas具有透明矩形的背景,与裁剪 selection 相同。现在我想限制对象放置在那个透明矩形中,现在我可以将对象放置在 canvas.

中的任何位置

HTML

   <img src="https://images.unsplash.com/photo-1595438337199-d50ba5072c7e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=330&q=80" id="target">

   <div class="canvas-container" style="position: relative; user-select: none;">
     <canvas id="c1" width="600" height="600" style="border:1px solid #ccc; position: absolute;  left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas>
   </div>

JS

function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
  var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
  return {
    width: srcWidth * ratio,
    height: srcHeight * ratio,
    aspectratio: ratio
  };
}

jQuery(function($) {
    //alert("Testing");
  var img = new Image();
  img.onload = function() {
    var data = calculateAspectRatioFit(this.width, this.height, '400', '600');
    console.log(data);
    jQuery('#target').attr('width', data.width);
    jQuery('#target').attr('height', data.height);
    jQuery('#pdr-drawing-area').html("Aspect Ratio: " + data.aspectratio);
    const stage = Jcrop.attach('target');
    stage.listen('crop.change', function(widget, e) {
      const pos = widget.pos;
      console.log(pos.x, pos.y, pos.w, pos.h);
      //fabric js
      var canvas = new fabric.Canvas('c1');
      var center = canvas.getCenter();
      var img = 'https://images.unsplash.com/photo-1595438337199-d50ba5072c7e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=330&q=80';
      canvas.setBackgroundImage(img, function() {
        canvas.backgroundImage && canvas.backgroundImage.scaleToWidth(data.width);
        canvas.backgroundImage && canvas.backgroundImage.scaleToHeight(data.height);
        //canvas.sendToBack(img);
        canvas.renderAll();
      });
      console.log(pos.x * data.aspectratio);
      var rect = new fabric.Rect({
        left: pos.x,
        top: pos.y,
        fill: 'transparent',
        width: (pos.w),
        height: (pos.h),
        strokeDashArray: [5, 5],
        stroke: "black",
        selectable: false,
        evented: false,
        //visible: false
      });



      canvas.add(new fabric.Circle({
        radius: 30,
        fill: '#f55',
        top: pos.y + 2,
        left: pos.x + 2
      }));

      canvas.add(rect);
      canvas.setHeight(data.height);
      canvas.setWidth(data.width);
      canvas.renderAll();
    });
  },
   img.src = 'https://images.unsplash.com/photo-1595438337199-d50ba5072c7e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=330&q=80';
});

这是一个如何在 FabricJS 中限制移动的例子。
我正在使用 canvas 的有状态 属性,请参阅下面的 function objectMoving

var canvas = new fabric.Canvas("canvas");
canvas.stateful = true;

function inside(p, vs) {
    var inside = false;
    for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
        var xi = vs[i].x, yi = vs[i].y;
        var xj = vs[j].x, yj = vs[j].y;
        var intersect = yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;
        if (intersect) inside = !inside;
    }
    return inside;
}

function getCoords(rect) {
    var coords = []
    coords.push(rect.aCoords.tl);
    coords.push(rect.aCoords.tr);
    coords.push(rect.aCoords.br);
    coords.push(rect.aCoords.bl);
    coords.push(rect.aCoords.tl);
    return coords;
}

function objectMoving(e) {
    var cCoords = getCoords(parent);
    var inBounds = inside({ x: e.target.left + 30, y: e.target.top + 30 }, cCoords);

    if (inBounds) {
        e.target.setCoords();
        e.target.saveState();
    } else {
        e.target.left = e.target._stateProperties.left;
        e.target.top = e.target._stateProperties.top;
    }
}

var boundary = new fabric.Rect({
    width: 310, height: 170,
    left: 5, top: 5,
    selectable: false,
    strokeDashArray: [5, 2],
    stroke: "blue",
    fill: "transparent"
});

var parent = new fabric.Rect({
    width: 250, height: 110,
    left: 35, top: 35,
    selectable: false,
    strokeDashArray: [2, 5],
    stroke: "black",
    fill: "transparent"
});

var child = new fabric.Circle({
    radius: 30,
    fill: "rgba(255,0,0,0.8)",
    top: 50, left: 50,
    hasControls: false,
});

canvas.add(boundary);
canvas.add(parent);
canvas.add(child);
canvas.on("object:moving", objectMoving);
<canvas id="canvas" width="400" height="180"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>

function inside 我使用的是光线投射算法,您可以在这里阅读更多相关信息: https://github.com/substack/point-in-polygon/blob/master/index.js
我更喜欢这个算法,因为它为以后允许更复杂的形状作为父边界打开了大门,它可以处理任何形状的多边形。

如果您需要有关该代码的任何说明,请告诉我。


现在您确实需要将其集成到您的项目中,并在“JCrop”选项中的用户更改时动态更改父边界