为什么要写这篇?
从去年开始,我就逐步将手上的文档转化成后缀为.md的格式保存。最初的原因是我希望图片不会在文档中被压缩,以及代码块有语法高亮和正确的缩进。随着对markdown语法的熟悉,现在我基本上可以完全弃用微软的传统办公三件套。Markdown的方便易用以及多平台的兼容性,让它已经成为了我日常的一个高效生产力工具。这里我想分享一下Markdown中最新的绘图功能,目的是能部分取代Office中的Visio工具
。
Markdown 是由约翰·格鲁伯(John Gruber)于2004年创建的一种轻量级标记语言。它允许人们使用易读易写的纯文本格式编写文档,并且可以导出为 HTML 、Word、图像、PDF、Epub 等多种格式的文档。
本文为使用Markdown的进阶篇,基础语法可以参考以下教程,:
www.runoob.com/markdown/md-tutorial.html
Markdown 有多款优秀的编辑器,这里我使用的是一款支持实时预览的免费编辑器:Typora。
在Typora中有“实时预览模式”和“源代码模式”,可以直接通过快捷键组合 Ctrl+/
进行切换。
“源代码模式”是直接编写Markdown代码的,相比之下我更习惯于在“实时预览模式”中通过各类快捷键组合进行编辑,这也是Typora这款软件的高效之处。
在“源代码模式”中插入代码块的方式是直接输入:
``````
中间直接写入代码即可。
如果想要指定编程语言的高亮规则,只用在第一个```后面添加相应语言的小写名称即可。例如:
```python print("Hello, world") ```
在Typora的“实时预览模式”中插入代码就更加简单了。可以直接在菜单栏的“段落“中选择“代码块”,然后在出现的代码块右下角填入要选择的语言:
或者使用快捷键组合 Ctrl+Shift+K
快速插入。
Markdown本身没有作图功能,但是由于其优秀的设计理念和简洁的语法风格,吸引了很多开发者制作了相应的领域特定语言(DSL)。
领域特定语言(Domain Specific Language, DSL)是一种为解决特定领域问题而对某个特定领域操作和概念进行抽象的语言。
其中就包括我想给大家分享的两个JavaScript项目:
flowchart.js
mermaid.js
本文主要介绍如何在Markdown编辑器中使用这两个开源项目绘制常用图形。文章分为上、下两篇,本篇主要讲述 flowchart.js 在Typora中的使用方法。
上篇:flowchart.js
Ⅰ. flowchart.js 简介
flowchart.js是一个用来制作流程图的领域特定语言(DSL),可以在浏览器或终端中生成可缩放矢量图形(SVG)。目前版本号为 v1.13.0
。
项目官网:
http://flowchart.js.org/
Github地址为:
https://github.com/adrai/flowchart.js
如果想要在Typora中使用flowchart.js,只需要将代码块的语言设置为flow
即可。
flowchart.js最大的特点是在流程图中的节点与连接是分开定义的。这样做的好处是节点可以被快速复用,连接也可以很方便地被修改。
如官方示例代码:st=>start: Start:>http://www.google.com[blank]e=>end:>http://www.google.comop1=>operation: My Operationsub1=>subroutine: My Subroutinecond=>condition: Yesor No?:>http://www.google.comio=>inputoutput: catch something...para=>parallel: parallel tasksst->op1->condcond(yes)->io->econd(no)->parapara(path1, bottom)->sub1(right)->op1para(path2, top)->op1
代码前半部分(1-8行)是节点类型及属性的定义,后半部分(10-14行)是定义节点之间的连接方式。
语法非常简洁易懂,最后得到的图形为:Ⅱ. flowchart.js语法
流程图的主要组成就是节点和节点之间的关系。
1. 节点语法
节点的语法可以概括为:
nodeName=>nodeType: nodeText[|flowstate][:>urlLink]
其中[ ]
中的内容为可选项,其他各项的含义如下:
nodeName - 节点名称:定义流程图文件当中节点变量的名称。
nodeType - 节点类型:定义节点所属的类型。
nodeText - 节点文本:节点中插入的文本,会在流程图中显示。
flowstate - 流程状态:可选项,使用
|
算子来为节点定义额外的样式。urlLink - URL链接:可选项,使用
:>
算子来关联指向的链接。
2. 节点类型
一共有七种节点类型。
① start 开始
作为流程图开始的第一个节点,默认文本为 Start
,以椭圆形表示。
st=>start: start
② end 结束
作为流程图结束的最后一个节点,默认文本为 End
,以椭圆形表示。
e=>end: end
③ operation 操作
标明流程中发生了一次操作的节点,以矩形形表示。
op1=>operation: operation
④ inputoutput输入输出
标明流程中的一个有输入输出的节点(IO节点),以平行四边形形表示。
io=>inputoutput: inputoutput
⑤ subroutine 子流程
标明流程图中有一个子流程,需要另外一个流程图去详细说明这个子流程,以三格矩形表示。
sub1=>subroutine: subroutine
⑥ condition 条件选择
允许使用条件选择或者逻辑声明的方式控制流程的走向,以菱形四边形表示。
cond=>condition: condition Yes or No?
⑦ parallel 平行流
标明多个流程同时发生,以矩形形表示。。
para=>parallel: parallel
3. 节点连接
定义好节点后就可以进行节点连接的定义。使用符号->
就可以表示从一个节点连接到另一个节点,例如:nodeVar1->nodeVar2->nodeVar3
。
如果要把节点的连接分开表述,就可以用以下这种形式:
nodeVar1->nodeVar2nodeVar2->nodeVar3
连接的语法为:
[([, [[([, ]
其中<nodevariable name>为节点变量名,[ ]
中的内容为可选项。
现在我们已经了解了节点以及连接的定义方法,就可以进行流程图的制作了。这里以简单的登录场景为例,流程图代码和效果如下:
start=>start: 开始loginInfo=>inputoutput: 登录数据verifyLogin=>subroutine: 登录验证isSuccess=>condition: 验证成功?respondSuccess=>operation: 响应成功responseFailure=>operation: 响应失败end=>end: 结束start->loginInfo->verifyLogin->isSuccessisSuccess(yes)->respondSuccess->endisSuccess(no)->responseFailure->end
可以看到,其中的 isSuccess
是一个 condition
类型的节点,所以在连接中要分别用 (yes)
和 (no)
标明相应的流向。
*连接方向
在上述例子中,流程图会自动根据连接的定义来选择对线条进行布局。同时也可以使用下面四个关键字来调整线条的位置,以便使流程图更加清晰。
left:向左
right:向右
top:向上
bottom:向下(默认)
例如以下代码的流程图中,如果使用默认模式,会让线条之间出现重叠:
start=>start: startoperation1=>operation: operation1isSuccess=>condition: success?operation2=>operation: operation2operation3=>operation: operation3operation4=>operation: operation4end=>end: 结束start->operation1->isSuccessisSuccess(yes)->operation2->endisSuccess(no)->operation3->operation4->operation1
此时只要给operation4
元素添加right
关键字,就可以分离重叠的线条。
start=>start: startoperation1=>operation: operation1isSuccess=>condition: success?operation2=>operation: operation2operation3=>operation: operation3operation4=>operation: operation4end=>end: 结束start->operation1->isSuccessisSuccess(yes)->operation2->endisSuccess(no)->operation3->operation4(right)->operation1
如果给condition
元素添加这些关键字的话会调整整个分支的方向:
start=>start: startoperation1=>operation: operation1isSuccess=>condition: success?operation2=>operation: operation2operation3=>operation: operation3operation4=>operation: operation4end=>end: 结束start->operation1->isSuccessisSuccess(yes)->operation2->endisSuccess(no,left)->operation3->operation4(left)->operation1
4. 节点状态标记
节点状态标记是指使用不同的颜色标记节点当前的状态,这在涉及到时间周期的流程图中十分有用。
遗憾的是目前版本的Typora (version 0.9.86) 还不支持此项新特性,因此暂不展开。
5. 节点外部链接
可以在节点定义后面使用:>
运算符添加一个外链,节点的颜色也会变为蓝色。
st=>start: Start:>http://www.baidu.com[blank]e=>end: End:>http://www.bing.comst->e
上述代码中, st
节点指向 http://www.baidu
.com
,并且由于尾部带有 [blank]
所以会打开一个新的标签页。
而 e
节点指向 http://www.bing.com
且链接尾部没有指示所以会将当前浏览器页面跳转到相应链接,而不是重新打开一个标签页。
6. 路径高亮
绘制完流程图后,如果想要特别标出其中的一条路径(例如主流程),可以在最后添加一条类似下面的语句:
st@>op1({"stroke":"Red"})@>cond({"stroke":"Red","stroke-width":6,"arrow-end":"classic-wide-long"})@>c2({"stroke":"Red"})@>op2({"stroke":"Red"})@>e({"stroke":"Red"})
仍然以前面登录流程为例,我们使用红色高亮登录成功的主路径:
start=>start: 开始loginInfo=>inputoutput: 登录数据verifyLogin=>subroutine: 登录验证isSuccess=>condition: 验证成功?respondSuccess=>operation: 响应成功responseFailure=>operation: 响应失败end=>end: 结束start->loginInfo->verifyLogin->isSuccessisSuccess(yes)->respondSuccess->endisSuccess(no)->responseFailure->endstart@>loginInfo({"stroke":"Red"})@>verifyLogin({"stroke":"Red"})@>isSuccess({"stroke":"Red"})@>respondSuccess({"stroke":"Red"})@>end({"stroke":"Red","stroke-width":6,"arrow-end":"classic-wide-long"})
可以通过改变下列属性中的值,达到自己想要的效果:
"stroke":"Red"
"stroke-width":6
"arrow-end":"classic-wide-long"
Ⅲ. flowchart.js实例
下面列举几个在Typora中使用flowchart.js作图的实际案例。
1. 用户登录验证流程
flowchatst=>start: 开始e=>end: 登录io1=>inputoutput: 输入用户名密码sub1=>subroutine: 数据库查询子类cond=>condition: 是否有此用户cond2=>condition: 密码是否正确op=>operation: 读入用户信息st->io1->sub1->condcond(yes,right)->cond2cond(no)->io1(right)cond2(yes,right)->op->econd2(no)->io1
2. 微信接入验证流程
st=>start: 微信验证接入e=>end: ENDcond1=>condition: echostr == nullop2_1=>operation: 将token、timestamp、nonce三个参数进行字典序排序op2_2=>operation: 将三个参数字符串拼接成一个字符串进行sha1加密cond2=>condition: 加密字符串 == signatureio1=>inputoutput: 返回echostrop1=>operation: 获取post,解析xml数据op2=>operation: 判断信息内容,处理相关操作io2=>inputoutput: post返回数据st->cond1cond1(yes)->op1->op2->io2->econd1(no)->op2_1(right)->op2_2->cond2cond2(no)->econd2(yes)->io1->e
3. 在线招投标流程
st=>start: indexop=>operation: 申请op2=>operation: 结果页op3=>operation: 查询本地i1=>inputoutput: bid入库i2=>inputoutput: 填写个人信息c1=>condition: 检查登录c2=>condition: 登录c3=>condition: 查询本地记录c4=>condition: 检测状态c5=>operation: 风控审核e=>endst->op->c1()c1(no)->c2(yes)->op()c1(yes)->c3(no)->i1(right)->i2(right)->c5()->op2->ec1(yes)->c3(yes)->c4(no)->i2c1(yes)->c3(yes)->c4(yes)->op3->op2c3()->e
Ⅳ. 小结
Flowchart.js
是一个可以在Markdown编辑器中快速绘制流程图的工具,特别是对于相对简单的组织架构图形,可以用极低的学习成本立即构建。
但由于该项目只有七种节点类型,连接方法和形式也非常简单,很难胜任更加复杂的需求。在下一篇当中我会接着介绍mermaid.js
——另一个功能更强大、样式更加丰富的项目。
欢迎关注我的公众号“数析万变”,原创技术观点第一时间推送。