Canvas好难,如何让研发低成本实现Web端流程图设计功能
摘要:本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
前言
相信大家在职场中经常会用到流程图,在互联网行业,绘制流程图不论在产品的设计阶段,还是后期优化业务流程的阶段,都有着巨大的价值。事实上,不仅是互联网行业,流程图其实广泛应用于各行各业。
比如说,银行在办理开户业务时,会有一套较为复杂的流程,中间不仅有固定的步骤,如审核材料、打印凭证等,还会有一些判断条件,如金额是否超过20万、是否需凭密码支取等,这个时候可以通过一张流程图来清晰明了地展现整个业务流:

再例如在进行新员工培训时,可能有多个部门之间的协作,那么用流程图也可以很好地帮助员工了解后续的培训步骤:

再举个例子,在互联网行业中,一个项目上线前需要进行完整的测试,测试分为很多类型,如黑盒、白盒、冒烟测试等,按照步骤进行,还要生成对应的测试报告。如果其中某一步测试不通过,需要通知研发修改bug,并重新测试,下面的流程图就可以非常清晰地展现研发、产品和测试相互合作的过程:
之所以有这么多的行业都在使用流程图,是因为它具备以下几点好处:
1. 让复杂的过程易于理解。
2. 方便识别业务瓶颈,改进现有流程。
3. 容易向其他人解释业务。
而SreadJS(本公司产品,一款前端在线Excel表格)也支持插入流程图,但是有时候我们并不想自己去绘制流程图,而是希望根据某种数据结构自动生成一个流程图,而这个数据可以在服务端自动拼接好,也可以直接是其他三方服务的数据。将数据发送到前端后,自动生成一个流程图,如果对流程图做出一定的修改,数据也跟着变动,这样流程图的数据也可以保存下来,方便下次使用。
假定我们目前有一个这样的数据结构(省略部分数据)。

其中elements数组保存了所有的流程,id为流程的唯一id值;text代表流程框中的文本;type代表是普通流程的矩形框还是决策型的菱形框;process代表当前流程的进展,分为未开始、进行中和已完成,默认为未开始;width和height代表形状的宽高,可以不写。
edge数组则包含了各个流程中间的连接关系,表现在流程图中就是箭头从source指向target,其中flag代表在决策型流程中的结果。
最终想要在SpreadJS中生成这样一个流程图:

那么如何才能实现这样的效果呢?我认为大致需要做以下几个工作:
1. 根据elements的信息,向SpreadJS插入所有流程图形状
2. 根据edge的连线关系,将各个形状摆放到正确的位置
3. 创建形状之间的连线
4. 添加监听,当流程发生变化时,动态地改变数据
实现步骤
接下来就讲一下以上四个步骤具体如何实现。
1. 根据elements的信息,向SpreadJS插入所有流程图形状
这一步比较简单,无非就是遍历elements,并向当前的sheet插入形状:

我们通过数据中的信息来修改shape的样式,包括宽高以及背景色。
这里我们可以将id挂在shape上,后续方便通过id找到对应的形状或者数据model。
另外,读者可以注意到我在数据model上挂载了两个函数,分别为next和prev,这是为了方便寻找流程的下一级或者上一级,后续会经常用到这两个函数。
这样处理后,SpreadJS中的形状就已经生成好了:

2. 根据edge的连线关系,将各个形状摆放到正确的位置
这一步是比较困难的,假设我们的流程图是由左向右扩展的,那么横坐标(x方向)的位置是很好确定的,每深入一级,横坐标向右移动即可,困难的在于纵坐标(y方向)的位置计算,我这里抛砖引玉,如果大家有更好的算法,可以在评论区分享~
大致思路如下:请看下图的结构,左右两图中,B、C两节点距离A的纵向位置是不同的,这是因为左图的B节点拥有更多的子节点,而右图则较少,所以左侧在纵向需要拉开更多的距离,以摆放后续的节点。

当然,这里并不是单指子节点数量的多少,而是要看他们所占据的高度,也就是兄弟节点的数量。所以在代码中,我们需要递归计算一个节点后续的高度值:

其中hasCountMax值是为了预防节点循环的情况,比如A→B→A,代码中还有类似的处理。
得到节点的高度值后,就可以计算位置了,这个高度值越大,它离父级节点的纵向距离就越远,当然这里还要考虑当前节点占据兄弟节点的第几个,以及父级、兄弟节点的高度情况:

最后的代码可以看到这里也是一个递归计算,需要计算每一个节点下一级的位置。
3. 创建形状之间的连线
这一步的思路有一点小复杂,但是实现起来比较简单。
难点主要在于确定连接点的位置。矩形和菱形都有4个连接点,在下图中,左2连接右2并不是最好的连接方式,我们希望是以下三种方式:左2右1、左3右1、左3右0 ,所以我们就需要根据两个形状的位置关系来确定连接点。

这里要用到一点初高中的数学知识,我们要计算从起始形状到目标形状中心位置的连线,与横轴夹角的正弦值来确定连接点:

这里一共有12种情况,不做一一赘述。
决策图的连线还要标明“是”和“否”两种不同的情况,计算连线的中心点并插入形状即可:

4. 添加监听,当流程图发生变化时,动态地改变数据

因为用户可以随时拖动流程图,而流程图的变化属性大致有以下几种:位置、长宽、文字属性,我们要将他们最新的值记录下来,方便下次还原。另外,当位置和长宽变化时,连线也会自动更新,我们需要更新上文提到的“是”和“否”的文字的位置,这里用到了防抖模式以提升性能。
另外,我还在设计器中添加了一些新菜单,可以对流程的状态进行修改,也可以将流程图导出为图片,或打印流程图的数据model等,感兴趣的读者可以在源码中自行查看实现方式。

这里展示一下修改流程图后,数据同步修改的功能,我们以“换货”举例,默认状态下,换货的数据是这样的:

我们通过上方的按钮调整换货为已完成,修改文本,并且移动它的位置,改变其宽高后:

可以看到,表示其状态的process已经从1(进行中)变成了2(已完成),宽高、位置、文本也有相应的变化。
结语:
流程图是一种非常有用,也很常用的工具,结合SpreadJS,你可以比较方便的实现动态生成流程图的功能,在这个demo的基础上,你还可以添加右键新增子级、新增兄弟级元素等功能,借助SpreadJS丰富、开放的Api,你可以非常灵活地实现你要的功能。
最后,希望这篇文章能对你有帮助~
源码地址:
扩展链接:
项目实战:在线报价采购系统(React +SpreadJS+Echarts)
Svelte 框架结合 SpreadJS 实现纯前端类 Excel 在线报表设计
Canvas好难,如何让研发低成本实现Web端流程图设计功能的更多相关文章
- snkrs web端分析,canvas中的fingerpint
snkrs web端分析,canvas中的fingerpint 代码如下 (()=>{ const canvas = document.createElement("canvas&qu ...
- 流量难、获客难、增长难?增长黑客思维“解救”B端业务
随着市场竞争的不断加剧,流量越来越贵.留存与转化越来越难,实现用户和业务的增长并不容易.无论是B2C 还是B2B的企业,都可能遇到增长的挑战.对于营销团队而言,传统的漏斗式营销思维已有些力不从心,需要 ...
- web图片前端裁剪功能实现_利用html5 canvas技术实现图片裁剪
用户上传头像然后截图的需求很常见,很多做法是把图像发送到后端,把裁剪后的结果发送给浏览器,这种方式会增加处理时延.最近正好学习了HTML5里的canvas,发现它的图片处理功能比较强大,就打算用can ...
- [canvas入坑3] 类似ps中魔术棒或者画图中油漆桶的功能
查看效果请到 http://philippica.github.io/ 点击fill 这功能其实实现很low,最早高一看黑书的时候看到了floodfill算法感觉好神奇,转念一想这不就是bfs么!! ...
- 剁手党也有春天 -- 淘宝 UWP ”比较“功能诞生记
前言 网购已经不再是现在的时髦,而变成了我们每天的日常生活.上网已经和买买买紧密地联系在了一起,成为了我们的人生信条.而逛街一词,越来越多地变成了一种情怀.有时候我们去逛街,要么是为了打发时间,要么是 ...
- 学习React Native必看的几个开源项目
学习React native ,分享几个不错的开源项目,相信你学完之后,一定会有所收获.如果还没有了解RN的同学们可以参考手把手教你React Native 实战之开山篇<一> 1.Fac ...
- django请求生命周期,FBV和CBV,ORM拾遗,Git
一.django 请求生命周期 流程图: 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post, ...
- python 全栈开发,Day84(django请求生命周期,FBV和CBV,ORM拾遗,Git)
一.django 请求生命周期 流程图: 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post, ...
- 9月16日,base 福州,2018MAD技术论坛邀您一起探讨最前沿AR技术!
“ 人工智能新一波浪潮带动了语音.AR等技术的快速发展,随着智能手机和智能设备的普及,人机交互的方式也变得越来越自然. 9月16日,由网龙网络公司.msup联合主办的MAD技术论坛将在福州举行.本次论 ...
- 搞IT产品,请谨记Mobile First
我们在哪儿? 作为一名企业IT的老鸟,发现一个比较有意思的事情,就是我们的企业IT产品,仍然投入大量的精力,在基于PC的WEB端的设计和交付上,而在APP上的,移动端的考虑,一直都是在PC搞完之后,再 ...
随机推荐
- Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round) 小记
在机房其它人都有许多的橙名小号后我终于大号上橙了(果然还是太菜了),写篇博客记录一下. 计数水平太弱,赛场最后 5 分钟乱糊了一个 F 的做法,后来发现其它人做法都短好多. A & B &am ...
- 推荐一个基于.Net Framework开发的Windows右键菜单管理工具
平常在我们电脑,我们都会安装非常多的软件,很多软件默认都会向系统注册右键菜单功能,这样方便我们快捷打开.比如图片文件,通过右键的方式,快捷选择PS软件打开. 如果我们电脑安装非常多的软件,就会导致我们 ...
- 2020-10-17:谈一谈DDD面向领域编程。
福哥答案2020-10-17:#福大大架构师每日一题# [答案来自此链接](https://www.jianshu.com/p/fb319d7674ff) 一个通用领域驱动设计的架构性解决方案包含4 ...
- vue全家桶进阶之路19:webpack资源打包工具
Vue.js 是一个前端开发框架,它可以帮助我们快速构建单页应用和复杂的交互界面.而 Webpack 则是一个前端资源打包工具,它可以将多个 JavaScript.CSS.HTML.图片等资源打包成一 ...
- mysql基础_视图
介绍 MySQL 视图(View)是一种虚拟存在的表,同真实表一样,视图也由列和行构成,但视图并不实际存在于数据库中.行和列的数据来自于定义视图的查询中所使用的表,并且还是在使用视图时动态生成的. 优 ...
- 03、SECS-I 协议介绍
03.SECS-I 协议介绍 上一篇我们学习了 SECS-II 协议,对 SECS-II 协议有了初略的了解,现在我们再来一起学习 SECS-I 协议. 文章的内容基本上来自参考资料和自己看的文档,若 ...
- Health Kit文档大变样,一起尝鲜!
Health Kit文档全新升级,开发场景更清晰,聚焦你关心的问题,快来一起尝鲜! 文档入口请戳:文档入口~ 如果你是运动健康的老朋友,可以从旧文档页面上方的提示信息中进入:最新版本哦. 一. 架构调 ...
- 6.4. HttpClient
1. 什么是HttpClient? HttpClient是Java 11中引入的一个新特性,用于支持同步和异步发送HTTP请求以及处理HTTP响应.它提供了简单易用的API,使得发送HTTP请求变得非 ...
- Win10环境配置(二) ——Java篇
Win10环境配置(二) --Java篇 1.工具准备 官网下载地址:[jdk-11.0.11](Java SE Development Kit 11- - Downloads (oracle.com ...
- 从0搭建Vue3组件库(九):VitePress 搭建部署组件库文档
VitePress 搭建组件库文档 当我们组件库完成的时候,一个详细的使用文档是必不可少的.本篇文章将介绍如何使用 VitePress 快速搭建一个组件库文档站点并部署到GitHub上 安装 首先新建 ...