当前位置: 首页 > news >正文

nuxt、vue树形图d3.js

在这里插入图片描述

直接上代码

//安装
npm i d3 --save
<template><div class="d3"><div :id="id" class="d3-content"></div></div>
</template>
<script>
import * as d3 from "d3";export default {props: {data: Object,nodeWidth: {type: Number,default: 340,},nodeHeight: {type: Number,default: 40,},active: {type: String,default: "",},},data() {return {id: "TreeMap" + randomString(4),deep: 0,treeData: null,show: true,demoData: {label: "中国",// link: "demo",url: "https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD/1122445?fr=aladdin",children: [{label: "浙江45468761321",// link: "isClick",disabled: true,children: [{ label: "杭州999999999" },{ label: "宁波" },{ label: "温州" },{ label: "绍兴" },],},{label: "广西",children: [{label: "桂林56465465465464",children: [{ label: "秀峰区" },{ label: "叠彩区" },{ label: "象山区" },{ label: "七星区" },],},{ label: "南宁" },{ label: "柳州" },{ label: "防城港" },],},],},};},mounted() {this.$nextTick(() => {this.drawMap();window.handleCustom=this.handleCustom;});},methods: {drawMap() {let that = this;// 源数据let data = {};// 判断data是否为空对象if (this.data && JSON.stringify(this.data) !== "{}") {data = this.data;} else {data = this.demoData;}if (!this.treeData) {this.treeData = data;} else {// 清空画布d3.select("#" + this.id).selectAll("svg").remove();}let leafList = [];getTreeLeaf(data, leafList);let leafNum = leafList.length;let TreeDeep = getDepth(data);// 左右内边距let mapPaddingLR = 10;// 上下内边距let mapPaddingTB = 0;let mapWidth = this.nodeWidth * TreeDeep + mapPaddingLR * 2;let mapHeight = (this.nodeHeight - 4) * leafNum + mapPaddingTB * 2;// 定义画布—— 外边距 10pxlet svgMap = d3.select("#" + this.id).append("svg").attr("width", mapWidth).attr("height", mapHeight).style("margin", "0px");// 定义树状图画布let treeMap = svgMap.append("g").attr("transform","translate(" +mapPaddingLR +"," +(mapHeight / 2 - mapPaddingTB) +")");// 将源数据转换为可以生成树状图的数据(有节点 nodes 和连线 links )let treeData = d3.tree()// 设置每个节点的尺寸.nodeSize(// 节点包含后方的连接线 [节点高度,节点宽度][this.nodeHeight, this.nodeWidth])// 设置树状图节点之间的垂直间隔.separation(function (a, b) {// 样式一:节点间等间距// return (a.parent == b.parent ? 1: 2) / a.depth;// 样式二:根据节点子节点的数量,动态调整节点间的间距let rate =(a.parent == b.parent? b.children? b.children.length / 2: 1: 2) / a.depth;// 间距比例不能小于0.7,避免间距太小而重叠if (rate < 0.7) {rate = 0.7;}return rate;})(// 创建层级布局,对源数据进行数据转换d3.hierarchy(data).sum(function (node) {// 函数执行的次数,为树节点的总数,node为每个节点return node.value;}));// 贝塞尔曲线生成器let Bézier_curve_generator = d3.linkHorizontal().x(function (d) {return d.y;}).y(function (d) {return d.x;});//绘制边treeMap.selectAll("path")// 节点的关系 links.data(treeData.links()).enter().append("path").attr("d", function (d) {// 根据name值的长度调整连线的起点var start = {x: d.source.x,// 连线起点的x坐标// 第1个10为与红圆圈的间距,第2个10为link内文字与边框的间距,第3个10为标签文字与连线起点的间距,60为自定义htmly:d.source.y +10 +(d.source.data.link ? getPXwidth(d.source.data.link) + 10 : 0) +getPXwidth(d.source.data.label) +(!d.source.data.children?82:0) +20,};var end = { x: d.target.x, y: d.target.y };return Bézier_curve_generator({ source: start, target: end });}).attr("fill", "none").attr("stroke", "#00AB6B")// 虚线// .attr("stroke-dasharray", "8").attr("stroke-width", 1);// 创建分组——节点+文字let groups = treeMap.selectAll("g")// 节点 nodes.data(treeData.descendants()).enter().append("g").attr("transform", function (d) {var cx = d.x;var cy = d.y;return "translate(" + cy + "," + cx + ")";});//绘制节点(节点前的圆圈)groups.append("circle")// 树的展开折叠.on("click", function (event, node) {let data = node.data;if (data.children) {data.childrenTemp = data.children;data.children = null;} else {data.children = data.childrenTemp;data.childrenTemp = null;}that.drawMap();}).attr("cursor", "pointer").attr("r", 4).attr("fill", function (d) {if (d.data.childrenTemp) {return "#00AB6B";} else {return "white";}}).attr("stroke", "#00AB6B").attr("stroke-width", 1);//绘制标注(节点前的矩形)groups.append("rect").attr("x", 8).attr("y", -10).attr("width", function (d) {return d.data.link ? getPXwidth(d.data.link) + 10 : 0;}).attr("height", 22).attr("fill", "red").attr("border", "blue")// 添加圆角.attr("rx", 4);//绘制链接方式groups.append("text").attr("x", 12).attr("y", -5).attr("dy", 10).attr("fill", "white").attr("font-size", 12).text(function (d) {return d.data.link;});//绘制文字groups.append("text").on("click", function (event, node) {let data = node.data;// 被禁用的节点,点击无效if (data.disabled) {return;}// 有外链的节点,打开新窗口后恢复到思维导图页面if (data.url) {window.open(data.url);that.$emit("activeChange", "map");return;}// 标准节点—— 传出 propif (data.dicType) {that.$emit("dicTypeChange", data.dicType);}// 标准节点—— 传出 propif (data.prop) {that.$emit("activeChange", data.prop);}}).attr("x", function (d) {return 12 + (d.data.link ? getPXwidth(d.data.link) + 10 : 0);}).attr("fill", function (d) {if (d.data.prop === that.active) {return "#409EFF";}}).attr("font-weight", function (d) {if (d.data.prop === that.active) {return "bold";}}).attr("font-size", 14).attr("cursor", function (d) {if (d.data.disabled) {return "not-allowed";} else {return "pointer";}}).attr("y", -5).attr("dy", 10).attr("slot", function (d) {return d.data.prop;});// .text(function (d) {//   return d.data.label;// });groups.append("foreignObject").attr("width", (d) => {return getPXwidth(d.data.label) + 22 + (!d.data.children?82:0);}).attr("height", 100).attr("x", function (d) {return 12 + (d.data.link ? getPXwidth(d.data.link) + 10 : 0);}).on("click", function (event, node) {}).attr("y", -10).append("xhtml:div").style("font", '14px "Helvetica Neue"').html((d) => {let _html = `<div class="custom-html"><div>${d.data.label}</div></div>`;if(!d.data.children){_html = `<div class="custom-html"><div>${d.data.label}</div><div οnclick="handleCustom(${1})"><i class="iconfont">&#xe648;</i>视频课</div></div>`;}return _html});},handleCustom(data){debugger}},
};// 获取树的深度
function getDepth(json) {var arr = [];arr.push(json);var depth = 0;while (arr.length > 0) {var temp = [];for (var i = 0; i < arr.length; i++) {temp.push(arr[i]);}arr = [];for (var i = 0; i < temp.length; i++) {if (temp[i].children && temp[i].children.length > 0) {for (var j = 0; j < temp[i].children.length; j++) {arr.push(temp[i].children[j]);}}}if (arr.length >= 0) {depth++;}}return depth;
}// 提取树的子节点,最终所有树的子节点都会存入传入的leafList数组中
function getTreeLeaf(treeData, leafList) {// 判断是否为数组if (Array.isArray(treeData)) {treeData.forEach((item) => {if (item.children && item.children.length > 0) {getTreeLeaf(item.children, leafList);} else {leafList.push(item);}});} else {if (treeData.children && treeData.children.length > 0) {getTreeLeaf(treeData.children, leafList);} else {leafList.push(treeData);}}
}// 获取包含汉字的字符串的长度
function getStringSizeLength(string) {//先把中文替换成两个字节的英文,再计算长度return string.replace(/[\u0391-\uFFE5]/g, "aa").length;
}// 生成随机的字符串
function randomString(strLength) {strLength = strLength || 32;let strLib = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz";let n = "";for (let i = 0; i < strLength; i++) {n += strLib.charAt(Math.floor(Math.random() * strLib.length));}return n;
}// 获取字符串的像素宽度
function getPXwidth(str, fontSize = "12px", fontFamily = "Microsoft YaHei") {var span = document.createElement("span");var result = {};result.width = span.offsetWidth;result.height = span.offsetHeight;span.style.visibility = "hidden";span.style.fontSize = fontSize;span.style.fontFamily = fontFamily;span.style.display = "inline-block";document.body.appendChild(span);if (typeof span.textContent != "undefined") {span.textContent = str;} else {span.innerText = str;}result.width = parseFloat(window.getComputedStyle(span).width) - result.width;// 字符串的显示高度// result.height = parseFloat(window.getComputedStyle(span).height) - result.height;return result.width;
}
</script>
<style lang="scss" scoped>
.d3 {position: relative;overflow: hidden;width: calc(100%);min-height: 500px;overflow-x: scroll;.d3-content {position: absolute;width: max-content;::v-deep .custom-html {display: flex;div {i {font-size: 12px;margin-right: 4px;}&:nth-child(2) {margin-left: 10px;background: #f2faf7;border: 0.5px solid #c3e7da;border-radius: 4px;color: #00ab6b;font-size: 12px;padding: 0 4px;height: 20px;cursor: pointer;}}}}
}
</style>

相关文章:

nuxt、vue树形图d3.js

直接上代码 //安装 npm i d3 --save<template><div class"d3"><div :id"id" class"d3-content"></div></div> </template> <script> import * as d3 from "d3";export default {props: {d…...

香橙派AIpro测评:yolo8+usb鱼眼摄像头的Camera图像获取及识别

一、前言 近期收到了一块受到业界人士关注的开发板"香橙派AIpro",因为这块板子具有极高的性价比&#xff0c;同时还可以兼容ubuntu、安卓等多种操作系统&#xff0c;今天博主便要在一块832g的香橙派AI香橙派AIpro进行YoloV8s算法的部署并使用一个外接的鱼眼USB摄像头…...

大华设备接入GB28181视频汇聚管理平台EasyCVR安防监控系统的具体操作步骤

智慧城市/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分发RTMP、…...

Laravel包开发指南:构建可重用组件的艺术

标题&#xff1a;Laravel包开发指南&#xff1a;构建可重用组件的艺术 Laravel不仅是一个强大的Web应用框架&#xff0c;它的包&#xff08;Package&#xff09;系统也为开发者提供了构建和共享可重用组件的能力。通过包开发&#xff0c;开发者可以轻松地扩展Laravel的功能&am…...

JavaDS预备知识

集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 interfaces和其实现类 classes 。 其主要表现为将多个元素 element 置于一个单元中&#xff0c;对数据进行创建(Create)、读取(Retrieve…...

日常学习--20240705

1、IO流 按照IO操作的数据类型分为字节流和字符流&#xff1a; 字节流&#xff1a;又分为输入流&#xff08;其他程序传递过来的数据&#xff0c;读取流中的数据&#xff09;和输出流&#xff08;往流中写数据&#xff0c;传递给其他程序&#xff09;;可以操作二进制文件&…...

Java中初始化一个List的多种方式

1.最原始的方式&#xff1a;先创建&#xff0c;然后再添加元素 List<String> list new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("cherry");2.使用Arrays.asList 这是一种快速方便的方式&#xff0c;直接…...

BeikeShop多国语言多货币商城系统源码基于Laravel框架

BeikeShop是基于 Laravel 开发的一款开源商城系统&#xff0c;支持多语言商城 多货币商城 100%全开源 ChatGPT OpenAI B2C商城系统 H5商城 PHP商城系统 商城源码 PC商城 跨境电商系统 跨境商城系统 电商商城系统 Laravel 10 框架开发系统&#xff0c;支持插件市场。 Event 机制…...

gradle构建工具

setting.gradle // settings.gradle rootProject.name my-project // 指定根项目名称include subproject1, subproject2 // 指定子项目名称&#xff0c;可选jar包名称 方式一 jar {archiveBaseName my-application // 设置 JAR 文件的基本名称archiveVersion 1.0 // 设置…...

Java需要英语基础吗?

Java编程语言本身并不要求必须有很强的英语基础&#xff0c;因为Java的语法和逻辑是独立于任何特定语言的。我收集归类了一份嵌入式学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕设800套和语言类教学&am…...

14-36 剑和诗人10 - 用LLM构建 AI 代理平台

介绍 在当今快速发展的技术环境中&#xff0c;大型语言模型 (LLM) 和 AI 代理正在改变我们与信息交互、实现流程自动化以及应对不同行业复杂挑战的方式。随着这些强大的模型不断发展&#xff0c;对能够无缝集成和协调它们的强大平台的需求变得越来越重要。 让我们深入研究设计…...

如何在Java中实现批量数据处理

如何在Java中实现批量数据处理 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 引言 在大数据时代&#xff0c;处理大量数据是许多应用程序中必不可少的需…...

项目部署_持续集成_Jenkins

1 今日内容介绍 1.1 什么是持续集成 持续集成&#xff08; Continuous integration &#xff0c; 简称 CI &#xff09;指的是&#xff0c;频繁地&#xff08;一天多次&#xff09;将代码集成到主干 持续集成的组成要素 一个自动构建过程&#xff0c; 从检出代码、 编译构建…...

如何选择TikTok菲律宾直播网络?

为了满足用户对于实时互动的需求&#xff0c;TikTok推出了直播功能&#xff0c;让用户能够与粉丝即时交流。本文将探讨如何选择适合的TikTok菲律宾直播网络&#xff0c;并分析OgLive是否是值得信赖的选择。 TikTok菲律宾直播网络面临的挑战 作为全球领先的短视频平台&#xff…...

Pseudo-Label : The Simple and Efficient Semi-Supervised Learning Method--论文笔记

论文笔记 资料 1.代码地址 https://github.com/iBelieveCJM/pseudo_label-pytorch 2.论文地址 3.数据集地址 论文摘要的翻译 本文提出了一种简单有效的深度神经网络半监督学习方法。基本上&#xff0c;所提出的网络是以有监督的方式同时使用标记数据和未标记数据来训练的…...

信息收集-arping

信息收集-arping 简介 arping 是一个用于发送 ARP 请求和接收 ARP 回复的工具。它通常用于检查网络中的 IP 地址是否被使用&#xff0c;或发现网络中的重复 IP 地址。arping 工具类似于 ping 命令&#xff0c;但它使用的是 ARP 协议而不是 ICMP 协议。在 Kali Linux 中&#…...

一文了解常见DNS问题

当企业的DNS出现故障时&#xff0c;为不影响企业的正常运行&#xff0c;团队需要能够快速确定问题的性质和范围。那么有哪些常见的DNS问题呢&#xff1f; 域名解析失败&#xff1a; 当您输入一个域名&#xff0c;但无法获取到与之对应的IP地址&#xff0c;导致无法访问相应的网…...

TCP/IP 网络协议族分层

TCP/IP协议族 TCP/IP不单是TCP和IP两个协议&#xff0c;TCP/IP实际上是一组协议&#xff0c;它包括上百个各种功能的协议&#xff0c;如&#xff1a;远程登录、文件传输和电子邮件等&#xff0c;当然&#xff0c;也包括TCP、IP协议 它将软件通信过程抽象化为四个抽象层&#…...

Qt:5.QWidget属性介绍(Enabled属性-控件可用性设置、geometry属性-控件位置/大小设置)

目录 一、 QWidget属性的介绍&#xff1a; 二、Enabled属性-控件可用性设置&#xff1a; 2.1Enabled属性的介绍&#xff1a; 2.2获取控件当前可用状态的api——isEnabled()&#xff1a; 2.3设置控件当前的可用状态的api—— setEnabled() &#xff1a; 2.4 实例&#xff…...

NoSQL 非关系型数据库 Redis 的使用:

redis是基于内存型的NoSQL 非关系型数据库&#xff0c;本内容只针对有基础的小伙伴&#xff0c; 因为楼主不会做更多的解释&#xff0c;而是记录更多的技术接口使用&#xff0c;毕竟楼主不是做教学的&#xff0c;没有教学经验。 关于redis的介绍请自行搜索查阅。 使用redis数据…...

python库(5):Psutil库实现系统和硬件监控工具

1 psutil简介 psutil&#xff08;process and system utilities&#xff09;是一个跨平台库&#xff0c;用于检索运行中进程和系统利用率&#xff08;包括 CPU、内存、磁盘、网络等&#xff09;的信息&#xff0c;可以提供丰富的系统监控功能。 2 psutil安装 pip install -i …...

实验四 图像增强—灰度变换之直方图变换

一&#xff0e;实验目的 1&#xff0e;掌握灰度直方图的概念及其计算方法&#xff1b; 2&#xff0e;熟练掌握直方图均衡化计算过程&#xff1b;了解直方图规定化的计算过程&#xff1b; 3&#xff0e;了解色彩直方图的概念和计算方法 二&#xff0e;实验内容&#xff1a; …...

使用el-col和el-row布局,有版心,一页有两栏布局 三栏布局 四栏布局 使用vue动态渲染元素

使用Vue结合Element UI的el-row和el-col组件来实现版心布局&#xff0c;并动态渲染不同栏数的布局&#xff0c;可以通过以下步骤实现&#xff1a; 定义版心容器&#xff1a;使用el-container来定义整个页面的容器&#xff0c;其中el-header、el-main、el-footer分别定义头部、主…...

中软国际加入龙蜥社区,促进“技术+生态”双向赋能

近日&#xff0c;中软国际有限公司&#xff08;简称“中软国际”&#xff09;签署了 CLA&#xff08;Contributor License Agreement&#xff0c;贡献者许可协议&#xff09;&#xff0c;正式加入龙蜥社区&#xff08;OpenAnolis&#xff09;。 中软国际创立于 2000 年&#x…...

adobe pdf设置默认打开是滚动而不是单页视图

上班公司用adobe pdf&#xff0c;自己还不能安装其它软件。 每次打开pdf&#xff0c;总是默认单页视图&#xff0c;修改滚动后&#xff0c;下次打开又 一样&#xff0c;有时候比较烦。 后面打开编辑->首选项&#xff0c; 如下修改&#xff0c;下次打开就是默认滚动了...

React Hooks 深度解析

Hooks简介 诞生背景&#xff1a; 在React 16.8之前的版本中&#xff0c;组件主要分为函数组件和类组件两大类。函数组件简单轻量&#xff0c;但不支持状态&#xff08;state&#xff09;和生命周期方法&#xff1b;而类组件虽然功能强大&#xff0c;但编写和维护起来相对复杂。…...

14-32 剑和诗人6 - GenAI 重塑 SRE 和云工程实践

在不断发展的软件开发和运营领域&#xff0c;各种学科的融合催生了新的范式和实践&#xff0c;旨在简化流程、加强协作和推动创新。DevSecOps、站点可靠性工程 (SRE)、平台工程和云工程已成为支持现代软件系统的重要支柱&#xff0c;每个支柱都解决了独特的挑战和要求。 然而&…...

Towards Deep Learning Models Resistant to Adversarial Attacks

这篇论文的主要内容是关于开发对抗攻击具有抗性的深度学习模型。对抗攻击是通过对输入数据进行微小且精心设计的扰动&#xff0c;诱使深度学习模型做出错误的预测。这种攻击在图像识别、语音识别和自然语言处理等任务中尤为突出。 这篇论文的主要内容是关于开发对抗攻击具有抗…...

2、Key的层级结构

Key的层级结构 Redis的key允许有多个单词形成层级结构&#xff0c;多个单词之间用’:隔开。 举个例子: 我们有一个项目project&#xff0c;有user和product俩种不同的数据类型&#xff0c;那么我们可以这么定义key&#xff1a; user相关的key&#xff1a;project:user:1 pr…...

如何在Qt使用uchardet库

如何在 Qt 中使用 uchardet 库 文章目录 如何在 Qt 中使用 uchardet 库一、简介二、uchardet库的下载三、在Qt中直接调用四、编译成库文件后调用4.1 编译工具下载4.2 uchardet源码编译4.3 测试编译文件4.4 Qt中使用 五、一些小问题5.1 测试文件存在的问题5.2 uchardet库相关 六…...