d3.js的关系图初试(附加拖拽、缩放及根据自定义名称确定节点)

来源:互联网 发布:太阳黑子数据下载 编辑:程序博客网 时间:2024/06/10 01:59

上次用的百度的echarts做的关系图,这周选择的是d3.js做的关系图。总体来看,echarts更简单一些,因为他的文档很容易,而d3的因为是外国的,所以文档阅读起来比较麻烦,即使有中文文档但是有些东西仍然要看英文的。但是因为echarts封装的很好,所以说要用起来就只能很规范化的做那一套了,而有些东西要进行自己设计就不行了,而d3就解决了这一点。就比如说连线上的箭头,echarts只能在连线的左右,而d3是自己绘制的所以可以决定大小和位置。另d3主要是用svg而echarts用的canvas。不过现在d3的v4版本也加入了canvas。

我就直接把代码复制下来了,里面具体的需要查看的资料以及实现都已经注释了,方便自己查看。

注:仅为我练习所用,虽然应该没人看。只是给自己记录一下

<!DOCTYPE html><meta charset="utf-8"><head><meta charset="utf-8"/><title></title></head><body><style>.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: 10px 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-size: 12px Microsoft YaHei;}.tooltip{position: absolute;width: 120;height: auto;font-family: simsun;font-size: 14px;text-align: center;border-style: solid; border-width: 1px;background-color: white;border-radius: 5px;}</style><script src="jquery-1.11.3.js" type="text/javascript" charset="utf-8"></script><script src="http://d3js.org/d3.v3.min.js"></script><!--作者:offline时间:2017-08-04描述:d3.js需在Firefox、Internet Explorer9、谷歌Chrome和Safari中使用。因为是直接在html中添加svg代码--><script>var chaxuntext=$(".chaxuntext").text;// http://blog.thomsonreuters.com/index.php/mobile-patent-suits-graphic-of-the-day/var links = [  {source: "同花顺", target: "IFIND", type: "resolved", rela:"主营产品",jieshao:"专门做股票的,哈哈1"},  {source: "同花顺", target: "手机金融信息服务", type: "resolved", rela:"主营产品",jieshao:"专门做股票的,哈哈2"},  {source: "同花顺", target: "互联网金融信息服务", type: "resolved", rela:"主营产品",jieshao:"专门做股票的,哈哈3"},  {source: "同花顺", target: "网上行情交易系统", type: "resolved", rela:"主营产品",jieshao:"专门做股票的,哈哈4"},  {source: "同花顺", target: "金融资讯及数据服务", type: "resolved", rela:"主营产品",jieshao:"专门做股票的,哈哈5"},  {source: "同花顺", target: "互联网金融", type: "resolved",rela:"主营产品",jieshao:"专门做股票的,哈哈6"},  {source: "同花顺", target: "金融服务", type: "resolved",rela:"主营产品",jieshao:"专门做股票的,哈哈7"},  {source: "手机金融信息服务", target: "金融信息服务", type: "resolved", rela:"上位产品",jieshao:"母鸡"},  {source: "互联网金融信息服务", target: "金融信息服务", type: "resolved", rela:"上位产品",jieshao:"test"},  {source: "二三四五002195", target: "金融信息服务", type: "resolved", rela:"主营产品",jieshao:"123456789"},  {source: "大智慧601519", target: "金融信息服务", type: "resolved", rela:"主营产品",jieshao:"智慧"},  {source: "大智慧601519", target: "互联网金融信息服务看看长度啊啊啊哈哈", type: "resolved", rela:"主营产品",jieshao:"智慧"},  {source: "金融服务", target: "移动互联网", type: "resolved", rela:"上游",jieshao:"测试"},  {source: "金融服务", target: "互联网金融服务", type: "resolved", rela:"下位产品",jieshao:"测试"},  {source: "金融服务", target: "综合金融服务", type: "resolved", rela:"下位产品",jieshao:"测试"},  {source: "1", target: "2", rela:"下位产品",jieshao:"测试"}];var nodes = {};links.forEach(function(link) {//参考https://stackoverflow.com/questions/23986466/d3-force-layout-linking-nodes-by-name-instead-of-index//利用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 = 1560,    height = 800;var force = d3.layout.force()//layout将json格式转化为力学图可用的格式    .nodes(d3.values(nodes))//设定节点数组    .links(links)//设定连线数组    .size([width, height])//大小    .linkDistance(150)//连接线长度    .charge(-1500)//值为+,则相互吸引,绝对值越大吸引力越大。值为-,则相互排斥,绝对值越大排斥力越大    .on("tick", tick)//指时间间隔,隔一段时间刷新一次画面    .start();//开始转换var zoom = d3.behavior.zoom()//缩放配置,            .scaleExtent([0, 2])//缩放比例            .on("zoom", zoomed);      function zoomed(){//缩放函数            svg.selectAll("g").attr("transform",//svg下的g标签移动大小                "translate("  +d3.event.translate + ")scale(" +d3.event.scale + ")");   }        var svg = d3.select("body").append("svg")//添加svg元素进行图形的绘制    .attr("width", width)    .attr("height", height)    .call(zoom)    ;   //箭头var marker=//注意SVG规范中明确指出,附加到一个'Marker'元素上的“事件属性和事件的listener”不会被处理    svg.append("marker")//添加一个marker标签来绘制箭头    .attr("id", "resolved")//箭头id,用于其他标记进行引用时的url    .attr("markerUnits","userSpaceOnUse")//定义标记的坐标系统,userSpaceOnUse表示按照引用的元件来决定,strokeWidth按照用户单位决定    .attr("viewBox", "0 -5 10 10")//坐标系的区域    .attr("refX",40)//箭头坐标    .attr("refY", 0)    .attr("markerWidth", 12)//标识的大小    .attr("markerHeight", 12)    .attr("orient", "auto")//绘制方向,可设定为:auto(自动确认方向)和 角度值    .attr("stroke-width",3)//箭头宽度    .append("path")    .attr("d", "M0,-5L10,0L0,5")//绘制箭头,路径为一个三角形,有疑问参考svg的path http://www.runoob.com/svg/svg-path.html    .attr('fill','#000000');//箭头颜色//设置连接线    var edges_line = svg.append("g").selectAll(".edgepath")    .data(force.links())//连线数据    .enter()//当数组中的个数大于元素个数时,由d3创建空元素并与数组中超出的部分进行绑定。    //可以参考http://www.ourd3js.com/wordpress/797/ enter、exit、update的区别    .append("path")//添加path标签    .attr({          'd': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},//变量 d 是由D3.js提供的一个在匿名函数中的可用变量。这个变量是对当前要处理的元素的_data_属性的引用。          'class':'edgepath',//定义该path标签class为edgepath          'id':function(d,i) {return 'edgepath'+i;}})// i也是d3.js提供的变量,表示当前处理的HTML元素在已选元素选集中的索引值    .style("stroke","#A254A2")//设置线条颜色    .style("stroke-width",1)//线条粗细    .attr("marker-end", "url(#resolved)" );//根据箭头标记的id号引用箭头//连线上的文字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':60,//在连线上的坐标               '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;    //拖拽开始后设定被拖拽对象为固定  });//.on("drag", dragmove);}                                     //圆圈的提示文字 根据需要到数据库中进行读取数据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",function(node){        var color;//圆圈背景色        var link=links[node.index];        if(link!=undefined){                if(link.source.name==node.name && node.name==chaxuntext){            color="#F6E8E9";        }else{            color="#F9EBF9";        }        }        return color;    })    .style('stroke',function(node){ //        var color;//圆圈边框的颜色        var link=links[node.index];//        if(link!=undefined){        if(node.name==link.source.name && node.name==chaxuntext){             color="#B43232";        }else{            color="#A254A2";        }        }        return color;    })    .attr("r", 38)//设置圆圈半径    .on("click",function(node){        //单击时让连接线加粗        edges_line.style("stroke-width",function(line){                        if(line.source.name==node.name || line.target.name==node.name){//当与连接点连接时变粗                return 4;                           }else{                return 1;            }        });        circle.style('stroke-width',1);//所有的圆圈边框        d3.select(this).style('stroke-width',4);//被选中的圆圈边框    })    .on("dblclick",function(d){    //双击节点时节点恢复拖拽    d.fixed = false;    })    .on("mouseover",function(d){    tooltip.html(d.name + "的介绍为" + "<br />" +   "数据库数据"+ " .")            .style("left", (d3.event.pageX) + "px")            .style("top", (d3.event.pageY + 20) + "px")            .style("opacity",1.0);    })    .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.selectAll("circle").call(drag());//svg.selectAll("path").call(drag());  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',function(node){        var color;//文字颜色        var link=links[node.index];        if(link!=undefined){               if(node.name==link.source.name && node.name==chaxuntext){            color="#B43232";        }else{            color="#A254A2";        }        }        return color;    }).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 + ")";}</script></body>


阅读全文
0 0