本文简介

点赞 + 关注 + 珍藏 = 学会了


fabric.js 在出厂时就提供了几个根底图形,比方矩形、圆形、三角形等。

但这些图形可能不能满足日常开发,咱们可能还须要一些自定义的图形。

我做了个 自定义半圆 的demo,聊聊如何创立自定义图形。


尽管 fabric.js 提供了非常简单的办法创立自定义子类,但如果须要创立简单的图形,还是须要有肯定 canvas 根底的。

如果你还不太熟悉原生 canvas ,举荐浏览 《Canvas 从入门到劝敌人放弃(图解版)》


本文所有案例都默认引入了 fabric.js ,所以不会在每段代码里反复引入了。



什么是 fabric.js 的子类?

fabric.js 类的概念其实和原生 jsclass 差不多。

fabric.js 中,能够创立类,能够继承类。

比方在 官网例子 中,继承 矩形 创立进去的一个带文本的类。它领有矩形元素的所有属性和办法,同时还增加了 label 属性,能够在矩形中增加文本标签。



fabric.js 如何创立类?

文档:fabric.util.createClass

fabric.js 中创立类,能够应用 fabric.util.createClass() 办法。

这里借用官网的demo进行解说。

let Point = fabric.util.createClass({  initialize: function(x, y) {    this.x = x || 0    this.y = y || 0  },  toString: function() {    return `${this.x}/${this.y}`  }})

fabric.util.createClass 承受一个对象参数,并基于该对象的配置创立一个“类”。

须要注意的是 initialize 属性,initialize 的值是一个办法,用于初始化。有点相似原生 jsclassconstructor 。留神,是相似

initialize 中接管实例化时传进来的参数。

let point = new Point(10, 20)console.log(point.x) // 10console.log(point.y) // 20console.log(point.toString()) // "10/20"



子类的继承

在创立类时,只需在 fabric.util.createClass 中传入1个对象即可。

如果创立子类时须要继承某个父类,则要在 fabric.util.createClass 中传入2个参数。

fabric.util.createClass(parentopt, propertiesopt)

  • parentopt: 父类
  • propertiesopt 创立子类的对象(和后面创立类的对象一样)


还是 官网例子 。

在后面的创立类时,咱们创立了一个 Point 的类,这个类只承受 xy 属性;外部还有一个 toString() 办法。

如果咱们想在 Point 类的根底上再创立一个 ColoredPoint 类(也就是 ColoredPoint 继承 Point),能够这样写。

let ColoredPoint = fabric.util.createClass(  // 参数1:父类  Point,  // 参数2:子类  {    initialize: function(x, y, color) {      this.callSuper('initialize', x, y) // 传给父类的      this.color = color || '#000' // 新增的 color 属性    }  })

此时 ColoredPoint 就继承了 Point ,并在 Point 的根底上多了 color 属性了。

let redPoint = new ColoredPoint(15, 33, '#f55')console.log(redPoint.x) // 15console.log(redPoint.y) // 33console.log(redPoint.color) // "#f55"console.log(redPoint.toString()) // "15/33"

Point 里有 toString() 办法, redPoint.toString() 会先 ColoredPoint 找,找不到就从 Point 找。一层层往上找。


如果在 ColoredPoint 中又定义了 toString() 办法,就会笼罩 Point 里定义的。

// 省略局部代码// 父类let Point = new fabric.util.createClass({  initialize(x, y) {...},  toString() {    return this.x + '/' + this.y  }})// 子类let ColoredPoint = fabric.util.createClass(  // 参数1:父类  Point,  // 参数2:子类  {    initialize(x, y, color) {...},    toString() {      return '雷猴'    }  })// 实例化let redPoint = new ColoredPoint(15, 33, '#f55')console.log(redPoint.toString()) // "雷猴"


如果在子类中想继承父类的办法能够应用 callSuper

// 父类let Point = new fabric.util.createClass({...})// 省略局部代码let ColoredPoint = fabric.util.createClass(  // 参数1:父类  Point,  // 参数2:子类  {    initialize(x, y, color) {...},    toString() {      return this.callSuper('toString')    }  })// let redPoint = new ColoredPoint(15, 33, '#f55')console.log(redPoint.toString()) // "15/33"


还能够二次包装

// 省略局部代码// ColoredPoint 的,省略局部代码toString() {  return '从子类ColoredPoint调用: ' + this.callSuper('toString')}// 输入 redPoint 的,省略局部代码console.log(redPoint.toString()) // 从子类ColoredPoint调用: 15/33



继承 fabric.js 自带的图形

在官网案例中实现了这么一个成果。

上图的成果是一个继承了矩形的子类。

矩形是 fabric.js 默认提供的图形对象之一,继承矩形时只需把矩形当做 fabric.util.createClass 的第一个参数即可,而后再增加自定义性能。

// 省略局部代码// 创立带标签性能的矩形const LabeledRect = fabric.util.createClass(  // 要继承的是 fabric 的矩形  fabric.Rect,  {    type: 'labeledRect', // 增加一个 type 属性    // 初始化    initialize: function(options) {      options || (options = {}) // 初始化参数,免得报错      this.callSuper('initialize', options) // 继承      this.set('label', options.label || '') // 设置 label ,默认值是空      this.set({ width: 100, height: 50 }) // 设置默认宽高    },    toObject: function() {      return fabric.util.object.extend(        this.callSuper('toObject'),        {          label: this.get('label')        }      )    },    // 增加渲染时的操作    _render: function(ctx) {      this.callSuper('_render', ctx)      ctx.font = this.labelFont || '20px Helevtica'      ctx.fillStyle = this.labelFill || '#333'      // 将 label 渲染进去      ctx.fillText(        this.label,        -this.width / 2,        -this.height / 2 + 20      )    }  })// 创立标签矩形let labeledRect = new LabeledRect({  // width: 100,  // height: 50,  left: 100,  top: 100,  label: 'test',  fill: '#faa'})// 将标签矩形增加到画布中canvas.add(labeledRect)


因为继承的是矩形,所以还能够应用 fabric.Rect 的属性和办法。

// 省略局部代码labeledRect.set({  label: 'trololo',  fill: '#faf',  rx: 10,  ry: 10})

rxry 都是 fabric.Rect 的属性,能够设置圆角。



创立自定义子类

fabric.js 中的 矩形 Rect三角形 Triangl圆形 Circle 等图形元素都是继承 fabric.Object 的。

通过继承 fabric.Object 创立进去的元素对象,默认是有管制柄之类的货色。

接下来要创立的 “半圆” 元素也是继承 fabric.Object ,这是 fabric.js 提供的一个十分便当的对象。

<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script>  // 创立画布  let canvas = new fabric.Canvas('c')  // 创立半圆对象,继承 fabric.Object  let Semicircle = fabric.util.createClass(fabric.Object, {    // 初始化    initialize(options) {      this.callSuper('initialize', options)      this.width = 100      this.height = 50    },    // 渲染    _render(ctx)       ctx.strokeStyle = this.stroke || '#333' // 初始化描边色彩      ctx.lineWidth = this.strokeWidth || 1 // 初始化描边宽度      ctx.fillStyle = this.fill || '#333' // 初始化填充色      ctx.beginPath() // 开始绘制门路      ctx.arc(0, -25, 50, 0, 180 * Math.PI / 180) // 绘制半圆      ctx.closePath() // 完结绘制门路      ctx.stroke() // 描边      ctx.fill() // 填充    }  })  // 创立一个半圆  let semicircle = new Semicircle({    top: 10,    left: 10,    stroke: '#7bcfa6', // 描边色    fill: '#ed5736', // 填充色    strokeWidth: 10 // 描边宽度  })  // 将半圆增加到画布里  canvas.add(semicircle)</script>

_render 提供了 ctx 参数,这个参数是 canvas 提供的一个 context 对象。通过该对象能够发明不同图形,这是 canvas 的基础知识,也是 fabric.js 创立子类时必须把握的常识。

如果对 canvas 还不太纯熟的话,能够看看 《Canvas 从入门到劝敌人放弃(图解版)》


如果你不喜爱将子类定义成一个变量,也能够把子类绑在 fabric 上。

fabric.Semicircle = fabric.util.createClass(...)// 创立一个半圆let semicircle = new fabric.Semicircle(...)

尽管这么做看上去和创立矩形、圆形等图形的写法差不多,但我还是不太倡议这么做。

因为有可能一不小心就跟 fabric 的某个属性重名,有可能就被你笼罩了本来的办法。

所以还是将子类保留到独立的变量中比拟稳。



代码仓库

⭐创立子类 createClass



举荐浏览

《Fabric.js 从入门到_ _ _ _》

《Fabric.js 管制元素层级》

《Fabric.js 动静设置字号大小》

《Fabric.js 激活输入框》

《Fabric.js 自定义选框款式》

《Fabric.js 元素核心缩放》


点赞 + 关注 + 珍藏 = 学会了
代码仓库