d3js 矩阵图
先贴出效果图:
这里我们解释下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