仿Neo4j里的知識圖譜,利用d3+vue開發的一個網絡拓撲圖


項目需要畫一個類似知識圖譜的節點關系圖。


 

  一開始用的是echart畫的。

  根據https://gallery.echartsjs.com/editor.html?c=xH1Rkt3hkb,成功畫出簡單的節點關系。

  如圖: 

 

 

 

  總結——

    【優點】:關系一目了然,可以鼠標懸浮查看相鄰節點,其他節點淡化。

    【缺點】:拖動結果不理想,尤其是數據過多時,一旦拖動一個,整個頁面所有的節點都在動,很久都無法停止(可能是我配置方法不對,但是后續沒找到解決方法)

 


 

  於是轉而使用d3力導圖。

 

 

   除了基本的節點展示和拖動之外,還可以雙擊新增節點,以及右擊展示節點詳情。

  核心操作有以下:

    1、繪制graph力

var simulation = d3
        .forceSimulation(nodes)
        .force(
          'collide',
          d3
            .forceCollide()
            .radius(() => 30)
            .iterations(2)
        )
        .force(
          'charge',
          d3
            .forceManyBody()
            // .distanceMax(300)
            .strength(-400)
        )
        .force(
          'link',
          d3
            .forceLink(links)
            .id(d => d.id)
            .distance(100)
        )
        .force('center', d3.forceCenter(this.width / 2, this.height / 2))
      // .force('x', d3.forceX(this.width / 2))
      // .force('y', d3.forceY(this.height / 2))

    2、繪制存放節點和關系的svg

var svgArea = d3
        .select('.containers')
        .append('svg')
        .attr('viewBox', [0, 0, this.width, this.height])
        .attr('class', 'd3Test')
        .call(
          d3.zoom().on('zoom', function() {
            g.attr('transform', d3.event.transform)
          })
        )
        .on('dblclick.zoom', () => {}) // 禁止雙擊放大

const g = this.svgArea.append('g').attr('class', 'content')

      3、繪制節點關系

var links = g
        .append('g')
        .attr('class', 'links')
        .selectAll('path')
        .data(links, function(d) {
          if (typeof d.source === 'object') {
            return d.source.name + '_' + d.relationship + '_' + d.target.name
          } else {
            return d.source + '_' + d.relationship + '_' + d.target
          }
        })
        .join('path')
        .attr('stroke-width', d => Math.sqrt(d.value))
        .attr('class', 'link')
        .attr('id', function(d) {
          if (typeof d.source === 'object') {
            return d.source.name + '_' + d.relationship + '_' + d.target.name
          } else {
            return d.source + '_' + d.relationship + '_' + d.target
          }
        })

      4、繪制節點

var nodes = g
        .append('g')
        .attr('class', 'nodes')
        .selectAll('circle')
        .data(nodes, d => d.name)
        .join('circle')
        .attr('r', d => (d.number ? d.number : 20))
        .attr('class', 'node')
        .attr('stroke', '#fff')
        .attr('stroke-width', 1.5)
        .attr('fill', this.color)
        .on('dblclick', this.dbclickNode)//雙擊節點事件
        .on('click', this.clickNode)//單擊節點觸發事件
        // .on('mouseover', this.mouseoverNode)
        // .on('mouseout', this.mouseoutNode)
        .call(this.drag(this.simulation))
nodes.append('title').text(d => d.name)

      5、然后還有個讓節點緩慢停止下來的tick

 this.simulation.on('tick', () => {
        this.links.attr('d', function(d) {
          if (d.source.x < d.target.x) {
            return (
              'M ' +
                            d.source.x +
                            ' ' +
                            d.source.y +
                            ' L ' +
                            d.target.x +
                            ' ' +
                            d.target.y
            )
          } else {
            return (
              'M ' +
                            d.target.x +
                            ' ' +
                            d.target.y +
                            ' L ' +
                            d.source.x +
                            ' ' +
                            d.source.y
            )
          }
        })

        this.nodes
          .attr('cx', function(d) {
            if (d.fixed) {
              d.fx = nodes[d.index].x
            }
            return d.x
          })
          .attr('cy', function(d) {
            if (d.fixed) {
              d.fy = nodes[d.index].y
            }
            return d.y
          })

        this.nodesName.attr('x', d => d.x).attr('y', d => d.y)
      })

  附上官網案例:https://observablehq.com/@d3/force-directed-graph

  這個案例的版本好像比較老,個人建議用新版,不過新版的API有改動。

 

  參考案例:https://eisman.github.io/neo4jd3/

 

知識點匯總:

  關於x,y,vx,vy,fx,fy

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM