vue.js中使用D3树状图异步按需加载数据绘制人物关系图

1 篇文章 0 订阅

vue.js中使用D3树状图异步按需加载数据绘制人物关系图,网上查了好多资料没找到合适的,就自己写个简单的,方便以后查看,附上效果图

重点:这个树状图不管是Vue的,还是HTML的,使用的D3.js 版本是3.5.17,如果使用别的版本,可能里面的语法不同,所以使用者请确认好下载的D3.js的版本

D3.js是一个基于 web 标准的 JavaScript 可视化库. D3 可以借助 SVG, Canvas 以及 HTML 将你的数据生动的展现出来. D3 结合了强大的可视化交互技术以及数据驱动 DOM 的技术结合起来, 让你可以借助于现代浏览器的强大功能自由的对数据进行可视化.

图形绘制,D3默认采用的是异步加载,但是,这里的异步加载,指的是一次性的将图形展示所需要的数据异步的方式加载到浏览器前端显示,最终以树状图展现给用户。 若一次性加载所有的数据,会比较影响用户体验,因为一次遍历数据库所有的跟踪记录,无论是递归先根遍历还是非递归方式循环查找,最终的体验都是不令人满意的。 我们便采取按需的异步加载数据方式,即,当用户点击节点时,才从后台取数据。由于D3的优秀数据管理架构,数据一旦加载了,后续便可以不用再从服务器后台取数据。

先使用HTML创建异步按需加载数据绘制的树状图

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node {
  cursor: pointer;
}

.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1.5px;
}

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

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
}

.link2 {
  fill: none;
  stroke: #f00;
  stroke-width: 1.5px;
}

</style>
<body>
<script src="lib/jquery.min.js" charset="utf-8"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var root = {
    "name": "flare",
    "deal": "1",
    "children": [{
      "name": "AAA",
      "deal": "2"
    },{
      "name": "BBB",
      "deal": "3"
    }]
};
var margin = {top: 20, right: 120, bottom: 20, left: 550},
    width = 1024 - margin.right - margin.left,
    height = 798 - margin.top - margin.bottom;

var i = 0,
duration = 750,
root;

var tree = d3.layout.tree().nodeSize([90, 60]);

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.x, d.y]; });

    
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


//Redraw for zoom
// function redraw() {
//     // debugger
//   // console.log("here", d3.event.translate, d3.event.scale);
  
//   svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
// }
// console.log(d3.select("body"))
// var svg = d3.select("body").append("svg").attr("width", 1024).attr("height", 798)
//     .call(zm = d3.behavior.zoom().scaleExtent([1,3]).on("zoom", redraw))
//     .append("g")
//     .attr("transform", "translate(" + 512 + "," + 50 + ")");
    // console.log(svg)
//necessary so that zoom knows where to zoom and unzoom from
// zm.translate([512, 50]);
  
root.x0 = 0;
root.y0 = height / 2;

function collapse(d) {
//   debugger
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
}
console.log(root.children)
root.children.forEach(collapse);
update(root);

// d3.select(self.frameElement).style("height", "100px");
// console.log(d3.select(self.frameElement).style("height", "100px"))

function update(source) {
//   debugger

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse(),
      links = tree.links(nodes);
    // console.log(nodes)
    // console.log(links)
  // Normalize for fixed-depth.
  nodes.forEach(function(d) { d.y = d.depth * 180; });

  // Update the nodes…
//   console.log(svg)
  var node = svg.selectAll("g.node")
      .data(nodes, function(d) { return d.id || (d.id = ++i); });
    // console.log(node.transition())
  // Enter any new nodes at the parent's previous position.
  var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.x0 + "," + source.y0 + ")"; })
      .on("click", click);

  nodeEnter.append("circle")
      .attr("r", 1e-6)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeEnter.append("text")
      .attr("cx", function(d) { return d.children || d._children ? -10 : 10; })
      .attr("cy", ".35em")
      .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
      .text(function(d) { return d.name; })
      .style("fill-opacity", 1e-6);

  // Transition nodes to their new position.
  
  var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
// console.log(nodeUpdate)
  nodeUpdate.select("circle")
      .attr("r", 20)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeUpdate.select("text")
      .style("fill-opacity", 1);

  // Transition exiting nodes to the parent's new position.
  var nodeExit = node.exit().transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })
      .remove();

  nodeExit.select("circle")
      .attr("r", 1e-6);

  nodeExit.select("text")
      .style("fill-opacity", 1e-6);

  // Update the links…
  var link = svg.selectAll("path.link")
      .data(links, function(d) { return d.target.id; });
    // console.log(link)
  // Enter any new links at the parent's previous position.
  link.enter().insert("path", "g")
      .attr("class", "link")
      .attr("d", function(d) {
        var o = {x: source.x0, y: source.y0};
        return diagonal({source: o, target: o});
      });
  /*
  console.log(link);

  link.enter().insert("path", "g")
  .attr("class", function(d){
      if(d.source.deal != null && d.source.deal != undefined){
            if(d.target.deal != null && d.target.deal != undefined){
                return "link2";
            }
        }
        return "link";
      })
  .attr("d", function(d) {
    var o = {x: source.x0, y: source.y0};
    return diagonal({source: o, target: o});
  });
  */
  // Transition links to their new position.
  link.transition()
      .duration(duration)
      .attr("d", diagonal);      

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {x: source.x, y: source.y};
        return diagonal({source: o, target: o});
      })
      .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}

function getNode(){     
 // #自定义的一个新的以同步方式从后台取数据的ajax函数
//   debugger
    var mynodes = [{
              "name": "CCC",
              "size": "4"  
            },{
              "name": "DDD",
              "size": "5"  
            },{
              "name": "EEE",
              "size": "6"  
            }];
    // $.ajax({  
    //     url : "./node",  
    //     async : false, // 注意此处需要同步  
    //     type : "POST",  
    //     dataType : "json",  
    //     success : function(data) {            
    //         mynodes = data;
    //         console.log(mynodes);            
    //         //nodes = JSON.parse(nodes);
    //     }  
    // });  
    return mynodes;
}

// Toggle children on click.
function click(d) {
//   debugger
      // console.log(d) 
      // #重点关注这个函数的不同之处。尤其是else部分
      // debugger
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else if(d._children){         
        d.children = d._children;
        d._children = null;
      }else {
         var mnodes = getNode();
         // console.log(mnodes)
        d.children = mnodes;        
      }
  update(d);
}

</script>

 

这个HTML是参考:https://www.cnblogs.com/shihuc/p/6064448.html

Vue的是我自己改写的,里面使用了elementUI样式库,如果没有下载的话,可以把“<el-container>”这个标签删掉自己写,引入的D3的版本是3.5.17,如果是新版本,语法被简写了,可能不支持,所以下载D3.js版本的时候,要注意版本号。

<template>
  <div class="register">
    <el-container>
      <div class="tree-svg" id="treeId"></div>
    </el-container>
  </div>
</template>

<script>
import d3 from 'd3'
var diagonal = d3.svg.diagonal()
  .projection(function(d) { return [d.x, d.y]; });
export default {
  name: 'register',
  components: {
    
  },
  computed: {

  },
  data() {
    return {
      root: {
        "name": "flare",
        "size": "1",
        "image": "http://www.ourd3js.com/demo/J-2.0/lingsha.png",
        "children": [{
          "name": "AAA",
          "size": "11",
          "image": "http://www.ourd3js.com/demo/J-2.0/tianhe.png"
        },{
          "name": "BBB",
          "size": "12",
          "image": "http://www.ourd3js.com/demo/J-2.0/mengli.png"
        }]
      },
      tree: null,
      zm: null,
      height: 750,
      count: 0,
      duration: 800,
    };
  },
  created () {
    var that = this
    var tree = d3.layout.tree().nodeSize([60, 60]);
    that.tree = tree
  },
  mounted () {
    var that = this;
    var svg = d3.select("#treeId").append("svg").attr("width", 960).attr("height", 650)
          .call(that.zm = d3.behavior.zoom().scaleExtent([1,3]).on("zoom", d=>{svg.attr("transform", "translate(" + d3.event.translate + ")" );}))
          .append("g")
          .attr("transform", "translate(" + 480 + "," + 50 + ")");

        that.zm.translate([512, 50]);
        that.svg = svg
        that.root.x0 = 0;
        that.root.y0 = that.height / 2;

        function collapse(d) {
          if (d.children) {
            d._children = d.children;
            d._children.forEach(collapse);
            d.children = null;
          }
        }
        // Initialize the display to show a few nodes.
        that.root.children.forEach(collapse);
        
        that.update(that.root);
  },
  methods: {
    update (source) {
      var that = this
      // Compute the new tree layout.
      var nodes = that.tree.nodes(that.root).reverse(),
      links = that.tree.links(nodes);

      // Normalize for fixed-depth.
      nodes.forEach(function(d) { d.y = d.depth * 180; });
       // Update the nodes…
      var node = that.svg.selectAll("g.node")
        .data(nodes, function(d) { return d.id || (d.id = ++that.count); });

      // Enter any new nodes at the parent's previous position.
      var nodeEnter = node.enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) {
          return "translate(" + source.x0 + "," + source.y0 + ")"; 
        })
        .on("click", d => that.click(d));

      nodeEnter.append('image')
        .attr('xlink:href', d => {
            return d.image
        })
        .attr('x', d => {
          return d.children || d._children ? -25 : -25
        })
        .attr('y', -50)

      nodeEnter.append("text")
      .attr("x", function(d) { return d.children || d._children ? -20 : -20; })
      .attr("y", "15")
      .attr("font-size", "18px")
      .text(function(d) { return d.name; })
      .style("fill-opacity", 1e-6);

      // Transition nodes to their new position.
      var nodeUpdate = node.transition()
        .duration(that.duration)
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

      nodeUpdate.selectAll('image')
        .attr('width', 50)
        .attr('height', 50)

      nodeUpdate.select("text")
        .style("fill-opacity", 1);

      // Transition exiting nodes to the parent's new position.
      var nodeExit = node.exit().transition()
        .duration(that.duration)
        .attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })
        .remove();

      nodeExit.select('image')
        .attr('width', 0)
        .attr('height', 0)
        
      nodeExit.select("text")
        .style("fill-opacity", 1e-6);

      // Update the links…
      var link = that.svg.selectAll("path.link")
        .data(links, function(d) {
          return d.target.id;
        });

      // Enter any new links at the parent's previous position.
      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});
        });

      // Transition links to their new position.
      link.transition()
        .duration(that.duration)
        .attr("d", diagonal);
      
      // Transition exiting nodes to the parent's new position.
      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();
      
      // Stash the old positions for transition.
      nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });
    },
    click(d) {
      var that = this
      // #重点关注这个函数的不同之处。尤其是else部分
      
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else if(d._children){     
        d.children = d._children;
        d._children = null;
      }else {
        var mnodes = that.getNode(d.size);
        d.children = mnodes;        
      }
      that.update(d);
    },
    getNode (id) { 
      // #自定义的一个新的以同步方式从后台取数据的ajax函数
      var mynodes = [];
      if (id === '11') {
        mynodes = [{
          "name": "AAA01",
          "image": "http://www.ourd3js.com/demo/J-2.0/ziying.png",
          "size": "111"  
        },{
          "name": "AAA02",
          "image": "http://www.ourd3js.com/demo/J-2.0/tianqing.png",
          "size": "112"  
        },{
          "name": "AAA03",
          "image": "http://www.ourd3js.com/demo/J-2.0/suyu.png",
          "size": "113"
        }];
      } else if(id === '12') {
        mynodes = [{
          "name": "BBB01",
          "image": "http://www.ourd3js.com/demo/J-2.0/xuanxiao.png",
          "size": "121"  
        },{
          "name": "BBB02",
          "image": "http://www.ourd3js.com/demo/J-2.0/suyao.png",
          "size": "122"  
        },{
          "name": "BBB03",
          "image": "http://www.ourd3js.com/demo/J-2.0/taiqing.png",
          "size": "123"
        }];
      } else {
        mynodes = [{
          "name": "DDD",
          "image": "http://www.ourd3js.com/demo/J-2.0/xizhong.png",
          "size": "131"  
        },{
          "name": "EEE",
          "image": "http://www.ourd3js.com/demo/J-2.0/guixie.png",
          "size": "132"  
        },{
          "name": "FFF",
          "image": "http://www.ourd3js.com/demo/J-2.0/chanyou.png",
          "size": "133"
        }];
      } 
      return mynodes;
    },
  }
};


</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.register {
  padding-top: 50px;
  width: 100%;
}
.tree-svg{
  margin: 0 auto;
  border: 1px solid #f00;
}

</style>

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Vue.js使用Echarts实现数据动态刷新功能,要先安装Echarts和Vue.js的相关依赖。 1. 首先,在Vue项目安装Echarts和Vue-Echarts依赖。可以使用npm或yarn安装。 ```bash npm install echarts vue-echarts ``` 2. 在Vue的组件引入Echarts和Vue-Echarts。 ```javascript import echarts from 'echarts' import VueECharts from 'vue-echarts' // 引入要的Echarts主题 import 'echarts/theme/macarons' export default { components: { VueECharts }, data() { return { chartOptions: {}, data: [] } }, mounted() { this.initChart() // 调用数据刷新方法 this.refreshData() }, methods: { initChart() { // 初始化表配置 this.chartOptions = { // 设置Echarts主题 theme: 'macarons', // 设置表类型和数据 series: [{ type: 'bar', data: this.data }] } }, refreshData() { // 模拟异步获取数据 setTimeout(() => { // 更新数据 this.data = [100, 200, 300, 400, 500] // 在数据更新后重新渲染表 this.$refs.chart.refresh() // 定时调用数据刷新方法 this.refreshData() }, 2000) } } } ``` 3. 在Vue模板使用Vue-Echarts组件显示表。 ```html <template> <div> <vue-echarts ref="chart" :options="chartOptions"></vue-echarts> </div> </template> ``` 以上是一个简单的示例,通过不断更新数据并定时刷新表实现了数据动态刷新功能。在实际开发,可以根据求对表样式、数据等进行自定义配置。 ### 回答2: Vue.js是一种基于JavaScript的前端框架,而Echarts是一种数据可视化工具。在Vue.js使用Echarts实现数据动态刷新功能,主要分为以下几个步骤。 首先,我们要安装Echarts。可以通过npm或者yarn来安装Echarts,命令如下: ``` npm install echarts --save ``` 然后,在Vue组件引入Echarts的库文件,可以在main.js全局引入,或者在使用Echarts的组件局部引入,命令如下: ``` import echarts from 'echarts' ``` 接下来,创建一个div作为Echarts表的容器,并设置其样式和大小,例如: ``` <div id="chart" style="width: 600px; height: 400px;"></div> ``` 然后,在Vue组件的生命周期钩子函数使用Echarts创建表,并将数据传入表。例如,在created钩子函数: ``` created() { this.initChart() }, methods: { initChart() { // 根据容器的id获取表的dom对象 const chartDom = document.getElementById('chart') // 创建echarts实例对象 const myChart = echarts.init(chartDom) // 根据实际求设置表的配置项和数据 const option = { //... series: [ { //... data: this.data // 设置数据 } ] } // 使用配置项配置表 myChart.setOption(option) } } ``` 最后,当要刷新数据时,可以通过更新this.data来动态刷新数据,并重新渲染表。例如,在一个按钮的点击事件: ``` methods: { refreshData() { // 在此处根据实际求更新this.data的值 //... // 重新渲染表 this.initChart() } } ``` 通过以上步骤,就可以在Vue.js使用Echarts实现数据动态刷新功能了。当数据变化时,只要更新数据并重新渲染表即可。 ### 回答3: 在Vue.js使用ECharts实现数据动态刷新功能的具体步骤如下: 1. 首先,安装ECharts库。可以通过npm安装ECharts,运行命令:npm install echarts --save 2. 引入ECharts库。在Vue组件,通过import语句引入ECharts库,如:import echarts from 'echarts' 3. 在Vue组件的data选项定义一个变量,用于存储ECharts实例。例如:chart: null 4. 在Vue组件的mounted钩子函数,初始化ECharts实例,并将其挂载到页面上的DOM节点上。例如: ``` mounted() { this.chart = echarts.init(this.$refs.chartContainer) } ``` 5. 在Vue组件的methods选项,编写一个方法用于更新数据。例如: ``` updateChart() { // 获取新的数据 const newData = fetchData() // 更新数据 this.chart.setOption({ series: [ { data: newData } ] }) } ``` 在这个方法,首先通过适当的方式获取新的数据,然后通过setOption方法更新表的数据。 6. 在要的时机,调用updateChart方法来更新数据。 以上就是在Vue.js使用ECharts实现数据动态刷新功能的基本步骤。在实际应用,可能还要根据具体求对表进行配置和样式的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值