独行漫步者
我自独行,漫步天下
d3js 矩阵图

先贴出效果图:

1.png

这里我们解释下js:

test() :作为数据源函数并调用d3画图

drawApply() :画图函数,负责画图


具体解释看代码,如下:

<html>
<head>
	<title></title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>

<div id="metrics"></div>

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript">

function test(){
	var appStatus = {
		lineageSatus:1,
		impactStatus:1,
		sameServerAppStatus:1,
		sameRackAppStatus:0.1,
		appDbStatus:1,
		appRedisStatus:1,
		appMqStatus:1,
		appHaproxyStatus:1
	};
	var dymicInfo = {
		rt : 1,
		tps : 1,
		cpu : 1,
		mem : 1,
		disk : 1,
		switchPercent : 1,
		machineRoomPercent : 1
	};

	var basicInfo ={
		appName : 'test',
		departmentName : 'test',
		businessName : 'test',
		connectPerson : 'test',
		appLevel : 'test',
		serviceNum : 'test',
		machineRoomNum : 'test',
		machineNum : 'test'
	};
	drawApply(basicInfo, dymicInfo,appStatus);
}
function drawApply(basicInfo, dymicInfo,appStatus){
	
	
	var maxdepth=3;
	var width = 420,height = 420;
	//width = height;
	var margin = {top: 10, right: 50, bottom: 10, left: 50}
    var cluster = d3.layout.cluster()
              .size([height, width/2]);

    var maxScaleX = 0;
    appStatus =eval(appStatus);
     var newnode
/*    svg.append("rect")
    .attr("width", "500px")
    .attr("height", "500px")
    .attr("fill", "#ffffff")
    .attr("stroke", "#0000ff")
    .attr("stroke-width", "2px")
    .attr("stroke-opacity", "0.1");*/
     var nodePositionDictionary = {};
     var root = {children:[], name:"a","pos":"mid"};
     var rootLeft = {children:[], name:"a","pos":"mid"};
     var rootRight = {children:[], name:"a","pos":"mid"};
     dymicInfo = eval(dymicInfo);
     newnode = {"name":"血缘","value":appStatus.lineageSatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
    
     newnode = {"name":"影响","value":appStatus.impactStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"同服务器","value":appStatus.sameServerAppStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
    
     newnode = {"name":"同机柜","value":appStatus.sameRackAppStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"数据库","value":appStatus.appDbStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"Redis","value":appStatus.appRedisStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"MQ","value":appStatus.appMqStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"Haproxy","value":appStatus.appHaproxyStatus};
     rootRight.children.push(newnode);
     root.children.push(newnode);
     
     var nodesRight = cluster.nodes(rootRight);
     maxScaleX = d3.max(nodesRight,function(d){return d.x;});
     for (var j = 0; j < nodesRight.length; j++) {
	       var node = nodesRight[j];
	       node.right = true;
	       nodePositionDictionary[node.name + (node.parent?node.parent.name:"") + node.pos] = node;
     };
     
     newnode = {"name":"RT","value":dymicInfo.rt};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"TPS","value":dymicInfo.tps};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     var cpu =Math.floor(dymicInfo.cpu*100)
     newnode = {"name":"CPU","value":cpu+"%"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     var mem =Math.floor(dymicInfo.mem*100)
     newnode = {"name":"MEM","value":mem+"%"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     newnode = {"name":"LOAD","value":"10"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
   
     newnode = {"name":"硬盘","value":dymicInfo.disk+"%"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     var switchPercent =Math.floor(dymicInfo.switchPercent*100)
     newnode = {"name":"机柜","value":switchPercent+"%"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     var machineRoomPercent =Math.floor(dymicInfo.machineRoomPercent*100)
     newnode = {"name":"机房","value":machineRoomPercent+"%"};
     rootLeft.children.push(newnode);
     root.children.push(newnode);
     
     var nodesLeft = cluster.nodes(rootLeft);
     var maxLeft = d3.max(nodesLeft,function(d){return d.x;});
     console.log(maxLeft);
     if(maxLeft>maxScaleX)  maxScaleX = maxLeft;
     for (var j = 0; j < nodesLeft.length; j++) {
	         var node = nodesLeft[j];
	         node.right = false;
	         nodePositionDictionary[node.name + (node.parent?node.parent.name:"")  + node.pos] = node;
     };
     
     var svg = d3.select("#metrics").append("svg")
               .attr("width", width+margin.left+margin.right)
               .attr("height", height+margin.top+margin.bottom)
               .append("g")
               .attr("transform", "translate(" + margin.left + ",0)");
     
     addSymbol(svg);
     
     
     basicInfo = eval(basicInfo);
     var basicInfoJson = [];
     newnode = {"name":"英文名","value":basicInfo.appName};
     basicInfoJson.push(newnode);
     newnode = {"name":"部门","value":basicInfo.departmentName};
     basicInfoJson.push(newnode);
     newnode = {"name":"业务域","value":basicInfo.businessName};
     basicInfoJson.push(newnode);
     newnode = {"name":"负责人","value":basicInfo.connectPerson};
     basicInfoJson.push(newnode);
     newnode = {"name":"等 级","value":basicInfo.appLevel+"级"};
     basicInfoJson.push(newnode);
     newnode = {"name":"服务数","value":basicInfo.serviceNum};
     basicInfoJson.push(newnode);
     newnode = {"name":"机房数","value":basicInfo.machineRoomNum};
     basicInfoJson.push(newnode);
     newnode = {"name":"机器数","value":basicInfo.machineNum};
     basicInfoJson.push(newnode);

    // manually create nodes with their positions instead of doing cluster.nodes because 
    // i want them to be drawn left and right
     var nodes = [];
  
     updateNodePositions(root);
     
     var diagonalRight = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });
     var diagonalLeft = d3.svg.diagonal().projection(function(d) { return [-d.y, d.x]; });
     var links = cluster.links(nodes);
     var link = svg.append("g")
                     .attr("transform", "translate(" + width/2+ "," + 0+ ")")
                     .selectAll(".link")
                     .data(links)
    	             .enter().append("path")
      		         .attr("stroke",function(d){return d.target.fillcolor;})
      		         .attr("stroke-width", 2)
      		         .attr("fill", "none")
      		         .attr("d", function(d){
      		        	     return d.target.right || d.source.right?diagonalRight(d):diagonalLeft(d);
      		          });
     var nodeEnter =svg.append("g")
				     .attr("transform", "translate(" + width/2+ "," + 0+ ")")
				     .selectAll(".node")
				     .data(nodes)
				     .enter();
     console.log(nodeEnter);
     
     var node = nodeEnter.append("circle")
                     .attr("class", "node")
                     .attr("r", 25)
                     .attr("cx",function(d) {
                    	 if((d.right==null)||(d.right)){
                    		 return d.y;
                    	 }else{
                    		 return -d.y; 
                    	 }})
                     .attr("cy",function(d) { return d.x;})
                     .style("display", function(d) {
			    	            if (d.pos == 'mid') {
			    		            return 'none';
			    	            }
                     })
                     .style("fill", function(d) { 
                    	 if(d.right==true){
                    		 if(d.value=="1"){
                    			 //return "#FF0000"; //右边颜色
                    			 return "red";  // 报警颜色
                    		 }else{
                    			 return "green"; // 正常颜色
                    		 }
                    	 }
                    	 if(d.name=="TPS" ||  d.name=="RT"){
                    		 return "#E6E6E6";
                    	 }else if(d.name=="CPU" ||  d.name=="MEM"){
                    		 return "#E6E6E6";
                    	 }else if(d.name=="入带宽" ||  d.name=="出带宽"){
                    		 return "#E6E6E6";
                    	 }else{
                    		 return "#E6E6E6";
                    	 }
                     })
                     .on("click", function(d){
                    	 showDetailInfo(d);
			         });
     
     var textn1 = nodeEnter.append("text")
                     .attr("x",function(d) { if((d.right==null)||(d.right)){
		                		 return d.y;
		                	 }else{
		                		 return -d.y; 
		                	 }})
                     .attr("y",function(d) { 
                    	 if(d.right==false){
                    	       return d.x-4;  
                    	 }else{
                    		   return d.x+10
                    	 }
                     })
                     .text(function(d) {  return d.name;})
                     .style("display", function(d) {
			    	            if (d.pos == 'mid') {
			    		            return 'none';
			    	            }
                     })
                     .style('cursor', 'pointer')
                     .attr("text-anchor", function(d) { 
                    		 return "middle";
                     })
                     .on("click", function(d){
                    	 showDetailInfo(d);
			         });
                    
     var textn2 = nodeEnter.append("text")
			     .attr("x",function(d) { if((d.right==null)||(d.right)){
			        		 return d.y;
			        	 }else{
			        		 return -d.y; 
			        	 }})
			     .attr("y",function(d) { 
			    	 if(d.right==false){
			    	      return d.x+14;  
			    	 }else{
              		      return d.x+10
              	     }
			    	 })
			     .text(function(d) {  
			    	 console.log(d);
			    	 if(d.right==true){
                			 return ""; 
                			 
                	 }else{
			    	      return d.value;
			    	 }})
			     .style("display", function(d) {
				            if (d.pos == 'mid') {
					            return 'none';
				            }
			     })
			     .attr("text-anchor", function(d) { 
			    		 return "middle";
			     });
     var centerNode;
     for(var i=0;i<nodes.length;i++){
    	 var nodet=nodes[i];
    	 if(nodet.pos=='mid'){
    		 centerNode = nodet;
    	 }
     }
     
     

	 svg.append("use")
           .attr("xlink:href", "#tableSymbol")
           .attr("x",centerNode.y+width/2-110)
           .attr("y",centerNode.x-112.5);
     svg.append("text")
	       .attr("x",centerNode.y+width/2)
           .attr("y",centerNode.x-112.5+17)
           .attr("text-anchor","middle")
	       .text(basicInfo.appChnName);
     for(var i=0;i<basicInfoJson.length;i++){
	        if(i>1){
	    	    svg.append("use")
		               .attr("xlink:href", "#columnSymbol")
		               .attr("x",centerNode.y+width/2-110)
		               .attr("y",centerNode.x-(112.5-(i+1)*25));
		         svg.append("text")
			           .attr("x",centerNode.y+width/2-110)
	                   .attr("y",centerNode.x-(112.5-(i+1)*25)+17)
	                   .attr("text-anchor","left")
			           .text("  "+basicInfoJson[i].name+" : "+basicInfoJson[i].value);
	        }else{
	        	svg.append("use")
	               .attr("xlink:href", "#columnSymbol")
	               .attr("x",centerNode.y+width/2-110)
	               .attr("y",centerNode.x-(112.5-(i+1)*25));
	            svg.append("text")
		           .attr("x",centerNode.y+width/2-110)
                .attr("y",centerNode.x-(112.5-(i+1)*25)+17)
                .attr("text-anchor","left")
			      
		           .text("  "+basicInfoJson[i].value);
	        } 
     }

     // 删除不显示的图例
     var us = svg.selectAll("use");
     us[0].forEach(function(o) {
    	 if (o.style['display'] == 'none') {
    		 o.remove();
    	 }
     });
     
     
     function updateNodePositions(n){
    	
    		var nodePosition = nodePositionDictionary[n.name + (n.parent?n.parent.name:"") + n.pos];
    		
    		if(nodePosition){
    			n.x = nodePosition.x;
    			n.y = nodePosition.y;
    			n.depth = nodePosition.depth;
    			nodes.push(n);
    		}
    		
    		for(var i=0; i< n.children.length;i++)
    		{
    			var node = n.children[i];
    			node.parent = n;

    			nodes.push(node);
                
    			var childNodePosition = nodePositionDictionary[node.name + (node.parent?node.parent.name:"") + node.pos];
    			
    			if(childNodePosition){
					node.x = childNodePosition.x;
					node.y = childNodePosition.y;
					node.depth = childNodePosition.depth;
					node.right = childNodePosition.right;

					if(node.name=="TPS" ||  node.name=="RT"){
						node.fillcolor="#E6E6E6";
					}else if(node.name=="CPU" ||  node.name=="MEM"){
						node.fillcolor="#E6E6E6";
					}else if(node.name=="入带宽" ||  node.name=="出带宽"){
						node.fillcolor="#E6E6E6";
					}else{
						node.fillcolor="#E6E6E6";
					}
    			}

    			if(node.children){
    				updateNodePositions(node);
    			}
    		}

    	}      
     
     
     
}


function showDetailInfo(d) {
	console.log(d);
	if (d.name == '影响') {
		window.open(getContextPath() +'/smAllImpact/app/'+ appId);
	} else if (d.name == '血缘') {
		window.open(getContextPath() +'/smAllLineage/app/'+ appId);
	} else if (d.name == '同服务器') {
		window.open(getContextPath() +'/server/index?sapp='+ appId);
	} else if (d.name == '同机柜') {
		window.open(getContextPath() +'/rack/index?sapp='+ appId);
	} else if (d.name == '数据库') {
		window.open(getContextPath() +'/db/index?sapp='+ appId);
	} else if (d.name == 'Redis') {
		window.open(getContextPath() +'/redis/index?sapp='+ appId);
	} else if (d.name == 'MQ') {
		window.open(getContextPath() +'/mq/index?sapp='+ appId);
	} else if (d.name == 'Haproxy') {
		window.open(getContextPath() +'/haproxy/index');
	}
}



function addSymbol(svg) {
	var tableSymbol = svg.append("symbol").attr('id', 'tableSymbol');
	tableSymbol.append("rect")
	    .attr('x', 0)
	    .attr('y', 0)
		.attr('width', '220')
		.attr('height', '25')
		.attr("fill", "#eeeeee")
        .attr("fill-opacity", 1)
        .attr("stroke-width", 0.2)
        .attr("stroke", "#000000");
	svg.append("defs").append("filter")
	    .attr("id", "clippy")
	    .attr("x", "0")
	    .attr("y", "1")
	    .attr("height", "18")
	    .attr("width","202")
	    .append("feColorMatrix")
	    .attr("type", "identity");
	var columnSymbol = svg.append("symbol").attr('id', 'columnSymbol');
	columnSymbol.append("rect")
	    .attr('x', 0)
	    .attr('y', 0)
		.attr('width', '220')
		.attr('height', '25')
		.attr("fill", "#ffffff")
	    .attr("fill-opacity", 1)
	    .attr("stroke-width", 0.2)
	    .attr("stroke", "#000000");
	
}

// 画图
test();
</script>
</body>
</html>


这里可以参考对应d3js的Concept network browser

<< 上一篇 二分查找数组中 n 所在的位置 PHP 对二维数组指定key排序 下一篇 >>
文章标签
随意 | Created At 2014 By William Clinton | 蜀ICP备14002619号-4 |