D3.js创建力导向图(V4)附带详细的参数说明

版权声明:转载请声明原地址 https://blog.csdn.net/dk2290/article/details/83510655

一.效果展示

在这里插入图片描述

二.代码示例

<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>D3 test</title>
</head>

<body>
    <div class="container">
        <div id="graph"></div>
    </div>
</body>

</html>
<script src="/static/js/d3-v4.js"></script>
<script>

    var nodes = [ { name: "桂林" }, { name: "广州" },
              { name: "厦门" }, { name: "杭州" },
              { name: "上海" }, { name: "青岛" },
              { name: "天津" } ];

    var links = [ { source : 0 , target: 1 } , { source : 0 , target: 2 } ,
               { source : 0 , target: 3 } , { source : 1 , target: 4 } ,
               { source : 1 , target: 5 } , { source : 1 , target: 6 } ];

    var width = 800;
    var height = 600;
    var svg = d3.select("#graph")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .call(d3.zoom() //创建缩放行为
            .scaleExtent([-5, 2])
            .on('zoom',zoom_actions)); //设置缩放范围
        
   


    //初始化力学仿真器,通过布局函数格式化数据    
    var simulation = d3.forceSimulation(nodes)
        .force("link", d3.forceLink(links).distance(100))   //distance设置连线距离
        .force("charge", d3.forceManyBody().strength(-100))  //注1> 
        .force("center", d3.forceCenter(width / 2, height / 2))  //设置力学仿真器的中心
        .on("tick", ticked);  
	
	//布局函数格式化后的数据,注2>
	console.log('nodes', nodes);
    console.log('links', links);  
    
    var color = d3.scaleOrdinal(d3.schemeCategory20);  //生成颜色选择器函数,此函数返回颜色数组 (string [])
    
     //添加group包裹svg元素以进行缩放,目的是在缩放时不会影响整个容器的位置
    var g = svg.append("g")
    .attr("class", "everything");

    // 绘制连线
    var svg_links = g.append('g')
        .selectAll("line")
        .data(links)
        .enter()
        .append("line")
        .style("stroke", "#ccc")
        .style("stroke-width", 3)
        

    // 绘制节点    
    var svg_nodes = g.append('g')
        .selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("r", '20')
        .style("fill", function (d, i) {
            return color(i);
        }).call(d3.drag().on("start", dragstarted) //d3.drag() 创建一个拖曳行为
          .on("drag", dragged)
          .on("end", dragended));
   
    //绘制描述节点的文字
    var svg_texts =  g.append('g')
        .selectAll("text")
        .data(nodes)
        .enter()
        .append("text")
        .style("fill", "black")
        .attr("dx", 20)
        .attr("dy", 8)
        .text(function (d) {
            return d.name;
        });

    //监听拖拽开始    
    function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart(); //alpha是动画的冷却系数,运动过程中会不断减小,直到小于0.005为止,此时动画会停止。
        d.fx = d.x;    //fx为固定坐标,x为初始坐标  注3>  
        d.fy = d.y;
    }

    //监听拖拽中  
    function dragged(d) {
        d.fx = d3.event.x;  //fevent.x为拖拽移动时的坐标
        d.fy = d3.event.y;
    }

    //监听拖拽结束
    function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;        //固定坐标清空
        d.fy = null;
    }

    function zoom_actions() { 
        g.attr("transform", d3.event.transform)
     }

    //拖拽时的事件监听器  以实时更新坐标
    function ticked() {
        svg_links.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;
            });

        svg_nodes.attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            });

        svg_texts.attr("x", function (d) {
                return d.x;
            })
            .attr("y", function (d) {
                return d.y;
            });
    }

</script>

三.注释详解


相关函数的说明在代码的注释中已经写的很清楚了,下面我针对以上注释中的注1>,2>,3>做一些详细的解释。

1> forceManyBody()函数为创建多体力函数,strength为相互作用力,正的为吸力,负的为斥力,何为多体力?你可以把它理解成是一个创建作用力,设置作用力阈值和计算作用力大小的高阶函数

这是github上D3.js对于forceManyBody()的解释。

在这里插入图片描述


简单来说,就是此函数可以创建一个带参的多体力对象,此对象中有一些函数,咱们可以调用,具体有如下几个函数:

在这里插入图片描述
strength,distanceMindistanceMax都是字面意思,无需多说,我稍微解释下theta函数。


我先放上github官网上对于此manyBody.theta()函数的解释。
在这里插入图片描述
什么意思呢?简单来说,就是这个函数用来计算你每个节点所受到的其他所有节点的合力的近似值,而theta函数就是用来设置此近似值的精度,官方给了一个默认值是0.9。

我们可以看到,这个函数依赖的是Barnes-Hut算法,那么何为Barnes-Hut?

Barnes-Hut算法是一种用于实现N体问题(n-body)模拟的近似算法。

以下是维基百科的解释
在这里插入图片描述
上面那一堆东西就是说,这个算法是从节点的根数据开始递归,并遵循一定的原则,最终计算出合力。具体规则如下:

1.如果当前节点是一个外部节点(而且它不是物体bb),计算当前节点施加在物体bb上的力,并将其加到bb的合力上。
2.计算商s/ds/d的值。如果s/d<θs/d<θ,将这个内部节点看成一个单独的物体
3.计算其施加在物体bb上的力,并将其加到bb的合力上。否则,在当前节点的每个孩子节点上递归地执行上述步骤。


2>,3>原始数据被布局函数转化后使什么格式呢?我们可以看下打印后的结果。

在这里插入图片描述
以上参数什么含义呢?

index - 节点的索引号
vx, vy - 节点上一个时刻的坐标
x, y - 节点的当前坐标

拖拽函数中的fx,就对应着节点中的x,是节点的初始横坐标;fy就对应着节点中的y,是节点的初始纵坐标。

四.参考文章


【1】D3.js GitHub
【2】D3.js 4.x API中文手册
【3】Barnes-Hut算法(quad-tree的一个应用)

猜你喜欢

转载自blog.csdn.net/dk2290/article/details/83510655