参考链接:https://www.cnblogs.com/xcxcxcxc/p/5900444.html
页面:keyword.html
页面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
*{
margin: 0;
padding: 0;
}
.main {
width: 850px;
height: 600px;
background-color: #f4f4f4;
}
#keyword{
width: 100%;
height: 100%;
}
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
#licensing {
fill: green;
}
.link.licensing {
stroke: green;
}
.link.resolved {
stroke-dasharray: 0,2 1;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 12px Microsoft YaHei;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
.linetext {
font: 12px Microsoft YaHei;
}
.tooltip{
position: absolute;
height: auto;
font-family: "microsoft yahei", simhei;
font-size: 14px;
text-align: center;
border: 1px solid #999;
padding: 5px;
background-color: white;
border-radius: 5px;
}
</style>
</head>
<body>
<div class='main'>
<div id="keyword">
</div>
</div>
<script src="assets/plugins/jquery/jquery-3.3.1.min.js"></script>
<script src="assets/plugins/d3/d3.v3.min.js"></script>
<script src="assets/js/pages/keyword.js"></script>
</body>
</html>
keyword.js 代码:
d3.json("assets/data/word.json",function(error,root){
var links = [];
for(var i=0;i<root.length;i++){
links.push({
source: root[i].word1,
target: root[i].word2,
rela: root[i].freq
})
}
var nodes = {};
links.forEach(function(link) {
//利用source和target名称进行连线以及节点的确认
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
var width = $("#keyword").width(),
height = $("#keyword").height();
var force = d3.layout.force()//layout将json格式转化为力学图可用的格式
.nodes(d3.values(nodes))//设定节点数组
.links(links)//设定连线数组
.size([width, height])//大小
.linkDistance(120)//连接线长度
.charge(-800)//值为+,则相互吸引,绝对值越大吸引力越大。值为-,则相互排斥,绝对值越大排斥力越大
.on("tick", tick)//指时间间隔,隔一段时间刷新一次画面
.start();//开始转换
var zoom = d3.behavior.zoom()//缩放配置,
.scaleExtent([0.4, 2])//缩放比例
.on("zoom", zoomed);
function zoomed(){//缩放函数
svg.selectAll("g").attr("transform",//svg下的g标签移动大小
"translate(" +d3.event.translate + ")scale(" +d3.event.scale + ")");
/*console.log(d3.event.translate+"/"+d3.event.scale);*/
}
var svg = d3.select("#keyword").append("svg")//添加svg元素进行图形的绘制
.attr("width", width)
.attr("height", height)
.call(zoom);
//设置连接线
var edges_line = svg.append("g").selectAll(".edgepath")
.data(force.links())//连线数据
.enter()
.append("path")//添加path标签
.attr({
'd': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
'class':'edgepath',//定义该path标签class为edgepath
'id':function(d,i) {return 'edgepath'+i;}})
.style("stroke","#B43232")//设置线条颜色
.style("stroke-width",0.5)//线条粗细
//连线上的文字
var edges_text = svg.append("g").selectAll(".edgelabel")
.data(force.links())
.enter()
.append("text")//添加text标签
.attr({ 'class':'edgelabel',//定义该text标签class为edgelabel
'id':function(d,i){return 'edgepath'+i;},
'dx':50,//在连线上的坐标
'dy':0
});
//设置线条上的文字路径
edges_text.append('textPath')
.attr('xlink:href',function(d,i) {return '#edgepath'+i})
.style("pointer-events", "none")
.text(function(d){return d.rela;});
function drag(){//拖拽函数
return force.drag()
.on("dragstart",function(d){
d3.event.sourceEvent.stopPropagation(); //取消默认事件
d.fixed = true; //拖拽开始后设定被拖拽对象为固定
});
}
//圆圈的提示文字 根据需要到数据库中进行读取数据
var tooltip = d3.select("body")
.append("div")//添加div并设置成透明
.attr("class","tooltip")
.style("opacity",0.0);
//圆圈
var circle = svg.append("g")
.selectAll("circle")
.data(force.nodes())//表示使用force.nodes数据
.enter().append("circle")
.style("fill","#39e3db")
.style('stroke',"#39e3db")
.style('cursor',"pointer")
.attr("r",function(node,i){
var r;
r = set_r(node.name);
return r;
})//设置圆圈半径
.on("click",function(node){
//单击时让连接线加粗
edges_line.style("stroke-width",function(line){
if(line.source.name==node.name || line.target.name==node.name){//当与连接点连接时变粗
return 2;
}else{
return 0.5;
}
});
circle.style('stroke-width',1);//所有的圆圈边框
d3.select(this).style('stroke-width',4);//被选中的圆圈边框
})
.on("dblclick",function(d){
//双击节点时节点恢复拖拽
d.fixed = false;
})
.on("mouseover",function(d){
set_tooltip(d.name);
})
.on("mousemove",function(d){
tooltip.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 20) + "px");
})
.on("mouseout",function(d){
tooltip.style("opacity",0.0);
})
.call(drag());//使顶点可以被拖动
svg.selectAll("g").call(drag());//为svg下的所有g标签添加拖拽事件
svg.on("dblclick.zoom", null);//取消svg和圆圈的双击放大事件(d3中默认开启7个事件,关闭防止与上面的双击事件冲突)
circle.on("dblclick.zoom", null);
var text = svg.append("g").selectAll("text")
.data(force.nodes())
//返回缺失元素的占位对象(placeholder),指向绑定的数据中比选定元素集多出的一部分元素。
.enter()
.append("text")//添加text标签
.attr("dy", ".35em") //将文字下移
.attr("text-anchor", "middle")//在圆圈中加上数据
.style('fill',"#555")
.style('cursor',"pointer")
.on("mouseover",function(d){
set_tooltip(d.name);
})
.on("mouseout",function(d){
tooltip.style("opacity",0.0);
})
.call(drag())
.attr('x',function(d){
// console.log(d.name+"---"+ d.name.length);
var re_en = /[a-zA-Z]+/g;
//如果是全英文,不换行
if(d.name.match(re_en)){
d3.select(this).append('tspan')//添加tspan用来方便时使用绝对或相对坐标来调整文本
.attr('x',0)
.attr('y',2)
.text(function(){return d.name;});
}
//如果小于8个字符,不换行
else if(d.name.length<=8){
d3.select(this).append('tspan')
.attr('x',0)
.attr('y',2)
.text(function(){return d.name;});
}else if(d.name.length>=16){//大于16个字符时,将14个字后的内容显示为。。。
var top=d.name.substring(0,8);
var bot=d.name.substring(8,14)+"...";
d3.select(this).text(function(){return '';});
d3.select(this).append('tspan')//前n个字
.attr('x',0)
.attr('y',-7)
.text(function(){return top;});
d3.select(this).append('tspan')//后n个字
.attr('x',0)
.attr('y',10)
.text(function(){return bot;});
}
else {//8-16字符分两行显示
var top=d.name.substring(0,8);
var bot=d.name.substring(8,d.name.length);
d3.select(this).text(function(){return '';});
d3.select(this).append('tspan')
.attr('x',0)
.attr('y',-7)
.text(function(){return top;});
d3.select(this).append('tspan')
.attr('x',0)
.attr('y',10)
.text(function(){return bot;});
}
});
function tick() {//刷新页面函数
circle.attr("transform", transform1);//圆圈
text.attr("transform", transform1);//顶点文字
edges_line.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();//获取矩形空间,并且调整翻转中心。(因为svg与css中的翻转不同,具体区别可看http://www.zhangxinxu.com/wordpress/2015/10/understand-svg-transform/)
rx = bbox.x+bbox.width/2;
ry = bbox.y+bbox.height/2;
return 'rotate(180 '+rx+' '+ry+')';
}
else {
return 'rotate(0)';
}
})
.attr('dx',function(d,i){
return Math.sqrt(Math.pow(d.target.x-d.source.x,2)+Math.pow(d.target.y-d.source.y,2))/2-20;
//设置文字一直显示在线的中间
});
}
//设置圆圈和文字的坐标
function transform1(d) {
return "translate(" + d.x + "," + d.y + ")";
}
function set_r(name){ //设置圆圈大小
var r;
for(var i=0;i<links.length;i++){
if(name == links[i].source.name || name == links[i].target.name){
r=parseInt(links[i].rela) * 3;
break;
}
}
return r;
}
function set_tooltip(name){//设置提示内容
var r;
for(var i=0;i<links.length;i++){
if(name == links[i].source.name || name == links[i].target.name){
r=links[i].rela;
break;
}
}
tooltip.html(name + "【总次数:" + r + "】")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 20) + "px")
.style("opacity",1.0);
}
})
如果需要初始化图形的大小和位置,可以在js中添加:
zoom.translate([242,180]);
zoom.scale(zoom.scale() * 0.4);
svg.selectAll("g").attr("transform","translate(242,180)scale(0.4)");
此处的 242,180 和 0.4 可根据实际需要自行修改
如果不想显示连线上文字,可以在js中添加:
edges_text.style("opacity",0);
源码下载:https://pan.baidu.com/s/1j5MS4wT7kSRxHY9nx3Mz2A 密码:9yg6
需要前端资源可前往我的下载主页:https://download.csdn.net/user/qq_34114082/uploads