d3.js V3版本 绘制力导向图(可缩放,可拖拽)

参考链接: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




  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我可以为您介绍一下绘制导向的方法。d3.js是一个非常流行的JavaScript库,它提供了丰富的绘功能,包括绘制导向。 首先,您需要定义一个包含节点和链接信息的数据集。节点可以是一个对象,包含其名称和其他属性,链接可以是一个具有源节点和目标节点的对象。例如: ```javascript var nodes = [ { name: "A", group: 1 }, { name: "B", group: 2 }, { name: "C", group: 2 }, { name: "D", group: 3 } ]; var links = [ { source: "A", target: "B", value: 1 }, { source: "B", target: "C", value: 2 }, { source: "C", target: "D", value: 3 } ]; ``` 然后,您需要定义一个SVG容器来容纳您的形: ```javascript var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); ``` 接下来,您可以使用d3.forceSimulation()方法来创建一个导向的仿真器,并使用d3.forceLink()和d3.forceManyBody()方法来定义链接和节点之间的。 ```javascript var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.id; })) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); ``` 最后,您可以使用d3.select()和d3.selectAll()方法来选择和绘制节点和链接。 ```javascript var link = svg.append("g") .attr("class", "links") .selectAll("line") .data(links) .enter().append("line") .attr("stroke-width", function(d) { return Math.sqrt(d.value); }); var node = svg.append("g") .attr("class", "nodes") .selectAll("circle") .data(nodes) .enter().append("circle") .attr("r", 5) .attr("fill", function(d) { return color(d.group); }) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); ``` 以上是一个简单的导向绘制过程,如果您需要更多高级的控制,您可以查看d3.js的官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值