背景
通过平板抄写公式、文字等
需求分析
- 一个抄写模板展示面板
- 面板可拖动、缩放
- 面板不可影响手势采集
- 实时轨迹
- 实时可视化用户手指/笔在平板上的绘制轨迹
- 通过手势绘制一个多边形来圈选轨迹集合
- 可撤销上一条轨迹
- 轨迹图可缩放、拖动
- 背景网格
- 工具栏
- 可折叠展开
- 笔画可调整大小、颜色
- 展示一些额外信息
- 清空轨迹
- 撤销上一条轨迹
- 可全屏
- 审核时,可附加审核数据
功能拆分
- toolBar:工具栏
- modelBar:模板bar
- EventProxy:事件代理层
- fabric:视图层
- paintZone
- sider:侧边栏
- core:内核层,数据处理
- forbidenZone:禁止绘画bar
技术选型
涉及复杂轨迹的增删,canvas和svg都无法满足要求,需要一个封装几何元素、集管理、优化、抽象为一体的框架,开源库中有konva/fabricjs,fabricjs目前活跃度最高,所以技术选型为fabricjs。
架构设计
设计图如下 主要是将事件代理层解耦出来,做统一的代理、性能优化并分发
设计模式
- mvc:利用model层+react-hook的方式控制view层,即利用了react-hook的范围锁定、也高度放开了controller层的可操作性
- 订阅发布模式:将事件监听层剥离出来,以订阅发布的方式管理,解耦了事件监听层和事件处理层,提高了可维护性、可测试性。
- fabric
- 工厂模式:大部分几何元素都通过一个工厂类来生成
- 单例模式:全局唯一的canvas对象,方便共享变量,全局访问
- 观察者模式:将事件触发和事件处理通过订阅发布的方式解耦
- 命令模式:以遥控器里的各个按钮(命令)来控制电视机;fabricjs将用户的操作(创建元素、移动、旋转、缩放对象)命令化,从而能记录用户的行为并方便撤销行为
- 适配者模式:对不同的浏览器做不同的适配操作
问题收集
性能问题
- 圈选是实时的,即判断一个多边形是否相交于或包含于一条复杂轨迹,因为使用了射线法,当遇到大量轨迹的时候,可能会卡顿。目前做了多重优化手段,比如函数节流、先稀疏复杂轨迹的点、然后判断图形的占位区域是否相交、然后判断图形的线段之间是否相交、然后判断是否包含关系。
- 轨迹的实时生成,在一长串touchmove事件中,使用一个初始化的polyline,后续更改其点集,这样只需要实例化一个对象,性能高。
- touchmove回调里执行复杂的逻辑,这会阻塞touchmove的触发频率,我们将touchmove里的回调通过settimeout放到异步队列中,这样就剥离了touchmove
事件层
和 回调函数处理层
,这样touchmove的触发频率就不会被影响
禁止绘制区域
该需求无法实现,因为当我们手掌放在平板上时,会触发系统级别的误触识别算法,阻止所有的触摸事件,所以我们没办法在页面上实现该功能。
项目总结
最值得突出的两个点,
- 针对三个性能问题的优化
- 设计模式的添加,从fabricjs的设计模式中学到很多,比如工厂模式、单例模式、命令模式、观察者模式的应用