D3 二维图表的绘制系列(十七)树图

D3js快速入门——用最新版D3js实现树图 文章目录:引言1. D3js 是什么2. D3js 相对其他数据可视化方案的优势2.1 SVG 对比 Canvas2.2 D3.js 对比 Echarts3. 怎么用 D3.js 开发一个树图3.1 前置基础3.2 d3开发树图流程3.3 动手实现一个树图3.3.1 普通tide tree3.3.2 你的树图不简单—— radio tide tree3.3.3 更多可能——更多类型的树图 引言 上周我们组新开项目,技术调研之后决定使用 d3.js 做数据可视化开发,mentor让我来做初期技术调研,之后的技 阅读详情

上一篇: 矩形树图 https://blog.youkuaiyun.com/zjw_python/article/details/98489369

下一篇: 漏斗图 https://blog.youkuaiyun.com/zjw_python/article/details/98497967

代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article/details/98182540

本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/master/src/treeChart/basicTreeChart

1 图表效果

在这里插入图片描述

2 数据

{
    "name": "grandfather",
    "children": [
        {
            "name": "father",
            "children": [
                {
                    "name": "son",
                    "children": [
                        {"name": "grandson1", "house": 2},
                        {"name": "grandson2", "house": 3},
                        {"name": "grandson3", "house": 4}

                    ]
                }
            ]
        },
        {
            "name": "mother1",
            "children": [
                {
                    "name": "daughter1",
                    "children": [
                        {"name": "granddaughter1", "house": 4},
                        {"name": "granddaughter2", "house": 2}
                    ]
                },
                {
                    "name": "daughter2",
                    "children": [
                        {"name": "granddaughter3", "house": 4}
                    ]
                }
            ]
        },
        {
            "name": "mother2",
            "children": [
                {
                    "name": "son1",
                    "children": [
                        {"name": "grandson4", "house": 6},
                        {"name": "granddaughter4", "house": 1}
                    ]
                },
                {
                    
                    "name": "son2",
                    "children": [
                        {"name": "granddaughter5", "house": 2},
                        {"name": "grandson5", "house": 3},
                        {"name": "granddaughter5", "house": 2}
                    ]
                    
                }
            ]
        }

    ]
}

3 关键代码

导入数据

d3.json('./data.json').then(function(data){
....

一些样式参数配置,例如节点,线条的颜色等

const config = {
        margins: {top: 80, left: 50, bottom: 50, right: 50},
        textColor: 'black',
        title: '基础树图',
        hoverColor: 'gray',
        animateDuration: 1000,
        pointSize: 5,
        pointFill: 'white',
        pointStroke: 'red',
        paddingLeft: 20,
        lineStroke: 'gray'
    }

数据转换,树图与矩阵树图类似,都是树形层次性数据结构,因此需要将数据转化为一系列节点,对于树图,其布局算法是d3.tree,传入处理后的数据后,将自动为每个节点添加布局信息

/* ----------------------------数据转换------------------------  */
	chart._nodeId = 0;  //用于标识数据唯一性
	
    const root = d3.hierarchy(data);

    const generateTree = d3.tree()
                    .size([chart.getBodyHeight(), chart.getBodyWidth()*0.8]);
    
    generateTree(root);

渲染树的节点,其实渲染出树的节点很简单,直接使用circle元素就可以了,难点在于过渡的动画效果,我们想做出类似于Echart树图的效果,点击节点时会放缩子树,并重新布局。要做到这种效果就必须对节点的各个阶段,enter,update和exit添加对应的动画效果。

/* ----------------------------渲染节点------------------------  */
    chart.renderNode = function(){

        const groups = chart.body().selectAll('.g')
                                    .data(root.descendants(), (d) => d.id || (d.id = ++chart._nodeId));

        const groupsEnter = groups.enter()
                                    .append('g')
                                    .attr('class', (d) => 'g g-' + d.id)
                                    .attr('transform-origin', (d) => {    //子树从点击位置逐渐放大
                                        if (d.parent){
                                            return chart.oldY + config.paddingLeft + ' ' + chart.oldX;
                                        }
                                        return d.y + config.paddingLeft + ' ' + d.x;
                                    })
                                    .attr('transform', (d) => {    //首次渲染进入不放缩
                                        if (d.parent && chart.first) return 'scale(0.01)' + 'translate(' + (chart.oldY + config.paddingLeft) + ',' + chart.oldX + ')';
                                        return 'scale(1)' + 'translate(' + (d.y + config.paddingLeft) + ',' + d.x + ')';
                                    })
                      
              groupsEnter.append('circle')
                            .attr('r', config.pointSize)
                            .attr('cx', 0)
                            .attr('cy', 0)
                            .attr('fill', config.pointFill)
                            .attr('stroke', config.pointStroke);

              groupsEnter.merge(groups)
                            .transition().duration(config.animateDuration)
                            .attr('transform', (d) => 'translate(' + (d.y + config.paddingLeft) + ',' + d.x + ')')
                            .select('circle')
                                .attr('fill', (d) => d._children ? config.hoverColor : config.pointFill);
            
              groups.exit()   
                        .attr('transform-origin', (d) => (chart.targetNode.y + config.paddingLeft) + ' ' + chart.targetNode.x)  //子树逐渐缩小到新位置
                        .transition().duration(config.animateDuration)
                        .attr('transform', 'scale(0.01)')
                        .remove();
        

    }

树的节点渲染好了,那么节点的文本标签位置也就定了下来

/* ----------------------------渲染文本标签------------------------  */
    chart.renderText = function(){
        d3.selectAll('.text').remove();

        const groups = d3.selectAll('.g');

        groups.append('text')
              .attr('class', 'text')
              .text((d) => d.data.name.length<5?d.data.name:d.data.name.slice(0,3) + '...')
              .attr('dy', function(){
                  return chart.textDy || (chart.textDy = this.getBBox().height/4);
              })
              .attr('text-anchor', (d) =>{
                  return d.children ? 'end' : 'start';
              })
              .attr('dx', (d) =>{
                return d.children ? -config.pointSize*1.5 : config.pointSize*1.5;
            });
    }

接下来渲染节点之间的连线,这里使用d3.path绘制贝塞尔曲线,并选取两节点的中间点作为控制点,过渡动画效果与节点类似,通过scale实现

/* ----------------------------渲染连线------------------------  */
    chart.renderLines = function(){
        const nodesExceptRoot = root.descendants().slice(1);

        const links = chart.body().selectAll('.link')
                                .data(nodesExceptRoot, (d) => d.id || (d.id = ++chart._nodeId));
        
              links.enter()
                     .insert('path', '.g')
                     .attr('class', 'link')
                     .attr('transform-origin', (d) => {
                        if (d.parent){           //连线从点击位置逐渐放大
                            return chart.oldY + config.paddingLeft + ' ' + chart.oldX;
                        }
                        return d.y + config.paddingLeft + ' ' + d.x;
                    })
                    .attr('transform', (d) => {                //首次渲染进入不放缩
                        if (d.parent && chart.first) return 'scale(0.01)';
                        return 'scale(1)';
                    })
                   .merge(links)
                     .transition().duration(config.animateDuration)
                     .attr('d', (d) => {
                        return generatePath(d, d.parent);
                     })
                     .attr('transform', 'scale(1)')
                     .attr('fill', 'none')
                     .attr('stroke', config.lineStroke)
              
              links.exit()
                     .attr('transform-origin', (d) => {    //连线逐渐缩小到新位置
                         return chart.targetNode.y + config.paddingLeft + ' ' + chart.targetNode.x;
                     })
                     .transition().duration(config.animateDuration)
                     .attr('transform', 'scale(0.01)')
                     .remove();
        
        function generatePath(node1, node2){
            const path = d3.path();

            path.moveTo(node1.y + config.paddingLeft, node1.x);
            path.bezierCurveTo(
                                (node1.y + node2.y)/2 + config.paddingLeft, node1.x, 
                                (node1.y + node2.y)/2 + config.paddingLeft, node2.x, 
                                node2.y + config.paddingLeft, node2.x
                              );
            return path.toString();
        }
    }

最后绑定鼠标交互事件,当点击某个节点隐藏子树时,将其children属性设置为null,并暂存其子树数据,重新触发布局。当点击某各节点显现子树时,将暂存的子树数据拿出并重新赋值children属性,并重新布局,如此达到子树切换的效果。

/* ----------------------------绑定鼠标交互事件------------------------  */
    chart.addMouseOn = function(){

        d3.selectAll('.g circle')
            .on('click', function(d){
                toggle(d);
                generateTree(root);
                chart.renderNode();
                chart.renderLines();
                chart.renderText();
                chart.addMouseOn();
            });

        function toggle(d){
            chart.first = true;
            if (d.children){
                d._children = d.children;
                d.children = null;
            }else{
                d.children = d._children;
                d._children = null;
            }
            chart.oldX = d.x;  //点击位置x坐标
            chart.oldY = d.y;  //点击位置y坐标
            chart.targetNode = d;  //被点击的节点
        }
    }

大功告成!!!


如果觉得这篇文章帮助了您,请打赏一个小红包鼓励作者继续创作哦!!!

在这里插入图片描述

d3.js绘制树形图 最新版(v7)d3.js绘制树形图,网上搜到的大多使用低版本的绘制,只好自己摸索一下了! 阅读详情

相关推荐

D3 二维图表的绘制系列(一)介绍

1 介绍 D3 (或者叫 D3.js )是一个基于 web 标准的 JavaScript 可视化库. D3 可以借助 SVG, Canvas 以及HTML 将你的数据生动的展现出来. D3 结合了强大的可视化交互技术以及数据驱动 DOM 的技术,让你可以借助于现代浏览器的强大功能自由的对数据进行可视化 学习了d3一个多月,通过绘制一些简单的二维图表,总算入门了d3。强烈推荐《D3数据可视化实战...

zjw_python的博客 6万+

d3 tree 实现双向动画树总结

使用d3.js 实现双向tree,并实现节点展开收起动画。使用svg 绘制。

japlus的博客 3168

【D3.js Tidy tree绘制树形图,单棵树,左右树,平移,拖拽,树形中的天花板实现,源码实现】

D3.js Tidy tree绘制树形图,单棵树,左右树,平移,拖拽,树形中的天花板实现,源码实现

『梁超』博弈人生-JAVA地盘 2159

D3 绘制 树图(tree) 笔记

绘制一个树形图分为四部 选中页面设置的svg绘制区域的宽高 添加g元素 设置位置 生成树状布局,设置尺寸 对角线生成器 请求数据 获取节点数组和连线数组 绘制连线 绘制节点 给节点添加圆圈设置半径 给节点添加文本 设置文本样式 位置   本地连接json会出现跨域问题 需要用http-server启动本地服...

肖皓文 5888

PyTorch ModelNet点云数据集加载实战:从下载到Dataset类完整实现

在三维视觉与点云处理领域,数据集是算法研发的基石。ModelNet作为三维物体分类的基准数据集,其地位类似于图像领域的MNIST,是入门和评估模型性能的通用标准。理解其数据格式与加载原理,是进行点云分类、分割等任务的关键前置步骤。通过PyTorch的Dataset类,开发者可以构建高效的数据管道,将原始点云文件转换为神经网络可直接处理的张量格式,这一过程涉及数据采样、归一化、特征组装等核心操作,直接影响模型的训练效率和最终性能。本文聚焦于ModelNet10/40数据集,详细解析其目录结构,并提供一套稳健的

weixin_29032337的博客 282

单目标跟踪算法及其复现过程---SiamFC(一)

在test.py文件中,就是利用训练出来的模型进行测试,需要更改预训练模型的路径,测试集的路径,以OTB100为例,最后输出的是对每一帧目标位置的坐标点。代码如下:首先需要下载got10k官方库,只需要在终端输入(注意:在终端安装各种库的时候不能使用网络代理),在环境已经配置到的情况下,只需要该其中的路径和就可以运行。这个系列博客仅为了记录各目标跟踪算法的复现(大多为跑通大佬们实现的代码),包括其中出现的很多问题和错误,学到的新知识等等。解决,而且只使用在线的方法,限制了他们可以学习的模型的丰富性。

weixin_58244117的博客 4761

D3.js-基础知识

数据可视化已变得越来越被重视,市面上也出现了越来越多的图标库,如Highcharts。图标库很容易可以上手,然而在当前注重用户交互的时代,其不易交互性突显的越来越明显。 一、数据可视化数据可视化起源于18世纪,当时使用柱形图和折线图来表示国家进出口量。近年,随着大数据时代的到来,数据可视化作为大数据量的呈现方式,成为当前重要的课题。数据可视化的目的,是要对数据进行可视化处理,以使得能够明确地、有效地

李刚的学习专栏 1万+

手把手教你用西门子博图V18配置阿特拉斯PF6000拧紧枪PN通讯(附完整GSD文件与ToolsTalk配置文件)

本文详细介绍了如何使用西门子博图V18配置阿特拉斯PF6000拧紧枪的PN通讯,包括硬件连接、网络参数规划、ToolsTalk软件配置及博图工程设置。通过完整的GSD文件和配置文件,帮助工程师快速实现高精度拧紧设备与PLC的高效通讯,适用于汽车装配和电子制造等工业自动化场景。

weixin_42662293的博客 602

【D3.js - v5.x】(6)绘制树状图 | 层级布局 | 附完整代码

树状图 在d3 中,绘制树状图,要用到层级布局这个概念: d3.hierarchy(data[, children]) 根据指定的层次结构数据构造一个根节点。指定的数据 data 必须为一个表示根节点的对象。比如: { "name": "Eve", "children": [ { "name": "Cain" }, { "name": "S.........

前端进阶之路 | 中大厂、外企、国企内推 | 面试培训 | 简历修改 6389

STM32F407 HAL库定时器触发ADC采集与DMA数据传输(定时器TIM+ADC+DMA)

在STM32F407系列微控制器的开发中,结合定时器、ADC(模数转换器)与DMA(直接存储器访问)控制器,能够显著提升数据采集与传输的效率。本文将指导你如何使用STM32 HAL库,通过定时器触发ADC1的单通道采集,利用DMA传输数据,最终通过串口将电压值打印出来。具体实现中,我们将读取ADC1的通道5(对应引脚PA5),并将转换得到的电压值发送到串口助手上进行显示。

jmlinux的博客 7012

从零开始的 AI Infra 学习之路

AI Infra(AI 基础设施)是指为上层的 AI 算法应用提供支持的 AI 全栈底层技术,通过合理利用计算机体系结构,可以实现 AI 计算的加速和部署。AI Infra 主要包括以下内容:AI 训练框架 & 推理引擎;AI 编译 & 计算架构;AI 硬件 & 体系结构。参考资料:;。

AI Infra / LLM / 软件开发 3万+

D3最新版本实现组织型tree结构,包含拖拽、缩放、平移、折叠、异步加载节点自定义渲染等功能

import { PureComponent } from 'react' import { D3 } from "@weapp/ui" let d3: any = null; //辅助函数: 递归获取tree的节点数量 function getCount(parent: any) { var count = 0; if (Array.isArray(parent.children)) { count += parent.children.length; parent.chil..

qq_44621394的博客 2098

ptrade量化策略之ST股弱转强,回测年化115%

本策略的核心是精选ST股票,国九条过滤,防止直接暴雷退市,只做ST股票的弱转强

qq_29301281的博客 1785

D3.js绘制树形图

1、什么是D3: data-driven-document,翻译为数据驱动的文档,是一种由数据来决定绘图流程的程序设计模型。简单说,D3是一个JavaScript的函数库,用来做数据可视化(将数据的各种属性和变量以图形图表的形式呈现出来)。 2、D3的优点: 前端可视化库:Hightcharts(付费)、Echarts、Chart等可以看做一类(是被封装好的库),使开发者很容易的就能制作图表(只需修改一下数据即可),但是能够给与开发者设计和控制的空间太少(个人...

xinxiaoyong的博客 7929

手把手教你学simulink(57.2)--电励磁同步电动机场景示例:基于Simulink的矢量控制(Field-Oriented Control, FOC)电励磁同步电动机

在某电动汽车驱动系统中,采用了本项目开发的带有矢量控制功能的电励磁同步电动机驱动系统,结合三相逆变器实现了对电动机的高效控制。在某工业驱动系统中,采用了本项目开发的带有矢量控制功能的电励磁同步电动机驱动系统,结合三相逆变器实现了对电动机的精确控制。经过实际测试,该系统的应用使得生产效率提高了10%,并且在高负载条件下,电动机的温升得到了有效控制,延长了电动机的使用寿命。通过本项目的实施,我们成功配置了三相交流电源、三相逆变器和电励磁同步电动机的参数,并实现了对电动机的精确控制。

MHD0815的博客 944

四舵轮底盘运动学模型(源码)(四轮四独立转向)二

舵轮4转向活动范围 x 轴正半轴,x轴正方向为0弧度,左正右负, -M_PI/2 < 转向范围 < M_PI/2;移动底盘的正前方为x方向,左侧为y轴方向(遵循右手坐标系,右手大拇指指向天空为z轴方向,食指与中指垂直,食指指向小车正前方为x轴,中指指向为移动底盘y轴方向)转向:逆时针旋转角速度w为正,顺时针旋转角速度w为负。(遵循右手螺旋法则,右手握拳大拇指指向天空为旋转z轴方向,拳垂直于地面,4指方向即底盘转动的正方向)左前轮为1号轮,右前轮为2号轮,左后轮为3号轮,右后轮为4号轮。

苏凯的博客 527

D3 数据可视化 文字二叉树绘制

【代码】D3 数据可视化 文字二叉树绘制。

DoKiDoK的博客 262

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

d3tree树控件,点击动态加载,默认展开三层

// 5 给节点添加文本 设置文本样式 位置 nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) .attr("dy", ".35em")

qq_38687592的博客 1546

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

d3.js Tree

一、功能: 1.增加节点 2.删除节点 3.上下移动节点 4.保存 5.画布可放大缩小 6.单击节点选中,双击节点折叠 二、知识点: 1.D3.js(官网:D3.js - Data-Driven Documents)(我是小白) echarts和D3的作用相似,那他们有什么不同之处呢?我觉得他们之间最大的不同之处就在于echarts它是使用canvas来绘制图形的,而D3是通过Svg来绘制图形的。这两者的不同之处在于,svg可以操作...

weixin_51045106的博客 1899

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

D3(V7)树图绘制-数据可视化

点击对应的点可以在下方显示该地点的简介。鼠标停在某个点上该点会变色(图中没有体现出来) 数据来源:建筑-故宫博物馆 v7版本的资料实在太少了,所以写完记录一下……主要是记录v3和v7版本的差异 核心布局代码是这一句。一共有3种可写形式,最后出来的结果图形布局也不一样。 <script> var tree=d3.cluster() .size([width,height*0.7]); //d3.tree().size([2*Math.PI, radius -..

菜鸟写写 1438

d3.tree树图

&lt;!DOCTYPE html&gt;   &lt;meta charset="utf-8"&gt;   &lt;title&gt;tree&lt;/title&gt; &lt;script src="http://apps.bdimg.com/libs/d3/3.4.8/d3.min.js"&gt;&lt;/script&gt; &lt;script src=

songqiang2011的博客 5802

D3.js学习笔记十五:D3.js树图(Tree)展开和折叠

构图(d3.layout)——树图(Tree)的展开和折叠 树的基本操作就是展开和折叠,在D3里面,树的展开和折叠是通过设置树的子节点属性来实现的,tree.nodes(root)返回树的当前节点集合,通过操作这个集合,可以实现节点的动态变化。 children - the array of child nodes, or null for leaf nodes. x - the

小飞侠的博客 1万+

D3树图

介绍 树状图由两个部分组成节点node和连接线link组成,link是一个路径,而node是一个组由text和circle组成,D3能够帮助我们计算路径,计算节点的位置. 示例 https://tinuv.top/MyPages/tree/tree.html 初始化 var width = 1000; var height = 1000; var padd...

测试 960

D3 Tree

D3生成树

weixin_39967005的博客 1067

使用vue.js+d3生成树以及遇到的坑

vue项目中使用d3实现树结构1. vue.js安装vue.js2. d3安装d3vue中引入3. 代码部分(1)生成树实现(2)如果想要树的连接线是直线(3)处理文字溢出,溢出部分显示...a. 坑1(4)鼠标点击提示框显示完整标题(5)全部样式a. 坑2(6)HTML部分坑34. 结果展示5. 完整代码结语 1. vue.js 安装vue.js 最新稳定版本 $ npm install vue...

qq_37842366的博客 4160

【亲测免费】 React D3 Tree 使用教程

React D3 Tree 是一个基于 React 和 D3.js 的开源项目,用于在网页上展示树状结构数据。它结合了 React 的组件化和 D3.js 的数据驱动文档(Data-Driven Documents)特性,使得开发者可以轻松地在 React 应用中嵌入交互式的树状图。 ## 项目快速启动 ### 安装 首先,你需要在你的 React 项目中安装 `react-d3-tree`...

gitblog_00693的博客 936
上一篇: D3 二维图表的绘制系列(十六)矩形树状图
下一篇: D3 二维图表的绘制系列(十八)漏斗图
PAT-python-zjw
博客等级 码龄10年 381粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值