angular routerlink传递参数_基于Angular的Canvas手写签名插件

灵感来源

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

966a272f32b9a1234765fc0dafc15674.gif
签名演示

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

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

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

6032862b9026c9ee09366ed25494ca84.gif
全屏签名

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

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

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

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

一. API风格更加ng化

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

7a255c6a02dc140d1704e0713dc5ac43.png
摘自sp README部分

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

<ngx-signature-pad
  [options]="options"
  (beginSign)="onBeginSign()"
  (endSign)="onEndSign()">
</ngx-signature-pad>

二. 只有小屏签名

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

sp.fullScreen();

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

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

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

8205406628738e4d74b8c96b4e360000.png
小屏签名

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

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

21369cf60cf006ce6818f8372f7a45ad.png
全屏签名

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

a8012b88515d5221aaaa52e7f87b0ff1.png
摘自ngx-sp源码

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

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

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

// Returns true if canvas is empty, otherwise returns false
signaturePad.isEmpty();

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

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

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

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

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

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

0226cae7e19288f525f4f20a3c725d1e.png
摘自sp源码

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

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

c810afdd5c60eccda14cb9f977661c1f.png

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

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

0cfeb1da93c547d811aab20016815ee8.png
摘自ngx-sp源码

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

四. 自由度不够

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

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

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

a3ddc64f88706a99b6a76121fbae1bf0.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只允许你设置背景颜色, 而且是纯色.

faf0b83749f893d2a5318b1c7e86c221.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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值