Vue和d3.js(v4)力導向圖force結合使用,v3版本升級v4【一】

webhmy發表於2020-09-14

前段時間因為參與專案涉密,所以一直沒有更新部落格,有些博友給我私信或者留言要部分博文的原始碼,因為我的電腦更換,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力導圖繪製節點間多條關係平行線的方法

小結

本文主要寫了下佈局,拖拽,縮放一些基礎方法的改變和使用。下篇將說一些最近調研的一些新玩意,包括文字加底色,線條加底色的方法。

相關文章