canvas 插件_基于Angular的Canvas手写签名插件

灵感来源

之前, 在轻流的业务中遇到了一个需求, 是能够让客户使用手写签名的功能.

7d6a5c0a1dcdf2b68b93e6adf990dd01.gif
签名演示

问题来了, 这...我不会啊! 这得是Canvas了吧. 正所谓, 插件用的好, 下班走的早. 于是我就开始找插件了. 找到了一个ng生态的插件, 名字不记得了, 只记得他就一个核心文件, 封装了一个第三方插件. 没有提供任何原创的方法, 都是直接把第三方签名插件所提供的方法emit了出来. 以下就是他import的第三方插件.

https://github.com/szimek/signature_pad​github.com

那么问题来了, 那我要你干嘛? 我为啥不自己封装一个呢? 因为业务比较紧, 没有那么多时间去思考如何封装地更好. 所以直接在轻流中封装了一个更加适合轻流业务的签名模块. 比如说, 全屏签名

30c2edfcaa2067f0cfe701ad37e47f96.gif
全屏签名

在完成业务后, 我使用angular library封装了属于自己的第三方插件.

https://github.com/eve-sama/ngx-signature-pad​github.com

那么我的插件有什么特别之处呢? of course~ 因为第三方插件我认为有些地方的设计不是很合理, 并且没有一些我想要的API.

注意: 为了方便描述和对比, 在下文中, 第三方插件我将称之为sp(signature pad的缩写), 我的插件将称之为ngx-sp.

一. API风格更加ng化

现在让你来设计这个签名组件, 要求实现当用户签字的时候通知父组件一个签名事件. 当结束签字的时候需要通知父组件一个结束事件. 我们先看看sp是如何处理的

42b2c3e6ad7f8a60853dd7fcd3d035bc.png
摘自sp README部分

sp是通过一个对象的形式传递参数, 包括事件也是通过回调函数的方法. 如果是我我就不会这么设计. 我觉得ng社区的同僚应该下意识都是像下面这样设计API的

<

二. 只有小屏签名

其实全屏签名是个非常常见的场景, 但是sp并没有提供. 其实这个不能说是sp的问题. 因为他提供了一块儿签名的canvas, 理论上你就可以在这个基础上开发出各种姿势的签名. 只是我比较懒, 我希望他能提供类似如下的代码

sp.fullScreen();

遗憾的是他没有, 在全屏相关的需求中, Angular CDK是个非常好的工具, 其实可以结合CDK轻而易举地实现这样的需求. 所以, sp没有, 那ngx-sp就来做.

adecc269cebe40fdd67de369373c0180.png
摘自ngx-signature-pad README部分

需要注意一点, 大家想象下, 你比如初始化了一个签名组件, 尺寸是300*150, 在上面画了几笔. 大概这个样子

ed51cd0ab16f9e31f654c28a90b47592.png
小屏签名

当调用fullScrren()的时候, 签名组件会展示全屏化, 请问, 已经签过的内容该如何处理呢? 显然是要放大的吧. 但是小屏签名的宽高是由用户自定义的, 那么全屏的话, 假如ngx-sp真的100%的宽*100%的高, 不一定和用户设定的比例相同.

比例不同造成的后果, 就是已签过的内容会被拉宽或者拉高. 所以, 我的设定就是全屏的宽高比与小屏的宽高比是保持一致的.

58a4264e6a7bffd5e3d5e412fd97dd8c.png
全屏签名

顺便一提, 之所以我执意要把全屏的API封装进ngx-sp, 是因为全屏要做的事儿比较恶心, 我不想在业务层做这种事儿. 这几十行倒也算不上很难, 就是对canvas不熟悉、数学又差的一逼的人, 比如我, 比较折腾.

aa7a8ef8db6f81dbfcc2457c137adbdc.png
摘自ngx-sp源码

现在好了, 你只需要一个xxx.fullScreen()就可以直接全屏化, 那叫一个美汁儿美汁儿~

三. 只能判断是否被签过, 不允许更改状态

在sp中, 是这样判断是否被签名过的

// Returns true if canvas is empty, otherwise returns false

但是并没有提供手动更改签名状态的方法. 为什么需要这样的函数呢?

比如说前文的全屏签名, 大家注意看这个操作过程

  1. 先显示小屏签名, 允许用户签名
  2. 当点击放大图标时, 全屏覆盖签名
  3. 再点击缩小图标时, 显示小屏签名

我的思路, 其实是创建2个canvas实例. 一个用于小屏, 一个用于全屏(使用CDK包装). 当用户切换模式的时候, 就会把原模式的内容copy到新模式的canvas上. 但是因为sp没有提供手动更改签名状态的方法, 就会导致一个问题.

当ngx-sp把小屏签名的内容copy到全屏签名上, 此时调用isEmpty()方法, 一定是true(也就是显示你从未签名过, 从逻辑上看, 这就是bug了). 因为你全屏签名的内容并不是鼠标绘制出来的. 而是通过canvas相关的方法copy的.

查看sp的源码, 会发现相关属性是private

2f820284a12b279ddd19f2f4502e08fb.png
摘自sp源码

问题不大, 在轻流的业务模块中, 我就强行把_isEmpty给改了. 反正private在run time时被更改, 浏览器也拦不住我.

在ngx-sp中则对外提供了手动更改状态的函数

753531e2311dcbb617e34fd69313ee9a.png

当然了, 在ngx-sp中没有使用强行更改private这种野路子的方法. 那么我是怎么做的呢? 核心思路其实就是我自己维护了这个变量.

下面这段代码, 简单来说就是在initSmallPad()中会根据开发者传递的参数(options), 初始化sp. sp对外提供了一个onBegin的方法, 当他触发的时候, 我就会手动把_isEmpty标记为false. 既然这个变量由我自己来维护, 那么我就可以任意更改了.

e7281e1c5daa5c3360d43fdfecc09155.png
摘自ngx-sp源码

所以, 同样对外暴露了isEmpty()的方法, 但是我的判断依据并不是根据sp源码里的变量, 也不是直接调用的sp的isEmpty(), 而是我自己维护的私有变量.

四. 自由度不够

sp并没有对外暴露canvas实例相关的属性. 这是一个很麻烦的事儿. 为什么呢, 给不了解canvas的同学科普一个概念. canvas是允许通过dragImage方法把图片等资源画在上面的, 如下图.

8de432c75f7dfa9d5216e801489f69e1.png
https://eve-sama.github.io/ngx-signature-pad/document (注意是PC模式)

我常年写的字儿自己都不认识. 上图的签名显然不是我手画的. 其实'前夕'那2个字是个图片.

e209779608ffd97afd0d70fd61388c7f.png
摘自ngx-sp README

在ngx-sp中很容易做到这样的事儿.

this.signature.getContext().drawImage(this.image, 230, 35, 100, 50, 230, 110, 100, 50);
this.signature.setDirty();

举个例子, 假如你的产品经理希望你在签名区域+个背景图, 类似下面这样. 在sp中确实没法实现, 因为sp只允许你设置背景颜色, 而且是纯色.

8f34d44d5b6acf85d7c88769a6578612.png
百度随便搜的

而如果在ngx-sp中, 通过获取canvas相关实例, 你可以想怎么画就怎么画.

总结

以上就是对ngx-signature-pad的介绍了, 更多介绍请查看Repo. 我也只是站在巨人的肩膀上做了一点点扩展, 希望能帮助到有需要的人~!

Repo地址

https://github.com/eve-sama/ngx-signature-pad​github.com

demo页, 如果使用浏览器的PC模式访问则侧重文档, Mobile模式则侧重demo.

NgxSignaturePad​eve-sama.github.io
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值