开发组在开发过程当中,都不可避免地遇到了一些困难或问题,但都最终想出办法克服了。咱们认为这样的经验是有必要记录下来的,所以就有了【技术博客】。javascript
这篇技术博客基于软件工程课程的VisualPytorch之上,代码在必定程度上参考了http://www.javashuo.com/article/p-ntwdyfrg-du.html这篇博客。css
VisualPytorch项目连接以下:VisualPytorchhtml
对于这样一个类流程图或者模型图,用户会有保存、查看以及再编辑的需求,仅仅提供让用户拖拽连线的功能、让用户每次都从头搭建是会严重影响用户体验的,所以须要可以保存模型图。java
这篇博客主要用于提供思路,而非提供整套的解决方案,具体解决方案因人而异。node
保存流程图是两方面的问题:jquery
(1)选定合适的保存格式git
(2)确保保存的信息足够来还原完整的图github
在保存时,我采用的是将整个图分为两个数组保存入数据库中。图主要由模块(开始、reshape层)和连线两部分组成,所以我选择将模块保存为一个json,而连线保存为数组。数据库
$("#canvas").find(".node").each(function (index, element) { var id = $(element).attr('id'); nets[id] = { "name": $(element).attr('name'), "attribute": eval('(' + window.localStorage.getItem(id) + ')'), "left": $(element).css('left'), "top": $(element).css('top') } });
在画布中遍历全部的模块类,nets对象的标签为模块的id,而内容为须要保存的属性。须要注意的是,left与top属性必须保存,其至关于x,y坐标,用于还原时定位div的位置。json
for (var i = 0; i < conn_list.length; i++) { var source_id = conn_list[i]["sourceId"]; var target_id = conn_list[i]["targetId"]; var conn = { "source": { "id": source_id, "anchor_position": conn_list[i]["endpoints"][0]["anchor"]["type"] }, "target": { "id": target_id, "anchor_position": conn_list[i]["endpoints"][1]["anchor"]["type"] } }; nets_conn.push(conn); }
连线保存须要注意两个地方,首先是conn_list的得到,即如何获得目前的全部连线,这里我调用了JsPlumb中现有的接口
conn_list = jsPlumb.getAllConnections()
另外一个地方时anchor_position。这里涉及到了JsPlumb的部分,在连线的时候,只有有anchor的地方才能够连线,为了复原整个图,咱们须要记录下anchor的位置。
如何将保存的数据从数据库中取出不该该是本博客的内容,很少赘述。先贴上完整代码
var structure = eval('(' + net_work["structure"] + ')'); var nets = structure['nets']; var nets_conn = structure['nets_conn']; var static_val = structure['static']; var drop_function = $("#canvas").droppable('option', 'drop'); var event; jQuery.each(nets, function (id, val) { jsPlumb.ready(function () { var ui = { 'offset': { 'left': parseInt(val['left'].split('px')) + $("#canvas").offset().left, 'top': parseInt(val['top'].split('px')) + $("#canvas").offset().top }, 'draggable': [{ "id": val['name'], "innerHTML": $("#" + val['name'])[0].innerHTML }], 'id': id }; drop_function(event, ui); }); window.localStorage.setItem(id, JSON.stringify(val['attribute'])); }); jQuery.each(nets_conn, function (id, val) { jsPlumb.ready(function () { jsPlumb.connect({ "source": val['source']['id'], "target": val['target']['id'], "anchors": [val['source']['anchor_position'], val['target']['anchor_position']], "endpoint": ["Dot", {radius: 5}], "paintStyle": { stroke: "#fc2f49", strokeWidth: 3, }, "maxConnections": -1, "connector": ["Flowchart", { stub: [40, 60], gap: 5, cornerRadius: 5, alwaysRespectStubs: true }], "overlays": [["Arrow", {width: 10, length: 10, location: 1}]], "connectionsDetachable": true, }) }); });
代码看着不少,原理很是简单,就是把用户画图的操做再用js脚本作一遍。
首先第一点,用户在拖拽div进入画布时,画布为droppable状态,会触发JQuery-UI 的drop事件。
$("#canvas").droppable({ scope: "ss", drop: function (event, ui) { ....... } })
第一段代码中的
var drop_function = $("#canvas").droppable('option', 'drop')
drop_function函数就对应了drop事件触发后执行的代码块。
如此一来便很容易理解,只要让每一个被保存的模块去触发drop事件便可,参数ui用保存的属性来本身构造,详情参照代码。
从新连线部分,直接调用JsPlumb的连线方法
jsPlumb.connect()
便可。
注意咱们的anchor要选择以前保存的anchor。