Proper way to approach loadable masks in Fabric.js

后端 未结 1 1218
不思量自难忘°
不思量自难忘° 2021-01-16 23:19

I have this bounty open Fabricjs mask object with transformation when trying to mask objects with Fabric.js.

The tool I\'m developing should allow users

1条回答
  •  孤街浪徒
    2021-01-17 00:14

    I extended fabric.Image with some custom attributes. Also I attached the mask on fabric.Image. For fabric.Image.fromObject after the image is loaded I need it to load also the mask( which I know is a path) and attach to image. This is a fast implementation. I'm pretty sure this code can be simplified. Please tell me know if something is not clear enougth

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

    UPDATE I updated the code to fix the problem with angle from here:

    0 讨论(0)
提交回复
热议问题