Fabric.js进阶自订控制项

2018-11-28 12:57:07
2883次阅读
0个评论

今天要来做更进阶的自订控制项,不只能够修改内建的一些样式,够能够让我们使用自己想要的图示来做控制项,甚至变更每个控制项的功能。


今日就来做把左上控制项改成删除功能。

物件控制一些基础样式调整可以参考
Day 15 - Fabricjs 物件控制项样式调整
透过复写原本的方法

因為 fabricjs 并没有提供 api 能够让我们去改变物件的控制项,所以我们必须透过复写原来 fabricjs 所绘画控制项的方法,来达到自订控制项的目的。

这边讲一下自己再复写的心得,到 fabricjs docs 找有没有对应的方法。可以看到我找到了 Object.drawControls 这个方法。

接著看到的 Source 点选 line 15906 连结可观看 fabricjs 原始码这个方法的所在地。

点选 line 15906


就能看到 drawControls 原本的样貌啦


复写 fabric.Object.prototype.drawControls

我们想要做的是改变所有產生出来的物件的控制项,所以我们必须要来复写 fabricjs 原本画出控制项的方法。

也就是 fabric.Object.prototype.drawControls,这个方法為 fabricjs 原本画出控制项图示的方法。

再覆盖之前,我们得先去参考原本的写法如何,再来做客製化修改。
Fabricjs 原始码 #line15906 drawControls
// 变更所有物件画出的控制项
fabric.Object.prototype.drawControls = function (ctx, styleOverride) {
  // 复写他,改成什麼都不画
}

const rect = new fabric.Rect({
  width: 100,
  height: 100,
  left: 100,
  top: 100
})

canvas.add(rect)

可看到因為把 drawControls 覆盖过去了,所以看不到任何控制项。


接著直接将

fabricjs drawControls method source: http://fabricjs.com/docs/fabric.js.html#line15906
整段 call 下来复写,就会正常画出控制项了。

接著分析一下原始码,可以发现控制向都是透过一个名為 _drawControl 的私有函数所画出来的。

// top-left
this._drawControl('tl', ctx, methodName,
  left,
  top, styleOverride);

把任何一个拿掉就会少掉那一个控制项。

接著我们把原本的 _drawControl 拿掉,换成我们自己的方式画出控制项。

// top-left
const cancel = new Image()
cancel.src = 'https://upload.wikimedia.org/wikipedia/commons/6/65/Crystal_button_cancel.svg'
ctx.drawImage(cancel, left, top, this.cornerSize, this.cornerSize)

OK,这样一来,就能够有自己定义的控制项图示了。


不过这时我们是想将左上角的控制向改成删除的功能,但发现只是改变了图示,并没有连功能都一起被改变。

再次来复写 fabric.Object 的 prototype

接下来来改写原本是缩放功能的控制项,改成删除的功能。
一样先看了 fabricjs doc 不过发现好像没有什麼线索,只好透过 google 大神。

大神告诉我 _getActionFromCorner 这个方法,看起来就像是我们所需要的,稍微在看了一下 fabricjs 原始码,大概了解了前因后果。

__onMouseDown 当在 canvas 中点下后触发。其中就判断一些你是否点在物件上,若点选在物件上则触发 _setupCurrentTransform 来设定接下来要转变资讯。
_setupCurrentTransform 设定转变资讯,其中有一个 _getActionFromCorner 方法判断点选的控制项使用什麼方法。
_getActionFromCorner 纪录会做的动作,因為原本的控制项就只有缩放和旋转,都只是在之后 mousemove 发生时会做的动作,所以只有纪录接下来会发生甚麼事情,而我们要改变的删除方法,加在这边就可以了。
复写 fabric.Canvas.prototype._getActionFromCorner

这边很简单就复写 _getActionFromCorner 方法,在 switch case 加上自己自订的方法就可以了。

fabric.Canvas.prototype._getActionFromCorner = function(target, corner, e) {
      if (!corner) {
        return 'drag';
      }
      switch (corner) {
        case 'mtr':
          return 'rotate';
        case 'ml':
          break;
        case 'mr':
          return e[this.altActionKey] ? 'skewY' : 'scaleX';
        case 'mt':
        case 'mb':
          return e[this.altActionKey] ? 'skewX' : 'scaleY';
        case 'tl': // 增加左上删除动作
          canvas.remove(target)
          return 'deleted'
        default:
          return 'scale';
      }
    }

改变鼠标样式

最后我们将原本缩放的箭头样式,改成手指 pointer 样式。

直接修改 fabric.Canvas.prototype.cursorMap 这个阵列就可以了。

 
var cursorOffset = {
        mt: 0, // n
        tr: 1, // ne
        mr: 2, // e
        br: 3, // se
        mb: 4, // s
        bl: 5, // sw
        ml: 6, // w
        tl: 7 // nw
      }
fabric.Canvas.prototype.cursorMap[7] = 'pointer'


参考 fabricjs 原始码 #line10929
这样就完成客製化自己的控制项囉,将左上角改為删除功能


本日小结

fabricjs 对使用自订控制项,并没有提供简易的 api 来变换控制项。

但还是能透过修改原本 fabricjs 提供的方法来达到需求。

缺点是若版本不同,作法可能会不同,因為不是正规提供的方法,且要复写必须要深入 fabricjs 原始码了解原本写法,较麻烦。

但有人提供了一个良好的解决方案 - fabricjs-customise-controls-extension
来解决这个问题,明天再来介绍。

价值 $150 的问题

Ability to customize controls $150
有人悬赏了 150 美元為了解决这个问题,其实一些 fabricjs 主要的贡献者也有想要修改此问题,加入能够让开发者好用的 api,从 2015 年就开始讨论此问题 (客製化 controls icon & 功能),不过到现在还没有被完美的被解决。

贡献者表示他还有其他更重要的事情要做 XD



最新的进展是写上面那个 extension 的人想协助将套件加入 fabricjs 核心,不过因為一直在更新似乎还没有看到结果。

写这篇文章时版本為 2.4.3
收藏00

登录 后评论。没有帐号? 注册 一个。