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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/369361.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Facebook广告被拒:常见原因以及避免屏蔽的方法

大多数情况下&#xff0c;广告被屏蔽是因为违反了规则&#xff0c;这不仅仅是因为审核因素。有些规则并不明显&#xff0c;也没有在任何地方指定。例如&#xff0c;在广告中使用广告政策中未列出的停用词&#xff1b;审核算法确定照片描绘的模特过于暴露。下面小编将为你介绍Fa…

NET程序开发可能会用到的一些资料文档

NET程序开发使用的一些资料文件&#xff0c;NET高级调试&#xff0c;NET关键技术深入解析&#xff0c;WPF专业编程指南&#xff0c;程序员求职攻略&#xff0c;WPF编程宝典等。 下载链接&#xff1a;https://download.csdn.net/download/qq_43307934/89518582

【微信小程序开发实战项目】——如何制作一个属于自己的花店微信小程序(1)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

带安全启动—Ubuntu系统—手动安装Nvidia驱动

教程1&#xff1a;在启用安全启动的 Fedora 中安装英伟达驱动 教程2&#xff1a;UEFI安全启动模式下安装Ubuntu的NVIDIA显卡驱动 1. 搜索合适的驱动 Nvidia驱动官网 选择这个 驱动(.run)链接 2. 安装必要的软件依赖 CUDA底层用C写的&#xff0c;因此导入编译器 sudo apt i…

RabbitMQ入门教程(精细版二带图)

目录 六 RabbitMQ工作模式 6.1Hello World简单模式 6.1.1 什么是简单模式 6.1.2 RabbitMQ管理界面操作 6.1.3 生产者代码 6.1.4 消费者代码 6.2 Work queues工作队列模式 6.2.1 什么是工作队列模式 6.2.2 RabbitMQ管理界面操作 6.2.3 生产者代码 6.2.4 消费者代码 …

【hive】数据采样

参考https://hadoopsters.com/how-random-sampling-in-hive-works-and-how-to-use-it-7cdb975aa8e2&#xff0c;可以直接查看原文&#xff0c;下面只是对原文进行概括和实际性能测试。 1.distribute by sort by2.测试3.map端数据过滤优化采样 在说数据采样之前&#xff0c;需要…

浅析基于量子成像的下一代甚高灵敏度图像传感器技术

高灵敏度探测成像是空间遥感应用中的一个重要技术领域&#xff0c;如全天时对地观测、空间暗弱目标跟踪识别等应用&#xff0c;对于甚高灵敏度图像传感器的需求日益强烈。随着固态图像传感器技术水平的不断提高&#xff0c;尤其背照式及埋沟道等工艺的突破&#xff0c;使得固态…

2021-06-15 protues(ISIS)脉冲发生器仿真仪表使用

缘由这个脉冲发生器怎么连线_编程语言-CSDN问答

【C++】 解决 C++ 语言报错:Invalid Cast

文章目录 引言 无效类型转换&#xff08;Invalid Cast&#xff09;是 C 编程中常见且严重的错误之一。当程序试图进行不合法或不安全的类型转换时&#xff0c;就会发生无效类型转换错误。这种错误不仅会导致程序崩溃&#xff0c;还可能引发不可预测的行为。本文将深入探讨无效…

利用MATLAB绘制傅里叶变换后的图形

题目如下&#xff0c;其中周期是 2 π 2\pi 2π y { 1 0 < x < π 0 x 0 − 1 − π < x < 0 y\begin{cases} 1 \ 0<x<\pi\\ 0 \ x0\\ -1 \ -\pi <x<0\\ \end{cases} y⎩ ⎨ ⎧​1 0<x<π0 x0−1 −π<x<0​ 计算可得 a n 1 π ∫ −…

CNN文献综述

卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;简称CNN&#xff09;是深度学习领域中的一种重要模型&#xff0c;主要用于图像识别和计算机视觉任务。其设计灵感来自于生物学中视觉皮层的工作原理&#xff0c;能够高效地处理图像和语音等数据。 基本原理…

VPSA制氧设备在不同行业的应用解析

VPSA制氧设备以其独特的吸附原理&#xff0c;能够在穿透大气压的条件下&#xff0c;通过专用的分子筛选择性吸附空气中的氮气、二氧化碳和水等杂质&#xff0c;从而制得纯度较高的氧气。本文将探讨VPSA制氧设备在不同行业中的应用及其重要性。 一、钢铁行业 在钢铁行业中&#…

JVM线上监控环境搭建Grafana+Prometheus+Micrometer

架构图 一: SpringBoot自带监控Actuator SpringBoot自带监控功能Actuator&#xff0c;可以帮助实现对程序内部运行情况监控&#xff0c;比如监控内存状况、CPU、Bean加载情况、配置属性、日志信息、线程情况等。 使用步骤&#xff1a; 1. 导入依赖坐标 <dependency><…

实验三 图像增强—灰度变换

一、实验目的&#xff1a; 1、了解图像增强的目的及意义&#xff0c;加深对图像增强的感性认识&#xff0c;巩固所学理论知识。 2、学会对图像直方图的分析。 3、掌握直接灰度变换的图像增强方法。 二、实验原理及知识点 术语‘空间域’指的是图像平面本身&#xff0c;在空…

工作助手VB开发笔记(2)

今天继续讲功能 2.功能 2.9开机自启 设置程序随windows系统启动&#xff0c;其实就是就是将程序加载到注册表 Public Sub StartRunRegHKLM()REM HKEY_LOCAL_MACHINE \ SOFTWARE \ WOW6432Node \ Microsoft \ Windows \ CurrentVersion \ RunDim strName As String Applicat…

Netty学习(NIO基础)

NIO基础 三大组件 Channel and Buffer 常用的只有ByteBuffer Selector&#xff08;选择器&#xff09; 结合服务器的设计演化来理解Selector 多线程版设计 最早在nio设计出现前服务端程序的设计是多线程版设计,即一个客户端对应一个socket连接,一个连接用一个线程处理,每…

基于docker环境及Harbor部署{很简短一点了,耐心看吧}

用到的环境&#xff1a; docker 、nacos、compose、harbor&#xff08;自行安装 ,以下连接作为参考&#xff09; nacos&#xff1a;史上最全整合nacos单机模式整合哈哈哈哈哈_nacos 源码启动 单机模式-CSDN博客 docker、compose、harbor:史上最全的整合Harbor安装教程&#…

一览 Anoma 上的有趣应用概念

撰文&#xff1a;Tia&#xff0c;Techub News 本文来源香港Web3媒体&#xff1a;Techub News Anoma 的目标是为应用提供通用的意图机器接口&#xff0c;这意味着使用 Anoma&#xff0c;开发人员可以根据意图和分布式意图机编写应用&#xff0c;而不是根据事务和特定状态机进行…

技术成神之路:设计模式(二)建造者模式

1.定义 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许你分步骤创建复杂对象&#xff0c;而不必直接调用构造函数。建造者模式特别适合那些包含多个组成部分并且构造过程复杂的对象。 2. 结构 建造者模式的主要组成部分包括&#…