用代码画流程图和时序图快餐教程(1)

用代码画流程图和时序图快餐教程(1)

版本历史:

2016.06.02,v1:初稿
2016.07.31,v2:更新中文字体的设置。更新颜色的作用。
2017.08.02,v3:更新命令行方式

graphviz的dot图

工具下载网址:http://www.graphviz.org/
可以使用sublime text来编辑。

sublime_graphviz
sublime_graphviz

Windows下的GVEdit

在Windows下,Graphviz提供一个GVedit工具来编辑。


gvedit
gvedit

命令行方式

在mac和Linux下,我们可以采用命令行的方式来实现。
对于层次图,我们主要使用dot工具,常用格式如下例:

dot -Tpng -O model2.gv

-T是输出的格式类型,如png,jpg,pdf等。

图的结构

首先写个有向图的结构:

digraph G{
}

节点和边

然后就用“节点1 -> 节点2”的方式画图就好了。

例:

Context_sendbroadcast -> ContextWrapper_sendBroadcast;
ContextWrapper_sendBroadcast -> ContextImpl_sendBroadcast;
ContextImpl_sendBroadcast -> ActivityManagerService_broadcastIntent;

节点的文字

如果节点的文字太长,可以通过label属性来保存完整的文本。
例:

Context_sendbroadcast[label="Context.sendBroadcast(Intent)"];
Context_sendbroadcast_asUser[label="Context.sendBroadcastAsUser(Intent,UserHandle)"];
Context_sendOrderedBroadcast[label="Context.sendOrderedBroadcast(Intent,String,BroadcastReceiver,Handler,int,String,Bundle)"];
Context_sendOrderedBroadcast2[label="Context.sendOrderedBroadcast(Intent,String"];
Context_sendStickyBroadcast[label="Context.sendStickyBroadcast(Intent)"];
Context_sendStickyBroadcast2[label="Context.sendStickyOrderedBroadcast(Intent,BroadcastReceiver,Handler,int,String,Bundle)"];

边和节点的属性

可以针对每个节点和边设置属性,也可以为所有的节点和边统一设。
例:针对所有的节点和边都设属性

node [shape = "Mrecord", color="skyblue", style="filled"];
edge [color="darkgreen"];

注释

dot语言支持C++格式的注释,也就是说/**/和//的注释都是支持的。

完整例子

digraph G{
node [shape = "Mrecord", color="skyblue", style="filled"];
edge [color="darkgreen"];

Context_sendbroadcast[label="Context.sendBroadcast(Intent)"];
Context_sendbroadcast_asUser[label="Context.sendBroadcastAsUser(Intent,UserHandle)"];
Context_sendOrderedBroadcast[label="Context.sendOrderedBroadcast(Intent,String,BroadcastReceiver,Handler,int,String,Bundle)"];
Context_sendOrderedBroadcast2[label="Context.sendOrderedBroadcast(Intent,String"];
Context_sendStickyBroadcast[label="Context.sendStickyBroadcast(Intent)"];
Context_sendStickyBroadcast2[label="Context.sendStickyOrderedBroadcast(Intent,BroadcastReceiver,Handler,int,String,Bundle)"];

ContextWrapper_sendBroadcast[label="ContextWrapper.sendBroadcast(Intent)"];
ContextWrapper_sendOrderedBroadcast2[label="ContextWrapper.sendOrderedBroadcast(Intent,String)"];
ContextWrapper_sendOrderedBroadcast[label="ContextWrapper.sendOrderedBroadcast(Intent,String,BroadcastReceiver,Handler,int,String,Bundle)"];
ContextWrapper_sendStickyBroadcast[label="ContextWrapper.sendStickyBroadcast(Intent)"];
ContextWrapper_sendStickyBroadcast2[label="ContextWrapper.sendStickyOrderedBroadcast(Intent,BroadcastReceiver,Handler,int,String,Bundle)"];
ContextWrapper_sendbroadcast_asUser[label="ContextWrapper.sendBroadcastAsUser(Intent,UserHandle)"];
ContextImpl_sendBroadcast[label="ContextImpl.sendBroadcast(Intent)"];
ContextImpl_sendOrderedBroadcast2[label="ContextImpl.sendOrderedBroadcast(Intent,String)"];
ContextImpl_sendOrderedBroadcast[label="ContextImpl.sendOrderedBroadcast(Intent,String,BroadcastReceiver,Handler,int,String,Bundle)"];
ContextImpl_sendStickyBroadcast[label="ContextImpl.sendStickyBroadcast(Intent)"];
ContextImpl_sendStickyBroadcast2[label="ContextImpl.sendStickyOrderedBroadcast(Intent,BroadcastReceiver,Handler,int,String,Bundle)"];
ContextImpl_sendbroadcast_asUser[label="ContextImpl.sendBroadcastAsUser(Intent,UserHandle)"];

ContextImpl_sendOrderedBroadcast_all[label="ContextImpl.sendOrderedBroadcast(Intent,String,int,BroadcastReceiver,Handler,int,String,Bundle,Bundle)"];

ActivityManagerService_broadcastIntent[label="ActivityManagerService.broadcastIntent(IApplicationThread,Intent,String,IIntentReceiver,int,String,Bundle,String[],int,Bundle,boolean,boolean,int)"];

Context_sendbroadcast -> ContextWrapper_sendBroadcast;
ContextWrapper_sendBroadcast -> ContextImpl_sendBroadcast;
ContextImpl_sendBroadcast -> ActivityManagerService_broadcastIntent;

Context_sendbroadcast_asUser -> ContextWrapper_sendbroadcast_asUser;
ContextWrapper_sendbroadcast_asUser -> ContextImpl_sendbroadcast_asUser;
ContextImpl_sendbroadcast_asUser -> ActivityManagerService_broadcastIntent;

Context_sendOrderedBroadcast2 -> ContextWrapper_sendOrderedBroadcast2;
ContextWrapper_sendOrderedBroadcast2 -> ContextImpl_sendOrderedBroadcast2;
ContextImpl_sendOrderedBroadcast2 -> ActivityManagerService_broadcastIntent;

Context_sendOrderedBroadcast -> ContextWrapper_sendOrderedBroadcast;
ContextWrapper_sendOrderedBroadcast -> ContextImpl_sendOrderedBroadcast;
ContextImpl_sendOrderedBroadcast -> ContextImpl_sendOrderedBroadcast_all;
ContextImpl_sendOrderedBroadcast_all -> ActivityManagerService_broadcastIntent;

Context_sendStickyBroadcast -> ContextWrapper_sendStickyBroadcast;
ContextWrapper_sendStickyBroadcast -> ContextImpl_sendStickyBroadcast;
ContextImpl_sendStickyBroadcast -> ActivityManagerService_broadcastIntent;

Context_sendStickyBroadcast2 -> ContextWrapper_sendStickyBroadcast2;
ContextWrapper_sendStickyBroadcast2 -> ContextImpl_sendStickyBroadcast2;
ContextImpl_sendStickyBroadcast2 -> ActivityManagerService_broadcastIntent;
}

我们看看最终生成的图的样子:


Android_broadcast
Android_broadcast

中文的支持

按照默认的配置,中文显示会成为乱码的。我们需要设置中文字体.
比如下面我们设成仿宋字体:

node [shape = "Mrecord", color="skyblue", style="filled",fontname="SimSun"];

这样,存为UTF-8格式,我们就可以放心地使用中文了。
中文例:

digraph G{
node [shape = "Mrecord", color="skyblue", style="filled",fontname="SimSun"];
edge [color="darkgreen"];

Golang[label="Go语言"]

basic_structure[label="基本结构"]
basic_type[label="基本组件"]
basic_flow_control[label="流程控制"]

variable[label="变量与常量"]
package_manager[label="包管理"]
functions[label="函数"]
types[label="自定义类型"]
reference[label="引用类型"]
goroutines[label="并发"]
control_flow[label="单任务流程控制"]
defers[label="延时型流程控制"]

Golang -> basic_structure;
Golang -> basic_type;
Golang -> basic_flow_control;

basic_structure -> variable;
basic_structure -> package_manager;
basic_type -> functions;
basic_type -> types;
basic_type -> reference;
basic_flow_control -> control_flow;
basic_flow_control -> goroutines;
basic_flow_control -> defers;
}
golang1
golang1

颜色很重要

边和节点都可以设颜色,颜色的值可以在http://www.graphviz.org/content/color-names中查到。

下面我们举个例子,看看颜色的作用:

digraph G{
node [shape = "Mrecord", color="skyblue", style="filled",fontname="SimSun"];
edge [color="darkgreen", fontname="SimHei"];

armv4[label="ARM v4", color="antiquewhite4"]
armv4T[label="ARM-V4T", color="bisque3"]
ARMv5TE[label="ARMv5TE",color="burlywood"]
ARMv6[label="ARM v6",color="cyan3"]
ARMv7A[label="ARM v7-A",color="gold1"]
ARMv8A[label="ARMv8-A",color="chartreuse1"]

arm32[label="ARM 32位指令集",color="darkolivegreen1"]
thumb16[label="Thumb指令集",color="darkseagreen3"]
thumb32[label="Thumb2指令集",color="chocolate3"]
arm64 [label="ARM 64位指令集",color="deepskyblue"]

armv4 -> armv4T [label="发展",color="deeppink"]
armv4T -> ARMv5TE [label="发展",color="deeppink"]
ARMv5TE -> ARMv6 [label="发展",color="deeppink"]
ARMv6 -> ARMv7A [label="发展",color="deeppink"]
ARMv7A -> ARMv8A [label="发展",color="deeppink"]

armv4 -> arm32 [label="支持"]
armv4T -> arm32 [label="支持"]
ARMv5TE -> arm32 [label="支持"]
ARMv6 -> arm32 [label="支持"]
ARMv7A -> arm32 [label="支持"]
ARMv8A -> arm32 [label="支持"]

armv4T -> thumb16 [label="支持"]
ARMv5TE -> thumb16 [label="支持"]
ARMv6 -> thumb16 [label="支持"]

ARMv6 -> thumb32 [label="可选"];
ARMv7A -> thumb32 [label="支持"]
ARMv8A -> thumb32 [label="支持"]

ARMv8A -> arm64 [label="支持"]
}

最终生成的图是这样子的:

arm_1
arm_1

形状

graphviz的节点支持各种形状,比如椭圆,平行四边形,梯形,鸡蛋形,七边形,八边形,文件夹等。
下面我们看一个各处奇形怪状凑在一起的例子:

digraph G{
node [shape = "Mrecord", color="skyblue", style="filled",fontname="SimSun"];
edge [color="darkgreen", fontname="SimHei"];

java1[label="Java 1.0", color="antiquewhite4",shape="box3d"]

java5[label="Java 5.0", color="bisque3",shape="ellipse"]

java7[label="Java 7.0",color="burlywood",shape="oval"]

java8[label="Java 8.0",color="gold1",shape="septagon"]

Synchronized[label="基于线程和锁的并发",color="deepskyblue",shape="egg"]

Future[label="Future模式",color="darkolivegreen1",shape="octagon"]

ForkJoin[label="Fork-Join框架",color="darkseagreen3",shape="folder"]

Lambda[label="基于Lambda表达式的并发",color="chocolate3",shape="component"]

java1 -> java5 [label="发展",color="deeppink"]
java5 -> java7 [label="发展",color="deeppink"]
java7 -> java8 [label="发展",color="deeppink"]

java1 -> Synchronized;

java5 -> Future

java7 -> ForkJoin

java8 -> Lambda
}

生成的图是这样的:


java_con_gv
java_con_gv
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容