d3数据可视化实践-径向树

效果图展示:

实现思路:

使用 D3.js 的 d3.tree()d3.stratify() 来创建树布局,并将其转换为径向布局。

实现步骤

1、svg

html中准备一个svg元素,也可以通过js创建

arduino 复制代码
<svg width="600" height="600"></svg>

确定画布大小、径向图半径

ini 复制代码
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = Math.min(width, height) / 2;

2、创建树布局

scss 复制代码
 const tree = d3.tree().size([2 * Math.PI, radius - 100]); //角度2PI,半径radius - 100

 // 使用 d3.hierarchy 将数据转换为树结构
  const root = d3.hierarchy(data);
  
  // 布局树
  tree(root);

3、创建一个组元素,控制径向图居中

ini 复制代码
const g = svg.append("g").attr("transform", `translate(${width / 2},${height / 2})`);

4、绘制连线

javascript 复制代码
//径向链接生成器类似于笛卡尔链接生成器,只是x和y访问器被角度和半径访问器取代。
//返回具有径向切线的新链接生成器
const linkRadial = d3
      .linkRadial()
      .angle((d) => d.x)
      .radius((d) => d.y)

//绘制连线
const link = g.selectAll(".link")
      .data(root.descendants().slice(1)) //过滤掉顶层节点
      .enter().append("path")
      .attr("class", "link")
      .attr("d", d => {
        return linkRadial({ source: d, target: d.parent })
      });

5、绘制节点

javascript 复制代码
const node = g.selectAll(".node")
      .data(root.descendants())
      .enter().append("g")
      .attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
      .attr("transform", d => `rotate(${(d.x - Math.PI / 2) / Math.PI * 180}) translate(${d.y},0)`);

6、添加节点圆圈

go 复制代码
node.append("circle")
      .attr("r", 4.5);

7、添加节点文本

javascript 复制代码
node.append("text")
      .attr("dy", ".31em")
      .attr("x", d => d.x < Math.PI ? 8 : -8)
      .attr("text-anchor", d => d.x < Math.PI ? "start" : "end")
      .attr("transform", d => d.x >= Math.PI ? "rotate(180)" : "")
      .text(d => d.data.name);

8、完整代码

xml 复制代码
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Radial Tree with D3.js</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <style>
    .node {
      cursor: pointer;
    }

    .node circle {
      fill: #999;
    }

    .node text {
      font: 10px sans-serif;
    }

    .link {
      fill: none;
      stroke: #555;
      stroke-opacity: 0.4;
      stroke-width: 1.5px;
    }
  </style>
</head>

<body>
  <svg width="600" height="600"></svg>
  <script>
    const data = {
      name: "Root",
      children: [
        {
          name: "Child 1",
          children: [
            { name: "Grandchild 1" },
            { name: "Grandchild 2" },
          ],
        },
        {
          name: "Child 2",
          children: [
            { name: "Grandchild 3" },
            { name: "Grandchild 4" },
          ],
        },
      ],
    };

    const svg = d3.select("svg");
    const width = +svg.attr("width");
    const height = +svg.attr("height");
    const radius = Math.min(width, height) / 2;

    // 创建树布局
    const tree = d3.tree().size([2 * Math.PI, radius - 100]);

    // 使用 d3.hierarchy 将数据转换为树结构
    const root = d3.hierarchy(data);

    // 布局树
    tree(root);
    // 创建一个组元素,用于平移和缩放
    const g = svg.append("g").attr("transform", `translate(${width / 2},${height / 2})`);
    // 绘制连接线
    const linkRadial = d3
      .linkRadial()
      .angle((d) => d.x)
      .radius((d) => d.y)
    const link = g.selectAll(".link")
      .data(root.descendants().slice(1)) //过滤掉顶层节点
      .enter().append("path")
      .attr("class", "link")
      .attr("d", d => {
        return linkRadial({ source: d, target: d.parent })
      });

    // 绘制节点
    const node = g.selectAll(".node")
      .data(root.descendants())
      .enter().append("g")
      .attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
      .attr("transform", d => `rotate(${(d.x - Math.PI / 2) / Math.PI * 180}) translate(${d.y},0)`);

    // 添加节点圆圈
    node.append("circle")
      .attr("r", 4.5);

    // 添加节点文本
    node.append("text")
      .attr("dy", ".31em")
      .attr("x", d => d.x < Math.PI ? 8 : -8)
      .attr("text-anchor", d => d.x < Math.PI ? "start" : "end")
      .attr("transform", d => d.x >= Math.PI ? "rotate(180)" : "")
      .text(d => d.data.name);
  </script>
</body>

</html>
相关推荐
xptwop36 分钟前
05-ES6
前端·javascript·es6
Heo41 分钟前
调用通义千问大模型实现流式对话
前端·javascript·后端
前端小巷子1 小时前
深入 npm 模块安装机制
前端·javascript·面试
深职第一突破口喜羊羊2 小时前
记一次electron开发插件市场遇到的问题
javascript·electron
cypking3 小时前
electron中IPC 渲染进程与主进程通信方法解析
前端·javascript·electron
西陵3 小时前
Nx带来极致的前端开发体验——借助playground开发提效
前端·javascript·架构
江城开朗的豌豆3 小时前
Element UI动态组件样式修改小妙招,轻松拿捏!
前端·javascript·vue.js
float_六七3 小时前
JavaScript:现代Web开发的核心动力
开发语言·前端·javascript
zhaoyang03014 小时前
vue3笔记(2)自用
前端·javascript·笔记
UrbanJazzerati4 小时前
JavaScript Promise完整指南
javascript