树形图数据量可能会很大,一次性全部加载可能会有延迟,所以一开始只加载一层节点的数据,当我们点击节点去展开的子节点的时候,再通过请求去加载子节点的数据,并更新到树上

本demo中还添加了放大缩小、点击节点居中的功能,参考链接http://www.jq22.com/yanshi21370

注意:本demo用的d3版本是v3,用最新版有些功能无法使用

    <script src="https://d3js.org/d3.v3.min.js"></script>

效果图

<template><div class="main" style="margin-top: 10px"><el-card><el-row><el-col :span="6"><el-col :span="16"><el-input v-model="condition" size="small" placeholder="搜索用户名" /></el-col><el-col :span="2" :offset="2"><el-button type="primary" size="small" @click="searchList">搜索</el-button></el-col></el-col></el-row></el-card><div class="chartTooltip hidden"><p><strong class="name"></strong></p></div><div class="tree" id="tree"></div></div></template><script>
import OyUserApi from '@/api/systemManage/oyUserApi'
import Axios from '@/interceptor/HttpInterceptor'
var diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });export default {name:'d3',components:{},data() {return {condition:'',root: {},tree:null,duration: 700,treeData: '',count:0,zm:null,separation: () => 1,}},created () {this.getData()},mounted() {const that= thisvar width = document.getElementById("tree").offsetWidth;var height = document.getElementById("tree").offsetHeight;that.height=heightthat.width=widthvar tree = d3.layout.tree().size([height, width])that.tree=tree},methods:{searchList(){const that =thisconst params = {condition:that.condition,layer:1}if(that.condition==''){this.$message.error("请输入用户名!")return}const http = new OyUserApi()http.getMemberProfile(params).then(res => {if (res.code === 200) {that.root=res.datathat.update(that.root)}else{this.$message.error("用户不存在!")}})},getData(){const that =thisconst params = {id:1,layer:1}const http = new OyUserApi()http.getSubMemberProfile(params).then(res => {if (res.code === 200) {that.root=res.datathat.DrawTree()}})},DrawTree() {const that =this var svg = d3.select("body").select("#tree").append("svg").attr("width", 1560).attr("height", 800).call(that.zm=d3.behavior.zoom().scaleExtent([0.1, 100]).on("zoom", d=>{svg.attr("transform","translate(" + d3.event.translate + ")" +"scale(" + d3.event.scale + ")");})) //给svg绑定zoom事件.append("g").attr("transform", "translate(150, 0)")that.zm.translate([150, 0])that.svg=svg    // 根节点和位置that.root.x0 = that.height / 2;that.root.y0 = 0;//(1) 折叠函数,递归调用,有子孙的就把children(显示)给_children(不显示)暂存,便于折叠,function collapse(d) {if (d.children) {d._children = d.children;d._children.forEach(collapse);d.children = null;}}// 折叠根节点的每个孩子that.root.children.forEach(collapse);// 折叠之后要重绘this.update(that.root);},//(2) 更新布局update(source) { const that =this// (2-1) 计算新树的布局var nodes = that.tree.nodes(that.root).reverse(),links = that.tree.links(nodes);// (2-2) 树的深度这里树d.y。树的宽度最大720,要分四层,所以每层就乘180nodes.forEach(function(d) {d.y = d.depth * 180; });// (2-3) 数据连接,根据id绑定数据var node = that.svg.selectAll("g.node").data(nodes, function(d) { return d.id || (d.id = ++that.count); });var div = d3.select('.chartTooltip').style("opacity", 0)var timer = null;var nodeEnter = node.enter().append("g").attr("class", "node").style("cursor", "pointer").attr("transform", function(d) {return "translate(" + source.y0 + "," + source.x0 + ")";}).on("mouseover", d => {if (timer) clearTimeout(timer)d3.select('.chartTooltip').transition().duration(300).style('opacity', 1).style('display', 'block')// 从d3.event获取鼠标的位置var transform = d3.event;var yPosition = transform.layerY + 40;var xPosition = transform.layerX + 40;// 将浮层位置设置为鼠标位置var chartTooltip = d3.select(".chartTooltip").style("left", xPosition + "px").style("top", yPosition + "px");// 更新浮层内容chartTooltip.select(".name").html('用户名:'+d.name+'<br>'+'手机号:'+d.telephone);// 移除浮层hidden样式,展示浮层chartTooltip.classed("hidden", false);})// 添加mouseover事件.on("mouseout", () => {// 添加浮层hidden样式,隐藏浮层timer = setTimeout(function() {d3.select('.chartTooltip').style('opacity', 0).style('display', 'none')}, 400);}).on("click", d => that.click(d));d3.select('.chartTooltip').on('mouseover', function() {if (timer) clearTimeout(timer)d3.select('.chartTooltip').transition().duration(300).style('opacity', 1).style('display', 'block')}).on('mouseout', function() {timer = setTimeout(function() {d3.select('.chartTooltip').style('opacity', 0).style('display', 'none')}, 400);})// 原点nodeEnter.append("circle").attr("r", 1e-6).style("fill", function(d) {return d. hasChildren? "#f00" : "#BEBEBE";});//文字 1nodeEnter.append("text").attr("x", function(d) {return d.children || d._children ? 10 : 10;}).attr("dy", ".35em").attr("text-anchor", function(d) {// return d.children || d._children ? "end" : "start";return "start";}).text(function(d) {return d.name;}).style("fill-opacity", 1).style("font-size", "12px");// (2-5) 原有节点更新到新位置var nodeUpdate = node.transition().duration(that.duration).attr("transform", function(d) {return "translate(" + d.y + "," + d.x + ")";});nodeUpdate.select("circle").attr("r", 4.5).attr("r", function(d) {return d._children ? "5" : "5";}).style("fill", function(d) {return d. hasChildren? "#f00" : "#BEBEBE";});nodeUpdate.select("text").style("fill-opacity", 1);// (2-6) 折叠节点的子节点收缩回来var nodeExit = node.exit().transition().duration(that.duration).attr("transform", function(d) {return "translate(" + source.y + "," + source.x + ")";}).remove();nodeExit.select("circle").attr("r", 1e-6);nodeExit.select("text").style("fill-opacity", 1);// (2-7) 数据连接,根据目标节点的id绑定数据var link = that.svg.selectAll("path.link").data(links, function(d) {return d.target.id;});// (2-8) 增加新连接link.enter().insert("svg:path", "g").attr("class", "link").attr("fill", "none").attr("stroke", "#ccc").attr("stroke-width", "2").attr("d", function(d) {var o = {x: source.x0, y: source.y0};return diagonal({source: o, target: o});});// (2-9) 原有连接更新位置link.transition().duration(that.duration).attr("d",diagonal);// (2-10) 折叠的链接,收缩到源节点处link.exit().transition().duration(that.duration).attr("d", function(d) {var o = {x: source.x,y: source.y};return diagonal({ source: o,target: o });}).remove();// 把旧位置存下来,用以过渡nodes.forEach(function(d) {d.x0 = d.x;d.y0 = d.y;});},// (3) 切换折叠与否async click(d) {const that =thisif (d.children) {d._children = d.children;d.children = null; } else if(d._children&&d._children.length!=0){     d.children = d._children;d._children = null;}else if(d.hasChildren){var mnodes = await  that.getNode(d);   }if(d.hasChildren){that.update(d);}// 点击节点 以当前节点位置居中const a = that.zm.scale()that.svg.attr('transform', 'translate(' + (that.width / 3 - d.y0 * a) + ', ' + (that.height / 2 - d.x0 * a) + ') scale(' + a +')')that.zm.translate([(that.width / 3 - d.y0 * a), (that.height / 2 - d.x0 * a)]).scale(a)},getNode (d) { const that =thisconst http = new OyUserApi()const params={'id':d.id,'layer':1}// #自定义的一个新的以同步方式从后台取数据的请求函数http.getSubMemberProfile(params).then(res => {if (res.code === 200) {d.children =  res.data.children; d._children = null; that.update(d);}})},}}
</script><style  scoped>.main{width: 100%;height: 99%;overflow: auto; }.tree{width: 100%;height: 100%;overflow: auto;}.node {cursor: pointer;}.node circle {fill: none;stroke: #fff;stroke-width: 1.5px;}.node text {font: 10px sans-serif;}.link {fill: none;stroke: #ccc;stroke-width: 1.5px;}.link {fill: none;stroke: #ccc;stroke-width: 1.5px;}#tree {height: 100%;margin: 0 auto;/* background: #E0E0E0; */box-sizing: border-box;}#tree svg{width: 100%;height: 100%;}.chartTooltip {position: absolute;width: 200px;height: auto;padding: 10px;box-sizing: border-box;background-color: white;border-radius: 5px;box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);}.chartTooltip.hidden {display: none;}.chartTooltip p {margin: 0;font-size: 14px;line-height: 20px;word-wrap: break-word;}
</style>

在vue中使用d3做一个动态加载的树形图相关推荐

  1. VUE中的img的:src动态加载图片的问题,require也不能随便用

    问题描述: 写的一个系统,用户登录后会使用数据库的数据作为用户头像,需要显示在页面上,那头像链接就需要用变量表示,那就用到了:src做动态绑定,直接加变量 问题解决: 1.使用require 由于我们 ...

  2. vue中使用echarts做一个雷达图

    在vue中使用echarts做一个雷达图 效果如图 首先 1.安装echarts npm install echarts -S 2.使用 全局使用 在main.js中 // 引入echarts imp ...

  3. 初识canvas,使用canvas做一个百分比加载进度的动画

    canvas作为H5中重要的新增特性,使开发者可以用它来创作各种令人惊叹的作品.先来看一下浏览器对canvas的支持情况. <canvas> 标签定义图形,比如图表和其他图像,我们使用脚本 ...

  4. vue中写svg组件svg图片加载不出来

    vue中写svg组件svg图片加载不出来 结构 首先要安装3个插件:svg-sprite-loader,svgo,svgo-loader npm install svg-sprite-loader - ...

  5. three、vue中使用three、three怎么加载obj模型和mtl文件、three自定义800*800大小怎么拾取/点击

    以上都是这一个星期碰到的坑,找了很多很多资料,总结归纳一下,希望对你的项目有一点点帮助 先说说需求 1.加载3D模型 2.点击模型的子模型会显示对于子模型名称 3.不全屏展示,还要点击子模型 4.创建 ...

  6. vue中使用lazyload实现图片懒加载

    原理:先将img标签的src链接设为同一张图片(比如空白图片),然后给img标签设置自定义属性(比如 data-src),然后将真正的图片地址存储在data-src中,当JS监听到该图片元素进入可视窗 ...

  7. HTML中容器(div)动态加载HTML页面的方法

    在学习前端相关知识的时候,遇到了div中如何动态切换页面的问题,经过网络上的搜索,发现了一个不错的方法. 使用JavaScript代码替换div内容 <script>function lo ...

  8. html 循环tr只显示一个,动态加载进来的tr该如何去循环查看它的值呢

    营业场所大类营业场所小类 请选择 检查标准大类检查标准小类 请选择 list: [] });varbig=$("#SOTYPEBID").html();vardom=$(html) ...

  9. 铵钮提交事件PostBack之后,一些动态加载的物件丢失

    今早起来,发现skype有网友留言,情况大约如下,不过Insus.NET还是先感谢网友的测试. http://www.cnblogs.com/insus/p/3193619.html  如果你有看此篇 ...

最新文章

  1. 如何从路由器中查找ADSL帐号 [2007年4月13日]
  2. 内存储器和cpu一起构成了计算机,计算机系统的组成
  3. Python 进阶_OOP 面向对象编程_类属性和方法
  4. shell date 格式化
  5. [C++] 为什么Linux需要itoa函数
  6. 1.14 Java注释:类、方法和字段注释
  7. 关于TP框架的微信开发服务器配置TOKEN验证失败解决方案
  8. uC/OS II--与ECB操作相关的四个函数
  9. Liveness 探测 - 每天5分钟玩转 Docker 容器技术(143)
  10. WEB界面测试用例~ 收藏
  11. Vue使用iconfont(阿里图标库)
  12. 控制继电器(esp32+继电器)
  13. excel多个工作表合并怎么操作
  14. 整理一些个人常用的windows软件
  15. 杰理之设置立体声输出,播左右声道歌曲后DAC没有声音或声音变小
  16. 在阿里(02):阿里入职记
  17. ios label文字行间距_ios实践之Label 字间距、行间距、两端对齐、分行显示
  18. RFM客户价值分类模型应用
  19. Windows安装Go语言开发环境+配置
  20. FBX格式mesh解析与加载(一)

热门文章

  1. ng-alain支持ie浏览器
  2. 免费域名注册的一些知识以及域名解析相关知识
  3. 58元/月,支付宝的付费选股指标「神奇九转」有用吗?
  4. Folx Pro 5 最好用的Mac磁力链接BT种子下载工具
  5. JetBrains PyCharm激活
  6. AIOps学习资料汇总
  7. 遥感大数据深度学习变化检测
  8. Quartz——Spring定时任务配置
  9. 《人性的枷锁》的读后感作文3800字
  10. noj大作业c语言扫雷,noj大作业简介.doc