jsPlumb插件做一个模仿viso的可拖拉流程图

前言

这是我第一次写博客,心情还是有点小小的激动!这次主要分享的是用jsPlumb,做一个可以给用户自定义拖拉的流程图,并且可以序列化保存在服务器端。

我在这次的实现上面做得比较粗糙,还有分享我在做jsPlumb流程图遇到的一些问题。

准备工作

制作流程图用到的相关的脚本:

1 <script src="<%= ResolveUrl("~/resources/jquery/jquery-1.11.1.min.js")%>" type="text/javascript"></script>
2     <script src="<%= ResolveUrl("~/resources/jquery-ui-1.10.4/js/jquery-ui-1.10.4.min.js") %>" type="text/javascript"></script>
3     <script src="<%= ResolveUrl("~/resources/jquery-plugins/jquery.jsPlumb-1.6.2-min.js") %>" type="text/javascript"></script>

jsPlumb-1.6.2-min.js在官网上下载,这里用得是最新版本。jquery-1.11.1.min.js等脚本百度上都能找到,这里就不多说了。

css样式在官网里也可以搜到,这里我就贴出来。

 1     .node {
 2             box-shadow: 2px 2px 19px #aaa;
 3             -o-box-shadow: 2px 2px 19px #aaa;
 4             -webkit-box-shadow: 2px 2px 19px #aaa;
 5             -moz-box-shadow: 2px 2px 19px #aaa;
 6             -moz-border-radius: 0.5em;
 7             border-radius: 0.5em;
 8             opacity: 0.8;
 9             filter: alpha(opacity=80);
10             border: 1px solid #346789;
11             width: 150px;
12             /*line-height: 40px;*/
13             text-align: center;
14             z-index: 20;
15             position: absolute;
16             background-color: #eeeeef;
17             color: black;
18             padding: 10px;
19             font-size: 9pt;
20             cursor: pointer;
21             height: 50px;
22             line-height: 50px;
23         }
24         .radius {
25             border-radius: 25em;
26         }
27         .node:hover {
28             box-shadow: 2px 2px 19px #444;
29             -o-box-shadow: 2px 2px 19px #444;
30             -webkit-box-shadow: 2px 2px 19px #444;
31             -moz-box-shadow: 2px 2px 19px #444;
32             opacity: 0.8;
33             filter: alpha(opacity=80);
34         }

这里还有提到一点,jsPlumb官网上的api全是英文的,博主我从小英文就不好,所以看里面的doc非常费劲,一般都是一边开着金山翻译,

一边看着文档,英语好的略过这段。

正文

言归正传,现在开始我们的jsPlumb流程图制作,下面先附上流程图。

功能

根据客户的要求,我们要完成的功能点有以下几点:

1.支持将左边的div层复制拖拉到右边中间的层,并且左边同一个div拖拉没有次数限制,如果只能拖拉一次,做这个东西就没有什么意义了。

2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框。

3.拖动到中间的层,四周能有4个endpoint点,可供客户连线。

4.能支持删除多余的div的功能。

5.支持删除连接线。

6.能双击修改流程图的文字。

7.能序列化保存流程图。

操作

下面我们根据功能开始制作:

1.拖拉jsPlumb其实是提供draggable方法,和droppable方法官网里有介绍, 但是我这里用得是jquery里的draggable()和droppable()。

 1 <div id="left">
 2             <div class="node radius" id="node1">开始</div>
 3             <div class="node" id="node2">流程</div>
 4             <div class="node" id="node3">判断</div>
 5             <div class="node radius" id="node4">结束</div>
 6         </div>
 7
 8         <div id="right">
 9             <p>拖拉到此区域</p>
10         </div>
11         <div id="save">
12             <input type="button" value="保存" onclick="save()" />
13         </div>

1     $("#left").children().draggable({
2                 helper: "clone",
3                 scope: "ss",
4             });

helper:"clone"表示复制,scope:"ss"是一个标识为了判断是否可以放置,主要用于droppable方法里面也设置这个标识来判断拖放到的地方,

除非两个都不写scope,可以随便拖放,但是会有一个问题,每次我从左边拖东西到右边,我再拖到的时候就会有div拖到不了,所以最好设置

scope:"//里面的值随便,只是一个标识"。

下面是完整的拖放:

 1 $("#left").children().draggable({
 2                 helper: "clone",
 3                 scope: "ss",
 4             });
 5             $("#right").droppable({
 6                 scope: "ss",
 7                 drop: function (event, ui) {
 8                     var left = parseInt(ui.offset.left - $(this).offset().left);
 9                     var top = parseInt(ui.offset.top - $(this).offset().top);
10                     var name = ui.draggable[0].id;
11                     switch (name) {
12                     case "node1":
13                         i++;
14                         var id = "state_start" + i;
15                         $(this).append(‘<div class="node" style="border-radius: 25em"  id="‘ + id + ‘" >‘ + $(ui.helper).html() + ‘</div>‘);
16                         $("#" + id).css("left", left).css("top", top);
17                         jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
18                         jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
19                         jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
20                         jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
21                         jsPlumb.draggable(id);
22                         $("#" + id).draggable({ containment: "parent" });
23                         doubleclick("#" + id);
24                         break;
25                     case "node2":
26                         i++;
27                         id = "state_flow" + i;
28                         $(this).append("<div class=‘node‘ id=‘" + id + "‘>" + $(ui.helper).html() + "</div>");
29                         $("#" + id).css("left", left).css("top", top);
30                         jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
31                         jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
32                         jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
33                         jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
34                         jsPlumb.addEndpoint(id, hollowCircle);
35                         jsPlumb.draggable(id);
36                         $("#" + id).draggable({ containment: "parent" });
37                         doubleclick("#" + id);
38                         break;
39                     case "node3":
40                         i++;
41                         id = "state_decide" + i;
42                         $(this).append("<div class=‘node‘ id=‘" + id + "‘>" + $(ui.helper).html() + "</div>");
43                         $("#" + id).css("left", left).css("top", top);
44                         jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
45                         jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
46                         jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
47                         jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
48                         jsPlumb.addEndpoint(id, hollowCircle);
49                         jsPlumb.draggable(id);
50                         $("#" + id).draggable({ containment: "parent" });
51                         doubleclick("#" + id);
52                         break;
53                     case "node4":
54                         i++;
55                         id = "state_end" + i;
56                         $(this).append(‘<div class="node" style="border-radius: 25em"  id="‘ + id + ‘" >‘ + $(ui.helper).html() + ‘</div>‘);
57                         $("#" + id).css("left", left).css("top", top);
58                         jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
59                         jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
60                         jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
61                         jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
62                         jsPlumb.draggable(id);
63                         $("#" + id).draggable({ containment: "parent" });
64                         doubleclick("#" + id);
65                         break;
66                     }
67                 }
68             });

怎么样把左边的层复制到右边的层,我的做法是这样的:

1 $(this).append(‘<div class="node" style="border-radius: 25em"  id="‘ + id + ‘" >‘ + $(ui.helper).html() + ‘</div>‘);

做到这里会有人奇怪,怎么做到左边能拉无数次append到右边,id这样不会冲突吗?我就在外面var i=0; 当有元素拖放到右边的div时,i++;

然后var id="state_start"+i;拼接起来,这样你的id就不会一样了。

然后再设置div的left和top:

    drop: function (event, ui) {
                    var left = parseInt(ui.offset.left - $(this).offset().left);
                    var top = parseInt(ui.offset.top - $(this).offset().top);

    $("#" + id).css("left", left).css("top", top);

2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框:

jsPlumb.draggable(id);$("#" + id).draggable({ containment: "parent" });

3.拖动到中间的层,四周能有4个endpoint点,可供客户连线:

这个功能是本文的重点,如何通过jsPlumb初始化端点和构造端点(endpoint)。

3.1 初始化端点样式设置:主要设置一些基本的端点,连接线的样式,里面的属性不设置,默认使用默认值

 1     //基本连接线样式
 2             var connectorPaintStyle = {
 3                 lineWidth: 4,
 4                 strokeStyle: "#61B7CF",
 5                 joinstyle: "round",
 6                 outlineColor: "white",
 7                 outlineWidth: 2
 8             };
 9             // 鼠标悬浮在连接线上的样式
10             var connectorHoverStyle = {
11                 lineWidth: 4,
12                 strokeStyle: "#216477",
13                 outlineWidth: 2,
14                 outlineColor: "white"
15             };
16 var hollowCircle = {
17                 endpoint: ["Dot", { radius: 8 }],  //端点的形状
18                 connectorStyle: connectorPaintStyle,//连接线的颜色,大小样式
19                 connectorHoverStyle: connectorHoverStyle,
20                 paintStyle: {
21                     strokeStyle: "#1e8151",
22                     fillStyle: "transparent",
23                     radius: 2,
24                     lineWidth: 2
25                 },        //端点的颜色样式
26                 //anchor: "AutoDefault",
27                 isSource: true,    //是否可以拖动(作为连线起点)
28                 connector: ["Flowchart", { stub: [40, 60], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }],  //连接线的样式种类有[Bezier],[Flowchart],[StateMachine ],[Straight ]
29                 isTarget: true,    //是否可以放置(连线终点)
30                 maxConnections: -1,    // 设置连接点最多可以连接几条线
31                 connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]]
32             };

3.2 构造端点(endpoint):怎样将端点添加到div的四周?

1     jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
2                         jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
3                         jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
4                         jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);

通过jsPlumb.addEndpoint(a,b,c)里面有三个参数,a:要添加端点的div的id;b:设置端点放置的位置("TopCenter","RightMiddle","BottomCenter","LeftMiddle")

四个初始位置;c:端点和连接线的样式。b,c(可选).

添加多个端点:jsPlumb.addEndpoints(a,b,c)三个参数 c(可选),a:要添加端点的div的id;b:含端点的构造函数参数的对象列表;

举个例子:

4.支持删除多余的div的功能:

有时候拖拉div经常会发生拖多了等问题,所有需要删除功能。我要做的删除效果是:鼠标放到div上面,div的右上角会出现一个红色的删除图标,鼠标移走就消失。如下图:

我是通过以下代码实现的:

 1         $("#right").on("mouseenter", ".node", function () {
 2                 $(this).append(‘<img src="../../resources/images/close2.png"  style="position: absolute;" />‘);
 3                 if ($(this).text() == "开始" || $(this).text() == "结束") {
 4                     $("img").css("left", 158).css("top", 0);
 5                 } else {
 6                     $("img").css("left", 158).css("top", -10);
 7                 }
 8             });
 9             $("#right").on("mouseleave", ".node", function () {
10                 $("img").remove();
11             });

我想在这里大家都有疑问吧,为什么用on()事件委托。因为<img />是后添加进来的元素,前面页面已经完成了初始化,所以你用$("img")根本找不到这个元素,

因为img是在页面初始化后,才添加的元素。这里就提到了live()为什么不用这个,jquery1.7.2才有这个方法,这里用的是jquery1.11.1 已经没有live()方法了,

取而代之的是on()方法。(live()有许多缺点,所以在新的版本被摒弃了)

后面删除比较简单:

1     $("#right").on("click", "img",function () {
2                 if (confirm("确定要删除吗?")) {
3                     jsPlumb.removeAllEndpoints($(this).parent().attr("id"));
4                     $(this).parent().remove();
5
6                 }
7             });

注明:这里我遇到一个问题,你删除了那个div,你还得把它周围的4个端点(endpoint)删除,这个问题刚开始我想了很多,一直没做出来,后来去jsPlumb官网查看相关的资料,

发现jsPlumb提供一个方法能删除div四周的端点。方法如下:

 jsPlumb.removeAllEndpoints($(this).parent().attr("id"));//删除指定id的所有端点

5.支持删除连接线:

1     jsPlumb.bind("click", function (conn, originalEvent) {
2                 if (confirm("确定删除吗?    "))
3                     jsPlumb.detach(conn);
4             });

6. 能双击修改流程图的文字:

 1     function doubleclick(id) {
 2             $(id).dblclick(function () {
 3                 var text = $(this).text();
 4                 $(this).html("");
 5                 $(this).append("<input type=‘text‘ value=‘" + text + "‘ />");
 6                 $(this).mouseleave(function () {
 7                     $(this).html($("input[type=‘text‘]").val());
 8                 });
 9             });
10         }

7.能序列化保存流程图:

我的思路是这样的,将中间div里所有的"流程图div信息和连接线两端的信息"保存到数组里,然后序列化成json数据,通过ajax传到asp.net 后台,将json写入到txt文档里保存到服务器端。

(其实保存到数据库里是最好的,后面会考虑保存到数据库),下次展示页面的时候,只要读取txt文档里的json,然后再转成泛型集合。

将页面上的div信息,和连线信息转成json跳转到ajax.aspx页面:

 1     function save() {
 2             var connects = [];
 3             $.each(jsPlumb.getAllConnections(), function (idx, connection) {
 4                 connects.push({
 5                     ConnectionId: connection.id,
 6                     PageSourceId: connection.sourceId,
 7                     PageTargetId: connection.targetId,
 8                     SourceText: connection.source.innerText,
 9                     TargetText: connection.target.innerText,
10                 });
11             });
12             var blocks = [];
13             $("#right .node").each(function (idx, elem) {
14                 var $elem = $(elem);
15                 blocks.push({
16                     BlockId: $elem.attr(‘id‘),
17                     BlockContent: $elem.html(),
18                     BlockX: parseInt($elem.css("left"), 10),
19                     BlockY: parseInt($elem.css("top"), 10)
20                 });
21             });
22
23             var serliza = JSON.stringify(connects) + "&" + JSON.stringify(blocks);
24             $.ajax({
25                 type: "post",
26                 url: "ajax.aspx",
27                 data: { id: serliza },
28                 success: function (filePath) {
29                     window.open("show-flowChart.aspx?path=" + filePath);
30                 }
31             });
32         }

ajax.aspx页面将前台传过来的json保存到服务器端,并跳转至 show-flowChart.aspx:

 1   protected void Page_Load(object sender, EventArgs e)
 2     {
 3         if (!IsPostBack)
 4         {
 5             string str = Request["id"];
 6             string filePath = Server.MapPath("~/prototype/project-reply")+"\\json"+DateTime.Now.ToString("yyyyMMddhhmmss")+".txt";
 7               WriteToFile(filePath,str,false);
 8             //Response.Redirect("show-flowChart.aspx?path="+filePath);
 9             Response.Write(filePath);
10         }
11     }
12     public static void WriteToFile(string name, string content, bool isCover)
13     {
14         FileStream fs = null;
15         try
16         {
17             if (!isCover && File.Exists(name))
18             {
19                 fs = new FileStream(name, FileMode.Append, FileAccess.Write);
20                 StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
21                 sw.WriteLine(content);
22                 sw.Flush();
23                 sw.Close();
24             }
25             else
26             {
27                 File.WriteAllText(name, content, Encoding.UTF8);
28             }
29         }
30         finally
31         {
32             if (fs != null)
33             {
34                 fs.Close();
35             }
36         }
37
38     }

show-flowChart.aspx页面:

 1 protected void Page_Load(object sender, EventArgs e)
 2     {
 3         if (!IsPostBack)
 4         {
 5             string str = Request["path"];
 6             StreamReader sr = new StreamReader(str);
 7             string jsonText = sr.ReadToEnd();
 8
 9             List<JsPlumbConnect> list = new JavaScriptSerializer().Deserialize<List<JsPlumbConnect>>(jsonText.Split(‘&‘)[0]);
10             List<JsPlumbBlock> blocks = new JavaScriptSerializer().Deserialize<List<JsPlumbBlock>>(jsonText.Split(‘&‘)[1]);
11             string htmlText = "";
12             string conn = "";
13             if (blocks.Count > 0)
14             {
15                 foreach (JsPlumbBlock block in blocks)
16                 {
17                     if(block.BlockContent=="开始"||block.BlockContent=="结束")
18                         htmlText += "<div class=‘node radius‘ id=‘" + block.BlockId + "‘style=‘left:"+block.BlockX+"px;top:"+block.BlockY+"px;‘ >" + block.BlockContent + "</div>";
19                     else
20                         htmlText += "<div class=‘node‘ id=‘" + block.BlockId + "‘style=‘left:" + block.BlockX + "px;top:" + block.BlockY + "px;‘ >" + block.BlockContent + "</div>";
21                 }
22                 foreach (JsPlumbConnect jsplum in list)
23                     conn += "jsPlumb.connect({ source: \"" + jsplum.PageSourceId + "\", target: \"" + jsplum.PageTargetId + "\" }, flowConnector);";
24                 Literal1.Text = htmlText;
25                 string script = "jsPlumb.ready(function () {" + conn + "});";
26                 ClientScript.RegisterStartupScript(this.GetType(), "myscript", script, true);
27             }
28         }
29     }

以及两个用到的类JsPlumbConnect类和JsPlumbBlock类:

 1 /// <summary>
 2     /// 连接线信息
 3     /// </summary>
 4     public class JsPlumbConnect
 5     {
 6         public string ConnectionId { get; set; }
 7         public string PageSourceId { get; set; }
 8         public string PageTargetId { get; set; }
 9         public string SourceText { get; set; }
10         public string TargetText { get; set; }
11     }
12      /// <summary>
13      /// 流程图的所有div
14      /// </summary>
15     public class JsPlumbBlock
16     {
17         /// <summary>
18         /// div Id
19         /// </summary>
20          public string BlockId { get; set; }
21         /// <summary>
22         /// div里面的内容
23         /// </summary>
24          public string BlockContent { get; set; }
25          public int BlockX { get; set; }
26          public int BlockY { get; set; }
27     }

结尾

有许多的地方并不合理,希望大家能提出自己的意见。

jsPlumb插件做一个模仿viso的可拖拉流程图

时间: 2024-10-07 16:03:14

jsPlumb插件做一个模仿viso的可拖拉流程图的相关文章

做一个模仿Smarty的简易模版

---恢复内容开始--- 今天终于学习完了一个慕课网的正则表达式的视频,感觉挺不错的,推荐给大家 下面是我学习写的一些代码 首先要先明白什么是Smarty模版. 这种模版就是将一个文件中的代码运用正则替换为令一段代码以供下一步的运行.也就是说可以通过这个模版来省略很多语法,结构上面的规则,从而很好的将前端开发和后端开发分离,不需什么都懂,在这个山寨的模版里面主要是将前端的HTML代码中的一些字段替换成可被运行的PHP代码,完成给用户的最后的输出. 好,首先是新建的项目,既然有编译,就有个源文件和

用bootstrap的tab插件做一个图层切换效果(感觉会误导淫们,大家当乐子看吧)

小伙伴们啊,我JS真的是个渣渣,所以总想要偷懒,于是为了实现效果就把tab插件给改了(各位大神轻拍啊,我是小白,很纯洁滴,小心脏也很脆弱)…… 最近做的项目为了考虑以后的移动设备兼容性,所以用了Bootstrap.首页有一个需要鼠标点击不一样的按钮固定位置图层内容变化的效果(我描述清楚了吗Orz……),如下图: 分别点击1,2,3,4按钮时现实对应的内容变化. 我就呵呵了,这个跟tab插件很类似啊~~不就是点按钮换图层吗.如果在别处找独立插件,我这记性的,项目js文件里早晚被我弄得乱七八糟我都不

使用node.js做一个自用的天气插件

var request = require('request') var url = 'http://www.baidu.com/home/xman/data/superload' var cookie = '你登录百度后的cookie' var options = { method: "GET", url: url, qs: { "type": "weather", "asyn": 1, "t": new

扩展一个boot的插件—tooltip&amp;做一个基于boot的表达验证

在线演示 本地下载 (代码太多请查看原文) 加班,加班加班,我爱加班··· 我已经疯了,哦也. 这次发一个刚接触boot的时候用boot做的表单验证,我们扩展一下tooltip的插件,让他可以换颜色. 其实挺简单的,主要是考究代码阅读的能力. boot的代码写的很简单,能省略“;”的地方就省略掉了,而且他的闭包也很有意思 +function($){ }(jQuery); 这种写法等同于 (function($){ })(jQuery); 少些一个符号,比较节俭. 他的对外接口写的就比较正常了:

从零开始学会做一个简单的APP

本人是矿大学信息安全的大三狗,混了两年日子之后幡然醒悟决定做些自己早就想做的事情,学校的联通宽带是按时长收费的,但是每次查询已用时长和所扣费用步骤都十分的繁琐,大二的时候都想着要自己做一个APP来帮助大家减少这些繁琐的步骤,终于拖了半年多才开始做.从只有一点Java基础到最后做出来可用的APP只用了一个星期的时间,以下是干货内容.(其实我就是想来求红包的!如果能拿到红包那就是我学计算机挣来的第一桶金了!) 我们最先要上的是成果图,还有在学校发的帖子:http://tieba.baidu.com/

VUE2.0+VUE-Router做一个图片上传预览的组件

之前发了一篇关于自己看待前端组件化的文章,但是由于学习和实践的业务逻辑差异,所以自己练习的一些demo逻辑比较简单,打算用vue重构现在公司做的项目,所以在一些小的功能页面上使用vue来做的,现在写的这个是项目中用户反馈功能而来的,收获还是挺多的. 收获:dom操作=>数据操作       router的使用       组件的使用,具体总结放在尾部. 功能:1.上传图片 2.显示缩略图 3.可以删除 4.可以重新选择文件 先上成品图(主要抽取图片这块),自己在家主要做的功能,样式就不计较了.

使用eclipse插件创建一个web project

使用eclipse插件创建一个web project 首先创建一个Maven的Project如下图 我们勾选上Create a simple project (不使用骨架) 这里的Packing 选择 war的形式 由于packing是war包,那么下面也就多出了webapp的目录 由于我们的项目要使用eclipse发布到tomcat下面,这里我们需要先把项目转成dynamic web project 在我们的项目上点击右键,选择properties 并找到 Project Facets ,并点

做一个互联网+时代的新农民

在村里,每天零晨闻鸡鸣,因为太宁静,鸡鸣就显得特别地高亢嘹亮,今天干脆做一个闻鸡起舞之人,来简单梳理这两天边做农民边思考的问题.技术发展得太快了,这些年感觉都在追赶,我们似乎只是国外的跟屁虫,但国外是相当害怕的,他们自以为无法超越的东西,我们从模仿到超越也就很短的时间,当然除了核心技术,我们是没有耐心也无法静下心来钻研的,比如操作系统和数据库系统之类的,就算我们再狠狠地干个几十年,依然是扶不起的. 如今,不知不觉就来到了互联网+时代,DT时代,感觉我们还没有学会好好地走路,就开始飞翔了,连一个网

【小松教你手游开发】【系统模块开发】做一个3d旋转菜单

在unity做一个3d旋转菜单,像乱斗西游2的这种: 暂时有两种方法可以实现: 一.当做是2d界面,通过定义几个固定点的坐标.大小.透明度,还有每个点的panel depth大小,把数据存储下来,在手机滑动的过程中计算滑动划过的距离和这个panel大小的比值,乘以两个点之间的距离,获得坐标点移动的距离,通过改变x轴改变位置,同理改变大小和透明度. 这个方法我自己做2d游戏的时候实现过,做起来比较简单,没有什么可拓展性可言,并且会有很多限制,比如拖动过程中很难转变方向.要自己实现运动中的弹性(这里