├── imgAndDoc
├── .gitignore
└── img
│ ├── output.jpg
│ ├── output_small.jpg
│ ├── food_product_flow.jpg
│ └── food_product_flow_small.jpg
├── flow_designer
├── .gitignore
└── WebContent
│ ├── css
│ └── designer.css
│ ├── imgs
│ └── design
│ │ ├── cog.png
│ │ ├── anyone.gif
│ │ ├── node.png
│ │ ├── result.gif
│ │ ├── trash.png
│ │ ├── paiallel.gif
│ │ ├── sequence.gif
│ │ ├── sub_flow.png
│ │ ├── Blue Ball.png
│ │ ├── Blue Ball16.png
│ │ ├── Orange Ball.png
│ │ ├── anyone_auto.gif
│ │ ├── anyone_gray.gif
│ │ ├── menus
│ │ ├── broom.png
│ │ ├── disk.png
│ │ ├── print.png
│ │ ├── publish.png
│ │ ├── property.png
│ │ ├── cross-circle.png
│ │ ├── folder-plus.png
│ │ ├── printer_set.png
│ │ ├── tick-circle.png
│ │ ├── folder-open-image-disk.png
│ │ ├── folder-open-image-network.png
│ │ ├── document-attribute-x-export.png
│ │ └── document-attribute-x-download.png
│ │ ├── mouse_add.png
│ │ ├── result_auto.gif
│ │ ├── time_driven.png
│ │ ├── anyone_start.gif
│ │ ├── arrow_refresh.png
│ │ ├── paiallel_gray.gif
│ │ ├── result_break.gif
│ │ ├── sequence_gray.gif
│ │ ├── arrow_refresh_v.png
│ │ ├── sub_flow_anyone.png
│ │ ├── sub_flow_paiallel.png
│ │ └── sub_flow_sequence.png
│ ├── index.html
│ ├── js
│ ├── file_save.js
│ ├── base64.js
│ └── modal.js
│ ├── xmlCreator.js
│ ├── xmlPareser.js
│ ├── dragController.js
│ ├── example
│ └── example1.xml
│ ├── designer.html
│ └── designer.js
├── README.md
├── CODE_OF_CONDUCT.md
└── LICENSE
/imgAndDoc/.gitignore:
--------------------------------------------------------------------------------
1 | /.project
2 |
--------------------------------------------------------------------------------
/flow_designer/.gitignore:
--------------------------------------------------------------------------------
1 | /.project
2 | /.settings/
--------------------------------------------------------------------------------
/imgAndDoc/img/output.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/output.jpg
--------------------------------------------------------------------------------
/imgAndDoc/img/output_small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/output_small.jpg
--------------------------------------------------------------------------------
/imgAndDoc/img/food_product_flow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/food_product_flow.jpg
--------------------------------------------------------------------------------
/flow_designer/WebContent/css/designer.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/css/designer.css
--------------------------------------------------------------------------------
/imgAndDoc/img/food_product_flow_small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/imgAndDoc/img/food_product_flow_small.jpg
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/cog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/cog.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/anyone.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/node.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/result.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/trash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/trash.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/paiallel.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/paiallel.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sequence.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sequence.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sub_flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/Blue Ball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Blue Ball.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/Blue Ball16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Blue Ball16.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/Orange Ball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/Orange Ball.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/anyone_auto.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_auto.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/anyone_gray.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_gray.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/broom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/broom.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/disk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/disk.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/print.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/mouse_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/mouse_add.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/result_auto.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result_auto.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/time_driven.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/time_driven.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/anyone_start.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/anyone_start.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/arrow_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/arrow_refresh.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/publish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/publish.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/paiallel_gray.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/paiallel_gray.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/result_break.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/result_break.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sequence_gray.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sequence_gray.gif
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/arrow_refresh_v.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/arrow_refresh_v.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/property.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/property.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sub_flow_anyone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_anyone.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/cross-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/cross-circle.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/folder-plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-plus.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/printer_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/printer_set.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/tick-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/tick-circle.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sub_flow_paiallel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_paiallel.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/sub_flow_sequence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/sub_flow_sequence.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/folder-open-image-disk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-open-image-disk.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/folder-open-image-network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/folder-open-image-network.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/document-attribute-x-export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/document-attribute-x-export.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/imgs/design/menus/document-attribute-x-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoke1256/FlowDesigner/HEAD/flow_designer/WebContent/imgs/design/menus/document-attribute-x-download.png
--------------------------------------------------------------------------------
/flow_designer/WebContent/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 流程模型管理
6 |
7 |
8 | 点击此处进入流程编辑页面。
9 |
注意:目前支持以下浏览器:chrome,firefox,opera.
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/wanlinus/Anti996-License/blob/master/LICENSE)
2 | [](https://github.com/xiaoke1256/FlowDesigner/blob/master/LICENSE)
3 |
4 | FlowDesigner
5 | ===
6 | 一个用H5实现的工作流引擎的可视化编辑器。可在其上绘制一个流程图。完成绘制后可以以xml文件导出。
7 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/js/file_save.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 本函数用于向本地导出文件。
3 | * @param content 文件内容
4 | * @param type 文件类型,取值类似"text/plain;charset=utf-8"
5 | * @param fileName 文件名
6 | * @returns
7 | */
8 | function saveFile(content, type, fileName) {
9 | var blob;
10 | if (typeof window.Blob == "function") {
11 | blob = new Blob([content], {type: type});
12 | } else {
13 | var BlobBuilder = window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder;
14 | var bb = new BlobBuilder();
15 | bb.append(content);
16 | blob = bb.getBlob(type);
17 | }
18 | var URL = window.URL || window.webkitURL;
19 | var bloburl = URL.createObjectURL(blob);
20 | var anchor = document.createElement("a");
21 | if ('download' in anchor) {
22 | anchor.style.visibility = "hidden";
23 | anchor.href = bloburl;
24 | anchor.download = fileName;
25 | document.body.appendChild(anchor);
26 | var evt = document.createEvent("MouseEvents");
27 | evt.initEvent("click", true, true);
28 | anchor.dispatchEvent(evt);
29 | document.body.removeChild(anchor);
30 | window.URL.revokeObjectURL(anchor.href);
31 | } else if (navigator.msSaveBlob) {
32 | navigator.msSaveBlob(blob, fileName);
33 | } else {
34 | location.href = bloburl;
35 | }
36 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at xiaoke_1256@sina.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/js/base64.js:
--------------------------------------------------------------------------------
1 | function Base64() {
2 |
3 | // private property
4 | _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
5 |
6 | // public method for encoding
7 | this.encode = function (input) {
8 | var output = "";
9 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
10 | var i = 0;
11 | input = _utf8_encode(input);
12 | while (i < input.length) {
13 | chr1 = input.charCodeAt(i++);
14 | chr2 = input.charCodeAt(i++);
15 | chr3 = input.charCodeAt(i++);
16 | enc1 = chr1 >> 2;
17 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
18 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
19 | enc4 = chr3 & 63;
20 | if (isNaN(chr2)) {
21 | enc3 = enc4 = 64;
22 | } else if (isNaN(chr3)) {
23 | enc4 = 64;
24 | }
25 | output = output +
26 | _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
27 | _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
28 | }
29 | return output;
30 | }
31 |
32 | // public method for decoding
33 | this.decode = function (input) {
34 | var output = "";
35 | var chr1, chr2, chr3;
36 | var enc1, enc2, enc3, enc4;
37 | var i = 0;
38 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
39 | while (i < input.length) {
40 | enc1 = _keyStr.indexOf(input.charAt(i++));
41 | enc2 = _keyStr.indexOf(input.charAt(i++));
42 | enc3 = _keyStr.indexOf(input.charAt(i++));
43 | enc4 = _keyStr.indexOf(input.charAt(i++));
44 | chr1 = (enc1 << 2) | (enc2 >> 4);
45 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
46 | chr3 = ((enc3 & 3) << 6) | enc4;
47 | output = output + String.fromCharCode(chr1);
48 | if (enc3 != 64) {
49 | output = output + String.fromCharCode(chr2);
50 | }
51 | if (enc4 != 64) {
52 | output = output + String.fromCharCode(chr3);
53 | }
54 | }
55 | output = _utf8_decode(output);
56 | return output;
57 | }
58 |
59 | // private method for UTF-8 encoding
60 | _utf8_encode = function (string) {
61 | string = string.replace(/\r\n/g,"\n");
62 | var utftext = "";
63 | for (var n = 0; n < string.length; n++) {
64 | var c = string.charCodeAt(n);
65 | if (c < 128) {
66 | utftext += String.fromCharCode(c);
67 | } else if((c > 127) && (c < 2048)) {
68 | utftext += String.fromCharCode((c >> 6) | 192);
69 | utftext += String.fromCharCode((c & 63) | 128);
70 | } else {
71 | utftext += String.fromCharCode((c >> 12) | 224);
72 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
73 | utftext += String.fromCharCode((c & 63) | 128);
74 | }
75 |
76 | }
77 | return utftext;
78 | }
79 |
80 | // private method for UTF-8 decoding
81 | _utf8_decode = function (utftext) {
82 | var string = "";
83 | var i = 0;
84 | var c = c1 = c2 = 0;
85 | while ( i < utftext.length ) {
86 | c = utftext.charCodeAt(i);
87 | if (c < 128) {
88 | string += String.fromCharCode(c);
89 | i++;
90 | } else if((c > 191) && (c < 224)) {
91 | c2 = utftext.charCodeAt(i+1);
92 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
93 | i += 2;
94 | } else {
95 | c2 = utftext.charCodeAt(i+1);
96 | c3 = utftext.charCodeAt(i+2);
97 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
98 | i += 3;
99 | }
100 | }
101 | return string;
102 | }
103 | }
104 |
105 | /**
106 | * 把base64数组转成byte数组
107 | * @returns
108 | */
109 | function base64ToBytes(base64){
110 | var arr = base64.split(',') , mime = arr[0].match(/:(.*?);/)[1] , bstr = atob(arr[1]) , n = bstr.length , u8arr = new Uint8Array(n);
111 | while (n--) {
112 | u8arr[n] = bstr.charCodeAt(n);
113 | }
114 | return u8arr;
115 | }
--------------------------------------------------------------------------------
/flow_designer/WebContent/js/modal.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用jQuery实现一个模态对话框
3 | * 本模块依赖于 jQuery
4 | */
5 |
6 |
7 |
8 | (function($){
9 | //滚动条的宽度,页面加载时就获取
10 | var scrollWidth = 0;
11 | $(function(){
12 | scrollWidth = getScrollWidth();
13 | });
14 |
15 | //默认的长和宽
16 | var defaultSize = {width:600,height:220};
17 |
18 | /**模态对话框对象*/
19 | var modalObj = null;
20 |
21 | $.extend({
22 | modal:function(html,size){
23 | size = $.extend(defaultSize,size);
24 | //获取整个页面可视区域的大小
25 | var cWidth = $(window).width();
26 | var cHeight = $(window).height();
27 | console.log("scrollWidth:"+scrollWidth);
28 | //先创建一个蒙板,蒙住整个页面。
29 | var mask = $('
');
30 | mask.width(cWidth);
31 | mask.height(cHeight);
32 | mask.css('background','#999');
33 | $('body').append(mask);
34 |
35 | //页面正中放一个dev作为模态框。
36 | var $modal = $('');
37 | if(html){
38 | $modal.html(html);
39 | }
40 | $modal.width(size.width);
41 | $modal.height(size.height);
42 | var left = (cWidth-size.width)/2;
43 | if(left< 20)
44 | left = 20;
45 | var top = (cHeight-size.height)/2;
46 | if(top< 10)
47 | top = 10;
48 | $modal.css("left",left);
49 | $modal.css("top",top);
50 | $('body').append($modal);
51 |
52 | //窗口大小变更,蒙板尺寸要跟着变
53 | var hasYScoll = hasYScrollbar(mask[0]);//是否存在纵向的滚动条。
54 | var hasXScoll = hasXScrollbar(mask[0]);
55 | var resizeEve = function(){
56 | var nWidth = $(window).width();
57 | var nHeight = $(window).height();
58 | var newHasYScoll = hasYScrollbar(mask[0]);
59 | var newHasXScoll = hasXScrollbar(mask[0]);
60 | //console.log("newHasYScoll:"+newHasYScoll+" hasYScoll:"+hasYScoll);
61 | if(!hasYScoll && newHasYScoll){//原先没的 后来有了
62 | console.log("纵向滚动条原先没的 后来有了");
63 | nWidth += scrollWidth;
64 | hasYScoll = false;//修正后应当没有滚动条了
65 | }else{
66 | hasYScoll = newHasYScoll;
67 | }
68 | if(!hasXScoll && newHasXScoll){//原先没的 后来有了
69 | console.log("横向滚动条原先没的 后来有了");
70 | nHeight += scrollWidth;
71 | hasXScoll = false;//修正后应当没有滚动条了
72 | }else{
73 | hasXScoll = newHasXScoll;
74 | }
75 | console.log("最终蒙版的高度:"+nHeight);
76 | mask.width(nWidth);
77 | mask.height(nHeight);
78 |
79 | //模态对话框的位置也要跟着变。
80 | var left = (nWidth-size.width)/2;
81 | if(left< 20)
82 | left = 20;
83 | var top = (nHeight-size.height)/2;
84 | if(top< 10)
85 | top = 10;
86 | $modal.css("left",left);
87 | $modal.css("top",top);
88 | }
89 | $(window).resize(resizeEve);
90 |
91 | //滚动条滚动了,蒙版位置要跟着变。
92 | var scrollEve = function() {
93 | var scroH = $(document).scrollTop();//滚动的高度
94 | var scroV = $(document).scrollLeft();//滚动的居左位置
95 | mask.css("top",scroH);
96 | mask.css("left",scroV);
97 |
98 | //模态对话框的位置也要跟着变。
99 | $modal.css("left",left+scroV);
100 | $modal.css("top",top+scroH);
101 | }
102 | $(document).scroll(scrollEve);
103 |
104 | //返回模态窗口对象
105 | modalObj = {
106 | /*关闭模态对话框*/
107 | closed:function(){
108 | //删除模态对话框
109 | $modal.remove();
110 | //删除蒙板
111 | mask.remove();
112 | //注销窗口变化事件
113 | $(window).off('resize',resizeEve);
114 | //注销滚动条变化事件
115 | $(document).off('scroll',scrollEve);
116 | }
117 | };
118 | return modalObj;
119 | },
120 | closeModal:function(){
121 | if(modalObj){
122 | modalObj.closed();
123 | }
124 | }
125 | });
126 |
127 | })(jQuery);
128 |
129 | /**
130 | * 是否有纵向的滚动条
131 | * @returns
132 | */
133 | function hasYScrollbar(mask) {
134 | var height = 0;
135 | if(mask){
136 | height = mask.scrollHeight;
137 | }
138 | height = Math.max(height,document.body.scrollHeight);
139 | //console.log("scrollHeight:"+mask.scrollHeight+ " innerHeight:"+(window.innerHeight || document.documentElement.clientHeight) )
140 | return height > document.documentElement.clientHeight;
141 | }
142 | /**
143 | * 是否有横向的滚动条
144 | * @returns
145 | */
146 | function hasXScrollbar(mask) {
147 | var width = 0;
148 | if(mask){
149 | width = $(mask).outerWidth(true);
150 | }
151 | width = Math.max(width,document.body.scrollWidth);
152 | console.log("width:"+width+" clientWidth: "+document.documentElement.clientWidth);
153 | return width > document.documentElement.clientWidth;
154 | }
155 |
156 | /**
157 | * 获取滚动条的宽度
158 | * @returns
159 | */
160 | function getScrollWidth() {
161 | var noScroll, scroll, oDiv = document.createElement("DIV");
162 | oDiv.style.cssText = "position:absolute;top:-1000px;width:100px;height:100px; overflow:hidden;";
163 | noScroll = document.body.appendChild(oDiv).clientWidth;
164 | oDiv.style.overflowY = "scroll";
165 | scroll = oDiv.clientWidth;
166 | document.body.removeChild(oDiv);
167 | return noScroll-scroll;
168 | }
169 |
170 |
171 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/xmlCreator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 把流程模型转成xml的js.
3 | */
4 | function flModelToXml(flModel){
5 | var xmlDOM = createXMLDOM();
6 | if (xmlDOM) {
7 | //创建根节点
8 | var rootNode = xmlDOM.createElement('esflow');
9 | xmlDOM.appendChild(rootNode);
10 |
11 | var flowInfoModel = flModel.flowInfo.model;
12 | //创建流程节点
13 | var flowNode = xmlDOM.createElement('flow');
14 | for(var prop in flowInfoModel){
15 | flowNode.setAttribute(prop,flowInfoModel[prop]);
16 | }
17 | rootNode.appendChild(flowNode);
18 |
19 | //创建活动节点
20 | var actsNode = xmlDOM.createElement('activities');
21 | flowNode.appendChild(actsNode);
22 |
23 | bizObjsToXmlNode(xmlDOM,flModel.activities,'activity',actsNode);
24 |
25 | //创建结果节点
26 | var opersNode = xmlDOM.createElement('operations');
27 | flowNode.appendChild(opersNode);
28 |
29 | bizObjsToXmlNode(xmlDOM,flModel.operations,'operation',opersNode);
30 |
31 | //创建后续节点
32 | var subseqsNode = xmlDOM.createElement('subsequents');
33 | flowNode.appendChild(subseqsNode);
34 |
35 | bizObjsToXmlNode(xmlDOM,flModel.subsequents,'subsequent',subseqsNode)
36 |
37 | return xmlFormat(parserXMLToString(xmlDOM));
38 | }
39 | }
40 |
41 | /**
42 | * 把一批业务对象转成xml节点
43 | * @returns
44 | */
45 | function bizObjsToXmlNode(xmlDOM,bizes,tagName,parentNode){
46 | for(var i in bizes){
47 | var biz = bizes[i];
48 | var bizNode = xmlDOM.createElement(tagName);
49 | var modelNode = xmlDOM.createElement('model');
50 | var viewNode = xmlDOM.createElement('view');
51 | for(var prop in biz.model){
52 | propNode = xmlDOM.createElement(prop);
53 | textNode = xmlDOM.createTextNode(biz.model[prop]);
54 | propNode.appendChild(textNode);
55 | modelNode.appendChild(propNode);
56 | }
57 | for(var prop in biz.view){
58 | propNode = xmlDOM.createElement(prop);
59 | textNode = xmlDOM.createTextNode(biz.view[prop]);
60 | propNode.appendChild(textNode);
61 | viewNode.appendChild(propNode);
62 | }
63 | bizNode.appendChild(modelNode);
64 | bizNode.appendChild(viewNode);
65 | parentNode.appendChild(bizNode);
66 | }
67 | }
68 |
69 | /**
70 | * 创建 XMLDOM
71 | * @returns xmlDOM
72 | */
73 | function createXMLDOM() {
74 | var xmlDOM;
75 | if (window.ActiveXObject) {
76 | xmlDOM = new ActiveXObject('Microsoft.XMLDOM');
77 | } else if (document.implementation
78 | && document.implementation.createDocument) {
79 | xmlDOM = document.implementation.createDocument('', '', null);
80 | } else {
81 | alert('您的浏览器不支持文档对象XMLDOM');
82 | return;
83 | }
84 | return xmlDOM;
85 | }
86 |
87 | /**
88 | * 把XMLDOM解析成字符串
89 | * @param xmlDOM
90 | * @returns
91 | */
92 | function parserXMLToString(xmlDOM) {
93 | if (window.ActiveXObject) {
94 | return xmlDOM.xml;
95 | } else if (document.implementation
96 | && document.implementation.createDocument) {
97 | return new XMLSerializer().serializeToString(xmlDOM);
98 | }
99 | }
100 |
101 | /**
102 | * 把xml格式化一下
103 | * @param xml
104 | * @returns
105 | */
106 | function xmlFormat(xml){
107 | if(!xml){
108 | return xml;
109 | }
110 | xml = $.trim(xml);
111 | var prefix = '';
112 | if(xml.indexOf('\n\n';
114 | }
115 | var sp = 0;//缩进
116 | var preTagName = ''; //上次循环处理的TagName
117 | var preStartTagFlage = false;//true为 false 为 ,null为 .
118 | var index = xml.indexOf('<',0);
119 | while(index>=0){
120 | //console.log(index+" char At(index+1):"+xml.charAt(index+1));
121 | var tagEndIndex = xml.indexOf('>',index+1);
122 | //console.log("end Tag index:"+tagEndIndex);
123 | var tagName = xml.substring(index+1,tagEndIndex);
124 | //console.log("tagName:"+tagName);
125 | var startTagFlage = false;
126 | if(tagName.charAt(0)=='/'){
127 | //需要出栈
128 | console.log("出栈.");
129 | startTagFlage = false;
130 | tagName = tagName.substring(1);
131 | }else if(tagName.charAt(tagName.length-1)=='/'){
132 | //不出栈也不入栈
133 | console.log("不出栈也不入栈.");
134 | startTagFlage = null;
135 | tagName = tagName.substring(0,tagName.length-1);
136 | }else{
137 | console.log("入栈.");
138 | //需要入栈
139 | startTagFlage = true;
140 | }
141 | console.log("tagName:"+tagName);
142 | if(startTagFlage==null){
143 | //要换行,
144 | //sp+=2;
145 | }else if(!startTagFlage ){
146 | sp -= 2;
147 | //上次为入栈且处理的标签是一样的。
148 | if(preStartTagFlage && preTagName == tagName){
149 | //不用换行处理
150 | index = xml.indexOf('<',index+1);
151 | continue;
152 | }
153 |
154 | }else if(startTagFlage){
155 | //不处理后续再处理。
156 | }
157 | //在index位置插入一个换行符和若干个空格
158 | //console.log("sp:"+sp);
159 | var spaces = '';
160 | for(var i=0;i0?sp:0)+1);
173 | index = xml.indexOf('<',index+1);
174 | }
175 |
176 | return prefix+xml;
177 | }
178 |
179 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/xmlPareser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 把xml的内容转成Doc对象
3 | * @returns
4 | */
5 | function loadXML(xmlString){
6 | var xmlDoc = null ;
7 | // 判断浏览器的类型
8 | // 支持IE浏览器
9 | if ( ! window.DOMParser && window.ActiveXObject){ // window.DOMParser 判断是否是非ie浏览器
10 | var xmlDomVersions = [ ' MSXML.2.DOMDocument.6.0 ' , ' MSXML.2.DOMDocument.3.0 ' , ' Microsoft.XMLDOM ' ];
11 | for ( var i = 0 ;i < xmlDomVersions.length;i ++ ){
12 | try {
13 | xmlDoc = new ActiveXObject(xmlDomVersions[i]);
14 | xmlDoc.async = false ;
15 | xmlDoc.loadXML(xmlString); // loadXML方法载入xml字符串
16 | break ;
17 | } catch (e){
18 | }
19 | }
20 | }
21 | // 支持Mozilla浏览器
22 | else if (window.DOMParser && document.implementation && document.implementation.createDocument){
23 | try {
24 | /* DOMParser 对象解析 XML 文本并返回一个 XML Document 对象。
25 | * 要使用 DOMParser,使用不带参数的构造函数来实例化它,然后调用其 parseFromString() 方法
26 | * parseFromString(text, contentType) 参数text:要解析的 XML 标记 参数contentType文本的内容类型
27 | * 可能是 "text/xml" 、"application/xml" 或 "application/xhtml+xml" 中的一个。注意,不支持 "text/html"。
28 | */
29 | domParser = new DOMParser();
30 | xmlDoc = domParser.parseFromString(xmlString, 'text/xml' );
31 | } catch (e){
32 | console.error(e);
33 | throw e;
34 | }
35 | }
36 | else {
37 | return null ;
38 | }
39 |
40 | return xmlDoc;
41 | }
42 |
43 | /**把xml文档转成一个对象*/
44 | function xmlDocToObj(xmlDoc){
45 | var flowModle = {
46 | flowInfo:{model:{},view:{}},
47 | activities:[],/*活动*/
48 | operations:[],/*操作结果*/
49 | subsequents:[] /*后续线*/
50 | };
51 | var flowInfoModel = flowModle.flowInfo.model;
52 | var nodes = xmlDoc.getElementsByTagName("flow")
53 | if(!nodes || nodes.length==0){
54 | throw "xml 解析异常,未找到 flow 节点。";
55 | }
56 | var flowNode = nodes[0];
57 | console.log("flowNode.attributes:"+flowNode.attributes);
58 | var flowId = flowNode.getAttribute("flowId");
59 | var version = flowNode.getAttribute("version");
60 | var flowName = flowNode.getAttribute("flowName");
61 | var displayName = flowNode.getAttribute("displayName");
62 | var description = flowNode.getAttribute("description");
63 | flowInfoModel.flowId = flowId;
64 | flowInfoModel.version = version;
65 | flowInfoModel.flowName = flowName;
66 | flowInfoModel.displayName = displayName;
67 | flowInfoModel.description = description;
68 |
69 | //处理各个环节
70 | var nodes = flowNode.getElementsByTagName("activities");
71 | if(!nodes || nodes.length==0){
72 | throw "xml 解析异常,未找到 activities 节点。";
73 | }
74 | var actsNode = nodes[0];
75 | var actNodes = actsNode.getElementsByTagName("activity");
76 | if(!actNodes || actNodes.length==0){
77 | throw "xml 解析异常,未找到 activity 节点。";
78 | }
79 | for(var i in actNodes){
80 | var actNode = actNodes[i];
81 |
82 | var act = bizNodeToObj(actNode);
83 | if(act)
84 | flowModle.activities.push(act);
85 | }
86 |
87 | //处理各个结果
88 | var nodes = flowNode.getElementsByTagName("operations");
89 | if(!nodes || nodes.length==0){
90 | throw "xml 解析异常,未找到 operations 节点。";
91 | }
92 | var opersNode = nodes[0];
93 | var operNodes = opersNode.getElementsByTagName("operation");
94 | if(!operNodes || operNodes.length==0){
95 | throw "xml 解析异常,未找到 operation 节点。";
96 | }
97 | for(var i in operNodes){
98 | var operNode = operNodes[i];
99 |
100 | var oper = bizNodeToObj(operNode);
101 | if(oper)
102 | flowModle.operations.push(oper);
103 | }
104 |
105 | //处理各个后续线
106 | var nodes = flowNode.getElementsByTagName("subsequents");
107 | if(!nodes || nodes.length==0){
108 | throw "xml 解析异常,未找到 operations 节点。";
109 | }
110 | var subseqsNode = nodes[0];
111 | var subseqNodes = subseqsNode.getElementsByTagName("subsequent");
112 | for(var i in subseqNodes){
113 | var subseqNode = subseqNodes[i];
114 |
115 | var subseq = bizNodeToObj(subseqNode);
116 | if(subseq)
117 | flowModle.subsequents.push(subseq);
118 | }
119 |
120 | return flowModle;
121 | }
122 |
123 | /**
124 | * 把xml中的业务节点转成业务对象。
125 | * @param bizNode
126 | * @returns
127 | */
128 | function bizNodeToObj(bizNode){
129 | if(typeof(bizNode.getElementsByTagName)!='function' ){
130 | console.log("getElementsByTagName is not a function! "+typeof(bizNode.getElementsByTagName));
131 | }
132 | var childNodes = bizNode.children;
133 | if(!childNodes){
134 | console.warn("childNodes 居然为空!!text:"+bizNode.text);
135 | return null;
136 | }
137 | if(childNodes.length<2){
138 | throw "xml 解析异常,一个业务对象应当既包含model节点,又包含view节点。";
139 | }
140 | var modelNode =childNodes[0];
141 | var viewNode =childNodes[1];
142 | if(modelNode.nodeName!='model'){
143 | throw "xml 解析异常,activity 下未找到 model 节点。";
144 | }
145 | if(viewNode.nodeName!='view'){
146 | throw "xml 解析异常,activity 下未找到 view 节点。";
147 | }
148 | var model = {};
149 | var view = {};
150 | var propNodes = modelNode.children;
151 | for(var j in propNodes){
152 | if(!propNodes[j].nodeName)
153 | continue;
154 | model[propNodes[j].nodeName]=propNodes[j].textContent ;
155 | //console.log("针对字段“"+propNodes[j].nodeName+"”设置了值“"+propNodes[j].textContent +"”");
156 | }
157 | var propNodes = viewNode.children;
158 | for(var j in propNodes){
159 | if(!propNodes[j].nodeName)
160 | continue;
161 | view[propNodes[j].nodeName]=parseInt(propNodes[j].textContent) ;
162 | //console.log("针对字段“"+propNodes[j].nodeName+"”设置了值“"+parseInt(propNodes[j].textContent) +"”");
163 | }
164 | return {model:model,view:view};
165 | }
--------------------------------------------------------------------------------
/flow_designer/WebContent/dragController.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 本js文件定义了,鼠标拖动的控制器。
3 | * 包含两个控制器,一个是默认的,一个是调整坐标系时用的。
4 | * 本js程序依赖于以下程序:
5 | * jQuery.js
6 | */
7 |
8 | /**
9 | * 默认的鼠标拖动控制器
10 | */
11 | var getDefaultDragCtrl = function(renderCtx){
12 |
13 | var flRender = renderCtx;
14 |
15 | /**结束鼠标拖动事件*/
16 | function _onEndDrag(obj){
17 | //如果拖动的是控制点的话需要处理
18 | if(obj instanceof ControlPoint){
19 | var redMarked = flRender.getRedMarked();
20 | //看是否拖动到了某个对象内
21 | if(!redMarked){
22 | resetControlPoint(obj.parent);
23 | return;
24 | }
25 | if(obj.parent instanceof Oper){
26 | var target = redMarked;
27 | if(!(target instanceof Act)){//一个结果必须与一个活动关联.
28 | resetControlPoint(obj.parent);
29 | return;
30 | }
31 | if(!target.model.activityId){
32 | showErrMsg('请先填写“活动代码”。');
33 | resetControlPoint(obj.parent);
34 | return;
35 | }
36 | obj.parent.model.activityId = target.model.activityId;
37 | obj.parent.view.controlPoint = null;
38 | }
39 | if(obj.parent instanceof Subsequent){
40 | var target = redMarked;
41 | if (target instanceof Act){
42 | if(!target.model.activityId){
43 | showErrMsg('请先填写“活动代码”。');
44 | resetControlPoint(obj.parent,obj);
45 | return;
46 | }
47 | if(obj.parent.model.activityId){
48 | showErrMsg('后续线应当一头连接活动,一头连接结果。');
49 | resetControlPoint(obj.parent,obj);
50 | return;
51 | }
52 | obj.parent.model.activityId = target.model.activityId;
53 | if(obj.parent.view.controlPoint===obj){
54 | obj.parent.view.controlPoint = null;
55 | }else if(obj.parent.view.controlPoint1===obj){
56 | obj.parent.view.controlPoint1 = null;
57 | }
58 | }
59 | if (target instanceof Oper){
60 | if(!target.model.operationId){
61 | showErrMsg('请先填写“结果代码”。');
62 | resetControlPoint(obj.parent,obj);
63 | return;
64 | }
65 | if(obj.parent.model.operationId){
66 | showErrMsg('后续线应当一头连接活动,一头连接结果。');
67 | resetControlPoint(obj.parent,obj);
68 | return;
69 | }
70 | obj.parent.model.operationId = target.model.operationId;
71 | if(obj.parent.view.controlPoint===obj){
72 | obj.parent.view.controlPoint = null;
73 | }else if(obj.parent.view.controlPoint1===obj){
74 | obj.parent.view.controlPoint1 = null;
75 | }
76 | }
77 | }
78 |
79 | }
80 | }
81 |
82 | /**业务对象被拖动事件*/
83 | function _onBusinessObjDrag(bizObj,beforePos,afterPos){
84 | bizObj.view.x=bizObj.view.x+afterPos.x-beforePos.x;
85 | bizObj.view.y=bizObj.view.y+afterPos.y-beforePos.y;
86 | if(bizObj.view.controlPoint){
87 | bizObj.view.controlPoint.x = bizObj.view.controlPoint.x+afterPos.x-beforePos.x;
88 | bizObj.view.controlPoint.y = bizObj.view.controlPoint.y+afterPos.y-beforePos.y;
89 | }
90 | if(bizObj.view.controlPoint1){
91 | bizObj.view.controlPoint1.x = bizObj.view.controlPoint1.x+afterPos.x-beforePos.x;
92 | bizObj.view.controlPoint1.y = bizObj.view.controlPoint1.y+afterPos.y-beforePos.y;
93 | }
94 | }
95 | /**控制点被拖动事件*/
96 | function _onControlPointDrag(controlPoint,beforePos,afterPos){
97 | var flowModle = flRender.getFlowModle();
98 | controlPoint.x = controlPoint.x + afterPos.x-beforePos.x;
99 | controlPoint.y = controlPoint.y + afterPos.y-beforePos.y;
100 | //标红
101 | for(var i in flowModle.activities){
102 | var act = flowModle.activities[i];
103 | var view = act.view;
104 | if(view.x < afterPos.x && afterPos.x < view.x + view.width
105 | && view.y < afterPos.y && afterPos.y < view.y + view.height ){
106 | console.log('actact');
107 | flRender.setRedMarked(act);
108 | return;
109 | }
110 | }
111 | for(var i in flowModle.operations){
112 | var oper = flowModle.operations[i];
113 | var view = oper.view;
114 | if(view.x < afterPos.x && afterPos.x < view.x + view.width
115 | && view.y < afterPos.y && afterPos.y < view.y + view.height ){
116 | console.log('oper selected : '+(oper instanceof Oper));
117 | flRender.setRedMarked(oper);
118 | return;
119 | }
120 | }
121 | //没有拖动到任何对象内则取消标红
122 | flRender.setRedMarked(null);
123 | }
124 |
125 | return {
126 | /**开始拖动事件*/
127 | onStartDrag:function (obj){
128 | //do nothing.
129 | },
130 | /**结束拖动鼠标事件*/
131 | onEndDrag:function(obj){
132 | _onEndDrag(obj);
133 | },
134 | /**拖动事件*/
135 | onDrag:function(obj,beforePos,afterPos){
136 | if(!obj)
137 | return;
138 | if(obj instanceof BussinessObj){
139 | _onBusinessObjDrag(obj,beforePos,afterPos);
140 | }else if(obj instanceof ControlPoint){
141 | _onControlPointDrag(obj,beforePos,afterPos);
142 | }
143 | },
144 | /**右击事件*/
145 | rightClick:function(obj){
146 | //先把业务对象选中
147 | flRender.resetSelected(obj);
148 | //然后将右键菜单显示出来
149 | //将右键菜单挪到鼠标所在的位置
150 | var x = event.pageX;
151 | var y = event.pageY;
152 | var rightMenuDiv = null;
153 | if(obj instanceof Act){
154 | rightMenuDiv = $('#rightMenuForAct');
155 | }else if(obj instanceof Oper){
156 | rightMenuDiv = $('#rightMenuForOper');
157 | }else if(obj instanceof Subsequent){
158 | rightMenuDiv = $('#rightMenuForSubseq');
159 | }else{
160 | return;
161 | }
162 | rightMenuDiv.css("left",x);
163 | rightMenuDiv.css("top",y);
164 | rightMenuDiv.show();
165 | }
166 | }
167 | };
168 |
169 | //为了配合上述处理把浏览器默认的右键菜单禁用掉.
170 | $(function(){
171 | //把浏览器默认的右键菜单禁用掉.
172 | $('.rightMenu').bind("contextmenu", function(){
173 | return false;
174 | });
175 | //点击任何地方,就把右键菜单隐藏起来.
176 | $('body').click(function(){
177 | $('.rightMenu').hide();
178 | })
179 | });
180 |
181 | /**
182 | * 把控制点调整到默认位置。
183 | * @param obj 业务对象
184 | * @param thisControlPoint 本控制点。
185 | * @returns
186 | */
187 | function resetControlPoint(obj,thisControlPoint){
188 | if(!thisControlPoint && obj.view.controlPoint || thisControlPoint && thisControlPoint===obj.view.controlPoint){
189 | var controlPoint = obj.view.controlPoint;
190 | var x = obj.view.x +Math.floor((obj.view.width)/2);
191 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。
192 | controlPoint.x = x;
193 | controlPoint.y = y;
194 | }
195 | if(!thisControlPoint && obj.view.controlPoint1 || thisControlPoint && thisControlPoint===obj.view.controlPoint1){
196 | var controlPoint = obj.view.controlPoint1;
197 | var x = obj.view.x +Math.floor((obj.view.width)/2);
198 | var y = obj.view.y+30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。
199 | controlPoint.x = x;
200 | controlPoint.y = y;
201 | }
202 | //如果控制点缺失要将他补齐
203 | if(obj instanceof Oper ){
204 | if(!obj.model.activityId && !obj.view.controlPoint){
205 | var x = obj.view.x +Math.floor((obj.view.width)/2);
206 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。
207 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个
208 | controlPoint.parent = obj;//父对象就是其业务对象。
209 | controlPoint.parentType = 'result';
210 | obj.view.controlPoint = controlPoint;
211 | }
212 | }
213 | if(obj instanceof Subsequent){
214 | var fillNum = 0;//需要补充的数量。
215 | if(!obj.model.operationId){
216 | fillNum++;
217 | }
218 | if(!obj.model.activityId){
219 | fillNum++;
220 | }
221 | if(obj.view.controlPoint){
222 | fillNum--;
223 | }
224 | if(obj.view.controlPoint1){
225 | fillNum--;
226 | }
227 | if(fillNum>0 && !obj.view.controlPoint){
228 | var x = obj.view.x +Math.floor((obj.view.width)/2);
229 | var y = obj.view.y-30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。
230 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个
231 | controlPoint.parent = obj;//父对象就是其业务对象。
232 | controlPoint.parentType = 'subseq';
233 | obj.view.controlPoint = controlPoint;
234 | fillNum--;
235 | }
236 | if(fillNum>0 && !obj.view.controlPoint1){
237 | var x = obj.view.x +Math.floor((obj.view.width)/2);
238 | var y = obj.view.y+30+Math.floor(icons['mouse'].height/2);// 鼠标图形的一半。
239 | var controlPoint = new ControlPoint(x,y);//坐标先随便设一个
240 | controlPoint.parent = obj;//父对象就是其业务对象。
241 | controlPoint.parentType = 'subseq';
242 | obj.view.controlPoint1 = controlPoint;
243 | fillNum--;
244 | }
245 |
246 | }
247 | }
248 |
249 | /**
250 | * 鼠标拖动控制器,用来调整坐标系
251 | */
252 | var getMovimgDragCtrl = function(renderCtx){
253 | var flRender = renderCtx;
254 | function _onDrag(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos){
255 | renderCtx.moveOriginPoint(afterAbsPos.x-beforeAbsPos.x,afterAbsPos.y-beforeAbsPos.y);
256 | }
257 | return {
258 | /**开始拖动事件*/
259 | onStartDrag:function (obj){
260 | //do nothing.
261 | },
262 | /**结束拖动鼠标事件*/
263 | onEndDrag:function(obj){
264 | //do nothing.
265 | },
266 | /**拖动事件*/
267 | onDrag:function(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos){
268 | _onDrag(obj,beforePos,afterPos,beforeAbsPos,afterAbsPos)
269 | },
270 | /**右击事件*/
271 | rightClick:function(obj){
272 | //do nothing.
273 | }
274 | };
275 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2020 Tang Jun
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/example/example1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 0
10 | 01
11 | 1
12 | 0
13 | 0000
14 | 提交请假申请
15 | 提交请假申请
16 | 0000
17 |
18 |
19 | 105
20 | 36
21 | 28
22 | 401
23 | 124
24 |
25 |
26 |
27 |
28 | 0
29 | 01
30 | 0
31 | 1
32 | 0001
33 | 科长审批
34 | 科长审批
35 | 0001
36 |
37 |
38 | 106
39 | 36
40 | 28
41 | 402
42 | 294
43 |
44 |
45 |
46 |
47 | 0
48 | 01
49 | 0
50 | 0
51 | 0002
52 | 处级领导审批
53 | 处级领导审批
54 | 0002
55 |
56 |
57 | 108
58 | 36
59 | 28
60 | 404
61 | 463
62 |
63 |
64 |
65 |
66 | 0
67 | 01
68 | 0
69 | 0
70 | 0003
71 | 局级领导审批
72 | 局级领导审批
73 | 0003
74 |
75 |
76 | 112
77 | 36
78 | 28
79 | 405
80 | 627
81 |
82 |
83 |
84 |
85 | 0
86 | 01
87 | 0
88 | 0
89 | 0004
90 | 人事部备案
91 | 人事部备案
92 | 0004
93 |
94 |
95 | 122
96 | 36
97 | 28
98 | 633
99 | 699
100 |
101 |
102 |
103 |
104 |
105 |
106 | 0
107 | 1
108 | 00:00:00
109 | 0000
110 |
111 |
112 | 提交
113 | 提交
114 | 000001
115 | 000001
116 | 1
117 |
118 |
119 | 107
120 | 12
121 | 12
122 | 409
123 | 201
124 | null
125 |
126 |
127 |
128 |
129 | 0
130 | 1
131 | 00:00:00
132 | 0001
133 |
134 |
135 | 审批通过
136 | 审批通过
137 | 000101
138 | 1
139 | 000101
140 |
141 |
142 | 109
143 | 12
144 | 12
145 | 526
146 | 374
147 | null
148 |
149 |
150 |
151 |
152 | 0
153 | 1
154 | 00:00:00
155 | 0001
156 |
157 |
158 | 审批驳回
159 | 审批驳回
160 | 000198
161 | 000198
162 | 0
163 | 0
164 |
165 |
166 | 110
167 | 12
168 | 12
169 | 294
170 | 230
171 | null
172 |
173 |
174 |
175 |
176 | 0
177 | 1
178 | 00:00:00
179 | 0001
180 |
181 |
182 | 请假2天以上
183 | 请假2天以上
184 | 000103
185 | 000103
186 |
187 |
188 | 111
189 | 12
190 | 12
191 | 411
192 | 371
193 | null
194 |
195 |
196 |
197 |
198 | 0
199 | 1
200 | 00:00:00
201 | 0002
202 |
203 |
204 | 请假一周以上
205 | 请假一周以上
206 | 000202
207 | 000202
208 |
209 |
210 | 113
211 | 12
212 | 12
213 | 412
214 | 536
215 | null
216 |
217 |
218 |
219 |
220 | 0
221 | 1
222 | 00:00:00
223 | 0002
224 |
225 |
226 | 驳回
227 | 驳回
228 | 000298
229 | 000298
230 |
231 |
232 | 114
233 | 12
234 | 12
235 | 299
236 | 445
237 | null
238 |
239 |
240 |
241 |
242 | 0
243 | 1
244 | 00:00:00
245 | 0002
246 |
247 |
248 | 通过
249 | 通过
250 | 000201
251 | 000201
252 | 0
253 |
254 |
255 | 115
256 | 12
257 | 12
258 | 522
259 | 495
260 | null
261 |
262 |
263 |
264 |
265 | 0
266 | 1
267 | 00:00:00
268 | 0003
269 |
270 |
271 | 驳回
272 | 驳回
273 | 000398
274 | 000398
275 |
276 |
277 | 120
278 | 12
279 | 12
280 | 294
281 | 604
282 | null
283 |
284 |
285 |
286 |
287 | 0
288 | 1
289 | 00:00:00
290 | 0003
291 |
292 |
293 | 通过
294 | 通过
295 | 000301
296 | 000301
297 |
298 |
299 | 121
300 | 12
301 | 12
302 | 520
303 | 676
304 | null
305 |
306 |
307 |
308 |
309 | 0
310 | 1
311 | 00:00:00
312 | 0004
313 |
314 |
315 | 结束
316 | 结束
317 | 000401
318 | 000401
319 | 1
320 |
321 |
322 | 124
323 | 12
324 | 12
325 | 640
326 | 782
327 | null
328 |
329 |
330 |
331 |
332 |
333 |
334 | 0
335 | 0
336 | 1
337 |
338 | 0001
339 | 000001
340 |
341 |
342 | 410
343 | 255
344 | null
345 | null
346 | 12
347 | 12
348 | 116
349 |
350 |
351 |
352 |
353 | 0
354 | 0
355 | 1
356 |
357 | 0002
358 | 000103
359 |
360 |
361 | 412
362 | 422
363 | null
364 | null
365 | 12
366 | 12
367 | 117
368 |
369 |
370 |
371 |
372 | 0
373 | 0
374 | 1
375 |
376 | 0001
377 | 000298
378 |
379 |
380 | 299
381 | 338
382 | null
383 | null
384 | 12
385 | 12
386 | 118
387 |
388 |
389 |
390 |
391 | 0
392 | 0
393 | 1
394 |
395 | 0003
396 | 000202
397 |
398 |
399 | 412
400 | 584
401 | null
402 | null
403 | 12
404 | 12
405 | 119
406 |
407 |
408 |
409 |
410 | 0
411 | 0
412 | 1
413 |
414 | 0000
415 | 000198
416 |
417 |
418 | 294
419 | 178
420 | null
421 | null
422 | 12
423 | 12
424 |
425 |
426 |
427 |
428 | 0
429 | 0
430 | 1
431 |
432 | 0002
433 | 000398
434 |
435 |
436 | 296
437 | 499
438 | null
439 | null
440 | 12
441 | 12
442 |
443 |
444 |
445 |
446 | 0
447 | 0
448 | 1
449 |
450 | 0004
451 | 000201
452 |
453 |
454 | 639
455 | 599
456 | null
457 | null
458 | 12
459 | 12
460 |
461 |
462 |
463 |
464 | 0
465 | 0
466 | 1
467 |
468 | 0004
469 | 000301
470 |
471 |
472 | 576
473 | 691
474 | null
475 | null
476 | 12
477 | 12
478 |
479 |
480 |
481 |
482 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/designer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 流程模型管理
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
438 |
439 |
440 |
450 |
454 |
457 |
458 |
459 |
484 |
485 |
486 |
487 |
514 |
515 |
516 |
活动基本信息
517 |
565 |
活动控制信息
566 |
593 |
活动权限范围信息
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
结果基本信息
605 |
633 |
结果控制信息
634 |
635 |
636 |
637 | | 是否中断 |
638 |
639 |
640 | 撤销本活动引发的所有后续待办任务
641 |
642 | |
643 |
644 |
645 | | 意见必输 |
646 |
647 |
648 | 用户意见必输
649 |
650 | |
651 |
652 |
653 |
654 |
自动完成信息
655 |
688 |
689 |
690 |
691 |
692 |
后续控制信息
693 |
737 |
后续用户对象
738 |
802 |
803 |
804 |
805 |
806 |
807 |
812 |
818 |
825 |
891 |
892 |
--------------------------------------------------------------------------------
/flow_designer/WebContent/designer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 流程图编辑器
3 | * 本js程序依赖于以下程序:
4 | * jQuery.js
5 | * dragController.js
6 | */
7 | /*
8 | * 定义业务对象
9 | */
10 | /**
11 | * 基类的构造函数
12 | * @param obj
13 | * @returns
14 | */
15 | var BussinessObj = function(obj){
16 | this.model={};
17 | if(obj && obj instanceof Object){
18 | this.model=obj.model;
19 | console.log("obj.model.displayName:"+obj.model.displayName);
20 | }
21 | this.view={};
22 | if(obj && obj instanceof Object && obj.view){
23 | this.view=obj.view;
24 | }
25 | }
26 |
27 | /**
28 | * 子类,Activity
29 | */
30 | var Act = function(obj){
31 | var defaultModel = {
32 | "listNo":0,/*排序号*/
33 | "activityType":'01',
34 | "activityBz":'0',
35 | "authority":'0',
36 | "canWithdraw":'0'
37 | }
38 | obj.model = $.extend(defaultModel,obj.model);
39 | BussinessObj.call(this,obj);
40 | };
41 | Act.prototype = new BussinessObj();
42 |
43 | /**
44 | * 子类,操作选项
45 | */
46 | var Oper = function(obj){
47 | var defaultModel = {
48 | "listNo":0,/*排序号*/
49 | "deadlineType":'1',
50 | "deadlineTime":'00:00:00',
51 | "resultFlag":'0',
52 | "mustHaveOpinion":'0',
53 | "autoFinish":'0'
54 | }
55 | obj.model = $.extend(defaultModel,obj.model);
56 | BussinessObj.call(this,obj);
57 | if(!obj.model.activityId){
58 | //在业务对象的上方(30个像素处)增加一个控制点。(控制点以图形的中心为准)
59 | var x = this.view.x +Math.floor((icons['oper'].width)/2);
60 | var heightOfMouse = icons['mouse'].height;//鼠标图形的高度
61 | var y = this.view.y-30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。
62 | var controlPoint = new ControlPoint(x,y);
63 | controlPoint.parent = this;//父对象就是其业务对象。
64 | controlPoint.parentType = 'result';
65 | this.view.controlPoint = controlPoint;
66 | }
67 | };
68 | Oper.prototype = new BussinessObj();
69 |
70 | /**
71 | * 子类,后续线
72 | */
73 | var Subsequent = function(obj){
74 | var defaultModel = {
75 | "sortNumber":0,/*排序号*/
76 | "sequence":'0',
77 | "postDisplay":'1',
78 | "postDefault":'',
79 | "inessential":'0',
80 | "postDisplay":'0',
81 | "postMustHave":'0',
82 | "postMustOne":'0',
83 | "postSameDept":'0'
84 | }
85 | obj.model = $.extend(defaultModel,obj.model);
86 | BussinessObj.call(this,obj);
87 | var numOfControlPoint = 0;//控制点数量
88 | if(!obj.model.activityId){
89 | numOfControlPoint++;
90 | }
91 | if(!obj.model.operationId){
92 | numOfControlPoint++;
93 | }
94 | //有两个控制点,一个是controlPoint,一个是controlPoint1
95 | if(numOfControlPoint>=1){
96 | //在业务对象的上方(30个像素处)增加一个控制点。(控制点以图形的中心为准)
97 | var x = this.view.x +Math.floor((icons['subseq'].width)/2);
98 | var heightOfMouse = icons['mouse'].height;//鼠标图形的高度
99 | var y = this.view.y-30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。
100 | var controlPoint = new ControlPoint(x,y);
101 | controlPoint.parent = this;//父对象就是其业务对象。
102 | controlPoint.parentType = 'result';
103 | this.view.controlPoint=controlPoint;
104 | }
105 | if(numOfControlPoint>=2){
106 | //在业务对象的下方(30个像素处)增加一个控制点。
107 | var x = this.view.x +Math.floor((icons['subseq'].width)/2);
108 | var y = this.view.y+30+Math.floor(heightOfMouse/2);// 鼠标图形高度的一半。
109 | var controlPoint = new ControlPoint(x,y);
110 | controlPoint.parent = this;//父对象就是其业务对象。
111 | controlPoint.parentType = 'mouse';
112 | this.view.controlPoint1=controlPoint;
113 | }
114 | }
115 | Subsequent.prototype = new BussinessObj();
116 |
117 | /**
118 | * 流程基本信息
119 | */
120 | var FlowInfo =function(obj){
121 | var defaultModel = {
122 | "flowId":0,/*流程模型的编号*/
123 | "version":'1.0',/*流程模型的版本号*/
124 | "flowName":'',/*流程模型的名称*/
125 | "displayName":'',
126 | "description":''
127 | };
128 | if(!obj){
129 | obj = {};
130 | }
131 | obj.model = $.extend(defaultModel,obj.model);
132 | if(!obj.view){
133 | obj.view = {width:84,height:60};
134 | }
135 | BussinessObj.call(this,obj);
136 | }
137 |
138 | /**
139 | * 一个坐标点
140 | */
141 | var Point = function(x,y){
142 | this.x = 0;
143 | this.y = 0;
144 | if(x)
145 | this.x=x;
146 | if(y)
147 | this.y=y;
148 | }
149 | /**
150 | * 控制点(业务对象上可以被鼠标拖动的点)
151 | */
152 | var ControlPoint = function(x,y){
153 | Point.call(this,x,y);
154 | }
155 | ControlPoint.prototype = new Point();
156 |
157 | /**
158 | * 绘图过程中要使用到的图片(图标)
159 | */
160 | var icons = (function(){
161 | //活动图片.
162 | var actImg = new Image();
163 | actImg.src='imgs/design/anyone.gif';
164 | actImg.width = 28;//这里未必是图片真实的宽度,因图片上有可能有空白的边。
165 | actImg.height = 36;//这里未必是图片真实的高度,因图片上有可能有空白的边。
166 | //开始活动图片.
167 | var actStartImg = new Image();
168 | actStartImg.src='imgs/design/anyone_start.gif';
169 | actStartImg.width = 28;
170 | actStartImg.height = 36;
171 | //自动完成活动图片.
172 | var actAutoImg = new Image();
173 | actAutoImg.src='imgs/design/anyone_auto.gif';
174 | actAutoImg.width = 28;
175 | actAutoImg.height = 36;
176 | //多人并行
177 | var actPiallImg = new Image();
178 | actPiallImg.src='imgs/design/paiallel.gif';
179 | actPiallImg.width = 28;
180 | actPiallImg.height = 36;
181 | //多人串行
182 | var actSeqImg = new Image();
183 | actSeqImg.src='imgs/design/sequence.gif';
184 | actSeqImg.width = 28;
185 | actSeqImg.height = 36;
186 | //图片结果图片
187 | var operImg = new Image();
188 | operImg.src='imgs/design/result.gif';
189 | operImg.width = 12;
190 | operImg.height = 12;
191 | //自动完成的结果
192 | var operAutoImg = new Image();
193 | operAutoImg.src= 'imgs/design/result_auto.gif';
194 | operAutoImg.width = 12;
195 | operAutoImg.height = 12;
196 | //中断的结果
197 | var operBreakImg = new Image();
198 | operBreakImg.src= 'imgs/design/result_break.gif';
199 | operBreakImg.width = 12;
200 | operBreakImg.height = 12;
201 | //控制点图片
202 | var mouseImg = new Image();
203 | mouseImg.src='imgs/design/mouse_add.png';
204 | mouseImg.width = 16;
205 | mouseImg.height = 16;
206 | //后续线图片(没有图片,是直接在画布上画的圆圈)
207 | var subseqImg = new Image();
208 | subseqImg.width = 12;
209 | subseqImg.height = 12;
210 | return {
211 | "act":actImg,
212 | "act_start":actStartImg,
213 | "act_auto":actAutoImg,
214 | "act_piall":actPiallImg,
215 | "act_seq":actSeqImg,
216 | "oper":operImg,
217 | "oper_auto":operAutoImg,
218 | "oper_break":operBreakImg,
219 | "mouse":mouseImg,
220 | "subseq":subseqImg
221 | }
222 |
223 |
224 | })();
225 |
226 | /**
227 | * 图形绘制器
228 | * @param canvasId 页面上的画布元素
229 | * @options 配置项.
230 | * @returns
231 | */
232 | function FlRenderer(canvasId,options){
233 | options = options || {};
234 |
235 | /**
236 | * 模型
237 | */
238 | var flowModle = {
239 | flowInfo:new FlowInfo({}),
240 | activities:[],/*活动*/
241 | operations:[],/*操作结果*/
242 | subsequents:[] /*操作结果*/
243 | };
244 |
245 | var originPoint = {x:0,y:0};//坐标系原点在画布上的位置
246 |
247 | /*
248 | * 选中的对象
249 | */
250 | var selected = [];
251 | var redMarked = null;//标红的对象
252 |
253 | var c = null;//画布元素.
254 |
255 | var maxDisplayindex = 0 ;//displayindex从0开始编号
256 |
257 | /**拖动模式:normal-正常模式,moving-移动模式(调整坐标系时) */
258 | //var dragMode = 'normal';
259 |
260 | c = document.getElementById(canvasId);
261 | var cxt = c.getContext("2d"); //绘图上下文.
262 |
263 | /**
264 | * 选中一个业务对象后需要触发的事件
265 | */
266 | var onSelect = function(bizObj){/*空函数*/};
267 |
268 | if(typeof(options.onSelect)=='function'){
269 | onSelect = options.onSelect;
270 | }
271 |
272 | //init();
273 | drawAll(cxt);
274 |
275 | var isMouseDown = false;//鼠标左键是否按下
276 | //鼠标拖动控制器,暂时不设定,等后面再设定.
277 | var defualtDragCtrl = null;//getDefaultDragCtrl(this);
278 | var dragCtrl = null;//defualtDragCtrl;
279 |
280 | //监听事件onclick
281 | $(c).click(function(){
282 | //看看鼠标落在哪个对象上。
283 | selected = [];
284 | //先看看有没有选择流程的基本信息
285 | var x = event.pageX-c.offsetLeft;
286 | var y = event.pageY-c.offsetTop;
287 | flowInfoView = flowModle.flowInfo.view;
288 | if(0<=x && x<=flowInfoView.width && 0<=y && y<=flowInfoView.height){
289 | selected.push(flowModle.flowInfo);
290 | }else{
291 | //获取鼠标的坐标(相对于画布的位置)。
292 | var cursorPos = getCursorPos(event,c);
293 | x = cursorPos.x;
294 | y = cursorPos.y;
295 | //console.log("x:"+x+" y:"+y );
296 | var obj = selectObj(x,y);
297 | if(obj && obj instanceof BussinessObj){
298 | selected.push(obj);
299 | }
300 | }
301 | drawAll(cxt);
302 | if(selected.length>0){
303 | //TODO obj 应当深拷贝后再传出去的。
304 | onSelect(selected[selected.length-1]);
305 | }else{
306 | onSelect(null);
307 | }
308 | });
309 |
310 | //处理右键
311 | //先把他禁用掉
312 | $(c).bind("contextmenu", function(){
313 | return false;
314 | });
315 | //再处理事件
316 | $(c).mouseup(function(e) {
317 | if(event.button == 2){//右键为2
318 | if(typeof(dragCtrl.rightClick)=='function'){
319 | var cursorPos = getCursorPos(event,c);
320 | var obj = selectObj(cursorPos.x,cursorPos.y);
321 | if(obj instanceof BussinessObj){
322 | dragCtrl.rightClick(obj);
323 | }
324 |
325 | }
326 | }
327 | });
328 |
329 | //监听鼠标移动事件
330 | $(c).mousemove(function(){
331 | if(!isMouseDown)
332 | return;
333 | //获取鼠标的坐标(相对于原点的位置)。
334 | var cursorPos = getCursorPos(event,c);
335 | //鼠标当前位置,(相对于画布的位置)。
336 | var absPos = getCursorAbsPos(event,c);
337 | //console.log("x:"+cursorPos.x+" y:"+cursorPos.y );
338 | if(preDragPos==null || preDragAbsPos == null){
339 | preDragPos = cursorPos;
340 | preDragAbsPos = absPos;
341 | }
342 | thisDragePos = cursorPos;
343 | thisAbsPos = absPos;
344 | dragCtrl.onDrag(dragedObj,preDragPos,thisDragePos,preDragAbsPos,thisAbsPos);
345 | drawAll(cxt);
346 | preDragPos = thisDragePos;
347 | preDragAbsPos = thisAbsPos;
348 | });
349 |
350 | var dragedObj = null;//被拖动的对象
351 | var preDragPos = null;//上次拖动的坐标(相对于原点)
352 | var preDragAbsPos = null;//上次拖动的坐标(相对于画布)
353 |
354 | //监听鼠标左键按下事件
355 | $(c).mousedown(function(){
356 | if(event.button == 0){//为0表示左键
357 | isMouseDown = true;
358 | //获取鼠标的当前位置
359 | var cursorPos = getCursorPos(event,c);
360 | var absPos = getCursorAbsPos(event,c);
361 | //看看有没有controlPoint被选中
362 | var obj = selectObj(cursorPos.x,cursorPos.y);
363 | if(obj){
364 | //console.log("onStartDrag obj:"+obj);
365 | dragedObj = obj;
366 | preDragPos = cursorPos;//getCursorPos(event,c);
367 | preDragAbsPos = absPos;
368 | dragCtrl.onStartDrag(obj);
369 | }
370 | }
371 | });
372 | //监听鼠标左键释放事件
373 | $(c).mouseup(function(){
374 | if(event.button == 0){
375 | isMouseDown = false;
376 | //有可能是拖动结束
377 | if(preDragPos!=null){
378 | //拖动结束
379 | dragCtrl.onEndDrag(dragedObj);
380 | preDragPos = null;
381 | preDragAbsPos = null;
382 | dragedObj = null;
383 | }
384 | redMarked = null;
385 | }
386 | });
387 |
388 | /**清空选中*/
389 | function _clearSelected(){
390 | selected=[];
391 | //需要触发onSelect事件,放在另一个线程中执行
392 | setTimeout(function(){onSelect(null);},0);
393 | }
394 |
395 | /**
396 | * 根据鼠标所选中的位置,判断哪个控件被选中了。
397 | */
398 | function selectObj(x,y){
399 | for(var i in flowModle.activities){
400 | view = flowModle.activities[i].view;
401 | //console.log("view.x:"+view.x+" view.y:"+view.y + " x:"+x+" y:"+y );
402 | if(view.xy1){
572 | y-=500;
573 | }
574 | y+=500
575 | while(y<=y2){
576 | if(yx1){
592 | x-=500;
593 | }
594 | x+=500
595 | while(x<=x2){
596 | if(x=3){//优先级大于2,则用双点划线
672 | cxt.setLineDash([10,4,2,4,2,4]);
673 | }
674 |
675 | if(subseq.model.activityId){//如果关联了一个活动
676 | //console.log("subseq.model.activityId:"+subseq.model.activityId);
677 | //查找对应的活动
678 | var act = selectActByActId(subseq.model.activityId);
679 | //绘制从圆圈到活动的线条。
680 | if(act){
681 | //act.view
682 | cxt.beginPath();
683 | cxt.lineWidth=0.5;
684 | cxt.strokeStyle='black';
685 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5);//由于像素精度问题所以每个坐标都要减0.5个像素
686 | cxt.lineTo(act.view.x+act.view.width/2-0.5,act.view.y+act.view.height/2-0.5);
687 | cxt.stroke();
688 | }
689 | }
690 | if(subseq.model.operationId){//如果关联了一个结果
691 | //console.log("subseq.model.activityId:"+subseq.model.operationId);
692 | //查找对应的结果
693 | var oper = selectOperByOperId(subseq.model.operationId);
694 | //绘制从圆圈到活动的结果。
695 | if(oper){
696 | //act.view
697 | cxt.beginPath();
698 | cxt.lineWidth=0.5;
699 | cxt.strokeStyle='black';
700 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5);
701 | cxt.lineTo(oper.view.x+oper.view.width/2-0.5,oper.view.y+oper.view.height/2-0.5);
702 | cxt.stroke();
703 | }
704 |
705 | }
706 | if(subseq.view.controlPoint){//存在控制点
707 | var controlPoint = subseq.view.controlPoint;
708 | //绘制连线到控制点
709 | cxt.beginPath();
710 | cxt.lineWidth=0.5;
711 | cxt.strokeStyle='black';
712 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5);
713 | cxt.lineTo(controlPoint.x-0.5,controlPoint.y-0.5);
714 | cxt.stroke();
715 | }
716 | if(subseq.view.controlPoint1){//存在控制点
717 | var controlPoint = subseq.view.controlPoint1;
718 | //绘制连线到控制点
719 | cxt.beginPath();
720 | cxt.lineWidth=0.5;
721 | cxt.strokeStyle='black';
722 | cxt.moveTo(view.x+view.width/2-0.5,view.y+view.height/2-0.5);
723 | cxt.lineTo(controlPoint.x-0.5,controlPoint.y-0.5,15);//15每一行的高度(字体高12个像素,在加上3个像素的行距。)
724 | cxt.stroke();
725 | }
726 | cxt.setLineDash([]);//绘制完后还原成实线。
727 | }
728 |
729 | /**
730 | * 绘制流程基本信息
731 | */
732 | function drawFlowInfo(cxt,obj){
733 | if(!(obj instanceof FlowInfo)){
734 | return ;//本函数仅处理FLowInfo
735 | }
736 | cxt.beginPath();
737 | cxt.lineWidth=1;
738 | cxt.fillStyle = '#bdf';
739 | cxt.strokeStyle='grey';
740 | cxt.rect(0.5,0.5,obj.view.width+0.5,obj.view.height+0.5);
741 | cxt.fill();
742 | cxt.stroke();
743 | //画文字
744 | cxt.fillStyle = 'black';
745 | cxt.font = "bold 14px songti";
746 | console.log(obj.model.displayName);
747 | if(obj.model.displayName){//不至于在页面上显示undefind
748 | cxt.textAlign="center";
749 | cxt.textBaseline="middle";
750 | _fillTextInRect(cxt,obj.model.displayName, 0,0,obj.view.width, obj.view.height);//12是字体的高度
751 | cxt.textAlign="start";//恢复成默认值
752 | cxt.textBaseline="alphabetic";//恢复成默认值
753 | }
754 | //是否被选中
755 | if(selected.indexOf(obj)>=0){
756 | //选中则要绘制一下
757 | cxt.beginPath();
758 | cxt.lineWidth=1;
759 | cxt.strokeStyle='green';
760 | cxt.rect(0,0,obj.view.width+1,obj.view.height+1);
761 | cxt.stroke();
762 | }
763 | }
764 |
765 | function _fillTextInRect(cxt,text,x1,y1,x2,y2,lineH){
766 | var dimension = cxt.measureText(text);
767 | var allLength = dimension.width;
768 | if(allLength<(x2-x1)){
769 | //单行文本
770 | cxt.fillText(text, (x1+x2)/2, (y1+y2)/2);
771 | return
772 | }
773 | //否则字符超超长需要换行
774 | var widthPorChar = Math.ceil(allLength/text.length);//每个字符的宽度.
775 | var lineH = lineH||14;//每一行的高度()
776 | var charsPorLine = Math.floor(((x2-x1)/widthPorChar));//每行能容纳的文字数.
777 | //先计算一下总共能容纳多少文字
778 | var charCapacity = Math.floor((y2-y1)/lineH)*charsPorLine;
779 | if(text.lengt>charCapacity){
780 | text = text.substr(0,charCapacity-2)+'...';
781 | }
782 | //文字换行切割
783 | var texts = [];
784 | while(text.length>charsPorLine){
785 | texts.push(text.substr(0,charsPorLine));
786 | text = text.substr(charsPorLine);
787 | }
788 | texts.push(text);
789 | var lines = texts.length;//行数
790 | console.log("lines:"+lines);
791 | var startY = (y1+y2)/2;
792 | if(lines%2==1){//奇数行
793 | startY -= lineH*Math.floor(lines/2);
794 | }else{//偶数行
795 | startY -= lineH*(Math.floor(lines/2)-0.5);
796 | }
797 | var y=startY;
798 | console.log("yyyyyy:"+y);
799 | for(var i in texts){
800 | cxt.fillText(texts[i], (x1+x2)/2, y);
801 | y+=lineH;
802 | console.log("yyyyyy:"+y);
803 | }
804 |
805 | }
806 |
807 | /**
808 | * 绘制一个业务对象
809 | */
810 | function drawBizObj(cxt,obj){
811 | if(obj instanceof Act){
812 | drawActivity(cxt,obj);
813 | }else if(obj instanceof Oper){
814 | drawOperation(cxt,obj);
815 | }else if(obj instanceof Subsequent){
816 | drawSubsequent(cxt,obj);
817 | }
818 | }
819 |
820 | /**
821 | * 绘制一个活动
822 | */
823 | function drawActivity(cxt,act){
824 | //console.log("act.model:"+act.model);
825 | //绘制活动的名称
826 | //console.log("act.model.displayName:"+act.model.displayName);
827 | if(act.model.displayName){
828 | cxt.fillStyle = 'black';
829 | cxt.font = "bold 14px songti";
830 | var textLeft = act.view.x+(act.view.width-act.model.displayName.length*14)/2 //14是字体的宽度。
831 | //console.log("act.model.displayName:"+act.model.displayName+" textLeft:"+textLeft+" act.view.y-8"+(act.view.y-8));
832 | cxt.fillText(act.model.displayName,textLeft,act.view.y-8);//文字写在图像上方8个像素点处。
833 | }
834 | var icon = icons['act'];
835 | if(act.model.activityBz=='1'){
836 | icon = icons['act_start'];
837 | }else if(act.model.activityBz=='2'){
838 | icon = icons['act_auto'];
839 | }else if(act.model.activityType=='03'){
840 | icon = icons['act_piall'];
841 | }else if(act.model.activityType=='02'){
842 | icon = icons['act_seq'];
843 | }
844 | cxt.drawImage(icon,act.view.x,act.view.y);
845 | }
846 | /**
847 | * 绘制一个结果线
848 | */
849 | function drawOperation(cxt,oper){
850 | var view = oper.view;
851 | var icon = icons['oper'];
852 | if(oper.model.resultFlag=='1'){
853 | icon = icons['oper_break'];
854 | }else if(oper.model.autoFinish=='1'){
855 | icon = icons['oper_auto'];
856 | }
857 | cxt.drawImage(icon,oper.view.x,oper.view.y);
858 | //如果关联了一个活动
859 | //console.log("oper.model.activityId:"+oper.model.activityId);
860 | if(oper.model.activityId){
861 | console.log("oper.model.activityId:"+oper.model.activityId);
862 | //do nothing.
863 | }else if(oper.view.controlPoint){//存在控制点
864 | //在控制点处绘制一个鼠标。
865 | var mouseLeft = oper.view.controlPoint.x - Math.floor(icons['mouse'].width/2);
866 | var mouseTop = oper.view.controlPoint.y - Math.floor(icons['mouse'].height/2);
867 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop);
868 | }
869 | cxt.fillStyle = 'black';
870 | cxt.font = "12px songti";
871 | var textLeft = oper.view.x+Math.floor((oper.view.width-oper.model.displayName.length*12)/2); //12是字体的宽度
872 | cxt.fillText(oper.model.displayName,textLeft,oper.view.y+oper.view.height+12);//12是字体的高度
873 | }
874 | /**
875 | * 绘制一个后续线.
876 | */
877 | function drawSubsequent(ctx,subseq){
878 | //后续线的中心点上绘制一个圆圈
879 | //先计算圆形的中心
880 | var x = subseq.view.x + Math.floor(subseq.view.width/2);
881 | var y = subseq.view.y + Math.floor(subseq.view.height/2);
882 | //半径是宽度的1/4
883 | var r = Math.floor(subseq.view.width/4);
884 | //console.log('arc: x:'+x+" y:"+y+ " r:"+r);
885 | //开始绘制
886 | ctx.beginPath();
887 | //设置弧线的颜色为灰色
888 | ctx.lineWidth="0.5";
889 | ctx.strokeStyle = "black";
890 | ctx.arc(x, y, r, 0, 2*Math.PI);
891 | ctx.closePath();
892 | ctx.fillStyle = "white";
893 | ctx.fill();
894 | ctx.stroke();
895 | //绘制控制点
896 | var controlPoint = subseq.view.controlPoint;
897 | if(controlPoint){
898 | var mouseLeft = controlPoint.x - Math.floor(icons['mouse'].width/2);
899 | var mouseTop = controlPoint.y - Math.floor(icons['mouse'].height/2);
900 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop);
901 | }
902 | var controlPoint = subseq.view.controlPoint1;
903 | if(controlPoint){
904 | var mouseLeft = controlPoint.x - Math.floor(icons['mouse'].width/2);
905 | var mouseTop = controlPoint.y - Math.floor(icons['mouse'].height/2);
906 | cxt.drawImage(icons['mouse'],mouseLeft,mouseTop);
907 | }
908 | }
909 | /**
910 | * 绘制选中的元素
911 | */
912 | function drawSelect(ctx){
913 | for(var i in selected){
914 | var view = selected[i].view;
915 | if(selected[i] instanceof FlowInfo){
916 | continue;//FlowInfo 另行处理
917 | }
918 | //console.log("draw selected.");
919 | ctx.beginPath();
920 | ctx.lineWidth="1";
921 | ctx.strokeStyle="green";
922 | ctx.rect(view.x,view.y,view.width,view.height);
923 | ctx.stroke();
924 | }
925 | }
926 |
927 | function drawReadMarked(ctx){
928 | if(redMarked){
929 | var view = redMarked.view;
930 | //console.log("draw red mark.");
931 | ctx.beginPath();
932 | ctx.lineWidth="1";
933 | ctx.strokeStyle="red";
934 | ctx.rect(view.x,view.y,view.width,view.height);
935 | ctx.stroke();
936 | }
937 | }
938 |
939 | /**
940 | * 获取鼠标的位置,考虑坐标系
941 | * @param event 事件
942 | * @param canvase 元素
943 | * @returns {x:x,y:y}
944 | */
945 | function getCursorPos(event,c){
946 | var x = event.pageX-c.offsetLeft;
947 | var y = event.pageY-c.offsetTop;
948 | //按原点位置调整坐标系
949 | x+=originPoint.x;
950 | y+=originPoint.y;
951 | return {x:x,y:y};
952 | }
953 |
954 | /**获取鼠标的位置,不考虑坐标系*/
955 | function getCursorAbsPos(event,c){
956 | var x = event.pageX-c.offsetLeft;
957 | var y = event.pageY-c.offsetTop;
958 | return {x:x,y:y};
959 | }
960 |
961 | /**
962 | * 获取整个图形的边界
963 | */
964 | function getBound(){
965 | var maxX = null;
966 | var minX = null;
967 | var maxY = null;
968 | var minY = null;
969 |
970 | for(var i in flowModle.activities){
971 | var x=flowModle.activities[i].view.x;
972 | var y=flowModle.activities[i].view.y;
973 | if(maxX==null){
974 | maxX = x;
975 | }else{
976 | maxX = Math.max(maxX,x);
977 | }
978 | if(minX==null){
979 | minX = x;
980 | }else{
981 | minX = Math.min(minX,x);
982 | }
983 | if(maxY==null){
984 | maxY = y;
985 | }else{
986 | maxY = Math.max(maxY,y);
987 | }
988 | if(minY==null){
989 | minY = y;
990 | }else{
991 | minY = Math.min(minY,y);
992 | }
993 | }
994 |
995 | for(var i in flowModle.operations){
996 | var x=flowModle.operations[i].view.x;
997 | var y=flowModle.operations[i].view.y;
998 | if(maxX==null){
999 | maxX = x;
1000 | }else{
1001 | maxX = Math.max(maxX,x);
1002 | }
1003 | if(minX==null){
1004 | minX = x;
1005 | }else{
1006 | minX = Math.min(minX,x);
1007 | }
1008 | if(maxY==null){
1009 | maxY = y;
1010 | }else{
1011 | maxY = Math.max(maxY,y);
1012 | }
1013 | if(minY==null){
1014 | minY = y;
1015 | }else{
1016 | minY = Math.min(minY,y);
1017 | }
1018 | }
1019 |
1020 | for(var i in flowModle.subsequents){
1021 | var x=flowModle.subsequents[i].view.x;
1022 | var y=flowModle.subsequents[i].view.y;
1023 | if(maxX==null){
1024 | maxX = x;
1025 | }else{
1026 | maxX = Math.max(maxX,x);
1027 | }
1028 | if(minX==null){
1029 | minX = x;
1030 | }else{
1031 | minX = Math.min(minX,x);
1032 | }
1033 | if(maxY==null){
1034 | maxY = y;
1035 | }else{
1036 | maxY = Math.max(maxY,y);
1037 | }
1038 | if(minY==null){
1039 | minY = y;
1040 | }else{
1041 | minY = Math.min(minY,y);
1042 | }
1043 | }
1044 |
1045 | if(maxX==null || minX==null || maxY==null || minY==null ){
1046 | //只要有一个为空则无需处理坐标系
1047 | return;
1048 | }
1049 | return {maxX:maxX,minX:minX,maxY:maxY,minY:minY};
1050 | }
1051 |
1052 | /**
1053 | * 使整个流程图居中
1054 | */
1055 | function _makeCenter(){
1056 | var bound = getBound();
1057 | var maxX = bound.maxX;
1058 | var minX = bound.minX;
1059 | var maxY = bound.maxY;
1060 | var minY = bound.minY;
1061 |
1062 | //获得了模型的中心点
1063 | var centerX = (minX+maxX)/2;
1064 | var centerY = (minY+maxY)/2;
1065 | console.log("centerX:"+centerX);
1066 | console.log("centerY:"+centerY);
1067 | console.log("c.height:"+c.height);
1068 | console.log("c.height/2:"+(c.height/2));
1069 | //新的原点
1070 | var x = Math.floor(centerX-c.width/2+0.5);//0.5的目的是为了四舍五入
1071 | var y = Math.floor(centerY-c.height/2+0.5);
1072 | console.log("x:"+x);
1073 | console.log("y:"+y);
1074 | originPoint.x=x;
1075 | originPoint.y=y;
1076 | drawAll(cxt);
1077 | }
1078 |
1079 | /**当业务对象的属性发生变化时要处理的事情 */
1080 | function _onValueChange(obj,prop,beforValue,value){
1081 | if(obj instanceof Act){
1082 | if(prop=='activityId' && beforValue){
1083 | obj.model.baseId = value;
1084 | var opers = selectOpersByActId(beforValue);
1085 | for(var i in opers){
1086 | opers[i].model.activityId = value;
1087 | //如果activityId被改成空了就要把控制点恢复
1088 | if(!value){
1089 | resetControlPoint(opers[i]);
1090 | }
1091 | }
1092 | var subseqs = selectSubseqByActId(beforValue);
1093 | for(var i in subseqs){
1094 | subseqs[i].model.activityId = value;
1095 | //如果activityId被改成空了就要把控制点恢复
1096 | if(!value){
1097 | resetControlPoint(subseqs[i]);
1098 | }
1099 | }
1100 | }
1101 | }else if(obj instanceof Oper){
1102 | if(prop=='operationId' && beforValue){
1103 | obj.model.baseId = value;
1104 | var subseqs = selectSubseqByOperId(beforValue);
1105 | for(var i in subseqs){
1106 | subseqs[i].model.operationId = value;
1107 | //如果operationId被改成空了就要把控制点恢复
1108 | if(!value){
1109 | var controlPoint = new ControlPoint(0,0);//坐标先随便设一个
1110 | controlPoint.parent = subseqs[i];//父对象就是其业务对象。
1111 | controlPoint.parentType = 'subseq';
1112 | if(!subseqs[i].view.controlPoint){
1113 | subseqs[i].view.controlPoint = controlPoint;
1114 | }else if(!subseqs[i].view.controlPoint1){
1115 | subseqs[i].view.controlPoint1 = controlPoint;
1116 | }
1117 | resetControlPoint(subseqs[i]);
1118 | }
1119 | }
1120 | }
1121 | }
1122 | }
1123 |
1124 | /**(级联)删除一个业务对象*/
1125 | function _deleteObj(obj){
1126 | if(obj instanceof Act ){
1127 | _deleteAct(obj);
1128 | }else if(obj instanceof Oper){
1129 | _deleteOper(obj)
1130 | }else if(obj instanceof Subsequent){
1131 | _deleteSubseq(obj)
1132 | }
1133 | }
1134 |
1135 | /**(级联)删除一个业务对象*/
1136 | function _deleteAct(act){
1137 | var index = flowModle.activities.indexOf(act);
1138 | if(index>=0){
1139 | flowModle.activities.splice(index,1);
1140 | }
1141 | //查一下有没有子对象,有则把它删除掉.
1142 | if(act.model.activityId){
1143 | var opers = selectOpersByActId(act.model.activityId);
1144 | for(var i in opers){
1145 | _deleteOper(opers[i]);
1146 | }
1147 | var subseqs = selectSubseqByActId(act.model.activityId);
1148 | for(var i in subseqs){
1149 | _deleteSubseq(subseqs[i]);
1150 | }
1151 | }
1152 | }
1153 |
1154 | /**(级联)删除一个业务对象*/
1155 | function _deleteOper(oper){
1156 | var index = flowModle.operations.indexOf(oper);
1157 | if(index>=0){
1158 | flowModle.operations.splice(index,1);
1159 | }
1160 | //查一下有没有子对象,有则把它删除掉.
1161 | if(oper.model.operationId){
1162 | var subseqs = selectSubseqByOperId(oper.model.operationId);
1163 | for(var i in subseqs){
1164 | _deleteSubseq(subseqs[i]);
1165 | }
1166 | }
1167 | }
1168 |
1169 | /**删除一个业务对象*/
1170 | function _deleteSubseq(subseq){
1171 | var index = flowModle.subsequents.indexOf(subseq);
1172 | if(index>=0){
1173 | flowModle.subsequents.splice(index,1);
1174 | }
1175 | }
1176 |
1177 | /**某字段是否存在重复*/
1178 | function _isRepeate(obj,prop,value){
1179 | if(obj instanceof Act){
1180 | for(var i in flowModle.activities){
1181 | var another =flowModle.activities[i];
1182 | if(another===obj){
1183 | continue;
1184 | }
1185 | var model = another.model;
1186 | if(model[prop]==value){
1187 | return true;
1188 | }
1189 | }
1190 | }else if(obj instanceof Oper){
1191 | for(var i in flowModle.operations){
1192 | var another =flowModle.operations[i];
1193 | if(another===obj){
1194 | continue;
1195 | }
1196 | var model = another.model;
1197 | if(model[prop]==value){
1198 | return true;
1199 | }
1200 | }
1201 | }
1202 | return false;
1203 | }
1204 |
1205 | /**把整个流程图转成一个图片,base64方式输出*/
1206 | function _getImgData(){
1207 | //记录下当前的画布大小,坐标系等。
1208 | var orgSize = {width:c.width,height:c.height} ;
1209 | var orgOPoint = {x:originPoint.x,y:originPoint.y};
1210 | //调整画布大小
1211 | var bound = getBound();
1212 | c.width=(bound.maxX-bound.minX+100)>orgSize.width?(bound.maxX-bound.minX+100):orgSize.width;//100是指留100个像素的空白边
1213 | c.height=(bound.maxY-bound.minY+100)>orgSize.height?(bound.maxY-bound.minY+100):orgSize.height;//100是指留100个像素的空白边
1214 | //居中显示
1215 | _makeCenter();
1216 | //把流程图转成base64.
1217 | var imgData = c.toDataURL("image/png");
1218 | console.log("imgData:"+imgData);
1219 | //还原画布大小,坐标系等。
1220 | c.width = orgSize.width;
1221 | c.height = orgSize.height;
1222 | originPoint.x = orgOPoint.x;
1223 | originPoint.y = orgOPoint.y;
1224 | //重新绘制
1225 | drawAll(cxt);
1226 |
1227 | return imgData;
1228 | }
1229 |
1230 |
1231 | //暴露出去一个对象
1232 | var exportObj = {
1233 | /**加载一个模型*/
1234 | loadModel:function(modelJson){
1235 | //先清空模型
1236 | flowModle.flowInfo={};
1237 | flowModle.activities = [];
1238 | flowModle.operations = [];
1239 | flowModle.subsequents = [];
1240 | _clearSelected();
1241 | //基本信息
1242 | console.log("displayName:"+modelJson.flowInfo.displayName);
1243 | flowModle.flowInfo = new FlowInfo(modelJson.flowInfo);
1244 | flowModle.flowInfo.view.width = 84;
1245 | flowModle.flowInfo.view.height = 60;
1246 | for(var i in modelJson.activities){
1247 | var act = new Act(modelJson.activities[i]);
1248 | if(act.view.displayindex){
1249 | maxDisplayindex = Math.max(maxDisplayindex,act.view.displayindex);
1250 | }else{
1251 | act.view.displayindex = ++maxDisplayindex;
1252 | }
1253 | //设置宽度和高度.
1254 | act.view.width = icons['act'].width;
1255 | act.view.height = icons['act'].height;
1256 | flowModle.activities.push(act);
1257 | console.log('加载了一个Act');
1258 | }
1259 | for(var i in modelJson.operations){
1260 | var oper = new Oper(modelJson.operations[i]);
1261 | if(oper.view.displayindex){
1262 | maxDisplayindex = Math.max(maxDisplayindex,oper.view.displayindex);
1263 | }else{
1264 | oper.view.displayindex = ++maxDisplayindex;
1265 | }
1266 | //设置宽度和高度.
1267 | oper.view.width = icons['oper'].width;
1268 | oper.view.height = icons['oper'].height;
1269 | flowModle.operations.push(oper);
1270 | }
1271 | for(var i in modelJson.subsequents){
1272 | var subseq = new Subsequent(modelJson.subsequents[i]);
1273 | if(subseq.view.displayindex){
1274 | maxDisplayindex = Math.max(maxDisplayindex,oper.view.displayindex);
1275 | }else{
1276 | subseq.view.displayindex = ++maxDisplayindex;
1277 | }
1278 | //设置宽度和高度.
1279 | subseq.view.width = icons['subseq'].width;
1280 | subseq.view.height = icons['subseq'].height;
1281 | flowModle.subsequents.push(subseq);
1282 | }
1283 | //加载成功后默认选中流程基本信息
1284 | selected=[flowModle.flowInfo];
1285 | setTimeout(function(){onSelect(flowModle.flowInfo);},0)//触发回调函数
1286 | //加载完后渲染一下。放到另外一个线程去渲染,以保证图像已加载完成。由于浏览器加载图片是异步的,可能需要花较长时间,所以给他200毫秒去加载
1287 | setTimeout(function(){console.log('开始绘图');drawAll(cxt);},200);
1288 | },
1289 | /**向模型中增加一个Act*/
1290 | addAct:function(actJson){
1291 | var act = new Act(actJson);
1292 | act.view.displayindex=++maxDisplayindex;
1293 | //设置宽度和高度.
1294 | act.view.width = icons['act'].width;
1295 | act.view.height = icons['act'].height;
1296 | flowModle.activities.push(act);
1297 | //新添加的对象设置为选中
1298 | selected = [act];
1299 | onSelect(act);
1300 | drawAll(cxt);
1301 | },
1302 | /**向模型中增加一个Oper*/
1303 | addOper:function(operJson){
1304 | var oper = new Oper(operJson);
1305 | oper.view.displayindex=++maxDisplayindex;
1306 | //设置宽度和高度.
1307 | oper.view.width = icons['oper'].width;
1308 | oper.view.height = icons['oper'].height;
1309 | flowModle.operations.push(oper);
1310 | //新添加的对象设置为选中
1311 | selected = [oper];
1312 | onSelect(oper);
1313 | drawAll(cxt);
1314 | },
1315 | addSubseq:function(subseqJson){
1316 | var subseq = new Subsequent(subseqJson);
1317 | //设置宽度和高度.
1318 | subseq.view.width = icons['subseq'].width;
1319 | subseq.view.height = icons['subseq'].height;
1320 | flowModle.subsequents.push(subseq);
1321 | //新添加的对象设置为选中
1322 | selected = [subseq];
1323 | onSelect(subseq);
1324 | drawAll(cxt);
1325 | },
1326 | /**获取画布中心点的坐标*/
1327 | getCenter:function(){
1328 | var cwidth = $(c).attr('width').replace('px','');
1329 | var cheight = $(c).attr('height').replace('px','');
1330 | var x = Math.floor((cwidth)/2);
1331 | var y = Math.floor((cheight)/2);
1332 | //按坐标系调整
1333 | x = x + originPoint.x;
1334 | y = y + originPoint.y;
1335 | return {x:x,y:y};
1336 | },
1337 | /**标红需要暴露出去*/
1338 | getRedMarked:function(){
1339 | return redMarked;
1340 | },
1341 | setRedMarked:function(rm){
1342 | redMarked=rm;
1343 | },
1344 | /**把流程模型暴露出去*/
1345 | getFlowModle:function(){
1346 | //TODO : 应当深拷贝后再报露出去.
1347 | return flowModle;
1348 | },
1349 | /**移动坐标系*/
1350 | moveOriginPoint:function(dx,dy){
1351 | originPoint.x-=dx;
1352 | originPoint.y-=dy;
1353 | },
1354 | /**设置鼠标移动控制器*/
1355 | setDragCtrl:function(ctrl){
1356 | if(ctrl)
1357 | dragCtrl = ctrl;
1358 | },
1359 | /**将鼠标控制器复原成默认*/
1360 | resetDragCtrl:function(){
1361 | dragCtrl = defualtDragCtrl;
1362 | },
1363 | /**使整个流程图居中显示*/
1364 | makeCenter:function(){
1365 | _makeCenter();
1366 | },
1367 | /**给业务对象的属性设值*/
1368 | setVal:function(prop,value){
1369 | //先找到选中的业务对象
1370 | if(selected.length==0){
1371 | return;
1372 | }
1373 | var obj = selected[selected.length-1];
1374 | var model = obj.model;
1375 | var beforeValue = model[prop];
1376 | model[prop]=value;
1377 | _onValueChange(obj,prop,beforeValue,value);
1378 | //属性变了有可能影响图形外观
1379 | drawAll(cxt);
1380 | },
1381 | /**删除一个选中的业务对象(同时级联删除他关联到的子对象)*/
1382 | deleteSelected:function(){
1383 | for(var i in selected){
1384 | _deleteObj(selected[i]);
1385 | }
1386 | //删除后清空selected
1387 | _clearSelected();
1388 | //重绘一下
1389 | drawAll(cxt);
1390 | },
1391 | /**判断某字段是否重复*/
1392 | isRepeate:function(prop,value){
1393 | if(selected.length==0){
1394 | return false;
1395 | }
1396 | var obj = selected[selected.length-1];
1397 | return _isRepeate(obj,prop,value);
1398 | },
1399 | /**重新设置选中框里的内容*/
1400 | resetSelected:function(obj){
1401 | //把选中框清空,然后把Obj放进去
1402 | selected = [];
1403 | if(obj && obj instanceof BussinessObj){
1404 | selected.push(obj);
1405 | }
1406 | //重绘一下
1407 | drawAll(cxt);
1408 | onSelect(obj);//触发一下相关事件
1409 | },
1410 | /**断开连接与活动的连接*/
1411 | disconWithAct:function(){
1412 | //先找到选中的业务对象
1413 | if(selected.length==0){
1414 | return;
1415 | }
1416 | var obj = selected[selected.length-1];
1417 | obj.model.activityId = '';
1418 | resetControlPoint(obj);
1419 | //重绘一下
1420 | drawAll(cxt);
1421 | },
1422 | /**断开连接与结果的连接*/
1423 | disconWithOper:function(){
1424 | //先找到选中的业务对象
1425 | if(selected.length==0){
1426 | return;
1427 | }
1428 | var obj = selected[selected.length-1];
1429 | obj.model.operationId = '';
1430 | resetControlPoint(obj);
1431 | //重绘一下
1432 | drawAll(cxt);
1433 | },
1434 | /**重新绘制*/
1435 | redraw:function(){
1436 | drawAll(cxt);
1437 | },
1438 | getImgData:function(){
1439 | return _getImgData();
1440 | }
1441 | };
1442 | //设定鼠标拖动控制器
1443 | defualtDragCtrl = getDefaultDragCtrl(exportObj);
1444 | dragCtrl = defualtDragCtrl;
1445 | return exportObj;
1446 | }
1447 |
1448 |
1449 | /**
1450 | * 显示错误信息给用户
1451 | * 如果不满意显示效果可以另写一个函数把它覆盖掉。
1452 | * @returns
1453 | */
1454 | function showErrMsg(msg){
1455 | alert(msg);
1456 | }
1457 |
--------------------------------------------------------------------------------