d3.js树图示例demo

转载:d3.js树图示例 (juejin.cn)

前言

本文总结了d3.js中绘制树图的基本过程

 

完整代码:

GitHub地址
CodePen地址

原理阐述

其实用d3.js构建树图非常简单,主要用到的是如下几个API

  • const hierarchyData = d3.hierarchy(data) - 将层级数据进一步精细化
  • const treeLayout = d3.tree() - 获取layout
  • const nodesData = treeLayout( hierarchyData ) - 通过layout获得易于d3方便绘图的数据

以上的api会在后文进行解释,如果读者对**d3布局(layout)**不了解可以参阅本人之前的总结:d3.js 布局(layout)是什么,也欢迎大家提出宝贵建议

以下流程图是对整个逻辑的简单展示

 

接下来会分布对代码进行说明

代码

初始标签及数据

<svg class="chart">

</svg>
复制代码
const data = {
    name: "root",
    children: [
        {
            name: "二级节点1",
            children: [
                {
                    name: "A",
                    value: "叶子节点"
                },
                {
                    name: "B",
                    value: "叶子节点"
                }
            ]
        },
        {
            name: "二级节点2",
            children: [
                {
                    name: "C",
                    value: "叶子节点"
                },
                {
                    name: "D",
                    value: "叶子节点"
                }
            ]
        }
    ]
};
复制代码

这是本次实验的初始数据,以root为根节点,children中放置子节点,子节点也有其后裔节点。此例中以三层为例。
后文中,d3.hierarchy函数默认处理数据中节点属性名为children,此处我们直接将子节点数组属性设置为children

接下来是设置宽度,高度,及g容器

const width = 1366;
const height = 580;
const svg = d3.select('.chart')
    .attr('width', width)
    .attr('height', height);
const g = svg.append('g').attr('transform', 'translate(0, 20)');
复制代码

获得进一步层级化的数据

const hierarchyData = d3.hierarchy(data);
console.log("——————d3.hierarchy(data)——————");
console.log(hierarchyData);
复制代码

 

我们可以看到,相对初始数据,经过d3.hierarchy处理后,节点的数据类型变为了Node(Object),同时返回了相应的depth及height

接下来我们获取layout

获取layout

const treeLayout = d3.tree()
    .size([width, height - 30])  //设置tree的大小
    .separation((a, b) => {      // 根据是否为同一父节点设置节点距离比例
        return a.parent === b.parent ? 1 : 2;
    });
console.log("——————treeLayout——————");
console.log(treeLayout);
复制代码

 

我们可以看到d3.tree()返回的就是一个函数

接下来就是把hierarchyData交给treeLayout处理获得便于绘图的数据了

使用treeLayout获取易于绘图的数据

const nodesData = treeLayout(hierarchyData);
console.log("——————nodesData——————");
console.log(nodesData);
复制代码

 

我们可以看到经过treeLayout处理返回的数据多了x、y属性,它们定位了在图中的位置,绘图时我们会用到它们

同时也注意layout函数并不是纯函数,由于是引用,原先的hierarchyData数据也变得如上,大家可以在控制台中自行查看

开始绘图

现在我们已经有定位了位置的数据了,接下来要做的非常简单,就是根据这些x,y来画线,画节点

先画线

const links = g.selectAll('.links')
    .data(nodesData.descendants().slice(1)) //nodesData.descendants()返回所有节点的数据,利于我们绑定数据,slcie(1)截取root后的全部节点,防止重绘
    .enter().append('path') //用path画线
    .attr('fill', 'none')
    .attr('stroke', '#313131')
    .attr('stroke-width', 2)
    .attr('d', (d) => {//通过三次贝塞尔曲线设置连线的弯曲程度。M:move to,即到控制点 C后设置两个控制点及终点
        return `
        M${d.x},${d.y}
        C${d.x},${(d.y + d.parent.y) / 2}
        ${d.parent.x},${(d.y + d.parent.y) / 2.5}
        ${d.parent.x},${d.parent.y}`;
    });
复制代码

最后结果如下:

 

接下来是画圆

//当一个节点中有多个子元素时(比如本例中有text和circle),我个人喜欢用g作为容器
const nodes = g.selectAll('.node')
    .data(nodesData.descendants()) //同样是获得所有节点,便于数据绑定
    .enter().append('g')
    .attr('transform', (d) => {
        return `translate(${d.x}, ${d.y})`;//位移
    });
//画圆 
nodes.append('circle')
    .style('fill', '#c03027')
    .attr('r', 10);
//插入文字
nodes.append('text')
    .attr('dx', '.9em')
    .text((d) => {
        return d.data.name;
    });
复制代码

 

至此,已经完成一个基本的树图。

结语

整个步骤下来我们可以发现并不是特别难,只要理解了layout及知道了如何处理层级数据即可以画出一个树图。

参考资料

d3.js API——d3.tree()
d3.js API——Hierarchy
d3.js API——node.descendants()
Tree Layout Orientations
Tidy Tree

### 使用D3.js实现图可视化 #### D3.js简介及其优势 D3.js是一个用于通过可编程方式操作基于数据的文档的JavaScript库。它利用HTML、SVG以及CSS来创建丰富的交互式图表和图形界面[^1]。 相比于其他的数据可视化工具,如ECharts,在灵活性方面,D3.js提供了更底层的操作能力,允许开发者完全自定义视觉效果;而在性能表现上,对于大规模复杂数据集处理时也展现出色的能力。特别是当涉及到定制化需求较高的场景下,比如构建特定结构的形图,D3.js无疑是更好的选择。 #### 创建图的基础准备 为了能够顺利地使用D3.js绘制状图,建议先掌握以下几个方面的基础知识: - **熟悉HTML/CSS/JS**: 这些是Web前端开发的核心技术栈; - **理解JSON格式**: 大多数情况下,输入给D3.js的数据源都是以这种轻量级交换格式呈现出来的; - **学习SVG基本概念**: 作为矢量图形标准之一,SVG非常适合用来描述复杂的二维图像,而D3.js正是依赖于该技术来进行绘图工作。 #### 实现过程概述 具体到实际编码环节,则可以按照如下思路展开: ##### 准备环境并加载必要的资源文件 确保页面中已经引入了最新的d3.min.js版本,并设置好容器元素以便后续挂载生成的内容。 ```html <script src="https://d3js.org/d3.v7.min.js"></script> <div id="tree-container"></div> ``` ##### 定义数据模型 通常来说,型结构可以用嵌套的对象数组表示出来,其中每个对象代表一个节点,包含名称和其他属性字段。 ```javascript const data = { name: &#39;root&#39;, children: [ {name: &#39;childA&#39;}, {name: &#39;childB&#39;, children:[ {name:&#39;subChild&#39;} ]} ] }; ``` ##### 构建布局算法实 借助内置函数`d3.tree()`或者其变体形式(如`d3.cluster()`),可以根据传入的数据自动计算出各个节点的位置坐标信息。 ```javascript let treeLayout = d3.tree().size([width, height]); // 或者采用聚类样式显示 // let clusterLayout = d3.cluster().size([height, width]); ``` ##### 绘制链接线与节点标记 最后一步就是运用之前提到过的SVG特性,分别针对连接边和顶点部分编写对应的DOM片段,再经由D3的选择器机制附加至目标区域之下。 ```javascript svg.append(&#39;g&#39;) .selectAll(&#39;.link&#39;) .data(treeLayout.links(nodes)) .enter() .append(&#39;path&#39;) .attr(&#39;class&#39;,&#39;link&#39;) .attr(&#39;d&#39;,d=>`M${d.source.x},${d.source.y}C${(d.target.x+d.source.x)/2},${d.source.y}, ${(d.target.x+d.source.x)/2},${d.target.y},${d.target.x},${d.target.y}`); svg.selectAll(&#39;.node&#39;) .data(nodes) .enter() .append(&#39;circle&#39;) .attr(&#39;r&#39;,5); ``` 上述代码展示了如何用最简单的线条和圆形来表达父子关系链路及端点位置。 #### 高级功能拓展 除了以上介绍的基本形态之外,还可以进一步探索更加多样化的展现手法,如带有标签说明的路径文字标注[^2],或是尝试不同的分支排列模式等,从而满足不同应用场景下的特殊要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值