fabric.js学习

一,前言

1.fabric [ˈfæbrɪk'] 是一个功能强大的运行在HTML5 canvasJavaScriptfabriccanvas提供了一个交互式对象模型,通过简洁的api就可以在画布上进行丰富的操作。

2.可以使用包管理工具直接安装:npm install fabric

3.fabric兼容pc端和移动端,不支持运行在小程序环境下

二,初始化画布

1.首先创建一个canvas元素,作为容器

<canvas id="mapCanvas" width="350" height="200">canvas>

2.实例化一个canvas上下文对象,接管原生容器,根据使用api的不同,初始化后的画布可以分为 可交互不可交互 两种

import { fabric } from "fabric";
//可交互画布,用于需要编辑图片等场景
const canvasCtx = new fabric.Canvas("mapCanvas", {
    enableRetinaScaling: true,
    perPixelTargetFind: true, // 对象基于像素检测
    skipTargetFind: true,
    
    //框选
    selection: true, //是否支持鼠标框选
    selectable: true, //是否支持鼠标框选
    selectionColor: "rgba(255,255,255,0.3)", // 鼠标框选背景色
    selectionLineWidth: 1, // 画布中鼠标框选边框
    
    preserveObjectStacking: true, //取消被选中的元素会处于顶层的默认行为
    backgroundColor: '#fff', //画布背景颜色
  });

//不可交互画布, 用于画海报等场景,鼠标事件都无效
const canvasCtx = new fabric.StaticCanvas("mapCanvas",{})

3.创建canvas元素时可直接设置widthheight ,当一开始不确定宽高时可不设置,之后使用setWidthsetHeight动态设置

canvasCtx.setWidth(400)
canvasCtx.setHeight(400)

4.相应的可以使用getWidthgetHeight获取canvas的宽高

canvasCtx.getWidth()
canvasCtx.getHeight()

三,基础图像绘制

1.fabric已经内置了许多基础图像,调用相应api,可直接应用,免去了原生繁琐的过程。

(1)矩形 [ 圆角矩形 ]
(2)圆
(3)椭圆
(4)直线
(5)曲线
(6)折线
(7)虚线
(8)多边形
(9)三角形

2.矩形绘制 fabric.Rect

(1)使用fabric.Rect绘制矩形,主要配置项为左上角的(left,top)widthheight

let forbiddenArea = new fabric.Rect({
	//主要配置属性
    left: 0, //距离画布左侧的距离,单位是像素
    top: 0, //距离画布上边的距离
    width: 100,
    height: 100,
	
	//样式配置属性
    fill: "#fef0f08a", //填充的颜色
    stroke: "#fab6b6", //边界的颜色
	//通过配置rx,ry,可以让矩形具有圆角
    rx:20,
    ry:20,
 });

2.绘制圆 fabric.Circle

(1)使用fabric.Circle绘制圆,主要配置项为中心点(left,top)和半径radius

let circle = new fabric.Circle({
  //主要配置属性
  left: 10, //距离左边的距离
  top: 10, //距离上边的距离
  radius: 2, //圆的半径
  
  //样式配置属性
  fill: "#eee", //填充的颜色
  stroke: "#fab6b6", //边界的颜色
});

3.绘制椭圆 fabric.Ellipse

(1)使用fabric.Ellipse绘制圆,主要配置项为中心点(left,top)和长短半轴rxry

let circle = new fabric.Ellipse({
  //主要配置属性
  left: 10, //距离左边的距离
  top: 10, //距离上边的距离
  rx: 10, 
  ry: 10, 
  
  //样式配置属性
  fill: "#eee", //填充的颜色
});

4.绘制直线 fabric.Line

(1)使用fabric.Line绘制直线,主要配置项为两个点x1,y1,x2,y2

let line = new fabric.Line([x1,y1,x2,y2],{
    stroke: "#c45656",
    strokeWidth: 3,
});

5.绘制线段 fabric.Polyline

(1)使用fabric.Polyline绘制线段,主要配置项为多个点x1,y1,x2,y2

  const polyline = new fabric.Polyline([
    {x: 30, y: 30},
    {x: 150, y: 140},
    {x: 240, y: 150},
    {x: 100, y: 30}
  ], {
    fill: 'transparent', // 如果画折线,需要填充透明
    stroke: '#6639a6', // 线段颜色
    strokeWidth: 5 // 线段粗细 
  })

6.绘制不规则图形 fabric.Path

(1)使用fabric.Path绘制不规则图形,主要配置项为一个字符串,其中M代表移动到某个点,L是中途的点,z表示闭合

  const path = new fabric.Path('M 0 0 L 200 100 L 170 200 z');
  path.set({ left: 120, top: 120,fill:'red' });

7.绘制曲线

(1)fabric提供了自由画笔的功能让我们可以随意绘制线条

(2)使用isDrawingMode来开启自由绘制模式

  //1.在初始化canvas实例时,直接开启自由画笔
  const canvasCtx = new fabric.Canvas("mapCanvas", {
  	isDrawingMode:true,
  });
  
  //2.设置`isDrawingMode`动态开启
  canvasCtx.isDrawingMode =true;

  //设置画笔颜色		
  canvasCtx.freeDrawingBrush.color = "#f56c6c";
  //设置画笔粗细
  canvasCtx.freeDrawingBrush.width = 3;

(3)关闭自由绘制

  //设置isDrawingMode为false
  canvasCtx.isDrawingMode =false;
 
  //关闭的时机可以根据需求设置,这里介绍鼠标弹起时关闭
  canvasCtx.on("mouse:up", function (opt) {
    this.isDrawingMode = false;
  });

(4)自由绘制的曲线,也会生成实例对象

8.绘制虚线

(1)绘制虚线要使用strokeDashArray属性,strokeDashArray[a,b] 含义为 每隔a个像素空b个像素,直线和线段都可以使用这个属性来绘制成虚线。


const line = new fabric.Line([x1,y1,x2,y2],{
    stroke: "#c45656",
    strokeWidth: 3,
    strokeDashArray: [20, 10],
});

 const polyline = new fabric.Polyline(
    [
      { x: 30, y: 30 },
      { x: 150, y: 140 },
      { x: 240, y: 150 },
      { x: 100, y: 30 },
    ],
    {
      fill: "transparent", // 如果画折线,需要填充透明
      hasBorder: true,
      strokeDashArray: [20, 10],
    }
  );

四,图片绘制

1.将图片绘制进canvas有两种方式

(1)方式一:根据图片元素绘制图片,使用fabric.Image

  let image = new Image();
  image.src = 'xxxx';
  image.onload = ()=>{
  	//1.创建图片实例对象
    let imgInstance = new fabric.Image(image, {
      left: 0, //位置
      top: 0,
      scaleX:1,
      scaleY:1,
      erasable:false, //是否可擦除
      hasControls: false, // 是否开启图层的控件
      evented:true,//是否可以支持事件
      ...
    });
    //实例对象的width和height可以获取图片的大小
    imgInstance.width
    imgInstance.height
    //2.添加到画布
    canvasCtx.add(imgInstance);
  };

(2)方式二:根据图片地址绘制图片fabric.Image.fromURL

  new fabric.Image.fromURL("/resources/images/robot.png", function (oImg) {
  	//oImg是图片对象实例
    oImg.set({
      top:10,
      left:10,
      scaleX:1,
      scaleY:1,
      evented: false,
      ...
    });
    //实例对象的width和height可以获取图片的大小
    oImg.width
    oImg.height
    
    canvasCtx.add(oImg);
  });

2.当我们已经声明了一个fabric图片对象,可以在维持原对象的情况下使用setSrc动态修改图片。

  //注意,第一个参数只能是图片地址远程地址本地地址,base64等,不能是图像元素
  oimg.setSrc("./img.png", () => {
    canvasCtx.renderAll();
  });

五,绘制文本

1.绘制普通文本

  let text = new fabric.Text(`hello \n world!`, {
      left: 0,
      top: 0,
      fill: 'red', // 字体颜色
      fontSize: 12, //字体大小
      fontWeight: 100, //字体粗细
      charSpacing: 10 //字体间距,
      angle: 30, // 旋转
      backgroundColor: '#ffd460', // 背景色
      stroke: '#3f72af', // 文字描边颜色(蓝色)
      strokeWidth: 2, // 文字描边粗细
      textAlign: 'lfet', // 对齐方式:left 左对齐; right 右对齐; center 居中
      opacity: 0.8, // 不透明度
      selectable: true, // 能否被选中,默认true
      shadow: 'rgba(0, 0, 0, 0.5) 5px 5px 5px', // 投影
      ...
    });

2.绘制可编辑文本

  let text = new fabric.IText(`hello \n world!`, {
      left: 0,
      top: 0,
      cornerColor: 'pink', // 角的颜色(被选中时)
      borderColor: 'yellowGreen', // 边框颜色(被选中时)
      ...
    });

3.绘制文本框

  let text = new fabric.Textbox(`hello \n world!`, {
      left: 0,
      top: 0,
      cornerColor: 'pink', // 角的颜色(被选中时)
      borderColor: 'yellowGreen', // 边框颜色(被选中时)
      ...
    });

4.可以通过set实例方法动态修改文本,和其他属性

text.set({
	text:'change content'
})

六,对象的定位

1.在fabric中,我们使用对象的topleft来定位对象在画布中的位置,且topleft默认是对象的左上角位置

2.我们可以通过配置对象的originXoriginY来修改默认原点的位置

3.originXoriginY分别代表对象平移的水平起始点和垂直起始点,可以设置的值如下

originX : "left"|"right"|"center"
originY : "top"|"bottom"|"center"

4.如下图所示,相同的lefttop值,原点不一样时,对象的位置是不一样的,红色的为默认的原点,紫色的originXoriginYcenter

fabric.js学习_第1张图片
5.除了lefttop, 我们可以通过对象的aCoords获取对象在没缩放没移动时的原始位置,

七,kclass对象

1.往深层面看,绘制的每一个图形都是一个kclass对象,如下
fabric.js学习_第2张图片
2.对于所有的对象,需要使用add 方法添加进画布

3.我们可以使用getObjects获取所有绘制的对象,返回一个元素为kclass对象的数组,注意没有add进画布的对象,无法通过getObjects获取到

canvasCtx.getObjects()

3.在kclass可以获取对象的一些有用的信息其中

(1)lineCoords : 线性对象边界的四个点坐标,是在画布缩放移动时,动态变化的当前时刻快照的对象坐标

(2)aCoords : 原始对象边界的四个点坐标原始值,该属性反映了画布没缩放没移动时的对象位置,

每一个lineCoords都对应着一个aCoordslineCoords是当前肉眼看到的,aCoords是隐藏在背后的原始位置。

(3)top,left :对象定位时的topleft

(4)angle:对象旋转的角度

(5)自定义的一些属性,也会在kclass对象中展示

(6)配置的属性等等

八,设置对象属性

1.对于所有对象,除了在创建时可以声明属性,我们还可以使用对象的set实例方法动态设置属性

 directionArrow.set({
      left: 10,
      top: 22,
 });

九,限制激活对象的操作行为

1.正常情况下一个可交互的画布上的元素支持缩放,平移和旋转的操作
fabric.js学习_第3张图片

2.我们可以通过设置 hasControlsfalse禁用所以功能,此时不会渲染操作框

3.同时我们也可以通过属性配置,限制一部分行为。

(1)限制元素的旋转:object.lockRotation = true
(2)限制元素x轴的缩放:object.lockScalingX= true
(3)限制元素y轴的缩放:object.lockScalingY= true
(4)限制元素上下移动:object.lockMovementY =true
(5)限制元素左右移动:object.lockMovementX =true

4.另一种方式使用对象的实例方法setControlsVisibility,该方法用于隐藏操作框的部分corner,从而达到禁用功能

 workNode.setControlsVisibility({
      bl: false,
      br: false,
      mb: false,
      ml: false,
      mr: false,
      mt: false,
      tl: false,
      tr: false,
      mtr:false,
  });

5.对于删除按钮,需要自定义


var deleteImg = document.createElement("img");
deleteImg.src = deleteIcon;

fabric.Object.prototype.controls.deleteControl = new fabric.Control({
  x: 0.5,
  y: -0.5,
  offsetY: -16,
  offsetX: 16,
  cursorStyle: "pointer",
  mouseUpHandler: function (eventData, transform) {
    var target = transform.target;
	//target 为当前对象,这里可执行业务判断
    canvasCtx.remove(target);
    canvasCtx.requestRenderAll();
  },
  render: function (ctx, left, top, styleOverride, fabricObject) {
  	//fabricObject为当前对象,可根据当前对象自定义是否渲染删除按钮
    var size = this.cornerSize + 2;
    ctx.save();
    ctx.translate(left, top);
    ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
    //deleteImg 是图片元素
    ctx.drawImage(deleteImg, -size / 2, -size / 2, size, size);
    ctx.restore();
  },
  cornerSize: 18,
});

九,事件

1.画布对象元素对象都有on实例方法用于绑定事件,当设置对象的属性 eventedfalse时,绑定的事件不生效

canvasCtx.on(eventname,handler)

canvasCtx.on("mouse:down",(e)=>{})
text.on("mouse:down",(e)=>{})

2.支持的常用事件

(1)鼠标上常用的操作事件

mouse:down 或 mousedown 鼠标按下时触发
mouse:move
mouse:up 或 mouseup 鼠标抬起时触发
mouse:down:before
mouse:move:before
mouse:up:before
mouse:over 或 mouseover 鼠标悬浮时触发
mouse:out 或 mouseout 鼠标进入后离开时触发
mouse:dbclick 或 mousedblclick 鼠标双击时触发

//for example
canvasCtx.on("mouse:down",(e)=>{})
text.on("mouse:down",(e)=>{})

(2)对象操作的一些监控

modified
rotating
scaling
moving
skewing

//for example
text.on("rotating",(e)=>{})

3.fabric的鼠标事件能够兼容在移动端的手势操作

mouse:down  ==> 在移动端手指点击一下也会触发
mouse:move  ==> 在移动端手指移动也会触发
mouse:up ==> 在移动端手指抬起也会触发

mouse:down:before 
mouse:move:before
mouse:up:before

mouse:over  ==> 不支持移动端
mouse:out ==> 移动端手指离开元素触发
mouse:dbclick ==> 在移动端双击也会触发

4.注意,虽然部分鼠标事件兼容移动端,但是同一个事件在PC端和移动端返回的事件对象是不一样的,pc端返回的mouseEvent,移动端返回的touchEvent,两者返回的字段含义不一样,要自己做兼容。

5.注意,当对画布进行拖动和缩放后,事件对象的offsetXoffsetY会产生偏移,不能准确的表示位置,需要使用如下的方法转化坐标

//根据缩放等级转化鼠标的x,y
function getTransformedPosX(canvasCtx, x) {
  let zoom = Number(canvasCtx.getZoom());
  return (x - canvasCtx.viewportTransform[4]) / zoom;
}
function getTransformedPosY(canvasCtx, y) {
  let zoom = Number(canvasCtx.getZoom());
  return (y - canvasCtx.viewportTransform[5]) / zoom;
}

十,橡皮擦

1.fabric.js 的基础包并没有包含橡皮擦模块,要使用橡皮擦功能可以使用npm安装fabric-with-erasing

2.fabric-with-erasing是在fabric.js的基础上加上橡皮擦,因此在使用fabric-with-erasing后,可以不需要fabric包。

3.开启橡皮擦

  canvasCtx.isDrawingMode = true; // 进入绘画模式
  canvasCtx.freeDrawingBrush = new fabric.EraserBrush(canvasCtx); // 使用橡皮擦画笔
  canvasCtx.freeDrawingBrush.width = 8; // 设置画笔粗细为 10

4.恢复橡皮擦擦除部分

  canvasCtx.isDrawingMode = true;
  canvasCtx.freeDrawingBrush = new fabric.EraserBrush(canvasCtx);
  canvasCtx.freeDrawingBrush.width = 10;
  canvasCtx.freeDrawingBrush.inverted = true;

5.关闭橡皮擦功能

  canvasCtx.isDrawingMode = false;

6.橡皮擦经过的部分会变成透明的

十,设置画布zoom和获取zoom

1.canvas默认层级是1

2.设置层级方法: canvasCtx.setZoom(zoom);

3.获取层级方法: canvasCtx.getZoom();

4.根据鼠标滚轮来设置层级:

  canvasCtx.on("mouse:wheel", function (opt) {
    var delta = opt.e.deltaY;
    var zoom = canvasCtx.getZoom();
    zoom *= 0.999 ** delta;
    if (zoom > 20) zoom = 20;
    if (zoom < 0.01) zoom = 0.01;
    canvasCtx.setZoom(zoom);
    opt.e.preventDefault();
    opt.e.stopPropagation();
  });

十一,修改鼠标样式

1.fabric支持修改不同状态下默认的鼠标样式

(1)默认的鼠标样式

canvasCtx.defaultCursor = 'default' 

(2)鼠标移动到对象上的样式

canvasCtx.hoverCursor = 'move' 

(3)鼠标拖动时的样式

canvasCtx.moveCursor = 'move' 

(4)自由绘制时的样式

canvasCtx.freeDrawingCursor = 'crosshair' 

(5)旋转时的样式

canvasCtx.rotationCursor = 'crosshair' 

2.上面的样式都是默认样式,我们可以赋值为其它css支持的cursor

十二,将画布保存为图片

1.使用toDataURL可以将canvas转为图片,该函数返回的是图片的base64格式字符串。

let imgUrl = canvasCtx.toDataURL({
    format: "png",
  })

2.可以通过topleftwidthheight参数将指定部分canvas绘制成图片。

let imgUrl = canvasCtx.toDataURL({
    format: "png",
    width: mapImgInstance.lineCoords.br.x - mapImgInstance.lineCoords.bl.x,
    height: mapImgInstance.lineCoords.bl.y - mapImgInstance.lineCoords.tr.y,
    left: mapImgInstance.lineCoords.bl.x,
    top: mapImgInstance.lineCoords.tl.y,
  });

十三,释放canvas

1.使用dispose可以释放已经创建的canvas

canvasCtx.dispose()

十四,移动端手势支持

1.使用fabric_with_gestures版本
??做个假想,使用这个版本纯天然支持双指缩放

   /* 要想触发 必须是fabric-with-gestures
        touch:gesture
        touch:drag
        touch:shake
        touch:longpress

2.双指缩放

  handleDoubleFinger(options) {
                const {
                    clientX: finger1X,
                    clientY: finger1Y
                } = options.e.targetTouches[0];
                const {
                    clientX: finger2X,
                    clientY: finger2Y
                } = options.e.targetTouches[1];
                const powX = (finger2X - finger1X) * (finger2X - finger1X);
                const powY = (finger2Y - finger1Y) * (finger2Y - finger1Y);
                // 计算两个手指之间的距离
                const distance = Math.sqrt(powX + powY);
                // 每次缩放的比例
                let ratio = -0.05;
                if (distance > preDistance) {
                    ratio = 0.05;
                }
                preDistance = distance;
                const x = scaleCenter.x || (Math.abs(finger1X + finger2X)) / 2;
                const y = scaleCenter.y || (Math.abs(finger1Y + finger2Y)) / 2;
                scaleCenter = {
                    x, y
                };
                // 计算当前缩放的大小
                let zoom = ratio + canvasCtx.getZoom(); // 获取当前缩放比
                zoom = Math.max(0.5, zoom);
                zoom = Math.min(3, zoom);
                const zoomPoint = new fabric.Point(x, y);
                canvasCtx.zoomToPoint(zoomPoint, zoom);
            }

十五,操作像素

1.fabric好像没有直接操作像素的方法,想要操作像素可以使用原生的canvas

2.关键的两个apigetImageDataputImageData

  //初始化canvas上下文
  let canvas = document.getElementById("canvas");
  let ctx = canvas.getContext("2d");
  
  //初始化图像元素
  let img = new Image();
  img.crossOrigin = "anonymous";
  img.src = url; // url是要改变图像的地址
		
  //图像加载完成后
  img.onload = () => {
	canvas.width = img.width;
    canvas.height = img.height;
	
	//往canvas绘制图像元素
    ctx.drawImage(img, 0, 0);
    //获取图像像素对象
    let imgData = ctx.getImageData(0, 0, img.width, img.height);
	//imgData.data 类似于 [r1,g1,b1,a1,r2,g2,b2,a2,r3,g3,b3,a3,...] 每四个元素组成一个rgba

	//...根据索引可以直接修改像素值
	
	//使用putImageData可以把改变后的图片,重新绘制到canvas上
	ctx.putImageData(imgData, 0, 0);
	//之后可以将图片重新下载下来
    let url = canvas.toDataURL("image/png", { quality: 1 });
  }

十六,参考资料

1.中文api文档

你可能感兴趣的:(前端学习汇总,fabric,学习,javascript)