Преглед на файлове

Merge branch 'master' of http://192.168.1.220:10080/esb/esb

Airhead преди 8 години
родител
ревизия
9625990361
променени са 81 файла, в които са добавени 3798 реда и са изтрити 4900 реда
  1. 0 5
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/configuration/ArbiterServerConfiguration.java
  2. 0 2
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/listener/ApplicationStartListener.java
  3. 1 1
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/routers/SerivceHealthRouter.java
  4. 0 9
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/ArbiterServerService.java
  5. 1 1
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/BrokerServerService.java
  6. 5 0
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/EndpointService.java
  7. 1 1
      hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/ServiceFlowService.java
  8. 0 5
      hos-arbiter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
  9. 2 2
      hos-arbiter/src/main/resources/application.yml
  10. 1 1
      hos-broker/pom.xml
  11. 32 0
      hos-broker/src/main/java/com/yihu/hos/broker/common/processor/AggregateProcessor.java
  12. 31 0
      hos-broker/src/main/java/com/yihu/hos/broker/common/processor/DefaultHttpProcessor.java
  13. 18 0
      hos-broker/src/main/java/com/yihu/hos/broker/common/processor/HttpProcessor.java
  14. 19 0
      hos-broker/src/main/java/com/yihu/hos/broker/util/Aggregate.java
  15. 1 1
      hos-camel/src/main/java/crawler/Split.java
  16. 1 1
      hos-broker/src/main/resources/application.yml
  17. 32 0
      hos-camel/src/main/java/com/yihu/hos/broker/common/processor/AggregateProcessor.java
  18. 31 0
      hos-camel/src/main/java/com/yihu/hos/broker/common/processor/DefaultHttpProcessor.java
  19. 18 0
      hos-camel/src/main/java/com/yihu/hos/broker/common/processor/HttpProcessor.java
  20. 1 1
      hos-camel/src/main/java/crawler/Aggregate.java
  21. 11 0
      hos-camel/src/main/java/com/yihu/hos/broker/util/Split.java
  22. 0 18
      hos-camel/src/main/java/crawler/processor/Processor0.java
  23. 0 16
      hos-camel/src/main/java/crawler/processor/Processor1.java
  24. 0 24
      hos-camel/src/main/java/crawler/processor/Processor2.java
  25. 2 2
      hos-camel/src/main/java/crawler/route/CrawlerQuartzRoute.java
  26. 5 5
      hos-camel/src/main/java/crawler/route/CrawlerRouteBulider.java
  27. 2 2
      hos-camel/src/main/java/crawler/route/QuartzRoute.java
  28. 6 6
      hos-camel/src/main/java/crawler/route/RouteBulider1.java
  29. 14 27
      src/main/java/com/yihu/hos/common/graph/BFSGraph.java
  30. 1 1
      src/main/java/com/yihu/hos/common/graph/DGraph.java
  31. 26 7
      src/main/java/com/yihu/hos/system/controller/ProcessController.java
  32. 8 0
      src/main/java/com/yihu/hos/system/dao/FlowProcessDao.java
  33. 18 0
      src/main/java/com/yihu/hos/system/model/ProcessResultModel.java
  34. 14 5
      src/main/java/com/yihu/hos/system/model/SystemServiceFlowProcess.java
  35. 54 0
      src/main/java/com/yihu/hos/system/service/FlowManager.java
  36. 211 0
      src/main/java/com/yihu/hos/system/service/ProcessEditor.java
  37. 101 190
      src/main/java/com/yihu/hos/system/service/ProcessManager.java
  38. 8 3
      src/main/resources/resource/SystemServiceFlowProcess.hbm.xml
  39. 35 35
      src/main/webapp/WEB-INF/ehr/jsp/common/indexJs.jsp
  40. 2 2
      src/main/webapp/WEB-INF/ehr/jsp/system/app/appJs.jsp
  41. 4 1
      src/main/webapp/WEB-INF/ehr/jsp/system/flow/flowJs.jsp
  42. 15 5
      src/main/webapp/WEB-INF/ehr/jsp/system/process/process.jsp
  43. 12 43
      src/main/webapp/WEB-INF/ehr/jsp/system/process/processJs.jsp
  44. 0 102
      src/main/webapp/develop/lib/gooflow/GooFunc.js
  45. 734 0
      src/main/webapp/develop/lib/gooflow/css/GooFlow.css
  46. 0 19
      src/main/webapp/develop/lib/gooflow/default.css
  47. BIN
      src/main/webapp/develop/lib/gooflow/goo/GooFlow_line_oper.png
  48. BIN
      src/main/webapp/develop/lib/gooflow/goo/Thumbs.db
  49. BIN
      src/main/webapp/develop/lib/gooflow/goo/bullet_blue.png
  50. 0 1
      src/main/webapp/develop/lib/gooflow/goo/child.js
  51. 0 138
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.css
  52. 0 135
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.css.bak
  53. 0 2000
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.js
  54. 0 1915
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.js.bak
  55. 0 131
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow2.css
  56. 0 16
      src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow_color.js
  57. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/Thumbs.db
  58. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_bg.png
  59. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank.gif
  60. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank2.gif
  61. 0 12
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank2.htm
  62. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_btn_bg.png
  63. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_icon.png
  64. BIN
      src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_icon2.png
  65. 0 1
      src/main/webapp/develop/lib/gooflow/goo/data.js
  66. BIN
      src/main/webapp/develop/lib/gooflow/goo/ui-icons_222222_256x240.png
  67. BIN
      src/main/webapp/develop/lib/gooflow/goo/未命名-3 - 副本.png
  68. BIN
      src/main/webapp/develop/lib/gooflow/goo/未命名-3.png
  69. 0 0
      src/main/webapp/develop/lib/gooflow/img/GooFlow_line_oper.png
  70. BIN
      src/main/webapp/develop/lib/gooflow/img/arrow.png
  71. 0 0
      src/main/webapp/develop/lib/gooflow/img/gooflow_bullet.png
  72. BIN
      src/main/webapp/develop/lib/gooflow/img/gooflow_icon.png
  73. 0 0
      src/main/webapp/develop/lib/gooflow/img/gooflow_tip.png
  74. BIN
      src/main/webapp/develop/lib/gooflow/img/sprite.head-tool.png
  75. BIN
      src/main/webapp/develop/lib/gooflow/img/sprite.tool.png
  76. BIN
      src/main/webapp/develop/lib/gooflow/img/sprite.work-are.png
  77. 0 2
      src/main/webapp/develop/lib/gooflow/jquery.min.js
  78. 2094 0
      src/main/webapp/develop/lib/gooflow/js/GooFlow.js
  79. 4 0
      src/main/webapp/develop/lib/gooflow/js/jquery.min.js
  80. 0 6
      src/main/webapp/develop/lib/gooflow/json2.js
  81. 222 0
      src/main/webapp/develop/lib/gooflow/test.json

+ 0 - 5
hos-arbiter/src/main/java/com/yihu/hos/arbiter/configuration/ArbiterServerConfiguration.java

@ -15,8 +15,6 @@ import java.io.IOException;
public class ArbiterServerConfiguration {
    @Value("${arbiter.central.url}")
    private String centralUrl;
    @Value("${arbiter.terminal.url}")
    private String terminalUrl;
    @Value("${arbiter.tenant.name}")
    private String tenant;
@ -28,9 +26,6 @@ public class ArbiterServerConfiguration {
        return centralUrl;
    }
    public String getTerminalUrl() {
        return terminalUrl;
    }
    public String getTenant() {
        return tenant;

+ 0 - 2
hos-arbiter/src/main/java/com/yihu/hos/arbiter/listener/ApplicationStartListener.java

@ -6,9 +6,7 @@ import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent> {
    private static Logger logger = LogManager.getLogger(ApplicationStartListener.class);

+ 1 - 1
hos-arbiter/src/main/java/com/yihu/hos/arbiter/routers/SerivceHealthRouter.java

@ -6,7 +6,7 @@ import org.springframework.stereotype.Component;
/**
 * @created Airhead 2016/8/1.
 */
@Component
//@Component
public class SerivceHealthRouter extends RouteBuilder {
    @Override
    public void configure() throws Exception {

+ 0 - 9
hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/ArbiterServerService.java

@ -35,15 +35,6 @@ public class ArbiterServerService {
        this.configuration = configuration;
    }
    public void start() {
        ArbiterServer arbiterServer = new ArbiterServer();
        arbiterServer.setTenant(configuration.getTenant());
        arbiterServer.setUrl(configuration.getTerminalUrl());
        this.save(arbiterServer);
    }
    public void save(ArbiterServer arbiterServer) {
        Query query = new Query();
        query.addCriteria(Criteria.where("tenant").is(arbiterServer.getTenant()));

+ 1 - 1
hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/BrokerServerService.java

@ -64,7 +64,7 @@ public class BrokerServerService {
        WriteResult writeResult = mongoOperations.upsert(query, update, BrokerServer.class);
        if (writeResult.isUpdateOfExisting()) {
            //避免Broker重启的情况
            HTTPResponse response = HttpClientKit.post(brokerServer.getURL() + "/esb/heartbeat");
            HTTPResponse response = HttpClientKit.get(brokerServer.getURL() + "/esb/heartbeat");
            if (response.getStatusCode() == 200 && brokerServer.isRegistered()) {
                return;
            }

+ 5 - 0
hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/EndpointService.java

@ -1,6 +1,7 @@
package com.yihu.hos.arbiter.services;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.core.http.HTTPResponse;
import com.yihu.hos.core.http.HttpClientKit;
import com.yihu.hos.web.framework.model.bo.Endpoint;
@ -102,6 +103,10 @@ public class EndpointService {
     */
    private void remoteCheck(Endpoint endpoint) {
        String url = endpoint.getHealthCheckURL();
        if (StringUtil.isEmpty(url)) {
            return;
        }
        HTTPResponse response = HttpClientKit.get(url);
        if (response.getStatusCode() == 200) {
            return;

+ 1 - 1
hos-arbiter/src/main/java/com/yihu/hos/arbiter/services/ServiceFlowService.java

@ -321,7 +321,7 @@ public class ServiceFlowService {
                BrokerServer brokerServer = objectMapper.readValue(msg, BrokerServer.class);
                String serviceFlowMsg = objectMapper.writeValueAsString(serviceFlow);
                boolean result = sendMessage(brokerServer, "post", "/esb/serviceFlow/serverServiceFlow", serviceFlowMsg);
                boolean result = sendMessage(brokerServer, "post", "/esb/serviceFlow/start", serviceFlowMsg);
                if (!result) {
                    logger.error("sendMessage to broker start failed, broker:" + brokerServer.getURL() + ", msg:" + serviceFlowMsg);

+ 0 - 5
hos-arbiter/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@ -10,11 +10,6 @@
      "type": "java.lang.String",
      "description": "Description for arbiter.central.url."
    },
    {
      "name": "arbiter.terminal.url",
      "type": "java.lang.String",
      "description": "Description for arbiter.terminal.url."
    },
    {
      "name": "arbiter.tenant.name",
      "type": "java.lang.String",

+ 2 - 2
hos-arbiter/src/main/resources/application.yml

@ -22,9 +22,9 @@ arbiter:
  timer:
    period: 10000
  central:
    url:
    url: localhost:15555
  terminal:
    url: 192.168.131.119:15555
    url: localhost:15555
  tenant:
    name: jkzl

+ 1 - 1
hos-broker/pom.xml

@ -58,7 +58,7 @@
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
            <!--<scope>provided</scope>-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.camel/camel-stream -->
        <!-- sigar -->

+ 32 - 0
hos-broker/src/main/java/com/yihu/hos/broker/common/processor/AggregateProcessor.java

@ -0,0 +1,32 @@
package com.yihu.hos.broker.common.processor;
import net.sf.json.JSONObject;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import java.util.Iterator;
public class AggregateProcessor implements Processor {
    private String paramJson;
    public AggregateProcessor(String paramJson) {
        this.paramJson = paramJson;
    }
    public void process(Exchange exchange) throws Exception {
        Message inMessage = exchange.getIn();
        Message outMessage = exchange.getOut();
        JSONObject jsonObject = JSONObject.fromObject(paramJson);
        Iterator iterator = jsonObject.keys();
        while (iterator.hasNext()) {
            String name = (String) iterator.next();
            String value = (String) jsonObject.get(name);
            outMessage.setHeader(name, value);
        }
        String body = inMessage.getBody(String.class);
        outMessage.setBody(body);
    }
}

+ 31 - 0
hos-broker/src/main/java/com/yihu/hos/broker/common/processor/DefaultHttpProcessor.java

@ -0,0 +1,31 @@
package com.yihu.hos.broker.common.processor;
import com.yihu.hos.core.datatype.StringUtil;
import net.sf.json.JSONObject;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import java.util.Iterator;
public class DefaultHttpProcessor implements Processor {
    private String paramJson;
    public DefaultHttpProcessor(String paramJson) {
        this.paramJson = paramJson;
    }
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        JSONObject jsonObject = JSONObject.fromObject(paramJson);
        Iterator iterator = jsonObject.keys();
        String queryStr = "";
        while (iterator.hasNext()) {
            String name = (String) iterator.next();
            String value = (String) jsonObject.get(name);
            queryStr += name + "=" + value + "&&";
        }
        queryStr = StringUtil.substring(queryStr, 0, queryStr.length()-2);
        outMessage.setHeader(Exchange.HTTP_QUERY, queryStr);
    }
}

+ 18 - 0
hos-broker/src/main/java/com/yihu/hos/broker/common/processor/HttpProcessor.java

@ -0,0 +1,18 @@
package com.yihu.hos.broker.common.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
public class HttpProcessor implements Processor {
    private String paramName;
    public HttpProcessor(String paramName) {
        this.paramName = paramName;
    }
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        Message inMessage = exchange.getIn();
        outMessage.setHeader(Exchange.HTTP_QUERY, paramName + "=" + inMessage.getBody(String.class));
    }
}

+ 19 - 0
hos-broker/src/main/java/com/yihu/hos/broker/util/Aggregate.java

@ -0,0 +1,19 @@
package com.yihu.hos.broker.util;
import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;
public class Aggregate implements AggregationStrategy {
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        //如果oldExchange为null,则说明是第一个分解包
        if (oldExchange == null) {
            return newExchange;
        }
        String oldBody = oldExchange.getIn().getBody(String.class);
        String newBody = newExchange.getIn().getBody(String.class);
        //将新与旧包进行合并,再设置进Message的body中
        oldExchange.getIn().setBody(oldBody + "\n" + newBody);
        return oldExchange;
    }
}

+ 1 - 1
hos-camel/src/main/java/crawler/Split.java

@ -1,4 +1,4 @@
package crawler;
package com.yihu.hos.broker.util;
import net.sf.json.JSONArray;
import org.apache.camel.Body;

+ 1 - 1
hos-broker/src/main/resources/application.yml

@ -48,7 +48,7 @@ spring:
    port: 8066
hos:
  esb:
    rest-url: http://192.168.131.119:8080/esb
    rest-url: http://localhost:8080/esb
  arbiter:
    enable: true
    url: http://localhost:10135

+ 32 - 0
hos-camel/src/main/java/com/yihu/hos/broker/common/processor/AggregateProcessor.java

@ -0,0 +1,32 @@
package com.yihu.hos.broker.common.processor;
import net.sf.json.JSONObject;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import java.util.Iterator;
public class AggregateProcessor implements Processor {
    private String paramJson;
    public AggregateProcessor(String paramJson) {
        this.paramJson = paramJson;
    }
    public void process(Exchange exchange) throws Exception {
        Message inMessage = exchange.getIn();
        Message outMessage = exchange.getOut();
        JSONObject jsonObject = JSONObject.fromObject(paramJson);
        Iterator iterator = jsonObject.keys();
        while (iterator.hasNext()) {
            String name = (String) iterator.next();
            String value = (String) jsonObject.get(name);
            outMessage.setHeader(name, value);
        }
        String body = inMessage.getBody(String.class);
        outMessage.setBody(body);
    }
}

+ 31 - 0
hos-camel/src/main/java/com/yihu/hos/broker/common/processor/DefaultHttpProcessor.java

@ -0,0 +1,31 @@
package com.yihu.hos.broker.common.processor;
import com.yihu.hos.core.datatype.StringUtil;
import net.sf.json.JSONObject;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import java.util.Iterator;
public class DefaultHttpProcessor implements Processor {
    private String paramJson;
    public DefaultHttpProcessor(String paramJson) {
        this.paramJson = paramJson;
    }
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        JSONObject jsonObject = JSONObject.fromObject(paramJson);
        Iterator iterator = jsonObject.keys();
        String queryStr = "";
        while (iterator.hasNext()) {
            String name = (String) iterator.next();
            String value = (String) jsonObject.get(name);
            queryStr += name + "=" + value + "&&";
        }
        queryStr = StringUtil.substring(queryStr, 0, queryStr.length()-2);
        outMessage.setHeader(Exchange.HTTP_QUERY, queryStr);
    }
}

+ 18 - 0
hos-camel/src/main/java/com/yihu/hos/broker/common/processor/HttpProcessor.java

@ -0,0 +1,18 @@
package com.yihu.hos.broker.common.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
public class HttpProcessor implements Processor {
    private String paramName;
    public HttpProcessor(String paramName) {
        this.paramName = paramName;
    }
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        Message inMessage = exchange.getIn();
        outMessage.setHeader(Exchange.HTTP_QUERY, paramName + "=" + inMessage.getBody(String.class));
    }
}

+ 1 - 1
hos-camel/src/main/java/crawler/Aggregate.java

@ -1,4 +1,4 @@
package crawler;
package com.yihu.hos.broker.util;
import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;

+ 11 - 0
hos-camel/src/main/java/com/yihu/hos/broker/util/Split.java

@ -0,0 +1,11 @@
package com.yihu.hos.broker.util;
import net.sf.json.JSONArray;
import org.apache.camel.Body;
public class Split {
    public JSONArray splitJsonArray(@Body String jsonArrayStr) {
        return JSONArray.fromObject(jsonArrayStr);
    }
}

+ 0 - 18
hos-camel/src/main/java/crawler/processor/Processor0.java

@ -1,18 +0,0 @@
package crawler.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.http.common.HttpMessage;
import java.util.Map;
/**
 * Created by Zdm on 2016/7/13.
 */
public class Processor0 implements Processor {
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        outMessage.setHeader(Exchange.HTTP_QUERY, "jobId=5ad5c11655d443c30155d477a6b10000");
    }
}

+ 0 - 16
hos-camel/src/main/java/crawler/processor/Processor1.java

@ -1,16 +0,0 @@
package crawler.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
/**
 * Created by Zdm on 2016/7/13.
 */
public class Processor1 implements Processor {
    public void process(Exchange exchange) throws Exception {
        Message outMessage = exchange.getOut();
        Message inMessage = exchange.getIn();
        outMessage.setHeader(Exchange.HTTP_QUERY, "str=" + inMessage.getBody(String.class));
    }
}

+ 0 - 24
hos-camel/src/main/java/crawler/processor/Processor2.java

@ -1,24 +0,0 @@
package crawler.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
/**
 * Created by Zdm on 2016/7/13.
 */
public class Processor2 implements Processor {
    private String key;
    public Processor2(String key) {
        this.key = key;
    }
    public void process(Exchange exchange) throws Exception {
        Message inMessage = exchange.getIn();
        Message outMessage = exchange.getOut();
        outMessage.setHeader("test_correlation_key", this.key);
        String body = inMessage.getBody(String.class);
        outMessage.setBody(body);
    }
}

+ 2 - 2
hos-camel/src/main/java/crawler/route/CrawlerQuartzRoute.java

@ -1,6 +1,6 @@
package crawler.route;
import crawler.processor.Processor0;
import com.yihu.hos.broker.common.processor.DefaultHttpProcessor;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
@ -9,7 +9,7 @@ import org.apache.camel.builder.RouteBuilder;
 */
public class CrawlerQuartzRoute extends RouteBuilder {
    public void configure() throws Exception {
        from("quartz://myGroup/myTimerName?cron=0/3 * * * * ?").routeId("routeId").process(new Processor0())
        from("quartz://myGroup/myTimerName?cron=0/3 * * * * ?").routeId("routeId").process(new DefaultHttpProcessor("{\"jobId\": \"sfsfsgafcas\"}"))
                .setHeader(Exchange.HTTP_METHOD, constant("POST")).to("http4://localhost:8088/crawler/patientList").to("stream:out");
    }
}

+ 5 - 5
hos-camel/src/main/java/crawler/route/CrawlerRouteBulider.java

@ -1,6 +1,6 @@
package crawler.route;
import crawler.processor.Processor0;
import com.yihu.hos.broker.common.processor.DefaultHttpProcessor;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
@ -13,19 +13,19 @@ public class CrawlerRouteBulider extends RouteBuilder {
    public void configure() throws Exception {
        from("jetty:http://192.168.131.96:8066/crawlerPull").routeId("crawlerPull")
                .process(new Processor0()).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .process(new DefaultHttpProcessor("{\"jobId\":\"5ad5c11655d443c30155d477a6b10000\"}")).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .to("http://192.168.131.96:8088/crawler/patientList");
        from("jetty:http://192.168.131.96:8066/crawlerPush").routeId("crawlerPush")
                .process(new Processor0()).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .process(new DefaultHttpProcessor("{\"jobId\":\"5ad5c11655d443c30155d477a6b10000\"}")).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .to("http://192.168.131.96:8088/crawler/patient");
        from("jetty:http://192.168.131.96:8066/crawlerFlowPull").routeId("crawlerFlowPull")
                .process(new Processor0()).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .process(new DefaultHttpProcessor("{\"jobId\":\"5ad5c11655d443c30155d477a6b10000\"}")).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .to("http://192.168.131.96:8088/crawler/patientListFlow");
        from("jetty:http://192.168.131.96:8066/crawlerFlowPush").routeId("crawlerFlowPush")
                .process(new Processor0()).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .process(new DefaultHttpProcessor("{\"jobId\":\"5ad5c11655d443c30155d477a6b10000\"}")).setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .to("http://192.168.131.96:8088/crawler/patientFlow");
    }
}

+ 2 - 2
hos-camel/src/main/java/crawler/route/QuartzRoute.java

@ -1,6 +1,6 @@
package crawler.route;
import crawler.processor.Processor0;
import com.yihu.hos.broker.common.processor.DefaultHttpProcessor;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
@ -15,7 +15,7 @@ public class QuartzRoute extends RouteBuilder {
        from("quartz://myGroupName/myTimerName?cron=0/5+*+*+*+*+?")
                .process(new Processor0() {
                .process(new DefaultHttpProcessor("{\"jobId\":\"5ad5c11655d443c30155d477a6b10000\"}") {
                    @Override
                    public void process(Exchange exchange) throws Exception {
                        System.out.println("I'm running every 5 sec...Change by XXXX===========");

+ 6 - 6
hos-camel/src/main/java/crawler/route/RouteBulider1.java

@ -1,9 +1,9 @@
package crawler.route;
import crawler.Aggregate;
import crawler.processor.Processor1;
import crawler.Split;
import crawler.processor.Processor2;
import com.yihu.hos.broker.util.Aggregate;
import com.yihu.hos.broker.common.processor.HttpProcessor;
import com.yihu.hos.broker.util.Split;
import com.yihu.hos.broker.common.processor.AggregateProcessor;
import org.apache.camel.builder.RouteBuilder;
/**
@ -15,8 +15,8 @@ public class RouteBulider1 extends RouteBuilder {
        from("quartz://myGroup/myTimerName?cron=0/5 * * * * ? ").routeId("list")
                .to("http://localhost:9999/list")
                .split().method(Split.class, "splitJsonArray")
                .process(new Processor1()).to("http://localhost:9999/str")
                .process(new Processor2("key1"))
                .process(new HttpProcessor("str")).to("http://localhost:9999/str")
                .process(new AggregateProcessor("key1"))
                .aggregate(header("test_correlation_key"), new Aggregate()).completionSize(3).to("stream:out");
    }

+ 14 - 27
src/main/java/com/yihu/hos/common/graph/BFSGraph.java

@ -9,8 +9,8 @@ import java.util.*;
 * 邻接链表(Adjacency List)实现的有向图
 * @param <V>
 */
public class BFSGraph<V> implements DGraph<V>{
    private static Logger logger = LoggerFactory.getLogger(BFSGraph.class);
public class DGraphImpl<V> implements IDGraph<V> {
    private static Logger logger = LoggerFactory.getLogger(DGraphImpl.class);
    /**
     * 顶点对象,其中有对应的顶点以及从以此顶点为起点的边
     */
@ -27,7 +27,6 @@ public class BFSGraph<V> implements DGraph<V>{
        public VE(V v) {
            this.v = v;
            this.mEdgeList = new LinkedList<Edge<V>>();
            logger.info("VE construct : %s", v);
        }
        
        @Override
@ -42,11 +41,10 @@ public class BFSGraph<V> implements DGraph<V>{
         * @param e
         */
        public void addEdge(Edge<V> e) {
            logger.info("add edge : %s", e);
            if(getEdge(e.getDest()) == null) {
                mEdgeList.add(e);
            } else {
                logger.info("edge exist : %s", e);
                logger.warn("edge exist : %s", e);
            }
        }
        
@ -61,7 +59,6 @@ public class BFSGraph<V> implements DGraph<V>{
                for(Edge<V> edge : mEdgeList) {
                    if(edge.getDest() != null &&
                       dest.equals(edge.getDest())) {
                        logger.info("get edge : %s", edge);
                        ret = edge;
                        break;
                    }
@ -81,7 +78,6 @@ public class BFSGraph<V> implements DGraph<V>{
                for(Edge<V> edge : mEdgeList) {
                    if(edge.getDest() != null &&
                       dest.equals(edge.getDest())) {
                        logger.info("remove edge : %s", edge);
                        ret = edge;
                        mEdgeList.remove(edge);
                        break;
@ -96,12 +92,12 @@ public class BFSGraph<V> implements DGraph<V>{
    /**
     * 广度优先的迭代器
     */
    private class BFSIterator implements Iterator<V> {
    public class BFSIterator implements Iterator<V> {
        /**已访问过的顶点列表*/
        private List<V> mVisitList = null;
        /**待访问的顶点队列*/
        private Queue<V> mVQueue = null;
        
        /**
         * 构造广度优先迭代器
         * @param root
@ -109,14 +105,13 @@ public class BFSGraph<V> implements DGraph<V>{
        public BFSIterator(V root) {
            mVisitList = new LinkedList<V>();
            mVQueue = new LinkedList<V>();
            
            //将初始节点入队列
            mVQueue.offer(root);
        }
        
        @Override
        public boolean hasNext() {
            logger.info("queue size : " + mVQueue.size());
            if(mVQueue.size() > 0) {
                return true;
            } else {
@ -128,7 +123,7 @@ public class BFSGraph<V> implements DGraph<V>{
        public V next() {
            //1.取队列元素
            V v = mVQueue.poll();
            
            if(v != null) {
                //2.将此元素的邻接边中对应顶点入队列,这些顶点需要符合以下条件:
                //1)没访问过;
@ -141,15 +136,14 @@ public class BFSGraph<V> implements DGraph<V>{
                        if(!VinList(dest, mVisitList.iterator()) &&
                           !VinList(dest, mVQueue.iterator())) {
                            mVQueue.offer(dest);
                            logger.info("add to queue : " + dest);
                        }
                    }
                }
                
                //3.将此顶点添加到已访问过的顶点列表中
                mVisitList.add(v);
            }
            
            //4.返回出队列的元素
            return v;
        }
@ -158,24 +152,22 @@ public class BFSGraph<V> implements DGraph<V>{
        public void remove() {
            // 暂时不实现
        }
        
    }
    
    /**顶点列表,由于会经常进行插入删除,使用链表队列*/
    private LinkedList<VE> mVEList;
    /**
     * 构造邻接链表有向图
     */
    public BFSGraph() {
    public DGraphImpl() {
        mVEList = new LinkedList<VE>();
        logger.info("ListDGraph construct!");
    }
    @Override
    public int add(V v) {
        int index = -1;
        if(v != null) {
            logger.info("add v: %s", v);
            VE ve = new VE(v);
            mVEList.add(ve);
            index = mVEList.indexOf(ve);
@ -186,14 +178,13 @@ public class BFSGraph<V> implements DGraph<V>{
    @Override
    public void add(Edge<V> e) {
        if(e != null) {
            logger.info("add edge: %s", e);
            VE ve = getVE(e.getSource());
            if(ve != null) {
                //若边的起点已经在列表里,则直接将其添加到对应的顶点对象中
                ve.addEdge(e);
            } else {
                //否则提示错误
                logger.info("Error, can't find v : %s", e.getSource());
                logger.error("Error, can't find v : %s", e.getSource());
            }
        }
    }
@ -233,7 +224,6 @@ public class BFSGraph<V> implements DGraph<V>{
            VE ve = mVEList.get(index);
            if(ve != null) {
                ret = ve.v;
                logger.info("get , index : %s , v : %s", index, ret);
            }
        }
        return ret;
@ -279,7 +269,6 @@ public class BFSGraph<V> implements DGraph<V>{
        if(v != null) {
            for(VE ve : mVEList) {
                if(ve.v != null && v.equals(ve.v)) {
                    logger.info("getVE : %s", ve);
                    ret = ve;
                    break;
                }
@ -301,7 +290,6 @@ public class BFSGraph<V> implements DGraph<V>{
        if(v != null) {
            for(VE ve : mVEList) {
                if(ve.v != null && v.equals(ve.v)) {
                    logger.info("getVE : %s", ve);
                    ret = ve;
                    break;
                }
@ -320,7 +308,6 @@ public class BFSGraph<V> implements DGraph<V>{
        if(v != null) {
            for(VE ve : mVEList) {
                if(ve.v != null && v.equals(ve.v)) {
                    logger.info("removeVE : %s", v);
                    ret = ve;
                    mVEList.remove(ve);
                    break;

+ 1 - 1
src/main/java/com/yihu/hos/common/graph/DGraph.java

@ -7,7 +7,7 @@ import java.util.List;
 * 有向图接口,定义需要实现的各个方法,可以选择使用邻接矩阵或者邻接链表来实现
 * @param <V> V代表端点,可以根据需要设置器数据类型
 */
public interface DGraph<V> {
public interface IDGraph<V> {
    
    /**广度优先遍历*/
    public static final int ITERATOR_TYPE_BFS = 0;

+ 26 - 7
src/main/java/com/yihu/hos/system/controller/ProcessController.java

@ -23,16 +23,17 @@ public class ProcessController  extends BaseController {
     * @return
     */
    @RequestMapping("/initial")
    public String processInitial(Model model) {
    public String processInitial(Model model, Integer flowId) {
        model.addAttribute("flowId", flowId);
        model.addAttribute("contentPage", "system/process/process");
        return "partView";
    }
    @RequestMapping(value = "/getAllEndpoints", method = RequestMethod.GET)
    @ResponseBody
    public Result getEndpoints(String endpointName) {
    public Result getAllEndpoints(String endpointName) {
        try {
            return processManager.getEndpoints(endpointName);
            return processManager.getAllEndpoints(endpointName);
        } catch (Exception e) {
            return Result.error("查找端点失败");
        }
@ -48,16 +49,34 @@ public class ProcessController  extends BaseController {
        }
    }
    @RequestMapping(value = "/chart", method = RequestMethod.GET)
    @ResponseBody
    public Result getFlowchart(Integer flowId) {
        try {
            if (flowId != null) {
                String flowchart = processManager.getFlowchart(flowId);
                return Result.success(flowchart);
            } else {
                return Result.success("无初始化数据");
            }
        } catch (Exception e) {
            return Result.error("生成业务流程失败");
        }
    }
    @RequestMapping(value = "/json", method = RequestMethod.POST)
    @ResponseBody
    public Result formatJson(String code, String name, String positionJson, String flowJson) {
        try {
            String fileName = processManager.formatJson(flowJson);
            processManager.saveProcess(code, name, fileName, positionJson);
            Integer flowId = processManager.generateFlow(code, name, flowJson);
            if (flowId == null) {
                return Result.error("生成业务流程失败,请确认流程图是否编辑错误");
            }
            processManager.saveProcess(code, name, flowId, positionJson, flowJson);
            return Result.error("生成模板成功");
            return Result.success("生成业务流程成功");
        } catch (Exception e) {
            return Result.error("生成模板失败");
            return Result.error("生成业务流程失败");
        }
    }
}

+ 8 - 0
src/main/java/com/yihu/hos/system/dao/FlowProcessDao.java

@ -23,4 +23,12 @@ public class FlowProcessDao extends SQLGeneralDAO {
        }
        return null;
    }
    public SystemServiceFlowProcess getFlowProcessByFlowId(Integer flowId) throws Exception {
        List<SystemServiceFlowProcess> list = (List<SystemServiceFlowProcess>) super.hibernateTemplate.find("from SystemServiceFlowProcess s where flowId=? ", flowId);
        if (!CollectionUtil.isEmpty(list)) {
            return list.get(0);
        }
        return null;
    }
}

+ 18 - 0
src/main/java/com/yihu/hos/system/model/ProcessResultModel.java

@ -8,6 +8,8 @@ public class ProcessResultModel implements java.io.Serializable {
	private String name;
	private String value;
	private String config;
	private String nodeType;
	public String getName() {
		return name;
@ -24,4 +26,20 @@ public class ProcessResultModel implements java.io.Serializable {
	public void setValue(String value) {
		this.value = value;
	}
	public String getConfig() {
		return config;
	}
	public void setConfig(String config) {
		this.config = config;
	}
	public String getNodeType() {
		return nodeType;
	}
	public void setNodeType(String nodeType) {
		this.nodeType = nodeType;
	}
}

+ 14 - 5
src/main/java/com/yihu/hos/system/model/SystemServiceFlowProcess.java

@ -4,8 +4,9 @@ public class SystemServiceFlowProcess implements java.io.Serializable {
    private Integer id;
    private String code;
    private String name;
    private String fileName;
    private Integer flowId;
    private String result;
    private String flowResult;
    public Integer getId() {
        return id;
@ -39,11 +40,19 @@ public class SystemServiceFlowProcess implements java.io.Serializable {
        this.result = result;
    }
    public String getFileName() {
        return fileName;
    public String getFlowResult() {
        return flowResult;
    }
    public void setFileName(String fileName) {
        this.fileName = fileName;
    public void setFlowResult(String flowResult) {
        this.flowResult = flowResult;
    }
    public Integer getFlowId() {
        return flowId;
    }
    public void setFlowId(Integer flowId) {
        this.flowId = flowId;
    }
}

+ 54 - 0
src/main/java/com/yihu/hos/system/service/FlowManager.java

@ -644,6 +644,60 @@ public class FlowManager {
        return null;
    }
    public Integer sendAddRoute(String code, String name, String javaName, String packageName, String fileInfo) throws Exception {
        String fileName = javaName + ".java";
        String filePath = this.getClass().getProtectionDomain().getClassLoader().getResource("").getPath() + "temp/" + fileName;
        boolean succ = FileUtil.writeFile(filePath, fileInfo, "UTF-8");
        if (succ) {
            fileName = GridFSUtil.uploadFile(filePath, fileName, null);
        } else {
            return null;
        }
        if (fileName != null) {
            SystemServiceFlow systemServiceFlow = new SystemServiceFlow();
            systemServiceFlow.setName(name);
            systemServiceFlow.setCode(code);
            systemServiceFlow.setCreateDate(new Date());
            systemServiceFlow.setValid(1);
            systemServiceFlow.setFileType(ServiceFlowConstant.JAVA);
            flowDao.saveEntity(systemServiceFlow);
            String enFileName = DES.encrypt(fileName, DES.COMMON_PASSWORD);//加密文件名
            ServiceFlow serviceFlow = new ServiceFlow();
            serviceFlow.setRouteCode(code);
            serviceFlow.setFlowType(ServiceFlowConstant.CLASS);
            ServiceFlow.HandleFile handleFile = new ServiceFlow.HandleFile();
            handleFile.setRouteCode(code);
            handleFile.setFileType(ServiceFlowConstant.JAVA);
            handleFile.setPackageName(packageName);
            handleFile.setClassName(javaName);
            handleFile.setFilePath(enFileName);
            handleFile.setUsage(ServiceFlowConstant.FLOW_TYPE_ROUTE);
            ArrayList<ServiceFlow.HandleFile> handleFiles = new ArrayList<>();
            handleFiles.add(handleFile);
            serviceFlow.setHandleFiles(handleFiles);
            serviceFlowEventService.serviceFlowAdded(serviceFlow);
            String enClassName = DES.encrypt(javaName + ".class", DES.COMMON_PASSWORD);//生成加密过的classPath
            SystemServiceFlowClass flowClass = new SystemServiceFlowClass();
            flowClass.setPackageName(packageName);
            flowClass.setClassName(javaName);
            flowClass.setClassPath(enClassName);
            flowClass.setFlowId(systemServiceFlow.getId());
            flowClass.setType(ServiceFlowConstant.FLOW_TYPE_ROUTE);
            flowClass.setIsUpdate("1");
            flowClassDao.saveEntity(flowClass);
            return systemServiceFlow.getId();
        } else {
            System.out.println("生成route的java文件过程出错");
            return null;
        }
    }
    public Integer sendAddProcessor(String jobId, Integer flowId, Long timestamp) throws Exception {
        List<SystemServiceFlowTemp> flowTempRouters = flowTempDao.getFlowTemps(flowId, ServiceFlowConstant.FLOW_TYPE_ROUTE);
        List<SystemServiceFlowTemp> flowTempProces = flowTempDao.getFlowTemps(flowId, ServiceFlowConstant.FLOW_TYPE_PROCESSOR);

+ 211 - 0
src/main/java/com/yihu/hos/system/service/ProcessEditor.java

@ -0,0 +1,211 @@
package com.yihu.hos.system.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.yihu.hos.common.graph.Edge;
import com.yihu.hos.common.graph.IDGraph;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.core.datatype.StringUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class ProcessEditor {
    private String code;
    private Map<String, JsonNode> lineMap;
    private Map<String, JsonNode> nodeMap;
    private Iterator<String> nodeIt;
    private IDGraph<String> mDG;
    private StringBuilder bodyBuilder = new StringBuilder();
    private List<String> packageList = new ArrayList<>();
    private StringBuilder otherRouteBuilder = new StringBuilder();
    private StringBuilder preferBuilder = new StringBuilder();
    public String generate(String javaName, String packageName) throws IOException {
        Boolean isFirstNodeFlg = true;
        StringBuilder allBuilder = new StringBuilder();
//        packageBuilder.append("import org.apache.camel.Exchange;\n");
        addPackageList("import org.apache.camel.builder.RouteBuilder;\n");
        preferBuilder.append("public class "+javaName+" extends RouteBuilder {\n");
        preferBuilder.append("public void configure() throws Exception {\n");
        String nodeName = "";
        while(nodeIt.hasNext()) {
            if (isFirstNodeFlg) {
                nodeName = nodeIt.next();
                isFirstNodeFlg = false;
                bodyBuilder.append(montage(nodeName));
            } else {
                List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
                if (CollectionUtil.isEmpty(edgeList)) {
                    nodeIt.next();
                }
                for (Edge<String> edge : edgeList) {
                    nodeIt.next();
                    nodeName = edge.getDest();
                    bodyBuilder.append(montage(nodeName));
                }
            }
        }
        bodyBuilder.append(";");
        bodyBuilder.append(otherRouteBuilder);
        bodyBuilder.append("\n}\n}");
        StringBuilder packageBuilder = new StringBuilder();
        packageBuilder.append("package " + packageName + ";\n\n");
        packageList.forEach(packageBuilder::append);
        allBuilder.append(packageBuilder).append(preferBuilder).append(bodyBuilder);
        System.out.println(allBuilder.toString());
        return allBuilder.toString();
    }
    public StringBuilder montage(String nodeName) {
        JsonNode node = nodeMap.get(nodeName);
        String nodeType = node.get("nodeType").asText();
        String config = node.get("config").asText();
//        String name = node.get("name").asText();
        StringBuilder bodyBuilderTemp = new StringBuilder();
        if (nodeType.equals("start")) {
            bodyBuilder.append("from(\"");
            bodyBuilder.append(config + "\")");
            if (!StringUtil.isEmpty(code)) {
                bodyBuilder.append(".routeId(\""+code+"\")");
            }
        } else if (nodeType.equals("processor")) {
            String value = node.get("value").asText();
            String className = value.substring(value.lastIndexOf(".") + 1, value.length());
            addPackageList("import " + value + ";\n");
            if (config == null) {
                bodyBuilderTemp.append("\n.process(new "+className+"(\"\"))");
            } else {
                bodyBuilderTemp.append("\n.process(new "+className+"("+config+"))");
            }
        } else if (nodeType.equals("judgement")) {
            judgement(config, nodeName, bodyBuilderTemp);
        } else if (nodeType.equals("circle")) {
            split(config, bodyBuilderTemp);
        } else if (nodeType.equals("aggregate")) {
            aggregate(config, bodyBuilderTemp);
        } else if (nodeType.equals("multicast")) {
            multicast(config, nodeName, bodyBuilderTemp);
        } else if (nodeType.equals("format")) {
            format(config, nodeName, bodyBuilderTemp);
        } else {
//                    bodyBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
            bodyBuilderTemp.append("\n.to(\"");
            bodyBuilderTemp.append(config + "\")");
        }
        while (nodeIt.hasNext()) {
            List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
            if (CollectionUtil.isEmpty(edgeList)) {
                return bodyBuilderTemp;
            }
            for (Edge<String> edge : edgeList) {
                nodeIt.next();
                nodeName = edge.getDest();
                bodyBuilderTemp.append(montage(nodeName));
            }
        }
        return bodyBuilderTemp;
    }
    public void judgement(String config, String nodeName, StringBuilder builder) {
        builder.append("\n.choice()");
        builder.append("\n.when("+config+")");
        String trueNodeName = "";
        String falseNodeName = "";
        for (Edge<String> edge : mDG.getEdgeList(nodeName)) {
            nodeIt.next();
            String nextNodeName = edge.getDest();
            String nextLineName = edge.getName();
            JsonNode nextLine = lineMap.get(nextLineName);
            if (nextLine.get("config") != null && nextLine.get("config").asText().equals("true")) {
                trueNodeName = nextNodeName;
            } else {
                falseNodeName = nextNodeName;
            }
        }
        builder.append("\n.to(\"direct:ja\")");
        builder.append("\n.otherwise()");
        builder.append("\n.to(\"direct:jb\")");
        builder.append("\n.end()");
        StringBuilder trueBuilder = montage(trueNodeName);
        StringBuilder falseBuilder = montage(falseNodeName);
        otherRouteBuilder.append("\nfrom(\"direct:ja\")").append(trueBuilder).append(";");
        otherRouteBuilder.append("\nfrom(\"direct:jb\")").append(falseBuilder).append(";");
    }
    public void split(String config, StringBuilder builder) {
        addPackageList("import com.yihu.hos.broker.util.Split;\n");
        builder.append("\n.split().method(Split.class, \""+config+"\")");
    }
    public void aggregate(String config, StringBuilder builder) {
        addPackageList("import com.yihu.hos.broker.util.Aggregate;\n");
        builder.append("\n.aggregate(header(\""+config+"\"), new Aggregate()).completionSize(3)");
    }
    public void multicast(String config, String nodeName, StringBuilder builder) {
        String directs = "";
        int i = 'a';
        List<String> directList = new ArrayList<>();
        List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
        for (Edge<String> edge : edgeList) {
            nodeIt.next();
            String direct = "direct:m" + (char)i++;
            directList.add(direct);
            directs += "\"" + direct + "\",";
            StringBuilder directBuilder = new StringBuilder();
            directBuilder.append("\nfrom(\"");
            directBuilder.append(direct + "\")");
            nodeName = edge.getDest();
            otherRouteBuilder.append(directBuilder).append(montage(nodeName)).append(";");
        }
        directs = StringUtil.substring(directs, 0, directs.length() - 1);
        builder.append("\n.multicast().stopOnException().to("+directs+").end()");
    }
    public void format(String config, String nodeName, StringBuilder builder) {
        addPackageList("import org.apache.camel.model.dataformat.XmlJsonDataFormat;\n");
        preferBuilder.append("XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat();\n");
        builder.append("\n."+config + "(xmlJsonFormat)");
    }
    public void addPackageList(String pack) {
        if (!packageList.contains(pack)) {
            packageList.add(pack);
        }
    }
    public void setCode(String code) {
        this.code = code;
    }
    public void setLineMap(Map<String, JsonNode> lineMap) {
        this.lineMap = lineMap;
    }
    public void setNodeIt(Iterator<String> nodeIt) {
        this.nodeIt = nodeIt;
    }
    public void setNodeMap(Map<String, JsonNode> nodeMap) {
        this.nodeMap = nodeMap;
    }
    public void setmDG(IDGraph<String> mDG) {
        this.mDG = mDG;
    }
}

+ 101 - 190
src/main/java/com/yihu/hos/system/service/ProcessManager.java

@ -2,9 +2,9 @@ package com.yihu.hos.system.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.common.graph.BFSGraph;
import com.yihu.hos.common.graph.DGraph;
import com.yihu.hos.common.graph.DGraphImpl;
import com.yihu.hos.common.graph.Edge;
import com.yihu.hos.common.graph.IDGraph;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.system.dao.AppDao;
import com.yihu.hos.system.dao.AppServiceDao;
@ -17,7 +17,6 @@ import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
@Service("ProcessManager")
@ -33,10 +32,12 @@ public class ProcessManager {
    private ProcessorDao processorDao;
    @Resource(name = FlowProcessDao.BEAN_ID)
    private FlowProcessDao processDao;
    @Resource(name = FlowManager.BEAN_ID)
    private FlowManager flowManager;
    private ObjectMapper objectMapper = new ObjectMapper();
    public Result getEndpoints(String endpointName) throws Exception {
    public Result getAllEndpoints(String endpointName) throws Exception {
        List<SystemServiceEndpoint> serviceEndpointList = appServiceDao.getListByName(endpointName);
        List<String> appIdList = new ArrayList<>();
@ -45,7 +46,10 @@ public class ProcessManager {
            ProcessResultModel resultModel = new ProcessResultModel();
            resultModel.setName(endpoint.getName());
            resultModel.setValue(endpoint.getEndpoint());
            resultModel.setConfig(endpoint.getEndpoint());
            resultModel.setNodeType("service");
            appIdList.add(endpoint.getAppId());
            List<ProcessResultModel> endpointList;
            if (appServiceMap.get(endpoint.getAppId()) != null) {
                endpointList = appServiceMap.get(endpoint.getAppId());
@ -60,10 +64,30 @@ public class ProcessManager {
        for (SystemApp app : appList) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("title", app.getName());
            jsonObject.put("list", appServiceMap.get(app.getId()));
            jsonArray.add(jsonObject);
        }
            List<ProcessResultModel> resultModelList = appServiceMap.get(app.getId());
            List<ProcessResultModel> resultModelListListTemp = new ArrayList<>();
            if (app.getName().equals("起始端点")) {
                for (ProcessResultModel resultModel : resultModelList) {
                    resultModel.setNodeType("start");
                    resultModelListListTemp.add(resultModel);
                }
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(0, jsonObject);
            } else if (app.getName().equals("结束端点")) {
                for (ProcessResultModel resultModel : resultModelList) {
                    resultModel.setNodeType("end");
                    resultModelListListTemp.add(resultModel);
                }
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(1, jsonObject);
            } else {
                resultModelListListTemp = resultModelList;
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(jsonObject);
            }
        }
        return Result.success(jsonArray.toString());
    }
@ -74,61 +98,84 @@ public class ProcessManager {
//        return Result.success(result);
//    }
    public String getFlowchart(Integer flowId) throws Exception {
        SystemServiceFlowProcess serviceFlowProcess = processDao.getFlowProcessByFlowId(flowId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", serviceFlowProcess.getCode());
        jsonObject.put("name", serviceFlowProcess.getName());
        jsonObject.put("flowId", serviceFlowProcess.getFlowId());
        jsonObject.put("result", serviceFlowProcess.getResult());
        return jsonObject.toString();
    }
    public Result getAllProcessor(String processorName) throws Exception {
        List<SystemServiceFlowProcessor> processorList = processorDao.getListByName(processorName);
        List<ProcessResultModel> resultModelList = new ArrayList<>();
        ProcessResultModel json2xml = new ProcessResultModel();
        json2xml.setName("json转xml格式转换器");
        json2xml.setValue("unmarshal");
        json2xml.setConfig("unmarshal");
        json2xml.setNodeType("format");
        ProcessResultModel xml2json = new ProcessResultModel();
        xml2json.setName("xml转json格式转换器");
        xml2json.setValue("marshal");
        xml2json.setConfig("marshal");
        xml2json.setNodeType("format");
        resultModelList.add(json2xml);
        resultModelList.add(xml2json);
        for (SystemServiceFlowProcessor processor : processorList) {
            ProcessResultModel resultModel = new ProcessResultModel();
            resultModel.setName(processor.getName());
            resultModel.setValue(processor.getClassName());
            resultModel.setValue(processor.getPackageName() + "." + processor.getClassName());
            resultModel.setConfig("");
            resultModel.setNodeType("processor");
            resultModelList.add(resultModel);
        }
        String result = objectMapper.writeValueAsString(resultModelList);
        return Result.success(result);
    }
    public void saveProcess(String code, String name, String fileName, String positionJsonStr) throws Exception {
    public void saveProcess(String code, String name, Integer flowId, String positionJsonStr, String flowJsonStr) throws Exception {
        SystemServiceFlowProcess process = new SystemServiceFlowProcess();
        process.setCode(code);
        process.setName(name);
        process.setResult(positionJsonStr);
        process.setFileName(fileName);
        process.setFlowId(flowId);
        process.setFlowResult(flowJsonStr);
        processDao.saveEntity(process);
    }
    public static void main(String[] args) throws Exception {
    public void main(String[] args) throws Exception {
        String flowJsonStr = "{\n" +
                "    \"code\": \"crawler\",\n" +
                "    \"nodes\": {\n" +
                "        \"node_1\": {\n" +
                "            \"name\": \"quartz\",\n" +
                "            \"name\": \"Quartz\",\n" +
                "            \"value\": \"quartz://myGroup/myTimerName?cron=0/3 * * * * ?\",\n" +
                "            \"type\": \"service\"\n" +
                "            \"nodeType\": \"start\"\n" +
                "        },\n" +
                "        \"node_2\": {\n" +
                "            \"name\": \"Processor0\",\n" +
                "            \"value\": \"crawler.processor.Processor0\",\n" +
                "            \"type\": \"processor\"\n" +
                "            \"name\": \"DefaultHttpProcessor0\",\n" +
                "            \"value\": \"com.yihu.hos.broker.common.processor.DefaultHttpProcessor\",\n" +
                "\t\t\t\"param\": \"{\\\"jobId\\\":\\\"5ad5c11655d443c30155d477a6b10000\\\"}\",\n" +
                "            \"nodeType\": \"processor\"\n" +
                "        },\n" +
                "        \"node_3\": {\n" +
                "            \"name\": \"crawler0\",\n" +
                "            \"value\": \"http4://localhost:8088/crawler/patientList\",\n" +
                "            \"type\": \"service\"\n" +
                "        },\n" +
                "        \"node_4\": {\n" +
                "            \"name\": \"multicast0\",\n" +
                "            \"value\": \"2\",\n" +
                "            \"type\": \"multicast\"\n" +
                "            \"name\": \"Crawler0\",\n" +
                "            \"value\": \"http4://localhost:8088/crawler/patientList?method=post\",\n" +
                "            \"nodeType\": \"service\"\n" +
                "        },\n" +
                "        \"node_5\": {\n" +
                "            \"name\": \"crawle1r1\",\n" +
                "            \"value\": \"http4://localhost:8088/crawler/cralwer\",\n" +
                "            \"type\": \"service\"\n" +
                "\t\t\"node_4\": {\n" +
                "            \"name\": \"xml2json\",\n" +
                "            \"value\": \"marshal\",\n" +
                "            \"nodeType\": \"format\"\n" +
                "        },\n" +
                "        \"node_6\": {\n" +
                "            \"name\": \"crawler2\",\n" +
                "            \"value\": \"http4://localhost:8088/crawler/collect\",\n" +
                "            \"type\": \"service\"\n" +
                "\t\t\"node_5\": {\n" +
                "            \"name\": \"Stream\",\n" +
                "            \"value\": \"stream:out\",\n" +
                "            \"nodeType\": \"end\"\n" +
                "        }\n" +
                "    },\n" +
                "    \"lines\": {\n" +
@ -144,24 +191,23 @@ public class ProcessManager {
                "            \"from\": \"node_3\",\n" +
                "            \"to\": \"node_4\"\n" +
                "        },\n" +
                "        \"line_4\": {\n" +
                "\t\t\"line4\": {\n" +
                "            \"from\": \"node_4\",\n" +
                "            \"to\": \"node_5\"\n" +
                "        },\n" +
                "        \"line_5\": {\n" +
                "            \"from\": \"node_4\",\n" +
                "            \"to\": \"node_6\"\n" +
                "        }\n" +
                "    }\n" +
                "}";
        formatJson(flowJsonStr);
//        generateFlow("crawler", "业务流程图", flowJsonStr);
    }
    public static String formatJson(String flowJsonStr) throws Exception {
    public Integer generateFlow(String code, String name, String flowJsonStr) throws Exception {
        SystemServiceFlowProcess process = processDao.getFlowProcessByCode(code);
        if (process != null) {
            return null;
        }
        String root = "";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode flowJson = objectMapper.readValue(flowJsonStr, JsonNode.class);
        String code = flowJson.get("code").asText();
        //sort flow by lines
        JsonNode lines = flowJson.get("lines");
@ -172,11 +218,12 @@ public class ProcessManager {
        //for the java code import processor class
        Map<String, JsonNode> nodeMap = new HashMap<>();
        Map<String, JsonNode> lineMap = new HashMap<>();
        DGraph<String> mDG = new BFSGraph<String>();
        IDGraph<String> mDG = new DGraphImpl<String>();
        while (nodeIterator.hasNext()) {
            Map.Entry<String, JsonNode> map = nodeIterator.next();
            nodeMap.put(map.getKey(), map.getValue());
            if (StringUtil.isEmpty(mDG.get(0))) {
            String type = map.getValue().get("nodeType").asText();
            if (StringUtil.isEmpty(root) && type.equals("start")) {
                root = map.getKey();
            }
            mDG.add(map.getKey());
@ -189,99 +236,21 @@ public class ProcessManager {
            String nodeNameTo = map.getValue().get("to").asText();
            mDG.add(new Edge<>(nodeNameFrom, nodeNameTo, map.getKey()));
        }
        ProcessEditor editor = new ProcessEditor();
        Iterator<String> nodeIt = mDG.iterator(root);
        editor.setCode(code);
        editor.setNodeIt(nodeIt);
        editor.setmDG(mDG);
        editor.setLineMap(lineMap);
        editor.setNodeMap(nodeMap);
        //generate the java code
        return generate(code, root, lineMap, nodeMap, mDG);
    }
    public static String generate(String code, String root, Map<String, JsonNode> lineMap, Map<String, JsonNode> nodeMap, DGraph<String> mDG) throws IOException {
        Boolean isFirstNodeFlg = true;
        StringBuilder javaBuilder = new StringBuilder();
        StringBuilder bodyBuilder = new StringBuilder();
        StringBuilder packageBuilder = new StringBuilder();
        String javaName = toUpperCaseFirstOne(code)+"Route";
        String packageName = code+".route";
        packageBuilder.append("package "+code+".route;\n\n");
        packageBuilder.append("import org.apache.camel.Exchange;\n");
        packageBuilder.append("import org.apache.camel.builder.RouteBuilder;\n");
        for (String key : nodeMap.keySet()) {
            JsonNode node = nodeMap.get(key);
            String type = node.get("type").asText();
            if (type.equals("processor")) {
                packageBuilder.append("import " + node.get("value").asText() + ";\n");
            }
        }
        bodyBuilder.append("public class "+javaName+" extends RouteBuilder {\n");
        bodyBuilder.append("public void configure() throws Exception {\n");
        String fileInfo = editor.generate(javaName, packageName);
        Iterator<String> it = mDG.iterator(root);
        while(it.hasNext()) {
            String nodeName = it.next();
            JsonNode node = nodeMap.get(nodeName);
            String type = node.get("type").asText();
            String value = node.get("value").asText();
            String name = node.get("name").asText();
            if (isFirstNodeFlg) {
                bodyBuilder.append("from(\"");
                bodyBuilder.append(value + "\")");
                bodyBuilder.append(".routeId(\""+code+"\")");
                isFirstNodeFlg = false;
            } else {
                if (type.equals("processor")) {
                    JsonNode args = node.get("args");
                    if (args == null) {
                        bodyBuilder.append("\n.process(new "+name+"())");
                    } else {
                        String argStr = "";
                        String[] argArr = args.asText().split(",");
                        for (String arg : argArr) {
                            argStr += "\"" + arg + "\",";
                        }
                        argStr = StringUtil.substring(argStr, 0, argStr.length() - 1);
                        bodyBuilder.append("\n.process(new "+name+"("+argStr+"))");
                    }
                } else if (type.equals("judgement")) {
                    judgement(bodyBuilder, value, getEdgeList(nodeName, mDG), it, lineMap, nodeMap);
                } else if (type.equals("circle")) {
                    split(bodyBuilder, packageBuilder, value);
                } else if (type.equals("aggregate")) {
                    aggregate(bodyBuilder, packageBuilder, value);
                } else if (type.equals("multicast")) {
                    mulitcast(bodyBuilder, value, getEdgeList(nodeName, mDG), it, lineMap, nodeMap);
                } else {
//                    bodyBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
                    bodyBuilder.append("\n.to(\"");
                    bodyBuilder.append(value + "\")");
                }
            }
        }
        bodyBuilder.append(";");
        bodyBuilder.append("\n}\n}");
        javaBuilder.append(packageBuilder).append(bodyBuilder);
        System.out.println(javaBuilder.toString());
//        String packageFilePath = System.getProperty("user.dir");
//
//        String filePath = packageFilePath + "/" + javaName + ".java";
//        File file = new File(filePath);
//
//        FileWriter fw = new FileWriter(file);
//        fw.write(bodyBuilder.toString());
//        fw.flush();
//        fw.close();//这里只是产生一个JAVA文件,简单的IO操作
//
//        //upload to mongo
//        String newFileName;
//        try {
//            newFileName = GridFSUtil.uploadFile(filePath, file.getName(), null);
//            if (!StringUtil.isEmpty(newFileName)) {
//                return newFileName;
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        return "";
//        Integer flowId = flowManager.sendAddRoute(code, name, javaName, packageName, fileInfo);
        return null;
    }
    //首字母转大写
@ -291,62 +260,4 @@ public class ProcessManager {
        else
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
    }
    public static List<Edge<String>> getEdgeList(String nodeName, DGraph<String> mDG) {
        return mDG.getEdgeList(nodeName);
    }
    public static void judgement(StringBuilder bodyBuilder, String value, List<Edge<String>> edgeList, Iterator<String> it,  Map<String, JsonNode> lineMap, Map<String, JsonNode> nodeMap) {
        bodyBuilder.append("\n.choice()");
        bodyBuilder.append("\n.when("+value+")");
        String trueNodeName = "";
        String falseNodeName = "";
        for (Edge<String> edge : edgeList) {
            it.next();
            String nextNodeName = edge.getDest();
            String nextLineName = edge.getName();
            JsonNode nextLine = lineMap.get(nextLineName);
            if (nextLine.get("value") != null && nextLine.get("value").asText().equals("correct")) {
                trueNodeName = nextNodeName;
            } else {
                falseNodeName = nextNodeName;
            }
        }
        JsonNode node1 = nodeMap.get(trueNodeName);
        JsonNode node2 = nodeMap.get(falseNodeName);
        String firstValue = node1.get("value").asText();
        String secondValue =  node2.get("value").asText();
        bodyBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
        bodyBuilder.append("\n.to(\"");
        bodyBuilder.append(firstValue + "\")");
        bodyBuilder.append(".otherwise()");
        bodyBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
        bodyBuilder.append("\n.to(\"");
        bodyBuilder.append(secondValue + "\")");
        bodyBuilder.append("\n.end()");
    }
    public static void split(StringBuilder bodyBuilder, StringBuilder packageBuilder, String value) {
        packageBuilder.append("import crawler.Split;\n");
        bodyBuilder.append("\n.split().method(Split.class, \""+value+"\")");
    }
    public static void aggregate(StringBuilder bodyBuilder, StringBuilder packageBuilder, String value) {
        packageBuilder.append("import crawler.Aggregate;\n");
        bodyBuilder.append("\n.aggregate(header(\"test_correlation_key\"), new Aggregate()).completionSize(3)");
    }
    public static void mulitcast(StringBuilder bodyBuilder, String value, List<Edge<String>> edgeList, Iterator<String> it,  Map<String, JsonNode> lineMap, Map<String, JsonNode> nodeMap) {
        String endpoints = "";
        for (Edge<String> edge : edgeList) {
            String nextNodeName = edge.getDest();
            JsonNode node = nodeMap.get(nextNodeName);
            endpoints += node.get("value") + ",";
            it.next();
        }
        endpoints = StringUtil.substring(endpoints, 0, endpoints.length() - 1);
        bodyBuilder.append("\n.multicast().stopOnException().to("+endpoints+").end()");
    }
}

+ 8 - 3
src/main/resources/resource/SystemServiceFlowProcess.hbm.xml

@ -24,9 +24,14 @@
                <comment>模板编辑结果</comment>
            </column>
        </property>
        <property name="fileName" type="java.lang.String">
            <column name="file_name">
                <comment>生成文件存储名称</comment>
        <property name="flowResult" type="java.lang.String">
            <column name="flow_result">
                <comment>流程编辑结果</comment>
            </column>
        </property>
        <property name="flowId" type="java.lang.Integer">
            <column name="flow_id" length="11">
                <comment>流程ID</comment>
            </column>
        </property>
    </class>

+ 35 - 35
src/main/webapp/WEB-INF/ehr/jsp/common/indexJs.jsp

@ -408,41 +408,41 @@
    $(function () {
        if (window.history && window.history.pushState) {
            $(window).on('popstate', function () {
                var hashLocation = location.hash;
                var hashSplit = hashLocation.split("#!/");
                var hashName = hashSplit[1];
                if (hashName !== '') {
                    var hash = window.location.hash;
                    if (hash === '') {
                        $.ligerDialog.confirm('是否确认后退登出系统!', function (yes) {
                            if (yes) {
                                $.ajax({ //获取表的字段列表
                                    type: "POST",
                                    url: "${contextRoot}/system/logoutAction",
                                    dataType: "json",
                                    cache: false,
                                    success: function (data) {
                                        if (data.successFlg) {
                                            localStorage.removeItem("userRole");
                                            location.href = "${contextRoot}/"+data.data+"/loginPage";
                                        }
                                        else {
                                            $.ligerDialog.error(data.message);
                                        }
                                    },
                                    error: function (data) {
                                        $.ligerDialog.error("Status:" + data.status + "(" + data.statusText + ")");
                                    }
                                });
                            }
                        });
                    }
                }
            });
            window.history.pushState('forward', null, './indexPage');
        }
        <%--if (window.history && window.history.pushState) {--%>
            <%--$(window).on('popstate', function () {--%>
                <%--var hashLocation = location.hash;--%>
                <%--var hashSplit = hashLocation.split("#!/");--%>
                <%--var hashName = hashSplit[1];--%>
                <%--if (hashName !== '') {--%>
                    <%--var hash = window.location.hash;--%>
                    <%--if (hash === '') {--%>
                        <%--$.ligerDialog.confirm('是否确认后退登出系统!', function (yes) {--%>
                            <%--if (yes) {--%>
                                <%--$.ajax({ //获取表的字段列表--%>
                                    <%--type: "POST",--%>
                                    <%--url: "${contextRoot}/system/logoutAction",--%>
                                    <%--dataType: "json",--%>
                                    <%--cache: false,--%>
                                    <%--success: function (data) {--%>
                                        <%--if (data.successFlg) {--%>
                                            <%--localStorage.removeItem("userRole");--%>
                                            <%--location.href = "${contextRoot}/"+data.data+"/loginPage";--%>
                                        <%--}--%>
                                        <%--else {--%>
                                            <%--$.ligerDialog.error(data.message);--%>
                                        <%--}--%>
                                    <%--},--%>
                                    <%--error: function (data) {--%>
                                        <%--$.ligerDialog.error("Status:" + data.status + "(" + data.statusText + ")");--%>
                                    <%--}--%>
                                <%--});--%>
                            <%--}--%>
                        <%--});--%>
                    <%--}--%>
                <%--}--%>
            <%--});--%>
            <%--window.history.pushState('forward', null, './indexPage');--%>
        <%--}--%>
        isLogin();
        indexPage.init();

+ 2 - 2
src/main/webapp/WEB-INF/ehr/jsp/system/app/appJs.jsp

@ -30,11 +30,11 @@
                    status:appStatus
                },
                columns: [
                    {display: '应用名称', id: 'id', name: 'name', width: '15%'},
                    {display: '英文名', name: 'code', width: '10%'},
                    {display: '图标', name: 'icon', width: '10%',height:'50',align: 'center', render: function (rowdata, rowindex, value) {
                        return ' <div style="vertical-align:middle;"><img  style="width: 50px; height: 50px;"  src="${contextRoot}/app/read/'+ rowdata.icon+'" /></div>';
                    }},
                    {display: '应用名称', id: 'id', name: 'name', width: '15%'},
                    {display: '英文名', name: 'code', width: '10%'},
                    {display: '开发者', name: 'developer', width: '10%'},
                    {display: '状态', name: 'status', width: '10%',align: 'center', render: function (rowdata, rowindex, value) {
                        if(rowdata.status==1 ){

+ 4 - 1
src/main/webapp/WEB-INF/ehr/jsp/system/flow/flowJs.jsp

@ -45,7 +45,7 @@
                        display: '操作', name: 'operator', width: '40%', render: function (row) {
                        var html = '<div class="m-inline-buttons" style="width:350px;vertical-align:middle;">';
                        html += "<a class=\"m-btn\" style=\"padding-right:10px\" onclick=\"flow.showImage('${contextRoot}/app/read/"+row.chart+"')\">查看流程图</a>";
                        html += "<a class=\"m-btn\" style=\"padding-right:10px\" onclick=\"flow.showFlow('"+row.id+"')\">查看流程图</a>";
                        html += "<a class=\"m-btn-edit\" onclick=\"flow.editorDialog('"+row.id+"')\"></a>";
                        html += "<a class=\"m-btn-delete\" onclick=\"flow.delete('"+row.id+"')\"></a>";
                        html += '</div>';
@ -59,6 +59,9 @@
            });
        },
	    showFlow:function (id) {
		    indexPage.openChildPage("",'${contextRoot}/process/initial?flowId='+id);
	    },
        bindEvents: function () {
            var me = this;
            var flag = false;

+ 15 - 5
src/main/webapp/WEB-INF/ehr/jsp/system/process/process.jsp

@ -2,9 +2,19 @@
<%@include file="/WEB-INF/ehr/commons/jsp/commonInclude.jsp" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!--######用户管理页面Title设置######-->
<div class="container" style="width:1800px;">
    <div id="demo" style="margin:10px"></div>
    <input id="submit" type="button" class="btn" value='导出结果' onclick="Export()"/>
    <textarea id="result" row="6"></textarea>
<style>
	.back-box{
		overflow:hidden;
		padding:10px 0;
		text-align:center;
		border-bottom:1px solid #e1e1e1;
		line-height:30px;
	}
</style>
<div style="position:relative">
	<div class="back-box">
		<div id="div_back" class="back-box-btn l-button">返回</div>
		返回上一级目录
	</div>
	<div id="esb" class="GooFlow"></div>
</div>

+ 12 - 43
src/main/webapp/WEB-INF/ehr/jsp/system/process/processJs.jsp

@ -1,48 +1,17 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="utf-8" %>
<%@include file="/WEB-INF/ehr/commons/jsp/commonInclude.jsp" %>
<link rel="stylesheet" type="text/css" href="${contextRoot}/develop/lib/gooflow/goo/codebase/GooFlow2.css"/>
<link rel="stylesheet" type="text/css" href="${contextRoot}/develop/lib/gooflow/default.css"/>
<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/goo/data.js"></script>
<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/GooFunc.js"></script>
<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/json2.js"></script>
<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/goo/codebase/GooFlow.js"></script>
<link rel="stylesheet" type="text/css" href="${contextRoot}/develop/lib/gooflow/css/GooFlow.css"/>
<%--<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/js/jquery.min.js"></script>--%>
<%--<script type="text/javascript" src="${contextRoot}/develop/lib/ligerui/ligerui.min.js"></script>--%>
<script type="text/javascript" src="${contextRoot}/develop/lib/gooflow/js/GooFlow.js"></script>
<script type="text/javascript">
    var property = {
        width: 1600,
        height: 700,
        toolBtns: ["start round", "end round", "task round", "node", "chat", "state", "plug", "join", "fork", "complex mix"],
        haveHead: true,
        headBtns: ["new", "open", "save", "undo", "redo", "reload"], //如果haveHead=true,则定义HEAD区的按钮
        haveTool: true,
        haveGroup: true,
        useOperStack: true
    };
    var remark = {
        cursor: "选择指针",
        direct: "结点连线",
        start: "入口结点",
        "end": "结束结点",
        "task": "任务结点",
        node: "自动结点",
        chat: "决策结点",
        state: "状态结点",
        plug: "附加插件",
        fork: "分支结点",
        "join": "联合结点",
        "complex mix": "复合结点",
        group: "组织划分框编辑开关"
    };
    var demo;
    $(document).ready(function() {
        demo = $.createGooFlow($("#demo"), property);
        demo.setNodeRemarks(remark);
        //demo.onItemDel=function(id,type){
        //	return confirm("确定要删除该单元吗?");
        //}
        //  demo.loadData(jsondata);
 	$(function () {
		var esb = $('#esb').createGooFlow({},'${contextRoot}');
	    var id = "${flowId}";
	    var dataGetURL = "/esb/process/chart?flowId="+ id;
	    esb.loadData(dataGetURL);
	    $('#div_back').click(function () {
		    indexPage.loadPage('${contextRoot}/flow/initial');
	    })
    });
    var out;
    function Export() {
        document.getElementById("result").value = JSON.stringify(demo.exportData());
    }
</script>

+ 0 - 102
src/main/webapp/develop/lib/gooflow/GooFunc.js

@ -1,102 +0,0 @@
/*本系列框架中,一些用得上的小功能函数,一些UI必须使用到它们,用户也可以单独拿出来用*/
//获取一个DIV的绝对坐标的功能函数,即使是非绝对定位,一样能获取到
function getElCoordinate(dom) {
  var t = dom.offsetTop;
  var l = dom.offsetLeft;
  dom=dom.offsetParent;
  while (dom) {
    t += dom.offsetTop;
    l += dom.offsetLeft;
	dom=dom.offsetParent;
  }; return {
    top: t,
    left: l
  };
}
//兼容各种浏览器的,获取鼠标真实位置
function mousePosition(ev){
	if(!ev) ev=window.event;
    if(ev.pageX || ev.pageY){
        return {x:ev.pageX, y:ev.pageY};
    }
    return {
        x:ev.clientX + document.documentElement.scrollLeft - document.body.clientLeft,
        y:ev.clientY + document.documentElement.scrollTop  - document.body.clientTop
    };
}
//给DATE类添加一个格式化输出字串的方法
Date.prototype.format = function(format)   
{   
   var o = {   
      "M+" : this.getMonth()+1, //month  
      "d+" : this.getDate(),    //day  
      "h+" : this.getHours(),   //hour  
      "m+" : this.getMinutes(), //minute  
      "s+" : this.getSeconds(), //second  ‘
	  //quarter  
      "q+" : Math.floor((this.getMonth()+3)/3), 
      "S" : this.getMilliseconds() //millisecond  
   }   
   if(/(y+)/.test(format)) format=format.replace(RegExp.$1,(this.getFullYear()+"").substr(4 - RegExp.$1.length));   
    for(var k in o)if(new RegExp("("+ k +")").test(format))   
      format = format.replace(RegExp.$1,   
        RegExp.$1.length==1 ? o[k] :    
          ("00"+ o[k]).substr((""+ o[k]).length));   
    return format;   
}
//JS]根据格式字符串分析日期(MM与自动匹配两位的09和一位的9)
//alert(getDateFromFormat(sDate,sFormat));
function getDateFromFormat(dateString,formatString){
	var regDate = /\d+/g;
	var regFormat = /[YyMmdHhSs]+/g;
	var dateMatches = dateString.match(regDate);
	var formatmatches = formatString.match(regFormat);
	var date = new Date();
	for(var i=0;i<dateMatches.length;i++){
		switch(formatmatches[i].substring(0,1)){
			case 'Y':
			case 'y':
				date.setFullYear(parseInt(dateMatches[i]));break;
			case 'M':
				date.setMonth(parseInt(dateMatches[i])-1);break;
			case 'd':
				date.setDate(parseInt(dateMatches[i]));break;
			case 'H':
			case 'h':
				date.setHours(parseInt(dateMatches[i]));break;
			case 'm':
				date.setMinutes(parseInt(dateMatches[i]));break;
			case 's':
				date.setSeconds(parseInt(dateMatches[i]));break;
		}
	}
	return date;
}
//货币分析成浮点数
//alert(parseCurrency("¥1,900,000.12"));
function parseCurrency(currentString){
	var regParser = /[\d\.]+/g;
	var matches = currentString.match(regParser);
	var result = '';
	var dot = false;
	for(var i=0;i<matches.length;i++){
		var temp = matches[i];
		if(temp =='.'){
			if(dot) continue;
		}
		result += temp;
	}
	return parseFloat(result);
}
//将#XXXXXX颜色格式转换为RGB格式,并附加上透明度
function brgba(hex, opacity) {
    if( ! /#?\d+/g.test(hex) ) return hex; //如果是“red”格式的颜色值,则不转换。//正则错误,参考后面的PS内容
    var h = hex.charAt(0) == "#" ? hex.substring(1) : hex,
        r = parseInt(h.substring(0,2),16),
        g = parseInt(h.substring(2,4),16),
        b = parseInt(h.substring(4,6),16),
        a = opacity;
    return "rgba(" + r + "," + g + "," + b + "," + a + ")";
}

+ 734 - 0
src/main/webapp/develop/lib/gooflow/css/GooFlow.css

@ -0,0 +1,734 @@
/**
* 2015-12-03 下载于 17素材: http://www.17sucai.com/pins/3175.html 的演示代码。
* 
* 更新记录:
* 2016-04-19--sam--1. 重写大部分样式,格式化样式列表,去大部分除针对png图片的依赖。
*/
body{
    color: #333;
}
.GooFlow{
    width: 100%;
    overflow: hidden;
    background:#fff;
    font: 12px Arial, Helvetica, sans-serif;
    -moz-user-select:none;
    -webkit-user-select:none;
    -ms-user-select:none;
    -o-user-select:none;
}
.GooFlow_flowChart,.GooFlow_tool{
    overflow: hidden;
    float: left;
}
.GooFlow_flowChart i,.GooFlow_tool i{
    width: 50px;
    height: 60px;
    display: block;
    margin-left:20px;
    float: left;
    cursor: pointer;
}
/*头部*/
.GooFlow_top_box{
    overflow: hidden;
    padding: 10px 0;
}
.GooFlow_head label{
    font-weight: bold;
    width: 200px;
    text-align: center;
    float: left;
    color: #fff;
    overflow: hidden;
    font-size:18px;
}
.GooFlow_head span {
    float: left;
    height: 22px;
    width: 0px;
    overflow: hidden;
    border-left: #9AC6FF 1px solid;
    border-right: whiteFFF 1px solid;
    margin: 0px 1px;
}
/*工具栏*/
.GooFlow_tool i{
    margin-bottom: 2px;
}
.GooFlow_tool_btndown{
    overflow: hidden;
    background: #49A2DF;
    border-radius: 3px;
}
/*工作区-端点*/
.GooFlow_cont_box{
    border-top: 1px solid #e1e1e1;
    overflow: hidden;
    height: 600px;
}
.GooFlow_left,.GooFlow_right{
    width:202px;
    float:left;
    height:100%;
    overflow:hidden;
}
.GooFlow_right{
    float: right;
}
.GooFlow_app{
    font-size: 14px;
    border-left: 1px solid #e1e1e1;
    border-right: 1px solid #e1e1e1;
}
.GooFlow_app_head{
    overflow: hidden;
    background: #f0f0f0;
    padding: 10px;
}
.GooFlow_app_tit{
    font-size: 18px;
    font-size: 14px;
    height: 40px;
    line-height: 40px;
}
.GooFlow_app_search{
    border: 1px solid #e1e1e1;
    background: #fff;
    height: 30px;
    line-height: 30px;
    position: relative;
}
.GooFlow_app_search_input{
    border: none;
    background: none;
    width: 150px;
    height: 30px;
    line-height: 30px;
    text-indent: 10px;
    outline:none;
}
.GooFlow_search_btn{
    position: absolute;
    background:url(../img/sprite.tool.png);
    background-position: 0px -288px;
    width: 30px;
    height: 30px;
    border: none;
    /*cursor: pointer;*/
    outline:none;
    display: inline-block;
}
.GooFlow_app_cont{
    width: 250px;
    height: 500px;
    overflow: auto;
}
.GooFlow_app_list{
    width: 202px;
    background: #fff;
    list-style: none;
}
.GooFlow_left .GooFlow_app_list_item{
    border-top: 1px solid #e1e1e1;
}
.GooFlow_app_list_item:last-child{
    border-bottom: 1px solid #e1e1e1;
}
.GooFlow_app_list_tit{
    padding: 10px;
    background: #fff;
    position: relative;
    overflow: hidden;
    cursor: pointer;
}
.search_result{
    list-style: none;
    padding: 10px 0 0 5px;
    display: none;
    overflow: hidden;
}
.GooFlow_app_list_tit:after{
    content:'';
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -21px;
    width: 11px;
    height: 11px;
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
}
.GooFlow_app_list_item.selected .GooFlow_app_list_tit{
    background: #F5F8FA;
}
.GooFlow_app_list_item.selected .GooFlow_app_list_box{
    display: block;
}
.GooFlow_app_list_item.selected .GooFlow_app_list_tit:after{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px 0px;
}
.GooFlow_left .GooFlow_app_list_box,.GooFlow_right .GooFlow_app_list_box{
    padding: 10px 0 10px 5px;
    overflow: hidden;
    float: left;
}
.GooFlow_left .GooFlow_app_list_box{
    border-bottom: 1px solid #e1e1e1;
}
.GooFlow_left .GooFlow_app_list_box{
    display: none;
    width: 100%;
}
.GooFlow_app_item{
    width: 60px;
    height: 80px;
    overflow: hidden;
    float: left;
    margin:0 5px 5px 0;
    cursor: move
}
.GooFlow_app_item:hover{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -410px;
}
.GooFlow_app_item.active{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -410px;
}
.GooFlow_left .app_icon,.GooFlow_right .app_icon{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -180px;
    width: 26px;
    height: 26px;
    margin: 8px auto 0;
}
.GooFlow_right .app_icon{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -252px;
}
.app_name{
    padding: 10px 0;
    font-size: 12px;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    text-align: center;
}
/*工作区-控制器*/
/*工作区-画布*/
.GooFlow_work {
    margin: 0 202px;
    position: relative;
    width: inherit;
    height: inherit;
    overflow: auto;
}
.GooFlow_work .GooFlow_work_inner {
    width: 1920px;
    height: 700px;
    position: relative;
    overflow: hidden;
}
.GooFlow_work .GooFlow_work_group {
    position: absolute;
    overflow: hidden;
    top: 0px;
    left: 0px
}
/*组织划分框*/
.GooFlow_area {
    position: absolute;
    overflow: hidden;
}
.GooFlow_area.lock {
    cursor: default;
}
.GooFlow_area .bg {
    cursor: move;
    filter: Alpha(Opacity=30);
    -moz-opacity: 0.3;
    opacity: 0.3;
}
.GooFlow_area label {
    cursor: text;
    top: 1px;
    left: 1px;
    position: absolute;
    display: block;
    font-size: 12px;
    text-indent: 18px;
    height: 18px;
    line-height: 18px
}
.GooFlow_area i{
    font-size: 1em;
    display: block;
    height: 11px;
    width: 11px;
    top: 1px;
    left: 1px;
    padding: 2px;
    position: absolute;
    cursor: pointer;
    border-top: white 1px solid;
    border-left: white 1px solid;
    border-bottom: gray 1px solid;
    border-right: gray 1px solid;
}
.GooFlow_area i:before{
    content: "\f192";
}
.GooFlow_work .area_red .bg {
    border: 1px solid red;
    background-color: #FF7865
}
.GooFlow_work .area_red{
    color: red;
}
.GooFlow_work .area_yellow .bg {
    border: 1px solid #CD925A;
    background-color: #FFD564
}
.GooFlow_work .area_yellow{
    color: #AA7600;
}
.GooFlow_work .area_blue .bg {
    border: 1px solid #347BB1;
    background-color: #549CDE
}
.GooFlow_work .area_blue{
    color: #347BB1;
}
.GooFlow_work .area_green .bg {
    border: 1px solid green;
    background-color: #84CA04
}
.GooFlow_work .area_green{
    color: green;
}
/*svg、vml样式*/
v\:group,v\:rect,v\:imagedata,v\:oval,v\:line,v\:polyline,v\:stroke,v\:textbox {
    display:inline-block;
    background:transparent
}
.GooFlow_work svg{display:block;position:absolute}
.GooFlow_work v\:group{position:relative;display:block}
.GooFlow_work v\:group v\:line{overflow:visible}
.GooFlow_work v\:group v\:polyline{overflow:visible}
.GooFlow_work v\:group div {
    cursor: text;
    position: absolute;
    overflow: visible;
    display: inline;
    float: left;
    white-space: nowrap
}
.GooFlow_work .draw {
    color: #ff3300
}
/*方形元素(可拉伸的边缘)*/
.GooFlow div .rs_right {
    overflow: hidden;
    position: absolute;
    right: -1px;
    top: -1px;
    height: 100%;
    width: 6px;
    cursor: w-resize
}
.GooFlow div .rs_bottom {
    overflow: hidden;
    position: absolute;
    left: -1px;
    bottom: -1px;
    width: 100%;
    height: 6px;
    cursor: n-resize
}
#node-ghost{
    position: absolute;
    opacity: 0.5;
}
.GooFlow div .rs_rb {
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 9px;
    height: 9px;
    overflow: hidden;
    cursor: nw-resize;
    background: url(../img/gooflow_tip.png) no-repeat 0px -8px;
}
.GooFlow div .rs_close {
    z-index: 9;
    cursor: pointer;
    position: absolute;
    right: 0px;
    top: 50%;
    transform: translate(50%,-50%);
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -42px;
    width: 20px;
    height: 20px;
}
/*遮罩层*/
.GooFlow .rs_ghost {
    position: absolute;
    display: none;
    filter: Alpha(Opacity=60);
    -moz-opacity: 0.6;
    opacity: 0.6;
    z-index: 10
}
.GooFlow textarea {
    position: absolute;
    border: #5068AE 1px solid;
    display: none;
    font-size: 14px;
    overflow-y: visible;
    width: 200px;
    padding: 10px;
    z-index: 10001;
    /*top: 50%;*/
    /*left: 50%;*/
    /*transform: translate(-50%,-50%);*/
}
/*线条工具栏*/
.GooFlow .GooFlow_line_oper {
    width: 80px;
    height: 15px;
    background-color: #D8E8FC;
    border: #7DA2CE 1px solid;
    position: absolute;
    filter: Alpha(Opacity=50);
    -moz-opacity: 0.5;
    opacity: 0.5;
    z-index: 10000;
}
.GooFlow .GooFlow_line_move {
    filter: Alpha(Opacity=50);
    -moz-opacity: 0.5;
    opacity: 0.5;
    overflow: hidden;
    position: absolute;
    z-index: 9999
}
.GooFlow .GooFlow_line_oper b {
    display: inline-block;
    width: 15px;
    height: 15px;
    margin-left: 2px;
    cursor: pointer
}
.GooFlow .GooFlow_line_oper .b_l1 {
    background: url(../img/GooFlow_line_oper.png) no-repeat 1px 1px
}
.GooFlow .GooFlow_line_oper .b_l2 {
    background: url(../img/GooFlow_line_oper.png) no-repeat 1px -14px
}
.GooFlow .GooFlow_line_oper .b_l3 {
    background: url(../img/GooFlow_line_oper.png) no-repeat 1px -29px
}
.GooFlow .GooFlow_line_oper .b_x {
    background: url(../img/GooFlow_line_oper.png) no-repeat 1px -44px;
    margin-left: 10px
}
.GooFlow .GooFlow_line_oper b[class^="b_"]:hover{
    background-color: #7DA2CE;
}
/**
* 图标头部工具栏
*/
/*保存*/
.GooFlow_top_box .ico_save{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -70px;
}
.GooFlow_top_box .ico_save:hover{
    background-position: 0px -630px;
}
/*撤销*/
.GooFlow_top_box .ico_undo {
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -140px;
}
.GooFlow_top_box .ico_undo:hover{
    background-position: 0px -210px;
}
/*重做*/
.GooFlow_top_box .ico_redo{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -280px;
}
.GooFlow_top_box .ico_redo:hover{
    background-position: 0px -350px;
}
/*指针*/
.GooFlow_top_box .ico_cursor{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -1120px;
}
.GooFlow_top_box .ico_cursor:hover,.GooFlow_top_box .ico_cursor.active{
    background-position: 0px -1190px;
}
/*连线*/
.GooFlow_top_box .ico_direct{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -700px;
}
.GooFlow_top_box .ico_direct:hover,.GooFlow_tool_btndown .ico_direct{
    background-position: 0px -770px;
}
/*判断*/
.GooFlow_top_box .ico_state{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -840px;
}
.GooFlow_top_box .ico_state:hover,.GooFlow_tool_btndown .ico_state{
    background-position: 0px -910px;
}
/*循环*/
.GooFlow_top_box .ico_complex{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -980px;
}
.GooFlow_top_box .ico_complex:hover,.GooFlow_tool_btndown .ico_complex{
    background-position: 0px -1050px;
}
/*聚合*/
.GooFlow_top_box .ico_join{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px 0px;
}
.GooFlow_top_box .ico_join:hover,.GooFlow_tool_btndown .ico_join{
    background-position: 0px -560px;
}
/*分流*/
.GooFlow_top_box .ico_fork{
    background-image: url(../img/sprite.head-tool.png);
    background-position: 0px -420px;
}
.GooFlow_top_box .ico_fork:hover,.GooFlow_tool_btndown .ico_fork{
    background-position: 0px -490px;
}
/**
* 工作区图标
*/
.GooFlow .GooFlow_item{
    position: absolute;
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px 0px;
    width: 140px;
    height: 50px;
    cursor: move;
    
}
.GooFlow .GooFlow_item .line-begin{
    overflow: hidden;
    position: absolute;
    top: -15px;
    left: -30px;
}
.GooFlow .GooFlow_item.item-mark{
    border: 1px dashed #00b7ee;
}
.GooFlow .GooFlow_item .line-begin-icon{
    background: url("../img/arrow.png");
    background-size: 100%;
    width: 21px;
    height: 12px;
    position: absolute;
    opacity: 0.5;
    cursor: crosshair;
}
.GooFlow .GooFlow_item .line-begin-icon:hover{
    opacity: 1;
}
.GooFlow .GooFlow_item .line-begin-icon.top{
    left: 50%;
    transform: translateX(-50%);
    top: 0px;
}
.GooFlow .GooFlow_item .line-begin-icon.bottom{
    left: 50%;
    transform: translateX(-50%) rotate(180deg);
    bottom: 0px;
}
.GooFlow .GooFlow_item .line-begin-icon.left{
    top: 50%;
    transform: translateY(-50%) rotate(-90deg);
    left: 0px;
}
.GooFlow .GooFlow_item .line-begin-icon.right{
    top: 50%;
    transform: translateY(-50%) rotate(90deg);
    right: 0px;
}
.GooFlow .node-task{
    position: absolute;
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px 0px;
    width: 140px;
    height: 50px;
}
.GooFlow .GooFlow_item_cont{
    position: absolute;
    left: 0;
    width: 100%;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: move;
}
.GooFlow .node-task .GooFlow_item_cont,.GooFlow .node-plug .GooFlow_item_cont{
    justify-content:flex-start;
    padding-left:10px;
}
.GooFlow_item .GooFlow_item_cont i{
    width: 26px;
    height: 26px;
    display: inline-block;
}
.GooFlow_item_txt{
    display: inline-block;
    margin-left: 10px;
}
/*端点*/
.GooFlow_item .ico_task{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -180px;
}
/*转换器*/
.GooFlow_item .ico_plug{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -252px;
}
.GooFlow .node-plug{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -120px;
    width: 140px;
    height: 50px;
}
/*判断*/
.GooFlow_item .ico_state{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -72px;
}
.GooFlow .node-state{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -250px;
    width: 120px;
    height: 70px;
}
/*循环*/
.GooFlow_item .ico_complex{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -216px;
}
.GooFlow .node-complex{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -330px;
    width: 70px;
    height: 70px;
}
/*聚合*/
.GooFlow_item .ico_join{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -108px;
}
.GooFlow .node-join{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -180px;
    width: 90px;
    height: 60px;
}
/*分流*/
.GooFlow_item .ico_fork{
    background-image: url(../img/sprite.tool.png);
    background-position: 0px -144px;
}
.GooFlow .node-fork{
    background-image: url(../img/sprite.work-are.png);
    background-position: 0px -60px;
    width: 120px;
    height: 50px;
}
.node-error{
    border:2px dashed #f00;
}
.line-error{
    stroke:#f00
}
.file-box{
    position: absolute;
    top: 20px;
    padding-left: 30px;
    left: 50px;
    z-index: 9999;
}
.file-box.error{
    border:2px dashed #f00;
}
.file-box input{
    margin: 20px;
    border: none;
    background: none;
    padding: 5px;
    border-bottom: 1px solid #333;
    
}
.special-error{
    border:2px dashed #f00;
}

+ 0 - 19
src/main/webapp/develop/lib/gooflow/default.css

@ -1,19 +0,0 @@
/***** CSS Reset *****/
/**解决所有浏览器兼容性的重置样式代码**/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
	margin: 0;
	padding: 0;
	border: 0;
	outline: 0;
	font-size: 100%;
	vertical-align: baseline;
	background: transparent;
}

BIN
src/main/webapp/develop/lib/gooflow/goo/GooFlow_line_oper.png


BIN
src/main/webapp/develop/lib/gooflow/goo/Thumbs.db


BIN
src/main/webapp/develop/lib/gooflow/goo/bullet_blue.png


Файловите разлики са ограничени, защото са твърде много
+ 0 - 1
src/main/webapp/develop/lib/gooflow/goo/child.js


+ 0 - 138
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.css

@ -1,138 +0,0 @@
v\:group,v\:rect,v\:imagedata,v\:oval,v\:line,v\:polyline,v\:stroke,v\:textbox { display:inline-block;background:transparent }
.GooFlow{
	background:#D2E1F0 url(img/gooflow_bg.png) repeat-x;border:#99BBE8 1px solid;font: 12px Arial, Helvetica, sans-serif;
	-moz-user-select:none;-webkit-user-select:none;
}
.GooFlow_head{clear:both;height:22px;padding:1px}
.GooFlow_head label{
	font-weight:bold;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;height:15px;margin:2px;border:#B7C8D7 1px solid;border-right:#E9F4FA 1px solid;border-bottom:#E9F4FA 1px solid;padding:1px 1px 1px 12px;width:160px;text-align:center;
	background: url(img/gooflow_icon.png) no-repeat -137px 1px;float:left;color:#15428B;border-radius:3px;overflow:hidden;
}
.GooFlow_head span{float:left;height:22px;width:0px;overflow:hidden;border-left:#9AC6FF 1px solid;border-right:#FFFFFF 1px solid;margin:0px 3px;}
.GooFlow_head_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:0px 3px;float:left;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_head_btn i{display:inline-block;overflow:hidden;width:18px;height:18px;border:0px;}
.GooFlow_head_btn:hover{
	border-radius:2px;width:20px;height:20px;
	padding:0px;border:#8B7654 1px solid; background:url(img/gooflow_btn_bg.png) repeat-x;
}
.GooFlow_head_btn:hover i{border:#F6A32D 1px solid;border-top-color:#B1905D;margin:0px;border-radius:1px}
.GooFlow_tool{
	border:#B7C8D7 1px solid;float:left;margin:0px 3px;overflow:hidden;clear:left;border-radius:3px
}
.GooFlow_tool_div{border:#E9F4FA 1px solid;overflow:hidden;border-radius:2px;width:24px;}
.GooFlow_tool span{height:0px;overflow:hidden;border-bottom:#9AC6FF 1px solid;border-top:#FFFFFF 1px solid;margin:3px 1px;clear:both;display:block;}
.GooFlow_tool_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:3px 0px;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_tool_btn i{display:block;overflow:hidden;width:18px;height:18px;border:0px}
.GooFlow_tool_btn:hover{border-radius:3px;padding:0px;border:#8E9DA6 1px solid;width:20px;height:20px;}
.GooFlow_tool_btn:hover i{border:#F5FAFC 1px solid;border-radius:2px}
.GooFlow_tool_btndown{
	width:20px;height:20px;cursor:default;margin:3px 1px;outline:none;blr:expression(this.onFocus=this.blur());
	border-radius:3px;padding:0px;border:#8B7654 1px solid; background:url(img/gooflow_btn_bg.png) repeat-x;display:block;
}
.GooFlow_tool_btndown i{
	display:block;overflow:hidden;width:14px;height:14px;border:#F6A32D 1px solid;
	border-top-color:#B1905D;margin:0px;border-radius:2px;
}
.GooFlow_work{float:right;margin:0px 3px 3px 0px;border:#99B1CE 1px solid;position:relative;overflow:scroll}
.GooFlow_work .GooFlow_work_inner{background-image:url(img/gooflow_blank.gif);position:relative;overflow:hidden}
.GooFlow_work .GooFlow_work_group{cursor:default;position:absolute;overflow:hidden;top:0px;left:0px}
.GooFlow_area{position:absolute;overflow:hidden;}
.GooFlow_area .lock{cursor:default;}
.GooFlow_area .bg{cursor:move;filter:Alpha(Opacity=30);-moz-opacity:0.3;opacity: 0.3;}
.GooFlow_work .lock .bg{cursor:default;}
.GooFlow_area label{cursor:text;top:1px;left:1px;position:absolute;display:block;font-size:12px;text-indent:18px;height:18px;line-height:18px}
.GooFlow_work .lock label{cursor:default;}
.GooFlow_area i{display:block;height:18px;widht:18px;top:0px;left:0px;position:absolute;cursor:pointer}
.GooFlow_work .area_red .bg{border:1px solid red;background-color:#FF7865}
.GooFlow_work .area_red label{color:red;background:url(img/gooflow_bullet.png) no-repeat 1px 1px}
.GooFlow_work .area_yellow .bg{border:1px solid #CD925A;background-color:#FFD564}
.GooFlow_work .area_yellow label{color:#FFBA1D;background:url(img/gooflow_bullet.png) no-repeat 1px -16px}
.GooFlow_work .area_blue .bg{border:1px solid #347BB1;background-color:#549CDE}
.GooFlow_work .area_blue label{color:#347BB1;background:url(img/gooflow_bullet.png) no-repeat 1px -33px}
.GooFlow_work .area_green .bg{border:1px solid green;background-color:#84CA04}
.GooFlow_work .area_green label{color:green;background:url(img/gooflow_bullet.png) no-repeat 1px -50px}
.GooFlow_work svg{display:block;position:absolute}
.GooFlow_work v\:group{position:relative;display:block}
.GooFlow_work v\:group v\:line{overflow:visible}
.GooFlow_work v\:group v\:polyline{overflow:visible}
.GooFlow_work v\:group div{cursor:text;position:absolute;overflow:visible;display:inline;float:left;white-space: nowrap}
.GooFlow_work .draw{color:#ff3300}
.GooFlow_item{
	position:absolute;background:#DDE7F4 url(img/gooflow_btn_bg.png) repeat-x 0px -72px;border:#7DA2CE solid 1px;
	border-radius:3px;color:#15428B;background-color:#C1DCFC;
	box-shadow:1px 1px 2px rgba(148,170,194,2);-webkit-box-shadow:1px 1px 2px rgba(148,170,194,2);-moz-box-shadow:1px 1px 2px rgba(148,170,194,2);
}
.GooFlow table{border:1px #EBF4FD solid;padding:0px;border-radius:2px}
.GooFlow td{ vertical-align:middle;text-align:center;padding:0px;cursor:default;word-wrap: break-word;word-break:break-all}
.GooFlow .ico{width:18px;cursor:move}
.GooFlow i{display:block;width:18px;height:18px;overflow:hidden;}
.GooFlow .item_round{background:url(img/gooflow_bg.png) repeat-x;border-radius:11px;border:#7DA2CE solid 1px;width:22px;height:22px; overflow:visible}
.GooFlow .item_round table{border:0px;padding:2px;width:22px;height:22px}
.GooFlow .item_round .span{
	display:block;text-align:center; position:absolute;top:24px;left:-28px;width:80px;overflow:visible;text-align:center;
	padding:0px;cursor:default;word-wrap: break-word;word-break:break-all
}
.GooFlow .item_mix{background:#C2DB4E;}
.GooFlow div .rs_right{overflow:hidden;position:absolute;right:-1px;top:-1px;height:100%;width:6px;cursor:w-resize}
.GooFlow div .rs_bottom{overflow:hidden;position:absolute;left:-1px;bottom:-1px;width:100%;height:6px;cursor:n-resize}
.GooFlow div .rs_rb{
	position:absolute;right:-1px;bottom:-1px;width:9px;height:9px;overflow:hidden;cursor:nw-resize;background:url(img/gooflow_tip.png) no-repeat 0px -8px;
}
.GooFlow div .rs_close{
	position:absolute;right:1px;top:1px;width:7px;height:7px;overflow:hidden;cursor:pointer;background:url(img/gooflow_tip.png) no-repeat 0px 0px
}
.GooFlow .rs_ghost{
	position:absolute;display:none;overflow:hidden;border:#8EA4C1 1px dashed; background:#D9E8FB;
	filter:Alpha(Opacity=60);-moz-opacity:0.6;opacity: 0.6;z-index:10
}
.GooFlow .item_focus{border:#5068AE 1px solid}
.GooFlow .item_mark{border:#ff3300 1px solid}
.GooFlow .item_mark td{cursor:crosshair}
.GooFlow textarea{position:absolute;border:#5068AE 1px solid;display:none;font-size:12px;overflow-y:visible;width:100px;z-index:10001}
.GooFlow .GooFlow_line_oper{
	width:70px;height:15px;background-color:#D8E8FC;border:#7DA2CE 1px solid;position:absolute;
	filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity: 0.5;z-index:10000;
}
.GooFlow .GooFlow_line_mp{
	width:9px;height:9px;filter:Alpha(Opacity=40);-moz-opacity:0.4;opacity:0.4;overflow:hidden;
	position:absolute;z-index:9999;background:#333;cursor:crosshair
}
.GooFlow .GooFlow_line_move{filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity:0.5;overflow:hidden;position:absolute;z-index:9999;background:url(0) no-repeat}
.GooFlow .GooFlow_line_oper i{display:inline-block;width:15px;height:15px;margin-left:2px;cursor:pointer}
.GooFlow .b_l1{background:url(img/GooFlow_line_oper.png) no-repeat 1px 1px}
.GooFlow .b_l2{background:url(img/GooFlow_line_oper.png) no-repeat 1px -14px}
.GooFlow .b_l3{background:url(img/GooFlow_line_oper.png) no-repeat 1px -29px}
.GooFlow .b_x{background:url(img/GooFlow_line_oper.png) no-repeat 1px -44px;margin-left:10px}
.GooFlow .ico_cursor{background:url(img/gooflow_icon.png) no-repeat 2px -20px}
.GooFlow .ico_start{background:url(img/gooflow_icon.png) no-repeat -19px -20px}
.GooFlow .ico_end{background:url(img/gooflow_icon.png) no-repeat -39px -20px}
.GooFlow .ico_fork{background:url(img/gooflow_icon.png) no-repeat -59px -20px}
.GooFlow .ico_join{background:url(img/gooflow_icon.png) no-repeat -78px -20px}
.GooFlow .ico_direct{background:url(img/gooflow_icon.png) no-repeat -137px -20px}
.GooFlow .ico_group{background:url(img/gooflow_icon.png) no-repeat -96px -20px}
.GooFlow .ico_complex{background:url(img/gooflow_icon.png) no-repeat -116px -20px}
.GooFlow .ico_node{background:url(img/gooflow_icon.png) no-repeat -19px -45px}
.GooFlow .ico_task{background:url(img/gooflow_icon.png) no-repeat 2px -45px}
.GooFlow .ico_chat{background:url(img/gooflow_icon.png) no-repeat -38px -45px}
.GooFlow .ico_state{background:url(img/gooflow_icon.png) no-repeat -59px -45px}
.GooFlow .ico_plug{background:url(img/gooflow_icon.png) no-repeat -135px -45px}
.GooFlow .ico_menu{background:url(img/gooflow_icon.png) no-repeat 1px -65px}
.GooFlow .ico_sound{background:url(img/gooflow_icon.png) no-repeat -18px -65px}
.GooFlow .ico_topo{background:url(img/gooflow_icon.png) no-repeat -117px -45px}
.GooFlow .ico_open{background:url(img/gooflow_icon.png) no-repeat -19px 1px}
.GooFlow .ico_new{background:url(img/gooflow_icon.png) no-repeat 2px 1px}
.GooFlow .ico_reload{background:url(img/gooflow_icon.png) no-repeat -97px 1px}
.GooFlow .ico_save{background:url(img/gooflow_icon.png) no-repeat -39px 1px}
.GooFlow .ico_undo{background:url(img/gooflow_icon.png) no-repeat -58px 1px}
.GooFlow .ico_redo{background:url(img/gooflow_icon.png) no-repeat -78px 1px}

+ 0 - 135
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.css.bak

@ -1,135 +0,0 @@
v\:group,v\:rect,v\:imagedata,v\:oval,v\:line,v\:polyline,v\:stroke,v\:textbox { display:inline-block;background:transparent }
.GooFlow{
	background:#D2E1F0 url(img/gooflow_bg.png) repeat-x;border:#99BBE8 1px solid;font: 12px Arial, Helvetica, sans-serif;
	-moz-user-select:none;-webkit-user-select:none;
}
.GooFlow_head{clear:both;height:22px;padding:1px}
.GooFlow_head label{
	font-weight:bold;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;height:15px;margin:2px;border:#B7C8D7 1px solid;border-right:#E9F4FA 1px solid;border-bottom:#E9F4FA 1px solid;padding:1px 1px 1px 12px;width:160px;text-align:center;
	background: url(img/gooflow_icon.png) no-repeat -137px 1px;float:left;color:#15428B;border-radius:3px;overflow:hidden;
}
.GooFlow_head span{float:left;height:22px;width:0px;overflow:hidden;border-left:#9AC6FF 1px solid;border-right:#FFFFFF 1px solid;margin:0px 3px;}
.GooFlow_head_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:0px 3px;float:left;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_head_btn i{display:inline-block;overflow:hidden;width:18px;height:18px;border:0px;}
.GooFlow_head_btn:hover{
	border-radius:2px;width:20px;height:20px;
	padding:0px;border:#8B7654 1px solid; background:url(img/gooflow_btn_bg.png) repeat-x;
}
.GooFlow_head_btn:hover i{border:#F6A32D 1px solid;border-top-color:#B1905D;margin:0px;border-radius:1px}
.GooFlow_tool{
	border:#B7C8D7 1px solid;float:left;margin:0px 3px;overflow:hidden;clear:left;border-radius:3px
}
.GooFlow_tool_div{border:#E9F4FA 1px solid;overflow:hidden;border-radius:2px;width:24px;}
.GooFlow_tool span{height:0px;overflow:hidden;border-bottom:#9AC6FF 1px solid;border-top:#FFFFFF 1px solid;margin:3px 1px;clear:both;display:block;}
.GooFlow_tool_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:3px 0px;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_tool_btn i{display:block;overflow:hidden;width:18px;height:18px;border:0px}
.GooFlow_tool_btn:hover{border-radius:3px;padding:0px;border:#8E9DA6 1px solid;width:20px;height:20px;}
.GooFlow_tool_btn:hover i{border:#F5FAFC 1px solid;border-radius:2px}
.GooFlow_tool_btndown{
	width:20px;height:20px;cursor:default;margin:3px 1px;outline:none;blr:expression(this.onFocus=this.blur());
	border-radius:3px;padding:0px;border:#8B7654 1px solid; background:url(img/gooflow_btn_bg.png) repeat-x;display:block;
}
.GooFlow_tool_btndown i{
	display:block;overflow:hidden;width:14px;height:14px;border:#F6A32D 1px solid;
	border-top-color:#B1905D;margin:0px;border-radius:2px;
}
.GooFlow_work{float:right;margin:0px 3px 3px 0px;border:#99B1CE 1px solid;position:relative;overflow:scroll}
.GooFlow_work .GooFlow_work_inner{background-image:url(img/gooflow_blank.gif);position:relative;overflow:hidden}
.GooFlow_work .GooFlow_work_group{cursor:default;position:absolute;overflow:hidden;top:0px;left:0px}
.GooFlow_area{position:absolute;overflow:hidden;}
.GooFlow_area .lock{cursor:default;}
.GooFlow_area .bg{cursor:move;filter:Alpha(Opacity=30);-moz-opacity:0.3;opacity: 0.3;}
.GooFlow_work .lock .bg{cursor:default;}
.GooFlow_area label{cursor:text;top:1px;left:1px;position:absolute;display:block;font-size:12px;text-indent:18px;height:18px;line-height:18px}
.GooFlow_work .lock label{cursor:default;}
.GooFlow_area i{display:block;height:18px;widht:18px;top:0px;left:0px;position:absolute;cursor:pointer}
.GooFlow_work .area_red .bg{border:1px solid red;background-color:#FF7865}
.GooFlow_work .area_red label{color:red;background:url(img/gooflow_bullet.png) no-repeat 1px 1px}
.GooFlow_work .area_yellow .bg{border:1px solid #CD925A;background-color:#FFD564}
.GooFlow_work .area_yellow label{color:#FFBA1D;background:url(img/gooflow_bullet.png) no-repeat 1px -16px}
.GooFlow_work .area_blue .bg{border:1px solid #347BB1;background-color:#549CDE}
.GooFlow_work .area_blue label{color:#347BB1;background:url(img/gooflow_bullet.png) no-repeat 1px -33px}
.GooFlow_work .area_green .bg{border:1px solid green;background-color:#84CA04}
.GooFlow_work .area_green label{color:green;background:url(img/gooflow_bullet.png) no-repeat 1px -50px}
.GooFlow_work svg{display:block;position:absolute}
.GooFlow_work v\:group{position:relative;display:block}
.GooFlow_work v\:group v\:line{overflow:visible}
.GooFlow_work v\:group v\:polyline{overflow:visible}
.GooFlow_work v\:group div{cursor:text;position:absolute;overflow:visible;display:inline;float:left;white-space: nowrap}
.GooFlow_work .draw{color:#ff3300}
.GooFlow_item{
	position:absolute;background:#DDE7F4 url(img/gooflow_btn_bg.png) repeat-x 0px -72px;border:#7DA2CE solid 1px;
	border-radius:3px;color:#15428B;background-color:#C1DCFC;
	box-shadow:1px 1px 2px rgba(148,170,194,2);-webkit-box-shadow:1px 1px 2px rgba(148,170,194,2);-moz-box-shadow:1px 1px 2px rgba(148,170,194,2);
}
.GooFlow table{border:1px #EBF4FD solid;padding:0px;border-radius:2px}
.GooFlow td{ vertical-align:middle;text-align:center;padding:0px;cursor:default;word-wrap: break-word;word-break:break-all}
.GooFlow .ico{width:18px;cursor:move}
.GooFlow i{display:block;width:18px;height:18px;overflow:hidden;}
.GooFlow .item_round{background:url(img/gooflow_bg.png) repeat-x;border-radius:11px;border:#7DA2CE solid 1px;width:22px;height:22px; overflow:visible}
.GooFlow .item_round table{border:0px;padding:2px;width:22px;height:22px}
.GooFlow .item_round .span{
	display:block;text-align:center; position:absolute;top:24px;left:-28px;width:80px;overflow:visible;text-align:center;
	padding:0px;cursor:default;word-wrap: break-word;word-break:break-all
}
.GooFlow .item_mix{background:#C2DB4E;}
.GooFlow div .rs_right{overflow:hidden;position:absolute;right:-1px;top:-1px;height:100%;width:6px;cursor:w-resize}
.GooFlow div .rs_bottom{overflow:hidden;position:absolute;left:-1px;bottom:-1px;width:100%;height:6px;cursor:n-resize}
.GooFlow div .rs_rb{
	position:absolute;right:-1px;bottom:-1px;width:9px;height:9px;overflow:hidden;cursor:nw-resize;background:url(img/gooflow_tip.png) no-repeat 0px -8px;
}
.GooFlow div .rs_close{
	position:absolute;right:1px;top:1px;width:7px;height:7px;overflow:hidden;cursor:pointer;background:url(img/gooflow_tip.png) no-repeat 0px 0px
}
.GooFlow .rs_ghost{
	position:absolute;display:none;overflow:hidden;border:#8EA4C1 1px dashed; background:#D9E8FB;
	filter:Alpha(Opacity=60);-moz-opacity:0.6;opacity: 0.6;z-index:10
}
.GooFlow .item_focus{border:#5068AE 1px solid}
.GooFlow .item_mark{border:#ff3300 1px solid}
.GooFlow .item_mark td{cursor:crosshair}
.GooFlow textarea{position:absolute;border:#5068AE 1px solid;display:none;font-size:12px;overflow-y:visible;width:100px;z-index:10001}
.GooFlow .GooFlow_line_oper{
	width:70px;height:15px;background-color:#D8E8FC;border:#7DA2CE 1px solid;position:absolute;
	filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity: 0.5;z-index:10000;
}
.GooFlow .GooFlow_line_mp{
	width:9px;height:9px;filter:Alpha(Opacity=40);-moz-opacity:0.4;opacity:0.4;overflow:hidden;
	position:absolute;z-index:9999;background:#333;cursor:crosshair
}
.GooFlow .GooFlow_line_move{filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity:0.5;overflow:hidden;position:absolute;z-index:9999;background:url(0) no-repeat}
.GooFlow .GooFlow_line_oper i{display:inline-block;width:15px;height:15px;margin-left:2px;cursor:pointer}
.GooFlow .b_l1{background:url(img/GooFlow_line_oper.png) no-repeat 1px 1px}
.GooFlow .b_l2{background:url(img/GooFlow_line_oper.png) no-repeat 1px -14px}
.GooFlow .b_l3{background:url(img/GooFlow_line_oper.png) no-repeat 1px -29px}
.GooFlow .b_x{background:url(img/GooFlow_line_oper.png) no-repeat 1px -44px;margin-left:10px}
.GooFlow .ico_cursor{background:url(img/gooflow_icon.png) no-repeat 2px -20px}
.GooFlow .ico_start{background:url(img/gooflow_icon.png) no-repeat -19px -20px}
.GooFlow .ico_end{background:url(img/gooflow_icon.png) no-repeat -39px -20px}
.GooFlow .ico_fork{background:url(img/gooflow_icon.png) no-repeat -59px -20px}
.GooFlow .ico_join{background:url(img/gooflow_icon.png) no-repeat -78px -20px}
.GooFlow .ico_direct{background:url(img/gooflow_icon.png) no-repeat -137px -20px}
.GooFlow .ico_group{background:url(img/gooflow_icon.png) no-repeat -96px -20px}
.GooFlow .ico_complex{background:url(img/gooflow_icon.png) no-repeat -116px -20px}
.GooFlow .ico_node{background:url(img/gooflow_icon.png) no-repeat -19px -45px}
.GooFlow .ico_task{background:url(img/gooflow_icon.png) no-repeat 2px -45px}
.GooFlow .ico_chat{background:url(img/gooflow_icon.png) no-repeat -38px -45px}
.GooFlow .ico_state{background:url(img/gooflow_icon.png) no-repeat -59px -45px}
.GooFlow .ico_plug{background:url(img/gooflow_icon.png) no-repeat -135px -45px}
.GooFlow .ico_open{background:url(img/gooflow_icon.png) no-repeat -19px 1px}
.GooFlow .ico_new{background:url(img/gooflow_icon.png) no-repeat 2px 1px}
.GooFlow .ico_reload{background:url(img/gooflow_icon.png) no-repeat -97px 1px}
.GooFlow .ico_save{background:url(img/gooflow_icon.png) no-repeat -39px 1px}
.GooFlow .ico_undo{background:url(img/gooflow_icon.png) no-repeat -58px 1px}
.GooFlow .ico_redo{background:url(img/gooflow_icon.png) no-repeat -78px 1px}

+ 0 - 2000
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.js

@ -1,2000 +0,0 @@
//定义一个区域图类:
function GooFlow(bgDiv,property){
	if (navigator.userAgent.indexOf("MSIE 8.0")>0||navigator.userAgent.indexOf("MSIE 7.0")>0||navigator.userAgent.indexOf("MSIE 6.0")>0)
		GooFlow.prototype.useSVG="";
	else	GooFlow.prototype.useSVG="1";
//初始化区域图的对象
	this.$id=bgDiv.attr("id");
	this.$bgDiv=bgDiv;//最父框架的DIV
	this.$bgDiv.addClass("GooFlow");
	if(GooFlow.prototype.color.font){
    this.$bgDiv.css("color",GooFlow.prototype.color.font);
	}
	var width=(property.width||800)-2;
	var height=(property.height||500)-2;
	this.$bgDiv.css({width:width+"px",height:height+"px"});
	this.$tool=null;//左侧工具栏对象
	this.$head=null;//顶部标签及工具栏按钮
	this.$title="newFlow_1";//流程图的名称
	this.$nodeRemark={};//每一种结点或按钮的说明文字,JSON格式,key为类名,value为用户自定义文字说明
	this.$nowType="cursor";//当前要绘制的对象类型
	this.$lineData={};
	this.$lineCount=0;
	this.$nodeData={};
	this.$nodeCount=0;
	this.$areaData={};
	this.$areaCount=0;
	this.$lineDom={};
	this.$nodeDom={};
	this.$areaDom={};
	this.$max=property.initNum||1;//计算默认ID值的起始SEQUENCE
	this.$focus="";//当前被选定的结点/转换线ID,如果没选中或者工作区被清空,则为""
	this.$cursor="default";//鼠标指针在工作区内的样式
	this.$editable=false;//工作区是否可编辑
	this.$deletedItem={};//在流程图的编辑操作中被删除掉的元素ID集合,元素ID为KEY,元素类型(node,line.area)为VALUE
	var headHeight=0;
	var tmp="";
	if(property.haveHead){
		tmp="<div class='GooFlow_head' "+(GooFlow.prototype.color.main? "style='border-bottom-color:"+GooFlow.prototype.color.main+"'" : "")
		+">";
		if(property.headLabel){
      tmp+="<label title='"+(property.initLabelText||"newFlow_1")+"' "
        +(GooFlow.prototype.color.main? "style='background:"+GooFlow.prototype.color.main+"'" : "")+">"+(property.initLabelText||"newFlow_1")+"</label>";
		}
		for(var x=0;x<property.headBtns.length;++x){
			tmp+="<a href='javascript:void(0)' class='GooFlow_head_btn'><i class='ico_"+property.headBtns[x]+"'></i></a>"
		}
		tmp+="</div>";
		this.$head=$(tmp);
		this.$bgDiv.append(this.$head);
		headHeight=24;
		//以下是当工具栏按钮被点击时触发的事件自定义(虚函数),格式为function(),因为可直接用THIS操作对象本身,不用传参;用户可自行重定义:
		this.onBtnNewClick=null;//新建流程图按钮被点中
		this.onBtnOpenClick=null;//打开流程图按钮定义
		this.onBtnSaveClick=null;//保存流程图按钮定义
		this.onFreshClick=null;//重载流程图按钮定义
		if(property.headBtns)
		this.$head.on("click",{inthis:this},function(e){
			if(!e)e=window.event;
			var tar=e.target;
			if(tar.tagName=="DIV"||tar.tagName=="SPAN")	return;
			else if(tar.tagName=="a")	tar=tar.childNode[0];
			var This=e.data.inthis;
			//定义顶部操作栏按钮的事件
			switch($(tar).attr("class")){
				case "ico_new":		if(This.onBtnNewClick!=null)	This.onBtnNewClick();break;
				case "ico_open":	if(This.onBtnOpenClick!=null)	This.onBtnOpenClick();break;
				case "ico_save":	if(This.onBtnSaveClick!=null)	This.onBtnSaveClick();break;
				case "ico_undo":	This.undo();break;
				case "ico_redo":	This.redo();break;
				case "ico_reload"	:if(This.onFreshClick!=null)	This.onFreshClick();break;
			}
		});
	}
	var toolWidth=0;
	if(property.haveTool){
		this.$bgDiv.append("<div class='GooFlow_tool'"+(property.haveHead? "":" style='margin-top:3px'")+"><div style='height:"+(height-headHeight-(property.haveHead? 7:10))+"px' class='GooFlow_tool_div'></div></div>");
		this.$tool=this.$bgDiv.find(".GooFlow_tool div");
		//未加代码:加入绘图工具按钮
		this.$tool.append(
      "<a href='javascript:void(0)' type='cursor' class='GooFlow_tool_btndown' id='"+this.$id+"_btn_cursor'><i class='ico_cursor'/></a>"
     +"<a href='javascript:void(0)' type='mutiselect' class='GooFlow_tool_btn' id='"+this.$id+"_btn_mutiselect'><i class='ico_mutiselect'/></a>"
     +"<a href='javascript:void(0)' type='direct' class='GooFlow_tool_btn' id='"+this.$id+"_btn_direct'><i class='ico_direct'/></a>"
    );
		if(property.toolBtns&&property.toolBtns.length>0){
			tmp="<span/>";
			for(var i=0;i<property.toolBtns.length;++i){
				tmp+="<a href='javascript:void(0)' type='"+property.toolBtns[i]+"' id='"+this.$id+"_btn_"+property.toolBtns[i].split(" ")[0]+"' class='GooFlow_tool_btn'><i class='ico_"+property.toolBtns[i]+"'/></a>";//加入自定义按钮
			}
			this.$tool.append(tmp);
		}
		//加入区域划分框工具开关按钮
		if(property.haveGroup)
			this.$tool.append("<span/><a href='javascript:void(0)' type='group' class='GooFlow_tool_btn' id='"+this.$id+"_btn_group'><i class='ico_group'/></a>");
		toolWidth=31;
		this.$nowType="cursor";
		//绑定各个按钮的点击事件
		this.$tool.on("click",{inthis:this},function(e){
			if(!e)e=window.event;
			var tar;
			switch(e.target.tagName){
				case "SPAN":return false;
				case "DIV":return false;
				case "I":	tar=e.target.parentNode;break;
				case "A":	tar=e.target;
			};
			var type=$(tar).attr("type");
			e.data.inthis.switchToolBtn(type);
			return false;
		});
		this.$editable=true;//只有具有工具栏时可编辑
	}
	width=width-toolWidth-9;
	height=height-headHeight-(property.haveHead? 5:8);
	this.$bgDiv.append("<div class='GooFlow_work' style='width:"+(width)+"px;height:"+(height)+"px;"+(property.haveHead? "":"margin-top:3px")+"'></div>");
	this.$workArea=$("<div class='GooFlow_work_inner' style='width:"+width*3+"px;height:"+height*3+"px'></div>")
		.attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
	this.$bgDiv.children(".GooFlow_work").append(this.$workArea);
	this.$draw=null;//画矢量线条的容器
	this.initDraw("draw_"+this.$id,width,height);
	this.$group=null;
	if(property.haveGroup)
		this.initGroup(width,height);
	if(this.$editable){
	  this.$workArea.on("click",{inthis:this},function(e){
		if(!e)e=window.event;
		var This=e.data.inthis;
		if(!This.$editable)return;
		var type=This.$nowType;
		if(type=="cursor"){
			var t=$(e.target);
			var n=t.prop("tagName");
			//alert(n);
			if(n=="svg"||(n=="DIV"&&t.prop("class").indexOf("GooFlow_work")>-1)||n=="LABEL"){
        if(This.$lineOper.data("tid")){
          This.focusItem(This.$lineOper.data("tid"),false);
          //This.$mpFrom.removeData("p");
        }
        else{This.blurItem();}
			}
			return;
		}
		else if(type=="direct"||type=="group")return;
		var X,Y;
		var ev=mousePosition(e),t=getElCoordinate(this);
		X=ev.x-t.left+this.parentNode.scrollLeft-1;
		Y=ev.y-t.top+this.parentNode.scrollTop-1;
		This.addNode(This.$id+"_node_"+This.$max,{name:"node_"+This.$max,left:X,top:Y,type:This.$nowType});
		This.$max++;
	  });
	  //划线或改线时用的绑定
	  this.$workArea.mousemove({inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!e.data.inthis.$mpTo.data("p"))	return;
			var lineStart=$(this).data("lineStart");
			var lineEnd=$(this).data("lineEnd");
			if(!lineStart&&!lineEnd)return;
			
			var ev=mousePosition(e),t=getElCoordinate(this);
			var X,Y;
			X=ev.x-t.left+this.parentNode.scrollLeft;
			Y=ev.y-t.top+this.parentNode.scrollTop;
			var line=document.getElementById("GooFlow_tmp_line");
			if(lineStart){
					if(GooFlow.prototype.useSVG!=""){
					line.childNodes[0].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
					line.childNodes[1].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
					if(line.childNodes[1].getAttribute("marker-end")=="url(\"#arrow2\")")
						line.childNodes[1].setAttribute("marker-end","url(#arrow3)");
					else	line.childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}
				else	line.points.value=lineStart.x+","+lineStart.y+" "+X+","+Y;
			}else if(lineEnd){
				if(GooFlow.prototype.useSVG!=""){
					line.childNodes[0].setAttribute("d","M "+X+" "+Y+" L "+lineEnd.x+" "+lineEnd.y);
					line.childNodes[1].setAttribute("d","M "+X+" "+Y+" L "+lineEnd.x+" "+lineEnd.y);
					if(line.childNodes[1].getAttribute("marker-end")=="url(\"#arrow2\")")
						line.childNodes[1].setAttribute("marker-end","url(#arrow3)");
					else	line.childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}
				else	line.points.value=X+","+Y+" "+lineEnd.x+","+lineEnd.y;
			}
	  });
	  this.$workArea.mouseup({inthis:this},function(e){
	  	var This=e.data.inthis;
			if(This.$nowType!="direct"&&!This.$mpTo.data("p"))	return;
			var tmp=document.getElementById("GooFlow_tmp_line");
			if(tmp){
				$(this).css("cursor","auto").removeData("lineStart").removeData("lineEnd");
        This.$mpTo.hide().removeData("p");
        This.$mpFrom.hide().removeData("p");
        This.$draw.removeChild(tmp);
        This.focusItem(This.$focus,false);
			}else{
        This.$lineOper.removeData("tid");
			}
	  });
	  //为了结点而增加的一些集体delegate绑定
	  this.initWorkForNode();
	  //对结点进行移动或者RESIZE时用来显示的遮罩层
	  this.$ghost=$("<div class='rs_ghost'></div>").attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
	  this.$bgDiv.append(this.$ghost);
	  this.$textArea=$("<textarea></textarea>");
	  this.$bgDiv.append(this.$textArea);
	  this.$lineMove=$("<div class='GooFlow_line_move' style='display:none'></div>");//操作折线时的移动框
	  this.$workArea.append(this.$lineMove);
	  this.$lineMove.on("mousedown",{inthis:this},function(e){
		  if(e.button==2)return false;
		  var lm=$(this);
		  lm.css({"background-color":GooFlow.prototype.color.font||"#333"});
		  var This=e.data.inthis;
		  var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
		  var X,Y;
		  X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		  Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
		  var p=This.$lineMove.position();
		  var vX=X-p.left,vY=Y-p.top;
		  var isMove=false;
		  document.onmousemove=function(e){
			if(!e)e=window.event;
			var ev=mousePosition(e);
			var ps=This.$lineMove.position();
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		 	Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			if(This.$lineMove.data("type")=="lr"){
			  X=X-vX;
			  if(X<0)	X=0;
			  else if(X>This.$workArea.width())
				X=This.$workArea.width();
			  This.$lineMove.css({left:X+"px"});
			}
			else if(This.$lineMove.data("type")=="tb"){
			  Y=Y-vY;
			  if(Y<0)	Y=0;
			  else if(Y>This.$workArea.height())
				Y=This.$workArea.height();
			  This.$lineMove.css({top:Y+"px"});
		    }
			isMove=true;
		  }
		  document.onmouseup=function(e){
			if(isMove){
				var p=This.$lineMove.position();
				if(This.$lineMove.data("type")=="lr")
					This.setLineM(This.$lineMove.data("tid"),p.left+3);
				else if(This.$lineMove.data("type")=="tb")
					This.setLineM(This.$lineMove.data("tid"),p.top+3);
			}
			This.$lineMove.css({"background-color":"transparent"});
			if(This.$focus==This.$lineMove.data("tid")){
				This.focusItem(This.$lineMove.data("tid"));
			}
			document.onmousemove=null;
			document.onmouseup=null;
		  }
	  });
	  //选定一条转换线后出现的浮动操作栏,有改变线的样式和删除线等按钮。
	  this.$lineOper=$("<div class='GooFlow_line_oper' style='display:none'><i class='b_l1'></i><i class='b_l2'></i><i class='b_l3'></i><i class='b_x'></i></div>");//选定线时显示的操作框
	  this.$workArea.parent().append(this.$lineOper);
	  this.$lineOper.on("click",{inthis:this},function(e){
	 	if(!e)e=window.event;
		if(e.target.tagName!="I")	return;
		var This=e.data.inthis;
		var id=$(this).data("tid");
		switch($(e.target).attr("class")){
			case "b_x":	
			This.delLine(id);
			this.style.display="none";break;
			case "b_l1":
			This.setLineType(id,"lr");break;
			case "b_l2":
			This.setLineType(id,"tb");break;
			case "b_l3":
			This.setLineType(id,"sl");break;
		}
	  });
	  //新增移动线两个端点至新的结点功能移动功能,这里要提供移动用的DOM
		this.$mpFrom=$("<div class='GooFlow_line_mp' style='display:none'></div>");
		this.$mpTo=$("<div class='GooFlow_line_mp' style='display:none'></div>");
		this.$workArea.append(this.$mpFrom).append(this.$mpTo);
		this.initLinePointsChg();
	  
	  //下面绑定当结点/线/分组块的一些操作事件,这些事件可直接通过this访问对象本身
	  //当操作某个单元(结点/线/分组块)被添加时,触发的方法,返回FALSE可阻止添加事件的发生
	  //格式function(id,type,json):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,json即addNode,addLine或addArea方法的第二个传参json.
	  this.onItemAdd=null;
	  //当操作某个单元(结点/线/分组块)被删除时,触发的方法,返回FALSE可阻止删除事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
	  this.onItemDel=null;
	  //当操作某个单元(结点/分组块)被移动时,触发的方法,返回FALSE可阻止移动事件的发生
	  //格式function(id,type,left,top):id是单元的唯一标识ID,type是单元的种类,有"node","area"两种取值,线line不支持移动,left是新的左边距坐标,top是新的顶边距坐标
	  this.onItemMove=null;
	  //当操作某个单元(结点/线/分组块)被重命名时,触发的方法,返回FALSE可阻止重命名事件的发生
	  //格式function(id,name,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,name是新的名称
	  this.onItemRename=null;
	  //当操作某个单元(结点/线)被由不选中变成选中时,触发的方法,返回FALSE可阻止选中事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被选中
	  this.onItemFocus=null;
	  //当操作某个单元(结点/线)被由选中变成不选中时,触发的方法,返回FALSE可阻止取消选中事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被取消选中
	  this.onItemBlur=null;
	  //当操作某个单元(结点/分组块)被重定义大小或造型时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type,width,height):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值;width是新的宽度,height是新的高度
	  this.onItemResize=null;
	  //当移动某条折线中段的位置,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,M):id是单元的唯一标识ID,M是中段的新X(或Y)的坐标
	  this.onLineMove=null;
	  //当变换某条连接线的类型,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是连接线的新类型,"sl":直线,"lr":中段可左右移动的折线,"tb":中段可上下移动的折线
	  this.onLineSetType=null;
	  //当变换某条连接线的端点变更连接的结点时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,newStart,newEnd):id是连线单元的唯一标识ID,newStart,newEnd分别是起始结点的ID和到达结点的ID
	  this.onLinePointMove=null;
	  //当用重色标注某个结点/转换线时触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type,mark):id是单元的唯一标识ID,type是单元类型("node"结点,"line"转换线),mark为布尔值,表示是要标注TRUE还是取消标注FALSE
	  this.onItemMark=null;
	  
	  if(property.useOperStack&&this.$editable){//如果要使用堆栈记录操作并提供“撤销/重做”的功能,只在编辑状态下有效
		this.$undoStack=[];
		this.$redoStack=[];
		this.$isUndo=0;
		///////////////以下是构造撤销操作/重做操作的方法
		//为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存
		this.pushOper=function(funcName,paras){
			var len=this.$undoStack.length;
			if(this.$isUndo==1){
				this.$redoStack.push([funcName,paras]);
				this.$isUndo=false;
				if(this.$redoStack.length>40)	this.$redoStack.shift();
			}else{
				this.$undoStack.push([funcName,paras]);
				if(this.$undoStack.length>40)	this.$undoStack.shift();
				if(this.$isUndo==0){
					this.$redoStack.splice(0,this.$redoStack.length);
				}
				this.$isUndo=0;
			}
		};
		//将外部的方法加入到GooFlow对象的事务操作堆栈中,在过后的undo/redo操作中可以进行控制,一般用于对流程图以外的附加信息进行编辑的事务撤销/重做控制;
		//传参func为要执行方法对象,jsonPara为外部方法仅有的一个面向字面的JSON传参,由JSON对象带入所有要传的信息;
		//提示:为了让外部方法能够被UNDO/REDO,需要在编写这些外部方法实现时,加入对该方法执行后效果回退的另一个执行方法的pushExternalOper
		this.pushExternalOper=function(func,jsonPara){
			this.pushOper("externalFunc",[func,jsonPara]);
		};
		//撤销上一步操作
		this.undo=function(){
			if(this.$undoStack.length==0)	return;
			this.blurItem();
			var tmp=this.$undoStack.pop();
			this.$isUndo=1;
			if(tmp[0]=="externalFunc"){
				tmp[1][0](tmp[1][1]);
			}
			else{
			//传参的数量,最多支持6个.
			switch(tmp[1].length){
				case 0:this[tmp[0]]();break;
				case 1:this[tmp[0]](tmp[1][0]);break;
				case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
				case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
				case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
				case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
				case 6:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4],tmp[1][5]);break;
			}
			}
		};
		//重做最近一次被撤销的操作
		this.redo=function(){
			if(this.$redoStack.length==0)	return;
			this.blurItem();
			var tmp=this.$redoStack.pop();
			this.$isUndo=2;
			if(tmp[0]=="externalFunc"){
				tmp[1][0](tmp[1][1]);
			}
			else{
			//传参的数量,最多支持6个.
			switch(tmp[1].length){
				case 0:this[tmp[0]]();break;
				case 1:this[tmp[0]](tmp[1][0]);break;
				case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
				case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
				case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
				case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
				case 6:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4],tmp[1][5]);break;
			}
			}
		};
	  }
	  $(document).keydown({inthis:this},function(e){
		//绑定键盘操作
		var This=e.data.inthis;
		if(This.$focus=="")return;
  		switch(e.keyCode){
			case 46://删除
			This.delNode(This.$focus,true);
			This.delLine(This.$focus);
			break;
		}
	  });
	}
}
GooFlow.prototype={
	useSVG:"",
	getSvgMarker:function(id,color){
		var m=document.createElementNS("http://www.w3.org/2000/svg","marker");
		m.setAttribute("id",id);
		m.setAttribute("viewBox","0 0 6 6");
		m.setAttribute("refX",5);
		m.setAttribute("refY",3);
		m.setAttribute("markerUnits","strokeWidth");
		m.setAttribute("markerWidth",6);
		m.setAttribute("markerHeight",6);
		m.setAttribute("orient","auto");
		var path=document.createElementNS("http://www.w3.org/2000/svg","path");
		path.setAttribute("d","M 0 0 L 6 3 L 0 6 z");
		path.setAttribute("fill",color);
		path.setAttribute("stroke-width",0);
		m.appendChild(path);
		return m;
	},
	initDraw:function(id,width,height){
		var elem;
		if(GooFlow.prototype.useSVG!=""){
			this.$draw=document.createElementNS("http://www.w3.org/2000/svg","svg");//可创建带有指定命名空间的元素节点
			this.$workArea.prepend(this.$draw);
			var defs=document.createElementNS("http://www.w3.org/2000/svg","defs");
			this.$draw.appendChild(defs);
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow1",GooFlow.prototype.color.line||"#3892D3"));
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow2",GooFlow.prototype.color.mark||"#ff3300"));
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow3",GooFlow.prototype.color.mark||"#ff3300"));
		}
		else{
			this.$draw = document.createElement("v:group");
			this.$draw.coordsize = width*3+","+height*3;
			this.$workArea.prepend("<div class='GooFlow_work_vml' style='position:relative;width:"+width*3+"px;height:"+height*3+"px'></div>");
			this.$workArea.children("div")[0].insertBefore(this.$draw,null);
		}
		this.$draw.id = id;
		this.$draw.style.width = width*3 + "px";
		this.$draw.style.height = +height*3 + "px";
		//绑定连线的点击选中以及双击编辑事件
		var tmpClk=null;
		if(GooFlow.prototype.useSVG!="")  tmpClk="g";
		else  tmpClk="PolyLine";
		if(!this.$editable)	return;
		
		$(this.$draw).delegate(tmpClk,"click",{inthis:this},function(e){
			e.data.inthis.focusItem(this.id,true);
		});
		$(this.$draw).delegate(tmpClk,"dblclick",{inthis:this},function(e){
			var oldTxt,x,y,from,to;
			var This=e.data.inthis;
			if(GooFlow.prototype.useSVG!=""){
				oldTxt=this.childNodes[2].textContent;
				from=this.getAttribute("from").split(",");
				to=this.getAttribute("to").split(",");
			}else{
				oldTxt=this.childNodes[1].innerHTML;
				var n=this.getAttribute("fromTo").split(",");
				from=[n[0],n[1]];
				to=[n[2],n[3]];
			}
			if(This.$lineData[this.id].type=="lr"){
				from[0]=This.$lineData[this.id].M;
				to[0]=from[0];
			}
			else if(This.$lineData[this.id].type=="tb"){
				from[1]=This.$lineData[this.id].M;
				to[1]=from[1];
			}
			x=(parseInt(from[0],10)+parseInt(to[0],10))/2-60;
			y=(parseInt(from[1],10)+parseInt(to[1],10))/2-12;
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",width:120,height:14,
				left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
				top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"line");
				This.$textArea.val("").removeData("id").hide();
			});
		});
	},
	initGroup:function(width,height){
		this.$group=$("<div class='GooFlow_work_group' style='width:"+width*3+"px;height:"+height*3+"px'></div>");//存放背景区域的容器
		this.$workArea.prepend(this.$group);
		if(!this.$editable)	return;
	  //区域划分框操作区的事件绑定
	  this.$group.on("mousedown",{inthis:this},function(e){//绑定RESIZE功能以及移动功能
		if(e.button==2)return false;
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(This.$textArea.css("display")=="block"){
			This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
			This.$textArea.val("").removeData("id").hide();
			return false;
		};
		if(!e)e=window.event;
		var cursor=$(e.target).css("cursor");
		var id=e.target.parentNode;
		switch(cursor){
			case "nw-resize":id=id.parentNode;break;
			case "w-resize":id=id.parentNode;break;
			case "n-resize":id=id.parentNode;break;
			case "move":break;
			default:return;
		}
		id=id.id;
		var hack=1;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
		var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
		var X,Y;
		X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
		if(cursor!="move"){
			This.$ghost.css({display:"block",
				width:This.$areaData[id].width-2+"px", height:This.$areaData[id].height-2+"px",
				top:This.$areaData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
				left:This.$areaData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor});
			var vX=(This.$areaData[id].left+This.$areaData[id].width)-X;
			var vY=(This.$areaData[id].top+This.$areaData[id].height)-Y;
		}
		else{
			var vX=X-This.$areaData[id].left;
			var vY=Y-This.$areaData[id].top;
		}
		var isMove=false;
		This.$ghost.css("cursor",cursor);
		document.onmousemove=function(e){
			if(!e)e=window.event;
			var ev=mousePosition(e);
			if(cursor!="move"){
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].left+vX;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$areaData[id].top+vY;
			if(X<200)	X=200;
			if(Y<100)	Y=100;
			switch(cursor){
				case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
				case "w-resize":This.$ghost.css({width:X-2+"px"});break;
				case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
			}
			}
			else{
				if(This.$ghost.css("display")=="none"){
					This.$ghost.css({display:"block",
						width:This.$areaData[id].width-2+"px", height:This.$areaData[id].height-2+"px",
						top:This.$areaData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
						left:This.$areaData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor});
				}
				X=ev.x-vX;Y=ev.y-vY;
				if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
					X=t.left-This.$workArea[0].parentNode.scrollLeft;
				else if(X+This.$workArea[0].parentNode.scrollLeft+This.$areaData[id].width>t.left+This.$workArea.width())
					X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].width;
				if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
					Y=t.top-This.$workArea[0].parentNode.scrollTop;
				else if(Y+This.$workArea[0].parentNode.scrollTop+This.$areaData[id].height>t.top+This.$workArea.height())
					Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$areaData[id].height;
				This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
			}
			isMove=true;
		}
		document.onmouseup=function(e){
			This.$ghost.empty().hide();
			document.onmousemove=null;
			document.onmouseup=null;
			if(!isMove)return;
			if(cursor!="move")
				This.resizeArea(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
			else
				This.moveArea(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
			return false;
	  	}
	  });
	  //绑定修改文字说明功能
	  this.$group.on("dblclick",{inthis:this},function(e){
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(!e)e=window.event;
		if(e.target.tagName!="LABEL")	return false;
		var oldTxt=e.target.innerHTML;
		var p=e.target.parentNode;
		var x=parseInt(p.style.left,10)+18,y=parseInt(p.style.top,10)+1;
		var t=getElCoordinate(This.$workArea[0]);
		This.$textArea.val(oldTxt).css({display:"block",width:100,height:14,
			left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
			top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",p.id).focus();
		This.$workArea.parent().one("mousedown",function(e){
			if(e.button==2)return false;
			if(This.$textArea.css("display")=="block"){
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
				This.$textArea.val("").removeData("id").hide();
			}
		});
		return false;
	  });
	  //绑定点击事件
	  this.$group.mouseup({inthis:this},function(e){
	  
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(!e)e=window.event;
		switch($(e.target).attr("class")){
			case "rs_close":	This.delArea(e.target.parentNode.parentNode.id);return false;//删除该分组区域
			case "bg":	return;
		}
		switch(e.target.tagName){
			case "LABEL":	return false;
			case "I"://绑定变色功能
			var id=e.target.parentNode.id;
			switch(This.$areaData[id].color){
				case "red":	This.setAreaColor(id,"yellow");break;
				case "yellow":	This.setAreaColor(id,"blue");break;
				case "blue":	This.setAreaColor(id,"green");break;
				case "green":	This.setAreaColor(id,"red");break;
			}
			return false;
		}
		if(e.data.inthis.$ghost.css("display")=="none"){
      var X,Y;
      var ev=mousePosition(e),t=getElCoordinate(this);
      X=ev.x-t.left+this.parentNode.parentNode.scrollLeft-1;
      Y=ev.y-t.top+this.parentNode.parentNode.scrollTop-1;
      var color=["red","yellow","blue","green"];
      e.data.inthis.addArea(e.data.inthis.$id+"_area_"+e.data.inthis.$max,{name:"area_"+e.data.inthis.$max,left:X,top:Y,color:color[e.data.inthis.$max%4],width:200,height:100});
      e.data.inthis.$max++;
      return false;
		}
	  });
	},
	//初始化用来改变连线的连接端点的两个小方块的操作事件
	initLinePointsChg:function(){
		this.$mpFrom.on("mousedown",{inthis:this},function(e){
			var This=e.data.inthis;
			This.switchToolBtn("cursor");
			var ps=This.$mpFrom.data("p").split(",");
			var pe=This.$mpTo.data("p").split(",");
			$(this).hide();
			This.$workArea.data("lineEnd",{"x":pe[0],"y":pe[1],"id":This.$lineData[This.$lineOper.data("tid")].to}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[ps[0],ps[1]],[pe[0],pe[1]],true,true);
			This.$draw.appendChild(line);
			return false;
	  });
		this.$mpTo.on("mousedown",{inthis:this},function(e){
			var This=e.data.inthis;
			This.switchToolBtn("cursor");
			var ps=This.$mpFrom.data("p").split(",");
			var pe=This.$mpTo.data("p").split(",");
			$(this).hide();
			This.$workArea.data("lineStart",{"x":ps[0],"y":ps[1],"id":This.$lineData[This.$lineOper.data("tid")].from}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[ps[0],ps[1]],[pe[0],pe[1]],true,true);
			This.$draw.appendChild(line);
			return false;
	  });
	},
	//每一种类型结点及其按钮的说明文字
	setNodeRemarks:function(remark){
    if(this.$tool==null)  return;
		this.$tool.children("a").each(function(){
			this.title=remark[$(this).attr("id").split("btn_")[1]];
		});
		this.$nodeRemark=remark;
	},
	
	//切换左边工具栏按钮,传参TYPE表示切换成哪种类型的按钮
	switchToolBtn:function(type){
		this.$tool.children("#"+this.$id+"_btn_"+this.$nowType.split(" ")[0]).attr("class","GooFlow_tool_btn");
		if(this.$nowType=="group"){
			this.$workArea.prepend(this.$group);
			for(var key in this.$areaDom)	this.$areaDom[key].addClass("lock").children("div:eq(1)").css("display","none");
		}
		this.$nowType=type;
		this.$tool.children("#"+this.$id+"_btn_"+type.split(" ")[0]).attr("class","GooFlow_tool_btndown");
		if(this.$nowType=="group"){
			this.blurItem();
			this.$workArea.append(this.$group);
			for(var key in this.$areaDom)	this.$areaDom[key].removeClass("lock").children("div:eq(1)").css("display","");
		}else if(this.$nowType=="direct"){
      this.blurItem();
		}
		if(this.$textArea.css("display")=="none")	this.$textArea.removeData("id").val("").hide();
	},
	//增加一个流程结点,传参为一个JSON,有id,name,top,left,width,height,type(结点类型)等属性
	addNode:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"node",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delNode",[id]);
		}
		var mark=json.marked? " item_mark":"";
		if(json.type.indexOf(" round")<0){
			if(!json.width||json.width<100)json.width=100;
			if(!json.height||json.height<24)json.height=24;
			if(!json.top||json.top<0)json.top=0;
			if(!json.left||json.left<0)json.left=0;
			var hack=0;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
			this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><i class='ico_"+json.type+"'></i></td><td>"+json.name+"</td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div></div>");
		}
		else{
			json.width=24;json.height=24;
			this.$nodeDom[id]=$("<div class='GooFlow_item item_round"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='0'><tr><td class='ico'><i class='ico_"+json.type+"'></i></td></tr></table><div  style='display:none'><div class='rs_close'></div></div><div class='span'>"+json.name+"</div></div>");
		}
		if(GooFlow.prototype.color.node){
      if(json.type.indexOf(" mix")>-1){
        this.$nodeDom[id].css({"background-color":GooFlow.prototype.color.mix,"border-color":GooFlow.prototype.color.mix});
      }else{
        this.$nodeDom[id].css({"background-color":GooFlow.prototype.color.node,"border-color":GooFlow.prototype.color.node});
      }
      if(mark&&GooFlow.prototype.color.mark){
        this.$nodeDom[id].css({"border-color":GooFlow.prototype.color.mark});
      }
    }
		if(json.type.indexOf(" mix")>-1){
       this.$nodeDom[id].addClass("item_mix");
		}
		
		var ua=navigator.userAgent.toLowerCase();
		if(ua.indexOf('msie')!=-1 && ua.indexOf('8.0')!=-1)
			this.$nodeDom[id].css("filter","progid:DXImageTransform.Microsoft.Shadow(color=#94AAC2,direction=135,strength=2)");
		this.$workArea.append(this.$nodeDom[id]);
		this.$nodeData[id]=json;
		++this.$nodeCount;
		if(this.$editable){
			this.$nodeData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	initWorkForNode:function(){
		//绑定点击事件
		this.$workArea.delegate(".GooFlow_item","click",{inthis:this},function(e){
			e.data.inthis.focusItem(this.id,true);
			$(this).removeClass("item_mark");
		});
		//绑定用鼠标移动事件
		this.$workArea.delegate(".ico","mousedown",{inthis:this},function(e){
			if(!e)e=window.event;
			if(e.button==2)return false;
			var This=e.data.inthis;
			if(This.$nowType=="direct")	return;
			var Dom=$(this).parents(".GooFlow_item");
			var id=Dom.attr("id");
			This.focusItem(id,true);
			var hack=1;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			
			Dom.children("table").clone().prependTo(This.$ghost);
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			var vX=X-This.$nodeData[id].left,vY=Y-This.$nodeData[id].top;
			var isMove=false;
			document.onmousemove=function(e){
				if(!e)e=window.event;
				var ev=mousePosition(e);
				if(X==ev.x-vX&&Y==ev.y-vY)	return false;
				X=ev.x-vX;Y=ev.y-vY;
				
				if(isMove&&This.$ghost.css("display")=="none"){
					This.$ghost.css({display:"block",
						width:This.$nodeData[id].width-2+"px", height:This.$nodeData[id].height-2+"px",
						top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
						left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:"move"
					});
				}
				if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
					X=t.left-This.$workArea[0].parentNode.scrollLeft;
				else if(X+This.$workArea[0].parentNode.scrollLeft+This.$nodeData[id].width>t.left+This.$workArea.width())
					X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].width;
				if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
					Y=t.top-This.$workArea[0].parentNode.scrollTop;
				else if(Y+This.$workArea[0].parentNode.scrollTop+This.$nodeData[id].height>t.top+This.$workArea.height())
					Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].height;
				This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
				isMove=true;
			}
			document.onmouseup=function(e){
				if(isMove)This.moveNode(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
				This.$ghost.empty().hide();
				document.onmousemove=null;
				document.onmouseup=null;
			}
		});
		if(!this.$editable)	return;
		//绑定鼠标覆盖/移出事件
		this.$workArea.delegate(".GooFlow_item","mouseenter",{inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!document.getElementById("GooFlow_tmp_line"))	return;
			$(this).addClass("item_mark").addClass("crosshair").css("border-color",GooFlow.prototype.color.mark||"#ff3300");
		});
		this.$workArea.delegate(".GooFlow_item","mouseleave",{inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!document.getElementById("GooFlow_tmp_line"))	return;
			$(this).removeClass("item_mark").removeClass("crosshair");
			if(this.id==e.data.inthis.$focus){
        $(this).css("border-color",GooFlow.prototype.color.line||"#3892D3");
			}else{
        $(this).css("border-color",GooFlow.prototype.color.node||"#A1DCEB");
			}
		});
		//绑定连线时确定初始点
		this.$workArea.delegate(".GooFlow_item","mousedown",{inthis:this},function(e){
			if(e.button==2)return false;
			var This=e.data.inthis;
			if(This.$nowType!="direct")	return;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			This.$workArea.data("lineStart",{"x":X,"y":Y,"id":this.id}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[X,Y],[X,Y],true,true);
			This.$draw.appendChild(line);
		});
		//绑定连线时确定结束点
		this.$workArea.delegate(".GooFlow_item","mouseup",{inthis:this},function(e){
			var This=e.data.inthis;
			if(This.$nowType!="direct"&&!This.$mpTo.data("p"))	return;
			var lineStart=This.$workArea.data("lineStart");
			var lineEnd=This.$workArea.data("lineEnd");
			if(lineStart&&!This.$mpTo.data("p")){
				This.addLine(This.$id+"_line_"+This.$max,{from:lineStart.id,to:this.id,name:""});
				This.$max++;
			}
			else{
				if(lineStart){
					This.moveLinePoints(This.$focus,lineStart.id,this.id);
				}else if(lineEnd){
					This.moveLinePoints(This.$focus,this.id,lineEnd.id);
				}
				if(!This.$nodeData[this.id].marked){
          $(this).removeClass("item_mark");
          if(this.id!=This.$focus){
            $(this).css("border-color",GooFlow.prototype.color.node);
          }
          else{
            $(this).css("border-color",GooFlow.prototype.color.line);
          }
				}
			}
		});
		//绑定双击编辑事件
		this.$workArea.delegate(".GooFlow_item > .span","dblclick",{inthis:this},function(e){
			var oldTxt=this.innerHTML;
			var This=e.data.inthis;
			var id=this.parentNode.id;
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",height:$(this).height(),width:100,
				left:t.left+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft-24,
				top:t.top+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop+26})
				.data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
				This.$textArea.val("").removeData("id").hide();
			});
		});
		this.$workArea.delegate(".ico + td","dblclick",{inthis:this},function(e){
			var oldTxt=this.innerHTML;
			var This=e.data.inthis;
			var id=$(this).parents(".GooFlow_item").attr("id");
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",width:$(this).width()+24,height:$(this).height(),
				left:t.left+24+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft,
				top:t.top+2+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop})
				.data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
				This.$textArea.val("").removeData("id").hide();
			});
		});
		//绑定结点的删除功能
		this.$workArea.delegate(".rs_close","click",{inthis:this},function(e){
			if(!e)e=window.event;
			e.data.inthis.delNode(e.data.inthis.$focus);
			return false;
		});
		//绑定结点的RESIZE功能
		this.$workArea.delegate(".GooFlow_item > div > div[class!=rs_close]","mousedown",{inthis:this},function(e){
			if(!e)e=window.event;
			if(e.button==2)return false;
			var cursor=$(this).css("cursor");
			if(cursor=="pointer"){return;}
			var This=e.data.inthis;
			var id=This.$focus;
			This.switchToolBtn("cursor");
			e.cancelBubble = true;
			e.stopPropagation();
			var hack=1;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			This.$ghost.css({display:"block",
				width:This.$nodeData[id].width-2+"px", height:This.$nodeData[id].height-2+"px",
				top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
				left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor
			});
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			var vX=(This.$nodeData[id].left+This.$nodeData[id].width)-X;
			var vY=(This.$nodeData[id].top+This.$nodeData[id].height)-Y;
			var isMove=false;
			This.$ghost.css("cursor",cursor);
			document.onmousemove=function(e){
				if(!e)e=window.event;
				var ev=mousePosition(e);
				X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].left+vX;
				Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].top+vY;
				if(X<100)	X=100;
				if(Y<24)	Y=24;
				isMove=true;
				switch(cursor){
					case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
					case "w-resize":This.$ghost.css({width:X-2+"px"});break;
					case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
				}
			}
			document.onmouseup=function(e){
				This.$ghost.hide();
				if(!isMove)return;
				if(!e)e=window.event;
				This.resizeNode(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
				document.onmousemove=null;
				document.onmouseup=null;
	  		}
		});
	},
	//获取结点/连线/分组区域的详细信息
	getItemInfo:function(id,type){
		switch(type){
			case "node":	return this.$nodeData[id]||null;
			case "line":	return this.$lineData[id]||null;
			case "area":	return this.$areaData[id]||null;
		}
	},
	//取消所有结点/连线被选定的状态
	blurItem:function(){
		if(this.$focus!=""){
			var jq=$("#"+this.$focus);
			if(jq.prop("tagName")=="DIV"){
				if(this.onItemBlur!=null&&!this.onItemBlur(this.$focus,"node"))	return false;
				jq.removeClass("item_focus").children("div:eq(0)").css("display","none");
				if(GooFlow.prototype.color.line){
          if(this.$nodeData[this.$focus].marked){
            jq.css("border-color",GooFlow.prototype.color.mark||"#ff3300");
          }
          else{
            jq.css("border-color",GooFlow.prototype.color.node||"#A1DCEB");
          }
				}
			}
			else{
				if(this.onItemBlur!=null&&!this.onItemBlur(this.$focus,"line"))	return false;
				if(GooFlow.prototype.useSVG!=""){
					if(!this.$lineData[this.$focus].marked){
						jq[0].childNodes[1].setAttribute("stroke",GooFlow.prototype.color.line||"#3892D3");
						jq[0].childNodes[1].setAttribute("marker-end","url(#arrow1)");
					}
				}
				else{
					if(!this.$lineData[this.$focus].marked)	jq[0].strokeColor=GooFlow.prototype.color.line||"#3892D3";
				}
				this.$lineMove.hide().removeData("type").removeData("tid");
				if(this.$editable){
						this.$lineOper.hide().removeData("tid");
						this.$mpFrom.hide().removeData("p");
						this.$mpTo.hide().removeData("p");
				}
			}
		}
		this.$focus="";
		return true;
	},
	//选定某个结点/转换线 bool:TRUE决定了要触发选中事件,FALSE则不触发选中事件,多用在程序内部调用。
	focusItem:function(id,bool){
		var jq=$("#"+id);
		if(jq.length==0)	return;
		if(!this.blurItem())	return;//先执行"取消选中",如果返回FLASE,则也会阻止选定事件继续进行.
		if(jq.prop("tagName")=="DIV"){
			if(bool&&this.onItemFocus!=null&&!this.onItemFocus(id,"node"))	return;
			jq.addClass("item_focus");
			if(GooFlow.prototype.color.line){
        jq.css("border-color",GooFlow.prototype.color.line);
			}
			if(this.$editable)jq.children("div:eq(0)").css("display","block");
			this.$workArea.append(jq);
		}
		else{//如果是连接线
			if(this.onItemFocus!=null&&!this.onItemFocus(id,"line"))	return;
			if(GooFlow.prototype.useSVG!=""){
				jq[0].childNodes[1].setAttribute("stroke",GooFlow.prototype.color.mark||"#ff3300");
				jq[0].childNodes[1].setAttribute("marker-end","url(#arrow2)");
			}
			else	jq[0].strokeColor=GooFlow.prototype.color.mark||"#ff3300";
			if(!this.$editable)	return;
			var x,y,from,to,n;
			if(GooFlow.prototype.useSVG!=""){
				from=jq.attr("from").split(",");
				to=jq.attr("to").split(",");
				n=[from[0],from[1],to[0],to[1]];
			}else{
				n=jq[0].getAttribute("fromTo").split(",");
				from=[n[0],n[1]];
				to=[n[2],n[3]];
			}
			from[0]=parseInt(from[0],10);
			from[1]=parseInt(from[1],10);
			to[0]=parseInt(to[0],10);
			to[1]=parseInt(to[1],10);
			//var t=getElCoordinate(this.$workArea[0]);
			if(this.$lineData[id].type=="lr"){
				from[0]=this.$lineData[id].M;
				to[0]=from[0];
				
				this.$lineMove.css({
					width:"5px",height:(to[1]-from[1])*(to[1]>from[1]? 1:-1)+"px",
					left:from[0]-3+"px",
					top:(to[1]>from[1]? from[1]:to[1])+1+"px",
					cursor:"e-resize",display:"block"
				}).data({"type":"lr","tid":id});
			}
			else if(this.$lineData[id].type=="tb"){
				from[1]=this.$lineData[id].M;
				to[1]=from[1];
				this.$lineMove.css({
					width:(to[0]-from[0])*(to[0]>from[0]? 1:-1)+"px",height:"5px",
					left:(to[0]>from[0]? from[0]:to[0])+1+"px",
					top:from[1]-3+"px",
					cursor:"s-resize",display:"block"
				}).data({"type":"tb","tid":id});
			}
			x=(from[0]+to[0])/2-35;
			y=(from[1]+to[1])/2+6;
			this.$lineOper.css({display:"block",left:x+"px",top:y+"px"}).data("tid",id);
			if(this.$editable){
				this.$mpFrom.css({display:"block",left:n[0]-4+"px",top:n[1]-4+"px"}).data("p",n[0]+","+n[1]);
				this.$mpTo.css({display:"block",left:n[2]-4+"px",top:n[3]-4+"px"}).data("p",n[2]+","+n[3]);
			}
			this.$draw.appendChild(jq[0]);
		}
		this.$focus=id;
		this.switchToolBtn("cursor");
	},
	//移动结点到一个新的位置
	moveNode:function(id,left,top){
		if(!this.$nodeData[id])	return;
		if(this.onItemMove!=null&&!this.onItemMove(id,"node",left,top))	return;
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id].left,this.$nodeData[id].top];
			this.pushOper("moveNode",paras);
		}
		if(left<0)	left=0;
		if(top<0)	top=0;
		$("#"+id).css({left:left+"px",top:top+"px"});
		this.$nodeData[id].left=left;
		this.$nodeData[id].top=top;
		//重画转换线
		this.resetLines(id,this.$nodeData[id]);
		if(this.$editable){
			this.$nodeData[id].alt=true;
		}
	},
	//设置结点/连线/分组区域的文字信息
	setName:function(id,name,type){
		var oldName;
		if(type=="node"){//如果是结点
			if(!this.$nodeData[id])	return;
			if(this.$nodeData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"node"))	return;
			oldName=this.$nodeData[id].name;
			this.$nodeData[id].name=name;
			if(this.$nodeData[id].type.indexOf("round")>1){
				this.$nodeDom[id].children(".span").text(name);
			}
			else{
				this.$nodeDom[id].find("td:eq(1)").text(name);
				var hack=0;
				if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
				var width=this.$nodeDom[id].outerWidth();
				var height=this.$nodeDom[id].outerHeight();
				this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
				this.$nodeData[id].width=width;
				this.$nodeData[id].height=height;
			}
			if(this.$editable){
				this.$nodeData[id].alt=true;
			}
			//重画转换线
			this.resetLines(id,this.$nodeData[id]);
		}
		else if(type=="line"){//如果是线
			if(!this.$lineData[id])	return;
			if(this.$lineData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"line"))	return;
			oldName=this.$lineData[id].name;
			this.$lineData[id].name=name;
			if(GooFlow.prototype.useSVG!=""){
				this.$lineDom[id].childNodes[2].textContent=name;
			}
			else{
				this.$lineDom[id].childNodes[1].innerHTML=name;
				var n=this.$lineDom[id].getAttribute("fromTo").split(",");
				var x;
				if(this.$lineData[id].type!="lr"){
					x=(n[2]-n[0])/2;
				}
				else{
					var Min=n[2]>n[0]? n[0]:n[2];
					if(Min>this.$lineData[id].M) Min=this.$lineData[id].M;
					x=this.$lineData[id].M-Min;
				}
				if(x<0) x=x*-1;
				this.$lineDom[id].childNodes[1].style.left=x-this.$lineDom[id].childNodes[1].offsetWidth/2+4+"px";
			}
			if(this.$editable){
				this.$lineData[id].alt=true;
			}
		}
		else if(type=="area"){//如果是分组区域
			if(!this.$areaData[id])	return;
			if(this.$areaData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"area"))	return;
			oldName=this.$areaData[id].name;
			this.$areaData[id].name=name;
			this.$areaDom[id].children("label").text(name);
			if(this.$editable){
				this.$areaData[id].alt=true;
			}
		}
		if(this.$undoStack){
			var paras=[id,oldName,type];
			this.pushOper("setName",paras);
		}
	},
	//设置结点的尺寸,仅支持非开始/结束结点
	resizeNode:function(id,width,height){
		if(!this.$nodeData[id])	return;
		if(this.onItemResize!=null&&!this.onItemResize(id,"node",width,height))	return;
		if(this.$nodeData[id].type=="start"||this.$nodeData[id].type=="end")return;
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id].width,this.$nodeData[id].height];
			this.pushOper("resizeNode",paras);
		}
		var hack=0;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
		this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
		width=this.$nodeDom[id].outerWidth()-hack;
		height=this.$nodeDom[id].outerHeight()-hack;
		this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
		this.$nodeData[id].width=width;
		this.$nodeData[id].height=height;
		if(this.$editable){
			this.$nodeData[id].alt=true;
		}
		//重画转换线
		this.resetLines(id,this.$nodeData[id]);
	},
	//删除结点
	delNode:function(id){
		if(!this.$nodeData[id])	return;
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		//先删除可能的连线
		for(var k in this.$lineData){
			if(this.$lineData[k].from==id||this.$lineData[k].to==id){
				//this.$draw.removeChild(this.$lineDom[k]);
				//delete this.$lineData[k];
				//delete this.$lineDom[k];
				this.delLine(k);
			}
		}
		//再删除结点本身
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id]];
			this.pushOper("addNode",paras);
		}
		delete this.$nodeData[id];
		this.$nodeDom[id].remove();
		delete this.$nodeDom[id];
		--this.$nodeCount;
		if(this.$focus==id)	this.$focus="";
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_node_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_node_")<0)
				this.$deletedItem[id]="node";
		}
	},
	//设置流程图的名称
	setTitle:function(text){
		this.$title=text;
		if(this.$head)	this.$head.children("label").attr("title",text).text(text);
	},
	//载入一组数据
	loadData:function(data){
		var t=this.$editable;
		this.$editable=false;
		if(data.title)	this.setTitle(data.title);
		if(data.initNum)	this.$max=data.initNum;
		for(var i in data.nodes)
			this.addNode(i,data.nodes[i]);
		for(var j in data.lines)
			this.addLine(j,data.lines[j]);
		for(var k in data.areas)
			this.addArea(k,data.areas[k]);
		this.$editable=t;
		this.$deletedItem={};
	},
	//用AJAX方式,远程读取一组数据
	//参数para为JSON结构,与JQUERY中$.ajax()方法的传参一样
	loadDataAjax:function(para){
		var This=this;
		$.ajax({
			type:para.type,
			url:para.url,
			dataType:"json",
			data:para.data,
			success: function(msg){
				if(para.dataFilter)	para.dataFilter(msg,"json");
     			This.loadData(msg);
				if(para.success)	para.success(msg);
   			},
			error: function(XMLHttpRequest, textStatus, errorThrown){
				if(para.error)	para.error(textStatus,errorThrown);
			}
		})
	},
	//把画好的整个流程图导出到一个变量中(其实也可以直接访问GooFlow对象的$nodeData,$lineData,$areaData这三个JSON属性)
	exportData:function(){
		var ret={title:this.$title,nodes:this.$nodeData,lines:this.$lineData,areas:this.$areaData,initNum:this.$max};
		for(var k1 in ret.nodes){
			if(!ret.nodes[k1].marked){
				delete ret.nodes[k1]["marked"];
			}
		}
		for(var k2 in ret.lines){
			if(!ret.lines[k2].marked){
				delete ret.lines[k2]["marked"];
			}
		}
		return ret;
	},
	//只把本次编辑流程图中作了变更(包括增删改)的元素导出到一个变量中,以方便用户每次编辑载入的流程图后只获取变更过的数据
	exportAlter:function(){
		var ret={nodes:{},lines:{},areas:{}};
		for(var k1 in this.$nodeData){
			if(this.$nodeData[k1].alt){
				ret.nodes[k1]=this.$nodeData[k1];
			}
		}
		for(var k2 in this.$lineData){
			if(this.$lineData[k2].alt){
				ret.lines[k2]=this.$lineData[k2];
			}
		}
		for(var k3 in this.$areaData){
			if(this.$areaData[k3].alt){
				ret.areas[k3]=this.$areaData[k3];
			}
		}
		ret.deletedItem=this.$deletedItem;
		return ret;
	},
	//变更元素的ID,一般用于快速保存后,将后台返回新元素的ID更新到页面中;type为元素类型(节点,连线,区块)
	transNewId:function(oldId,newId,type){
		var tmp;
		switch(type){
			case "node":
			if(this.$nodeData[oldId]){
				tmp=this.$nodeData[oldId];
				delete this.$nodeData[oldId];
				this.$nodeData[newId]=tmp;
				tmp=this.$nodeDom[oldId].attr("id",newId);
				delete this.$nodeDom[oldId];
				this.$nodeDom[newId]=tmp;
			}
			break;
			case "line":
			if(this.$lineData[oldId]){
				tmp=this.$lineData[oldId];
				delete this.$lineData[oldId];
				this.$lineData[newId]=tmp;
				tmp=this.$lineDom[oldId].attr("id",newId);
				delete this.$lineDom[oldId];
				this.$lineDom[newId]=tmp;
			}
			break;
			case "area":
			if(this.$areaData[oldId]){
				tmp=this.$areaData[oldId];
				delete this.$areaData[oldId];
				this.$areaData[newId]=tmp;
				tmp=this.$areaDom[oldId].attr("id",newId);
				delete this.$areaDom[oldId];
				this.$areaDom[newId]=tmp;
			}
			break;
		}
	},
	//清空工作区及已载入的数据
	clearData:function(){
		for(var key in this.$nodeData){
			this.delNode(key);
		}
		for(var key in this.$lineData){
			this.delLine(key);
		}
		for(var key in this.$areaData){
			this.delArea(key);
		}
		this.$deletedItem={};
	},
	//销毁自己
	destrory:function(){
		this.$bgDiv.empty();
		this.$lineData=null;
		this.$nodeData=null;
		this.$lineDom=null;
		this.$nodeDom=null;
		this.$areaDom=null;
		this.$areaData=null;
		this.$nodeCount=0;
		this.$areaCount=0;
		this.$areaCount=0;
		this.$deletedItem={};
	},
///////////以下为有关画线的方法
	//绘制一条箭头线,并返回线的DOM
	drawLine:function(id,sp,ep,mark,dash){
		var line;
		if(GooFlow.prototype.useSVG!=""){
			line=document.createElementNS("http://www.w3.org/2000/svg","g");
			var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
			var path=document.createElementNS("http://www.w3.org/2000/svg","path");
			if(id!="")	line.setAttribute("id",id);
			line.setAttribute("from",sp[0]+","+sp[1]);
			line.setAttribute("to",ep[0]+","+ep[1]);
			hi.setAttribute("visibility","hidden");
			hi.setAttribute("stroke-width",9);
			hi.setAttribute("fill","none");
			hi.setAttribute("stroke","white");
			hi.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
			hi.setAttribute("pointer-events","stroke");
			path.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
			path.setAttribute("stroke-width",1.4);
			path.setAttribute("stroke-linecap","round");
			path.setAttribute("fill","none");
			if(dash)	path.setAttribute("style", "stroke-dasharray:6,5");
			if(mark){
				path.setAttribute("stroke",GooFlow.prototype.color.mark||"#ff3300");
				path.setAttribute("marker-end","url(#arrow2)");
			}
			else{
				path.setAttribute("stroke",GooFlow.prototype.color.line||"#3892D3");
				path.setAttribute("marker-end","url(#arrow1)");
			}
			line.appendChild(hi);
			line.appendChild(path);
			line.style.cursor="crosshair";
			if(id!=""&&id!="GooFlow_tmp_line"){
				var text=document.createElementNS("http://www.w3.org/2000/svg","text");
				text.setAttribute("fill",GooFlow.prototype.color.font||"#333");
				line.appendChild(text);
				var x=(ep[0]+sp[0])/2;
				var y=(ep[1]+sp[1])/2;
				text.setAttribute("text-anchor","middle");
				text.setAttribute("x",x);
				text.setAttribute("y",y);
				line.style.cursor="pointer";
				text.style.cursor="text";
			}
		}else{
			line=document.createElement("v:polyline");
			if(id!="")	line.id=id;
			//line.style.position="absolute";
			line.points.value=sp[0]+","+sp[1]+" "+ep[0]+","+ep[1];
			line.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
			line.strokeWeight="1.2";
			line.stroke.EndArrow="Block";
			line.style.cursor="crosshair";
			if(id!=""&&id!="GooFlow_tmp_line"){
				var text=document.createElement("div");
				//text.innerHTML=id;
				line.appendChild(text);
				var x=(ep[0]-sp[0])/2;
				var y=(ep[1]-sp[1])/2;
				if(x<0) x=x*-1;
				if(y<0) y=y*-1;
				text.style.left=x+"px";
				text.style.top=y-6+"px";
				line.style.cursor="pointer";
			}
			if(dash)	line.stroke.dashstyle="Dash";
			if(mark)	line.strokeColor=GooFlow.prototype.color.mark||"#ff3300";
			else	line.strokeColor=GooFlow.prototype.color.line||"#3892D3";
			line.fillColor=GooFlow.prototype.color.line||"#3892D3";
		}
		return line;
	},
	//画一条只有两个中点的折线
	drawPoly:function(id,sp,m1,m2,ep,mark){
		var poly,strPath;
		if(GooFlow.prototype.useSVG!=""){
			poly=document.createElementNS("http://www.w3.org/2000/svg","g");
			var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
			var path=document.createElementNS("http://www.w3.org/2000/svg","path");
			if(id!="")	poly.setAttribute("id",id);
			poly.setAttribute("from",sp[0]+","+sp[1]);
			poly.setAttribute("to",ep[0]+","+ep[1]);
			hi.setAttribute("visibility","hidden");
			hi.setAttribute("stroke-width",9);
			hi.setAttribute("fill","none");
			hi.setAttribute("stroke","white");
			strPath="M "+sp[0]+" "+sp[1];
			if(m1[0]!=sp[0]||m1[1]!=sp[1])
				strPath+=" L "+m1[0]+" "+m1[1];
			if(m2[0]!=ep[0]||m2[1]!=ep[1])
				strPath+=" L "+m2[0]+" "+m2[1];
			strPath+=" L "+ep[0]+" "+ep[1];
			hi.setAttribute("d",strPath);
			hi.setAttribute("pointer-events","stroke");
			path.setAttribute("d",strPath);
			path.setAttribute("stroke-width",1.4);
			path.setAttribute("stroke-linecap","round");
			path.setAttribute("fill","none");
			if(mark){
				path.setAttribute("stroke",GooFlow.prototype.color.mark||"#ff3300");
				path.setAttribute("marker-end","url(#arrow2)");
			}
			else{
				path.setAttribute("stroke",GooFlow.prototype.color.line||"#3892D3");
				path.setAttribute("marker-end","url(#arrow1)");
			}
			poly.appendChild(hi);
			poly.appendChild(path);
			var text=document.createElementNS("http://www.w3.org/2000/svg","text");
			text.setAttribute("fill",GooFlow.prototype.color.font||"#333");
			poly.appendChild(text);
			var x=(m2[0]+m1[0])/2;
			var y=(m2[1]+m1[1])/2;
			text.setAttribute("text-anchor","middle");
			text.setAttribute("x",x);
			text.setAttribute("y",y);
			text.style.cursor="text";
			poly.style.cursor="pointer";
		}
		else{
			poly=document.createElement("v:Polyline");
			if(id!="")	poly.id=id;
			poly.filled="false";
			strPath=sp[0]+","+sp[1];
			if(m1[0]!=sp[0]||m1[1]!=sp[1])
				strPath+=" "+m1[0]+","+m1[1];
			if(m2[0]!=ep[0]||m2[1]!=ep[1])
				strPath+=" "+m2[0]+","+m2[1];
			strPath+=" "+ep[0]+","+ep[1];
			poly.points.value=strPath;
			poly.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
			poly.strokeWeight="1.2";
			poly.stroke.EndArrow="Block";
			var text=document.createElement("div");
			//text.innerHTML=id;
			poly.appendChild(text);
			var x=(m2[0]-m1[0])/2;
			var y=(m2[1]-m1[1])/2;
			if(x<0) x=x*-1;
			if(y<0) y=y*-1;
			text.style.left=x+"px";
			text.style.top=y-4+"px";
			poly.style.cursor="pointer";
			if(mark)	poly.strokeColor=GooFlow.prototype.color.mark||"#ff3300";
			else	poly.strokeColor=GooFlow.prototype.color.line||"#3892D3";
		}
		return poly;
	},
	//计算两个结点间要连直线的话,连线的开始坐标和结束坐标
	calcStartEnd:function(n1,n2){
		var X_1,Y_1,X_2,Y_2;
		//X判断:
		var x11=n1.left,x12=n1.left+n1.width,x21=n2.left,x22=n2.left+n2.width;
		//结点2在结点1左边
		if(x11>=x22){
			X_1=x11;X_2=x22;
		}
		//结点2在结点1右边
		else if(x12<=x21){
			X_1=x12;X_2=x21;
		}
		//结点2在结点1水平部分重合
		else if(x11<=x21&&x12>=x21&&x12<=x22){
			X_1=(x12+x21)/2;X_2=X_1;
		}
		else if(x11>=x21&&x12<=x22){
			X_1=(x11+x12)/2;X_2=X_1;
		}
		else if(x21>=x11&&x22<=x12){
			X_1=(x21+x22)/2;X_2=X_1;
		}
		else if(x11<=x22&&x12>=x22){
			X_1=(x11+x22)/2;X_2=X_1;
		}
		
		//Y判断:
		var y11=n1.top,y12=n1.top+n1.height,y21=n2.top,y22=n2.top+n2.height;
		//结点2在结点1上边
		if(y11>=y22){
			Y_1=y11;Y_2=y22;
		}
		//结点2在结点1下边
		else if(y12<=y21){
			Y_1=y12;Y_2=y21;
		}
		//结点2在结点1垂直部分重合
		else if(y11<=y21&&y12>=y21&&y12<=y22){
			Y_1=(y12+y21)/2;Y_2=Y_1;
		}
		else if(y11>=y21&&y12<=y22){
			Y_1=(y11+y12)/2;Y_2=Y_1;
		}
		else if(y21>=y11&&y22<=y12){
			Y_1=(y21+y22)/2;Y_2=Y_1;
		}
		else if(y11<=y22&&y12>=y22){
			Y_1=(y11+y22)/2;Y_2=Y_1;
		}
		return {"start":[X_1,Y_1],"end":[X_2,Y_2]};
	},
	//计算两个结点间要连折线的话,连线的所有坐标
	calcPolyPoints:function(n1,n2,type,M){
		//开始/结束两个结点的中心
		var SP={x:n1.left+n1.width/2,y:n1.top+n1.height/2};
		var EP={x:n2.left+n2.width/2,y:n2.top+n2.height/2};
		var sp=[],m1=[],m2=[],ep=[];
		//如果是允许中段可左右移动的折线,则参数M为可移动中段线的X坐标
		//粗略计算起始点
		sp=[SP.x,SP.y];
		ep=[EP.x,EP.y];
		if(type=="lr"){
			//粗略计算2个中点
			m1=[M,SP.y];
			m2=[M,EP.y];
			//再具体分析修改开始点和中点1
			if(m1[0]>n1.left&&m1[0]<n1.left+n1.width){
				m1[1]=(SP.y>EP.y? n1.top:n1.top+n1.height);
				sp[0]=m1[0];sp[1]=m1[1];
			}
			else{
				sp[0]=(m1[0]<n1.left? n1.left:n1.left+n1.width)
			}
			//再具体分析中点2和结束点
			if(m2[0]>n2.left&&m2[0]<n2.left+n2.width){
				m2[1]=(SP.y>EP.y? n2.top+n2.height:n2.top);
				ep[0]=m2[0];ep[1]=m2[1];
			}
			else{
				ep[0]=(m2[0]<n2.left? n2.left:n2.left+n2.width)
			}
		}
		//如果是允许中段可上下移动的折线,则参数M为可移动中段线的Y坐标
		else if(type=="tb"){
			//粗略计算2个中点
			m1=[SP.x,M];
			m2=[EP.x,M];
			//再具体分析修改开始点和中点1
			if(m1[1]>n1.top&&m1[1]<n1.top+n1.height){
				m1[0]=(SP.x>EP.x? n1.left:n1.left+n1.width);
				sp[0]=m1[0];sp[1]=m1[1];
			}
			else{
				sp[1]=(m1[1]<n1.top? n1.top:n1.top+n1.height)
			}
			//再具体分析中点2和结束点
			if(m2[1]>n2.top&&m2[1]<n2.top+n2.height){
				m2[0]=(SP.x>EP.x? n2.left+n2.width:n2.left);
				ep[0]=m2[0];ep[1]=m2[1];
			}
			else{
				ep[1]=(m2[1]<n2.top? n2.top:n2.top+n2.height);
			}
		}
		return {start:sp,m1:m1,m2:m2,end:ep};
	},
	//初始化折线中段的X/Y坐标,mType='rb'时为X坐标,mType='tb'时为Y坐标
	getMValue:function(n1,n2,mType){
		if(mType=="lr"){
			return (n1.left+n1.width/2+n2.left+n2.width/2)/2;
		}
		else if(mType=="tb"){
			return (n1.top+n1.height/2+n2.top+n2.height/2)/2;
		}
	},
	//原lineData已经设定好的情况下,只在绘图工作区画一条线的页面元素
	addLineDom:function(id,lineData){
		var n1=this.$nodeData[lineData.from],n2=this.$nodeData[lineData.to];//获取开始/结束结点的数据
		if(!n1||!n2)	return;
		//开始计算线端点坐标
		var res;
		if(lineData.type&&lineData.type!="sl")
			res=GooFlow.prototype.calcPolyPoints(n1,n2,lineData.type,lineData.M);
		else
			res=GooFlow.prototype.calcStartEnd(n1,n2);
		if(!res)	return;
		
		if(lineData.type=="sl")
			this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,lineData.marked);
		else
			this.$lineDom[id]=GooFlow.prototype.drawPoly(id,res.start,res.m1,res.m2,res.end,lineData.marked);
		this.$draw.appendChild(this.$lineDom[id]);
		if(GooFlow.prototype.useSVG==""){
			this.$lineDom[id].childNodes[1].innerHTML=lineData.name;
			if(lineData.type!="sl"){
				var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
				if(Min>res.m2[0])	Min=res.m2[0];
				if(Min>res.m1[0])	Min=res.m1[0];
				this.$lineDom[id].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
				Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
				if(Min>res.m2[1])	Min=res.m2[1];
				if(Min>res.m1[1])	Min=res.m1[1];
				this.$lineDom[id].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2;
			}else
				this.$lineDom[id].childNodes[1].style.left=
				((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
		}
		else	this.$lineDom[id].childNodes[2].textContent=lineData.name;
	},
	//增加一条线
	addLine:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"line",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delLine",[id]);
		}
		if(json.from==json.to)	return;
		var n1=this.$nodeData[json.from],n2=this.$nodeData[json.to];//获取开始/结束结点的数据
		if(!n1||!n2)	return;
		//避免两个节点间不能有一条以上同向接连线
		for(var k in this.$lineData){
			if((json.from==this.$lineData[k].from&&json.to==this.$lineData[k].to))
				return;
		}
		//设置$lineData[id]
		this.$lineData[id]={};
		if(json.type){
			this.$lineData[id].type=json.type;
			this.$lineData[id].M=json.M;
		}
		else	this.$lineData[id].type="sl";//默认为直线
		this.$lineData[id].from=json.from;
		this.$lineData[id].to=json.to;
		this.$lineData[id].name=json.name;
		if(json.marked)	this.$lineData[id].marked=json.marked;
		else	this.$lineData[id].marked=false;
		//设置$lineData[id]完毕
		
		this.addLineDom(id,this.$lineData[id]);
		
		++this.$lineCount;
		if(this.$editable){
			this.$lineData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	//重构所有连向某个结点的线的显示,传参结构为$nodeData数组的一个单元结构
	resetLines:function(id,node){
		for(var i in this.$lineData){
		  var other=null;//获取结束/开始结点的数据
		  var res;
		  if(this.$lineData[i].from==id){//找结束点
			other=this.$nodeData[this.$lineData[i].to]||null;
			if(other==null)	continue;
			if(this.$lineData[i].type=="sl")
				res=GooFlow.prototype.calcStartEnd(node,other);
			else
				res=GooFlow.prototype.calcPolyPoints(node,other,this.$lineData[i].type,this.$lineData[i].M)
			if(!res)	break;
		  }
		  else if(this.$lineData[i].to==id){//找开始点
			other=this.$nodeData[this.$lineData[i].from]||null;
			if(other==null)	continue;
			if(this.$lineData[i].type=="sl")
				res=GooFlow.prototype.calcStartEnd(other,node);
			else
				res=GooFlow.prototype.calcPolyPoints(other,node,this.$lineData[i].type,this.$lineData[i].M);
			if(!res)	break;
		  }
		  if(other==null)	continue;
		  this.$draw.removeChild(this.$lineDom[i]);
		  if(this.$lineData[i].type=="sl"){
		  	this.$lineDom[i]=GooFlow.prototype.drawLine(i,res.start,res.end,this.$lineData[i].marked);
		  }
		  else{
			this.$lineDom[i]=GooFlow.prototype.drawPoly(i,res.start,res.m1,res.m2,res.end,this.$lineData[i].marked);
		  }
		  this.$draw.appendChild(this.$lineDom[i]);
		  if(GooFlow.prototype.useSVG==""){
			this.$lineDom[i].childNodes[1].innerHTML=this.$lineData[i].name;
			if(this.$lineData[i].type!="sl"){
				var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
				if(Min>res.m2[0])	Min=res.m2[0];
				if(Min>res.m1[0])	Min=res.m1[0];
				this.$lineDom[i].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[i].childNodes[1].offsetWidth/2+4;
				Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
				if(Min>res.m2[1])	Min=res.m2[1];
				if(Min>res.m1[1])	Min=res.m1[1];
				this.$lineDom[i].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[i].childNodes[1].offsetHeight/2-4;
			}else
				this.$lineDom[i].childNodes[1].style.left=
				((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[i].childNodes[1].offsetWidth)/2+4;
		  }
		  else	this.$lineDom[i].childNodes[2].textContent=this.$lineData[i].name;
		}
	},
	//重新设置连线的样式 newType= "sl":直线, "lr":中段可左右移动型折线, "tb":中段可上下移动型折线
	setLineType:function(id,newType,M){
		if(!newType||newType==null||newType==""||newType==this.$lineData[id].type)	return false;
		if(this.onLineSetType!=null&&!this.onLineSetType(id,newType))	return;
		if(this.$undoStack){
			var paras=[id,this.$lineData[id].type,this.$lineData[id].M];
			this.pushOper("setLineType",paras);
		}
		var from=this.$lineData[id].from;
		var to=this.$lineData[id].to;
		this.$lineData[id].type=newType;
		var res;
		//如果是变成折线
		if(newType!="sl"){
		  var res=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
		  if(M){
		  	this.setLineM(id,M,true);
		  }else{
		  	this.setLineM(id,this.getMValue(this.$nodeData[from],this.$nodeData[to],newType),true);
		  }
		}
		//如果是变回直线
		else{
		  delete this.$lineData[id].M;
		  this.$lineMove.hide().removeData("type").removeData("tid");
		  res=GooFlow.prototype.calcStartEnd(this.$nodeData[from],this.$nodeData[to]);
		  if(!res)	return;
		  this.$draw.removeChild(this.$lineDom[id]);
		  this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,this.$lineData[id].marked||this.$focus==id);
		  this.$draw.appendChild(this.$lineDom[id]);
		  if(GooFlow.prototype.useSVG==""){
		  	this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
			this.$lineDom[id].childNodes[1].style.left=
			((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
		  }
		  else
			this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
		}
		if(this.$focus==id){
			this.focusItem(id);
		}
		if(this.$editable){
			this.$lineData[id].alt=true;
		}
	},
	//设置折线中段的X坐标值(可左右移动时)或Y坐标值(可上下移动时)
	setLineM:function(id,M,noStack){
		if(!this.$lineData[id]||M<0||!this.$lineData[id].type||this.$lineData[id].type=="sl")	return false;
		if(this.onLineMove!=null&&!this.onLineMove(id,M))	return false;
		if(this.$undoStack&&!noStack){
			var paras=[id,this.$lineData[id].M];
			this.pushOper("setLineM",paras);
		}
		var from=this.$lineData[id].from;
		var to=this.$lineData[id].to;
		this.$lineData[id].M=M;
		var ps=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
		this.$draw.removeChild(this.$lineDom[id]);
		this.$lineDom[id]=GooFlow.prototype.drawPoly(id,ps.start,ps.m1,ps.m2,ps.end,this.$lineData[id].marked||this.$focus==id);
		this.$draw.appendChild(this.$lineDom[id]);
		if(GooFlow.prototype.useSVG==""){
			this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
			var Min=(ps.start[0]>ps.end[0]? ps.end[0]:ps.start[0]);
			if(Min>ps.m2[0])	Min=ps.m2[0];
			if(Min>ps.m1[0])	Min=ps.m1[0];
			this.$lineDom[id].childNodes[1].style.left = (ps.m2[0]+ps.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
			Min=(ps.start[1]>ps.end[1]? ps.end[1]:ps.start[1]);
			if(Min>ps.m2[1])	Min=ps.m2[1];
			if(Min>ps.m1[1])	Min=ps.m1[1];
			this.$lineDom[id].childNodes[1].style.top = (ps.m2[1]+ps.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2-4;
		}
		else	this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
		if(this.$editable){
			this.$lineData[id].alt=true;
		}
	},
	//删除转换线
	delLine:function(id){
		if(!this.$lineData[id])	return;
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		if(this.$undoStack){
			var paras=[id,this.$lineData[id]];
			this.pushOper("addLine",paras);
		}
		this.$draw.removeChild(this.$lineDom[id]);
		delete this.$lineData[id];
		delete this.$lineDom[id];
		if(this.$focus==id)	this.$focus="";
		--this.$lineCount;
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_line_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_line_")<0)
			this.$deletedItem[id]="line";
			this.$mpFrom.hide().removeData("p");
			this.$mpTo.hide().removeData("p");
		}
		this.$lineOper.hide().removeData("tid");
	},
	//变更连线两个端点所连的结点
	//参数:要变更端点的连线ID,新的开始结点ID、新的结束结点ID;如果开始/结束结点ID是传入null或者"",则表示原端点不变
	moveLinePoints:function(lineId, newStart, newEnd, noStack){
		if(newStart==newEnd)	return;
		if(!lineId||!this.$lineData[lineId])	return;
		if(newStart==null||newStart=="")
			newStart=this.$lineData[lineId].from;
		if(newEnd==null||newEnd=="")
			newEnd=this.$lineData[lineId].to;
		//避免两个节点间不能有一条以上同向接连线
		for(var k in this.$lineData){
			if((newStart==this.$lineData[k].from&&newEnd==this.$lineData[k].to))
				return;
		}
		if(this.onLinePointMove!=null&&!this.onLinePointMove(id,newStart,newEnd))	return;
		if(this.$undoStack&&!noStack){
			var paras=[lineId,this.$lineData[lineId].from,this.$lineData[lineId].to];
			this.pushOper("moveLinePoints",paras);
		}
		if(newStart!=null&&newStart!=""){
			this.$lineData[lineId].from=newStart;
		}
		if(newEnd!=null&&newEnd!=""){
			this.$lineData[lineId].to=newEnd;
		}
		//重建转换线
		this.$draw.removeChild(this.$lineDom[lineId]);
		this.addLineDom(lineId,this.$lineData[lineId]);
		if(this.$editable){
			this.$lineData[lineId].alt=true;
		}
	},
	
	//用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。
	//这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。
	markItem:function(id,type,mark){
		if(type=="node"){
			if(!this.$nodeData[id])	return;
			if(this.onItemMark!=null&&!this.onItemMark(id,"node",mark))	return;
			this.$nodeData[id].marked=mark||false;
			if(mark){
				this.$nodeDom[id].addClass("item_mark");
        jq.css("border-color",GooFlow.prototype.color.mark);
			}
			else{
				this.$nodeDom[id].removeClass("item_mark");
				if(id!=this.$focus) jq.css("border-color","transparent");
			}
			
		}else if(type=="line"){
			if(!this.$lineData[id])	return;
			if(this.onItemMark!=null&&!this.onItemMark(id,"line",mark))	return;
			this.$lineData[id].marked=mark||false;
			if(GooFlow.prototype.useSVG!=""){
				if(mark){
					this.$nodeDom[id].childNodes[1].setAttribute("stroke",GooFlow.prototype.color.mark||"#ff3300");
					this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}else{
					this.$nodeDom[id].childNodes[1].setAttribute("stroke",GooFlow.prototype.color.line||"#3892D3");
					this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow1)");
				}
			}else{
				if(mark)	this.$nodeDom[id].strokeColor=GooFlow.prototype.color.mark||"#ff3300";
				else	this.$nodeDom[id].strokeColor=GooFlow.prototype.color.line||"#3892D3"
			}
		}
		if(this.$undoStatck){
			var paras=[id,type,!mark];
			this.pushOper("markItem",paras);
		}
	},
	////////////////////////以下为区域分组块操作
	moveArea:function(id,left,top){
		if(!this.$areaData[id])	return;
		if(this.onItemMove!=null&&!this.onItemMove(id,"area",left,top))	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].left,this.$areaData[id].top];
			this.pushOper("moveNode",paras);
		}
		if(left<0)	left=0;
		if(top<0)	top=0;
		$("#"+id).css({left:left+"px",top:top+"px"});
		this.$areaData[id].left=left;
		this.$areaData[id].top=top;
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	//删除区域分组
	delArea:function(id){
		if(!this.$areaData[id])	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id]];
			this.pushOper("addArea",paras);
		}
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		delete this.$areaData[id];
		this.$areaDom[id].remove();
		delete this.$areaDom[id];
		--this.$areaCount;
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_area_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_area_")<0)
			this.$deletedItem[id]="area";
		}
	},
	//设置区域分组的颜色
	setAreaColor:function(id,color){
		if(!this.$areaData[id])	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].color];
			this.pushOper("setAreaColor",paras);
		}
		if(color=="red"||color=="yellow"||color=="blue"||color=="green"){
			this.$areaDom[id].removeClass("area_"+this.$areaData[id].color).addClass("area_"+color);
			this.$areaData[id].color=color;
		}
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	//设置区域分块的尺寸
	resizeArea:function(id,width,height){
		if(!this.$areaData[id])	return;
		if(this.onItemResize!=null&&!this.onItemResize(id,"area",width,height))	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].width,this.$areaData[id].height];
			this.pushOper("resizeArea",paras);
		}
		var hack=0;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
		this.$areaDom[id].children(".bg").css({width:width-2+"px",height:height-2+"px"});
		width=this.$areaDom[id].outerWidth();
		height=this.$areaDom[id].outerHeight();
		this.$areaDom[id].children("bg").css({width:width-2+"px",height:height-2+"px"});
		this.$areaData[id].width=width;
		this.$areaData[id].height=height;
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	addArea:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"area",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delArea",[id]);
		}
		this.$areaDom[id]=$("<div id='"+id+"' class='GooFlow_area area_"+json.color+"' style='top:"+json.top+"px;left:"+json.left+"px'><div class='bg' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px'></div>"
		+"<label>"+json.name+"</label><i></i><div><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div></div>");
		this.$areaData[id]=json;
		this.$group.append(this.$areaDom[id]);
		if(this.$nowType!="group")	this.$areaDom[id].children("div:eq(1)").css("display","none");
		++this.$areaCount;
		if(this.$editable){
			this.$areaData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	//重构整个流程图设计器的宽高
	reinitSize:function(width,height){
		var w=(width||800)-2;
		var h=(height||500)-2;
		this.$bgDiv.css({height:h+"px",width:w+"px"});
		var headHeight=0,hack=10;
		if(this.$head!=null){
			headHeight=24;
			hack=7;
		}
		if(this.$tool!=null){
			this.$tool.css({height:h-headHeight-hack+"px"});
		}
		w-=39;
		h=h-headHeight-(this.$head!=null? 5:8);
		this.$workArea.parent().css({height:h+"px",width:w+"px"});
		this.$workArea.css({height:h*3+"px",width:w*3+"px"});
		if(GooFlow.prototype.useSVG==""){
			this.$draw.coordsize = w*3+","+h*3;
		}
		this.$draw.style.width = w*3 + "px";
		this.$draw.style.height = +h*3 + "px";
		if(this.$group==null){
			this.$group.css({height:h*3+"px",width:w*3+"px"});
		}
	}
}
GooFlow.prototype.color={};
//将此类的构造函数加入至JQUERY对象中
jQuery.extend({
	createGooFlow:function(bgDiv,property){
		return new GooFlow(bgDiv,property);
	}
}); 

+ 0 - 1915
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow.js.bak

@ -1,1915 +0,0 @@
//定义一个区域图类:
function GooFlow(bgDiv,property){
	if (navigator.userAgent.indexOf("MSIE 8.0")>0||navigator.userAgent.indexOf("MSIE 7.0")>0||navigator.userAgent.indexOf("MSIE 6.0")>0)
		GooFlow.prototype.useSVG="";
	else	GooFlow.prototype.useSVG="1";
//初始化区域图的对象
	this.$id=bgDiv.attr("id");
	this.$bgDiv=bgDiv;//最父框架的DIV
	this.$bgDiv.addClass("GooFlow");
	var width=(property.width||800)-2;
	var height=(property.height||500)-2;
	this.$bgDiv.css({width:width+"px",height:height+"px"});
	this.$tool=null;//左侧工具栏对象
	this.$head=null;//顶部标签及工具栏按钮
	this.$title="newFlow_1";//流程图的名称
	this.$nodeRemark={};//每一种结点或按钮的说明文字,JSON格式,key为类名,value为用户自定义文字说明
	this.$nowType="cursor";//当前要绘制的对象类型
	this.$lineData={};
	this.$lineCount=0;
	this.$nodeData={};
	this.$nodeCount=0;
	this.$areaData={};
	this.$areaCount=0;
	this.$lineDom={};
	this.$nodeDom={};
	this.$areaDom={};
	this.$max=property.initNum||1;//计算默认ID值的起始SEQUENCE
	this.$focus="";//当前被选定的结点/转换线ID,如果没选中或者工作区被清空,则为""
	this.$cursor="default";//鼠标指针在工作区内的样式
	this.$editable=false;//工作区是否可编辑
	this.$deletedItem={};//在流程图的编辑操作中被删除掉的元素ID集合,元素ID为KEY,元素类型(node,line.area)为VALUE
	var headHeight=0;
	var tmp="";
	if(property.haveHead){
		tmp="<div class='GooFlow_head'><label title='"+(property.initLabelText||"newFlow_1")+"'>"+(property.initLabelText||"newFlow_1")+"</label>";
		for(var x=0;x<property.headBtns.length;++x){
			tmp+="<a href='javascript:void(0)' class='GooFlow_head_btn'><b class='ico_"+property.headBtns[x]+"'></b></a>"
		}
		tmp+="</div>";
		this.$head=$(tmp);
		this.$bgDiv.append(this.$head);
		headHeight=24;
		//以下是当工具栏按钮被点击时触发的事件自定义(虚函数),格式为function(),因为可直接用THIS操作对象本身,不用传参;用户可自行重定义:
		this.onBtnNewClick=null;//新建流程图按钮被点中
		this.onBtnOpenClick=null;//打开流程图按钮定义
		this.onBtnSaveClick=null;//保存流程图按钮定义
		this.onFreshClick=null;//重载流程图按钮定义
		if(property.headBtns)
		this.$head.on("click",{inthis:this},function(e){
			if(!e)e=window.event;
			var tar=e.target;
			if(tar.tagName=="DIV"||tar.tagName=="SPAN")	return;
			else if(tar.tagName=="a")	tar=tar.childNode[0];
			var This=e.data.inthis;
			//定义顶部操作栏按钮的事件
			switch($(tar).attr("class")){
				case "ico_new":		if(This.onBtnNewClick!=null)	This.onBtnNewClick();break;
				case "ico_open":	if(This.onBtnOpenClick!=null)	This.onBtnOpenClick();break;
				case "ico_save":	if(This.onBtnSaveClick!=null)	This.onBtnSaveClick();break;
				case "ico_undo":	This.undo();break;
				case "ico_redo":	This.redo();break;
				case "ico_reload"	:if(This.onFreshClick!=null)	This.onFreshClick();break;
			}
		});
	}
	var toolWidth=0;
	if(property.haveTool){
		this.$bgDiv.append("<div class='GooFlow_tool'"+(property.haveHead? "":" style='margin-top:3px'")+"><div style='height:"+(height-headHeight-(property.haveHead? 7:10))+"px' class='GooFlow_tool_div'></div></div>");
		this.$tool=this.$bgDiv.find(".GooFlow_tool div");
		//未加代码:加入绘图工具按钮
		this.$tool.append("<a href='javascript:void(0)' type='cursor' class='GooFlow_tool_btndown' id='"+this.$id+"_btn_cursor'><b class='ico_cursor'/></a><a href='javascript:void(0)' type='direct' class='GooFlow_tool_btn' id='"+this.$id+"_btn_direct'><b class='ico_direct'/></a>");
		if(property.toolBtns&&property.toolBtns.length>0){
			tmp="<span/>";
			for(var i=0;i<property.toolBtns.length;++i){
				tmp+="<a href='javascript:void(0)' type='"+property.toolBtns[i]+"' id='"+this.$id+"_btn_"+property.toolBtns[i].split(" ")[0]+"' class='GooFlow_tool_btn'><b class='ico_"+property.toolBtns[i]+"'/></a>";//加入自定义按钮
			}
			this.$tool.append(tmp);
		}
		//加入区域划分框工具开关按钮
		if(property.haveGroup)
			this.$tool.append("<span/><a href='javascript:void(0)' type='group' class='GooFlow_tool_btn' id='"+this.$id+"_btn_group'><b class='ico_group'/></a>");
		toolWidth=31;
		this.$nowType="cursor";
		//绑定各个按钮的点击事件
		this.$tool.on("click",{inthis:this},function(e){
			if(!e)e=window.event;
			var tar;
			switch(e.target.tagName){
				case "SPAN":return false;
				case "DIV":return false;
				case "B":	tar=e.target.parentNode;break;
				case "A":	tar=e.target;
			};
			var type=$(tar).attr("type");
			e.data.inthis.switchToolBtn(type);
			return false;
		});
		this.$editable=true;//只有具有工具栏时可编辑
	}
	width=width-toolWidth-8;
	height=height-headHeight-(property.haveHead? 5:8);
	this.$bgDiv.append("<div class='GooFlow_work' style='width:"+(width)+"px;height:"+(height)+"px;"+(property.haveHead? "":"margin-top:3px")+"'></div>");
	this.$workArea=$("<div class='GooFlow_work_inner' style='width:"+width*3+"px;height:"+height*3+"px'></div>")
		.attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
	this.$bgDiv.children(".GooFlow_work").append(this.$workArea);
	this.$draw=null;//画矢量线条的容器
	this.initDraw("draw_"+this.$id,width,height);
	this.$group=null;
	if(property.haveGroup)
		this.initGroup(width,height);
	if(this.$editable){
	  this.$workArea.on("click",{inthis:this},function(e){
		if(!e)e=window.event;
		if(!e.data.inthis.$editable)return;
		var type=e.data.inthis.$nowType;
		if(type=="cursor"){
			var t=$(e.target);
			var n=t.prop("tagName");
			if(n=="svg"||(n=="DIV"&&t.prop("class").indexOf("GooFlow_work")>-1)||n=="LABEL")e.data.inthis.blurItem();
			return;
		}
		else if(type=="direct"||type=="group")return;
		var X,Y;
		var ev=mousePosition(e),t=getElCoordinate(this);
		X=ev.x-t.left+this.parentNode.scrollLeft-1;
		Y=ev.y-t.top+this.parentNode.scrollTop-1;
		e.data.inthis.addNode(e.data.inthis.$id+"_node_"+e.data.inthis.$max,{name:"node_"+e.data.inthis.$max,left:X,top:Y,type:e.data.inthis.$nowType});
		e.data.inthis.$max++;
	  });
	  //划线或改线时用的绑定
	  this.$workArea.mousemove({inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!e.data.inthis.$mpTo.data("p"))	return;
			var lineStart=$(this).data("lineStart");
			var lineEnd=$(this).data("lineEnd");
			if(!lineStart&&!lineEnd)return;
			
			var ev=mousePosition(e),t=getElCoordinate(this);
			var X,Y;
			X=ev.x-t.left+this.parentNode.scrollLeft;
			Y=ev.y-t.top+this.parentNode.scrollTop;
			var line=document.getElementById("GooFlow_tmp_line");
			if(lineStart){
					if(GooFlow.prototype.useSVG!=""){
					line.childNodes[0].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
					line.childNodes[1].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
					if(line.childNodes[1].getAttribute("marker-end")=="url(\"#arrow2\")")
						line.childNodes[1].setAttribute("marker-end","url(#arrow3)");
					else	line.childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}
				else	line.points.value=lineStart.x+","+lineStart.y+" "+X+","+Y;
			}else if(lineEnd){
				if(GooFlow.prototype.useSVG!=""){
					line.childNodes[0].setAttribute("d","M "+X+" "+Y+" L "+lineEnd.x+" "+lineEnd.y);
					line.childNodes[1].setAttribute("d","M "+X+" "+Y+" L "+lineEnd.x+" "+lineEnd.y);
					if(line.childNodes[1].getAttribute("marker-end")=="url(\"#arrow2\")")
						line.childNodes[1].setAttribute("marker-end","url(#arrow3)");
					else	line.childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}
				else	line.points.value=X+","+Y+" "+lineEnd.x+","+lineEnd.y;
			}
	  });
	  this.$workArea.mouseup({inthis:this},function(e){
	  	var This=e.data.inthis;
			if(This.$nowType!="direct"&&!This.$mpTo.data("p"))	return;
			$(this).css("cursor","auto").removeData("lineStart").removeData("lineEnd");
			This.$mpTo.removeData("p");
			This.$mpFrom.removeData("p");
			var tmp=document.getElementById("GooFlow_tmp_line");
			if(tmp)This.$draw.removeChild(tmp);
	  });
	  //为了结点而增加的一些集体delegate绑定
	  this.initWorkForNode();
	  //对结点进行移动或者RESIZE时用来显示的遮罩层
	  this.$ghost=$("<div class='rs_ghost'></div>").attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
	  this.$bgDiv.append(this.$ghost);
	  this.$textArea=$("<textarea></textarea>");
	  this.$bgDiv.append(this.$textArea);
	  this.$lineMove=$("<div class='GooFlow_line_move' style='display:none'></div>");//操作折线时的移动框
	  this.$workArea.append(this.$lineMove);
	  this.$lineMove.on("mousedown",{inthis:this},function(e){
		  if(e.button==2)return false;
		  var lm=$(this);
		  lm.css({"background-color":"#333"});
		  var This=e.data.inthis;
		  var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
		  var X,Y;
		  X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		  Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
		  var p=This.$lineMove.position();
		  var vX=X-p.left,vY=Y-p.top;
		  var isMove=false;
		  document.onmousemove=function(e){
			if(!e)e=window.event;
			var ev=mousePosition(e);
			var ps=This.$lineMove.position();
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		 	Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			if(This.$lineMove.data("type")=="lr"){
			  X=X-vX;
			  if(X<0)	X=0;
			  else if(X>This.$workArea.width())
				X=This.$workArea.width();
			  This.$lineMove.css({left:X+"px"});
			}
			else if(This.$lineMove.data("type")=="tb"){
			  Y=Y-vY;
			  if(Y<0)	Y=0;
			  else if(Y>This.$workArea.height())
				Y=This.$workArea.height();
			  This.$lineMove.css({top:Y+"px"});
		    }
			isMove=true;
		  }
		  document.onmouseup=function(e){
			if(isMove){
				var p=This.$lineMove.position();
				if(This.$lineMove.data("type")=="lr")
					This.setLineM(This.$lineMove.data("tid"),p.left+3);
				else if(This.$lineMove.data("type")=="tb")
					This.setLineM(This.$lineMove.data("tid"),p.top+3);
			}
			This.$lineMove.css({"background-color":"transparent"});
			if(This.$focus==This.$lineMove.data("tid")){
				This.focusItem(This.$lineMove.data("tid"));
			}
			document.onmousemove=null;
			document.onmouseup=null;
		  }
	  });
	  //选定一条转换线后出现的浮动操作栏,有改变线的样式和删除线等按钮。
	  this.$lineOper=$("<div class='GooFlow_line_oper' style='display:none'><b class='b_l1'></b><b class='b_l2'></b><b class='b_l3'></b><b class='b_x'></b></div>");//选定线时显示的操作框
	  this.$workArea.append(this.$lineOper);
	  this.$lineOper.on("click",{inthis:this},function(e){
	 	if(!e)e=window.event;
		if(e.target.tagName!="B")	return;
		var This=e.data.inthis;
		var id=$(this).data("tid");
		switch($(e.target).attr("class")){
			case "b_x":	
			This.delLine(id);
			this.style.display="none";break;
			case "b_l1":
			This.setLineType(id,"lr");break;
			case "b_l2":
			This.setLineType(id,"tb");break;
			case "b_l3":
			This.setLineType(id,"sl");break;
		}
	  });
	  //新增移动线两个端点至新的结点功能移动功能,这里要提供移动用的DOM
		this.$mpFrom=$("<div class='GooFlow_line_mp' style='display:none'></div>");
		this.$mpTo=$("<div class='GooFlow_line_mp' style='display:none'></div>");
		this.$workArea.append(this.$mpFrom).append(this.$mpTo);
		this.initLinePointsChg();
	  
	  //下面绑定当结点/线/分组块的一些操作事件,这些事件可直接通过this访问对象本身
	  //当操作某个单元(结点/线/分组块)被添加时,触发的方法,返回FALSE可阻止添加事件的发生
	  //格式function(id,type,json):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,json即addNode,addLine或addArea方法的第二个传参json.
	  this.onItemAdd=null;
	  //当操作某个单元(结点/线/分组块)被删除时,触发的方法,返回FALSE可阻止删除事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
	  this.onItemDel=null;
	  //当操作某个单元(结点/分组块)被移动时,触发的方法,返回FALSE可阻止移动事件的发生
	  //格式function(id,type,left,top):id是单元的唯一标识ID,type是单元的种类,有"node","area"两种取值,线line不支持移动,left是新的左边距坐标,top是新的顶边距坐标
	  this.onItemMove=null;
	  //当操作某个单元(结点/线/分组块)被重命名时,触发的方法,返回FALSE可阻止重命名事件的发生
	  //格式function(id,name,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,name是新的名称
	  this.onItemRename=null;
	  //当操作某个单元(结点/线)被由不选中变成选中时,触发的方法,返回FALSE可阻止选中事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被选中
	  this.onItemFocus=null;
	  //当操作某个单元(结点/线)被由选中变成不选中时,触发的方法,返回FALSE可阻止取消选中事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被取消选中
	  this.onItemBlur=null;
	  //当操作某个单元(结点/分组块)被重定义大小或造型时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type,width,height):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值;width是新的宽度,height是新的高度
	  this.onItemResize=null;
	  //当移动某条折线中段的位置,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,M):id是单元的唯一标识ID,M是中段的新X(或Y)的坐标
	  this.onLineMove=null;
	  //当变换某条连接线的类型,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type):id是单元的唯一标识ID,type是连接线的新类型,"sl":直线,"lr":中段可左右移动的折线,"tb":中段可上下移动的折线
	  this.onLineSetType=null;
	  //当变换某条连接线的端点变更连接的结点时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,newStart,newEnd):id是连线单元的唯一标识ID,newStart,newEnd分别是起始结点的ID和到达结点的ID
	  this.onLinePointMove=null;
	  //当用重色标注某个结点/转换线时触发的方法,返回FALSE可阻止重定大小/造型事件的发生
	  //格式function(id,type,mark):id是单元的唯一标识ID,type是单元类型("node"结点,"line"转换线),mark为布尔值,表示是要标注TRUE还是取消标注FALSE
	  this.onItemMark=null;
	  
	  if(property.useOperStack&&this.$editable){//如果要使用堆栈记录操作并提供“撤销/重做”的功能,只在编辑状态下有效
		this.$undoStack=[];
		this.$redoStack=[];
		this.$isUndo=0;
		///////////////以下是构造撤销操作/重做操作的方法
		//为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存
		this.pushOper=function(funcName,paras){
			var len=this.$undoStack.length;
			if(this.$isUndo==1){
				this.$redoStack.push([funcName,paras]);
				this.$isUndo=false;
				if(this.$redoStack.length>40)	this.$redoStack.shift();
			}else{
				this.$undoStack.push([funcName,paras]);
				if(this.$undoStack.length>40)	this.$undoStack.shift();
				if(this.$isUndo==0){
					this.$redoStack.splice(0,this.$redoStack.length);
				}
				this.$isUndo=0;
			}
		};
		//将外部的方法加入到GooFlow对象的事务操作堆栈中,在过后的undo/redo操作中可以进行控制,一般用于对流程图以外的附加信息进行编辑的事务撤销/重做控制;
		//传参func为要执行方法对象,jsonPara为外部方法仅有的一个面向字面的JSON传参,由JSON对象带入所有要传的信息;
		//提示:为了让外部方法能够被UNDO/REDO,需要在编写这些外部方法实现时,加入对该方法执行后效果回退的另一个执行方法的pushExternalOper
		this.pushExternalOper=function(func,jsonPara){
			this.pushOper("externalFunc",[func,jsonPara]);
		};
		//撤销上一步操作
		this.undo=function(){
			if(this.$undoStack.length==0)	return;
			this.switchToolBtn("cursor");
			this.blurItem();
			var tmp=this.$undoStack.pop();
			this.$isUndo=1;
			if(tmp[0]=="externalFunc"){
				tmp[1][0](tmp[1][1]);
			}
			else{
			//传参的数量,最多支持6个.
			switch(tmp[1].length){
				case 0:this[tmp[0]]();break;
				case 1:this[tmp[0]](tmp[1][0]);break;
				case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
				case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
				case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
				case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
				case 6:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4],tmp[1][5]);break;
			}
			}
		};
		//重做最近一次被撤销的操作
		this.redo=function(){
			if(this.$redoStack.length==0)	return;
			this.switchToolBtn("cursor");
			this.blurItem();
			var tmp=this.$redoStack.pop();
			this.$isUndo=2;
			if(tmp[0]=="externalFunc"){
				tmp[1][0](tmp[1][1]);
			}
			else{
			//传参的数量,最多支持6个.
			switch(tmp[1].length){
				case 0:this[tmp[0]]();break;
				case 1:this[tmp[0]](tmp[1][0]);break;
				case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
				case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
				case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
				case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
				case 6:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4],tmp[1][5]);break;
			}
			}
		};
	  }
	  $(document).keydown({inthis:this},function(e){
		//绑定键盘操作
		var This=e.data.inthis;
		if(This.$focus=="")return;
  		switch(e.keyCode){
			case 46://删除
			This.delNode(This.$focus,true);
			This.delLine(This.$focus);
			break;
		}
	  });
	}
}
GooFlow.prototype={
	useSVG:"",
	getSvgMarker:function(id,color){
		var m=document.createElementNS("http://www.w3.org/2000/svg","marker");
		m.setAttribute("id",id);
		m.setAttribute("viewBox","0 0 6 6");
		m.setAttribute("refX",5);
		m.setAttribute("refY",3);
		m.setAttribute("markerUnits","strokeWidth");
		m.setAttribute("markerWidth",6);
		m.setAttribute("markerHeight",6);
		m.setAttribute("orient","auto");
		var path=document.createElementNS("http://www.w3.org/2000/svg","path");
		path.setAttribute("d","M 0 0 L 6 3 L 0 6 z");
		path.setAttribute("fill",color);
		path.setAttribute("stroke-width",0);
		m.appendChild(path);
		return m;
	},
	initDraw:function(id,width,height){
		var elem;
		if(GooFlow.prototype.useSVG!=""){
			this.$draw=document.createElementNS("http://www.w3.org/2000/svg","svg");//可创建带有指定命名空间的元素节点
			this.$workArea.prepend(this.$draw);
			var defs=document.createElementNS("http://www.w3.org/2000/svg","defs");
			this.$draw.appendChild(defs);
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow1","#15428B"));
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow2","#ff3300"));
			defs.appendChild(GooFlow.prototype.getSvgMarker("arrow3","#ff3300"));
		}
		else{
			this.$draw = document.createElement("v:group");
			this.$draw.coordsize = width*3+","+height*3;
			this.$workArea.prepend("<div class='GooFlow_work_vml' style='position:relative;width:"+width*3+"px;height:"+height*3+"px'></div>");
			this.$workArea.children("div")[0].insertBefore(this.$draw,null);
		}
		this.$draw.id = id;
		this.$draw.style.width = width*3 + "px";
		this.$draw.style.height = +height*3 + "px";
		//绑定连线的点击选中以及双击编辑事件
		var tmpClk=null;
		if(GooFlow.prototype.useSVG!="")  tmpClk="g";
		else  tmpClk="PolyLine";
		if(!this.$editable)	return;
		
		$(this.$draw).delegate(tmpClk,"click",{inthis:this},function(e){
			e.data.inthis.focusItem(this.id,true);
		});
		$(this.$draw).delegate(tmpClk,"dblclick",{inthis:this},function(e){
			var oldTxt,x,y,from,to;
			var This=e.data.inthis;
			if(GooFlow.prototype.useSVG!=""){
				oldTxt=this.childNodes[2].textContent;
				from=this.getAttribute("from").split(",");
				to=this.getAttribute("to").split(",");
			}else{
				oldTxt=this.childNodes[1].innerHTML;
				var n=this.getAttribute("fromTo").split(",");
				from=[n[0],n[1]];
				to=[n[2],n[3]];
			}
			if(This.$lineData[this.id].type=="lr"){
				from[0]=This.$lineData[this.id].M;
				to[0]=from[0];
			}
			else if(This.$lineData[this.id].type=="tb"){
				from[1]=This.$lineData[this.id].M;
				to[1]=from[1];
			}
			x=(parseInt(from[0],10)+parseInt(to[0],10))/2-60;
			y=(parseInt(from[1],10)+parseInt(to[1],10))/2-12;
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",width:120,height:14,
				left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
				top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"line");
				This.$textArea.val("").removeData("id").hide();
			});
		});
	},
	initGroup:function(width,height){
		this.$group=$("<div class='GooFlow_work_group' style='width:"+width*3+"px;height:"+height*3+"px'></div>");//存放背景区域的容器
		this.$workArea.prepend(this.$group);
		if(!this.$editable)	return;
	  //区域划分框操作区的事件绑定
	  this.$group.on("mousedown",{inthis:this},function(e){//绑定RESIZE功能以及移动功能
		if(e.button==2)return false;
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(This.$textArea.css("display")=="block"){
			This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
			This.$textArea.val("").removeData("id").hide();
			return false;
		};
		if(!e)e=window.event;
		var cursor=$(e.target).css("cursor");
		var id=e.target.parentNode;
		switch(cursor){
			case "nw-resize":id=id.parentNode;break;
			case "w-resize":id=id.parentNode;break;
			case "n-resize":id=id.parentNode;break;
			case "move":break;
			default:return;
		}
		id=id.id;
		var hack=1;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
		var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
		var X,Y;
		X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
		Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
		if(cursor!="move"){
			This.$ghost.css({display:"block",
				width:This.$areaData[id].width-2+"px", height:This.$areaData[id].height-2+"px",
				top:This.$areaData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
				left:This.$areaData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor});
			var vX=(This.$areaData[id].left+This.$areaData[id].width)-X;
			var vY=(This.$areaData[id].top+This.$areaData[id].height)-Y;
		}
		else{
			var vX=X-This.$areaData[id].left;
			var vY=Y-This.$areaData[id].top;
		}
		var isMove=false;
		This.$ghost.css("cursor",cursor);
		document.onmousemove=function(e){
			if(!e)e=window.event;
			var ev=mousePosition(e);
			if(cursor!="move"){
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].left+vX;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$areaData[id].top+vY;
			if(X<200)	X=200;
			if(Y<100)	Y=100;
			switch(cursor){
				case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
				case "w-resize":This.$ghost.css({width:X-2+"px"});break;
				case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
			}
			}
			else{
				if(This.$ghost.css("display")=="none"){
					This.$ghost.css({display:"block",
						width:This.$areaData[id].width-2+"px", height:This.$areaData[id].height-2+"px",
						top:This.$areaData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
						left:This.$areaData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor});
				}
				X=ev.x-vX;Y=ev.y-vY;
				if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
					X=t.left-This.$workArea[0].parentNode.scrollLeft;
				else if(X+This.$workArea[0].parentNode.scrollLeft+This.$areaData[id].width>t.left+This.$workArea.width())
					X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].width;
				if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
					Y=t.top-This.$workArea[0].parentNode.scrollTop;
				else if(Y+This.$workArea[0].parentNode.scrollTop+This.$areaData[id].height>t.top+This.$workArea.height())
					Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$areaData[id].height;
				This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
			}
			isMove=true;
		}
		document.onmouseup=function(e){
			This.$ghost.empty().hide();
			document.onmousemove=null;
			document.onmouseup=null;
			if(!isMove)return;
			if(cursor!="move")
				This.resizeArea(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
			else
				This.moveArea(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
			return false;
	  	}
	  });
	  //绑定修改文字说明功能
	  this.$group.on("dblclick",{inthis:this},function(e){
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(!e)e=window.event;
		if(e.target.tagName!="LABEL")	return false;
		var oldTxt=e.target.innerHTML;
		var p=e.target.parentNode;
		var x=parseInt(p.style.left,10)+18,y=parseInt(p.style.top,10)+1;
		var t=getElCoordinate(This.$workArea[0]);
		This.$textArea.val(oldTxt).css({display:"block",width:100,height:14,
			left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
			top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",p.id).focus();
		This.$workArea.parent().one("mousedown",function(e){
			if(e.button==2)return false;
			if(This.$textArea.css("display")=="block"){
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
				This.$textArea.val("").removeData("id").hide();
			}
		});
		return false;
	  });
	  //绑定点击事件
	  this.$group.mouseup({inthis:this},function(e){
	  
		var This=e.data.inthis;
		if(This.$nowType!="group")	return;
		if(!e)e=window.event;
		switch($(e.target).attr("class")){
			case "rs_close":	This.delArea(e.target.parentNode.parentNode.id);return false;//删除该分组区域
			case "bg":	return;
		}
		switch(e.target.tagName){
			case "LABEL":	return false;
			case "B"://绑定变色功能
			var id=e.target.parentNode.id;
			switch(This.$areaData[id].color){
				case "red":	This.setAreaColor(id,"yellow");break;
				case "yellow":	This.setAreaColor(id,"blue");break;
				case "blue":	This.setAreaColor(id,"green");break;
				case "green":	This.setAreaColor(id,"red");break;
			}
			return false;
		}
		if(e.data.inthis.$ghost.css("display")=="none"){
      var X,Y;
      var ev=mousePosition(e),t=getElCoordinate(this);
      X=ev.x-t.left+this.parentNode.parentNode.scrollLeft-1;
      Y=ev.y-t.top+this.parentNode.parentNode.scrollTop-1;
      var color=["red","yellow","blue","green"];
      e.data.inthis.addArea(e.data.inthis.$id+"_area_"+e.data.inthis.$max,{name:"area_"+e.data.inthis.$max,left:X,top:Y,color:color[e.data.inthis.$max%4],width:200,height:100});
      e.data.inthis.$max++;
      return false;
		}
	  });
	},
	//初始化用来改变连线的连接端点的两个小方块的操作事件
	initLinePointsChg:function(){
		this.$mpFrom.on("mousedown",{inthis:this},function(e){
			var This=e.data.inthis;
			This.switchToolBtn("cursor");
			var ps=This.$mpFrom.data("p").split(",");
			var pe=This.$mpTo.data("p").split(",");
			$(this).hide();
			This.$workArea.data("lineEnd",{"x":pe[0],"y":pe[1],"id":This.$lineData[This.$lineOper.data("tid")].to}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[ps[0],ps[1]],[pe[0],pe[1]],true,true);
			This.$draw.appendChild(line);
	  });
		this.$mpTo.on("mousedown",{inthis:this},function(e){
			var This=e.data.inthis;
			This.switchToolBtn("cursor");
			var ps=This.$mpFrom.data("p").split(",");
			var pe=This.$mpTo.data("p").split(",");
			$(this).hide();
			This.$workArea.data("lineStart",{"x":ps[0],"y":ps[1],"id":This.$lineData[This.$lineOper.data("tid")].from}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[ps[0],ps[1]],[pe[0],pe[1]],true,true);
			This.$draw.appendChild(line);
	  });
	},
	//每一种类型结点及其按钮的说明文字
	setNodeRemarks:function(remark){
		this.$tool.children("a").each(function(){
			this.title=remark[$(this).attr("id").split("btn_")[1]];
		});
		this.$nodeRemark=remark;
	},
	
	//切换左边工具栏按钮,传参TYPE表示切换成哪种类型的按钮
	switchToolBtn:function(type){
		this.$tool.children("#"+this.$id+"_btn_"+this.$nowType.split(" ")[0]).attr("class","GooFlow_tool_btn");
		if(this.$nowType=="group"){
			this.$workArea.prepend(this.$group);
			for(var key in this.$areaDom)	this.$areaDom[key].addClass("lock").children("div:eq(1)").css("display","none");
		}
		this.$nowType=type;
		this.$tool.children("#"+this.$id+"_btn_"+type.split(" ")[0]).attr("class","GooFlow_tool_btndown");
		if(this.$nowType=="group"){
			this.blurItem();
			this.$workArea.append(this.$group);
			for(var key in this.$areaDom)	this.$areaDom[key].removeClass("lock").children("div:eq(1)").css("display","");
		}
		if(this.$textArea.css("display")=="none")	this.$textArea.removeData("id").val("").hide();
	},
	//增加一个流程结点,传参为一个JSON,有id,name,top,left,width,height,type(结点类型)等属性
	addNode:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"node",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delNode",[id]);
		}
		var mark=json.mark? " item_mark":"";
		if(json.type.indexOf(" round")<0){
			if(!json.width||json.width<86)json.width=86;
			if(!json.height||json.height<24)json.height=24;
			if(!json.top||json.top<0)json.top=0;
			if(!json.left||json.left<0)json.left=0;
			var hack=0;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
			this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"'></b></td><td>"+json.name+"</td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div></div>");
			if(json.type.indexOf(" mix")>-1)	this.$nodeDom[id].addClass("item_mix");
		}
		else{
			json.width=24;json.height=24;
			this.$nodeDom[id]=$("<div class='GooFlow_item item_round"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='0'><tr><td class='ico'><b class='ico_"+json.type+"'></b></td></tr></table><div  style='display:none'><div class='rs_close'></div></div><div class='span'>"+json.name+"</div></div>");
		}
		var ua=navigator.userAgent.toLowerCase();
		if(ua.indexOf('msie')!=-1 && ua.indexOf('8.0')!=-1)
			this.$nodeDom[id].css("filter","progid:DXImageTransform.Microsoft.Shadow(color=#94AAC2,direction=135,strength=2)");
		this.$workArea.append(this.$nodeDom[id]);
		this.$nodeData[id]=json;
		++this.$nodeCount;
		if(this.$editable){
			this.$nodeData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	initWorkForNode:function(){
		//绑定点击事件
		this.$workArea.delegate(".GooFlow_item","click",{inthis:this},function(e){
			e.data.inthis.focusItem(this.id,true);
			$(this).removeClass("item_mark");
		});
		//绑定用鼠标移动事件
		this.$workArea.delegate(".ico","mousedown",{inthis:this},function(e){
			if(!e)e=window.event;
			if(e.button==2)return false;
			var This=e.data.inthis;
			if(This.$nowType=="direct")	return;
			var Dom=$(this).parents(".GooFlow_item");
			var id=Dom.attr("id");
			This.focusItem(id,true);
			var hack=1;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			
			Dom.children("table").clone().prependTo(This.$ghost);
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			var vX=X-This.$nodeData[id].left,vY=Y-This.$nodeData[id].top;
			var isMove=false;
			document.onmousemove=function(e){
				if(!e)e=window.event;
				var ev=mousePosition(e);
				if(X==ev.x-vX&&Y==ev.y-vY)	return false;
				X=ev.x-vX;Y=ev.y-vY;
				
				if(isMove&&This.$ghost.css("display")=="none"){
					This.$ghost.css({display:"block",
						width:This.$nodeData[id].width-2+"px", height:This.$nodeData[id].height-2+"px",
						top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
						left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:"move"
					});
				}
				if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
					X=t.left-This.$workArea[0].parentNode.scrollLeft;
				else if(X+This.$workArea[0].parentNode.scrollLeft+This.$nodeData[id].width>t.left+This.$workArea.width())
					X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].width;
				if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
					Y=t.top-This.$workArea[0].parentNode.scrollTop;
				else if(Y+This.$workArea[0].parentNode.scrollTop+This.$nodeData[id].height>t.top+This.$workArea.height())
					Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].height;
				This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
				isMove=true;
			}
			document.onmouseup=function(e){
				if(isMove)This.moveNode(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
				This.$ghost.empty().hide();
				document.onmousemove=null;
				document.onmouseup=null;
			}
		});
		if(!this.$editable)	return;
		//绑定鼠标覆盖/移出事件
		this.$workArea.delegate(".GooFlow_item","mouseenter",{inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!e.data.inthis.$mpTo.data("p"))	return;
			$(this).addClass("item_mark");
		});
		this.$workArea.delegate(".GooFlow_item","mouseleave",{inthis:this},function(e){
			if(e.data.inthis.$nowType!="direct"&&!e.data.inthis.$mpTo.data("p"))	return;
			$(this).removeClass("item_mark");
		});
		//绑定连线时确定初始点
		this.$workArea.delegate(".GooFlow_item","mousedown",{inthis:this},function(e){
			if(e.button==2)return false;
			var This=e.data.inthis;
			if(This.$nowType!="direct")	return;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			This.$workArea.data("lineStart",{"x":X,"y":Y,"id":this.id}).css("cursor","crosshair");
			var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[X,Y],[X,Y],true,true);
			This.$draw.appendChild(line);
		});
		//绑定连线时确定结束点
		this.$workArea.delegate(".GooFlow_item","mouseup",{inthis:this},function(e){
			var This=e.data.inthis;
			if(This.$nowType!="direct"&&!This.$mpTo.data("p"))	return;
			var lineStart=This.$workArea.data("lineStart");
			var lineEnd=This.$workArea.data("lineEnd");
			if(lineStart&&!This.$mpTo.data("p")){
				This.addLine(This.$id+"_line_"+This.$max,{from:lineStart.id,to:this.id,name:""});
				This.$max++;
			}
			else{
				if(lineStart){
					This.moveLinePoints(This.$focus,lineStart.id,this.id);
				}else if(lineEnd){
					This.moveLinePoints(This.$focus,this.id,lineEnd.id);
				}
			}
		});
		//绑定双击编辑事件
		this.$workArea.delegate(".GooFlow_item > .span","dblclick",{inthis:this},function(e){
			var oldTxt=this.innerHTML;
			var This=e.data.inthis;
			var id=this.parentNode.id;
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",height:$(this).height(),width:100,
				left:t.left+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft-24,
				top:t.top+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop+26})
				.data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
				This.$textArea.val("").removeData("id").hide();
			});
		});
		this.$workArea.delegate(".ico + td","dblclick",{inthis:this},function(e){
			var oldTxt=this.innerHTML;
			var This=e.data.inthis;
			var id=$(this).parents(".GooFlow_item").attr("id");
			var t=getElCoordinate(This.$workArea[0]);
			This.$textArea.val(oldTxt).css({display:"block",width:$(this).width()+24,height:$(this).height(),
				left:t.left+24+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft,
				top:t.top+2+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop})
				.data("id",This.$focus).focus();
			This.$workArea.parent().one("mousedown",function(e){
				if(e.button==2)return false;
				This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
				This.$textArea.val("").removeData("id").hide();
			});
		});
		//绑定结点的删除功能
		this.$workArea.delegate(".rs_close","click",{inthis:this},function(e){
			if(!e)e=window.event;
			e.data.inthis.delNode(e.data.inthis.$focus);
			return false;
		});
		//绑定结点的RESIZE功能
		this.$workArea.delegate(".GooFlow_item > div > div[class!=rs_close]","mousedown",{inthis:this},function(e){
			if(!e)e=window.event;
			if(e.button==2)return false;
			var cursor=$(this).css("cursor");
			if(cursor=="pointer"){return;}
			var This=e.data.inthis;
			var id=This.$focus;
			This.switchToolBtn("cursor");
			e.cancelBubble = true;
			e.stopPropagation();
			var hack=1;
			if(navigator.userAgent.indexOf("8.0")!=-1)	hack=0;
			var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
			This.$ghost.css({display:"block",
				width:This.$nodeData[id].width-2+"px", height:This.$nodeData[id].height-2+"px",
				top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
				left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor
			});
			var X,Y;
			X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
			Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
			var vX=(This.$nodeData[id].left+This.$nodeData[id].width)-X;
			var vY=(This.$nodeData[id].top+This.$nodeData[id].height)-Y;
			var isMove=false;
			This.$ghost.css("cursor",cursor);
			document.onmousemove=function(e){
				if(!e)e=window.event;
				var ev=mousePosition(e);
				X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].left+vX;
				Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].top+vY;
				if(X<86)	X=86;
				if(Y<24)	Y=24;
				isMove=true;
				switch(cursor){
					case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
					case "w-resize":This.$ghost.css({width:X-2+"px"});break;
					case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
				}
			}
			document.onmouseup=function(e){
				This.$ghost.hide();
				if(!isMove)return;
				if(!e)e=window.event;
				This.resizeNode(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
				document.onmousemove=null;
				document.onmouseup=null;
	  		}
		});
	},
	//获取结点/连线/分组区域的详细信息
	getItemInfo:function(id,type){
		switch(type){
			case "node":	return this.$nodeData[id]||null;
			case "line":	return this.$lineData[id]||null;
			case "area":	return this.$areaData[id]||null;
		}
	},
	//取消所有结点/连线被选定的状态
	blurItem:function(){	
		if(this.$focus!=""){
			var jq=$("#"+this.$focus);
			if(jq.prop("tagName")=="DIV"){
				if(this.onItemBlur!=null&&!this.onItemBlur(id,"node"))	return false;
				jq.removeClass("item_focus").children("div:eq(0)").css("display","none");
			}
			else{
				if(this.onItemBlur!=null&&!this.onItemBlur(id,"line"))	return false;
				if(GooFlow.prototype.useSVG!=""){
					if(!this.$lineData[this.$focus].marked){
						jq[0].childNodes[1].setAttribute("stroke","#5068AE");
						jq[0].childNodes[1].setAttribute("marker-end","url(#arrow1)");
					}
				}
				else{
					if(!this.$lineData[this.$focus].marked)	jq[0].strokeColor="#5068AE";
				}
				this.$lineMove.hide().removeData("type").removeData("tid");
				if(this.$editable){
						this.$lineOper.hide().removeData("tid");
						this.$mpFrom.hide().removeData("p");
						this.$mpTo.hide().removeData("p");
				}
			}
		}
		this.$focus="";
		return true;
	},
	//选定某个结点/转换线 bool:TRUE决定了要触发选中事件,FALSE则不触发选中事件,多用在程序内部调用。
	focusItem:function(id,bool){
		var jq=$("#"+id);
		if(jq.length==0)	return;
		if(!this.blurItem())	return;//先执行"取消选中",如果返回FLASE,则也会阻止选定事件继续进行.
		if(jq.prop("tagName")=="DIV"){
			if(bool&&this.onItemFocus!=null&&!this.onItemFocus(id,"node"))	return;
			jq.addClass("item_focus");
			if(this.$editable)jq.children("div:eq(0)").css("display","block");
			this.$workArea.append(jq);
		}
		else{//如果是连接线
			if(this.onItemFocus!=null&&!this.onItemFocus(id,"line"))	return;
			if(GooFlow.prototype.useSVG!=""){
				jq[0].childNodes[1].setAttribute("stroke","#ff3300");
				jq[0].childNodes[1].setAttribute("marker-end","url(#arrow2)");
			}
			else	jq[0].strokeColor="#ff3300";
			this.$draw.appendChild(jq[0]);
			if(!this.$editable)	return;
			var x,y,from,to,n;
			if(GooFlow.prototype.useSVG!=""){
				from=jq.attr("from").split(",");
				to=jq.attr("to").split(",");
				n=[from[0],from[1],to[0],to[1]];
			}else{
				n=jq[0].getAttribute("fromTo").split(",");
				from=[n[0],n[1]];
				to=[n[2],n[3]];
			}
			from[0]=parseInt(from[0],10);
			from[1]=parseInt(from[1],10);
			to[0]=parseInt(to[0],10);
			to[1]=parseInt(to[1],10);
			//var t=getElCoordinate(this.$workArea[0]);
			if(this.$lineData[id].type=="lr"){
				from[0]=this.$lineData[id].M;
				to[0]=from[0];
				
				this.$lineMove.css({
					width:"5px",height:(to[1]-from[1])*(to[1]>from[1]? 1:-1)+"px",
					left:from[0]-3+"px",
					top:(to[1]>from[1]? from[1]:to[1])+1+"px",
					cursor:"e-resize",display:"block"
				}).data({"type":"lr","tid":id});
			}
			else if(this.$lineData[id].type=="tb"){
				from[1]=this.$lineData[id].M;
				to[1]=from[1];
				this.$lineMove.css({
					width:(to[0]-from[0])*(to[0]>from[0]? 1:-1)+"px",height:"5px",
					left:(to[0]>from[0]? from[0]:to[0])+1+"px",
					top:from[1]-3+"px",
					cursor:"s-resize",display:"block"
				}).data({"type":"tb","tid":id});
			}
			x=(from[0]+to[0])/2-35;
			y=(from[1]+to[1])/2+6;
			this.$lineOper.css({display:"block",left:x+"px",top:y+"px"}).data("tid",id);
			if(this.$editable){
				this.$mpFrom.css({display:"block",left:n[0]-4+"px",top:n[1]-4+"px"}).data("p",n[0]+","+n[1]);
				this.$mpTo.css({display:"block",left:n[2]-4+"px",top:n[3]-4+"px"}).data("p",n[2]+","+n[3]);
			}
		}
		this.$focus=id;
		this.switchToolBtn("cursor");
	},
	//移动结点到一个新的位置
	moveNode:function(id,left,top){
		if(!this.$nodeData[id])	return;
		if(this.onItemMove!=null&&!this.onItemMove(id,"node",left,top))	return;
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id].left,this.$nodeData[id].top];
			this.pushOper("moveNode",paras);
		}
		if(left<0)	left=0;
		if(top<0)	top=0;
		$("#"+id).css({left:left+"px",top:top+"px"});
		this.$nodeData[id].left=left;
		this.$nodeData[id].top=top;
		//重画转换线
		this.resetLines(id,this.$nodeData[id]);
		if(this.$editable){
			this.$nodeData[id].alt=true;
		}
	},
	//设置结点/连线/分组区域的文字信息
	setName:function(id,name,type){
		var oldName;
		if(type=="node"){//如果是结点
			if(!this.$nodeData[id])	return;
			if(this.$nodeData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"node"))	return;
			oldName=this.$nodeData[id].name;
			this.$nodeData[id].name=name;
			if(this.$nodeData[id].type.indexOf("round")>1){
				this.$nodeDom[id].children(".span").text(name);
			}
			else{
				this.$nodeDom[id].find("td:eq(1)").text(name);
				var hack=0;
				if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
				var width=this.$nodeDom[id].outerWidth();
				var height=this.$nodeDom[id].outerHeight();
				this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
				this.$nodeData[id].width=width;
				this.$nodeData[id].height=height;
			}
			if(this.$editable){
				this.$nodeData[id].alt=true;
			}
			//重画转换线
			this.resetLines(id,this.$nodeData[id]);
		}
		else if(type=="line"){//如果是线
			if(!this.$lineData[id])	return;
			if(this.$lineData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"line"))	return;
			oldName=this.$lineData[id].name;
			this.$lineData[id].name=name;
			if(GooFlow.prototype.useSVG!=""){
				this.$lineDom[id].childNodes[2].textContent=name;
			}
			else{
				this.$lineDom[id].childNodes[1].innerHTML=name;
				var n=this.$lineDom[id].getAttribute("fromTo").split(",");
				var x;
				if(this.$lineData[id].type!="lr"){
					x=(n[2]-n[0])/2;
				}
				else{
					var Min=n[2]>n[0]? n[0]:n[2];
					if(Min>this.$lineData[id].M) Min=this.$lineData[id].M;
					x=this.$lineData[id].M-Min;
				}
				if(x<0) x=x*-1;
				this.$lineDom[id].childNodes[1].style.left=x-this.$lineDom[id].childNodes[1].offsetWidth/2+4+"px";
			}
			if(this.$editable){
				this.$lineData[id].alt=true;
			}
		}
		else if(type=="area"){//如果是分组区域
			if(!this.$areaData[id])	return;
			if(this.$areaData[id].name==name)	return;
			if(this.onItemRename!=null&&!this.onItemRename(id,name,"area"))	return;
			oldName=this.$areaData[id].name;
			this.$areaData[id].name=name;
			this.$areaDom[id].children("label").text(name);
			if(this.$editable){
				this.$areaData[id].alt=true;
			}
		}
		if(this.$undoStack){
			var paras=[id,oldName,type];
			this.pushOper("setName",paras);
		}
	},
	//设置结点的尺寸,仅支持非开始/结束结点
	resizeNode:function(id,width,height){
		if(!this.$nodeData[id])	return;
		if(this.onItemResize!=null&&!this.onItemResize(id,"node",width,height))	return;
		if(this.$nodeData[id].type=="start"||this.$nodeData[id].type=="end")return;
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id].width,this.$nodeData[id].height];
			this.pushOper("resizeNode",paras);
		}
		var hack=0;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
		this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
		width=this.$nodeDom[id].outerWidth()-hack;
		height=this.$nodeDom[id].outerHeight()-hack;
		this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
		this.$nodeData[id].width=width;
		this.$nodeData[id].height=height;
		if(this.$editable){
			this.$nodeData[id].alt=true;
		}
		//重画转换线
		this.resetLines(id,this.$nodeData[id]);
	},
	//删除结点
	delNode:function(id){
		if(!this.$nodeData[id])	return;
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		//先删除可能的连线
		for(var k in this.$lineData){
			if(this.$lineData[k].from==id||this.$lineData[k].to==id){
				//this.$draw.removeChild(this.$lineDom[k]);
				//delete this.$lineData[k];
				//delete this.$lineDom[k];
				this.delLine(k);
			}
		}
		//再删除结点本身
		if(this.$undoStack){
			var paras=[id,this.$nodeData[id]];
			this.pushOper("addNode",paras);
		}
		delete this.$nodeData[id];
		this.$nodeDom[id].remove();
		delete this.$nodeDom[id];
		--this.$nodeCount;
		if(this.$focus==id)	this.$focus="";
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_node_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_node_")<0)
				this.$deletedItem[id]="node";
		}
	},
	//设置流程图的名称
	setTitle:function(text){
		this.$title=text;
		if(this.$head)	this.$head.children("label").attr("title",text).text(text);
	},
	//载入一组数据
	loadData:function(data){
		var t=this.$editable;
		this.$editable=false;
		if(data.title)	this.setTitle(data.title);
		if(data.initNum)	this.$max=data.initNum;
		for(var i in data.nodes)
			this.addNode(i,data.nodes[i]);
		for(var j in data.lines)
			this.addLine(j,data.lines[j]);
		for(var k in data.areas)
			this.addArea(k,data.areas[k]);
		this.$editable=t;
		this.$deletedItem={};
	},
	//用AJAX方式,远程读取一组数据
	//参数para为JSON结构,与JQUERY中$.ajax()方法的传参一样
	loadDataAjax:function(para){
		var This=this;
		$.ajax({
			type:para.type,
			url:para.url,
			dataType:"json",
			data:para.data,
			success: function(msg){
				if(para.dataFilter)	para.dataFilter(msg,"json");
     			This.loadData(msg);
				if(para.success)	para.success(msg);
   			},
			error: function(XMLHttpRequest, textStatus, errorThrown){
				if(para.error)	para.error(textStatus,errorThrown);
			}
		})
	},
	//把画好的整个流程图导出到一个变量中(其实也可以直接访问GooFlow对象的$nodeData,$lineData,$areaData这三个JSON属性)
	exportData:function(){
		var ret={title:this.$title,nodes:this.$nodeData,lines:this.$lineData,areas:this.$areaData,initNum:this.$max};
		for(var k1 in ret.nodes){
			if(!ret.nodes[k1].marked){
				delete ret.nodes[k1]["marked"];
			}
		}
		for(var k2 in ret.lines){
			if(!ret.lines[k2].marked){
				delete ret.lines[k2]["marked"];
			}
		}
		return ret;
	},
	//只把本次编辑流程图中作了变更(包括增删改)的元素导出到一个变量中,以方便用户每次编辑载入的流程图后只获取变更过的数据
	exportAlter:function(){
		var ret={nodes:{},lines:{},areas:{}};
		for(var k1 in this.$nodeData){
			if(this.$nodeData[k1].alt){
				ret.nodes[k1]=this.$nodeData[k1];
			}
		}
		for(var k2 in this.$lineData){
			if(this.$lineData[k2].alt){
				ret.lines[k2]=this.$lineData[k2];
			}
		}
		for(var k3 in this.$areaData){
			if(this.$areaData[k3].alt){
				ret.areas[k3]=this.$areaData[k3];
			}
		}
		ret.deletedItem=this.$deletedItem;
		return ret;
	},
	//变更元素的ID,一般用于快速保存后,将后台返回新元素的ID更新到页面中;type为元素类型(节点,连线,区块)
	transNewId:function(oldId,newId,type){
		var tmp;
		switch(type){
			case "node":
			if(this.$nodeData[oldId]){
				tmp=this.$nodeData[oldId];
				delete this.$nodeData[oldId];
				this.$nodeData[newId]=tmp;
			}
			break;
			case "line":
			if(this.$lineData[oldId]){
				tmp=this.$lineData[oldId];
				delete this.$lineData[oldId];
				this.$lineData[newId]=tmp;
			}
			break;
			case "area":
			if(this.$areaData[oldId]){
				tmp=this.$areaData[oldId];
				delete this.$areaData[oldId];
				this.$areaData[newId]=tmp;
			}
			break;
		}
	},
	//清空工作区及已载入的数据
	clearData:function(){
		for(var key in this.$nodeData){
			this.delNode(key);
		}
		for(var key in this.$lineData){
			this.delLine(key);
		}
		for(var key in this.$areaData){
			this.delArea(key);
		}
		this.$deletedItem={};
	},
	//销毁自己
	destrory:function(){
		this.$bgDiv.empty();
		this.$lineData=null;
		this.$nodeData=null;
		this.$lineDom=null;
		this.$nodeDom=null;
		this.$areaDom=null;
		this.$areaData=null;
		this.$nodeCount=0;
		this.$areaCount=0;
		this.$areaCount=0;
		this.$deletedItem={};
	},
///////////以下为有关画线的方法
	//绘制一条箭头线,并返回线的DOM
	drawLine:function(id,sp,ep,mark,dash){
		var line;
		if(GooFlow.prototype.useSVG!=""){
			line=document.createElementNS("http://www.w3.org/2000/svg","g");
			var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
			var path=document.createElementNS("http://www.w3.org/2000/svg","path");
			if(id!="")	line.setAttribute("id",id);
			line.setAttribute("from",sp[0]+","+sp[1]);
			line.setAttribute("to",ep[0]+","+ep[1]);
			hi.setAttribute("visibility","hidden");
			hi.setAttribute("stroke-width",9);
			hi.setAttribute("fill","none");
			hi.setAttribute("stroke","white");
			hi.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
			hi.setAttribute("pointer-events","stroke");
			path.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
			path.setAttribute("stroke-width",1.4);
			path.setAttribute("stroke-linecap","round");
			path.setAttribute("fill","none");
			if(dash)	path.setAttribute("style", "stroke-dasharray:6,5");
			if(mark){
				path.setAttribute("stroke","#ff3300");
				path.setAttribute("marker-end","url(#arrow2)");
			}
			else{
				path.setAttribute("stroke","#5068AE");
				path.setAttribute("marker-end","url(#arrow1)");
			}
			line.appendChild(hi);
			line.appendChild(path);
			line.style.cursor="crosshair";
			if(id!=""&&id!="GooFlow_tmp_line"){
				var text=document.createElementNS("http://www.w3.org/2000/svg","text");
				//text.textContent=id;
				line.appendChild(text);
				var x=(ep[0]+sp[0])/2;
				var y=(ep[1]+sp[1])/2;
				text.setAttribute("text-anchor","middle");
				text.setAttribute("x",x);
				text.setAttribute("y",y);
				line.style.cursor="pointer";
				text.style.cursor="text";
			}
		}else{
			line=document.createElement("v:polyline");
			if(id!="")	line.id=id;
			//line.style.position="absolute";
			line.points.value=sp[0]+","+sp[1]+" "+ep[0]+","+ep[1];
			line.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
			line.strokeWeight="1.2";
			line.stroke.EndArrow="Block";
			line.style.cursor="crosshair";
			if(id!=""&&id!="GooFlow_tmp_line"){
				var text=document.createElement("div");
				//text.innerHTML=id;
				line.appendChild(text);
				var x=(ep[0]-sp[0])/2;
				var y=(ep[1]-sp[1])/2;
				if(x<0) x=x*-1;
				if(y<0) y=y*-1;
				text.style.left=x+"px";
				text.style.top=y-6+"px";
				line.style.cursor="pointer";
			}
			if(dash)	line.stroke.dashstyle="Dash";
			if(mark)	line.strokeColor="#ff3300";
			else	line.strokeColor="#5068AE";
		}
		return line;
	},
	//画一条只有两个中点的折线
	drawPoly:function(id,sp,m1,m2,ep,mark){
		var poly,strPath;
		if(GooFlow.prototype.useSVG!=""){
			poly=document.createElementNS("http://www.w3.org/2000/svg","g");
			var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
			var path=document.createElementNS("http://www.w3.org/2000/svg","path");
			if(id!="")	poly.setAttribute("id",id);
			poly.setAttribute("from",sp[0]+","+sp[1]);
			poly.setAttribute("to",ep[0]+","+ep[1]);
			hi.setAttribute("visibility","hidden");
			hi.setAttribute("stroke-width",9);
			hi.setAttribute("fill","none");
			hi.setAttribute("stroke","white");
			strPath="M "+sp[0]+" "+sp[1];
			if(m1[0]!=sp[0]||m1[1]!=sp[1])
				strPath+=" L "+m1[0]+" "+m1[1];
			if(m2[0]!=ep[0]||m2[1]!=ep[1])
				strPath+=" L "+m2[0]+" "+m2[1];
			strPath+=" L "+ep[0]+" "+ep[1];
			hi.setAttribute("d",strPath);
			hi.setAttribute("pointer-events","stroke");
			path.setAttribute("d",strPath);
			path.setAttribute("stroke-width",1.4);
			path.setAttribute("stroke-linecap","round");
			path.setAttribute("fill","none");
			if(mark){
				path.setAttribute("stroke","#ff3300");
				path.setAttribute("marker-end","url(#arrow2)");
			}
			else{
				path.setAttribute("stroke","#5068AE");
				path.setAttribute("marker-end","url(#arrow1)");
			}
			poly.appendChild(hi);
			poly.appendChild(path);
			var text=document.createElementNS("http://www.w3.org/2000/svg","text");
			//text.textContent=id;
			poly.appendChild(text);
			var x=(m2[0]+m1[0])/2;
			var y=(m2[1]+m1[1])/2;
			text.setAttribute("text-anchor","middle");
			text.setAttribute("x",x);
			text.setAttribute("y",y);
			text.style.cursor="text";
			poly.style.cursor="pointer";
		}
		else{
			poly=document.createElement("v:Polyline");
			if(id!="")	poly.id=id;
			poly.filled="false";
			strPath=sp[0]+","+sp[1];
			if(m1[0]!=sp[0]||m1[1]!=sp[1])
				strPath+=" "+m1[0]+","+m1[1];
			if(m2[0]!=ep[0]||m2[1]!=ep[1])
				strPath+=" "+m2[0]+","+m2[1];
			strPath+=" "+ep[0]+","+ep[1];
			poly.points.value=strPath;
			poly.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
			poly.strokeWeight="1.2";
			poly.stroke.EndArrow="Block";
			var text=document.createElement("div");
			//text.innerHTML=id;
			poly.appendChild(text);
			var x=(m2[0]-m1[0])/2;
			var y=(m2[1]-m1[1])/2;
			if(x<0) x=x*-1;
			if(y<0) y=y*-1;
			text.style.left=x+"px";
			text.style.top=y-4+"px";
			poly.style.cursor="pointer";
			if(mark)	poly.strokeColor="#ff3300";
			else	poly.strokeColor="#5068AE";
		}
		return poly;
	},
	//计算两个结点间要连直线的话,连线的开始坐标和结束坐标
	calcStartEnd:function(n1,n2){
		var X_1,Y_1,X_2,Y_2;
		//X判断:
		var x11=n1.left,x12=n1.left+n1.width,x21=n2.left,x22=n2.left+n2.width;
		//结点2在结点1左边
		if(x11>=x22){
			X_1=x11;X_2=x22;
		}
		//结点2在结点1右边
		else if(x12<=x21){
			X_1=x12;X_2=x21;
		}
		//结点2在结点1水平部分重合
		else if(x11<=x21&&x12>=x21&&x12<=x22){
			X_1=(x12+x21)/2;X_2=X_1;
		}
		else if(x11>=x21&&x12<=x22){
			X_1=(x11+x12)/2;X_2=X_1;
		}
		else if(x21>=x11&&x22<=x12){
			X_1=(x21+x22)/2;X_2=X_1;
		}
		else if(x11<=x22&&x12>=x22){
			X_1=(x11+x22)/2;X_2=X_1;
		}
		
		//Y判断:
		var y11=n1.top,y12=n1.top+n1.height,y21=n2.top,y22=n2.top+n2.height;
		//结点2在结点1上边
		if(y11>=y22){
			Y_1=y11;Y_2=y22;
		}
		//结点2在结点1下边
		else if(y12<=y21){
			Y_1=y12;Y_2=y21;
		}
		//结点2在结点1垂直部分重合
		else if(y11<=y21&&y12>=y21&&y12<=y22){
			Y_1=(y12+y21)/2;Y_2=Y_1;
		}
		else if(y11>=y21&&y12<=y22){
			Y_1=(y11+y12)/2;Y_2=Y_1;
		}
		else if(y21>=y11&&y22<=y12){
			Y_1=(y21+y22)/2;Y_2=Y_1;
		}
		else if(y11<=y22&&y12>=y22){
			Y_1=(y11+y22)/2;Y_2=Y_1;
		}
		return {"start":[X_1,Y_1],"end":[X_2,Y_2]};
	},
	//计算两个结点间要连折线的话,连线的所有坐标
	calcPolyPoints:function(n1,n2,type,M){
		//开始/结束两个结点的中心
		var SP={x:n1.left+n1.width/2,y:n1.top+n1.height/2};
		var EP={x:n2.left+n2.width/2,y:n2.top+n2.height/2};
		var sp=[],m1=[],m2=[],ep=[];
		//如果是允许中段可左右移动的折线,则参数M为可移动中段线的X坐标
		//粗略计算起始点
		sp=[SP.x,SP.y];
		ep=[EP.x,EP.y];
		if(type=="lr"){
			//粗略计算2个中点
			m1=[M,SP.y];
			m2=[M,EP.y];
			//再具体分析修改开始点和中点1
			if(m1[0]>n1.left&&m1[0]<n1.left+n1.width){
				m1[1]=(SP.y>EP.y? n1.top:n1.top+n1.height);
				sp[0]=m1[0];sp[1]=m1[1];
			}
			else{
				sp[0]=(m1[0]<n1.left? n1.left:n1.left+n1.width)
			}
			//再具体分析中点2和结束点
			if(m2[0]>n2.left&&m2[0]<n2.left+n2.width){
				m2[1]=(SP.y>EP.y? n2.top+n2.height:n2.top);
				ep[0]=m2[0];ep[1]=m2[1];
			}
			else{
				ep[0]=(m2[0]<n2.left? n2.left:n2.left+n2.width)
			}
		}
		//如果是允许中段可上下移动的折线,则参数M为可移动中段线的Y坐标
		else if(type=="tb"){
			//粗略计算2个中点
			m1=[SP.x,M];
			m2=[EP.x,M];
			//再具体分析修改开始点和中点1
			if(m1[1]>n1.top&&m1[1]<n1.top+n1.height){
				m1[0]=(SP.x>EP.x? n1.left:n1.left+n1.width);
				sp[0]=m1[0];sp[1]=m1[1];
			}
			else{
				sp[1]=(m1[1]<n1.top? n1.top:n1.top+n1.height)
			}
			//再具体分析中点2和结束点
			if(m2[1]>n2.top&&m2[1]<n2.top+n2.height){
				m2[0]=(SP.x>EP.x? n2.left+n2.width:n2.left);
				ep[0]=m2[0];ep[1]=m2[1];
			}
			else{
				ep[1]=(m2[1]<n2.top? n2.top:n2.top+n2.height);
			}
		}
		return {start:sp,m1:m1,m2:m2,end:ep};
	},
	//初始化折线中段的X/Y坐标,mType='rb'时为X坐标,mType='tb'时为Y坐标
	getMValue:function(n1,n2,mType){
		if(mType=="lr"){
			return (n1.left+n1.width/2+n2.left+n2.width/2)/2;
		}
		else if(mType=="tb"){
			return (n1.top+n1.height/2+n2.top+n2.height/2)/2;
		}
	},
	//原lineData已经设定好的情况下,只在绘图工作区画一条线的页面元素
	addLineDom:function(id,lineData){
		var n1=this.$nodeData[lineData.from],n2=this.$nodeData[lineData.to];//获取开始/结束结点的数据
		if(!n1||!n2)	return;
		//开始计算线端点坐标
		var res;
		if(lineData.type&&lineData.type!="sl")
			res=GooFlow.prototype.calcPolyPoints(n1,n2,lineData.type,lineData.M);
		else
			res=GooFlow.prototype.calcStartEnd(n1,n2);
		if(!res)	return;
		
		if(lineData.type=="sl")
			this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,lineData.mark);
		else
			this.$lineDom[id]=GooFlow.prototype.drawPoly(id,res.start,res.m1,res.m2,res.end,lineData.mark);
		this.$draw.appendChild(this.$lineDom[id]);
		if(GooFlow.prototype.useSVG==""){
			this.$lineDom[id].childNodes[1].innerHTML=lineData.name;
			if(lineData.type!="sl"){
				var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
				if(Min>res.m2[0])	Min=res.m2[0];
				if(Min>res.m1[0])	Min=res.m1[0];
				this.$lineDom[id].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
				Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
				if(Min>res.m2[1])	Min=res.m2[1];
				if(Min>res.m1[1])	Min=res.m1[1];
				this.$lineDom[id].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2;
			}else
				this.$lineDom[id].childNodes[1].style.left=
				((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
		}
		else	this.$lineDom[id].childNodes[2].textContent=lineData.name;
	},
	//增加一条线
	addLine:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"line",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delLine",[id]);
		}
		if(json.from==json.to)	return;
		var n1=this.$nodeData[json.from],n2=this.$nodeData[json.to];//获取开始/结束结点的数据
		if(!n1||!n2)	return;
		//避免两个节点间不能有一条以上同向接连线
		for(var k in this.$lineData){
			if((json.from==this.$lineData[k].from&&json.to==this.$lineData[k].to))
				return;
		}
		//设置$lineData[id]
		this.$lineData[id]={};
		if(json.type){
			this.$lineData[id].type=json.type;
			this.$lineData[id].M=json.M;
		}
		else	this.$lineData[id].type="sl";//默认为直线
		this.$lineData[id].from=json.from;
		this.$lineData[id].to=json.to;
		this.$lineData[id].name=json.name;
		if(json.mark)	this.$lineData[id].marked=json.mark;
		else	this.$lineData[id].marked=false;
		//设置$lineData[id]完毕
		
		this.addLineDom(id,this.$lineData[id]);
		
		++this.$lineCount;
		if(this.$editable){
			this.$lineData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	//重构所有连向某个结点的线的显示,传参结构为$nodeData数组的一个单元结构
	resetLines:function(id,node){
		for(var i in this.$lineData){
		  var other=null;//获取结束/开始结点的数据
		  var res;
		  if(this.$lineData[i].from==id){//找结束点
			other=this.$nodeData[this.$lineData[i].to]||null;
			if(other==null)	continue;
			if(this.$lineData[i].type=="sl")
				res=GooFlow.prototype.calcStartEnd(node,other);
			else
				res=GooFlow.prototype.calcPolyPoints(node,other,this.$lineData[i].type,this.$lineData[i].M)
			if(!res)	break;
		  }
		  else if(this.$lineData[i].to==id){//找开始点
			other=this.$nodeData[this.$lineData[i].from]||null;
			if(other==null)	continue;
			if(this.$lineData[i].type=="sl")
				res=GooFlow.prototype.calcStartEnd(other,node);
			else
				res=GooFlow.prototype.calcPolyPoints(other,node,this.$lineData[i].type,this.$lineData[i].M);
			if(!res)	break;
		  }
		  if(other==null)	continue;
		  this.$draw.removeChild(this.$lineDom[i]);
		  if(this.$lineData[i].type=="sl"){
		  	this.$lineDom[i]=GooFlow.prototype.drawLine(i,res.start,res.end,this.$lineData[i].marked);
		  }
		  else{
			this.$lineDom[i]=GooFlow.prototype.drawPoly(i,res.start,res.m1,res.m2,res.end,this.$lineData[i].marked);
		  }
		  this.$draw.appendChild(this.$lineDom[i]);
		  if(GooFlow.prototype.useSVG==""){
			this.$lineDom[i].childNodes[1].innerHTML=this.$lineData[i].name;
			if(this.$lineData[i].type!="sl"){
				var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
				if(Min>res.m2[0])	Min=res.m2[0];
				if(Min>res.m1[0])	Min=res.m1[0];
				this.$lineDom[i].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[i].childNodes[1].offsetWidth/2+4;
				Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
				if(Min>res.m2[1])	Min=res.m2[1];
				if(Min>res.m1[1])	Min=res.m1[1];
				this.$lineDom[i].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[i].childNodes[1].offsetHeight/2-4;
			}else
				this.$lineDom[i].childNodes[1].style.left=
				((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[i].childNodes[1].offsetWidth)/2+4;
		  }
		  else	this.$lineDom[i].childNodes[2].textContent=this.$lineData[i].name;
		}
	},
	//重新设置连线的样式 newType= "sl":直线, "lr":中段可左右移动型折线, "tb":中段可上下移动型折线
	setLineType:function(id,newType,M){
		if(!newType||newType==null||newType==""||newType==this.$lineData[id].type)	return false;
		if(this.onLineSetType!=null&&!this.onLineSetType(id,newType))	return;
		if(this.$undoStack){
			var paras=[id,this.$lineData[id].type,this.$lineData[id].M];
			this.pushOper("setLineType",paras);
		}
		var from=this.$lineData[id].from;
		var to=this.$lineData[id].to;
		this.$lineData[id].type=newType;
		var res;
		//如果是变成折线
		if(newType!="sl"){
		  var res=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
		  if(M){
		  	this.setLineM(id,M,true);
		  }else{
		  	this.setLineM(id,this.getMValue(this.$nodeData[from],this.$nodeData[to],newType),true);
		  }
		}
		//如果是变回直线
		else{
		  delete this.$lineData[id].M;
		  this.$lineMove.hide().removeData("type").removeData("tid");
		  res=GooFlow.prototype.calcStartEnd(this.$nodeData[from],this.$nodeData[to]);
		  if(!res)	return;
		  this.$draw.removeChild(this.$lineDom[id]);
		  this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,this.$lineData[id].marked||this.$focus==id);
		  this.$draw.appendChild(this.$lineDom[id]);
		  if(GooFlow.prototype.useSVG==""){
		  	this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
			this.$lineDom[id].childNodes[1].style.left=
			((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
		  }
		  else
			this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
		}
		if(this.$focus==id){
			this.focusItem(id);
		}
		if(this.$editable){
			this.$lineData[id].alt=true;
		}
	},
	//设置折线中段的X坐标值(可左右移动时)或Y坐标值(可上下移动时)
	setLineM:function(id,M,noStack){
		if(!this.$lineData[id]||M<0||!this.$lineData[id].type||this.$lineData[id].type=="sl")	return false;
		if(this.onLineMove!=null&&!this.onLineMove(id,M))	return false;
		if(this.$undoStack&&!noStack){
			var paras=[id,this.$lineData[id].M];
			this.pushOper("setLineM",paras);
		}
		var from=this.$lineData[id].from;
		var to=this.$lineData[id].to;
		this.$lineData[id].M=M;
		var ps=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
		this.$draw.removeChild(this.$lineDom[id]);
		this.$lineDom[id]=GooFlow.prototype.drawPoly(id,ps.start,ps.m1,ps.m2,ps.end,this.$lineData[id].marked||this.$focus==id);
		this.$draw.appendChild(this.$lineDom[id]);
		if(GooFlow.prototype.useSVG==""){
			this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
			var Min=(ps.start[0]>ps.end[0]? ps.end[0]:ps.start[0]);
			if(Min>ps.m2[0])	Min=ps.m2[0];
			if(Min>ps.m1[0])	Min=ps.m1[0];
			this.$lineDom[id].childNodes[1].style.left = (ps.m2[0]+ps.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
			Min=(ps.start[1]>ps.end[1]? ps.end[1]:ps.start[1]);
			if(Min>ps.m2[1])	Min=ps.m2[1];
			if(Min>ps.m1[1])	Min=ps.m1[1];
			this.$lineDom[id].childNodes[1].style.top = (ps.m2[1]+ps.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2-4;
		}
		else	this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
		if(this.$editable){
			this.$lineData[id].alt=true;
		}
	},
	//删除转换线
	delLine:function(id){
		if(!this.$lineData[id])	return;
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		if(this.$undoStack){
			var paras=[id,this.$lineData[id]];
			this.pushOper("addLine",paras);
		}
		this.$draw.removeChild(this.$lineDom[id]);
		delete this.$lineData[id];
		delete this.$lineDom[id];
		if(this.$focus==id)	this.$focus="";
		--this.$lineCount;
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_line_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_line_")<0)
			this.$deletedItem[id]="line";
		}
		this.$lineOper.hide();
	},
	//变更连线两个端点所连的结点
	//参数:要变更端点的连线ID,新的开始结点ID、新的结束结点ID;如果开始/结束结点ID是传入null或者"",则表示原端点不变
	moveLinePoints:function(lineId, newStart, newEnd, noStack){
		if(newStart==newEnd)	return;
		if(!lineId||!this.$lineData[lineId])	return;
		if(newStart==null||newStart=="")
			newStart=this.$lineData[lineId].from;
		if(newEnd==null||newEnd=="")
			newEnd=this.$lineData[lineId].to;
		//避免两个节点间不能有一条以上同向接连线
		for(var k in this.$lineData){
			if((newStart==this.$lineData[k].from&&newEnd==this.$lineData[k].to))
				return;
		}
		if(this.onLinePointMove!=null&&!this.onLinePointMove(id,newStart,newEnd))	return;
		if(this.$undoStack&&!noStack){
			var paras=[lineId,this.$lineData[lineId].from,this.$lineData[lineId].to];
			this.pushOper("moveLinePoints",paras);
		}
		if(newStart!=null&&newStart!=""){
			this.$lineData[lineId].from=newStart;
		}
		if(newEnd!=null&&newEnd!=""){
			this.$lineData[lineId].to=newEnd;
		}
		//重建转换线
		this.$draw.removeChild(this.$lineDom[lineId]);
		this.addLineDom(lineId,this.$lineData[lineId]);
		if(this.$editable){
			this.$lineData[lineId].alt=true;
		}
	},
	
	//用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。
	//这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。
	markItem:function(id,type,mark){
		if(type=="node"){
			if(!this.$nodeData[id])	return;
			if(this.onItemMark!=null&&!this.onItemMark(id,"node",mark))	return;
			this.$nodeData[id].marked=mark||false;
			if(mark)	this.$nodeDom[id].addClass("item_mark");
			else	this.$nodeDom[id].removeClass("item_mark");
			
		}else if(type=="line"){
			if(!this.$lineData[id])	return;
			if(this.onItemMark!=null&&!this.onItemMark(id,"line",mark))	return;
			this.$lineData[id].marked=mark||false;
			if(GooFlow.prototype.useSVG!=""){
				if(mark){
					this.$nodeDom[id].childNodes[1].setAttribute("stroke","#ff3300");
					this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow2)");
				}else{
					this.$nodeDom[id].childNodes[1].setAttribute("stroke","#5068AE");
					this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow1)");
				}
			}else{
				if(mark)	this.$nodeDom[id].strokeColor="#ff3300";
				else	this.$nodeDom[id].strokeColor="#5068AE"
			}
		}
		if(this.$undoStatck){
			var paras=[id,type,!mark];
			this.pushOper("markItem",paras);
		}
	},
	////////////////////////以下为区域分组块操作
	moveArea:function(id,left,top){
		if(!this.$areaData[id])	return;
		if(this.onItemMove!=null&&!this.onItemMove(id,"area",left,top))	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].left,this.$areaData[id].top];
			this.pushOper("moveNode",paras);
		}
		if(left<0)	left=0;
		if(top<0)	top=0;
		$("#"+id).css({left:left+"px",top:top+"px"});
		this.$areaData[id].left=left;
		this.$areaData[id].top=top;
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	//删除区域分组
	delArea:function(id){
		if(!this.$areaData[id])	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id]];
			this.pushOper("addArea",paras);
		}
		if(this.onItemDel!=null&&!this.onItemDel(id,"node"))	return;
		delete this.$areaData[id];
		this.$areaDom[id].remove();
		delete this.$areaDom[id];
		--this.$areaCount;
		if(this.$editable){
			//在回退新增操作时,如果节点ID以this.$id+"_area_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
			if(id.indexOf(this.$id+"_area_")<0)
			this.$deletedItem[id]="area";
		}
	},
	//设置区域分组的颜色
	setAreaColor:function(id,color){
		if(!this.$areaData[id])	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].color];
			this.pushOper("setAreaColor",paras);
		}
		if(color=="red"||color=="yellow"||color=="blue"||color=="green"){
			this.$areaDom[id].removeClass("area_"+this.$areaData[id].color).addClass("area_"+color);
			this.$areaData[id].color=color;
		}
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	//设置区域分块的尺寸
	resizeArea:function(id,width,height){
		if(!this.$areaData[id])	return;
		if(this.onItemResize!=null&&!this.onItemResize(id,"area",width,height))	return;
		if(this.$undoStack){
			var paras=[id,this.$areaData[id].width,this.$areaData[id].height];
			this.pushOper("resizeArea",paras);
		}
		var hack=0;
		if(navigator.userAgent.indexOf("8.0")!=-1)	hack=2;
		this.$areaDom[id].children(".bg").css({width:width-2+"px",height:height-2+"px"});
		width=this.$areaDom[id].outerWidth();
		height=this.$areaDom[id].outerHeight();
		this.$areaDom[id].children("bg").css({width:width-2+"px",height:height-2+"px"});
		this.$areaData[id].width=width;
		this.$areaData[id].height=height;
		if(this.$editable){
			this.$areaData[id].alt=true;
		}
	},
	addArea:function(id,json){
		if(this.onItemAdd!=null&&!this.onItemAdd(id,"area",json))return;
		if(this.$undoStack&&this.$editable){
			this.pushOper("delArea",[id]);
		}
		this.$areaDom[id]=$("<div id='"+id+"' class='GooFlow_area area_"+json.color+"' style='top:"+json.top+"px;left:"+json.left+"px'><div class='bg' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px'></div>"
		+"<label>"+json.name+"</label><b></b><div><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div></div>");
		this.$areaData[id]=json;
		this.$group.append(this.$areaDom[id]);
		if(this.$nowType!="group")	this.$areaDom[id].children("div:eq(1)").css("display","none");
		++this.$areaCount;
		if(this.$editable){
			this.$areaData[id].alt=true;
			if(this.$deletedItem[id])	delete this.$deletedItem[id];//在回退删除操作时,去掉该元素的删除记录
		}
	},
	//重构整个流程图设计器的宽高
	reinitSize:function(width,height){
		var w=(width||800)-2;
		var h=(height||500)-2;
		this.$bgDiv.css({height:h+"px",width:w+"px"});
		var headHeight=0,hack=10;
		if(this.$head!=null){
			headHeight=24;
			hack=7;
		}
		if(this.$tool!=null){
			this.$tool.css({height:h-headHeight-hack+"px"});
		}
		w-=39;
		h=h-headHeight-(this.$head!=null? 5:8);
		this.$workArea.parent().css({height:h+"px",width:w+"px"});
		this.$workArea.css({height:h*3+"px",width:w*3+"px"});
		if(GooFlow.prototype.useSVG==""){
			this.$draw.coordsize = w*3+","+h*3;
		}
		this.$draw.style.width = w*3 + "px";
		this.$draw.style.height = +h*3 + "px";
		if(this.$group==null){
			this.$group.css({height:h*3+"px",width:w*3+"px"});
		}
	}
}
//将此类的构造函数加入至JQUERY对象中
jQuery.extend({
	createGooFlow:function(bgDiv,property){
		return new GooFlow(bgDiv,property);
	}
}); 

+ 0 - 131
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow2.css

@ -1,131 +0,0 @@
v\:group,v\:rect,v\:imagedata,v\:oval,v\:line,v\:polyline,v\:stroke,v\:textbox { display:inline-block;background:transparent }
.GooFlow{
	background:#F5F5F5;border:#ccc 1px solid;font: 0.8em Microsoft Yahei;
	-moz-user-select:none;-webkit-user-select:none;border-radius:4px;color:#333
}
.GooFlow i{font: 1em}
.GooFlow_head{clear:both;height:20px;padding:1px;border-bottom:#00B4E1 2px solid;}
.GooFlow_head label{
	font-weight:bold;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:18px;padding:2px;width:170px;text-align:center;
	background:#00B4E1;float:left;color:#fff;border-radius:3px 0px 0px 0px;overflow:hidden;margin:-1px 4px 0px -1px;
}
.GooFlow_head span{float:left;height:22px;width:0px;overflow:hidden;border-left:#3892D3 1px solid;margin:0px 3px;}
.GooFlow_head_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:1px;margin:0px 3px;float:left;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_head_btn i{display:inline-block;overflow:hidden;width:18px;height:18px;border:0px;}
.GooFlow_head_btn:hover{border-radius:2px;background:#FFBF00}
.GooFlow_head_btn:hover i{}
.GooFlow_tool{float:left;padding:0px 3px;overflow:hidden;clear:left;border-right:#ccc 1px solid}
.GooFlow_tool_div{overflow:hidden;border-radius:2px;width:24px;padding:2px}
.GooFlow_tool span{height:0px;overflow:hidden;border-top:#ccc 1px solid;margin:3px 1px;clear:both;display:block;}
.GooFlow_tool_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:3px 1px;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_tool_btn i{display:block;overflow:hidden;width:18px;height:18px;border:0px}
.GooFlow_tool_btn:hover{border-radius:3px;padding:0px;border:#99B1CE 1px solid;width:20px;height:20px;background:#fff}
.GooFlow_tool_btn:hover i{margin:1px;border-radius:2px}
.GooFlow_tool_btndown{
	cursor:default;margin:3px 1px;outline:none;blr:expression(this.onFocus=this.blur());
	border-radius:3px;padding:2px;background:#FFBF00;display:block;
}
.GooFlow_tool_btndown i{display:block;overflow:hidden;width:18px;height:18px;border-radius:2px}
.GooFlow_work{float:right;margin:0px 3px 3px 0px;border:#F5F5F5 1px solid;position:relative;overflow:scroll;}
.GooFlow_work .GooFlow_work_inner{background-image:url(img/gooflow_blank2.gif);position:relative;overflow:hidden;}
.GooFlow_work .GooFlow_work_group{cursor:default;position:absolute;overflow:hidden;top:0px;left:0px}
.GooFlow_work text{color:#fff}
.GooFlow_area{cursor:default;position:absolute;overflow:hidden;}
.GooFlow_area .lock{cursor:default;}
.GooFlow_area .bg{cursor:move;filter:Alpha(Opacity=30);-moz-opacity:0.3;opacity: 0.3;}
.GooFlow_work .lock .bg{cursor:default;}
.GooFlow_area label{cursor:text;top:1px;left:1px;position:absolute;display:block;font-size:12px;text-indent:18px;height:18px;line-height:18px}
.GooFlow_work .lock label{cursor:default;}
.GooFlow_area i{display:block;height:18px;widht:18px;top:0px;left:0px;position:absolute;cursor:pointer}
.GooFlow_work .area_red .bg{border:1px solid red;background-color:#FF7865}
.GooFlow_work .area_red label{color:red;background:url(img/gooflow_bullet.png) no-repeat 1px 1px}
.GooFlow_work .area_yellow .bg{border:1px solid #CD925A;background-color:#FFD564}
.GooFlow_work .area_yellow label{color:#FFBA1D;background:url(img/gooflow_bullet.png) no-repeat 1px -16px}
.GooFlow_work .area_blue .bg{border:1px solid #347BB1;background-color:#549CDE}
.GooFlow_work .area_blue label{color:#347BB1;background:url(img/gooflow_bullet.png) no-repeat 1px -33px}
.GooFlow_work .area_green .bg{border:1px solid green;background-color:#84CA04}
.GooFlow_work .area_green label{color:green;background:url(img/gooflow_bullet.png) no-repeat 1px -50px}
.GooFlow_work svg{display:block;position:absolute}
.GooFlow_work v\:group{position:relative;display:block}
.GooFlow_work v\:group v\:line{overflow:visible}
.GooFlow_work v\:group v\:polyline{overflow:visible}
.GooFlow_work v\:group div{cursor:text;position:absolute;overflow:visible;display:inline;float:left;white-space: nowrap}
.GooFlow_work .draw{color:#ff3300}
.GooFlow_item{
	position:absolute;background:#A1DCEB;border:#A1DCEB solid 1px;
	border-radius:3px;background-color:#C1DCFC;box-shadow:1px 1px 2px rgba(99,99,99,2);
}
.GooFlow table{padding:1px;border-radius:2px}
.GooFlow td{ vertical-align:middle;text-align:center;padding:0px;cursor:default;word-wrap:break-word;word-break:break-all}
.GooFlow .ico{width:18px;cursor:move}
.GooFlow i{display:block;width:18px;height:18px;overflow:hidden}
.GooFlow .item_round{border-radius:11px;border:#C1DCFC solid 1px;width:22px;height:22px; overflow:visible}
.GooFlow .item_round table{border:0px;padding:2px;width:22px;height:22px}
.GooFlow .item_round .span{
	display:block;text-align:center; position:absolute;top:24px;left:-28px;width:80px;overflow:visible;text-align:center;
	padding:0px;cursor:default;word-wrap: break-word;word-break:break-all
}
.GooFlow .item_mix{background:#B6F700;border-color:#C2DB4E;color:#fff}
.GooFlow div .rs_right{overflow:hidden;position:absolute;right:-1px;top:-1px;height:100%;width:6px;cursor:w-resize}
.GooFlow div .rs_bottom{overflow:hidden;position:absolute;left:-1px;bottom:-1px;width:100%;height:6px;cursor:n-resize}
.GooFlow div .rs_rb{
	position:absolute;right:-1px;bottom:-1px;width:9px;height:9px;overflow:hidden;cursor:nw-resize;background:url(img/gooflow_tip.png) no-repeat 0px -8px;
}
.GooFlow div .rs_close{
	position:absolute;right:1px;top:1px;width:7px;height:7px;overflow:hidden;cursor:pointer;background:url(img/gooflow_tip.png) no-repeat 0px 0px
}
.GooFlow .rs_ghost{
	position:absolute;display:none;overflow:hidden;border:#8EA4C1 1px dashed; background:#D9E8FB;
	filter:Alpha(Opacity=60);-moz-opacity:0.6;opacity: 0.6;z-index:10
}
.GooFlow .item_focus{border:#3892D3 1px solid}
.GooFlow .item_mark{border:#ff3300 1px solid}
.GooFlow .item_mark td{cursor:crosshair}
.GooFlow textarea{position:absolute;border:#3892D3 1px solid;display:none;font: 1em Microsoft Yahei;overflow-y:visible;width:100px;z-index:10001}
.GooFlow .GooFlow_line_oper{
	width:70px;height:15px;background-color:#D8E8FC;border:#7DA2CE 1px solid;position:absolute;
	filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity: 0.5;z-index:10000;
}
.GooFlow .GooFlow_line_mp{
	width:9px;height:9px;filter:Alpha(Opacity=40);-moz-opacity:0.4;opacity:0.4;overflow:hidden;
	position:absolute;z-index:9999;background:#333;cursor:crosshair
}
.GooFlow .GooFlow_line_move{filter:Alpha(Opacity=50);-moz-opacity:0.5;opacity:0.5;overflow:hidden;position:absolute;z-index:9999;background:url(0) no-repeat}
.GooFlow .GooFlow_line_oper i{display:inline-block;width:15px;height:15px;margin-left:2px;cursor:pointer}
.GooFlow .b_l1{background:url(img/GooFlow_line_oper.png) no-repeat 1px 1px}
.GooFlow .b_l2{background:url(img/GooFlow_line_oper.png) no-repeat 1px -14px}
.GooFlow .b_l3{background:url(img/GooFlow_line_oper.png) no-repeat 1px -29px}
.GooFlow .b_x{background:url(img/GooFlow_line_oper.png) no-repeat 1px -44px;margin-left:10px}
.GooFlow .ico_cursor{background:url(img/gooflow_icon.png) no-repeat 2px -20px}
.GooFlow .ico_start{background:url(img/gooflow_icon.png) no-repeat -19px -20px}
.GooFlow .ico_end{background:url(img/gooflow_icon.png) no-repeat -39px -20px}
.GooFlow .ico_fork{background:url(img/gooflow_icon.png) no-repeat -59px -20px}
.GooFlow .ico_join{background:url(img/gooflow_icon.png) no-repeat -78px -20px}
.GooFlow .ico_direct{background:url(img/gooflow_icon.png) no-repeat -137px -20px}
.GooFlow .ico_group{background:url(img/gooflow_icon.png) no-repeat -96px -20px}
.GooFlow .ico_complex{background:url(img/gooflow_icon.png) no-repeat -116px -20px}
.GooFlow .ico_node{background:url(img/gooflow_icon.png) no-repeat -19px -45px}
.GooFlow .ico_task{background:url(img/gooflow_icon.png) no-repeat 2px -45px}
.GooFlow .ico_chat{background:url(img/gooflow_icon.png) no-repeat -38px -45px}
.GooFlow .ico_state{background:url(img/gooflow_icon.png) no-repeat -59px -45px}
.GooFlow .ico_plug{background:url(img/gooflow_icon.png) no-repeat -135px -45px}
.GooFlow .ico_menu{background:url(img/gooflow_icon.png) no-repeat 1px -65px}
.GooFlow .ico_sound{background:url(img/gooflow_icon.png) no-repeat -18px -65px}
.GooFlow .ico_topo{background:url(img/gooflow_icon.png) no-repeat -117px -45px}
.GooFlow .ico_open{background:url(img/gooflow_icon.png) no-repeat -19px 1px}
.GooFlow .ico_new{background:url(img/gooflow_icon.png) no-repeat 2px 1px}
.GooFlow .ico_reload{background:url(img/gooflow_icon.png) no-repeat -97px 1px}
.GooFlow .ico_save{background:url(img/gooflow_icon.png) no-repeat -39px 1px}
.GooFlow .ico_undo{background:url(img/gooflow_icon.png) no-repeat -58px 1px}
.GooFlow .ico_redo{background:url(img/gooflow_icon.png) no-repeat -78px 1px}
.GooFlow .ico_mutiselect{background:url(img/gooflow_icon.png) no-repeat -156px 1px}

+ 0 - 16
src/main/webapp/develop/lib/gooflow/goo/codebase/GooFlow_color.js

@ -1,16 +0,0 @@
GooFlow.prototype.color={
  main:"#00B4E1",
  node:"#A1DCEB",
  line:"#3892D3",
  mark:"#ff3300",
  mix:"#B6F700",
  font:"#15428B"
};/*
GooFlow.prototype.color={
  main:"#A8C508",
  node:"#DFE9B4",
  line:"#A8C508",
  mark:"#E98200",
  mix:"#B6F700",
  font:"#357425"
};*/

BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/Thumbs.db


BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_bg.png


BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank.gif


BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank2.gif


+ 0 - 12
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_blank2.htm

@ -1,12 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0014)about:internet -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>gooflow_blank2</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!--Fireworks CS6 Dreamweaver CS6 target.  Created Sun Oct 20 14:50:21 GMT+0800 2013-->
</head>
<body bgcolor="#ffffff">
<img name="gooflow_blank2" src="gooflow_blank2.gif" width="10" height="10" id="gooflow_blank2" alt="" /></body>
</html>

BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_btn_bg.png


BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_icon.png


BIN
src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_icon2.png


Файловите разлики са ограничени, защото са твърде много
+ 0 - 1
src/main/webapp/develop/lib/gooflow/goo/data.js


BIN
src/main/webapp/develop/lib/gooflow/goo/ui-icons_222222_256x240.png


BIN
src/main/webapp/develop/lib/gooflow/goo/未命名-3 - 副本.png


BIN
src/main/webapp/develop/lib/gooflow/goo/未命名-3.png


src/main/webapp/develop/lib/gooflow/goo/codebase/img/GooFlow_line_oper.png → src/main/webapp/develop/lib/gooflow/img/GooFlow_line_oper.png


BIN
src/main/webapp/develop/lib/gooflow/img/arrow.png


src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_bullet.png → src/main/webapp/develop/lib/gooflow/img/gooflow_bullet.png


BIN
src/main/webapp/develop/lib/gooflow/img/gooflow_icon.png


src/main/webapp/develop/lib/gooflow/goo/codebase/img/gooflow_tip.png → src/main/webapp/develop/lib/gooflow/img/gooflow_tip.png


BIN
src/main/webapp/develop/lib/gooflow/img/sprite.head-tool.png


BIN
src/main/webapp/develop/lib/gooflow/img/sprite.tool.png


BIN
src/main/webapp/develop/lib/gooflow/img/sprite.work-are.png


Файловите разлики са ограничени, защото са твърде много
+ 0 - 2
src/main/webapp/develop/lib/gooflow/jquery.min.js


+ 2094 - 0
src/main/webapp/develop/lib/gooflow/js/GooFlow.js

@ -0,0 +1,2094 @@
//公共方法
var GooFunc = {
	getElCoordinate: function (dom) {
		var t = dom.offsetTop;
		var l = dom.offsetLeft;
		dom = dom.offsetParent;
		while (dom) {
			t += dom.offsetTop;
			l += dom.offsetLeft;
			dom = dom.offsetParent;
		};
		return {top: t, left: l};
	},
	mousePosition: function (ev) {
		var dom = document.getElementById('divIndexContent');
		var domX = dom.scrollLeft;
		var domY = dom.scrollTop;
		//兼容各种浏览器的,获取鼠标真实位置
		if (!ev) ev = window.event;
		if (ev.pageX || ev.pageY) {
			return {x: ev.pageX + domX, y: ev.pageY + domY};
		}
		return {
			x: ev.clientX + document.documentElement.scrollLeft - document.body.clientLeft,
			y: ev.clientY + document.documentElement.scrollTop - document.body.clientTop
		};
	},
	getAjaxData: function (url, successFn, completeFn) {
		$.ajax({
			url: url,
			type: 'GET',
			async: true,
			dataType: 'json',
			success: successFn,
			error: function (data, xhr, textStatus) {
				console.log('错误')
				console.log(xhr)
				console.log(textStatus)
			},
			complete: completeFn
		})
	}
}
/*
 * Todo:  ## 构造函数 ***************************************************************************************
 * Author: LE
 * Date: 2017/2/15
 * time: 14:59
 * */
function GooFlow(bgDiv, property,url) {
	/*
	 * Todo: 初始化属性设置 【初始化】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:17
	 * */
	// *************************************************** 【UI相关】
	this.$id = property.id || bgDiv.attr("id"); // 容器id
	this.$bgDiv = bgDiv;                        // 容器对象
	this.$headBox = null;                       // 头部容器对象
	this.$toolBar = null;                       // 工具栏操作
	this.$flowChart = null;                     // 流程图工具
	this.$contBox = null;                       // 主内容容器
	this.$contBoxLeft = null;                   // 端点内容
	this.$contBoxRight = null;                  // 转换器内容
	this.$workAreaWrap = null;                  // 流程图区域容器
	this.$workArea = null;                      // 流程图区域
	this.$draw = null;                          // SVG绘制区
	this.$fileCode = '';                        // 流程图文件唯一标识
	this.$fileName = '';                        // 流程图文件名称
	// *************************************************** 【线条相关】
	this.$lineData = {};                        // 数据
	this.$lineType = '';                        // 类型
	this.$lineCount = 0;                        // 数量
	this.$lineDom = {};                         // DOM
	this.$lineMoveing = false;                  // 是否在移动
	this.$deteLineId = '';                      // 删除指定ID
	this.$lineMove = null;                      // 线条移动镜像
	this.$canDelLine = false;                   // 是否使用Delete删除线条
	// *************************************************** 【结点相关】
	this.$nodeData = {};                        // 数据
	this.$nodeCount = 0;                        // 数量
	this.$nodeDom = {};                         // DOM
	this.$newNodeValue = '';                    // 值
	this.$nodeConfig = '';                    // 配置项
	this.$nodeType = '';                        // 结点类型
	this.$deteNodeId = '';                      // 删除指定ID
	this.$ghost = null;                         // 结点镜像
	// *************************************************** 【当前选中】
	this.$nowType = "cursor";                   // 当前操作类型
	this.$focus = "";                           // SVG操作区中选中对象
	// *************************************************** 【其他】
	this.$MainContener = property.MainContener; // 重要内容
	this.$editable = property.editable;         // 是否可编辑
	// *************************************************** 【公用变量】
	var that = this;
	// *************************************************** 【请求地址】
	var getAllEndpointsURL = url + "/process/getAllEndpoints",
		getAllProcessorsURL = url + "/process/getAllProcessors",
		dataPostURL = URL + "/process/json";
	/*
	 * Todo: 初始化布局 【初始化】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:17
	 * */
	this.$headBox = $("<div class='GooFlow_top_box'></div>");  // 头部
	this.$contBox = $("<div class='GooFlow_cont_box'></div>"); // 中间主体内容
	this.$bgDiv.append(this.$headBox).append(this.$contBox);
	/*
	 * Todo: 工具栏构建 【UI相关--HEAD】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:17
	 * */
	if (property.haveTool) {
		var HtmlStr = "",
			i = 0,
			length = property.toolBtns.length;
		// 工具栏UI构建
		HtmlStr = "<div class='GooFlow_tool'>";
		for (; i < length; ++i) {
			HtmlStr += "<i class='ico_" + property.toolBtns[i] + "'></i>";
		}
		HtmlStr += "</div>";
		this.$toolBar = $(HtmlStr);
		this.$headBox.append(this.$toolBar);
		// 工具栏功能绑定
		this.$toolBar.children().on("click", function () {
			var icoName = $(this).attr("class").match(/ico_\w+/g)[0];
			switch (icoName) {
				case "ico_save":
					that.exportData();
					break;
				case "ico_undo":
					that.undo();
					break;
				case "ico_redo":
					that.redo();
					break;
			}
		});
	}
	/*
	 * Todo: 流程图结点构建 【UI相关--HEAD】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:17
	 * */
	if (property.flowChart) {
		var HtmlStr = "",
			i = 0,
			length = property.flowBtns.length;
		// 流程图结点UI构建
		HtmlStr += "<div class='GooFlow_flowChart'>"
		// 加入用户自定义工具栏
		for (; i < length; ++i) {
			HtmlStr += "<i id='" + this.$id + "_btn_" + property.flowBtns[i] + "' class='ico_" + property.flowBtns[i] + "'/></i>";
		}
		HtmlStr += "</div>"
		this.$flowChart = $(HtmlStr);
		this.$headBox.append(this.$flowChart);
	}
	/*
	 * Todo: 端点及转换器公共筛选方法
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	function itemSearchFn(obj) {
		var $list = obj.find($('.GooFlow_app_list_item'));
		var $input = obj.find($('.GooFlow_app_search_input'));
		var $item = obj.find($('.GooFlow_app_item'));
		$input.on('keyup', {inthis: that}, function () {
			var input = $input.val()
			if (input.length > 0) {
				$item.hide();
				var filterObj = $item.filter(function (index) {
					return $(this).text().indexOf(input) >= 0;
				})
				if (filterObj.length > 0) {
					filterObj.css("display", "block").parent().parent().parent().addClass('selected');
				} else {
					$item.show();
					$list.removeClass('selected');
				}
			}
			else {
				$item.show();
				$list.removeClass('selected');
			}
		})
	}
	/*
	 * Todo: 端点及转换器公共HTML结构搭建 【UI相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	function renderHtml(title, className, htmlStr) {
		var appBox = $("<div class='GooFlow_app'></div>");
		var appHead = $("<div class='GooFlow_app_head'><h1 class='GooFlow_app_tit'></h1><div class='GooFlow_app_search'><input class='GooFlow_app_search_input' type='text' placeholder='快速搜索'><div class='GooFlow_search_btn'></div></div></div>");
		var appCont = $("<div class='GooFlow_app_cont'><ul class='GooFlow_app_list'></ul></div>");
		appHead.children('.GooFlow_app_tit').text(title);
		appCont.children('.GooFlow_app_list').append(htmlStr);
		appBox.prepend(appHead).append(appCont).addClass(className);
		return appBox;
	}
	/*
	 * Todo: 端点数据渲染及事件添加 【UI相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	function getAllEndpointsFn(data) {
		var list = $.parseJSON(data.message),
			htmlStr = '';
		for (var i = 0; i < list.length; i++) {
			htmlStr += "<li class='GooFlow_app_list_item'>";
			htmlStr += "<div class='GooFlow_app_list_tit'>" + list[i].title + "</div>";
			htmlStr += "<div class='GooFlow_app_list_box'><ul>";
			for (var j = 0; j < list[i].list.length; j++) {
				htmlStr += "<li class='GooFlow_app_item' data-type='" + list[i].list[j].nodeType +
					"' data-value ='" + list[i].list[j].value + "' data-config='"  + list[i].list[j].config +
					"'><div class='app_icon'></div> <div class='app_name'>" + list[i].list[j].name + "</div></li>"
			}
			htmlStr += "</ul></li>";
		}
		if (htmlStr) {
			that.$contBoxLeft = renderHtml('端点', 'GooFlow_left', htmlStr);
			that.$contBox.prepend(that.$contBoxLeft)
			// tab标签页
			$('.GooFlow_app_list_tit', that.$contBoxLeft).on("click", function () {
				$('.GooFlow_app_item', that.$contBoxLeft).show();
				$(this).parent().toggleClass('selected').siblings().removeClass('selected');
			});
			// 拖拽
			addNodeByDrag($('.GooFlow_app_item', that.$contBoxLeft), 'task');
			// 筛选
			itemSearchFn(that.$contBoxLeft);
		}
	}
	/*
	 * Todo: 转换器数据渲染及事件添加 【UI相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	function getAllProcessorsFn(data) {
		var list = $.parseJSON(data.message),
			htmlStr = '';
		htmlStr += "<li class='GooFlow_app_list_item'><div class='GooFlow_app_list_box'><ul>";
		for (var i = 0; i < list.length; i++) {
			htmlStr += "<li class='GooFlow_app_item' data-type='" + list[i].nodeType +
				"' data-value='" + list[i].value + "' data-config='" + list[i].config +
				"'><div class='app_icon'></div> <div class='app_name'>" + list[i].name + "</div></li>"
		}
		htmlStr += "</ul></li>";
		if (htmlStr) {
			that.$contBoxRight = renderHtml('转换器', 'GooFlow_right', htmlStr);
			that.$contBox.prepend(that.$contBoxRight)
			// 拖拽
			addNodeByDrag($('.GooFlow_app_item', that.$contBoxRight), 'plug');
			// 筛选
			itemSearchFn(that.$contBoxRight);
		}
	}
	/*
	 * Todo: 端点及转换数据加载 【ajax相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	GooFunc.getAjaxData(getAllEndpointsURL, getAllEndpointsFn);
	GooFunc.getAjaxData(getAllProcessorsURL, getAllProcessorsFn);
	/*
	 * Todo: 画布区域HTML结构搭建 【UI相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:09
	 * */
	this.initDraw("draw_" + this.$id);
	// 结点镜像 & 文本框
	this.$ghost = $("<div class='rs_ghost GooFlow_item'></div>").attr({
		"unselectable": "on",
		"onselectstart": 'return false',
		"onselect": 'document.selection.empty()'
	});
	this.$textArea = $("<textarea class='text_input'></textarea>");
	this.$bgDiv.append(this.$ghost).append(this.$textArea);
	// 操作折线时的移动框 & 线条增删改操作框
	this.$lineMove = $("<div class='GooFlow_line_move' style='display:none'></div>");
	this.$lineOper = $("<div class='GooFlow_line_oper' style='display:none'><b class='b_l1'></b><b class='b_l2'></b><b class='b_l3'></b><b class='b_x'></b></div>");
	this.$workArea.append(this.$lineMove).append(this.$lineOper);
	/*
	 * Todo: 结点拖拽 【增加结点触发方法】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:03
	 * */
	var onDrag = false;
	function addNodeByDrag(obj, type) {
		obj.mousedown(function () {
			that.$nowType = type;
			if (!type) {
				var thisType = $(this).attr("id").split("btn_")[1];
				that.$nowType = thisType;
			}
			onDrag = true;
			that.$newNodeTxt = $(this).children('.app_name').text();
			that.$newNodeValue = $(this).attr('data-value');
			that.$nodeType = $(this).attr('data-type');
			that.$nodeConfig = $(this).attr('data-config');
		});
		$(document).mouseup(function () {
			onDrag = false;
		});
		that.$workArea.mousemove(function () {
			if (onDrag) {
				var X, Y;
				var ev = GooFunc.mousePosition();
				X = ev.x - 433 + this.parentNode.scrollLeft;
				Y = ev.y - 262 + this.parentNode.scrollTop;
				that.$workArea.children('#node-ghost').attr({class: 'node-' + that.$nowType});
				that.$workArea.css({cursor: 'move'}).children('#node-ghost').css({
					display: "block",
					top: Y + "px",
					left: X + "px",
					cursor: "move",
				});
			}
		})
		that.$workArea.mouseup(function () {
			if (onDrag) {
				addNodeOnArea();
				onDrag = false;
				that.$workArea.css({cursor: 'pointer'}).children('#node-ghost').remove();
			}
		});
		that.$workArea.mouseenter(function () {
			that.$workArea.append("<div id='node-ghost'></div>");
		})
		that.$workArea.mouseleave(function () {
			that.$workArea.css({cursor: 'pointer'}).children('#node-ghost').remove();
		})
		function addNodeOnArea() {
			var X, Y;
			var ev = GooFunc.mousePosition();
			X = ev.x - 433 + that.$workArea[0].parentNode.scrollLeft;
			Y = ev.y - 262 + that.$workArea[0].parentNode.scrollTop;
			that.addNode(that.$id + "_node_" + that.$nodeCount, {
				name: "node_" + that.$nodeCount,
				type: that.$nowType,
				left: X,
				top: Y
			});
		}
	}
	addNodeByDrag(this.$flowChart.children());
	/*
	 * Todo: ### 画布区域功能设置 ******************************************* //
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:15
	 * */
	if (this.$editable) {
		// 事件添加
		this.initEvents();
		/*
		 * Todo: 取消&重做函数 【堆栈相关】
		 * Author: LE
		 * Date: 2017/2/15
		 * time: 15:12
		 * */
		if (property.useOperStack) {
			this.$undoStack = [];
			this.$redoStack = [];
			this.$isUndo = 0;
			///////////////以下是构造撤销操作/重做操作的方法
			//为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存
			this.pushOper = function (funcName, paras) {
				var len = this.$undoStack.length;
				if (this.$isUndo == 1) {
					this.$redoStack.push([funcName, paras]);
					this.$isUndo = false;
					if (this.$redoStack.length > 40) this.$redoStack.shift();
				} else {
					this.$undoStack.push([funcName, paras]);
					if (this.$undoStack.length > 40) this.$undoStack.shift();
					if (this.$isUndo == 0) {
						this.$redoStack.splice(0, this.$redoStack.length);
					}
					this.$isUndo = 0;
				}
			};
			this.pushExternalOper = function (func, jsonPara) {
				this.pushOper("externalFunc", [func, jsonPara]);
			};
			//撤销上一步操作
			this.undo = function () {
				if (this.$undoStack.length == 0)   return;
				var tmp = this.$undoStack.pop();
				this.$isUndo = 1;
				if (tmp[0] == "externalFunc") {
					tmp[1][0](tmp[1][1]);
				}
				else {
					//传参的数量,最多支持5个.
					switch (tmp[1].length) {
						case 0:
							this[tmp[0]]();
							break;
						case 1:
							this[tmp[0]](tmp[1][0]);
							break;
						case 2:
							this[tmp[0]](tmp[1][0], tmp[1][1]);
							break;
						case 3:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2]);
							break;
						case 4:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3]);
							break;
						case 5:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4]);
							break;
					}
				}
			};
			//重做最近一次被撤销的操作
			this.redo = function () {
				if (this.$redoStack.length == 0)   return;
				var tmp = this.$redoStack.pop();
				this.$isUndo = 2;
				if (tmp[0] == "externalFunc") {
					tmp[1][0](tmp[1][1]);
				}
				else {
					//传参的数量,最多支持5个.
					switch (tmp[1].length) {
						case 0:
							this[tmp[0]]();
							break;
						case 1:
							this[tmp[0]](tmp[1][0]);
							break;
						case 2:
							this[tmp[0]](tmp[1][0], tmp[1][1]);
							break;
						case 3:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2]);
							break;
						case 4:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3]);
							break;
						case 5:
							this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4]);
							break;
					}
				}
			};
		}
	}
}
/*
 * Todo:  ## 原型方法 ***************************************************************************************
 * Author: LE
 * Date: 2017/2/15
 * time: 14:59
 * */
GooFlow.prototype = {
    useSVG: true,
	/*
	 * Todo: 初始化画布 【SVG & 箭头 UI相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:51
	 * */
    initDraw: function (id) {
        this.$workAreaWrap = $("<div class='GooFlow_work'></div>");
        this.$workArea = $("<div class='GooFlow_work_inner'></div>").attr({
            "unselectable": "on",
            "onselectstart": 'return false',
            "onselect": 'document.selection.empty()'
        });
        this.$workAreaWrap.append(this.$workArea);
        this.$contBox.append(this.$workAreaWrap);
        this.$draw = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        this.$workArea.prepend(this.$draw);
        this.$workArea.prepend("<div class='file-box'>编码:<input id='fileCode' value='" + this.$fileCode +
			"'>流程名称:<input id='fileName' value='" + this.$fileName +
			"'></div>")
        // 设置画布属性
        this.$draw.id = id;
        this.$draw.style.width = '100%';
        this.$draw.style.height = '100%';
        // 定义可以重复利用的元素
        var defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
        this.$draw.appendChild(defs);
        defs.appendChild(getSvgMarker("arrow1", "#323232"));
        defs.appendChild(getSvgMarker("arrow2", "#00b7ee"));
        defs.appendChild(getSvgMarker("arrow3", "#f00"));
        function getSvgMarker(id, color) {
            var m = document.createElementNS("http://www.w3.org/2000/svg", "marker");
            m.setAttribute("id", id);
            m.setAttribute("viewBox", "0 0 6 6");
            m.setAttribute("refX", 5);
            m.setAttribute("refY", 3);
            m.setAttribute("markerUnits", "strokeWidth");
            m.setAttribute("markerWidth", 8);
            m.setAttribute("markerHeight", 8);
            m.setAttribute("orient", "auto");
            var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
            path.setAttribute("d", "M 0 0 L 6 3 L 0 6  L 2 3 z");
            path.setAttribute("fill", color);
            path.setAttribute("stroke-width", 2);
            m.appendChild(path);
            return m;
        }
    },
	/*
	 * Todo: ### 初始化事件绑定********************************--开始
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:09
	 * */
    initEvents: function () {
        // 防止回调函数里this偏移
        var that = this;
        var timeId = null;
		/*
		 * Todo: 空白区域点击事件 【单击事件】
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 10:05
		 * */
        $(this.$draw).on("click", function (e) {
            that.$canDelLine = false;
            var n = $(e.target).prop("tagName");
            if (n == "svg") {
                that.blurItem();
            }
        });
		/*
		 * Todo: 结点事件绑定 【@@】
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 10:22
		 * */
        this.$workArea.on({
            // 选中
            click: function () {
                clearTimeout(timeId);
                var Dom = $(this);
                var id = Dom.attr("id");
                that.focusItem(id, true);
            },
            // 编辑
            dblclick: function () {
                var id = $(this).attr('id'),
                    objPosition = $(this).position(),
                    objLeft = objPosition.left,
                    objTop = objPosition.top,
                    oldTxt = that.$nodeData[id].config;
	                console.log(that.$nodeData[id]);
                // 编辑的时候禁止delete键删除
                that.$canDelLine = false;
                that.$deteNodeId = '';
                that.$deteLineId = '';
                clearTimeout(timeId);
                that.$textArea.val(oldTxt).css({
                    display: "block",
                    left: objLeft + 170,
                    top: objTop + 50
                }).data("id", that.$focus).focus();
                that.$workArea.parent().one("mousedown", function () {
                    that.setName(that.$textArea.data("id"), that.$textArea.val(), "node");
                    that.$textArea.val("").removeData("id").hide();
                });
            },
            // 移动
            mousedown: function (e) {
                if (!e) e = window.event;
                var Dom = $(this);
                var id = Dom.attr("id");
                clearTimeout(timeId);
                timeId = setTimeout(function () {
	                that.focusItem(id, true);
	                var ev = GooFunc.mousePosition(e),
                        t = GooFunc.getElCoordinate(that.$workArea[0]),
                        c = GooFunc.getElCoordinate(that.$MainContener);
                    that.$ghost.css({
                        display: "block",
                        top: that.$nodeData[id].top + 133 - that.$workArea[0].parentNode.scrollTop + "px",
                        left: that.$nodeData[id].left + 200 - that.$workArea[0].parentNode.scrollLeft + "px",
                        cursor: "move"
                    });
                    var X, Y;
                    X = ev.x - t.left + that.$workArea[0].parentNode.scrollLeft;
                    Y = ev.y - t.top + that.$workArea[0].parentNode.scrollTop;
                    var vX = X - that.$nodeData[id].left, vY = Y - that.$nodeData[id].top;
                    var isMove = false;
                    document.onmousemove = function (e) {
                        if (!e) {
                            e = window.event;
                        }
                        var ev = GooFunc.mousePosition(e);
                        X = ev.x - vX - c.left;
                        Y = ev.y - vY - c.top;
                        if (X < t.left - c.left - that.$workArea[0].parentNode.scrollLeft) {
                            X = t.left - c.left - that.$workArea[0].parentNode.scrollLeft;
                        }
                        else if (X + that.$workArea[0].parentNode.scrollLeft + that.$nodeData[id].width > t.left - c.left + that.$workArea.width()) {
                            X = t.left - c.left + that.$workArea.width() - that.$workArea[0].parentNode.scrollLeft - that.$nodeData[id].width;
                        }
                        if (Y < t.top - c.top - that.$workArea[0].parentNode.scrollTop) {
                            Y = t.top - c.top - that.$workArea[0].parentNode.scrollTop;
                        }
                        else if (Y + that.$workArea[0].parentNode.scrollTop + that.$nodeData[id].height > t.top - c.top + that.$workArea.height()) {
                            Y = t.top - c.top + that.$workArea.height() - that.$workArea[0].parentNode.scrollTop - that.$nodeData[id].height;
                        }
                        that.$ghost.css({left: X - 230 + "px", top: Y - 133 + "px"});
                        isMove = true;
                    }
                    document.onmouseup = function () {
                        if (isMove) that.moveNode(id, X + that.$workArea[0].parentNode.scrollLeft - t.left + c.left, Y + that.$workArea[0].parentNode.scrollTop - t.top + c.top);
                        {
                            that.$ghost.empty().hide();
                        }
                        document.onmousemove = null;
                        document.onmouseup = null;
                    }
                }, 150);
            },
            // 显示连线图标
            mouseenter: function () {
                var moving = that.$lineMoveing;
                if (!moving) {
                    var w = $(this).width() + 60 + 'px';
                    var h = $(this).height() + 30 + 'px';
                    $(this).append("<div class='line-begin' style='width:" + w + ";height:" + h + "'><div class='line-begin-icon top'></div><div class='line-begin-icon left'></div><div class='line-begin-icon right'></div><div class='line-begin-icon bottom'></div></div>")
                }
                if (moving) {
                    $(this).addClass('item-mark');
                }
            },
            mouseleave: function () {
                $(this).children('.line-begin').remove();
                $(this).removeClass('item-mark');
            },
            // 结束连线
            mouseup: function () {
                clearTimeout(timeId);
                if (that.$lineMoveing) {
                    var type = $(this).children('.GooFlow_item_cont').children('.GooFlow_item_txt').attr("id").split("type-")[1]
                    var obj = $(this);
                    if (that.$nowType != "cursor") {
                        return;
                    }
                    var lineT, lineM;
                    var lineType = that.$lineType;
                    switch (lineType) {
                        case 'top':
                        case 'bottom':
                            lineT = 'tb';
                            break;
                        case 'left':
                        case 'right':
                            lineT = 'lr';
                            break;
                    }
                    var lineStart = that.$workArea.data("lineStart");
                    console.log("lineStart" + lineStart);
                    var n1 = that.$nodeData[lineStart.id], n2 = that.$nodeData[obj[0].id];
                    //To结点中心点位置判断
                    var sLeft = n1.left;
                    var sRight = sLeft + n1.width;
                    var sTop = n1.top;
                    var sBottom = sTop + n1.height;
                    var EXcenter = n2.left + n2.width / 2;
                    var EYcenter = n2.top + n2.height / 2;
                    // 当To结点中心点在From结点内时,用直线
                    if ((EXcenter >= sLeft && EXcenter <= sRight) || (EYcenter >= sTop && EYcenter <= sBottom)) {
                        lineT = 'sl';
                        lineM = '';
                    }
                    var lineM = GooFlow.prototype.getMValue(n1, n2, lineT);
                    if (lineStart) {
                        that.addLine(that.$id + "_line_" + that.$lineCount, {
                            from: lineStart.id,
                            to: obj[0].id,
                            name: "",
                            x: lineStart.x,
                            y: lineStart.y,
                            typeFrom: lineStart.typeFrom,
                            typeTo: type,
                            type: lineT,
                            M: lineM
                        });
                    }
                }
            }
        }, ".GooFlow_item").on({
            // 删除
            mousedown: function () {
                that.delNode(that.$focus);
                return false;
            }
        }, ".rs_close")
	    $('.file-box input').click(function () {
		    // 编辑的时候禁止delete键删除
		    that.blurItem();
	    })
		/*
		 * Todo: 连线链接 【 $$$】
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 10:23
		 * */
        this.$workArea.on({
            // 连线开始
            mousedown: function () {
                var cs = $(this).attr("class").split(/\s+/);
                that.$lineMoveing = true;
                that.$lineType = cs[1];
                var obj = $(this).parent().parent();
                that.$nowType = "cursor";
                var type = obj.children('.GooFlow_item_cont').children('.GooFlow_item_txt').attr("id").split("type-")[1]
                // 将划线开始点定为元素中心点
                var X, Y;
                var objPosition = obj.position();
                var objLeft = objPosition.left;
                var objTop = objPosition.top;
                var w = (obj.width()) / 2;
                var h = (obj.height()) / 2;
                X = objLeft + w;
                Y = objTop + h;
                that.$workArea.data("lineStart", {
                    "x": X,
                    "y": Y,
                    "id": obj[0].id,
                    "typeFrom": type
                }).css("cursor", "crosshair");
                var line = GooFlow.prototype.drawLine("GooFlow_tmp_line", [X, Y], [X, Y], true, true);
                that.$draw.appendChild(line);
                $(document).mouseup(function () {
                    $('.GooFlow_item').removeClass('item-mark');
                    that.$lineMoveing = false;
                })
                return false;
            }
        }, ".GooFlow_item .line-begin > *").on({
            // 连线中
            mousemove: function (e) {
                if (that.$nowType == "cursor") {
                    var lineStart = $(this).data("lineStart");
                    if (!lineStart)return;
                    var ev = GooFunc.mousePosition(e), t = GooFunc.getElCoordinate(this);
                    var X, Y;
                    X = ev.x - t.left + this.parentNode.scrollLeft;
                    Y = ev.y - t.top + this.parentNode.scrollTop;
                    var line = document.getElementById("GooFlow_tmp_line");
                    line.childNodes[0].setAttribute("d", "M " + lineStart.x + " " + lineStart.y + " L " + X + " " + Y);
                    line.childNodes[1].setAttribute("d", "M " + lineStart.x + " " + lineStart.y + " L " + X + " " + Y);
                    if (line.childNodes[1].getAttribute("marker-end") == "url(\"#arrow2\")") {
                        line.childNodes[1].setAttribute("marker-end", "url(#arrow3)");
                    }
                    else {
                        line.childNodes[1].setAttribute("marker-end", "url(#arrow2)");
                    }
                }
            },
            // 连线结束
            mouseup: function () {
                if (that.$nowType != "cursor") {
                    return;
                }
                $(this).css("cursor", "auto").removeData("lineStart");
                var HtmlStr = document.getElementById("GooFlow_tmp_line");
                if (HtmlStr) {
                    that.$draw.removeChild(HtmlStr);
                }
            }
        })
		/*
		 * Todo: 线条文字编辑 【 $$$】
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 10:23
		 * */
        $(this.$draw).on({
            click: function () {
                that.focusItem(this.id, true);
            },
            dblclick: function () {
                var oldTxt, x, y, from, to;
                // 编辑的时候禁止delete键删除
                that.$canDelLine = false;
                that.$deteNodeId = '';
                that.$deteLineId = '';
                if (GooFlow.prototype.useSVG != "") {
                    oldTxt = this.childNodes[2].textContent;
                    from = this.getAttribute("from").split(",");
                    to = this.getAttribute("to").split(",");
                }
                if (that.$lineData[this.id].type == "lr") {
                    from[0] = that.$lineData[this.id].M;
                    to[0] = from[0];
                }
                else if (that.$lineData[this.id].type == "tb") {
                    from[1] = that.$lineData[this.id].M;
                    to[1] = from[1];
                }
                x = (parseInt(from[0], 10) + parseInt(to[0], 10)) / 2 + 230;
                y = (parseInt(from[1], 10) + parseInt(to[1], 10)) / 2 + 60;
                that.$textArea.val(oldTxt).css({
                    display: "block",
                    left: x,
                    top: y
                }).data("id", that.$focus).focus();
                that.$workArea.parent().one("mousedown", function () {
                    that.setName(that.$textArea.data("id"), that.$textArea.val(), "line");
                    that.$textArea.val("").removeData("id").hide();
                });
            }
        }, 'g');
		/*
		 * Todo: 线条移动 【 $$$】
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 10:33
		 * */
        this.$lineMove.on("mousedown", function (e) {
            var lm = $(this);
            lm.css({"background-color": "#333"});
            var ev = GooFunc.mousePosition(e), t = GooFunc.getElCoordinate(that.$workArea[0]);
            var X, Y;
            X = ev.x - t.left + that.$workArea[0].parentNode.scrollLeft;
            Y = ev.y - t.top + that.$workArea[0].parentNode.scrollTop;
            var p = that.$lineMove.position();
            var vX = X - p.left, vY = Y - p.top;
            var isMove = false;
            document.onmousemove = function (e) {
                if (!e) e = window.event;
                var ev = GooFunc.mousePosition(e);
                var ps = that.$lineMove.position();
                X = ev.x - t.left + that.$workArea[0].parentNode.scrollLeft;
                Y = ev.y - t.top + that.$workArea[0].parentNode.scrollTop;
                if (that.$lineMove.data("type") == "lr") {
                    X = X - vX;
                    if (X < 0) X = 0;
                    else if (X > that.$workArea.width())
                        X = that.$workArea.width();
                    that.$lineMove.css({left: X + "px"});
                }
                else if (that.$lineMove.data("type") == "tb") {
                    Y = Y - vY;
                    if (Y < 0) Y = 0;
                    else if (Y > that.$workArea.height())
                        Y = that.$workArea.height();
                    that.$lineMove.css({top: Y + "px"});
                }
                isMove = true;
            }
            document.onmouseup = function (e) {
                if (isMove) {
                    var p = that.$lineMove.position();
                    if (that.$lineMove.data("type") == "lr")
                        that.setLineM(that.$lineMove.data("tid"), p.left + 3);
                    else if (that.$lineMove.data("type") == "tb")
                        that.setLineM(that.$lineMove.data("tid"), p.top + 3);
                }
                that.$lineMove.css({"background-color": "transparent"});
                if (that.$focus == that.$lineMove.data("tid")) {
                    that.focusItem(that.$lineMove.data("tid"));
                }
                document.onmousemove = null;
                document.onmouseup = null;
            }
        });
        this.$lineOper.on("click", function (e) {
            if (e.target.tagName != "B")   return;
            var id = $(this).data("tid");
            switch ($(e.target).attr("class")) {
                case "b_x":
                    that.delLine(id);
                    this.style.display = "none";
                    break;
                case "b_l1":
                    that.setLineType(id, "lr");
                    break;
                case "b_l2":
                    that.setLineType(id, "tb");
                    break;
                case "b_l3":
                    that.setLineType(id, "sl");
                    break;
            }
        });
    },
	/*
	 * Todo: ### 初始化事件绑定******************************--结束
	 * */
	/*
	 * Todo: 取消选定状态 【取消聚焦公共方法】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:53
	 * */
    blurItem: function () {
	    this.$canDelLine = false;
	    this.$deteNodeId = '';
	    this.$deteLineId = '';
        if (this.$focus != "") {
            // 获取被选中对象
            var jq = $("#" + this.$focus);
            if (jq.prop("tagName") == "DIV") {
                if (this.onItemBlur != null && !this.onItemBlur(id, "node"))  return false;
                jq.removeClass("item_focus").children(".rs-box").css("display", "none");
            }
            else {
                if (this.onItemBlur != null && !this.onItemBlur(id, "line"))  return false;
                if (GooFlow.prototype.useSVG != "") {
                    if (!this.$lineData[this.$focus].marked) {
                        jq[0].childNodes[1].setAttribute("stroke", "#323232");
                        jq[0].childNodes[1].setAttribute("marker-end", "url(#arrow1)");
                    }
                }
                else {
                    if (!this.$lineData[this.$focus].marked) jq[0].strokeColor = "#323232";
                }
                this.$lineMove.hide().removeData("type").removeData("tid");
                if (this.$editable) this.$lineOper.hide().removeData("tid");
            }
        }
        this.$focus = "";
        return true;
    },
	/*
	 * Todo: 选定状态 【聚焦公共方法】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:53
	 * */
    focusItem: function (id, bool) {
        var jq = $("#" + id);
        var that = this;
        this.$ghost.attr({'class': 'rs_ghost ' + jq.attr('class')});
        if (jq.length == 0)    return;
        if (!this.blurItem())    return;//先执行"取消选中",如果返回FLASE,则也会阻止选定事件继续进行.
        if (jq.prop("tagName") == "DIV") {
            if (bool && this.onItemFocus != null && !this.onItemFocus(id, "node"))  return;
            jq.addClass("item_focus");
            if (this.$editable) jq.children(".rs-box").css("display", "block");
            this.$workArea.append(jq);
            that.$canDelLine = false;
            that.$deteLineId = '';
            that.$deteNodeId = id;
            $(document).keydown(function (e) {
                if (e.keyCode != 8 && that.$deteNodeId) {
                    return
                }
                that.delNode(that.$deteNodeId);
            });
        }
        else {//如果是连接线
            if (this.onItemFocus != null && !this.onItemFocus(id, "line"))    return;
            that.$canDelLine = true;
            that.$deteNodeId = '';
            that.$deteLineId = id;
            $(document).keydown(function (e) {
                if (e.keyCode == 8 && that.$deteLineId) {
                    that.delLine(that.$deteLineId);
                    $('.GooFlow_line_oper').hide();
                }
            })
            if (GooFlow.prototype.useSVG != "") {
                jq[0].childNodes[1].setAttribute("stroke", "#00b7ee");
                jq[0].childNodes[1].setAttribute("marker-end", "url(#arrow2)");
            }
            else    jq[0].strokeColor = "#00b7ee";
            if (!this.$editable) return;
            var x, y, from, to;
            if (GooFlow.prototype.useSVG != "") {
                from = jq.attr("from").split(",");
                to = jq.attr("to").split(",");
            } else {
                var n = jq[0].getAttribute("fromTo").split(",");
                from = [n[0], n[1]];
                to = [n[2], n[3]];
            }
            from[0] = parseInt(from[0], 10);
            from[1] = parseInt(from[1], 10);
            to[0] = parseInt(to[0], 10);
            to[1] = parseInt(to[1], 10);
            if (this.$lineData[id].type == "lr") {
                from[0] = this.$lineData[id].M;
                to[0] = from[0];
                this.$lineMove.css({
                    width: "5px", height: (to[1] - from[1]) * (to[1] > from[1] ? 1 : -1) + "px",
                    left: from[0] - 3 + "px",
                    top: (to[1] > from[1] ? from[1] : to[1]) + 1 + "px",
                    cursor: "e-resize", display: "block"
                }).data({"type": "lr", "tid": id});
            }
            else if (this.$lineData[id].type == "tb") {
                from[1] = this.$lineData[id].M;
                to[1] = from[1];
                this.$lineMove.css({
                    width: (to[0] - from[0]) * (to[0] > from[0] ? 1 : -1) + "px", height: "5px",
                    left: (to[0] > from[0] ? from[0] : to[0]) + 1 + "px",
                    top: from[1] - 3 + "px",
                    cursor: "s-resize", display: "block"
                }).data({"type": "tb", "tid": id});
            }
            x = (from[0] + to[0]) / 2 - 35;
            y = (from[1] + to[1]) / 2 + 6;
            this.$lineOper.css({display: "block", left: x + "px", top: y + "px"}).data("tid", id);
        }
        this.$focus = id;
        this.$nowType = "cursor";
    },
	/*
	 * Todo: 增加结点 【结点公共方法 @@】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:53
	 * */
    addNode: function (id, json) {
        if (this.onItemAdd != null && !this.onItemAdd(id, "node", json))return;
        if (this.$undoStack) {
            this.pushOper("delNode", [id]);
        }
        if (json.type != "start" && json.type != "end") {
            if (json.top < 0) json.top = 0;
            if (json.left < 0) json.left = 0;
            switch (json.type) {
                case "state":
                    json.name = '判断';
                    json.config = '';
                    json.nodeType = 'judgement'
                    break;
                case "complex":
                    json.name = '循环';
                    json.config = 'splitJsonArray';
                    json.nodeType = 'circle'
                    break;
                case "join":
                    json.name = '聚合';
                    json.config = '';
                    json.nodeType = 'aggregate'
                    break;
                case "fork":
                    json.name = '分流';
                    json.config = '';
                    json.nodeType = 'multicast'
                    break;
                case "task":
                    json.name = this.$newNodeTxt || json.name;
                    json.value = this.$newNodeValue || json.value;
                    json.config = this.$nodeConfig || json.config;
                    json.nodeType = this.$nodeType || json.nodeType;
                    break;
                case "plug":
                    json.name = this.$newNodeTxt || json.name;
                    json.value = this.$newNodeValue || json.value;
                    json.config = this.$nodeConfig || json.config;
                    json.nodeType = this.$nodeType || json.nodeType;
                    break;
            }
            this.$nodeDom[id] = $("<div class='GooFlow_item node-" + json.type + "' id='" + id + "' style='top:" + json.top + "px;left:" + json.left + "px'><div class='GooFlow_item_cont'> <i class='fa ico_" + json.type + "'></i><span class='GooFlow_item_txt' id='type-" + json.type + "'>" + json.name + "</span></div> <div class='rs-box' style='display:none'><div class='rs_close'><i class='fa fa-close' aria-hidden='true'></i></div></div></div>");
        }
        this.$workArea.append(this.$nodeDom[id]);
        json.width = this.$nodeDom[id].width();
        json.height = this.$nodeDom[id].height();
        this.$nodeData[id] = json;
        ++this.$nodeCount;
    },
	/*
	 * Todo: 删除结点 【结点公共方法 @@】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:55
	 * */
    delNode: function (id) {
        if (!this.$nodeData[id]) return;
        if (this.$undoStack) {
            var paras = [id, this.$nodeData[id]];
            this.pushOper("addNode", paras);
        }
        if (this.onItemDel != null && !this.onItemDel(id, "node"))    return;
        delete this.$nodeData[id];
        this.$nodeDom[id].remove();
        delete this.$nodeDom[id];
        if (this.$focus == id) this.$focus = "";
        for (var k in this.$lineData) {
            if (this.$lineData[k].from == id || this.$lineData[k].to == id) {
                this.$draw.removeChild(this.$lineDom[k]);
                delete this.$lineData[k];
                delete this.$lineDom[k];
            }
        }
    },
	/*
	 * Todo: 结点移动 【结点移动方法 @@】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:54
	 * */
    moveNode: function (id, left, top) {
        if (!this.$nodeData[id]) return;
        if (this.onItemMove != null && !this.onItemMove(id, "node", left, top)) return;
        if (this.$undoStack) {
            var paras = [id, this.$nodeData[id].left, this.$nodeData[id].top];
            this.pushOper("moveNode", paras);
        }
        if (left < 0) left = 0;
        if (top < 0) top = 0;
        $("#" + id).css({left: left + "px", top: top + "px"});
        this.$nodeData[id].left = left;
        this.$nodeData[id].top = top;
        //重画转换线
        this.resetLines(id, this.$nodeData[id]);
    },
	/*
	 * Todo: 设置结点线等内容 【内容设置公共方法 @@ $$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:54
	 * */
    setName: function (id, config, type) {
        var oldName;
        if (type == "node") {//如果是结点
            if (!this.$nodeData[id]) return;
            this.$nodeData[id].config = config;
        }
        else if (type == "line") {//如果是线
            if (!this.$lineData[id]) return;
            if (this.$lineData[id].config == config)   return;
            oldName = this.$lineData[id].value;
            this.$lineData[id].config = config;
            this.$lineDom[id].childNodes[2].textContent = config;
        }
    },
	/*
	 * Todo: 增加线条 【$$】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 16:46
	 * */
    addLine: function (id, json, isDataLoad) {
        if (!isDataLoad) {
            if (this.$undoStack) {
                this.pushOper("delLine", [id]);
            }
            if (json.from == json.to) {
                return;
            }
            var typeF = json.typeFrom || json.type;
            var typeT = json.typeTo || json.type;
            for (var k in this.$lineData) {
                // 单出
                var onlyOut = (json.from == this.$lineData[k].from);
                // 单进
                var onlyIn = (json.to == this.$lineData[k].to);
                // 来源等于去向
                var formEto = (json.from == this.$lineData[k].to);
                // 去向等于来源
                var tofrom = (json.to == this.$lineData[k].from);
                // 不能反向
                if (tofrom && formEto) {
                    return;
                }
                // 设置除了聚合其余都默认单进
                if (typeT != 'join') {
                    if (onlyIn) {
                        return;
                    }
                }
                switch (typeF) {
                    case 'task':
                    case 'plug':
                        if (onlyOut) {
                            return;
                        }
                        break;
                    case 'state':
                    case 'complex':
                        if (json.from == this.$lineData[k].from) {
                            var i = 0;
                            for (var j in this.$lineData) {
                                if (json.from == this.$lineData[j].from) {
                                    i++
                                }
                            }
                            if (i >= 2) {
                                return;
                            }
                        }
                        break;
                }
            }
        }
        //获取开始/结束结点的数据
        var n1 = this.$nodeData[json.from], n2 = this.$nodeData[json.to];
        if (!n1 || !n2) {
            return;
        }
        // 划线函数以及线条类型处理
        var res;
        if (json.type && json.type != "sl") {
            res = GooFlow.prototype.calcPolyPoints(n1, n2, json.type, json.M);
        }
        else {
            res = GooFlow.prototype.calcStartEnd(n1, n2);// 刚开始连线时,默认为直线
        }
        if (!res) {
            return;
        }
        // 存储线条
        this.$lineData[id] = {};
        if (json.type) {
            this.$lineData[id].type = json.type;
            this.$lineData[id].M = json.M;
        }
        else {
            this.$lineData[id].type = "sl";//默认为直线
        }
        this.$lineData[id].from = json.from;
        this.$lineData[id].to = json.to;
        this.$lineData[id].config = json.name;
        if (json.mark) {
            this.$lineData[id].marked = json.mark;
        }
        else {
            this.$lineData[id].marked = false;
        }
        if (this.$lineData[id].type == "sl") {
            this.$lineDom[id] = GooFlow.prototype.drawLine(id, res.start, res.end, json.mark);
        }
        else {
            this.$lineDom[id] = GooFlow.prototype.drawPoly(id, res.start, res.m1, res.m2, res.end, json.mark);
        }
        this.$draw.appendChild(this.$lineDom[id]);
        if (GooFlow.prototype.useSVG == "") {
            this.$lineDom[id].childNodes[1].innerHTML = json.name;
            if (this.$lineData[id].type != "sl") {
                var Min = (res.start[0] > res.end[0] ? res.end[0] : res.start[0]);
                if (Min > res.m2[0]) Min = res.m2[0];
                if (Min > res.m1[0]) Min = res.m1[0];
                this.$lineDom[i].childNodes[1].style.left = (res.m2[0] + res.m1[0]) / 2 - Min - this.$lineDom[id].childNodes[1].offsetWidth / 2 + 4;
                Min = (res.start[1] > res.end[1] ? res.end[1] : res.start[1]);
                if (Min > res.m2[1]) Min = res.m2[1];
                if (Min > res.m1[1]) Min = res.m1[1];
                this.$lineDom[id].childNodes[1].style.top = (res.m2[1] + res.m1[1]) / 2 - Min - this.$lineDom[id].childNodes[1].offsetHeight / 2;
            } else
                this.$lineDom[id].childNodes[1].style.left =
                    ((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) - this.$lineDom[id].childNodes[1].offsetWidth) / 2 + 4;
        }
        else {
            this.$lineDom[id].childNodes[2].textContent = json.name;
        }
        ++this.$lineCount;
    },
	/*
	 * Todo: 线条删除  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:57
	 * */
    delLine: function (id) {
        if (!this.$lineData[id]) return;
        if (this.$undoStack) {
            var paras = [id, this.$lineData[id]];
            this.pushOper("addLine", paras);
        }
        this.$draw.removeChild(this.$lineDom[id]);
        delete this.$lineData[id];
        delete this.$lineDom[id];
        if (this.$focus == id) this.$focus = "";
    },
	/*
	 * Todo: 直线生成 【$$】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 14:57
	 * */
    drawLine: function (id, sp, ep, mark, dash) {
        var line;
        if (GooFlow.prototype.useSVG != "") {
            line = document.createElementNS("http://www.w3.org/2000/svg", "g");
            var hi = document.createElementNS("http://www.w3.org/2000/svg", "path");
            var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
            if (id != "") line.setAttribute("id", id);
            line.setAttribute("from", sp[0] + "," + sp[1]);
            line.setAttribute("to", ep[0] + "," + ep[1]);
            hi.setAttribute("visibility", "hidden");
            hi.setAttribute("stroke-width", 15);
            hi.setAttribute("fill", "none");
            hi.setAttribute("stroke", "white");
            hi.setAttribute("d", "M " + sp[0] + " " + sp[1] + " L " + ep[0] + " " + ep[1]);
            hi.setAttribute("pointer-events", "stroke");
            path.setAttribute("d", "M " + sp[0] + " " + sp[1] + " L " + ep[0] + " " + ep[1]);
            path.setAttribute("stroke-width", 1.2);
            path.setAttribute("stroke-linecap", "round");
            path.setAttribute("fill", "none");
            if (dash) path.setAttribute("style", "stroke-dasharray:6,5");
            if (mark) {
                path.setAttribute("stroke", "#00b7ee");
                path.setAttribute("marker-end", "url(#arrow2)");
            }
            else {
                path.setAttribute("stroke", "#323232");
                path.setAttribute("marker-end", "url(#arrow1)");
            }
            line.appendChild(hi);
            line.appendChild(path);
            line.style.cursor = "crosshair";
            if (id != "" && id != "GooFlow_tmp_line") {
                var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
                //text.textContent=id;
                line.appendChild(text);
                var x = (ep[0] + sp[0]) / 2;
                var y = (ep[1] + sp[1]) / 2;
                text.setAttribute("text-anchor", "middle");
                text.setAttribute("x", x);
                text.setAttribute("y", y);
                line.style.cursor = "pointer";
                text.style.cursor = "text";
            }
        } else {
            line = document.createElement("v:polyline");
            if (id != "") line.id = id;
            //line.style.position="absolute";
            line.points.value = sp[0] + "," + sp[1] + " " + ep[0] + "," + ep[1];
            line.setAttribute("fromTo", sp[0] + "," + sp[1] + "," + ep[0] + "," + ep[1]);
            line.strokeWeight = "1.2";
            line.stroke.EndArrow = "Block";
            line.style.cursor = "crosshair";
            if (id != "" && id != "GooFlow_tmp_line") {
                var text = document.createElement("div");
                //text.innerHTML=id;
                line.appendChild(text);
                var x = (ep[0] - sp[0]) / 2;
                var y = (ep[1] - sp[1]) / 2;
                if (x < 0) x = x * -1;
                if (y < 0) y = y * -1;
                text.style.left = x + "px";
                text.style.top = y - 6 + "px";
                line.style.cursor = "pointer";
            }
            if (dash) line.stroke.dashstyle = "Dash";
            if (mark) line.strokeColor = "#00b7ee";
            else    line.strokeColor = "#323232";
        }
        return line;
    },
	/*
	 * Todo: 折线生成 【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:26
	 * */
    drawPoly: function (id, sp, m1, m2, ep, mark) {
        var poly, strPath;
        if (GooFlow.prototype.useSVG != "") {
            poly = document.createElementNS("http://www.w3.org/2000/svg", "g");
            var hi = document.createElementNS("http://www.w3.org/2000/svg", "path");
            var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
            if (id != "") poly.setAttribute("id", id);
            poly.setAttribute("from", sp[0] + "," + sp[1]);
            poly.setAttribute("to", ep[0] + "," + ep[1]);
            hi.setAttribute("visibility", "hidden");
            hi.setAttribute("stroke-width", 15);
            hi.setAttribute("fill", "none");
            hi.setAttribute("stroke", "white");
            strPath = "M " + sp[0] + " " + sp[1];
            if (m1[0] != sp[0] || m1[1] != sp[1])
                strPath += " L " + m1[0] + " " + m1[1];
            if (m2[0] != ep[0] || m2[1] != ep[1])
                strPath += " L " + m2[0] + " " + m2[1];
            strPath += " L " + ep[0] + " " + ep[1];
            hi.setAttribute("d", strPath);
            hi.setAttribute("pointer-events", "stroke");
            path.setAttribute("d", strPath);
            path.setAttribute("stroke-width", 1.2);
            path.setAttribute("stroke-linecap", "round");
            path.setAttribute("fill", "none");
            if (mark) {
                path.setAttribute("stroke", "#00b7ee");
                path.setAttribute("marker-end", "url(#arrow2)");
            }
            else {
                path.setAttribute("stroke", "#323232");
                path.setAttribute("marker-end", "url(#arrow1)");
            }
            poly.appendChild(hi);
            poly.appendChild(path);
            var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
            //text.textContent=id;
            poly.appendChild(text);
            var x = (m2[0] + m1[0]) / 2;
            var y = (m2[1] + m1[1]) / 2;
            text.setAttribute("text-anchor", "middle");
            text.setAttribute("x", x);
            text.setAttribute("y", y);
            text.style.cursor = "text";
            poly.style.cursor = "pointer";
        }
        else {
            poly = document.createElement("v:Polyline");
            if (id != "") poly.id = id;
            poly.filled = "false";
            strPath = sp[0] + "," + sp[1];
            if (m1[0] != sp[0] || m1[1] != sp[1])
                strPath += " " + m1[0] + "," + m1[1];
            if (m2[0] != ep[0] || m2[1] != ep[1])
                strPath += " " + m2[0] + "," + m2[1];
            strPath += " " + ep[0] + "," + ep[1];
            poly.points.value = strPath;
            poly.setAttribute("fromTo", sp[0] + "," + sp[1] + "," + ep[0] + "," + ep[1]);
            poly.strokeWeight = "1.2";
            poly.stroke.EndArrow = "Block";
            var text = document.createElement("div");
            //text.innerHTML=id;
            poly.appendChild(text);
            var x = (m2[0] - m1[0]) / 2;
            var y = (m2[1] - m1[1]) / 2;
            if (x < 0) x = x * -1;
            if (y < 0) y = y * -1;
            text.style.left = x + "px";
            text.style.top = y - 4 + "px";
            poly.style.cursor = "pointer";
            if (mark) poly.strokeColor = "#00b7ee";
            else    poly.strokeColor = "#323232"
        }
        return poly;
    },
	/*
	 * Todo: 直线坐标计算  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:26
	 * */
    calcStartEnd: function (n1, n2) {
        if (!n1 || !n2) {
            return {"start": [], "end": []};
        }
        var X_1, Y_1, X_2, Y_2;
        //X判断:
        var x11 = n1.left, x12 = n1.left + n1.width / 2, x13 = n1.left + n1.width, x21 = n2.left, x22 = n2.left + n2.width / 2, x23 = n2.left + n2.width;
        //Y判断:
        var y11 = n1.top, y12 = n1.top + n1.height / 2, y13 = n1.top + n1.height, y21 = n2.top, y22 = n2.top + n2.height / 2, y23 = n2.top + n2.height;
        X_1 = x12;
        X_2 = x22;
        // 结点2在结点1左边
        if (x11 >= x23) {
            X_1 = x11;
            Y_1 = y12;
            X_2 = x23;
            Y_2 = y22;
        }
        //结点2在结点1右边
        else if (x21 >= x13) {
            X_1 = x13;
            Y_1 = y12;
            X_2 = x21;
            Y_2 = y22;
        }
        else {
            // 结点2在结点1上边
            if (y11 >= y22) {
                Y_1 = y11;
                Y_2 = y23;
            }
            //结点2在结点1下边
            else if (y12 <= y21) {
                Y_1 = y13;
                Y_2 = y21;
            }
        }
        return {"start": [X_1, Y_1], "end": [X_2, Y_2]};
    },
	/*
	 * Todo: 折线坐标计算  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:27
	 * */
    calcPolyPoints: function (n1, n2, type, M) {
        //开始/结束两个结点的中心
        var SP = {x: n1.left + n1.width / 2, y: n1.top + n1.height / 2};
        var EP = {x: n2.left + n2.width / 2, y: n2.top + n2.height / 2};
        var sp = [], m1 = [], m2 = [], ep = [];
        //如果是允许中段可左右移动的折线,则参数M为可移动中段线的X坐标
        //粗略计算起始点
        sp = [SP.x, SP.y];
        ep = [EP.x, EP.y];
        if (type == "lr") {
            //粗略计算2个中点
            m1 = [M, SP.y];
            m2 = [M, EP.y];
            //再具体分析修改开始点和中点1
            if (m1[0] > n1.left && m1[0] < n1.left + n1.width) {
                m1[1] = (SP.y > EP.y ? n1.top : n1.top + n1.height);
                sp[0] = m1[0];
                sp[1] = m1[1];
            }
            else {
                sp[0] = (m1[0] < n1.left ? n1.left : n1.left + n1.width)
            }
            //再具体分析中点2和结束点
            if (m2[0] > n2.left && m2[0] < n2.left + n2.width) {
                m2[1] = (SP.y > EP.y ? n2.top + n2.height : n2.top);
                ep[0] = m2[0];
                ep[1] = m2[1];
            }
            else {
                ep[0] = (m2[0] < n2.left ? n2.left : n2.left + n2.width)
            }
        }
        //如果是允许中段可上下移动的折线,则参数M为可移动中段线的Y坐标
        else if (type == "tb") {
            //粗略计算2个中点
            m1 = [SP.x, M];
            m2 = [EP.x, M];
            //再具体分析修改开始点和中点1
            if (m1[1] > n1.top && m1[1] < n1.top + n1.height) {
                m1[0] = (SP.x > EP.x ? n1.left : n1.left + n1.width);
                sp[0] = m1[0];
                sp[1] = m1[1];
            }
            else {
                sp[1] = (m1[1] < n1.top ? n1.top : n1.top + n1.height)
            }
            //再具体分析中点2和结束点
            if (m2[1] > n2.top && m2[1] < n2.top + n2.height) {
                m2[0] = (SP.x > EP.x ? n2.left + n2.width : n2.left);
                ep[0] = m2[0];
                ep[1] = m2[1];
            }
            else {
                ep[1] = (m2[1] < n2.top ? n2.top : n2.top + n2.height);
            }
        }
        return {start: sp, m1: m1, m2: m2, end: ep};
    },
	/*
	 * Todo: 折线固定中线计算  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 10:27
	 * */
    getMValue: function (n1, n2, mType) {
        if (mType == "lr") {
            return (n1.left + n1.width / 2 + n2.left + n2.width / 2) / 2;
        }
        else if (mType == "tb") {
            return (n1.top + n1.height / 2 + n2.top + n2.height / 2) / 2;
        }
    },
	/*
	 * Todo: 重置线条  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:56
	 * */
    resetLines: function (id, node) {
        for (var i in this.$lineData) {
            var other = null;//获取结束/开始结点的数据
            var res;
            if (this.$lineData[i].from == id) {//找结束点
                other = this.$nodeData[this.$lineData[i].to] || null;
                if (other == null) continue;
                if (this.$lineData[i].type == "sl")
                    res = GooFlow.prototype.calcStartEnd(node, other);
                else
                    res = GooFlow.prototype.calcPolyPoints(node, other, this.$lineData[i].type, this.$lineData[i].M)
                if (!res)    break;
            }
            else if (this.$lineData[i].to == id) {//找开始点
                other = this.$nodeData[this.$lineData[i].from] || null;
                if (other == null) continue;
                if (this.$lineData[i].type == "sl")
                    res = GooFlow.prototype.calcStartEnd(other, node);
                else
                    res = GooFlow.prototype.calcPolyPoints(other, node, this.$lineData[i].type, this.$lineData[i].M);
                if (!res)    break;
            }
            if (other == null)   continue;
            this.$draw.removeChild(this.$lineDom[i]);
            if (this.$lineData[i].type == "sl") {
                this.$lineDom[i] = GooFlow.prototype.drawLine(i, res.start, res.end, this.$lineData[i].marked);
            }
            else {
                this.$lineDom[i] = GooFlow.prototype.drawPoly(i, res.start, res.m1, res.m2, res.end, this.$lineData[i].marked);
            }
            this.$draw.appendChild(this.$lineDom[i]);
            if (GooFlow.prototype.useSVG == "") {
                this.$lineDom[i].childNodes[1].innerHTML = this.$lineData[i].name;
                if (this.$lineData[i].type != "sl") {
                    var Min = (res.start[0] > res.end[0] ? res.end[0] : res.start[0]);
                    if (Min > res.m2[0]) Min = res.m2[0];
                    if (Min > res.m1[0]) Min = res.m1[0];
                    this.$lineDom[i].childNodes[1].style.left = (res.m2[0] + res.m1[0]) / 2 - Min - this.$lineDom[i].childNodes[1].offsetWidth / 2 + 4;
                    Min = (res.start[1] > res.end[1] ? res.end[1] : res.start[1]);
                    if (Min > res.m2[1]) Min = res.m2[1];
                    if (Min > res.m1[1]) Min = res.m1[1];
                    this.$lineDom[i].childNodes[1].style.top = (res.m2[1] + res.m1[1]) / 2 - Min - this.$lineDom[i].childNodes[1].offsetHeight / 2 - 4;
                } else
                    this.$lineDom[i].childNodes[1].style.left =
                        ((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) - this.$lineDom[i].childNodes[1].offsetWidth) / 2 + 4;
            }
            else  this.$lineDom[i].childNodes[2].textContent = this.$lineData[i].name;
        }
    },
	/*
	 * Todo: 重置线条类型  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:56
	 * */
    setLineType: function (id, newType) {
        if (!newType || newType == null || newType == "" || newType == this.$lineData[id].type)  return false;
        if (this.$undoStack) {
            var paras = [id, this.$lineData[id].type];
            this.pushOper("setLineType", paras);
            if (this.$lineData[id].type != "sl") {
                var para2 = [id, this.$lineData[id].M];
                this.pushOper("setLineM", para2);
            }
        }
        var from = this.$lineData[id].from;
        var to = this.$lineData[id].to;
        this.$lineData[id].type = newType;
        var res;
        //如果是变成折线
        if (newType != "sl") {
            var res = GooFlow.prototype.calcPolyPoints(this.$nodeData[from], this.$nodeData[to], this.$lineData[id].type, this.$lineData[id].M);
            this.setLineM(id, this.getMValue(this.$nodeData[from], this.$nodeData[to], newType), true);
        }
        //如果是变回直线
        else {
            delete this.$lineData[id].M;
            this.$lineMove.hide().removeData("type").removeData("tid");
            res = GooFlow.prototype.calcStartEnd(this.$nodeData[from], this.$nodeData[to]);
            if (!res)  return;
            this.$draw.removeChild(this.$lineDom[id]);
            this.$lineDom[id] = GooFlow.prototype.drawLine(id, res.start, res.end, this.$lineData[id].marked || this.$focus == id);
            this.$draw.appendChild(this.$lineDom[id]);
            if (GooFlow.prototype.useSVG == "") {
                this.$lineDom[id].childNodes[1].innerHTML = this.$lineData[id].name;
                this.$lineDom[id].childNodes[1].style.left =
                    ((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) - this.$lineDom[id].childNodes[1].offsetWidth) / 2 + 4;
            }
            else
                this.$lineDom[id].childNodes[2].textContent = this.$lineData[id].name;
        }
        if (this.$focus == id) {
            this.focusItem(id);
        }
    },
	/*
	 * Todo: 重置折线中点  【$$】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:57
	 * */
    setLineM: function (id, M, noStack) {
        if (!this.$lineData[id] || M < 0 || !this.$lineData[id].type || this.$lineData[id].type == "sl")   return false;
        if (this.$undoStack && !noStack) {
            var paras = [id, this.$lineData[id].M];
            this.pushOper("setLineM", paras);
        }
        var from = this.$lineData[id].from;
        var to = this.$lineData[id].to;
        this.$lineData[id].M = M;
        var ps = GooFlow.prototype.calcPolyPoints(this.$nodeData[from], this.$nodeData[to], this.$lineData[id].type, this.$lineData[id].M);
        this.$draw.removeChild(this.$lineDom[id]);
        this.$lineDom[id] = GooFlow.prototype.drawPoly(id, ps.start, ps.m1, ps.m2, ps.end, this.$lineData[id].marked || this.$focus == id);
        this.$draw.appendChild(this.$lineDom[id]);
        if (GooFlow.prototype.useSVG == "") {
            this.$lineDom[id].childNodes[1].innerHTML = this.$lineData[id].name;
            var Min = (ps.start[0] > ps.end[0] ? ps.end[0] : ps.start[0]);
            if (Min > ps.m2[0]) Min = ps.m2[0];
            if (Min > ps.m1[0]) Min = ps.m1[0];
            this.$lineDom[id].childNodes[1].style.left = (ps.m2[0] + ps.m1[0]) / 2 - Min - this.$lineDom[id].childNodes[1].offsetWidth / 2 + 4;
            Min = (ps.start[1] > ps.end[1] ? ps.end[1] : ps.start[1]);
            if (Min > ps.m2[1]) Min = ps.m2[1];
            if (Min > ps.m1[1]) Min = ps.m1[1];
            this.$lineDom[id].childNodes[1].style.top = (ps.m2[1] + ps.m1[1]) / 2 - Min - this.$lineDom[id].childNodes[1].offsetHeight / 2 - 4;
        }
        else    this.$lineDom[id].childNodes[2].textContent = this.$lineData[id].name;
    },
	/*
	 * Todo: 初始化数据加载 【AJAX相关】
	 * Author: LE
	 * Date: 2017/2/15
	 * time: 15:02
	 * */
    loadData: function (url) {
    	var that = this;
	    $.ajax({
		    url: url,
		    type: 'GET',
		    async: true,
		    dataType: 'json',
		    success: function (data) {
		    	var data = $.parseJSON(data.message);
			    that.fileMsg(data.code,data.name);
			    for (var i in data.result.nodes) {
				    that.addNode(i, data.result.nodes[i]);
			    }
			    for (var j in data.result.lines) {
				    that.addLine(j, data.result.lines[j], true);
			    }
		    },
		    error: function (data, xhr, textStatus) {
			    console.log('错误')
			    console.log(xhr)
			    console.log(textStatus)
		    },
	    })
    },
	fileMsg:function (code,name) {
		$('#fileCode').val(code);
		$('#fileName').val(name);
    },
	/*
	 * Todo: 导出数据  【AJAX相关】
	 * Author: LE
	 * Date: 2017/2/20
	 * time: 9:58
	 * */
    exportData: function () {
        this.$fileCode = $('#fileCode').val();
        this.$fileName = $('#fileName').val();
        var data = {
            nodes: {},
            lines: {}
        }
        var nodes = data.nodes;
        var lines = data.lines;
		function keyJson(obj, target, args) {
			for (var k in obj) {
				var jsonstr = JSON.stringify(obj[k], args);
				$.parseJSON(jsonstr);
				target[k] = $.parseJSON(jsonstr)
			}
		}
		keyJson(this.$nodeData, nodes, ['name', 'value', 'nodeType', 'config']);
		keyJson(this.$lineData, lines, ['from', 'to', 'config']);
		console.log(this.$lineData);
        var positionData = {
            nodes: this.$nodeData,
            lines: this.$lineData
        }
        postData = {
            code: this.$fileCode,
            name: this.$fileName,
            positionJson: JSON.stringify(positionData),
            flowJson: JSON.stringify(data)
        }
        console.log(postData);
		var nodeArr = [];
		var specialArr = [];
		var fromArr = [];
		var toArr = [];
		var noError = true;
		// 存储所有结点名,并将判断和循环结点单独存储
		for (var i in nodes) {
			nodeArr.push(i);
			if (nodes[i].nodeType === 'judgement') {
				specialArr.push(i)
			}
		}
		// 存储所有的线条的开始结点和结束结点
	    for (var j in lines) {
			fromArr.push(lines[j].from);
			toArr.push(lines[j].to);
		}
		// 如果存在没有连线的结点则报错
		nodeArr.forEach(function (elem) {
			var nodeWithoutLines = (fromArr.indexOf(elem) === -1) && (toArr.indexOf(elem) === -1) || (nodes[elem].config === '')
			if (nodeWithoutLines) {
				noError = false;
				$('#' + elem).addClass('node-error');
			} else {
				$('#' + elem).removeClass('node-error');
			}
		});
		// 判断和循环必须有两条线
	    // 每个节点都必须有配置项
	    specialArr.forEach(function (elem) {
			var i = 0;
			fromArr.forEach(function (el) {
				if (elem === el) {
					i++
				}
			})
			if (i < 2) {
				noError = false;
				$('#' + elem).addClass('special-error');
			} else {
				$('#' + elem).removeClass('special-error');
				for (var e in lines) {
					if (lines[e].from === elem) {
						console.log(lines[e]);
						if (lines[e].config === '') {
							noError = false;
							$('#' + e + ' path').attr({"marker-end":"url(#arrow3)","stroke":"#f00"});
							$('#' + elem).addClass('special-error');
						} else {
							$('#' + e + ' path').attr({"marker-end":"url(#arrow1)","stroke":"#323232"});
						}
					}
				}
			}
		})
	    // 标题code和name不能为空
	    if (this.$fileCode === '' || this.$fileName === ''){
		    noError = false;
		    $('.file-box').addClass('node-error');
	    }else{
		    $('.file-box').removeClass('node-error');
	    }
		// 如果没有错误则弹出保存菜单
		if (noError) {
			saveConfirm();
		} else {
			$.ligerDialog.alert('<p style="padding: 10px;">您还有未编排完成的对象,无法保存。</p>')
		}
		/*
		 * Todo: 保存发送请求
		 * Author: LE
		 * Date: 2017/2/22
		 * time: 18:59
		 * */
		function saveConfirm() {
			var callback = function (yes) {
				if (yes) {
					$.ajax({
						type: "POST",
						url: dataPostURL,
						data: postData,
						success: function () {
						}
					});
				}
			}
			$.ligerDialog.confirm2 = function (content, title, callback) {
				if (typeof (title) == "function") {
					callback = title;
					type = null;
				}
				var btnclick = function (item, Dialog) {
					Dialog.close();
					if (callback) {
						callback(item.type == 'ok');
					}
				};
				p = {
					type: 'question',
					content: content,
					buttons: [
						{
							text: $.ligerDefaults.DialogString.yes,
							onclick: btnclick,
							type: 'ok',
							cls: 'l-dialog-btn-ok'
						}, {
							text: $.ligerDefaults.DialogString.no,
							onclick: btnclick,
							type: 'no',
							cls: 'l-dialog-btn-no'
						}
					]
				};
				if (typeof (title) == "string" && title != "") p.title = title;
				$.extend(p, {
					width: 350,
					showMax: false,
					showToggle: false,
					showMin: false
				});
				return $.ligerDialog(p);
			};
			$.ligerDialog.confirm2('<p style="font-size: 15px;font-weight: bold;text-align: center;line-height: 20px">是否确认保存为正式流程,确认后流程将立即生效?</p><p style="margin-top: 10px;color: #999;text-align: center;line-height: 20px;">如果是请按确认,如果不是请按取消</p>', '保存流程', callback)
			$('.l-dialog-content').css({"padding": "0 40px 20px 40px"});
		}
    }
};
/*
 * Todo:  ## 注册JQ插件 ****************************************************************************
 * Author: LE
 * Date: 2017/2/15
 * time: 14:59
 * */
$.fn.extend({
	createGooFlow: function (property,url) {
		/*
		 * Todo: 初始化配置参数
		 * Author: LE
		 * Date: 2017/2/20
		 * time: 9:59
		 * */
		var defaultOption = {
			// ******************************************************* UI相关
			id: '',
			MainContener: $('body')[0],
			width: '100%',
			height: '100%',
			// ******************************************************* 工具栏
			haveTool: true,
			toolBtns: ["save", "undo", "redo"],
			toolBtnRemarks: ['保存', '撤销', '重做'],
			// ******************************************************* 流程图工具
			flowChart: true,
			flowBtns: ["state", "complex", "join", "fork"],
			useOperStack: true,  // 是否启用回滚栈, 如否, 头部工具栏的回滚和重做按钮都将失效
			editable: true,      // 是否可编辑
		};
		var options = $.extend({}, defaultOption, property);
		return new GooFlow(this, options,url);
	}
});

Файловите разлики са ограничени, защото са твърде много
+ 4 - 0
src/main/webapp/develop/lib/gooflow/js/jquery.min.js


Файловите разлики са ограничени, защото са твърде много
+ 0 - 6
src/main/webapp/develop/lib/gooflow/json2.js


+ 222 - 0
src/main/webapp/develop/lib/gooflow/test.json

@ -0,0 +1,222 @@
    var data = {
      "nodes": {
        "esb_node_0": {
          "name": "SDf",
          "left": 64,
          "top": 71,
          "type": "task",
          "value": "sd",
          "sType": "service",
          "width": 140,
          "height": 50
        },
        "esb_node_1": {
          "name": "crawler转换器",
          "left": 283,
          "top": 71,
          "type": "plug",
          "value": "CrawlerProcessor0",
          "sType": "processor",
          "width": 140,
          "height": 50
        },
        "esb_node_2": {
          "name": "判断",
          "left": 75,
          "top": 213,
          "type": "state",
          "sType": "judgement",
          "width": 120,
          "height": 70
        },
        "esb_node_3": {
          "name": "循环",
          "left": 100,
          "top": 363,
          "type": "complex",
          "sType": "circle",
          "width": 70,
          "height": 70
        },
        "esb_node_4": {
          "name": "全流程-用户信息",
          "left": 65,
          "top": 560,
          "type": "task",
          "value": "全流程-用户信息",
          "sType": "service",
          "width": 140,
          "height": 50
        },
        "esb_node_5": {
          "name": "全流程-就诊信息",
          "left": 319,
          "top": 435,
          "type": "task",
          "value": "jetty:http://localhost:8080/clinicInfo",
          "sType": "service",
          "width": 140,
          "height": 50
        },
        "esb_node_6": {
          "name": "分流",
          "left": 333,
          "top": 223,
          "type": "fork",
          "sType": "multicast",
          "width": 120,
          "height": 50
        },
        "esb_node_7": {
          "name": "crawler转换器",
          "left": 536,
          "top": 132,
          "type": "plug",
          "value": "CrawlerProcessor0",
          "sType": "processor",
          "width": 140,
          "height": 50
        },
        "esb_node_8": {
          "name": "crawler转换器",
          "left": 540,
          "top": 223,
          "type": "plug",
          "value": "CrawlerProcessor0",
          "sType": "processor",
          "width": 140,
          "height": 50
        },
        "esb_node_9": {
          "name": "crawler转换器",
          "left": 537,
          "top": 311,
          "type": "plug",
          "value": "CrawlerProcessor0",
          "sType": "processor",
          "width": 140,
          "height": 50
        },
        "esb_node_10": {
          "name": "聚合",
          "left": 830,
          "top": 305,
          "type": "join",
          "sType": "aggregate",
          "width": 90,
          "height": 60
        },
        "esb_node_11": {
          "name": "全流程-患者信息",
          "left": 687,
          "top": 453,
          "type": "task",
          "value": "全流程-患者信息",
          "sType": "service",
          "width": 140,
          "height": 50
        },
        "esb_node_12": {
          "name": "全流程-就诊信息",
          "left": 928,
          "top": 452,
          "type": "task",
          "value": "jetty:http://localhost:8080/clinicInfo",
          "sType": "service",
          "width": 140,
          "height": 50
        }
      },
      "lines": {
        "esb_line_0": {
          "type": "sl",
          "from": "esb_node_0",
          "to": "esb_node_1",
          "name": "",
          "marked": false
        },
        "esb_line_1": {
          "type": "tb",
          "M": 171.5,
          "from": "esb_node_1",
          "to": "esb_node_2",
          "name": "",
          "marked": false
        },
        "esb_line_2": {
          "type": "sl",
          "from": "esb_node_2",
          "to": "esb_node_3",
          "name": "自定义内容",
          "marked": false
        },
        "esb_line_3": {
          "type": "tb",
          "from": "esb_node_3",
          "to": "esb_node_5",
          "name": "自定义内容",
          "marked": false,
          "M": 390
        },
        "esb_line_4": {
          "type": "sl",
          "from": "esb_node_3",
          "to": "esb_node_4",
          "name": "自定义内容",
          "marked": false
        },
        "esb_line_5": {
          "type": "sl",
          "from": "esb_node_2",
          "to": "esb_node_6",
          "name": "自定义内容",
          "marked": false
        },
        "esb_line_6": {
          "type": "sl",
          "from": "esb_node_6",
          "to": "esb_node_8",
          "name": "",
          "marked": false
        },
        "esb_line_7": {
          "type": "lr",
          "M": 499.5,
          "from": "esb_node_6",
          "to": "esb_node_7",
          "name": "",
          "marked": false
        },
        "esb_line_8": {
          "type": "lr",
          "M": 500,
          "from": "esb_node_6",
          "to": "esb_node_9",
          "name": "",
          "marked": false
        },
        "esb_line_9": {
          "type": "sl",
          "from": "esb_node_9",
          "to": "esb_node_10",
          "name": "",
          "marked": false
        },
        "esb_line_10": {
          "type": "tb",
          "M": 406.5,
          "from": "esb_node_11",
          "to": "esb_node_10",
          "name": "",
          "marked": false
        },
        "esb_line_11": {
          "type": "tb",
          "M": 406,
          "from": "esb_node_12",
          "to": "esb_node_10",
          "name": "",
          "marked": false
        }
      }
    }