Codeuml —— 设计 UML 图表跟你编码一样快

原址:点击打开链接

Codeuml —— 设计 UML 图表跟你编码一样快

Codeuml —— 设计 UML 图表跟你编码一样快_第1张图片

简介

Codeuml是一个基于Web的UML设计工具,你可以用一种特别的语言编写图例,并快速输出图形。它比任何图形化设计工具(拖拽元素和点击鼠标连接元素)都来得更有效率。Codeuml使用开源引擎plantuml来从文本产生图形。你可以像编写代码一样迅速地设计图例。

Codeuml —— 设计 UML 图表跟你编码一样快_第2张图片

这个web应用展示了一些有趣的设计和编程挑战。首先,它告诉你如何创建一个基于web的IDE环境,并模仿了Windows 8 Metro UI。其次,它展示了怎样定期地从网站收集数据,异步地后台发送给服务器,并迅速返回结果。最后并且是最重要的,它显示了如何维护一个服务器端的数据池,来持久化一些必要的资源,你不可能在用户每次访问的时候生成它们,所以必须要有一个有限的数据池供所有web用户使用。

获取代码

实时演示地址: www.codeuml.com 

程序源码:  http://code.google.com/p/codeuml/ 

前端的创建 

我从Windows 8的Metro UI中得到了灵感,并且它对平板也很友好。你可以轻松地在平板上点击按钮。我使用jQuery Splitter plugin创建了三列的可变宽度面板;文本编辑器使用了CodeMirror,它功能很轻大但是图标很吓人;并用 jQuery New Ticker 插件创建了滚动新闻效果。

3列的视图是使用下面的html实现的:

01 <div id="MySplitter">
02         <div class="SplitterPane unselectable">
03             <div id="umlsnippets">
04 .
05 .
06 .
07             </div>
08         </div>
09         <div id="CenterAndRight">
10             <div class="SplitterPane">
11                 <img src="img/ajax-loader.gif" id="ProgressIndicator" />
12                 <textarea id="umltext" rows="10" cols="40"></textarea>
13             </div>
14             <div class="SplitterPane">
15                 <div id="umlimage_container">
16                     <img id="umlimage" src="img/defaultdiagram.png" />
17                     <div id="ticker">
18                         News ticker
19                     </div>
20                 </div>             
21             </div>
22         </div>
23     </div>

首先将屏幕分成两部分——左边的UML片段栏和右边的编辑器和图像栏。之后将右边分成两部分——文本编辑器和图示图像。之后的Javascript初始化了这种分割:

01 // Main vertical splitter, anchored to the browser window
02 $("#MySplitter").splitter({
03     type: "v",
04     outline: true,
05     minLeft: 60, sizeLeft: 100, maxLeft: 250,
06     anchorToWindow: true,
07     resizeOnWindow: true,
08     accessKey: "L"
09 });
10 // Second vertical splitter, nested in the right pane of the main one.
11 $("#CenterAndRight").splitter({
12     type: "v",
13     outline: true,
14     minRight: 200, sizeRight: ($(window).width() * 0.6), maxRight: ($(window).width() * 0.9),
15     accessKey: "R"
16 });
17 $(window).resize(function () {
18     $("#MySplitter").trigger("resize");
19 });

之后,将CodeMirror编辑器作用于文本域,让其变成一个出色的文本编辑器。 

1 myCodeMirror = CodeMirror.fromTextArea($('#umltext').get(0),
2             {
3                 onChange: refreshDiagram
4             });
5 myCodeMirror.focus();
6 myCodeMirror.setCursor({ line: myCodeMirror.lineCount() + 1, ch: 1 });

然后初始化左边的UML片段栏。每个按钮都有一段相关联的UML文本,当点击按钮的时候它们就会被写入编辑器。一个按钮的例子:

01 <div id="scrollable">
02     <!-- Sequence diagram -->
03     <h2>
04         Sequence
05     </h2>
06     <div class="sequence_diagram">
07         <div class="button">
08             <div class="icon">
09                 A&rarr;B</div>
10             <div class="title">
11                 Sync Msg</div>
12             <pre class="umlsnippet">A -> B: Sync Message</pre>
13         </div>
14     </div>

被插入文本编辑器中的代码在<pre>标签中。

你可以创建任意多的UML片段按钮,只要将UML片段放入<pre>中,并设置其类为umlsnippet就可以了。

当按钮被点击时,下面的代码用于将<pre>中的片段插入文本编辑器中:

01 $("#umlsnippets").find(".button").click(function () {
02     var diagramType = $(this).parent().attr("class");
03  
04     if (lastUmlDiagram !== diagramType) {
05         if (!confirm("The current diagram will be cleared? Do you want to continue?"))
06             return;
07  
08         myCodeMirror.setValue("");
09     }
10  
11     changeDiagramType(diagramType);
12  
13     var umlsnippet = $(this).find("pre.umlsnippet").text();
14      
15     var pos = myCodeMirror.getCursor(true);
16  
17     // When replaceRange or replaceSelection is called
18     // to insert text, in IE 8, the code editor gets 
19     // screwed up. So, it needs to be recreated after this.
20     myCodeMirror.replaceRange(umlsnippet, myCodeMirror.getCursor(true));
21  
22     // recreate the code editor to fix screw up in IE 7/8
23     myCodeMirror.toTextArea();
24     myCodeMirror = CodeMirror.fromTextArea($('#umltext').get(0),
25     {
26         onChange: refreshDiagram
27     });
28  
29     myCodeMirror.focus();
30     myCodeMirror.setCursor(pos);
31  
32     refreshDiagram();
33 });

这里有一个问题,如果我插入的文本中叫replaceRange,CodeMirror编辑器就会停止工作。我需要重写它使其重新正确地工作。

边输入边生成图表

在你输入的时候刷新图表是最具挑战的部分。下面的 javascript 函数会在文本编辑器的内容发生改变时触发。考虑到及时性和有效性的均衡,它被设置成每秒只向服务器发送一次 UML 。所以,即使你连续快速敲击,也不会导致对服务器的轰炸式请求。

01 function refreshDiagram() {
02  
03   if (lastTimer == null) {
04      
05     lastTimer = window.setTimeout(function () {
06       // Remove starting and ending spaces
07       var umltext = myCodeMirror.getValue().replace(/(^[\s\xA0]+|[\s\xA0]+$)/g, '');
08  
09       var umltextchanged = 
10         (umltext !== lastUmlText) 
11         && validDiagramText(umltext); 
12  
13       if (umltextchanged) {
14         $('#ProgressIndicator').show();
15  
16         lastUmlText = umltext;
17  
18         $.post("SendUml.ashx", { uml: umltext }, function (result) {
19           var key = $.trim(result);
20           $("#umlimage").attr("src""getimage.ashx?key=" + key);
21         }, "text");
22  
23         try {
24           var forCookie = $.base64.encode(umltext).replace(/==/, '');
25  
26           if (forCookie.length > 3800) {
27             alert("Sorry maximum 3800 characters allowed in a diagram");
28           }
29           else {
30             createCookie('uml', forCookie, 30);
31             var test = readCookie('uml');
32  
33             if (test !== forCookie) {
34               createCookie('uml'''30);
35             }                                
36           }
37         catch (e) {
38         }
39       }
40     }, 1000);
41   }
42   else {
43     window.clearTimeout(lastTimer);
44     lastTimer = null;
45     refreshDiagram();
46   }
47  
48 }

这个代码的确比较聪慧。首先,它确保当用户只是输入空格或敲回车时,由于并没有发生导致需要呈现一幅新图表的变化,所以就不把UML文本发往服务器,节省了没有必要的昂贵的图像生成过程。它还有一点验证以防止尚属半成品的图表表示文本被过早地发送到服务器。你越是能在这里捕捉越多验证细节,就越能在服务器上减少生成无用的图像。

首先,它将UML文本提交到名为endUml.ashx的http处理器.它会保存文本并返回一个GUID,GUID触发生成图的GetImage.ashx。SendUml.ashx很简单:

01 public class SendUml : IHttpHandler {
02      
03     public void ProcessRequest (HttpContext context) {
04         string uml = context.Request["uml"];
05         string key = Guid.NewGuid().ToString();
06  
07         context.Cache.Add(key, uml, null, DateTime.Now.AddSeconds(60), System.Web.Caching.Cache.NoSlidingExpiration,
08             System.Web.Caching.CacheItemPriority.Default, null);
09          
10         context.Response.ContentType = "text/plain";
11         context.Response.Write(key);

它只是将其短暂的存储在缓存之中,因为当获得GUID后立刻就会触发GetImage.ashx。

01 public void ProcessRequest (HttpContext context) {
02  
03     string key = context.Request["key"];
04     string umltext = context.Cache[key] as string;
05      
06     context.Response.ContentType = "image/png";
07     context.Response.Cache.SetCacheability(HttpCacheability.Private);
08     context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(5));
09      
10     if (context.Request["saveMode"] == "1")
11     {                
12         context.Response.AddHeader("Content-Disposition""attachment; filename=diagram.png");
13     }
14      
15     var connection = PlantUmlConnectionPool.Get(TimeSpan.FromSeconds(15));
16     if (connection == null)
17         throw new ApplicationException("Connection not found in pool.");
18  
19     try
20     {
21         var uploadFileName = key + ".txt";

你可能感兴趣的:(Codeuml —— 设计 UML 图表跟你编码一样快)