精华内容
下载资源
问答
  • Fabric.js允许您使用JavaScript在网页上HTML <canvas>元素上轻松创建简单的形状,例如矩形,圆形,三角形和其他多边形,或者由许多路径组成的更复杂的形状。 然后,Fabric.js将允许您使用鼠标来操纵这些对象的大小,...
  • fabric.js-源码

    2021-02-16 07:23:16
    Fabric.js允许您使用JavaScript在网页上HTML <canvas>元素上轻松创建简单的形状,例如矩形,圆形,三角形和其他多边形,或者由许多路径组成的更复杂的形状。 然后,Fabric.js将允许您使用鼠标来操纵这些对象的大小,...
  • 用于 fabric.js 的新过滤器以从图像中删除特定颜色 @例子 var filter = new fabric.Image.filters.RemoveColor({ color: [235,158,84] }); object.filters.push(filter); object.applyFilters(canvas.renderAll....
  • 使用 Snap.svg 将 SVG 操作添加到 Fabric.js 织物画布将 SVG 作为图像对象导入,因此失去了专用 SVG 库(如 Snap.svg)的操作级别。 Snap 提供了更详细的 SVG 界面,但缺少任何画布控件。 这个包引入了一个 ...
  • vue-fabric purestart vue-fabric. Installation npm install vue-fabric --save 依赖 下载.和 .到本地 static/js/文件下 本地项目 index.html 引入 [removed][removed] [removed][removed] Import 在main.js中 ...
  • 制图师 Fabric.js可视化编辑器以绘制图像 演示/样本
  • Vue 3 +打字稿+ Vite 该模板将帮助您开始在Vite中使用Vue 3和Typescript进行开发。 推荐的IDE设置 + 。 确保在设置中启用vetur.experimental.templateInterpolationService ! 如果使用[removed] ...
  • Fabric.js + Socket.io绘图工具 使用fabric.js和socket.io制作的绘图工具 专为在我的个人项目中使用而设计 可用工具: 3种尺寸的画笔工具(自由绘图模式); 可调的笔触颜色; 橡皮擦工具(无需物理“删除”键...
  • react-komik, 基于 fabric.js 画布绘制的基于ReactJS的漫画 响应 Komik !基于ReactJS的漫画条创建器使用 fabric.js 画布渲染。 这就像的眼镜但是对于漫画。 你可以在渲染后编辑( 定位,缩放,着色) 。 Reactify任何...
  • 扩展名 ExtJS 中的可视化 在 ExtJS 中使用一些可视化库。 重在 D3 方面,但也包括带有 Chart.jsFabric.js 的 HTML5 示例。 用法 下载并放置在 DOC_ROOT 下的某个位置。
  • 官网自定下载,有很多问题,git下载的,又不支持手机触屏事件。这个是个人整合的相关完美无报错版本---version: '2.0.0-beta6'
  • AngularJS&FabricJS-2D-图 关于 基于浏览器的2D图编辑器,使用AngularJS,AngularUI和Fabric.js构建。 该项目由[Big-Silver]构建。 预安装 如果未安装Bower和gulp,则要安装Bower,请访问 ;要安装gulp,请访问 ...
  • Fabric.js

    2020-09-15 15:25:32
    Fabric.js 是一个简化HTML5 Canvas开发的Javascript库,Fabric.js提供了HTML5 Canvas本身缺失的对象模型、交互层、SVG解析器以及其他一整套工具。它是一个完全开源的项目,在MIT下获得授权,多年来一直在维护,近期...

    Fabric.js是什么

    Fabric.js 是一个简化HTML5 Canvas开发的Javascript库,Fabric.js提供了HTML5 Canvas本身缺失的对象模型、交互层、SVG解析器以及其他一整套工具。它是一个完全开源的项目,在MIT下获得授权,多年来一直在维护,近期要发布4.0版本,支持自定义controls。

    Fabric.js能做什么

    在Canvas画布上创建、填充图形(包括图片、文字、规则图形和复杂路径组成图形)。
    给图形填充渐变颜色。
    组合图形(包括组合图形、图形文字、图片等)。
    设置图形动画及用户交互,生成的对象自带拖拉拽功能。
    JSON, SVG数据的序列化和反序列化。

    为什么使用Fabric.js

    HTML5 Canvas提供了完整的画布,可以轻松的在画布上绘制简单的图形、制作简单的动画,但是HTML5 Canvas提供的API过于低级,且操作基于上下文,因此在绘制复杂图形或者需要实现用户交互时,就显得不是那么方便了。Fabric.js在HTML5 Canvas原生API之上,提供完整的对象模型,由Fabric.js来管理HTML5 Canvas画布的状态和渲染,用户基于具体的对象,来编写代码,完成所需功能的开发(类似于面向过程和面向对象)。“Talk is cheap. Show me the code”,下面通过代码来看看用HTML5 Canvas原生方法和用Fabric.js分别实现在画布上画一个矩形这一功能。

    用HTML5 Canvas的原生方法实现

    // 获取canvas元素
    var canvasEl = document.getElementById('c');
    // 获取上下文
    var ctx = canvasEl.getContext('2d');
    // 设置填充颜色
    ctx.fillStyle = 'red';
    // 在100,100点创建20x20的矩形
    ctx.fillRect(100, 100, 20, 20);
    

    在线演示地址:https://codepen.io/liblack/pen/LYpaMwa

    用Fabric.js实现相同的功能:

    // 创建原生canvas元素的包装类(‘c’canvas元素的id)
    var canvas = new fabric.Canvas('c');
    
    // 创建一个矩形对象
    var rect = new fabric.Rect({
      left: 100,
      top: 100,
      fill: 'red',
      width: 20,
      height: 20
    });
    
    // 添加矩形到画布上
    canvas.add(rect);
    

    在线演示地址:https://codepen.io/liblack/pen/PoPLVwZ

    由上面例子,可以看到使用HTML5 Canvas原生方法是对context(代表整个画布位图的对象)进行操作,而使用Fabric.js,我们是对对象操作,只需要去实例化对象,设置对象的属性,然后将它们添加到canvas中。到这里,可能还感受不到Fabric对比原生Canvas方法的优势,下面可以完成这样的功能,即在刚才绘制的矩形的基础上,将矩形位置移动到(10,10)点上。
    这样的功能,在Canvas原生方法上实现,需要先把原来的矩形从画布上清除,然后在(10,10)位置重新绘制一个矩形,以此来实现矩形移动这样的功能。

    // 擦除之前的矩形(这里是擦除了整个canvas区域)
    ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
    // 重新绘制矩形
    ctx.fillRect(20, 50, 20, 20);
    

    听起来是不是很蹩脚?是的,使用Canvas原生方法时,就像是个带橡皮檫的笔刷,在画布上绘制图形时,是笔刷在画布上移动,绘制出的图形就是笔刷移动的整个痕迹,而想把绘制好的图形移动到其他地方,只好用橡皮檫擦掉,然后在新位置重新绘制。
    相应的,使用Fabric.js实现该功能时,只需要改变矩形对象的属性,然后重新刷新(渲染)画布即可。

    rect.set({ left: 20, top: 50 });
    canvas.renderAll();
    

    Canvas对象

    fabric.Canvas作为元素的包装器,创建fabric.Canvas对象如下:

    var canvas = new fabric.Canvas('...')
    

    它接收一个元素的id,并返回一个fabric.Canvas 的实例。fabric.Canvas对象,并不是DOM里的元素,如果需要直接控制DOM,或者对应的context,需要通过相应API去获取。

    var canvasElement = document.getElementById(canvasEle);
    var ctx = canvasElement.getContext("2d");
    fabric.Canvas对象负责管理画布上绘制的所有对象,可以将对象添加到fabric.Canvas对象,也可以从fabric.Canvas获取或删除对象。
    
    var canvas = new fabric.Canvas('c');
    var rect = new fabric.Rect();
    
    canvas.add(rect); // 添加对象
    
    canvas.item(0); ///获取之前添加的fabric.Rect(第一个对象)
    canvas.getObjects(); ///获取画布上的所有对象(rect将是第一个也是唯一一个)
    canvas.remove(rect); ///删除之前添加的对象删除
    

    fabric.Canvas对象可以对画布进行配置。比如需要为整个画布设置背景颜色或图像?需要将所有内容剪裁到特定区域?设置不同的宽度/高度?指定画布是否是交互式的?所有这些选项(及其他)都可以在fabric.Canvas对象上进行设置,可以在创建时或之后进行设置。

    var canvas = new fabric.Canvas('c', {
      backgroundColor: 'rgb(100,100,100,200)',
      selectionColor:'blue',
      selectLineWidth: 2
      // ...
    });
    
    // 或
    
    var canvas = new fabric.Canvas('c');
    canvas.setBackgroundImage('http://...');
    canvas.onFpsUpdate = function(){ /* ...... */ };
    // ...
    

    注意这种创建对象的形式,Fabric.js里基本上都是类似的,类名表示要创建的对象类型,第一个参数是必要的数据,第二个参数是各种选项。

    所有对canvas的修改,包括在其中添加删除对象,以及对象参数的修改,都需要调用渲染方法才能显示出来:

    canvas.renderAll();
    

    Objects基本图形
    Fabric.js提供了7种基本图形,下面是图形对应的类,

    fabric.Circle
    fabric.Ellipse
    fabric.Line
    fabric.Polygon
    fabric.Polyline
    fabric.Rect
    fabric.Triangle
    

    所有基本形状,都可以通过类实例的属性和方法来控制它们的位置、颜色、大小等样式。所有类都继承自fabric.Object类,有一些公共的属性和方法。

    创建

    下面是画线的例子(给出两个顶点坐标):

    var line =  new fabric.Line([x1, y1, x2, y2], {
        strokeWidth: 2, //线宽
        stroke: rgba(255,0,0,0.8), //线的颜色
        selectable: false
    });
    canvas.add(line);
    

    画圆的例子(顶点和半径是在选项里的),这里left和top其实就是(x,y),应该是借用了css里的命名。

    var circle =  new fabric.Circle({
        radius: 2,
        left: left,
        top: top,
        originX: 'center',
        originY: 'center',
        fill: rgba(0,200,0,0.8), 
        strokeWidth: 1,
        stroke: rgba(255,0,0,0.8),
        selectable: false
    });
    canvas.add(circle);
    

    从这里可以看出,和创建canvas类似,第一个参数是这个类专用的(比如画直线的时候传的起止点坐标),第二个参数是通用选项,如果没有专用参数,那么第一个参数就直接是通用选项。所有创建完的形状,只有通过canvas.add方法加入,才能显示出来。

    控制

    left和top是每种Object都有的属性,至于它到底指图形中哪一个点的坐标,由originX和originY这组参数决定,它们相当于文本编辑软件里的对齐方式,originX有三种可选值:left,center, right;originY也有三种可选值:top, center, bottom。

    它们的示意图如下:
    http://fabricjs.com/test/misc/origin.html

    如果希望对象的默认原点在中心,可以这样设置:

    fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center'
    

    width和height也是可以直接存取的属性,顾名思义,表示长和宽(所有形状都是有外接矩形的,所以可以用长和宽来控制大小)。除了上面那几个可以直接存取的属性,大部分属性需要使用get/set方法读写,比如:

    line.left = pointer.x;
    line.top = pointer.y;
    line.set('stroke', startColor);
    line.set('height', 20);
    

    Image对象

    Image跟其他形状类似,都是fabric.Object的子类,最大的区别在于,图像文件的加载是异步的,所以对Image的后续操作,都要在回调中完成。

    fabric.Image.fromURL('my_image.png', function(oImg) {
      // scale image down, and flip it, before adding it onto canvas
      oImg.scale(0.5).set('flipX, true);
      canvas.add(oImg);
    });
    

    Path对象

    在Fabric.js中的Path代表了一个形状的轮廓,它可以被填充、描边和修改。Path由一系列的命令组成,本质上是模仿一支笔从一个点到另一个点。在“move”, “line”, “curve”, or “arc”等命令的帮助下,Path可以形成非常复杂的形状。而在Paths(PathGroup’s)组的帮助下,Path的能实现更多的复杂图形。
    Fabric.js中的Path与SVG的 元素非常相似。它们使用相同的命令集,可以从 元素中创建,并将其序列化。我们稍后会更深入地研究序列化和SVG解析,但现在值得一提的是,实践中很少会手动创建Path实例。相反,更多的是使用Fabric.js的内置SVG解析器。
    手工创建一个简单的Path对象。

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

    实例化 fabric.Path 对象,传递给它一串路径指令。虽然看起来很隐蔽,但实际上很容易理解。”M “代表 “移动 “指令,告诉隐形笔要移动到0,0点。”L “代表 “线”,让笔画一条线到200,100点。然后,另一个 “L “代表 “线”,让笔画一条线到170,200点。最后,”z “告诉画笔关闭当前路径并最终确定形状。结果,得到的是一个三角形的形状。

    由于 fabric.Path 就像 Fabric 中的其他对象一样,我们还可以改变它的一些属性。但我们还可以对它进行更多的修改。

    ...
    var path = new fabric.Path('M 0 0 L 300 100 L 200 300 z');
    ...
    path.set({ fill: 'red', stroke: 'green', opacity: 0.5 });
    canvas.add(path);
    

    实践中,更多是直接使用fabric.loadSVGFromString 或 fabric.loadSVGFromURL 方法来加载整个 SVG 文件,然后让 Fabric 的 SVG 解析器来完成所有 SVG 元素的解析工作,并创建相应的 Path 对象。

    Events事件

    事件驱动的架构是一个框架灵活性和可扩展性的基础。Fabric.js提供了一个广泛的事件系统,覆盖了低级的 “鼠标”事件到高级的对象事件。
    这些事件使我们能够监控到到画布上发生的各种动作的不同时刻。比如想知道鼠标被按下的时间,只需监听”mouse:down”事件就可以了。想知道对象何时被添加到画布上,只需要监听”object:added “事件就在那里。

    事件API非常简单,类似于jQuery、Underscore.js或其他流行的JS库。有on方法来初始化事件监听器,有off方法来移除事件监听器。

    下面一个实际的例子。

    var canvas = new fabric.Canvas('...');
    canvas.on('mouse:down', function(options) {
      console.log(options.e.clientX, options.e.clientY);
    });
    

    上面例子演示了在canvas上添加”mouse:down”事件监听器,并给它设置事件处理程序,它将记录事件发生的坐标。事件处理程序会接收一个选项对象,它有两个属性:e—原始事件,和target—画布上的点击对象(如果有的话)。该事件在任何时候都是存在的,但目标只有在实际点击了画布上的某个对象后才会存在。target也只有在有意义的情况下才会传递给事件的处理程序,例如,对于 “mouse:down”事件,但对于 “after:render”事件(表示整个画布被重新绘制),target不会传递给事件处理程序。

    canvas.on('mouse:down', function(options) {
      if (options.target) {
        console.log('一个对象被点击了!', options.target.type);
      }
    });
    

    如果你点击了一个对象,上面的例子会输出 “一个对象被点击了!”。还会显示被点击的对象类型。

    那么,在Fabric.js中还有鼠标级的事件:“mouse:down”, “mouse:move”, 和”mouse:up”。通用的事件: “after:render”。选择相关的事件: “before:selection:cleared”,”selection:create”,”selection:cleared”。对象相关的事件: “object:moded”、”object:selected”、”object:moving”、”object:scaling”、”object:rotating”、”object:additional “和 “object:detter”。
    注意,像”object:moving”(或”object:scaling”)这样的事件在每次对象移动(或缩放)时,即使是一个像素点的移动,也会连续地被触发。另一方面,像 “object:modified” 或 “selection:create”这样的事件只在操作(对象修改或选区创建)结束时才会被触发。如果将事件直接附加到画布上的(canvas.on(‘mouse:down’, …)),这意味着事件被覆盖到了canvas实例上。如果一个页面上有多个画布,可以给每个画布附加不同的事件监听器。它们都是独立互不影响的。
    为了方便,Fabric.js将事件系统做得更进一步,允许直接将监听器附加到具体对象上。如下例子。

    var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
    rect.on('elected', function() {
      console.log('选择了一个矩形');
    });
    
    var circle = new fabric.Circle({ radius: 75, fill: 'blue' });
    circle.on('selected', function() {
      console.log('选择了一个圆圈');
    });
    

    上述例子直接给矩形和圆的实例附加事件监听器,使用的是 “selected “事件,而不是 “object:selected”。同样的,可以在对象上使用 “modified”事件(当附加到canvas上时使用 “object:modified”)、”rotating”事件(当附加到canvas时使用 “object:rotating”)等等。

    Groups组

    fabric.Group是Fabric.js提供的强大的功能之一。使用Groups可以将任何Fabric对象组合成一个单一实体,这样就能够将这些对象作为一个单一的单元来处理。用鼠标将画布上的任意数量的Fabric对象进行组合,一旦组合后,这些对象都可以一起移动甚至修改。它们组成了一个组。我们可以对该组进行缩放、旋转,甚至改变其呈现属性—颜色、透明度、边框等。

    下面创建一个由2个对象组成的组,即圆圈和文本。

    var circle = new fabric.Circle({
      radius: 100,
      fill: '#eef',
      scaleY: 0.5,
      originX: 'center',
      originY: 'center'
    });
    
    var text = new fabric.Text('hello world', {
      fontSize: 30,
      originX: 'center',
      originY: 'center'
    });
    
    var group = new fabric.Group([ circle, text ], {
      left: 150,
      top: 100,
      angle: -10
    });
    
    canvas.add(group);
    

    组成组以后,依旧可以对每个对象操作,改变对象的属性和状态。

    group.item(0).set('fill', 'red');
    group.item(1).set({
      text: 'trololo',
      fill: 'white'
    });
    

    Serialization序列化

    为构建某种有状态的应用程序,允许用户将canvas内容的结果保存在服务器上,或者将内容流媒体化到不同的客户端。Fabric.js提供了canvas序列化/解序列化支持。

    toObject, toJSON

    Fabric中序列化的主要方法是 fabric.Canvas#toObject()和 fabric.Canvas#toJSON()方法。让我们来看一个简单的例子,首先对一个空画布进行序列化。

    var canvas = new fabric.Canvas('c');
    JSON.stringify(canvas); // '{"objects":[], "background": "rgba(0,0,0,0,0)"}'
    

    使用的是ES5 JSON.stringify()方法,如果传入的对象存在toJSON方法,那么这个方法就会隐含地调用toJSON方法。由于Fabric中的canvas实例有toJSON方法,所以调用JSON.stringify(canvas)方法和调用JSON.stringify(canvas.toJSON())一样。

    注意,返回的字符串表示空的canvas。它是JSON格式的,本质上由 “objects”和”background”属性组成。”objects”目前是空的,因为canvas上没有任何东西,而 background 有一个默认的透明值(“rgba(0,0,0,0,0)”)。
    当在canvas上添加了具体对象后:

    canvas.add(new fabric.Circle({
      left: 100,
      top: 100,
      radius: 50,
      fill: 'red'
    }));
    console.log(JSON.stringify(canvas));
    

    序列化后结果如下:

    '{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,
    "scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
    "transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0},{"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red",
    "overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,
    "selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}'
    

    toSvg

    Fabric.js支持将canvas画布序列化为SVG格式的文本。

    canvas.add(new fabric.Rect({
      left: 50,
      top: 50,
      height: 20,
      width: 20,
      fill: 'green'
    }));
    console.log(canvas.toSVG());
    

    序列化结果如下:

    '<?xml version="1.0" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700" xml:space="preserve"><desc>Created with Fabric.js 0.9.21</desc>
    <rect x="-10" y="-10" rx="0" ry="0" width="20" height="20" style="stroke: none; stroke-width: 1; stroke-dasharray: ; fill: green; opacity: 1;" transform="translate(50 50)" /></svg>'
    

    Deserialization反序列化, SVG Parser SVG解析器

    与序列化类似,反序列化是从字符串中加载canvas,与序列化时相对应的,也有两种方法:从JSON文本反序列和从SVG文本反序列化。当使用JSON表示时,有 fabric.Canvas#loadFromJSON和 fabric.Canvas#loadFromDatalessJSON方法。当使用SVG时,

    有 fabric.loadSVGFromURL和 fabric.loadSVGFromString两个方法。

    var canvas = new fabric.Canvas();
    
    canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,
    "scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,
    "perPixelTargetFind":false,"rx":0,"ry":0},{"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red","overlayFill":null,"stroke":null,"strokeWidth":1,
    "strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,
    "hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}');
    

    更多资源

    fabric.js官网:http://fabricjs.com/
    fabric.js源码:https://github.com/fabricjs/fabric.js
    fabric.js应用案例:https://printio.ru/tees/new_v2
    HTML5 Canvas资料:https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial

    展开全文
  • Fabric.js制作的协作白板。 特征: 与其他人“实时”协作-您在一个屏幕上看到的是同时在另一个屏幕上看到的。 带有多种颜色选择的刷子 创建文本框 创建形状 一键下载Canvas内容 台式机和平板电脑的屏幕响应能力 ...
  • 理解transformations如何在fabricJS上工作是尽可能顺利地编写应用程序的一个关键方面。 Methods and properties related to transformations(与转换有关的方法和属性) 如果您计划了解和使用带有自定义代码的fabricJS...

    Using transformations, Introduction to Fabric.js Part 6

    其他文章见:Fabric.js中文文档导航

    理解transformations如何在fabricJS上工作是尽可能顺利地编写应用程序的一个关键方面。

    Methods and properties related to transformations(与转换有关的方法和属性)

    如果您计划了解和使用带有自定义代码的fabricJS转换,那么这些是您应该学会使用最多的方法。 一般而言,在此页面中,我们将矩阵称为6个数字的数组,这些数组表示平面上的变换,并指向一个简单的JS对象,看起来像{x:number,y:number}或fabric.Point类实例。 (通常没有什么区别)

    Canvas:
    - viewportTransform = matrix;
    Objects:
    - matrix = fabric.Object.prototype.calcTransformMatrix();
    - matrix = fabric.Object.prototype.calcOwnMatrix();
    Utils:
    - point = fabric.util.transformPoint(point, matrix);
    - matrix = fabric.util.multiplyTransformMatrices(matrix, matrix);
    - matrix = fabric.util.invertTransform(matrix);
    - options = fabric.util.qrDecompose(matrix);
    

    Moving from one space to another(从一个空间移动到另一个空间/空间变换)

    使用fabricJS时,通常必须与坐标和位置进行交互,但是如果您没有正确的背景,那么了解这些坐标的位置可能会很麻烦。 我将列出转换及其用法,然后尝试制作2个示例,以更好地说明发生了什么以及如何执行。

    Canvas.viewportTransform:将虚拟画布的一个点移至缩放和平移空间。

    在应用从viewportTransfrom M表示的缩放和平移后,当画布未缩放和平移时,位于位置P的点可以在坐标处找到: newP = fabric.util.transformPoint(P,canvas.viewportTransfor);

    Object.calcTransformMatrix:返回表示特定时刻(受top,left,scale和许多其他属性影响)通用对象变换的矩阵,并将点从对象空间移动到画布空间,而不缩放。因此,给定对象空间坐标中的一个点位于坐标P处,该点将在画布上的以下位置绘制: newP = fabric.util.transformPoint(P,object.calcTransformMatrix());

    Transforms order(转换顺序)

    在渲染期间,Fabric按以下顺序应用转换:

    zoom and pan => object transformation => nested object ( group ) => additionally nested objects ( nested groups )
    

    Reverting order(还原顺序)

    invertTransform实用程序用于移回转换逻辑,以便进行一些反向计算: 假设您要在单击的点上用鼠标单击将对象标记在画布上。您单击P点,例如在元素上10,10像素。您的对象被缩放和旋转,并且画布被缩放和平移。

    要反转渲染计算,您可以遵循以下逻辑:

    // calculate the total transformation that is applied to the objects pixels:
    var mCanvas = canvas.viewportTransform;
    var mObject = object.calcTransformMatrix();
    var mTotal = fabric.util.multiplyTransformMatrices(mCanvas, mObject); // inverting the order gives wrong result
    var mInverse = fabric.util.invertTransform(mTotal);
    var pointInObjectPixels = fabric.util.transformPoint(pointClicked, mInverse);
    

    现在,pointInObjectPixels是位于坐标空间中的点,其中(0,0)处位于对象的中心。

    Understanding the effect of a matrix(了解矩阵的效果)

    给定top,left,angle,scaleX,scaleY,skewX,skewY,flipX,flipY,创建表示该转换的矩阵相对简单。

    不直接的是如何返回。矩阵有6个维度,有6个数字,而属性是7个,因为我们可以按比例吸收翻转。确实存在无限多个矩阵,但是属性的可能组合数目是一个无限大。

    这里是Fabric.util.qrDecompose(matrix);可以为我们解码矩阵。给定函数的通用可逆矩阵,它将返回包含这些信息的选项对象:

    {
      angle: number, // in degree
      scaleX: number,
      scaleY: number,
      skewX: number, // in degree
      skewY: 0, // always 0! in degree.
      translateX: number,
      translateY: number,
    }
    

    该函数返回此矩阵的一种可能的解决方案,将skewY约束为0。

    A real use case(一个真实的案例)

    一位开发人员希望将对象分组在一起,但要同时保持它们空闲。理想情况下,当主要物体移动时,他希望其他物体跟随它。

    为了解释这个例子,我将调用主对象BOSS和其他MINIONS。

    因此,让我们想象一下在画布上有一些对象,我们可以自由移动它们。在某些时候,我们想锁定它们的相对位置并缩放在一起并移动一个。当我们设置所需的位置时,BOSS的位置将由矩阵来描述,正如我们到目前为止所学到的,每个minions也是如此。

    我确定它存在一个矩阵,该矩阵定义了从boss到minions的必要转换,我必须找到它。

    // i m looking for the UNKNOW relation matrix where:
    BOSS * UNKNOW = MINION
    // i multiply left for BOSS-INV
    BOSS-INV * BOSS * UNKNOW = BOSS-INV * MINION
    // BOSS-INV * BOSS = IDENTIY, a neutral matrix.
    IDENTITY * UNKNOW = BOSS-INV * MINION
    // so...
    UNKNOW = BOSS-INV * MINION
    // that in fabricJS code equals to:
    var minions = canvas.getObjects().filter(o => o !== boss);
    var bossTransform = boss.calcTransformMatrix();
    var invertedBossTransform = fabric.util.invertTransform(bossTransform);
    minions.forEach(o => {
      var desiredTransform = multiply(invertedBossTransform, o.calcTransformMatrix());
      // save the desired relation here.
      o.relationship = desiredTransform;
    });
    

    好了,现在我知道如何找到这种关系了,我可以编写一些事件处理程序以将这种关系应用于每个BOSS动作。

    var canvas = new fabric.Canvas('c');
    var boss = new fabric.Rect(
      { width: 150, height: 200, fill: 'red' });
    var minion1 = new fabric.Rect(
      { width: 40, height: 40, fill: 'blue' });
    var minion2 = new fabric.Rect(
      { width: 40, height: 40, fill: 'blue' });
    
    canvas.add(boss, minion1, minion2);
    
    boss.on('moving', updateMinions);
    boss.on('rotating', updateMinions);
    boss.on('scaling', updateMinions);
    
    var multiply = fabric.util.multiplyTransformMatrices;
    var invert = fabric.util.invertTransform;
    
    function updateMinions() {
      var minions = canvas.getObjects().filter(o => o !== boss);
      minions.forEach(o => {
        if (!o.relationship) {
          return;
        }
        var relationship = o.relationship;
        var newTransform = multiply(
          boss.calcTransformMatrix(),
          relationship
        );
        opt = fabric.util.qrDecompose(newTransform);
        o.set({
          flipX: false,
          flipY: false,
        });
        o.setPositionByOrigin(
          { x: opt.translateX, y: opt.translateY },
          'center',
          'center'
        );
        o.set(opt);
        o.setCoords();
      });
    }
    
    document.getElementById('bind').onclick = function() {
      var minions = canvas.getObjects().filter(o => o !== boss);
      var bossTransform = boss.calcTransformMatrix();
      var invertedBossTransform = invert(bossTransform);
      minions.forEach(o => {
        var desiredTransform = multiply(
          invertedBossTransform,
          o.calcTransformMatrix()
        );
        // save the desired relation here.
        o.relationship = desiredTransform;
      });
    }
    

    demo

    展开全文
  • 静止的 此目录包含您的静态文件。 此目录中的每个文件都映射到 /。 示例:/static/robots.txt 映射为 /robots.txt。 有关文档中此目录使用的更多信息: : 这个目录不是必须的,如果你不想使用它可以删除它。
  • Fabric.js Object caching(Fabric.js对象缓存) How does it work?(它是如何工作的?) 当fabric对象缓存处于活动状态时,在画布上绘制的对象实际上是在另一个较小的屏幕外画布上预先绘制的,与对象像素维度本身一样大...

    Fabric.js Object caching(Fabric.js对象缓存)

    其他文章见:Fabric.js中文文档导航

    How does it work?(它是如何工作的?)

    当fabric对象缓存处于活动状态时,在画布上绘制的对象实际上是在另一个较小的屏幕外画布上预先绘制的,与对象像素维度本身一样大。在“render”方法中,通过“drawImage”操作将预绘制的画布复制到主画布上。

    这意味着在drag-rotate-skew-scale操作期间,对象不会在画布上重新绘制,而只是将其复制的缓存图像绘制在画布上。

    How can I tweak/customize it?(我如何调整/自定义它?)

    此功能具有3个属性,可以不同方式使用它:

    /**
     * 当为true时,对象被缓存在另一个画布上。
     * 默认为 true
     * since 1.7.0
     * @type Boolean
     * @default
     */
    objectCaching:            objectCaching,
    
    /**
     * 当为true时,检查对象属性的高速缓存无效。 在某些特定情况下,您可能希望禁用此功能(喷刷,很大的路径组,组),或者如果您的应用程序不允许您修改组的属性,而您想对组禁用它。
     * 默认为 false
     * since 1.7.0
     * @type Boolean
     * @default
     */
    statefullCache:            false,
    
    /**
     * 如果为true,则在缩放过程中不会更新缓存。 如果缩放比例过大,图片将变得块状,并在缩放结束时以正确的细节重新绘制。此设置取决于性能和应用程序。
     * 默认为 false
     * since 1.7.0
     * @type Boolean
     * @default
     */
    noScaleCache:              true,
    
    /**
     * List of properties to consider when checking if cache needs refresh
     * Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single
     * calls to Object.set(key, value). If the key is in this list, the object is marked as dirty
     * and refreshed at the next render
     * @type Array
     */
    cacheProperties: (
      'fill stroke strokeWidth strokeDashArray width height stroke strokeWidth strokeDashArray' +
      ' strokeLineCap strokeLineJoin strokeMiterLimit fillRule backgroundColor'
    ).split(' '),
    
    /**
     * 当设置为“ true”时,对象的缓存将在下一次渲染调用时重新渲染。
     * @type Boolean
     * @default true
     */
    dirty:                true,
    
    /**
      * 当返回true时,强制对象拥有自己的缓存,即使它在组内,当对象在缓存上以特定方式运行并且始终需要其自己的隔离画布才能正确呈现时,也可能需要该对象。
      * since 1.7.12
      * @type function
      * @return false
      */
     needsItsOwnCache: function() {
       return false;
     },
    
     /**
     * 缓存画布的像素限制。 1Mpx,4Mpx应该可以。
     * @since 1.7.14
     * @type Number
     * @default
     */
    fabric.perfLimitSizeTotal = 2097152;
    
    /**
     * 缓存画布宽度或高度的像素限制。IE将最大值固定在5000
     * @since 1.7.14
     * @type Number
     * @default
     */
    fabric.maxCacheSideLimit = 4096;
    
    /**
     * *缓存画布的最低像素限制,设置为256PX
     * @since 1.7.14
     * @type Number
     * @default
     */
    fabric.minCacheSideLimit = 256;
    

    objectCaching是主要属性,浏览器默认为true,节点默认为false,它在对象级别启用objectCaching。

    statefullCache此属性规则决定,Fabric是否应该自动检查,是否需要重新绘制缓存的副本,或者开发人员应该手动使它无效。此属性默认为false。稍后对此进行更多讨论。

    noScaleCache默认为true,禁用缩放操作的缓存再生。它可以用来避免大比例的模糊效果。

    cacheProperties每次Object.set调用(key,value),则在该属性数组中搜索key。如果找到它,将对象标记为需要重新渲染。StatefullCache设置为true,而是在每次渲染时将所有键与旧值的副本进行比较。

    dirty是一个简单的标志,它强制在下一个渲染方法中重新渲染缓存,并在缓存重新生成后自动设置为false。

    fabric.perfLimitSizeTotal生成的缓存画布的最大像素大小。

    fabric.maxCacheSideLimit缓存画布最大边的最大大小(以像素为单位)。(大于5000的数字会中断IE)

    fabric.minCacheSideLimit缓存画布最小侧的最大大小(以像素为单位)。(小于256的数字可以禁用gpu合成。待核实)

    大于绘制对象的缓存画布的示例(默认情况下最小为256x256):

    默认值(2兆像素)下最大缓存画布的示例。滚动查看内容:

    carMaxCache.png (1773×1182)

    如果效果无法展示,可前往官网体验:http://fabricjs.com/fabric-object-caching

    How much performance gain I get, are there any problems?(我获得了多少性能,有没有什么问题?)

    这取决于您的项目外观。您是否仅绘制了一堆圆,矩形和简单的多边形?也许您不会获得那么多的性能。

    您要导入并显示大型和复杂的svg吗?好吧,您将从可能的关闭变为平滑。我应该注意什么吗?好吧,您可能不喜欢noScaleCache功能,这就是为什么有一个标记将其禁用的原因。

    What about compatibility problem with my current project? Should I update? Can I disable caching?(与我当前项目的兼容性问题如何?我应该更新吗?我可以禁用缓存吗?)

    我会说是的,切换到1.7.0,检查是否一切正常。如果没有向问题跟踪器报告任何视觉问题,您仍然可以在以下位置完全禁用该功能:

    fabric.Object.prototype.objectCaching = false;
    

    覆盖标准值,并且将为您的项目禁用缓存。

    Live samples(活样品)

    下面你可以看到2个fabric画布。左边的是默认的缓存,而右边的是绘制时禁用缓存,就像以前的版本一样。

    画布上装有沉重的路径组,白雪皑皑,我能找到的最重的路径是3份副本,使渲染速度下降。尝试在左侧或右侧画布上拖动形状之一,注意速度差异。

    Live samples

    如果效果无法展示,可前往官网体验:http://fabricjs.com/fabric-object-caching

    还可以发现值为true或false的noScaleCache之间的缩放差异。

    在左画布下方的画布中,canvas为false,这意味着在缩放tasinformation期间不会重新生成对象。如果将对象缩放到原始大小的3倍以上,则会注意到模糊,然后在执行鼠标向上移动时,会立即使用新的缓存副本进行修复。你自己试试:

    noScaleCache

    如果效果无法展示,可前往官网体验:http://fabricjs.com/fabric-object-caching

    When does the cache gets updated with a new version?(缓存何时更新为新版本?)

    Fabric有一个硬编码触发器,用于在开发人员没有简单方法插入代码的内置函数期间更新缓存。

    这些情况是:缩放、键入文本、画布全局缩放。

    在所有其他情况下,开发人员正在更改某个对象的某些属性以检测并触发更改,因此他还将通过操纵dirty标志将该对象设置为dirty。使用object方法set可以为您实现这一点。因此,调用object.set('fill','red')不需要其他操作。如果由于某些原因您没有使用set方法(例如,在文本对象处于设置某些属性的情况下会触发昂贵的函数),则将使用该标志。

    还有一种方法要求结构在渲染时检查属性更改。大多数情况下这并不昂贵,但我决定不使用它,因为在拥挤的情况下(例如喷刷或1000多个svg路径),它很昂贵。

    组和路径组的处理方式如下:

    当一个对象设置了一个属性时,该属性被选中,如果它在cacheProperties数组中,则该对象和组被设置为dirty。如果属性在stateProperties数组中,则只有组被设置为dirty。

    How does fabric check for changes in custom subclasses with custom properties?(fabric如何检查具有自定义属性的自定义子类中的更改?)

    自定义子类化是我认为最强大的结构特性之一,并且对象缓存已经建立在这个思想中。因此,有一个定义为cacheProperties的数组,它包含属性列表,当属性statefulcache设置为true时,在每次渲染时都会检查这些属性。(默认为false)。

    数组如下所示:

    cacheProperties: (
        'fill stroke strokeWidth strokeDashArray width height' +
        ' strokeLineCap strokeLineJoin strokeMiterLimit fillRule backgroundColor'
      ).split(' '),
    

    在不同的sublcasses中获得更多的属性,例如rect添加rxry等。这些属性递归地检查,这意味着在每次检测到更改时,都会保存该属性的副本,并且在下一次渲染时会进行深入的比较。通常需要深入检查的属性是gradients、patterns、path array、strokeDash。如果应用程序根本不使用某些属性,则可以将它们从cacheProperties数组中删除,并使检查更快,或者可以添加影响渲染的自定义属性以检查这些属性。

    Gotchas(陷阱)

    图像是对象边界框的截面:是。有一个不可见的画布可以保存对象的副本。此画布的大小取决于对象的宽度/高度。如果宽度和高度不适合我们要显示的对象,图像将被切断。除了禁用对象的缓存或修复问题之外,没有其他解决方案。

    当前受影响的用例:

    - (mainly solved since 1.7.7) sometimes things can look blurry
    - (mainly solved since 1.7.8) paths with wrongly parsed command sequence (very few)
    - (mainly solved since 1.7.3) Text using custom fonts with very big ascender/descender and of wich canvas is not able to measure extension.
    - Groups not initialized correctly ( created empty and not updated after using the .add method, please use addWithUpdate)
    - Scaling events that reset scale and modify width/height, disable noScaleCache, set it to false
    
    展开全文
  • Introduction to Fabric.js/ Part 8 - Clipping with clipPaths ClipPaths basics The new clipPath property(新的clipPath属性) 在2.4.0中,我们为所有对象引入了clipPath属性。 ClipPath将替换clipTo:funcion(){}...

    Introduction to Fabric.js/ Part 8 - Clipping with clipPaths

    其他文章见:Fabric.js中文文档导航

    ClipPaths basics

    The new clipPath property(新的clipPath属性)

    在2.4.0中,我们为所有对象引入了clipPath属性。 ClipPath将替换clipTo:funcion(){},以实现相同的灵活性,但具有更好的兼容性。

    ClipPath需要对象缓存。

    How to use it(如何使用)

    将您自己的clipPath创建为普通的Fabric对象,并将其分配给您要裁剪的对象的clipPath属性。 根据SVG规范中的定义,clipPath没有stroke,并用黑色填充,与黑色像素重叠的对象的像素将是可见的,而其他像素则不可见。

    让我们从一些基本示例开始,然后看看它的外观。 在此第一个示例中,红色的rect被一个圆圈夹住,只有圆形内的部分可见。虽然不是很有用,但是基本功能是这样的。

    请注意:clipPath从对象的中心开始定位,对象originX和originY不起任何作用,而clipPath originX和originY起作用。定位逻辑与fabric.Group相同。

    <template>
      <div class="groups">
        <canvas id="canvas"></canvas>
      </div>
    </template>
    <script>
    import { fabric } from "fabric";
    export default {
      data() {
        return {
          canvas: "",
        };
      },
      mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 400,
          height: 400,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Circle({
            radius:40,
            left:-40,
            top:-40
        })
    
        var rect = new fabric.Rect({
            width:200,
            height:100,
            fill:"red"
        })
    
        rect.clipPath = clipPath;
        this.canvas.add(rect)
      },
    };
    </script>
    <style>
    </style>
    

    image-20210330095035682

    我们可以剪辑一个组:

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Circle({
            radius:100,
            top:-100,
            left:-100
        })
    
        var group = new fabric.Group([
            new fabric.Rect({width :100,height:100,fill:"red"}),
            new fabric.Rect({width :100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width :100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width :100,height:100,fill:"green",left:100,top:100}),
        ]);
    
        group.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330095642004

    或者我们可以使用组进行剪辑。如果是组,请记住组中的每个对象在逻辑上或与其他对象成对,否则就不会有非零或奇数的裁剪规则。

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Group([
            new fabric.Circle({radius:70,top:-70,left:-70}),
            new fabric.Circle({radius:40,top:-95,left:-95}),
            new fabric.Circle({radius:40,top:15,left:15}),
        ],{left:-95,top:-95})
    
        var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        group.clipPath = clipPath;
        this.canvas.add(group);
      },
    

    image-20210330100942531

    Continue with more examples

    More advanced use cases(更多高级用法)

    Nesting clipPaths(折叠clipPaths)

    clipTo和canvas.clip()用法的一个问题是您一次最多只能有一个clipPath。

    通过此实现,clippaths可以具有自己的剪切路径。尽管手动编程不太直观,但它允许将clipPaths与gheter相交。

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Circle({radius:70,top:-50,left:-50});
        var innerClipPath = new fabric.Circle({radius:70,top:-90,left:-90});
        clipPath.clipPath = innerClipPath;
    
        var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        group.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330101926870

    组内对象中的ClipPath应与组本身的clipPath隔离:

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
      	var clipPath = new fabric.Circle({radius:100,top:-100,left:-100});
    
        var small = new fabric.Circle({radius:50,top:-50,left:-50})
    
        var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red",clipPath:small}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        group.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330102300786

    Clipping with Text

    同样,使用clipTo也无法进行文本剪切,因此开发人员通常不得不依靠这种模式。

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Text(
            'Hi I\'m the \nnew ClipPath!\nI hope we\'ll\nbe friends',
            {top:-100,left:-100}
        );
    
        var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        group.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330102719377

    Continue with more examples

    Clipping the canvas(剪裁画布)

    我们可以像对对象一样将clipPath应用于StaticCanvas。在这种情况下,clipPath受缩放和平移的影响,与Object.clipPath相反,它位于左上角。

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
    		var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        var clipPath = new fabric.Circle({radius:100,top:0,left:50})
    
        this.canvas.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330103259220

    与旧的clipTo函数一样,除非您将canvas.controlsAboveOverlay设置为true,否则clipPath也是剪辑控件。

    mounted() {
        this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
    		this.canvas.controlsAboveOverlay = true;
    
    		var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ])
    
        var clipPath = new fabric.Circle({radius:100,top:0,left:50})
    
        this.canvas.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    image-20210330103731185

    Animating the clipPaths

    ClipPath可以像其他任何对象一样设置动画。画布clipPath动画非常有效,而为Object动画时,每次都会使对象缓存无效。

    mounted() {
        var canvas = this.canvas = new fabric.Canvas("canvas", {
          width: 300,
          height: 300,
          backgroundColor: "#ddd",
        });
    
    		var clipPath = new fabric.Rect({width:100,height:100,top:0,left:0})
    
        this.canvas.controlsAboveOverlay = true;
    
        function animateLeft(){
            clipPath.animate({
                left:200,
            },{
                duration:900,
                onChange: canvas.requestRenderAll.bind(canvas),
                onComplete:animateRight,
            })
        }
        function animateRight(){
            clipPath.animate({
                left:0,
            },{
                duration:1200,
                onChange:canvas.requestRenderAll.bind(canvas),
                onComplete:animateLeft,
            })
        }
    
        function animateDown(){
            clipPath.animate({
                top:100,
            },{
                duration:500,
                onChange:canvas.requestRenderAll.bind(canvas),
                onComplete:animateUp,
            })
        }
    
        function animateUp(){
            clipPath.animate({
                top:0,
            },{
                duration:400,
                onChange:canvas.requestRenderAll.bind(canvas),
                onComplete:animateDown
            })
        }
    
        var group = new fabric.Group([
            new fabric.Rect({width:100,height:100,fill:"red"}),
            new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
            new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
            new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
        ],{
            scale:1.5
        })
    
        animateLeft();
        animateDown();
    
        this.canvas.clipPath = clipPath;
        this.canvas.add(group)
      },
    

    Mar-30-2021 10-57-38

    Continue with more examples

    Clipping the objects with absolute clipPaths(使用绝对定位的clipPaths剪切对象)

    我们可以对一个对象应用clipPath,指定它应该是绝对定位的。这意味着clipPath不是相对于对象的中心,而是仅仅定位在画布上。
    物体将不会移动,而clipPath将保持稳定。效果是clipPath在画布上创建了一个形状,并且只允许它自己的对象出现在画布中。

    mounted() {
       var canvas =  this.canvas = new fabric.Canvas("canvas", {
          width: 500,
          height: 500,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Rect({width:500,height:250,top:0,left:0,absolutePositioned:true})
    
        var clipPath2 = new fabric.Rect({width:500,height:250,top:250,left:0,absolutePositioned:true})
    
        fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg",function(img){
            img.clipPath = clipPath;
            img.scaleToWidth(500);
            canvas.add(img);
        })
    
        fabric.Image.fromURL("http://fabricjs.com/assets/dragon2.jpg",function(img){
            img.clipPath =clipPath2;
            img.scaleToWidth(500);
            img.top = 250;
            canvas.add(img)
        })
      },
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cO5mrx64-1617186594090)(https://gitee.com/eternitywith/blog-image-bed/raw/master/fabricjs/image-20210330111408043.png)]

    Inverted clipPaths(颠倒的clipPaths)

    我们还可以裁剪具有从clipPath定义的倒置形状的对象。 警告:如果创建一个组,则必须反转该组。反转组中用作clipPath的单个对象不会产生任何效果,因此不受支持。

    您也可以使用单个对象的globalCompositeOperation获得很酷的效果,但是也不支持。

    mounted() {
       var canvas =  this.canvas = new fabric.Canvas("canvas", {
          width: 500,
          height: 500,
          backgroundColor: "#ddd",
        });
    
        var clipPath = new fabric.Circle({radius:100,top:-200,left:-200});
    
        var clipPath2 = new fabric.Circle({radius:100,top:0,left:0})
    
        var clipPath3 = new fabric.Circle({radius:100,top:0,left:-200})
    
        var clipPath4 = new fabric.Circle({radius:100,top:-200,left:0})
    
        var g = new fabric.Group([clipPath,clipPath2,clipPath3,clipPath4])
    
        g.inverted = true;
    
        fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg",function(img){
            img.clipPath = g;
            img.scaleToWidth(500);
            canvas.add(img);
        })
      },
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAjwOz52-1617186594091)(https://gitee.com/eternitywith/blog-image-bed/raw/master/fabricjs/image-20210330112036636.png)]

    不颠倒的效果( g.inverted = false)如下:

    image-20210330112322753

    展开全文
  • Introduction to Fabric.js. Part 4. 在上一个系列中,我们讨论了很多主题。从基本的对象操作到动画,事件,过滤器,组和子类。但是仍然有一些非常有趣和有用的事情要讨论! Free drawing 如果说有什么功能能让<...
  • 这是本人在项目中用canvas画图,并对所画的图形当作对象操作所使用的canvas库fabric.js的方法总结
  • fabric.js官网(http://fabricjs.com/) fabric.js官方网站给出了控制器样式的修改,但仅局限于边框颜色以及边框节点形状的等基本样式的修改方式,无法修改添加图标,如图 官方文档修改样式代码 fabric.Object....
  • Fabric.js中文文档

    千次阅读 2021-03-31 17:53:22
    Fabric.js中文文档导航 说明: 1、本系列如果有两个超链接,则第一个是官方文档链接,第二个是中文文档链接,用/分隔,若不存在第二个链接或第二个链接无法跳转则代表没有或还未完成。 2、本系列大部分代码demo都是...
  • # Vue中用fabric.js画线会出现错位、放大等等问题。 ``` let l1 = new fabric.Line([10,10,20,20],{stroke: "red", strokeWidth: "1"}); //x let c1 = new fabric.Circle({radius: 20, fill: "green", left: ...
  • Fabric.js解读

    千次阅读 2019-07-28 10:49:52
    官 网:http://fabricjs.com/ npm地址:https://www.npmjs.com/package/fabric 开源协议:MIT 周下载量:4.8w 浏览器支持:Firefox 2+,Safari 3+,Opera 9.64+,Chrome (所有版本),IE10, IE11, Edge fabric...
  • fabric.js vue Vue-Fabric-wrapper (vue-fabric-wrapper) Vue Fabric.js Wrapper. Vue Fabric.js包装器。 View Demo 查看演示 View Github 查看Github Installation️安装 (⚙️ Installation) $ npm install vue...
  • Fabric.js 避坑指南

    2021-01-28 23:50:06
    新手写了几周 Fabric.js,项目是使用 group 对象对图片进行旋转缩放标记等操作,分享一下印象比较深的坑。随缘更新,欢迎讨论。
  • 在通过 loadSVGFromString 来进行渲染,报错 错误内容 fabric.js:4477 Uncaught TypeError: Cannot set property 'crossOrigin' of undefined at Object.fabric.parseSVGDocument (fabric.js:4477) at Object....
  • T恤简单的设计师应用程序
  • 问题 常见的在 canvas 里请求跨域图片导出时产生的跨域问题: ...很巧的是 fabric.js 用来做 canvas 操作时,其图片导入方法 fabric.Image 也给我们提供了一个 crossOrigin 属性设定。 于是: const image = new Imag
  • Fabric.js 实现文本自动换行

    千次阅读 2021-10-02 18:43:31
    Fabric.js中,可以通过Text或 IText;创建文字,但是文本是无法换行 Fabric.js 提供了 Textbox 类,继承自IText; Textbox 类允许用户调整文本矩形的大小并自动换行。文本框的Y比例已锁定,用户只能更改宽度。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,999
精华内容 3,199
关键字:

Fabric.js