Fork me on Bolg '◡'

Vue和d3.js(v4)力导向图force结合使用,v3版本升级v4

前段时间因为参与项目涉密,所以一直没有更新博客,有些博友给我私信或者留言要部分博文的源码,因为我的电脑更换,demo的源码没有备份 所以无法提供。大家可针对具体问题问我,有空我定会回复的。另外转发文章请说明出处,谢谢关注!
之前有多篇博文介绍了d3力导向图的绘制过程的一些问题,现在由于性能和UI的要求,要升级d3版本。因为v3版本现在使用的不多了,网上可找的资料不多且拓展性不好,因此花了点时间做了版本升级。

效果展示

初始化布局

this.force = d3.forceSimulation(nodes)
        .force('link', d3.forceLink(links).id(d => d.id).strength(0.6).distance(Math.floor(height / 4)))
        .force('charge', d3.forceManyBody().strength(-500).distanceMin(50).distanceMax(400))
        .force('center', d3.forceCenter())
        .force('collision', d3.forceCollide().radius(50))
        .velocityDecay(0.5)

基础的配置,中文api里说的很清楚,d3-force

容器创建


let circles = null; // circle元素集合
let lines = null; // line元素集合
let gContainer = null; // 所有元素容器
let gCircle = null; // circle元素容器
let gLine = null; // line元素容器
let svg = null;

......

   svg = d3.select('#svgForce')
        .append('svg')
        .attr('class', 'svg__container')
        .attr('viewBox', [-width / 2, -height / 2, width, height])

   // g容器,存放其他元素
      gContainer = svg
        .append('g')
        .attr('class', 'force__container')
        .attr('transform', 'translate(' + 10 + ',' + 10 + ')');

      // 容器
      gLine = gContainer.append('g').attr('class', 'force__line');
      gCircle = gContainer.append('g').attr('class', 'force__circle');

容器创建,区分线和节点,便于维护和处理

Zoom缩放(仅附上关键代码,不可粘贴复制直接实现哦~)

// zoom缩放
    let zoom = d3.zoom()
       .scaleExtent([0.5, 5])
       .on('zoom', this.zoomed);

// 鼠标放大缩小
    zoomed () {
      const transform = d3.event.transform;
      d3.selectAll('.force__container').attr('transform', transform);
    }
....
svg.call(zoom)

Drag拖拽

// 拖拽
      let drag = d3.drag()
        .on('start', d => {
          if (!d3.event.active) this.force.alphaTarget(0.8).restart(); // 当alpha为0 设置值让其动起来
          d.fx = d.x;
          d.fy = d.y;
        })
        .on('drag', d => {
          d.fx = d3.event.x;
          d.fy = d3.event.y;
          d.drag = true;
          this.force.force('center', null) // 允许随意拖动
        })
        .on('end', d => {
          if (!d3.event.active) this.force.alphaTarget(0); // 静下来
        })

      circles = gCircle.selectAll('g')
        .data(that.nodes, d => `circle${d.id}`)
        .join('g')
        .call(drag)
  1. d.fx 和 d.fy 表示设置拖拽固定的节点位置,如果想结束拽动后固定,需要在end中 删除2个值~
  2. 拖拽函数:start,dragend
  3. 设置this.force.force('center', null) 是让节点随着拖动的位置随意飘动,不然你拽不走它的,它会被center的向心力吸引的

仿真tick

this.force.on('tick', () => {
        circles.attr('transform', d => `translate(${d.x},${d.y})`);

        lines.selectAll('path')
          .attr('d', d => that.linkTick(d))

linkTick 是直线平行线的绘制方法,上篇博文有写,d3力导图绘制节点间多条关系平行线的方法

小结

本文主要写了下布局,拖拽,缩放一些基础方法的改变和使用。下篇将说一些最近调研的一些新玩意,包括文字加底色,线条加底色的方法。

posted @ 2020-09-14 11:48  webhmy  阅读(2281)  评论(0编辑  收藏  举报