⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 treepos.js

📁 流程图的制作
💻 JS
字号:
// 将节点自动排列
/*实现目标:
	1 将所有的节点自动排序
	2 解决连线的重叠问题
分析:
	1 设置每个节点的parentNode和childNode
	2 找到一个parentNode 为null的做为树根设坐标(row=0,0)
	3 判断childNode的节点数为每个子节点设置坐标(row+1,col),
		3.1 子节点的位置(row+1,fa.col+(i-(total/2)))
	4 如果坐标位置被占用,那么修改父节点坐标,使其col++ ,重复3
		4.1 判断占用关键是看col因为是自顶到下的,所以row不会重复
	5 设置完这个节点的子节点以后,设置这个节点为已操作already=1
	6 查找一个父节点不为空already=0的节点,重复3
	7 重复2
	8 完成节点的坐标设置,进行位移

	9 建立两点之间的连线
	10 写连线的名称和备注(选)
	11 判断如果两个连线的midPoint重叠,就左右移开
	12 如果连线的midPoint和node重叠,就移开
	
	author:shennan amushen@yahoo.com.cn
*/

var treeRow=0;		//记录当前行数
var already=new Array();	//记录是否已经操作
var treeNodes=null;		//这个树的所有节点,自顶至下,自左到右
var i_tn;					//treeNodes的循环变量
var minest=999;				//横坐标最小值,在位移的时候使用
var M_LEFT=120;				//坐标放大的倍数
var M_TOP=60;
var isNoRoot=true;		//如果出现环,没有根节点

function initPosing(){
	treeRow=0;
	minest=999;
	isNoRoot=true;
	for(var i=0;nodes!=null&&i<nodes.length;i++)
		already[i]=0;
}

function setNodeRelation(){
	//设置每个节点的父子节点
	if(nodes==null||nodes.length<1)return;
	var i;
	for(i=0;i<nodes.length;i++){
		if(nodes[i]!=null){
			nodes[i].parentNode=new Array();
			nodes[i].childNode=new Array();
		}
	}
	if(lines==null||lines.length<1)return;
	for(i=0;i<lines.length;i++){
		if(lines[i]==null)continue;
		nodes[lines[i].source].childNode.push(lines[i].destination);
		nodes[lines[i].destination].parentNode.push(lines[i].source);		
	}
}

function _getRoot(){
	var i;
	for(i=0;nodes!=null&&i<nodes.length;i++){
		if(nodes[i]==null)continue;
		if(already[i]==1)continue;
		if(nodes[i].parentNode.length>0)continue;		
		isNoRoot=false;
		return i;
	}
	if(isNoRoot){//出现环就返回第一个节点
		isNoRoot=false;
		for(i=0;nodes!=null&&i<nodes.length;i++){
			if(nodes[i]!=null){		
				return i;
			}
		}
	}
	return null;
}

function _setPosOfTree(root){
	//设置treeNodes数组
	treeNodes=new Array();
	treeNodes.push(root);
	var j,flag;
	i_tn=0;
	var k=0;
	while(k<treeNodes.length){
		for(var i=0;i<nodes[treeNodes[k]].childNode.length;i++){
			if(already[nodes[treeNodes[k]].childNode[i]]==1)continue;
			//必须保证这个点没有出现过,防止出现环路
			flag=true;
			for(j=0;j<treeNodes.length;j++)
				if(treeNodes[j]==nodes[treeNodes[k]].childNode[i]){
					flag=false;
					break;
				}
			if(flag)treeNodes.push(nodes[treeNodes[k]].childNode[i]);	
		}
		k++;
	}
}

function _getNextRoot(){
//下一个要处理的节点
	if(i_tn==treeNodes.length-1)return null;
	i_tn++;
	return treeNodes[i_tn];
}

function treePosing(){
	//主控函数	
	var root=null;
	var i;
	var maxCol=-999;	//下一行的最大left位置
	var total;//孩子总数
	
	root=_getRoot();
	if(root!=null){
		nodes[root].position.left=0;	//根始终在0位置		
		nodes[root].position.top=treeRow;//自顶向下
		_setPosOfTree(root);	//为一个树设置标号,自顶向下,自左向右标
	}
	treeRow++;	//开始第一层
	while(root!=null){
		total=nodes[root].childNode.length;
		//首先确定root的位置是否需要调整
		if(maxCol!=-999){
			//可能不是这层的第一个,有可能需要调整位置
			nodes[root].position.left=maxCol+1+parseInt(total/2);
		}
		//为这个点的孩子节点设置位置
		for(i=0;i<nodes[root].childNode.length;i++){
			if(already[nodes[root].childNode[i]]==1)continue;//如果子节点已经展开,那么就不再设置
			
			nodes[nodes[root].childNode[i]].position.top=treeRow;
			nodes[nodes[root].childNode[i]].position.left=nodes[root].position.left+(i-parseInt(total/2));
//			下面的三行代码可以让布局更对称,但是太占空间了,所以删除
//			if(total%2==0)
//				if(i-parseInt(total/2)>=0)
//					nodes[nodes[root].childNode[i]].position.left++;
					
			maxCol=nodes[nodes[root].childNode[i]].position.left;	
			if(maxCol<minest)minest=maxCol;
		}
		already[root]=1;
		root=_getNextRoot();
		if(root!=null&&nodes[root].position.top==treeRow){
			//换行	
			treeRow++;
			maxCol=-999;
		}
		
		if(root==null){
		//开始下一棵树	
			treeRow++;
			root=_getRoot();
			if(root!=null){
				nodes[root].position.left=0;	//根始终在0位置		
				nodes[root].position.top=treeRow;//自顶向下
				_setPosOfTree(root);	//为一个树设置标号,自顶向下,自左向右标
				treeRow++;
				
			}
		}
		
	}//end of while(root)

	//开始为每个节点设置准确坐标
	_moveAllToRight();
	//坐标放大
	_magnifyPos();
	//创建节点
	_createAllTreeNode();
	//创建节点间的连线
	_createAllTreeLine();	
}
function _moveAllToRight(){
	if(minest==999)minest=0;
	for(var i=0;nodes!=null&&i<nodes.length;i++)
		if(nodes[i]!=null){
			nodes[i].position.left-=minest-1;
		}
}

function _magnifyPos(){
	for(var i=0;nodes!=null&&i<nodes.length;i++)
		if(nodes[i]!=null){
			nodes[i].position.left*=M_LEFT;
			nodes[i].position.top*=M_TOP;
		}
	
}
function _createAllTreeNode(){
	var i;
	for(i=0;nodes!=null&&i<nodes.length;i++)
		if(nodes[i]!=null){
			createNode(nodes[i]);
			canDragOfNode(i);
		}
}

function _createAllTreeLine(){
	lines=null;
	lines=new Array();
	var i,j;
	for(i=0;nodes!=null&&i<nodes.length;i++)
		if(nodes[i]!=null){
			for(j=0;j<nodes[i].childNode.length;j++){
				var line=new Line();
				line.source=i;
				line.destination=nodes[i].childNode[j];
				line.index=lines.length;
				line.name="";
				line=getLineSDPoint(line);
				lines.push(line);				
			}
		}
	//避免连线重叠,只判断mid
	_avoidLineOverlap();
	for(i=0;lines!=null&&i<lines.length;i++)
		if(lines[i]!=null){
			createLine(lines[i]);
			canDragOfLine(i);
		}
}

function _avoidLineOverlap(){
	if(lines==null||lines.length<1)return;
	var i,j,d;
	for(i=0;i<lines.length;i++)
		if(lines[i]!=null){
			for(j=i+1;j<lines.length;j++)
				if(lines[j]!=null){
					//计算两点距离
					d=Math.sqrt(Math.pow(lines[i].midPoint.top-lines[j].midPoint.top,2)+Math.pow(lines[i].midPoint.left-lines[j].midPoint.left,2));
					if(d<10){
						lines[j].midPoint.left=lines[i].midPoint.left+10;
						lines[j].midPoint.top=lines[i].midPoint.top+10;
						
					}
				}			
		}	
}

function _initNodesFromExt(/*nodeDatas*/nd){
//将外部数据转换成系统格式的数据
	var i,j;
	nodes=null;
	nodes=new Array();
	for(i=0;i<nd.length;i++){
		var node=new Node();
		node.index=nd[i].index;
		node.name=nd[i].name;
		node.type=typeToNum(nd[i].type);
		node.position=new Position();
		node.childNode=new Array();
		node.parentNode=new Array();
		if(nd[i].children!=null)node.childNode=nd[i].children;
//		alert(node.index+","+node.name+",child:"+node.childNode);		
		nodes[node.index]=node;
	}
	//设置父节点
	for(i=0;i<nodes.length;i++)
		if(nodes[i]!=null){			
			for(j=0;j<nodes[i].childNode.length;j++){	
				try{
					nodes[nodes[i].childNode[j]].parentNode.push(i);
				}catch(e){}			
			}
		}	
		nd=null;
}
/////////////////

function _testShow(){	
	var str="";
	for(var i=0;i<nodes.length;i++)
		if(nodes[i]!=null)
			str+=nodes[i].name+":"+nodes[i].position+"<br>";
	$('_test').innerHTML=str;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -