在Fabric.js中处理可加载蒙版的正确方法

时间:2018-10-25 23:05:15

标签: fabricjs

当尝试用Fabric.js遮罩对象时,我有这个赏金开放Fabricjs mask object with transformation

我正在开发的工具应允许用户在图像对象上绘制蒙版,并在蒙版之前或之后对该对象应用变换(倾斜比例旋转等)。我即将获得此结果,但是有角度的对象仍无法正常工作。

我也在尝试使用toJSONloadFromJSON将该对象保存到数据库中,但是经过几天的尝试,我意识到该解决方案将无法工作,因为从JSON加载时无法访问ctx范围,因此它们会引发错误。

    clipTo: function(ctx) {
        mask.set({
            left:
                -object.width / 2 -
                (mask.width / 2) * originalMaskScaleX -
                originalObjLeft / originalObjScaleX,
            top:
                -object.height / 2 -
                (mask.height / 2) * originalMaskScaleY -
                originalObjTop / originalObjScaleY,
            objectCaching: false
        });
        mask.render(ctx);
    }

Fabric.js是解决此问题的正确方法吗?我应该使用其他东西吗?如果可以使用Fabric.js完成操作,什么是正确的方法?

1 个答案:

答案 0 :(得分:2)

我扩展了fabric.Image的自定义属性。 我还把面具戴在fabric.Image上。 对于fabric.Image.fromObject,在加载图像后,我还需要它同时加载mask(我知道这是一个路径)并附加到图像上。 这是一个快速的实现。我很确定这段代码可以简化。 请告诉我是否有不清楚的信息

 

    canvas = new fabric.Canvas("canvas", {
   backgroundColor: "lightgray",
   width: 1280,
   height: 720,
   preserveObjectStacking: true,
   selection: false,
   stateful: true
 });

 canvas.isDrawingMode = true;
 canvas.freeDrawingBrush.color = "black";
 canvas.freeDrawingBrush.width = 2;

 canvas.on("path:created", function(options) {

   clip(options.path);
 });

 function clip(path) {
   canvas.isDrawingMode = false;
   canvas.remove(path);

   let mask = new fabric.Path(path.path, {
     top: object.top,
     left: object.left,
     objectCaching: false,
     strokeWidth: 0,
     scaleX: 1 / object.scaleX,
     scaleY: 1 / object.scaleY,
     pathOffset: {
       x: 0,
       y: 0
     }
   });
   object = canvas.getObjects()[0];
   object.originalObjLeft = object.left,
     object.originalObjTop = object.top,
     object.originalMaskScaleX = mask.scaleX,
     object.originalMaskScaleY = mask.scaleY,
     object.originalObjScaleX = object.scaleX,
     object.originalObjScaleY = object.scaleY;
     var transformedTranslate = object.translateToGivenOrigin({
        x: object.left,
        y: object.top
    }, object.originX, object.originY, 'center', 'center');
    object.originalTransformLeft = transformedTranslate.x - object.getCenterPoint().x;
    object.originalTransformTop = transformedTranslate.y - object.getCenterPoint().y;
    object.originalAngle = object.angle;
    
    
   object.clipMask = mask;
   object.set({
     clipTo: function(ctx) {
			 
        ctx.save();
        ctx.rotate(-this.originalAngle * Math.PI / 180);

        ctx.translate(this.originalTransformLeft / this.originalObjScaleX, this.originalTransformTop / this.originalObjScaleY)

       
       
       this.clipMask.set({
         left: -object.width / 2 - (this.clipMask.width / 2 * this.originalMaskScaleX) - this.originalObjLeft / this.originalObjScaleX,
         top: -object.height / 2 - (this.clipMask.height / 2 * this.originalMaskScaleY) - this.originalObjTop / this.originalObjScaleY,
         objectCaching: false
       });
       this.clipMask.render(ctx);
        ctx.restore();
     }
   });

   canvas.requestRenderAll();
 }

 // image

 let image = new Image();


 image.onload = function() {
   object = new fabric.Image(image, {
     width: 500,
     height: 500,
     scaleX: 0.8,
     scaleY: 0.8,
      angle: 45,
     top: 50,
     left: 100
   });

   canvas.add(object);
 };

 image.src = "http://i.imgur.com/8rmMZI3.jpg";

 fabric.util.object.extend(fabric.Image.prototype, {
   clipMask: null,
   originalObjLeft: 0,
   originalObjTop: 0,
   originalMaskScaleX: 1,
   originalMaskScaleY: 1,
   originalObjScaleX: 1,
   originalObjScaleY: 1,
   originalAngle:0,
   originalTransformLeft:0,
   originalTransformTop:0
 });
 fabric.Image.prototype.toObject = (function(toObject) {
   return function(propertiesToInclude) {
     return fabric.util.object.extend(toObject.call(this, propertiesToInclude), {
       clipMask: this.clipMask ? this.clipMask.toObject(propertiesToInclude) : null,
       originalObjLeft: this.originalObjLeft,
       originalObjTop: this.originalObjTop,
       originalMaskScaleX: this.originalMaskScaleX,
       originalMaskScaleY: this.originalMaskScaleY,
       originalObjScaleX: this.originalObjScaleX,
       originalObjScaleY: this.originalObjScaleY,
       originalAngle:this.originalAngle,
       originalTransformLeft:this.originalTransformLeft,
       originalTransformTop:this.originalTransformTop
     });
   }
 })(fabric.Image.prototype.toObject);

 fabric.Image.fromObject = (function(fromObject) {
   return function(_object, callback) {
     fromObject.call(this, _object, (function(callback, _object) {
       return function(image) {
         if (image.clipMask) {
           fabric.Path.fromObject(image.clipMask, (function(callback) {
             return function(path) {
               path.pathOffset.x = 0;
               path.pathOffset.y = 0;
               image.clipMask = path;
               callback(image);
             }
           })(callback))
         } else {
           callback(image);
         }
       }
     })(callback, _object));
     return;
   }
 })(fabric.Image.fromObject)




 $("#button1").on('click', function() {
   let dataJSON = canvas.toJSON();
   canvas.clear();
   canvas.loadFromJSON(
     dataJSON,
     canvas.renderAll.bind(canvas));
 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<button id="button1">SAve/Load JSON</button>
<div class="canvas__wrapper">
  <canvas id="canvas" width="1280" height="720"></canvas>
</div>

更新 我更新了代码,从here角度解决了这个问题: