D3.js--动态树

html:

<div title="关联性配置">
	<div id="relevanceRule" class="relevance-rule">
		<form class="relevance-form" id="relevanceForm">
			<div class="col100" ><a onclick="importRelevance();" href="#" class="linkbutton" data-options="iconCls:'icon-import'">导入</a></div>
			<div class="clr"></div>
		</form>
		<div id="relevanceRuleConfig"></div>
	</div>
</div>

<div class="menu" id="menu">
	<div onclick="addSubTable()" data-options="iconCls:'icon-add'">添加子表</div>
	<div onclick="editPropertity()" data-options="iconCls:'icon-edit'">编辑表属性</div>
	<div onclick="removeTable()" data-options="iconCls:'icon-remove'">删除表</div>
</div>
	
<div id="tablePropertity" class="dialog">
	<form id="propertityForm">
		<div class="col75">表名:</div>
		<div class="col175"><input id="relevanceTableName" type="text"></div>
		<div class="col75">主表ID:</div>
		<div class="col175"><input id="mainTableId" type="text"></div>
		<div class="col75">关联字段:</div>
		<div class="col175"><input id="relevanceField" type="text"></div>
		<div class="clr"></div>
	</form>
</div>
<script type="text/javascript" src="<%=request.getContextPath()%>/jsproject/dqms/rulemanageconfig/relevance.js"></script>


js:

//初始化属性弹出窗
$("#tablePropertity").dialog({
	title: '编辑表属性',    
	width: 300,    
	height: 200,    
	closed: true,    
	cache: false,        
	modal: true,
	buttons:[{
		text:'保存',
		handler:function(){
			var relevanceTableName = $("#relevanceTableName").val();
			var mainTableId = $("#mainTableId").val();
			var relevanceField = $("#relevanceField").val();
			currentNode.name = relevanceTableName;
			currentNode.id = relevanceField;
			var rootNode = currentNode;
			while(rootNode.parent){
				rootNode = rootNode.parent;
			}
			drawTree(rootNode);
			$("#tablePropertity").dialog("close");
		}
	},{
		text:'关闭',
		handler:function(){
			$("#tablePropertity").dialog("close");
		}

	}]
});

relevance.js

var height = 500;//定义全局变量
var width = 1147;

//定义当前操作节点对象
var currentNode = null;

//定义布局偏移量
var leftW = 50,topH = 80;

//定义布局大小
var treeWidth = width-leftW;
var treeHeight = height-topH;

//绘制画布
var svg = d3.select("#relevanceRuleConfig").append("svg")
		.attr("width", treeWidth)
		.attr("height", treeHeight)
		.append("g")
		.attr("transform", "translate(80,0)");//定义偏移量

//定义D3树布局范围
var tree = d3.layout.tree()
	.size([treeHeight, treeWidth-180])//注意D3布局跟svg坐标系无关,size(高,宽)
	.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2); });//设置相隔节点的间距,a、b节点相隔

//定义连线过渡器
var diagonal = d3.svg.diagonal()
	.projection(function(d) { return [d.y, d.x]; });//设置连线点的变换器

$(function(){
	initTree();
	
	//加载数据
	d3.json($WEB_ROOT_PATH+"/jsproject/dqms/rulemanageconfig/data.json", function(error, root) {
		drawTree(root);
	});
})

function drawTree(sourceData){
	if(!sourceData){
		console.log("无数据可显示!");
		return;
	}
	
	var nodes = tree.nodes(sourceData);	//获取所有节点信息
	var links = tree.links(nodes);	//获取节点的连线信息集合
	
	//记录当前节点的位置
	nodes.forEach(function(d) {
			d.x0 = d.x;
			d.y0 = d.y;
		});
	 
    tree = tree.size([treeHeight, treeWidth-180]);
    
	//渲染节点
	drawTreeNode(sourceData,nodes);
	//渲染连线
	drawLink(sourceData,links);
	
	
}

//重绘节点
function drawTreeNode(sourceData,nodes){
	
	//获取修改前的节点,当节点改变时新节点需与旧节点的id相对应
	var node = svg.selectAll(".node")
	  		.data(nodes,function(d) { return d.id });
	
	//绘制新增的节点对象
	var nodeEnter = node.enter()
			.append("g")
			.attr("class", "node")
			.attr("transform", function(d) { return "translate(" + sourceData.y0 + "," + sourceData.x0 + ")"; })
			.on("dblclick",function(d,index){
					currentNode = d;
					editPropertity();
			})
			.on("contextmenu",function(d,index){
				d3.event.preventDefault();
				currentNode = d;
				$('#menu').menu('show',{
					left: d3.event.pageX,
					top: d3.event.pageY
				});
			});
	
	//为新增的节点对象添加图形
	nodeEnter.append("circle").attr("r", 4.5);
	
	//为新增的节点对像添加文字
	nodeEnter.append("text")		//添加节点显示文本
	  		 .attr("dx", function(d) { return d.children ? -8 : 8; })//定义文本显示x轴偏移量
	  		 .attr("dy", 3)//定义文本显示y轴偏移量
	  		 .style("text-anchor", function(d) { return d.children ? "end" : "start"; })//文字对齐显示
	  		 .text(function(d) { return d.name; });
	
	
	
	//修改节点处理
	var nodeUpdate =node.transition()
    		  	.duration(500)//使节点缓慢过度
    		  	.attr("transform", function(d) { 
    		  		return "translate(" + d.y + "," + d.x + ")"; //过渡到新的坐标位置
    		  	});
	
	nodeUpdate.select("circle").attr("r", 4.5);
	
	//新增节点文本显示
	nodeUpdate.select("text")		//添加节点显示文本
	  		 .attr("dx", function(d) { return d.children ? -8 : 8; })//定义文本显示x轴偏移量
	  		 .attr("dy", 3)//定义文本显示y轴偏移量
	  		 .style("text-anchor", function(d) { return d.children ? "end" : "start"; })//文字对齐显示
	  		 .text(function(d) { return d.name; });
	
	//删除的节点处理
	var nodeExit = node.exit()
			.transition()
	 		.duration(500)
	 		.attr("transform", function(d) { 
	 			return "translate(" + d.y + "," + d.x + ")"; 
	 		})
	 		.remove();
}

//重绘连线
function drawLink(sourceData,links){
	
	//获取连线的update部分
	var linkUpdate = svg.selectAll(".link")
	         .data(links, function(d){ return d.target.id; });
	 
	//获取连线的enter部分
	var linkEnter = linkUpdate.enter();
	 
	//获取连线的exit部分
	var linkExit = linkUpdate.exit();
	
	//连线的 Enter 部分的处理办法
	linkEnter.insert("path",".node")
	          .attr("class", "link")
	          .attr("d", function(d) {
	              var o = {x: sourceData.x0, y: sourceData.y0};
	              return diagonal({source: o, target: o});
	          })
	          .attr("marker-end", function(d){
	        	  return getArrow();
	          })
	          .transition()
	          .duration(500)
	          .attr("d", diagonal);
	 
	 //连线的 Update 部分的处理办法
	 linkUpdate.transition()
	        .duration(500)
	        .attr("d", diagonal);
	 
	 //连线的 Exit 部分的处理办法
	 linkExit.transition()
	          .duration(500)
	          .attr("d", function(d) {
	            var o = {x: sourceData.x, y: sourceData.y};
	            return diagonal({source: o, target: o});
	          })
	          .remove();
}


/**
 * 定义扩展箭头方法
 */
function getArrow(){
	 if($('marker#end-arrow').length==0){
	 svg.append('svg:defs').append('svg:marker')
    .attr('id', 'end-arrow')
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 10)
    .attr('markerWidth', 6)//箭头参数适当按需调整
    .attr('markerHeight', 10)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M0,-5L10,0L0,5')//绘制箭头形状
    .attr('fill', 'blue');
	 }
	 return 'url(#end-arrow)';
}



//初始化布局属性
function initTree(){
	height = parseInt(window.parent.$("#iframe").height());
	width = parseInt(window.parent.$("#iframe").width());
	
	treeWidth = width-leftW;
	treeHeight = height-topH;
	
	d3.select("svg").attr("width", treeWidth);
	d3.select("svg").attr("height", treeHeight);
	tree.size([treeHeight, treeWidth-180]);
}

//编辑节点属性
function editPropertity(){
	$CommonUI.getForm("#propertityForm").form("clear");
	$("#relevanceTableName").val(currentNode.name);
	if(currentNode.parent){
		$("#mainTableId").val(currentNode.parent.id);
	}
	$("#relevanceField").val(currentNode.id);
	$CommonUI.getDialog('#tablePropertity').dialog("open");
}

//添加节点
var index = 100;
function addSubTable(){
	var newNode={
			id:++index,
			name:"new node",
			children:null
	};
	if(!currentNode.children){
		currentNode.children=[];
	}
	currentNode.children.push(newNode);
	var rootNode = currentNode;
	while(rootNode.parent){
		rootNode = rootNode.parent;
	}
	drawTree(rootNode);
}

//删除节点
function removeTable(){
	//删除节点的孩子
	if(currentNode.children){
		currentNode.children=null;
	}
	var currentNodeId =  currentNode.id;
	var currentNodeParent =  currentNode.parent;
	if(currentNodeParent){//如果节点有父类,删除节点本身,保留其他节点信息
		for(var i=0;i<currentNodeParent.children.length;i++){
			if(currentNodeParent.children[i].id == currentNodeId){
				currentNodeParent.children.splice(i,1);
			}
		}
	}else{
		currentNode=null;
		$('#relevanceRuleConfig').first("g").children().remove();
	}
	
	var rootNode = currentNode;
	if(rootNode ){
		while(rootNode.parent){
			rootNode = rootNode.parent;
		}
		drawTree(rootNode);
	}
}





data.json

{
"id":"1",
"name":"就诊记录表",
"children":
[
	{ 
	  "id":"2",
	  "name":"患者信息表"
  	},
	{ 
	  "id":"3",
	  "name":"住院记录表"
	},
	{ 
		"id":"4",
	    "name":"出院记录表"
	},
	{ 
		"id":"5",
	    "name":"诊断信息表"
	},
	{ 
		"id":"6",
	    "name":"缴费信息表"
	}
]
}

效果图:











var myTree = null; function CreateTree() { myTree = new ECOTree(&#39;myTree&#39;,&#39;myTreeContainer&#39;); myTree.config.colorStyle = ECOTree.CS_LEVEL; myTree.config.nodeFill = ECOTree.NF_FLAT; myTree.config.selectMode = ECOTree.SL_NONE; //是否允许给节点加链接,是否允许给节点加图片 myTree.config.useTarget = false; myTree.config.useImg = true;   //设置节点的大小和间隔 myTree.config.defaultNodeWidth = 95; myTree.config.defaultNodeHeight = 140; myTree.config.iSubtreeSeparation = 50; myTree.config.iSiblingSeparation = 15; myTree.config.iLevelSeparation = 30; //此处通过从数据库或其它地方读取节点信息,生成添加节点的代码 //参数前三位是必须的; //第一位是本节点id,第二位是父节点id、根节点的父节点为-1,第三位为节点文本; //第四位为节点上显示的图片/照片、图片放到img下并在数据库中记录名称即可,未设参数则取默认图片; //第五位为超链接、最好是访问统一程序传入本节点id; //第六、七位为节点的个性化宽、高。 myTree.add(&#39;01&#39;,-1,&#39;总裁&#39;,&#39;./img/0.jpg&#39;,&#39;http://www.jq-school.com&#39;); myTree.add(&#39;02&#39;,&#39;01&#39;,&#39;技术副总裁&#39;,&#39;./img/1.jpg&#39;); myTree.add(&#39;03&#39;,&#39;01&#39;,&#39;总裁助理&#39;,&#39;./img/2.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;04&#39;,&#39;01&#39;,&#39;分公司&#39;,&#39;./img/3.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0201&#39;,&#39;02&#39;,&#39;技术经理&#39;,&#39;./img/4.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0202&#39;,&#39;02&#39;,&#39;技术员&#39;,&#39;./img/5.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0301&#39;,&#39;03&#39;,&#39;秘书&#39;,&#39;./img/5.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0302&#39;,&#39;03&#39;,&#39;助理&#39;,&#39;./img/6.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0401&#39;,&#39;04&#39;,&#39;总经理&#39;,&#39;./img/6.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.add(&#39;0402&#39;,&#39;04&#39;,&#39;财务&#39;,&#39;./img/7.jpg&#39;,&#39;http://www.jq-school.com&#39;,95,130); myTree.UpdateTree(); } 包含有例子和源码。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值