实现UML 序列图 -- Csdn MarkDown 第六篇 技术篇
这一篇开始讨论代码层面的问题。主要是markdown的功能的设计实现。
这一篇先从markdown外围的代码开始讲起:
UML序列图是从 https://github.com/bramp/js-sequence-diagrams
copy得到的。
当如这个UML代码还用到了两个JS,功能库和画图.
<script src="underscore-min.js"></script>
<script src="raphael-min.js"></script>
首先讲讲这个JS最核心的类:
[ https://github.com/bramp/js-sequence-diagrams/blob/master/src/sequence-
diagram.js ](https://github.com/bramp/js-sequence-diagrams/blob/master/src
/sequence-diagram.js)
首先这个类分为其实使用两种风格的。一种就是现在CSDN采用的风格,叫做simple. 另外一种是手绘风格,叫做hand。定义如下:
var themes = {
simple : RaphaelTheme,
hand : HandRaphaelTheme
};
Diagram.prototype.drawSVG = function (container, options) {
var default_options = {
theme: 'hand'
};
options = _.defaults(options || {}, default_options);
if (!(options.theme in themes))
throw new Error("Unsupported theme: " + options.theme);
var drawing = new themes[options.theme](this);
drawing.draw(container);
}; // end of drawSVG
drawSVG是最外层JS要画图调用的方法。例如:
<div id="diagram">Diagram will be placed here</div>
<script src="sequence-diagram-min.js"></script>
<script>
var diagram = Diagram.parse("A->B: Does something");
diagram.drawSVG('diagram');
</script>
下面就可以画出图形。所以drawSVG是核心入口。
drawSVG的实现过程中,最重要的一句:
drawing.draw(container);
这一句调用的draw function定义如下:
draw : function(container) {
var diagram = this.diagram;
this.init_paper(container);
this.init_font();
this.layout();
var title_height = this._title ? this._title.height : 0;
this._paper.setStart();
this._paper.setSize(diagram.width, diagram.height);
var y = DIAGRAM_MARGIN + title_height;
this.draw_title();
this.draw_actors(y);
this.draw_signals(y + this._actors_height);
this._paper.setFinish();
},
这几句看起来平淡无奇,就是初始化背景,初始化字体,初始化各种,然后画标题,画角色(也就是序列图中的实体),画调用箭头。
这里面看似简单,但是最为繁琐的就是:
this.layout();
布局:要遍历所有的要画到画布上的东西,要提前预知,各个东西的长宽,然后根据长宽,各个东西相距的距离,算出画布的尺寸。这段JS并没有做到固定长宽后,各个东西等
比缩放。
这个做完之后,开始画角色(也就是实体)
Created with Raphaël 2.1.2 A A 这就是角色A 包括上下两个方块和中间的竖线
再然后,两个角色之间是有间距的。例如:
Created with Raphaël 2.1.2 距离是什么? A A B B 我们两个角色之间的间距 包括上下两个方块和中间的竖线
间距的计算并不是很容易,首先确定每个角色的基本的高和宽,然后根据将信号signal计算在内(signal 包括两种,一种是 箭头关系,另外一种是 注释框)所
以大家可以看到注释框和箭头也是有从上到下的顺序的。signal的宽度和字的个数以及宽度均有关系(这里计算较为复杂,此处略去太多字…有兴趣的看源码)。
然后顺序遍历,依次确定A,B,C…各个角色所在的绝对坐标。
每一个signal都是有高度的,将所有的signal 高度加和,就得到了下端角色方框的坐标。然后连线就大功告成。
看源码发现了许多没有的功能…
例如 UML中增加title
以及UML中注释框除了Right, Left, 还有Over, 对于Over还可以置于多个角色之上。
title 和 Over
1
2
3
4
5
title: 距离是什么?
A->B: 我们两个角色之间的间距
Note Over A,B: 包括上下两个方块和中间的竖线
Note Over A: I'm A
表现:
Created with Raphaël 2.1.2 距离是什么? A A B B 我们两个角色之间的间距 包括上下两个方块和中间的竖线
I’m A
[ https://github.com/bramp/js-sequence-diagrams/blob/master/src/jquery-
plugin.js ](https://github.com/bramp/js-sequence-diagrams/blob/master/src
/jquery-plugin.js)
这个类中,如果没有定义option属性,那么就只能用simple的形式了。感觉CSDN的dev好像没有定义这个option. 我这边也无能为力。
[ https://github.com/bramp/js-sequence-diagrams/blob/master/src/diagram.js]
这个类没有什么好讲的,就是通过parser构造出来的实体类。
剩下的两个gammar JS. 这种词法解析的放到后面一篇再说. 网络实在不好,啥都timeout, 另外也该睡觉了。