D3.js力导向图(节点+连线+连线文字+节点文字)
json文件格式
{
"nodes":[
{"id":"1","name":"北京大学","ntype":"school"},
{"id":"2","name":"软件工程","ntype":"special"}],
"links": [
{"target":"1","source":"2","name":"专业","type":"special_link"}
]
具体代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
</style>
</head>
<body>
<script src="js/d3.min.js"></script>
<script>
const nodeConf = {
fillColor: {
school: 'rgb(255, 76, 10)',
special: '#00FF33',
A:'rgb(220,20,60)'
},
strokeColor: {
school: '#993300',
special: 'rgb(35, 148, 206)',
H:'rgb(255,240,245)'
},
strokeWidth: {
school: 3,
special: 3,
C:3
},
textFillColor: {
school: 'black',
special: 'black',
C:'black'
},
radius: {
school: 6,
special: 16,
C:25
}
};
const lineConf = {
strokeColor: {
special_link: 'rgb(204, 225, 152)',
INVEST_C: 'rgb(242, 90, 41)'
}
};
var width = 2000,
height = 900;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force() // - 使用物理模拟排放链接节点的位置
.size([width, height])
.charge(-100) // 取得或者设置电荷强度
.linkDistance(180);
d3.json("data2.json", function (error, graph) {
if (error) throw error;
var edges = [];
graph.links.forEach(
function (e) {
var sourceNode = graph.nodes.filter(function (n) {
return n.id === e.source;
})[0],
targetNode = graph.nodes.filter(
function (n) {
return n.id === e.target;
})[0]
edges.push({
source: sourceNode,
target: targetNode,
name:e.name,
type:e.type
});
}
);
force
.nodes(graph.nodes) // 取得或者设置布局的节点数组
.links(edges) // 取得或者设置节点间的链接数组
.on("tick", tick) // 监听在计算布局位置时的更新 执行tick函数
.start(); // 当节点变化时启动或者重启模拟
// line
var link = svg.selectAll(".link")
.data(edges)
.enter().append("path")
.attr({
'd': function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target
.y
},
'class': 'edgepath',
'id': function (d, i) {
return 'edgepath' + i;
}
})
.style('stroke', link => lineConf.strokeColor[link.type])
.style('stroke-width', 1)
// 线上文字
var edges_text = svg.selectAll(".edgelabel")
.data(edges)
.enter()
.append("text")
.attr({
'class': 'edgelabel',
'id': function (d, i) {
return 'edgepath' + i;
},
'dx': 80,
'dy': 0
//'font-size':10,
//'fill':'#aaa'
})
//设置线条上的文字
edges_text.append('textPath')
.attr('xlink:href', function (d, i) {
return '#edgepath' + i
})
.style("pointer-events", "none")
.text(function (d) {
return d.name;
});
// node
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag); // 为当前选择调用一个函数。 给节点绑定拖动行为
node.append("circle") // 设置圆圈的样式
.attr("r", node => nodeConf.radius[node.ntype])
.style("fill", node => nodeConf.fillColor[node.ntype])
.style('stroke', node => nodeConf.strokeColor[node.ntype])
node.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle") // 文本锚点属性被用来描述该文本与所给点的对齐方式 (开头、中间、末尾对齐) 。
.text(function (d) { // 确定节点的文字
return d.name;
}).style('fill', node => nodeConf.textFillColor[node.ntype])
.style("font-size",10);
//鼠标交互
function tick() {
// 更新线
link.selectAll("line")
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
link.attr('d', function (d) {
var path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target
.y;
return path;
});
edges_text.attr('transform', function (d, i) {
if (d.target.x < d.source.x) {
bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
} else {
return 'rotate(0)';
}
});
// 更新节点
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
});
</script>
</body>
</html>