总结使用fabric实现图片编辑器主要用到的知识点

对象

  • canvas
 var canvas = new fabric.Canvas('canvasId');
  • rect
var rect = new fabric.Rect();
  • circle
 var circle = new fabric.Circle({
  angle: 30,
  radius: 10,
  originX: 'center'// 坐标系,默认是左上 
  originY:'center'
 });
  • image
var img = document.getElementById("img");
image = new fabric.Image(img, {
	clipPath: new fabric.Rect({
          top: 0,
          left: 0,
          width: this.canvas.width,
          height: this.canvas.height,
          fill: "silver",
          stroke: "silver",
          strokeDashArray: [5, 5],
          absolutePositioned: true,
          lockMovementX: true, // 禁止水平移动
          lockMovementY: true, // 禁止垂直移动
          hasRotatingPoint: false, // 无旋转点
          hasControls: true, // 编辑框
          selectable: false // 不可选中
    })
});
image.crossOrigin = "anonymous"; // 可跨域访问图片

clipPath是裁剪(可见)范围
创建对象后,将对象加入到画布,然后重新渲染画布,画布上才会显示对象
fabric中新建图片对象有两种方法
一种是通过获取页面中的img标签,如上,但是要等图片加载完再渲染进画布里,img标签有一个load方法,在该方法里将图片渲染进画布。image.setSrc()是个回调方法,也会造成图片加载延缓的问题,可以:

var self = this;
 this.image.setSrc(this.imgSrc_clip, function(img){
          self.image.set({
            left: self.newImgLeft,
            top: self.newImgTop,
            scaleX: self.newImgScaleX,
            scaleY: self.newImgScaleY,
            angle: self.imgAngle,
            width: self.newImgWidth,
            height: self.newImgHeight
          });
          ......
          self.canvas.renderAll(); // 保证正确加载完图片后再渲染画布
 });

另一种是通过URL:

fabric.Image.fromURL('my_image.png', function(oImg) {
  canvas.add(oImg);
});

创建完对象后要加入到画布上,renderAll(),对象才会显示在画布上

canvas.add(rect, img); // 后加入的层级会高
canvas.preserveObjectStacking = true; // 禁止选中图层时自定义顶部
canvas.selection = false; // canvas无法被选中
fabric.textureSize = max; // 纹理尺寸,默认值是2048,如果图片大小超过这个值,图片会被截掉
fabric.filterBackend = fabric.initFilterBackend(); // 初始化后端渲染器,这两个属性与图片的过滤器有关
this.canvas.clear();  // 清除画布上的所有对象
canvas.renderAll(); // 渲染画布,只有重新渲染画布后才能看到更改后的画布
canvas.hoverCursor = ''; // 设置光标

var items = canvas.getObjects(); // 获得画布上的所有对象
// 设置对象的某个属性值,比如第 0 个对象的 id
tems[0].id ="items_id0" 或  items[0].set("id","items_id0") 
// 获得画布中对象的某个属性,比如 第0 个对象的 id
items[0].id;
//或
items[0].get("id");
canvas.setActiveObject(items[i]); // 设置画布上的某个对象为活动对象
canvas.getActiveObject() // 获得画布上的活动对象
canvas.discardActiveObject(); // 取消画布中的所有对象的选中状态

对象相关重要属性和方法

  • 对象居中设置
t.center();    //全部居中
t.centerH();   //水平居中
t.centerV();   //垂直居中
t.setCoords(); //注:必须设coords以上设置才会有效。setCoords是设置对象四角的坐标
  • 设置对象的层级
canvas.sendBackwards(t) //向下跳一层
canvas.sendToBack(t)    //向下跳底层:
canvas.bringForward(t)  //向上跳一层:
canvas.bringToFront(t)  //向上跳顶层:
//或者:
t.sendBackwards();
t.sendToBack();
t.bringForward();
t.bringToFront();
  • 其他一些样式
笔触
stroke: "silver", // 颜色
strokeWidth: 5, // 大小
填充
fill: "rgba(255, 255, 255, 0)",
编辑框
hasControls: true,
cornerColor: "#F5A623", // corner 是编辑框上的顶点
cornerSize: 7,
rect.setControlsVisibility({
          mt: false,
          mr: false,
          mb: false,
          ml: false
});

setCoords()时set的点

可见性
opacity:1, // 不透明度
visible: false 
缩放
this.image.scaleToWidth(); // 按给定的宽将整个图片缩放,高也会按比例跟着改变
this.image.scaleToHeight();

// 如果想将对象分别按给的宽高缩放
this.image.set("scaleX", this.image.getScaledWidth() / this.image.width);
this.image.set("scaleY", this.image.getScaledHeight() / this.image.height);
图片滤镜

图片滤镜这部分官方有demo

http://fabricjs.com/image-filters

applyFilter(index, filter) {
      this.image.filters[index] = filter;
      this.image.applyFilters();
      this.canvas.renderAll();
    },
applyFilterValue(index, prop, value) {
      if (this.image.filters[index]) {
        this.image.filters[index][prop] = value;
        this.image.applyFilters();
        this.canvas.renderAll();
      }
},
toApplyFilters(){
      this.applyFilter(0, new fabric.Image.filters.Brightness({
          brightness: parseFloat(this.brightness)
        })
      );
      this.applyFilter(1, new fabric.Image.filters.Contrast({
          contrast: parseFloat(this.contrast)
        })
      );
      this.applyFilter(2, new fabric.Image.filters.Saturation({
          saturation: parseFloat(this.saturation)
        })
      );
      this.applyFilter(3, new fabric.Image.filters.Blur({
          value: parseFloat(this.blur)
        })
      );
      this.applyFilter(4, new fabric.Image.filters.Gamma({
          gamma: [this.gammaRed, this.gammaGreen, this.gammaBlue]
        })
      );
      this.applyFilter(5, new fabric.Image.filters.Convolute({
          matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0]
        })
      );
      this.applyFilter(6, new fabric.Image.filters.BlendColor({
          color: this.blendColor,
          mode: this.blendMode,
          alpha: this.blendAlpha
        })
      );
},
	// 亮度
    changeBrightness() {
      this.applyFilterValue(0, "brightness", parseFloat(this.brightnessValue));
    },
    // 对比度
    changeContrast() {
      this.applyFilterValue(1, "contrast", parseFloat(this.contrastValue));
    },
    // 饱和度
    changeSaturation() {
      this.applyFilterValue(2, "saturation", parseFloat(this.saturationValue));
    },
    // 混合颜色
    changeBlend(prop) {
      if (prop == "color")
        this.applyFilterValue(6, "color", this.blendColorValue);
      else if (prop == "mode")
        this.applyFilterValue(6, "mode", this.blendModeValue);
      else if (prop == "alpha")
        this.applyFilterValue(6, "alpha", parseFloat(this.blendAlphaValue));
    },
    // 锐化
    changeSharpen() {
      var a = -(this.sharpenValue - 1) / 4;
      this.applyFilterValue(5, "matrix", [
        0,			a,			0,
        a,  this.sharpenValue,	a,
        0,			a,			0
      ]);
    },
    // 伽马
    changeGamma(color) {
      this.applyFilterValue(4, "gamma", [this.gammaRedValue, this.gammaGreenValue, this.gammaBlueValue]);
    },
    // 模糊
    changeBlur() {
      this.applyFilterValue(3, "blur", parseFloat(this.blurValue));
    },

事件

鼠标事件

mousedown,mousemove,mouseup,mouseover,mouseout,mousewheel

// 绑定
this.image.on({
	mousewheel: opt => {
    	if (opt && opt.e) {
        	opt.e.preventDefault();
            opt.e.stopPropagation();
        }
        ......
    }
});
// 取消绑定
this.image.off("mousewheel");

对象事件

“object:modified”, “object:selected”, “object:moving”, “object:scaling”, “object:rotating”, “object:added”, and “object:removed”

this.canvas.on('object:scaling', function () {})
// 或
this.mask.on({
          scaling: e => {
            ......
         }
});

绑定事件用on, 移除用off

序列化与反序列化

  • 对象转出成base64
canvas.toDataURL()({
        format: "png", // 背景色为透明
        multiplier: this.image.width / this.image.getScaledWidth(), // 乘以比例
        top: this.image.top, 
        left: this.image.left,
        width: this.image.getScaledWidth(),
        height: this.image.getScaledHeight()
});

可以通过 left、top、width、height 定位要转出的内容

  • toJSON(实质上是一个字符串化的toObject方法)
JSON.stringify(canvas); // 是字符串
canvas.toJSON(); // 将画布属性转成json数据,是一个对象
  • toObject返回与相同的表示toJSON形式,而无需字符串序列化
canvas.toObject()

fabric还提供了一个扩展属性的方法,在toObject()时可以带上扩展的属性

this.image.toObject = (function(toObject) {
     return function() {
	     return fabric.util.object.extend(toObject.call(this), {
	        name: this.name,
	     });
     };
})(this.image.toObject);
this.image.name = "image";

toObject() 和 toJson() 时都会带上这个扩展的name属性:
在这里插入图片描述
但是注意,在反序列后这个属性就会丢失,要重新添加

  • 反序列化
this.canvas.loadFromJSON(canvas.toJSON());
// 或
var self = this; // 在Vue中,因为作用域的不同,this的指向也是不同的,所以是无法获取this.image的
// 这个方法会循环读取json数据里的objects数组
this.canvas.loadFromJSON(currentObj,this.canvas.renderAll.bind(this.canvas),
   function(o, object) {   // o 是对象,object是类,我们可以根据需要赋给画布上相应的类或对象
   	  if(object.name == "image"){
   	  		self.image = object; // 将json数据重新组装成对象
   	  		self.image.toObject = (function(toObject) {
                return function() {
                  return fabric.util.object.extend(toObject.call(this), {
                    name: this.name,
                    scaledWidth: this.scaledWidth,
                    scaledHeight: this.scaledHeight,
                  });
               };
            })(self.image.toObject);
            self.image.name = 'watermark';
   	  }
   }
);

另外

我给canvas动态绑定了宽高:

mounted() {
    this.canvasWidth = window.innerWidth - 60;
    this.canvasHeight = window.innerHeight - this.$refs.nav.$el.offsetHeight - 40;
}

但是在Vue中,DOM的变动是异步的。如果想要得到数据更新后的dom对象,并执行操作。初始化时可以写在mounted中,此外可以写在nextTick这个api中。Vue.nextTick(callback,执行上下文环境的this) this.$nextTick() 这是异步调用的函数,它的回调必须等待所有数据修改完毕,进行视图更新后被调用。

this.$nextTick(() => {
    this.canvasHeight = window.innerHeight - this.$refs.nav.$el.offsetHeight - 40;
    this.canvas.setHeight(this.canvasHeight);
})
发布了8 篇原创文章 · 获赞 0 · 访问量 3047
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览