`
cheneyph
  • 浏览: 292649 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
【jquery】解析xml jquery Convert xml to string with jQuery
<!-- test2 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery XML</title>
<link rel="stylesheet" type="text/css" href="../../lib/jeasyui/themes/easyui.css">
<link rel="stylesheet" type="text/css" href="../../lib/jeasyui/themes/icon.css">
<link rel="stylesheet" type="text/css" href="../../lib/common/project.css">
	<script type="text/javascript" src="../../lib/jeasyui/jquery.min.js"></script>
	<script type="text/javascript" src="../../lib/jeasyui/jquery.easyui.min.js"></script>
	<script type="text/javascript" src="./jquery.xml.js"></script>
<!-- 	<script type="text/javascript" src="./jquery.jxml.js"></script> -->
</head>
<body>
<table>
	<tr>
		<td style="border: 1px solid;">
<xmp><data>
	<riskcode>APLP</riskcode>
	<riskname>的空格和换行会直接显示</riskname>
</data>
</xmp>
		</td>
	</tr>
	<tr>
		<td><textarea id="" name="" rows="15" cols="80" class="textarea"></textarea></td>
		<td><a href="javascript:void(0);" class="easyui-linkbutton">操作</a></td>
	</tr>
</table>
<script type="text/javascript">
(function($) {
	$.extend(jQuery, {
		loadXML: function(xmlString){
			return $($.parseXML(xmlString));
		}
	});
	$.fn.extend({
		appendXml: function(s){
			return this.each(function() {
				if (typeof s != "string") return;
// 	            if (!jQuery.isXMLDoc(this)){
// 	            	console.log("isXMLDoc = " + false);
// 	            	return;
// 	            }
	            var node = $.parseXML(s).firstChild.cloneNode(true);
// 	            console.log(node);
// 	            console.log(node.nodeName);
	            this.appendChild(node);
			});
		},
		toXMLString: function(){
			var xmlDoc = $(this)[0];
// 			return xmlDoc.xml || (new XMLSerializer()).serializeToString(xmlDoc);
			if (window.ActiveXObject){
				console.log("IE ...");
				return xmlDoc.xml;
			} else {
				return (new XMLSerializer()).serializeToString(xmlDoc);
			}
		}
	});
})(jQuery);

$(document).ready(function(){
	var xml = $("xmp").html();

	var $xml = $(xml);
	$xml.appendXml("<remark>daof想出来的</remark>");
	console.log("@>> " + $xml.toXMLString());
})
</script>
</body>
</html>





<!----------------------------------------------------------------------->
<!----------------------------------------------------------------------->
<!----------------------------------------------------------------------->

<!-- test1 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery XML</title>
<link rel="stylesheet" type="text/css" href="../../lib/jeasyui/themes/easyui.css">
<link rel="stylesheet" type="text/css" href="../../lib/jeasyui/themes/icon.css">
<link rel="stylesheet" type="text/css" href="../../lib/common/project.css">
	<script type="text/javascript" src="../../lib/jeasyui/jquery.min.js"></script>
	<script type="text/javascript" src="../../lib/jeasyui/jquery.easyui.min.js"></script>
</head>
<body>
<table>
	<tr>
		<td style="border: 1px solid;">
<xmp><data>
	<riskcode>APLP</riskcode>
	<riskname>的空格和换行会直接显示</riskname>
</data>
</xmp>
		</td>
	</tr>
	<tr>
		<td><textarea id="" name="" rows="15" cols="80" class="textarea"></textarea></td>
		<td><a href="javascript:void(0);" class="easyui-linkbutton">操作</a></td>
	</tr>
</table>
<script type="text/javascript">
$(document).ready(function(){
	$("a").click(function(){
		var xml = $("xmp").html();
		console.log(xml);
		
		var $xmlObj = null;
		if (window.ActiveXObject){
			var xmldoc = new ActiveXObject("Microsoft.XMLDOM");   //创建XMLDOC 对象
			xmldoc.async=false;  //使用同步方式加载XML字符串
			xmldoc.loadXML(xml);  //加载XML字符串
			$xmlObj = $(xmldoc);
		} else {
			$xmlObj = $(xml);
		}
// 		var $xmlObj = $.parseXML(xml);
		console.log("riskcode = " + $xmlObj.find('riskcode').text());
		
// 		var $msg = $("<msg/>");
// 		$msg.text("jquery xml 消息");
// 		$xmlObj.append($("<msg/>").text("jquery xml 消息"));
		
		var xmlString;
	    if (window.ActiveXObject){
		    // IE
	    	console.log("IE ...");
	        xmlString = $xmlObj[0].xml;
	    } else {
		    // code for Mozilla, Firefox, Opera, etc.
		    var oSerializer = new XMLSerializer(); 
	        xmlString = oSerializer.serializeToString($xmlObj[0]);
	    }
		$("textarea").val(xmlString);
	});
})
</script>
</body>
</html>
javascript stopPropagation() 方法 javascript stopPropagation() 方法
定义和用法
不再派发事件。
终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。

语法
event.stopPropagation()

说明
该方法将停止事件的传播,阻止它被分派到其他 Document 节点。在事件传播的任何阶段都可以调用它。注意,虽然该方法不能阻止同一个 Document 节点上的其他事件句柄被调用,但是它可以阻止把事件分派到其他节点。
【jsch】sftp 文件上传 java
/**
 * sftp 文件上传
 * 依赖:
 *		<dependency>
 *			<groupId>com.jcraft</groupId>
 *			<artifactId>jsch</artifactId>
 *			<version>0.1.50</version>
 *		</dependency>
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;
import java.util.Vector;

import org.apache.log4j.Logger;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

/**
 * @author c1panx
 * @ 2015年5月8日  下午4:12:28
 */
public class SFTPUtil {
	
	private static final Logger logger = Logger.getLogger(SFTPUtil.class);
	
	private static final String host = "10.140.130.50";
	private static final String username = "uat";
	private static final String password = "Aa123456";
	private static final String cdPath = "/home/uat/backup/temp";
	private static final String localPath = "D:\\LG\\jacob\\";
	
	private static final String separator = "/";

	public static void upload(){
		long startTime = System.currentTimeMillis();
		ChannelSftp sftp = null;
		Channel channel = null;
		try {
			JSch jsch = new JSch();
			Session sshSession = jsch.getSession(username, host);
			logger.debug("Session created.");
			
			sshSession.setPassword(password);
			Properties sshConfig = new Properties();
			sshConfig.put("StrictHostKeyChecking", "no");
			sshSession.setConfig(sshConfig);
			sshSession.connect();
			logger.debug("Session connected.");
			
			logger.debug("Opening Channel....");
			channel = sshSession.openChannel("sftp");
			channel.connect();
			sftp = (ChannelSftp) channel;
			
			// 遍历上传
			File file = new File(localPath);
			logger.info("start cleart remote folder .....");
			clearRemoteFolder(sftp, cdPath, file);
			
			logger.info("==========================================");
			logger.info("start upload files .....");
			uploadFile(sftp, cdPath, file);
			
			channel.disconnect();
		} catch (JSchException e) {
			logger.error(e.getMessage(), e);
		} catch (SftpException e) {
			logger.error(e.getMessage(), e);
		} catch (FileNotFoundException e) {
			logger.error(e.getMessage(), e);
		} finally {
			if (null != channel) {
				channel.disconnect();
			}
			if (null != sftp) {
				sftp.disconnect();
			}
			long endTime = System.currentTimeMillis();
			logger.info("diff time: " + (endTime - startTime));
		}
	}
	
	@SuppressWarnings("unchecked")
	private static void clearRemoteFolder(ChannelSftp sftp, String pwd,
			File file) throws SftpException {
		String childPwd = pwd + separator + file.getName();
		logger.debug("start rm remote file ...[" + childPwd + "]");

		boolean exists = false;
		Vector<LsEntry> v = sftp.ls(pwd);
		for (LsEntry lsEntry : v) {
			String fileName = lsEntry.getFilename();
			if (fileName.equalsIgnoreCase(file.getName())) {
				exists = true;
				break;
			}
		}
		
		if (exists == false) {
			logger.debug("[" + childPwd + "] does not exist.");
			return;
		}
		deleteFile(sftp, pwd, file.getName());
	}
	
	@SuppressWarnings("unchecked")
	private static void deleteFile(ChannelSftp sftp, String pwd, String delName)
			throws SftpException {
		String filePath = pwd + separator + delName;
		try {
			sftp.cd(filePath);
			Vector<LsEntry> v = sftp.ls(filePath);
			for (LsEntry lsEntry : v) {
				String fileName = lsEntry.getFilename();
				if (fileName.equals(".") || fileName.equals("..")) {
					continue;
				}
				deleteFile(sftp, filePath, fileName);
			}
			logger.debug("rm dir: " + filePath);
			sftp.rmdir(pwd + separator + delName);
		} catch (SftpException e) {
			// 删除文件
			logger.debug("rm file: " + filePath);
			sftp.rm(filePath);
		}
	}
	
	private static void uploadFile(ChannelSftp sftp, String pwd, File file)
			throws SftpException, FileNotFoundException {
		sftp.cd(pwd);
		if (file.isDirectory()) {
			String childPwd = pwd + separator + file.getName();
			logger.debug("mkdir: " + childPwd);
			sftp.mkdir(file.getName());
			
			sftp.cd(childPwd);
			File[] files = file.listFiles();
			for (File file2 : files) {
				uploadFile(sftp, childPwd, file2);
			}
		} else {
			logger.debug("upload file: " + file.getName());
			sftp.put(new FileInputStream(file), file.getName());
		}
	}
}
【html】pdf在线浏览 html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>pdf在线浏览</title>
</head>
<body marginheight="0" marginwidth="0">
<!-- <embed> 标签是 HTML 5 中的新标签 -->
	<embed height="100%" width="100%" src="pdf.pdf" type="application/pdf" />
</body>
</html>
【require.js】 require.js Javascript模块化编程(三):require.js的用法

        
【spring mvc】多数据源配置2 spring mvc
<!-- self-dataSource.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"
	default-autowire="byName">
	
	<!-- 配置数据源 -->
	<bean id="self_dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
        <property name="driverClassName" value="${self.jdbc.driverClassName}" />  
        <property name="url" value="${self.jdbc.url}" />  
        <property name="username" value="${self.jdbc.username}" />  
        <property name="password" value="${self.jdbc.password}" />  
        <property name="maxActive" value="100" />  
        <property name="maxWait" value="1000" />  
        <property name="poolPreparedStatements" value="false" />  
        <property name="defaultAutoCommit" value="false" />  
    </bean>  

	<!--把mybatis SqlSessionFactory的创建交由spring管理 -->
	<bean id="self_sqlSessionFactoryBeanName" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="self_dataSource" />
<!-- 		<property name="typeAliasesPackage" value="com.cignacmb.selfhelp.dao.self" /> -->
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="mapperLocations">
			<list>
				<value>classpath:com/cignacmb/selfhelp/self/mapper/*.xml</value>
			</list>
		</property>
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="sqlSessionFactoryBeanName" value="self_sqlSessionFactoryBeanName"/>
		<property name="basePackage" value="com.cignacmb.selfhelp.self.mapper" />
	</bean>

	<!-- Local Transaction Management (txManager) -->
	<bean id="selfTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="self_dataSource" />
		<qualifier value="selfTransaction" />
	</bean>

	<!--启动spring注解功能 -->
	<tx:annotation-driven transaction-manager="selfTransactionManager" />
</beans>

<!------------------------------------------------------------------------------------->

<!-- lis-dataSource.xml -->
	<!-- 配置数据源 -->
	<bean id="lis_dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
        <property name="driverClassName" value="${lis.jdbc.driverClassName}" />  
        <property name="url" value="${lis.jdbc.url}" />  
        <property name="username" value="${lis.jdbc.username}" />  
        <property name="password" value="${lis.jdbc.password}" />  
        <property name="maxActive" value="100" />  
        <property name="maxWait" value="1000" />  
        <property name="poolPreparedStatements" value="false" />  
        <property name="defaultAutoCommit" value="false" />  
    </bean>  
	<bean id="lis_sqlSessionFactoryBeanName" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="lis_dataSource" />
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="mapperLocations">
			<list>
				<value>classpath:com/cignacmb/selfhelp/lis/mapper/*.xml</value>
			</list>
		</property>
	</bean>
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="sqlSessionFactoryBeanName" value="lis_sqlSessionFactoryBeanName"/>
		<property name="basePackage" value="com.cignacmb.selfhelp.lis.mapper" />
	</bean>
	<bean id="lisTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="lis_dataSource" />
		<qualifier value="lisTransaction" />
	</bean>
	<tx:annotation-driven transaction-manager="lisTransactionManager" />

<!------------------------------------------------------------------------------------->

<!-- applicationContext.xml -->
	<context:property-placeholder location="classpath:system-config/dev.properties" ignore-unresolvable="true" />

	<!-- 自动扫描Bean -->
	<context:component-scan base-package="com.cignacmb.selfhelp" >
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
	
	<!-- enable autowire -->  
<!--     <context:annotation-config /> -->
    
	<!-- 强制使用CGLIB代理 -->
	<aop:aspectj-autoproxy proxy-target-class="true" />

	<import resource="datasource/self-dataSource.xml"/>
	<import resource="datasource/lis-dataSource.xml"/>
【jeasyui 1.4.2】methods扩展之autoMergeCells jeasyui
$.extend($.fn.datagrid.methods, {
	/**
	 * 自动合并表体<br>
	 * 从左向右合并,右边列能合并的行是右边列已合并的范围
	 * @param {} jq
	 * @param [] fields 需合并的列,columns中的field值组成的数组
	 * @return {}
	 */
	autoMergeCells : function(jq, fields) {
		/**
		 * 
		 * @param col 起始列
		 * @param startrow 起始索引
		 * @param endrow 结束索引
		 * @param allcols 列数据集合
		 * @param target grid对象
		 * @param [] fields 需合并的列,columns中的field值组成的数组
		 */
		function megerCol(col,startrow,endrow,allcols,target,fields){
			var colArrar = allcols[col];
			var startIndex = startrow;
			var field = fields[col];
			for(var i=(startIndex+1);i<=endrow;i++){
				if(colArrar[i] == colArrar[startIndex]){
					if(i == endrow){
						var rowspan = i-startIndex+1;
						//合并单元格
						target.datagrid('mergeCells', {
		                    index : startIndex,
		                    field : field,
		                    rowspan : rowspan
		                 });
						if(col+1 < fields.length){
							megerCol(col+1,startIndex,i,allcols,target,fields); 
						}
					}else{
						continue;	
					}
				}else{
					if(startIndex != (i-1)){
						var rowspan = i-startIndex;
						//合并单元格
						target.datagrid('mergeCells', {
		                    index : startIndex,
		                    field : field,
		                    rowspan : rowspan
		                 });
						if(col+1 < fields.length){
							megerCol(col+1,startIndex,i-1,allcols,target,fields);
						}
					}
					startIndex = i;
				}
			}
		};
		return jq.each(function() {
			var target = $(this);
			if (!fields) {
				fields = target.datagrid("getColumnFields");
			}
			var allfileldValue = [];
			var rows = target.datagrid("getRows");
			//循环fileld得到所有行的数据数组
			for (var j = 0; j < fields.length; j++) {
				var fileldValue = [];
				for (var i = 0; i < rows.length; i++) {
					var row = rows[i];
					fileldValue.push(row[fields[j]]);
				}
				allfileldValue.push(fileldValue);
			}
			megerCol(0, 0, rows.length - 1, allfileldValue, target, fields);
		});
	}
});

调用示例:
$("#testTable").datagrid("autoMergeCells");
or
$("#testTable").datagrid("autoMergeCells", ['price1', 'price2']);
【GooFlow】GooFlow Demo gooflow 主题:基于JQUERY的WEB在线流程图设计器GOOFLOW 0.7版
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>gooFlow</title>
<link rel="stylesheet" type="text/css" href="http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/default.css">
<link rel="stylesheet" type="text/css" href="./GooFlow.css">

<script type="text/javascript" src="http://sandbox.runjs.cn/js/sandbox/jquery/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/GooFunc.js"></script>
</head>
<body>
<div id="demo" style="margin:10px"></div>
<script type="text/javascript" src="./data.js"></script>
<script type="text/javascript" src="./GooFlow.js"></script>
<script type="text/javascript">
var property={
	width:1200,
	height:450,
//	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
};
$(document).ready(function(){
	var demo=$.createGooFlow($("#demo"),property);
// 	demo.setNodeRemarks(remark);
	//demo.onItemDel=function(id,type){
	//	return confirm("确定要删除该单元吗?");
	//}
	demo.loadData(jsondata);
});
</script>
</body>
</html>

// 参考
http://runjs.cn/detail/99epj1t2
http://sandbox.runjs.cn/show/99epj1t2


// product-data.js
var jsondata = {
	title : "产品分类",
	nodes : {
		"node_101" : {name : "人身保险",    left :  10, top : 220, width : 24, height : 24, type : "complex mix", alt : true},
		
		"node_201" : {name : "人寿保险",    left : 210, top : 80, width : 24, height : 24, type : "complex mix", alt : true},
		"node_202" : {name : "年金保险",    left : 210, top : 220, width : 24, height : 24, type : "complex mix", alt : true},
		"node_203" : {name : "健康保险",    left : 210, top : 325, width : 24, height : 24, type : "complex mix", alt : true},
		"node_204" : {name : "意外伤害保险", left : 210, top : 430, width : 60, height : 24, type : "complex mix", alt : true},

		"node_301" : {name : "定期寿险", left : 410, top : 10, width : 24, height : 24, type : "complex mix", alt : true},
		"node_302" : {name : "终身寿险", left : 410, top : 80, width : 24, height : 24, type : "complex mix", alt : true},
		"node_303" : {name : "两全保险", left : 410, top : 150, width : 24, height : 24, type : "complex mix", alt : true},
		"node_304" : {name : "疾病保险", left : 410, top : 290, width : 24, height : 24, type : "complex mix", alt : true},
		"node_305" : {name : "医疗保险", left : 410, top : 360, width : 24, height : 24, type : "complex mix", alt : true}
	},
	lines : {
		"line101_201" : {type:"sl", M:81.5, from:"node_101", to:"node_201", name: ""},
		"line101_202" : {type:"sl", M:81.5, from:"node_101", to:"node_202", name: ""},
		"line101_203" : {type:"sl", M:81.5, from:"node_101", to:"node_203", name: ""},
		"line101_204" : {type:"sl", M:81.5, from:"node_101", to:"node_204", name: ""},

		"line201_301" : {type:"sl", M:81.5, from:"node_201", to:"node_301", name: ""},
		"line201_302" : {type:"sl", M:81.5, from:"node_201", to:"node_302", name: ""},
		"line201_303" : {type:"sl", M:81.5, from:"node_201", to:"node_303", name: ""},

		"line203_304" : {type:"sl", M:81.5, from:"node_203", to:"node_304", name: ""},
		"line203_305" : {type:"sl", M:81.5, from:"node_203", to:"node_305", name: ""}
	}
};
// data.js
jsondata={"title":"10086网状流程","nodes":{"demo_node_9":{"name":"桂中区","left":10,"top":10,"type":"start round","width":24,"height":24,"alt":true},"demo_node_10":{"name":"桂北区","left":10,"top":81,"type":"start round","width":24,"height":24,"alt":true},"demo_node_11":{"name":"桂西区","left":9,"top":143,"type":"start round","width":24,"height":24,"alt":true},"demo_node_12":{"name":"桂北区","left":11,"top":290,"type":"start round","width":24,"height":24,"alt":true},"demo_node_14":{"name":"桂东区","left":7,"top":339,"type":"start round","width":24,"height":24,"alt":true},"demo_node_2":{"name":"问候语2","left":232,"top":104,"type":"chat","width":86,"height":24,"alt":true},"demo_node_3":{"name":"问候语3","left":220,"top":260,"type":"chat","width":86,"height":24,"alt":true},"demo_node_4":{"name":"问候语4","left":222,"top":327,"type":"chat","width":86,"height":24,"alt":true},"demo_node_5":{"name":"停机判断","left":107,"top":47,"type":"fork","width":86,"height":24,"alt":true},"demo_node_13":{"name":"停机判断2","left":103,"top":289,"type":"fork","width":86,"height":24,"alt":true},"demo_node_20":{"name":"停机菜单","left":355,"top":12,"type":"join","width":86,"height":24,"alt":true},"demo_node_21":{"name":"正常菜单","left":368,"top":362,"type":"join","width":86,"height":24,"alt":true},"demo_node_27":{"name":"延时停机","left":492,"top":13,"type":"node","width":86,"height":24,"alt":true},"demo_node_28":{"name":"开机","left":491,"top":62,"type":"node","width":86,"height":24,"alt":true},"demo_node_29":{"name":"缴费","left":466,"top":162,"type":"node","width":86,"height":24,"alt":true},"demo_node_30":{"name":"历史话费查询","left":591,"top":116,"type":"node","width":111,"height":24,"alt":true},"demo_node_1":{"name":"问候语1","left":228,"top":42,"type":"chat","width":86,"height":24,"alt":true},"demo_node_38":{"name":"积分查询","left":506,"top":261,"type":"complex mix","width":86,"height":24,"alt":true},"demo_node_39":{"name":"剩余资源查询","left":499,"top":312,"type":"complex mix","width":107,"height":24,"alt":true},"demo_node_40":{"name":"常用业务办理","left":491,"top":356,"type":"complex mix","width":110,"height":24,"alt":true},"demo_node_42":{"name":"网络服务","left":492,"top":397,"type":"complex mix","width":86,"height":24,"alt":true},"demo_node_43":{"name":"转人工服务","left":479,"top":457,"type":"state","width":91,"height":24,"alt":true},"demo_node_44":{"name":"话费查询","left":477,"top":213,"type":"state","width":86,"height":24,"alt":true},"demo_node_52":{"name":"实时话费查询","left":609,"top":212,"type":"node","width":107,"height":24,"alt":true},"demo_node_54":{"name":"网络专区投诉","left":639,"top":399,"type":"task","width":106,"height":24,"alt":true},"demo_node_55":{"name":"普通转人工","left":641,"top":456,"type":"task","width":109,"height":24,"alt":true},"demo_node_59":{"name":"10088","left":500,"top":514,"type":"task","width":86,"height":24,"alt":true}},"lines":{"demo_line_6":{"type":"lr","M":81.5,"from":"demo_node_9","to":"demo_node_5","name":""},"demo_line_7":{"type":"lr","M":81.5,"from":"demo_node_10","to":"demo_node_5","name":""},"demo_line_9":{"type":"lr","M":81.5,"from":"demo_node_11","to":"demo_node_5","name":""},"demo_line_14":{"type":"sl","from":"demo_node_12","to":"demo_node_13","name":""},"demo_line_15":{"type":"lr","M":78.5,"from":"demo_node_14","to":"demo_node_13","name":""},"demo_line_17":{"type":"tb","M":152,"from":"demo_node_5","to":"demo_node_2","name":"F"},"demo_line_18":{"type":"tb","M":239,"from":"demo_node_13","to":"demo_node_3","name":"T"},"demo_line_19":{"type":"tb","M":383.5,"from":"demo_node_13","to":"demo_node_4","name":"F"},"demo_line_22":{"type":"lr","M":339,"from":"demo_node_4","to":"demo_node_21","name":""},"demo_line_23":{"type":"lr","M":337.5,"from":"demo_node_2","to":"demo_node_21","name":""},"demo_line_26":{"type":"lr","M":366.5,"from":"demo_node_3","to":"demo_node_20","name":""},"demo_line_31":{"type":"tb","M":176.5,"from":"demo_node_20","to":"demo_node_29","name":"4"},"demo_line_32":{"type":"tb","M":25.5,"from":"demo_node_20","to":"demo_node_27","name":"1"},"demo_line_33":{"type":"tb","M":128,"from":"demo_node_20","to":"demo_node_30","name":"3"},"demo_line_34":{"type":"tb","M":74.5,"from":"demo_node_20","to":"demo_node_28","name":"2"},"demo_line_36":{"type":"tb","M":21.5,"from":"demo_node_5","to":"demo_node_1","name":"T"},"demo_line_37":{"type":"lr","M":367,"from":"demo_node_1","to":"demo_node_20","name":""},"demo_line_45":{"type":"tb","M":225,"from":"demo_node_21","to":"demo_node_44","name":"1"},"demo_line_46":{"type":"tb","M":274.5,"from":"demo_node_21","to":"demo_node_38","name":"2"},"demo_line_47":{"type":"tb","M":325.5,"from":"demo_node_21","to":"demo_node_39","name":"3"},"demo_line_48":{"type":"sl","from":"demo_node_21","to":"demo_node_40","name":"4"},"demo_line_49":{"type":"tb","M":411.5,"from":"demo_node_21","to":"demo_node_42","name":"5"},"demo_line_50":{"type":"tb","M":470.5,"from":"demo_node_21","to":"demo_node_43","name":"0"},"demo_line_51":{"type":"sl","from":"demo_node_44","to":"demo_node_30","name":"2"},"demo_line_53":{"type":"sl","from":"demo_node_44","to":"demo_node_52","name":"1"},"demo_line_56":{"type":"sl","from":"demo_node_43","to":"demo_node_55","name":"0"},"demo_line_57":{"type":"sl","from":"demo_node_43","to":"demo_node_54","name":"1"},"demo_line_58":{"type":"sl","from":"demo_node_42","to":"demo_node_54","name":"0"},"demo_line_60":{"type":"sl","from":"demo_node_43","to":"demo_node_59","name":"2","alt":true}},"areas":{},"initNum":61};
【GooFlow】GooFlow.css gooflow
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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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; text-indent:18px;display:block inline;height:14px;margin:2px;border:#B7C8D7 1px solid;border-right:#E9F4FA 1px solid;border-bottom:#E9F4FA 1px solid;padding:1px;width:160px;text-align:center;
	background: url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -137px 1px;float:left;color:#15428B;-moz-border-radius:3px; -webkit-border-radius:3px;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 1px;}
.GooFlow_head_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:0px 1px;float:left;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_head_btn b{display:inline-block;overflow:hidden;width:18px;height:18px;border:0px;}
.GooFlow_head_btn:hover{
	-moz-border-radius:2px; -webkit-border-radius:2px;border-radius:2px;border:#8E9DA6 1px solid;
	padding:0px;border:#8B7654 1px solid; background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_btn_bg.png) repeat-x;width:20px;height:20px;
}
.GooFlow_head_btn:hover b{border:#F6A32D 1px solid;border-top-color:#B1905D;margin:0px;-moz-border-radius:1px; -webkit-border-radius:1px;border-radius:1px;}
.GooFlow_tool{
	border:#B7C8D7 1px solid;float:left;margin:0px 3px;overflow:hidden;clear:left;
	-moz-border-radius:3px; -webkit-border-radius:3px;border-radius:3px;
}
.GooFlow_tool_div{border:#E9F4FA 1px solid;overflow:hidden;-moz-border-radius:2px; -webkit-border-radius:2px;border-radius:2px;width:24px;}

.GooFlow_tool span{height:0px;overflow:hidden;border-bottom:#9AC6FF 1px solid;border-top:#FFFFFF 1px solid;margin:1px;clear:both;display:block;}
.GooFlow_tool_btn{display:block;border:0px;height:18px;width:18px;cursor:default;padding:2px;margin:1px;outline:none;blr:expression(this.onFocus=this.blur());}
.GooFlow_tool_btn b{display:block;overflow:hidden;width:18px;height:18px;border:0px}
.GooFlow_tool_btn:hover{-moz-border-radius:3px; -webkit-border-radius:3px;border-radius:3px;padding:0px;border:#8E9DA6 1px solid;width:20px;height:20px;}
.GooFlow_tool_btn:hover b{border:#F5FAFC 1px solid;-moz-border-radius:2px; -webkit-border-radius:2px;border-radius:2px}
.GooFlow_tool_btndown{
	width:20px;height:20px;cursor:default;margin:1px;outline:none;blr:expression(this.onFocus=this.blur());
	-moz-border-radius:3px; -webkit-border-radius:3px;border-radius:3px;border:#8E9DA6 1px solid;border:0px;
	padding:0px;border:#8B7654 1px solid; background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_btn_bg.png) repeat-x;display:block;
}
.GooFlow_tool_btndown b{
	display:block;overflow:hidden;width:14px;height:14px;border:#F6A32D 1px solid;
	border-top-color:#B1905D;margin:0px;-moz-border-radius:2px;-webkit-border-radius:2px;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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_blank.gif);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_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 b{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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_btn_bg.png) repeat-x 0px -72px;border:#7DA2CE solid 1px;
	-moz-border-radius:3px; -webkit-border-radius:3px;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;-moz-border-radius:2px;-webkit-border-radius:2px;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 b{display:block;width:18px;height:18px;overflow:hidden;}

.GooFlow .item_round{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_bg.png) repeat-x;-moz-border-radius:11px;-webkit-border-radius:11px;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_complex{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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/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_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 b{display:inline-block;width:15px;height:15px;margin-left:2px;cursor:pointer}
.GooFlow .b_l1{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/GooFlow_line_oper.png) no-repeat 1px 1px}
.GooFlow .b_l2{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/GooFlow_line_oper.png) no-repeat 1px -14px}
.GooFlow .b_l3{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/GooFlow_line_oper.png) no-repeat 1px -29px}
.GooFlow .b_x{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/GooFlow_line_oper.png) no-repeat 1px -44px;margin-left:10px}

.GooFlow .ico_cursor{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat 2px -20px}
.GooFlow .ico_start{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -19px -20px}
.GooFlow .ico_end{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -39px -20px}
.GooFlow .ico_fork{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -59px -20px}
.GooFlow .ico_join{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -78px -20px}
.GooFlow .ico_direct{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -137px -20px}
.GooFlow .ico_group{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -96px -20px}
.GooFlow .ico_complex{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -116px -20px}
.GooFlow .ico_node{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -19px -45px}
.GooFlow .ico_task{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat 2px -45px}
.GooFlow .ico_chat{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -38px -45px}
.GooFlow .ico_state{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -59px -45px}
.GooFlow .ico_plug{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -135px -45px}

.GooFlow .ico_open{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -19px 1px}
.GooFlow .ico_new{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat 2px 1px}
.GooFlow .ico_reload{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -97px 1px}
.GooFlow .ico_save{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -39px 1px}
.GooFlow .ico_undo{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -58px 1px}
.GooFlow .ico_redo{background:url(http://sandbox.runjs.cn/uploads/rs/370/6xjzaeph/gooflow_icon.png) no-repeat -78px 1px}
【GooFlow】GooFlow.js gooflow
//定义一个区域图类:
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.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","#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.$l
【lhdialog】lhgDialog窗口组件 lhgdialog

        
【jeasyui 1.4.2】methods扩展之showCellTip jeasyui 基于1.3.3版本tooltip的datagrid单元格tip实现
$.extend($.fn.datagrid.methods, {
   /** 
    * 开打提示功能   
    * @param {} jq   
    * @param {} params 提示消息框的样式   
    * @return {}   
    */
    showCellTip: function (jq, params) {
        function showTip(data, td, e) {
            if ($(td).text() == "")
                return;
            data.tooltip.text($(td).text()).css({
                top: (e.pageY) + 'px',
                left: (e.pageX) + 'px',
                'z-index': $.fn.window.defaults.zIndex,
                display: 'block'
            });
        };
        return jq.each(function () {
            var grid = $(this);
            var options = $(this).data('datagrid');
            if (!options.tooltip) {
                var panel = grid.datagrid('getPanel').panel('panel');
                var defaultCls = {
                    'border': '1px solid #333',
                    'padding': '0.5em',
                    'color': '#333',
                    'background': '#f7f5d1',
                    'position': 'absolute',
                    'max-width': '200px',
                    'border-radius': '4px',
                    '-moz-border-radius': '4px',
                    '-webkit-border-radius': '4px',
                    'display': 'none'
                }
                var tooltip = $("<div id='celltip'></div>").appendTo('body');
                tooltip.css($.extend({}, defaultCls, params.cls));
                options.tooltip = tooltip;
                panel.find('.datagrid-body').each(function () {
                    var delegateEle = $(this).find('> div.datagrid-body-inner').length
                            ? $(this).find('> div.datagrid-body-inner')[0]
                            : this;
                    $(delegateEle).undelegate('td', 'mouseover').undelegate(
                            'td', 'mouseout').undelegate('td', 'mousemove')
                            .delegate('td', {
                                'mouseover': function (e) {
                                    if (params.delay) {
                                        if (options.tipDelayTime)
                                            clearTimeout(options.tipDelayTime);
                                        var that = this;
                                        options.tipDelayTime = setTimeout(
                                                function () {
                                                    showTip(options, that, e);
                                                }, params.delay);
                                    } else {
                                        showTip(options, this, e);
                                    }

                                },
                                'mouseout': function (e) {
                                    if (options.tipDelayTime)
                                        clearTimeout(options.tipDelayTime);
                                    options.tooltip.css({
                                        'display': 'none'
                                    });
                                },
                                'mousemove': function (e) {
                                    var that = this;
                                    if (options.tipDelayTime) {
                                        clearTimeout(options.tipDelayTime);
                                        options.tipDelayTime = setTimeout(
                                                function () {
                                                    showTip(options, that, e);
                                                }, params.delay);
                                    } else {
                                        showTip(options, that, e);
                                    }
                                }
                            });
                });

            }

        });
    },
   /** 
    * 关闭消息提示功能   
    * @param {} jq   
    * @return {}   
    */
    hideCellTip: function (jq) {
        return jq.each(function () {
            var data = $(this).data('datagrid');
            if (data.tooltip) {
                data.tooltip.remove();
                data.tooltip = null;
                var panel = $(this).datagrid('getPanel').panel('panel');
                panel.find('.datagrid-body').undelegate('td',
                                'mouseover').undelegate('td', 'mouseout')
                                .undelegate('td', 'mousemove')
            }
            if (data.tipDelayTime) {
                clearTimeout(data.tipDelayTime);
                data.tipDelayTime = null;
            }
        });
    }
});

// 示例
$productTables.datagrid('showCellTip', {
    onlyShowInterrupt: false,     //是否只有在文字被截断时才显示tip,默认值为false             
    position: 'bottom',   //tip的位置,可以为top,botom,right,left
    cls: { 'background-color': '#D1EEEE' },  //tip的样式
    delay: 100   //tip 响应时间
});

$productTables.datagrid('hideCellTip');
【jeasyui 1.3.6】methods扩展之showHideFieldsMenu表头右击字段显隐菜单【版本2】 jeasyui
$.extend($.fn.datagrid.methods,{
	// 表头右击字段显隐菜单
    showHideFieldsMenu : function(jq) {
        var menuID = jq.attr("id") + "_context_menu";
        var $contextMenu = $("#" + menuID);
        if ($contextMenu.length > 0) {
            return;
        }
        var fieldArray = jq.datagrid('getColumnFields');
        if (null == fieldArray || fieldArray == undefined) {
            return;
        }
        $contextMenu = $('<div class="easyui-menu" style="width:100px;"></div>').appendTo('body');
        $contextMenu.attr("id", menuID);
        var $fieldHTML = $('<div><span>显示/隐藏列</span></div>').appendTo($contextMenu);
        var $filedsList = $('<div class="menu-content" style="text-align:left"/>').appendTo($fieldHTML);
        
        var $menuItemList = $("<ul class='menu-table-fields'/>");
        for (var i = 0; i < fieldArray.length; i++) {
        	var checkboxID = menuID + "_checkbox_" + i;
            var $checkBox = $('<input type="checkbox">').attr("id", checkboxID);
            var $label = $('<label>' + jq.datagrid('getColumnOption', fieldArray[i]).title + '</label>');
            $label.attr("for", checkboxID);
            var $menuItem = $('<li />').append($checkBox).append($label);
            if (jq.datagrid('getColumnOption', fieldArray[i]).hidden == true) {
                $checkBox.attr('checked', true);
            }
            $checkBox.bind('click', {
                $jq : jq,
                field : fieldArray[i]
            }, function(ev) {
                var flag = ev.data.$jq.datagrid('getColumnOption', ev.data.field).hidden;
                $(this).attr('checked', !flag);
                var action = flag ? "showColumn" : "hideColumn";
                ev.data.$jq.datagrid(action, ev.data.field);
            });
            $checkBox.bind('mouseover', function(){
            	$(this).css('cursor', 'pointer');
            }).bind('mouseleft', function() {  
                $(this).css('cursor', 'none');  
            });
            $label.bind('mouseover', function(){
            	$(this).css('cursor', 'pointer');
            }).bind('mouseleft', function() {  
                $(this).css('cursor', 'none');  
            });
            $menuItemList.append($menuItem);
        }
        $filedsList.append($menuItemList);
        $.parser.parse();
        jq.datagrid({
            onHeaderContextMenu : function(e, field) {
                e.preventDefault();
                $contextMenu.menu('show', {
                    left : $(event.target).offset().left,
                    top : $(event.target).offset().top + 10
                });
            }
        });
    }
});

相关CSS:
ul.menu-table-fields li{
	list-style: none;
	line-height: 2.1em;
	margin-left: -3em;
	border-bottom: 1px solid #C1C1C1;
}

ul.menu-table-fields li:HOVER{
	background-color: #C1CDCD;
}
【SQLServer】常用查询 sqlserver
查询表下所有字段信息
SELECT * FROM SysColumns WHERE id=Object_Id('TableName') ;

查询包含指定字段的表
SELECT object_name(id), * FROM SysColumns WHERE name like 'campaign_code2' ;
【spring mvc】ObjectMapper之类型转换 spring mvc SpringMVC+MyBatis - 12 spring mvc4返回的json日期为Long的解决方案
import java.io.IOException;
import java.util.Date;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.springframework.stereotype.Service;

@Service
public class CustomObjectMapper extends ObjectMapper {
	public CustomObjectMapper() {
		CustomSerializerFactory factory = new CustomSerializerFactory();
		factory.addGenericMapping(Date.class, new JsonSerializer<Date>() {
			@Override
			public void serialize(Date value, JsonGenerator jsonGenerator,
					SerializerProvider provider) throws IOException,
					JsonProcessingException {
//				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//				jsonGenerator.writeString(sdf.format(value));
				
				if(null != value){
					jsonGenerator.writeString(String.valueOf(value.getTime()));
				}
			}
		});
		this.setSerializerFactory(factory);
	}
}


xml 配置
    <bean id="mappingJacksonHttpMessageConverter"  
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">  
        <property name="objectMapper" ref="customObjectMapper"/>  
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/html;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>
【spring mvc】多数据源配置 spring mvc Spring+Mybatis 多数据源配置
【注意项】
1. spring-test 3 是根据autowired自动注入;与junit 4.8.1结合使用;
2. @Resource、@Autowired、@Qualifier的注解注入及区别
   @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;
   @Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;
   @Resource注解是又J2EE提供,而@Autowired是由Spring提供,故减少系统对spring的依赖建议使用@Resource的方式;
   @Resource和@Autowired都可以书写标注在字段或者该字段的setter方法之上
3. spring-test 2.5.6 是通过set方法注入,而不是注解,可解决多数据库的问题;
   spring-test 2.5.6 与 junit 3.8.1结合使用;即:
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>2.5.6</version>
		</dependency>



---------------------------------------------------------------------------------------

1、注解式事务声明
@Transactional(value = "insurance", rollbackFor = Exception.class)
@Transactional(value = "isap", rollbackFor = Exception.class)

<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource2" />  
    <qualifier value="insurance" />  
</bean> 
【jeasyui 1.3.6】methods扩展之columnMoving表头拖拽 jeasyui
$.extend($.fn.datagrid.methods,{
    columnMoving: function(jq){
        return jq.each(function(){
            var target = this;
            var cells = $(this).datagrid('getPanel').find('div.datagrid-header td[field]');
            cells.draggable({
                revert:true,
                cursor:'pointer',
                edge:5,
                proxy:function(source){
                    var p = $('<div class="tree-node-proxy tree-dnd-no" style="position:absolute;border:1px solid #ff0000"/>').appendTo('body');
                    p.html($(source).text());
                    p.hide();
                    return p;
                },
                onBeforeDrag:function(e){
                    e.data.startLeft = $(this).offset().left;
                    e.data.startTop = $(this).offset().top;
                },
                onStartDrag: function(){
                    $(this).draggable('proxy').css({
                        left:-10000,
                        top:-10000
                    });
                },
                onDrag:function(e){
                    $(this).draggable('proxy').show().css({
                        left:e.pageX+15,
                        top:e.pageY+15
                    });
                    return false;
                }
            }).droppable({
                accept:'td[field]',
                onDragOver:function(e,source){
                    $(source).draggable('proxy').removeClass('tree-dnd-no').addClass('tree-dnd-yes');
                    $(this).css('border-left','1px solid #ff0000');
                },
                onDragLeave:function(e,source){
                    $(source).draggable('proxy').removeClass('tree-dnd-yes').addClass('tree-dnd-no');
                    $(this).css('border-left',0);
                },
                onDrop:function(e,source){
                    $(this).css('border-left',0);
                    var fromField = $(source).attr('field');
                    var toField = $(this).attr('field');
                    setTimeout(function(){
                        moveField(fromField,toField);
                        $(target).datagrid();
                        $(target).datagrid('columnMoving');
                    },0);
                }
            });
            // move field to another location  
            function moveField(from,to){
                var columns = $(target).datagrid('options').columns;
                var cc = columns[0];
                var c = _remove(from);
                if (c){
                    _insert(to,c);
                }
                
                function _remove(field){
                    for(var i=0; i<cc.length; i++){
                        if (cc[i].field == field){
                            var c = cc[i];
                            cc.splice(i,1);
                            return c;
                        }
                    }
                    return null;
                }
                function _insert(field,c){
                    var newcc = new Array();
                    for(var i=0; i<cc.length; i++){
                        if (cc[i].field == field){
                            newcc.push(c);
                        }
                        newcc.push(cc[i]);
                    }
                    columns[0] = newcc;
                }
            }
        });
    }
});

// 调用示例
$('#tt').datagrid({  
//    url: 'datagrid_data3.json',  
    title: 'DataGrid',  
    width: 700,  
    height: 220,  
    fitColumns: true,  
    nowrap:false,  
    rownumbers:true,  
    showFooter:true,  
    columns:[[
        {field:'itemid',title:'Item ID',width:80},  
        {field:'productid',title:'Product ID',width:120},  
        {field:'listprice',title:'List Price',width:80,align:'right'},  
        {field:'unitcost',title:'Unit Cost',width:80,align:'right'},  
        {field:'attr1',title:'Attribute',width:250, hidden:true},  
        {field:'status',title:'Status',width:60,align:'center'}  
    ]]
}).datagrid("columnMoving");
【jeasyui 1.3.6】methods扩展之showHideFieldsMenu表头右击字段显隐菜单 jeasyui
$.extend($.fn.datagrid.methods,{
    showHideFieldsMenu : function(jq) {
        var menuID = jq.attr("id") + "_context_menu";
        var $contextMenu = $("#" + menuID);
        if ($contextMenu.length > 0) {
            return;
        }
        var fieldArray = jq.datagrid('getColumnFields');
        if (null == fieldArray || fieldArray == undefined) {
            return;
        }
        $contextMenu = $('<div class="easyui-menu" style="width:100px;"></div>').appendTo('body');
        $contextMenu.attr("id", menuID);
        var $fieldHTML = $('<div><span>显示/隐藏列</span></div>').appendTo($contextMenu);
        var $filedsList = $('<div class="menu-content" style="text-align:left;padding:10px"/>').appendTo($fieldHTML);
        for (var i = 0; i < fieldArray.length; i++) {
            var $checkBox = $('<input type="checkbox">');
            var $label = $('<span>' + jq.datagrid('getColumnOption', fieldArray[i]).title + '</span>');
            var $menuItem = $('<div style="padding-left:-2em;"/>').append($checkBox).append($label);
            if (jq.datagrid('getColumnOption', fieldArray[i]).hidden == true) {
                $checkBox.attr('checked', true);
            }
            $checkBox.bind('click', {
                $jq : jq,
                field : fieldArray[i]
            }, function(ev) {
                var flag = ev.data.$jq.datagrid('getColumnOption', ev.data.field).hidden;
                $(this).attr('checked', !flag);
                var action = flag ? "showColumn" : "hideColumn";
                ev.data.$jq.datagrid(action, ev.data.field);
            });
            $label.bind('mouseover', function() {
                $(this).css('cursor', 'pointer');
            }).bind('mouseleft', function() {
                $(this).css('cursor', 'none');
            }).bind('click', {$jq : jq,
                    checkbox : $checkBox,
                    field : fieldArray[i]
                }, function(ev) {
                    var flag = ev.data.$jq.datagrid('getColumnOption', ev.data.field).hidden;
                    ev.data.checkbox.attr('checked', !flag);
                    var action = flag ? "showColumn" : "hideColumn";
                    ev.data.$jq.datagrid(action, ev.data.field);
            });
            $filedsList.append($menuItem);
        }
        $.parser.parse();
        jq.datagrid({
            onHeaderContextMenu : function(e, field) {
                e.preventDefault();
                $contextMenu.menu('show', {
                    left : event.pageX,
                    top : event.pageY
                });
            }
        });
    }
});


// 使用
$('#tt').datagrid({  
//    url: 'datagrid_data3.json',  
    title: 'DataGrid',  
    width: 700,  
    height: 220,  
    fitColumns: true,  
    nowrap:false,  
    rownumbers:true,  
    showFooter:true,  
    columns:[[
        {field:'itemid',title:'Item ID',width:80},  
        {field:'productid',title:'Product ID',width:120},  
        {field:'listprice',title:'List Price',width:80,align:'right'},  
        {field:'unitcost',title:'Unit Cost',width:80,align:'right'},  
        {field:'attr1',title:'Attribute',width:250, hidden:true},  
        {field:'status',title:'Status',width:60,align:'center'}  
    ]]
}).datagrid("showHideFieldsMenu");
【保险】投连险 保险 初始费用占大头 解读投连险的费用
      投连险的一个特点是费用透明,但收费项目较多。目前市场上的投连险产品层出不穷,但在收费上仍存在个体差异,在投保前,投保人不妨对投连险的7项费用做个梳理。
      从珠海友邦保险了解到,根据2007年10月1日开始实施的《投资连结保险精算规定》(以下简称精算规定),投连险收取7项费用:初始费用、买入卖出差价、死亡风险保险费、保单管理费、资产管理费、手续费(账户转换、部分领取时)和退保费用。

      初始费用占大头
      初始费用是投保人所缴的保费在进入投资账户前扣除的那部分费用。
      根据缴费方式的不同,趸缴型和期缴型扣除的比例也有区别。如果购买的是趸缴型产品,一般保险公司会根据投入资金的多少,来设定不同的扣除比例,投入越多,初始费用越低,比如瑞泰安裕之选(趸缴型)规定,缴费2万~10万元的部分收3%,10万~50万元的部分收2%,50万元以上收1.5%。也有一些保险公司不区分投入资金的高低,规定单一的初始费用比例。期缴型产品缴费时虽然分为年缴、季缴和月缴,但是初始费用的计费标准却都是按照年度来计算的,同一年内,收费比例不变。

      期缴形式的投连险,对基本保费和额外保费部分所能收取的初始费用差别较大。基本保费不能高于保险金额(指保单签发时的死亡保险金额)除以20,并不得超过人民币6000元;如果单期所缴保费超出上面的数额,超出部分就要算作额外保费。按照精算规定,基本保费所能收取的初始费用比例首年可高达50%,而额外保费初始费用上限仅为5%。比如张先生投保某投连险(期缴型),保额10万元,首年投入1万元。收取初始费用时,基本保费部分(100000元÷20=5000元)按50%的比例收取2500元,额外保费部分(10000元-5000元=5000元)按5%的比例收取250元。
【保险】万能险 保险
万能险
    由于万能险集保障、储蓄与理财功能于一体,具有缴费灵活、存取方便、利率保底、保额自主等特点,所以通俗地称为“万能”。

万能险结算公式:riskprem=riskamnt*premrate/1000*n/365

死亡风险保额:指有效保额减去保单账户价值。其中有效保额是指被保险人因疾病和意外等身故时,保险公司支付的死亡保险金额。
风险保费:根据风险保额所得到的保费。
初始费用:即保险费进入万能账户之前扣除的费用。

万能结算公式
风险保额:riskamnt
主险保额:amnt
附加险保额:famnt
现价:av
风险保费:主险gl,附加重疾险kf,轻症重疾mc
费率:rate

1.AULA :
  riskamnt=max(amnt,av*1.05)-av
  gl=riskamnt*rate*日差/1000/365
  附加险 ADDC
  riskamnt=max(famnt,av*1.05)-av*( max(famnt,av*1.05)/ max(amnt,av*1.05)   )
  kf =riskamnt*rate*日差/1000/365
2.AULC附加险ADDl多一个轻症重疾mc责任
  mc=附加险基本保额*0.2*rate*日差/1000/365
3.AULB:直接使用保额
  gl=amnt*rate*日差/1000/365   ;
  附加险 ADDE kf =famnt*rate*日差/1000/365

4.BULA,BULB,BULC 只收取管理费,而且是一个固定值
10        12       前5个保单年度12,从第6个保单年度开始6.





		
期交产品
   保单年度	初始费用上限
   第一年	50%
   第二年	25%
   第三年	15%
   第四、五年	10%
   以后各年	5%
   追加部分不得高于5%


趸交产品
	保险费		                         初始费用上限
   人民币50000元及以下部分		10%
   人民币50000元以上部分		5%
	趸交保险费保单追加保险费的初始费用比例的上限为5%。


万能险相关的表
--万能险费率表
select * from riskprem_aula;
--万能险初始费用表
select * from initprem_aula;
--万能险结算利率表
select * from lminsuaccrate;
--万能险账户表
select * from lcinsureacc;
--万能险账户子表
select * from lcinsureaccclass;
--万能险结算轨迹表
select * from lcinsureacctrace;
--万能险保额分层表
select * from lyamntlayer;
--万能扣费表
select  * from lcinsureaccfee;
--万能扣费子账户表
select * from  lcinsureaccclassfee;
--扣费轨迹表
select *  from lcinsureaccfeetrace;
--万能险投资计划表 >6000部分的分配计划
select * from lcperinvestplan;
--账户定义表
select * from lmriskinsuacc;
--险种层变化的轨迹表
select * from lppolchangetrace;
--账户轨迹表
select * from lpaccchangetrace;
--账户定义表
select * from lmrisktoacc;



【oracle】常用脚本 oracle
使用rename关键字来实现字段名的修改:alter table 表名 rename column旧的字段名 to 新的字段名名;
使用modify关键字来实现对数据类型的修改:alter table 表名 modify 字段名 数据类型;


-- 增加字段
alter table temp_user add sysdatestr varchar(40);
alter table temp_user add (sysdatestr varchar(40) default 'tsfdwe');

-- 移除字段
alter table temp_user drop column sysdatestr;

Oracle修改字段类型方法总结: http://blog.csdn.net/gdjlc/article/details/23762549
-- 假设字段数据为空,则不管改为什么字段类型,可以直接执行
alter table temp_user modify (sysdatestr varchar2(20));
【oracle】提取字段中的数字 oracle
select TRIM(TRANSLATE('<ROOT><MPAGE32ID>20673</MP',
         trim(
             TRANSLATE('<ROOT><MPAGE32ID>20673</MP', '0123456789', ' ')
         ),
       ' '))
  from dual
结果:3220673

内层的TRANSLATE将数字替换成空格
外层的TRANSLATE将数字之外的替换成空格,剩下的就是数字了

注意:全角数字也会被过滤掉

如:
select TRIM(TRANSLATE('<ROOT><MPAGE32ID1526>20673</MP',
         trim(
             TRANSLATE('<ROOT><MPAGE32ID1526>20673</MP', '0123456789', ' ')
         ),
       ' '))
  from dual
结果:3220673


电话号码字段非空,且仅包含数字的:
select *
  from member_user t
 where t.user_mobile is not null
   and translate(t.user_mobile, '0123456789', '') is null;

【oracle】全角转换成半角 oracle
把一些全角数字转换成半角的数据,可利用oracle的 to_single_byte 这个函数就可以解决问题 比如:
UPDATE ARCHIVES_IN T1
          SET T1.IN_CODE = (SELECT TO_SINGLE_BYTE(T2.IN_CODE)
                              FROM ARCHIVES_IN T2
                             WHERE T1.IN_ID = T2.IN_ID)
        WHERE NOT REGEXP_LIKE(T1.IN_CODE,
                              '^(-{0,1}+{0,1})[0-9]+(.{0,1}[0-9]+)
但是有个问题,如果这个in_code字段中只有一个全角数字的话,需要手动的去修改一下。
【oracle】正则表达式 oracle oracle正则表达式
在oracle里正则表达式有四个函数可用,分别是regexp_like、regexp_substr、regexp_instr 和regexp_replace。

REGEXP_LIKE:比较一个字符串是否与正则表达式匹配 
(srcstr, pattern [, match_option]) 

REGEXP_INSTR:在字符串中查找正则表达式,并且返回匹配的位置 
(srcstr, pattern [, position [, occurrence [, return_option [, match_option]]]]) 

REGEXP_SUBSTR:返回与正则表达式匹配的子字符串 
(srcstr, pattern [, position [, occurrence [, match_option]]]) 

REGEXP_REPLACE:搜索并且替换匹配的正则表达式 
(srcstr, pattern [, replacestr [, position [, occurrence [, match_option]]]]) 


1. select * from member_user t where regexp_like(t.user_mobile, '^1[[:digit:]]{10}');
^代表开始,
*表示出现0次或多次,
+表示出现1次或多次,
[:digit:]代表0-9的纯数字
(还有$代表以什么结尾,如果是[[:digit:]]+$代表以数字结尾)



select * from test_table where regexp_like(name,'[[:alpha:]]')
这里是表示查询匹配任意字母,也包括中文字


select * from test_table where regexp_like(name,'[[:alnum:]]')
这里是表示查询匹配任意字母和数字


select * from test_table where regexp_like(name,'[[:digit:]]')
这里是表示查询匹配任意数字
 
 
Select * from test_table Where regexp_like(name,’of’,’i’)
这里就是of不区分大小写
 
 
Select * from test_table Where regexp_like(name,’^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$’)
这样我们可以查询是不是ip格式





REGEXP_SUBSTR与SUBSTR函数相同,返回截取的子字符串
REGEXP_SUBSTR(srcstr, pattern [, position [, occurrence [, match_option]]])
注:
srcstr 源字符串
pattern 正则表达式样式
position 开始匹配字符位置
occurrence 匹配出现次数
match_option 匹配选项(区分大小写)

SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+') FROM dual;
Output: 1PSN
[[:alnum:]]+ 表示匹配1个或者多个字母或数字字符
 
 
SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+', 1, 2) FROM dual;
Output: 231
与上面一个例子相比,多了两个参数
1 表示从源字符串的第一个字符开始查找匹配
2 表示第2次匹配到的字符串(默认值是“1”,如上例)
【maven】安装JAR到本地Maven仓库 maven
mvn install:install-file -Dfile=kaptcha-2.3.2.jar -Dpackaging=jar -DgroupId=com.google.code -DartifactId=kaptcha -Dversion=2.3.2

-Dfile:本地JAR文件位置;
【spring mvc】CrossDomainView spring mvc
/**
 * 
 */

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.view.AbstractView;

import com.google.gson.Gson;

/**
 * 跨域请求视图
 * @author c1panx
 * 2015-01-11  下午2:16:40
 */
public class CrossDomainView extends AbstractView {
	
	public static final String DEFAULT_CONTENT_TYPE = "text/plain;charset=UTF-8";
	public static final String DEFAULT_CHAR_ENCODING = "UTF-8";
	
	private String encodeing = DEFAULT_CHAR_ENCODING;

	private Object jsonData = null;
	private Map<String, Object> _jsonDataMap = new HashMap<String, Object>();

	private Set<String> renderedAttributes;

	public CrossDomainView() {
		setContentType(DEFAULT_CONTENT_TYPE);
	}

	public CrossDomainView(Object data) {
		setContentType(DEFAULT_CONTENT_TYPE);
		this.jsonData = data;
	}

	public void setEncodeing(String encodeing) {
		this.encodeing = encodeing;
	}

	@Override
	protected void renderMergedOutputModel(Map<String, Object> model,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// 回调函数名
		String jsoncallback = request.getParameter("jsoncallback");
		
		String result = "";
		if (jsonData != null) {
			result = new Gson().toJson(jsonData);
		} else if (!_jsonDataMap.isEmpty()) {
			result = new Gson().toJson(_jsonDataMap);
		} else {
			model = filterModel(model);
			result = new Gson().toJson(model);
		}
		
		// 若未传递jsoncallback参数,则返回普通的JSON串
		if (StringUtils.isBlank(jsoncallback) == false) {
			result = jsoncallback + "(" + result + ")";
		}
		logger.info("CrossDomainView jsoncallback:" + jsoncallback);
		logger.info("CrossDomainView result:" + result);

		response.setCharacterEncoding(encodeing);
		response.setContentType(getContentType());
		PrintWriter out = null;
		try {
			out = response.getWriter();
			out.print(result);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			if (null != out) {
				out.flush();
				out.close();
			}
		}
	}

	/**
	 * Filters out undesired attributes from the given model.
	 * <p>
	 * Default implementation removes {@link BindingResult} instances and
	 * entries not included in the {@link #setRenderedAttributes(Set)
	 * renderedAttributes} property.
	 */
	protected Map<String, Object> filterModel(Map<String, Object> model) {
		Map<String, Object> result = new HashMap<String, Object>(model.size());
		Set<String> renderedAttributes = !CollectionUtils.isEmpty(this.renderedAttributes) ? this.renderedAttributes
				: model.keySet();
		for (Map.Entry<String, Object> entry : model.entrySet()) {
			if (!(entry.getValue() instanceof BindingResult)
					&& renderedAttributes.contains(entry.getKey())) {
				result.put(entry.getKey(), entry.getValue());
			}
		}

		return result;

	}

	public void setJsonData(Object jsonData) {
		this.jsonData = jsonData;
	}

	public static CrossDomainView returnJson(Object jsonData) {
		CrossDomainView jsonView = new CrossDomainView();
		jsonView.setJsonData(jsonData);
		return jsonView;
	}

	public CrossDomainView put(String key, Object value) {
		_jsonDataMap.put(key, value);
		return this;
	}
}




//跨域请求示例
$.ajax({
	url:t_json.url + "?jsoncallback=?",
	data: {mobile:t_json.$mobile.val(), type:t_json.type},
	dataType: "jsonp",
//	type: "POST",
	crossDomain: true,
	beforeSend: function(XMLHttpRequest){},
	success: function(data, textStatus){
		
	},
	error: function(XMLHttpRequest, textStatus, errorThrown){
		
	}
});
【spring mvc】kaptcha.ValidateCodeController spring mvc
/**
 * 
 */
package com.cignacmb.member.center.controller;

import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.google.code.kaptcha.Producer;

/**
 * 图片动态码
 * @author c1panx
 *  2015年2月5日 下午4:57:01
 */
@Controller
public class ValidateCodeController {
	
	private final Logger logger = Logger.getLogger(this.getClass());

	@Autowired
	private Producer captchaProducer = null;
	
	@RequestMapping("/validate-code.xhtml")
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setDateHeader("Expires", 0);
		// Set standard HTTP/1.1 no-cache headers.
		response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
		// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
		response.addHeader("Cache-Control", "post-check=0, pre-check=0");
		// Set standard HTTP/1.0 no-cache header.
		response.setHeader("Pragma", "no-cache");
		// return a jpeg
		response.setContentType("image/jpeg");
		// create the text for the image
		String capText = captchaProducer.createText();
		// store the text in the session
		request.getSession().setAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY,
				capText);
		// create the image with the text
		BufferedImage bi = captchaProducer.createImage(capText);
		
		ServletOutputStream out = null;
		try {
			out = response.getOutputStream();
			// write the data out
			ImageIO.write(bi, "jpg", out);
			out.flush();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			if (null != out) {
				out.close();
			}
		}
		return null;
	}
}
【spring mvc】kaptcha.MemberWordRenderer spring mvc
/**
 * 
 */
package com.cignacmb.member.center.validatecode;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.util.Random;

import com.google.code.kaptcha.text.WordRenderer;
import com.google.code.kaptcha.util.Configurable;

/**
 * <a href='http://fancyboy2050.iteye.com/blog/1146763'>Kaptcha使用</a>
 * @author c1panx
 *  2015年2月6日 上午9:45:25
 */
public class MemberWordRenderer extends Configurable implements WordRenderer {

	public MemberWordRenderer() {
	}  
	
	@Override
	public BufferedImage renderWord(String word, int width, int height) {
		int fontSize = getConfig().getTextProducerFontSize();
		// 这个地方我们自定义了验证码文本字符样式,虽然是可以配置的,但是字体展示都粗体,我们希望不是粗体就只有自定义这个渲染类了
		String paramName = "kaptcha.textproducer.font.names";
		String paramValue = (String) getConfig().getProperties().get(paramName);
		String fontNames[] = paramValue.split(",");
		Font fonts[] = new Font[fontNames.length];
		for (int i = 0; i < fontNames.length; i++) {
//			fonts[i] = new Font(fontNames[i], Font.ITALIC, fontSize);
			fonts[i] = new Font(fontNames[i], Font.BOLD + Font.ITALIC, fontSize);
		}

		java.awt.Color color = getConfig().getTextProducerFontColor();
		int charSpace = getConfig().getTextProducerCharSpace();
		BufferedImage image = new BufferedImage(width, height, 2);
		Graphics2D g2D = image.createGraphics();

		g2D.setColor(color);
		RenderingHints hints = new RenderingHints(
				RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		hints.add(new RenderingHints(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY));

		g2D.setRenderingHints(hints);
		java.awt.font.FontRenderContext frc = g2D.getFontRenderContext();
		Random random = new Random();
		int startPosY = (height - fontSize) / 5 + fontSize;
		char wordChars[] = word.toCharArray();
		Font chosenFonts[] = new Font[wordChars.length];
		int charWidths[] = new int[wordChars.length];
		int widthNeeded = 0;
		for (int i = 0; i < wordChars.length; i++) {
			chosenFonts[i] = fonts[random.nextInt(fonts.length)];
			char charToDraw[] = { wordChars[i] };
			GlyphVector gv = chosenFonts[i].createGlyphVector(frc, charToDraw);
			charWidths[i] = (int) gv.getVisualBounds().getWidth();
			if (i > 0)
				widthNeeded += 2;
			widthNeeded += charWidths[i];
		}

		int startPosX = (width - widthNeeded) / 2;
		for (int i = 0; i < wordChars.length; i++) {
			g2D.setFont(chosenFonts[i]);
			char charToDraw[] = { wordChars[i] };
			g2D.drawChars(charToDraw, 0, charToDraw.length, startPosX,
					startPosY);
			startPosX = startPosX + charWidths[i] + charSpace;
		}

		return image;
	}

}
【spring mvc】kaptcha.MemberWaterRipple spring mvc
/**
 * 
 */
package com.cignacmb.member.center.validatecode;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import com.google.code.kaptcha.NoiseProducer;
import com.google.code.kaptcha.impl.WaterRipple;
import com.jhlabs.image.RippleFilter;
import com.jhlabs.image.TransformFilter;
import com.jhlabs.image.WaterFilter;

/**
 * @author c1panx
 *  2015年2月9日 下午3:11:07
 */
public class MemberWaterRipple extends WaterRipple {

	public BufferedImage getDistortedImage(BufferedImage baseImage) {
		// baseImage,无噪点文字图片
		
		NoiseProducer noiseProducer = getConfig().getNoiseImpl();
		BufferedImage distortedImage = new BufferedImage(baseImage.getWidth(),
				baseImage.getHeight(), BufferedImage.TYPE_INT_ARGB);

		Graphics2D graphics = (Graphics2D) distortedImage.getGraphics();

		// http://javadox.com/com.jhlabs/filters/2.0.235-1/com/jhlabs/image/RippleFilter.html
		RippleFilter rippleFilter = new RippleFilter();
		// RippleFilter.SINE 正弦波的涟漪
		rippleFilter.setWaveType(RippleFilter.SINE);
		// 在 X 方向设置的波动幅度。
		rippleFilter.setXAmplitude(2.6f);
		rippleFilter.setYAmplitude(1.7f);
		// 在 X 方向设置波长的波纹。
		rippleFilter.setXWavelength(15);
		rippleFilter.setYWavelength(5);
		rippleFilter.setEdgeAction(TransformFilter.NEAREST_NEIGHBOUR);

		// http://www.2cto.com/kf/201302/188441.html
		WaterFilter waterFilter = new WaterFilter();
		waterFilter.setAmplitude(0.5f);	// 振幅
		waterFilter.setPhase(10);	// 相位
		waterFilter.setWavelength(2);	// 波长

		// baseImage,无噪点文字图片
		BufferedImage effectImage = baseImage;
		// waterFilter.filter 文字上添加噪点
//		BufferedImage effectImage = waterFilter.filter(baseImage, null);
		effectImage = rippleFilter.filter(effectImage, null);

		graphics.drawImage(effectImage, 0, 0, null, null);

		graphics.dispose();

		// 干扰线
		noiseProducer.makeNoise(distortedImage, .1f, .1f, .25f, .25f);
		noiseProducer.makeNoise(distortedImage, .1f, .25f, .5f, .9f);
		return distortedImage;
	}
}
【spring mvc】kaptcha.MemberNoise spring mvc
/**
 * 
 */
package com.cignacmb.member.center.validatecode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Random;

import com.google.code.kaptcha.impl.DefaultNoise;


/**
 * @author c1panx
 *  2015年2月5日 下午5:26:55
 */
public class MemberNoise extends DefaultNoise {

	public void makeNoise(BufferedImage image, float factorOne,
			float factorTwo, float factorThree, float factorFour) {
		Color color = getConfig().getNoiseColor();

		// image size
		int width = image.getWidth();
		int height = image.getHeight();

		// the points where the line changes the stroke and direction
		Point2D[] pts = null;
		Random rand = new Random();

		// the curve from where the points are taken
		CubicCurve2D cc = new CubicCurve2D.Float(width * factorOne, height
				* rand.nextFloat(), width * factorTwo, height
				* rand.nextFloat(), width * factorThree, height
				* rand.nextFloat(), width * factorFour, height
				* rand.nextFloat());

		// creates an iterator to define the boundary of the flattened curve
		PathIterator pi = cc.getPathIterator(null, 2);
		Point2D tmp[] = new Point2D[200];
		int i = 0;

		// while pi is iterating the curve, adds points to tmp array
		while (!pi.isDone()) {
			float[] coords = new float[6];
			switch (pi.currentSegment(coords)) {
			case PathIterator.SEG_MOVETO:
			case PathIterator.SEG_LINETO:
				tmp[i] = new Point2D.Float(coords[0], coords[1]);
			}
			i++;
			pi.next();
		}

		pts = new Point2D[i];
		System.arraycopy(tmp, 0, pts, 0, i);

		Graphics2D graph = (Graphics2D) image.getGraphics();
		graph.setRenderingHints(new RenderingHints(
				RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON));

		graph.setColor(color);

		// for the maximum 3 point change the stroke and direction
		for (i = 0; i < pts.length - 1; i++) {
			if (i < 3)
				graph.setStroke(new BasicStroke(0.9f * (4 - i)));
			graph.drawLine((int) pts[i].getX(), (int) pts[i].getY(),
					(int) pts[i + 1].getX(), (int) pts[i + 1].getY());
		}

		graph.dispose();
	}
	
}
Global site tag (gtag.js) - Google Analytics