关键字:设计器源代码,Web设计器,工做流设计器,jQuery插件,组态设计器,SCADA系统设计器,流程图设计,表单设计建模,报表设计,可视化,设计时,运行时,轻量级开放平台。html
上节讲到如何经过OOP思路设计设计器视图和元素,本节将重点讲述设计视图上的元素管理(建立组件,清除组件,打开文件,持久化设计),众所周知,设计器视图上的元素主要由组件和连线组成(连线也是组件),只是在建立时因为要先实例化组件,再在组件间连线,因此从管理上来讲将它分开定义,这样咱们在visualDesigner类中定义两个成员:nodes和lines,以下:前端
var VisualDesigner = function (element, options) { this.init(element, options) this.nodes = {};//设计器上全部节点集合 this.lines = {};//设计器上全部线条 }
也许眼尖的读者已经看出来了,为啥不该该是数组集合的类型:this.nodes=[];呢?主要是为了后续经过组件id属性查找时方便,不用遍历全部节点,代码片段以下:node
/*增长元素*/ VisualDesigner.prototype.addElement = function (e) { this.nodes[e.properties.id] = e; } VisualDesigner.prototype.createId = function() { var idx = 1; var name = ""; while (true) { name = "e" + idx; var element = this.nodes[name]; //同名组件是否存在? if (element) idx++; else break; } return name; }
1.建立组件数据库
页面上组件在两个地方会被建立,第一个是拖动工具面板中的组件到设计视图上(已经讲过:鼠标DRAG/DROP事件),第二个是打开保存的组件文件时,还原建立。笔者是有一些清洁代码强迫症的,只要是相同的代码,必须抽象,所以建立元素的代码能够抽象出来:数组
VisualDesigner.prototype.createElement = function (typeName, options) { options.id = this.createId(); //为元素增长id属性 switch (typeName) { case "圆": var circle = new Circle().init().render(options); this.addElement(circle); break; case "矩形": var rect = new Retangle().init().render(options); this.addElement(rect); break; case "椭圆": var path = new Ellipse().init().render(options); this.addElement(path); break; } }
而调用代码则简化为(传递要建立的元素类型和位置信息x/y):工具
this.$element.on("drop", function (event) { event.preventDefault(); var data = null; if (event.dataTransfer == undefined && event.originalEvent != undefined) data = event.originalEvent.dataTransfer.getData("text"); else if (event.dataTransfer != undefined) data = event.dataTransfer.getData("text"); var drag = false; me.createElement(data, { x: event.originalEvent.offsetX, y: event.originalEvent.offsetY }); });
一样的对于不一样的组件在render时也增长了一些默认属性(以前示例是在建立时指定,这是不合理的,所以移到子类组件中),好比typeName、大小、背景色等,以下示例:post
Retangle.prototype = $.extend(Retangle.prototype, { render: function (options) { this.properties.typeName = "矩形"; this.properties.width = 200; this.properties.height = 100; this.properties.opacity = 0.5; this.properties = $.extend(this.properties, options); var rect = new paper.Path.Rectangle({ point: [this.properties.x, this.properties.y], size: [this.properties.width, this.properties.height], radius: 5, strokeWidth: 1, strokeColor: this.properties.borderColor, fillColor: this.properties.backgroundColor, opacity: this.properties.opacity }); this.group.addChild(rect); return this; } });
2.清除组件:this
在打开一个现有设计视图时,必须将设计视图上的全部元素删除,这是如何作到的呢?url
由于咱们在设计视图中有一个nodes和lines对象保存了当前的全部元素,因此能够经过循环删除每个图形化元素,实际就是经过最终的this.group.remove()方法。所以在Component基类中增长destroy方法:spa
Component.prototype.destroy = function () { this.group.remove(); }
清除结点遍历的代码以下:
VisualDesigner.prototype.clear = function () { var me = this; $.each(this.nodes, function (idx, item) { item.destroy(); delete me.nodes[item.properties.id] }) }
3.保存:
保存时,设计器的主要工做就是将当前设计视图上的全部元素和连线序列化成字符串,并返回,由用户决定这个返回的内容是存入数据库仍是本地文件(本示例存到localStorage):
VisualDesigner.prototype.getContent = function () { return JSON.stringify({ "nodes": this.nodes, "lines": this.lines }); }
因此代码很是精简。
咱们再看看前端index.htm中保存代码的逻辑(增长一个btnSave的button元素)
$("#btnSave").on("click", function () { debugger; var content = view.getContent(); localStorage.setItem("visualdesigner", content); })
4.打开现有的设计视图文件:
接上面,设计视图已经保存到localStorage的visualdesigner中,所以按打开(btnOpen)按钮时,先获取已存的内容,再调用设计器的open方法:
$("#btnOpen").on("click", function () { var content = localStorage.getItem("visualdesigner"); if (content) view.open(content); })
VisualDesigner.prototype.open = function (content) { //此处打开操做:清除原来内容,并渲染新内容的代码 this.clear();//先清除原来内容 var contentObj = JSON.parse(content); for (var en in contentObj.nodes) { var el = contentObj.nodes[en]; this.createElement(el.properties.typeName, el.properties) } }
完整的示例效果以下:
源代码:sample.1.4.rar
(本文为原创,在引用代码和文字时请注明出处)