Fabric.js fillRule - evenodd(减去形状)

Fabric.js fillRule - evenodd (subtract shapes)

我正在尝试使用 fabric.js

中的 fillRule = 'evenodd' 在多边形中打洞

globalCompositeOperation 对我不起作用,因为我需要在多边形孔中查看形状 like this

这是我的代码:fiddle

有2个例子:

当我为 fabric.js 多边形设置 fillRule: 'evenodd' 时,它将转到结构函数并将上下文填充设置为 'eveneodd'

_renderFill: function(ctx) {
   ...
      if (this.fillRule === 'evenodd') {
        ctx.fill('evenodd');
      }
      ...
      ctx.restore();
    },

但是还是不行。 请告诉我如何使用 'enevodd' if fabric.js

'evenodd' 填充规则适用于一个织物对象。您不能将此规则用于单独的对象并将它们组合在一起,即使您使用的是组对象。在单独发生的形状的组渲染中,这意味着每个对象调用:

context.fill(); 

context.fill('evenodd')

Fabric.js 缺少对多个对象使用 'evenodd' 规则的功能。

这里有一些变通方法,如何对一个主题多边形和多个减去的多边形使用 'evenodd' 规则。

步骤:

  1. 找到减去多边形的最近点到主题多边形的最后一个点。
  2. 按最接近的索引对相减的多边形数组进行排序
  3. 将主题和减去的多边形合并为一个。

这里是fiddle.

此代码需要改进。它给出了如何使用 'evenodd' 规则在多边形中打孔的想法。

var canvas = new fabric.Canvas('c', { selection: false });
var polygons = [];

var subjectPoly = [{x:30,y:10}, {x:300,y:50}, {x:20,y:290}];
var subtractPoly1 = [{x:50,y:50}, {x:200,y:140}, {x:220,y:40}];
var subtractPoly2 = [{x:10,y:10}, {x:300,y:200}, {x:60,y:150}];
var subtractPoly = [];
subtractPoly.push(subtractPoly1);
subtractPoly.push(subtractPoly2);

 var result = combinePolygonArrays(subjectPoly,sortPolygonArray(subtractPoly, closetPoint(subjectPoly[0],subtractPoly)));
  var poly1 = new fabric.Polygon(result, {
    fillRule: 'evenodd',
     fill: 'green',
     selectable: false      });      
  canvas.add( poly1);
var c= (new fabric.Circle({
    radius: 50,
    left: 125,
    top: 50,
    fill: 'red'
}));

canvas.add(c);
c.sendToBack();
  
function closetPoint(subjPolyPoint, subtrPoly){
 var minIndexes = [];
 for (var j in subtrPoly){
   var minLength = Length(subjPolyPoint, subtrPoly[j][0]);
   var minIndex = 0;
    for (var i = 1; i < subtrPoly[j].length; i++){
      var newLength = Length(subjPolyPoint, subtrPoly[j][i])
        if (minLength > newLength){
          minLength = newLength;
          minIndex = i;
        }
    }
    minIndexes.push({arrayIndex: j, elementIndex: minIndex});
  }
    return minIndexes;
}

function Length(point1, point2) {      
    var x1 = point1.x,
        x2 = point2.x,
        y1 = point1.y,
        y2 = point2.y;
      return Math.sqrt((x1 -= x2) * x1 + (y1 -= y2) *y1);
}

function sortPolygonArray(array, indexes){
var result = [];
 for (var i in indexes){
   var newArray = [];
   var originalLength = array[indexes[i].arrayIndex].length;
   while (newArray.length != originalLength){
      if (indexes[i].elementIndex == originalLength){
        indexes[i].elementIndex = 0;
      }
     newArray.push(array[indexes[i].arrayIndex][indexes[i].elementIndex]);
     indexes[i].elementIndex++;
   }
   result.push(newArray);
  }
 
  return result;
}

function combinePolygonArrays(subjPoly, subtrPoly){
 var newArray = subjPoly;
  var lastSubjectPoint = subjPoly[subjPoly.length - 1];
  for (var i in subtrPoly){
   var firstSubtractedPoint = subtrPoly[i][0];
    newArray = newArray.concat(subtrPoly[i]);
   newArray.push(firstSubtractedPoint);
   newArray.push(lastSubjectPoint);
  }
  return newArray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.11/fabric.js"></script>
<canvas id="c" width="500" height="350" style="border:1px solid #ccc"></canvas>