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