仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图

摘要:
项目需要绘制一个类似于知识地图的节点图。它最初是由echart绘制的。拖动结果并不理想,尤其是当数据太多时,一旦拖动一个,整个页面上的所有节点都在移动,并且无法长时间停止,因此使用d3力图。除了基本节点显示和拖动外,还可以双击新节点并右键单击以显示节点详细信息。

项目需要画一个类似知识图谱的节点关系图。


  一开始用的是echart画的。

  根据https://gallery.echartsjs.com/editor.html?c=xH1Rkt3hkb,成功画出简单的节点关系。

  如图: 

 仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图第1张

  总结——

    【优点】:关系一目了然,可以鼠标悬浮查看相邻节点,其他节点淡化。

    【缺点】:拖动结果不理想,尤其是数据过多时,一旦拖动一个,整个页面所有的节点都在动,很久都无法停止(可能是我配置方法不对,但是后续没找到解决方法)


  于是转而使用d3力导图。

仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图第2张

仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图第3张

   除了基本的节点展示和拖动之外,还可以双击新增节点,以及右击展示节点详情。

  核心操作有以下:

    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

仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图第4张

  

免责声明:文章转载自《仿Neo4j里的知识图谱,利用d3+vue开发的一个网络拓扑图》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇如何关闭常见浏览器的 HSTS 功能PKU《生物信息学-导论与方法》学习笔记-week-1下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vue配置请求转发解决跨域问题

通过nodejs的请求转发到后台,前端地址:http://localhost:8080 后端地址:http://localhost:8081 vue.config.js内容如下: let proxyObj={} proxyObj['/']={ //websocket ws:false, target:'http://localho...

Linux下解压缩文件命令总结

---------------------------------------------tar命令: -v 可视化-c 新建包-f 指定文件名(除非你用默认用户名)-x 解压target.tar-r 增加file文件到target.tar-t 列出target.tar中的文件-u 更新target.tar中的file文件-z 调用gzip-j 调用bzi...

Vue.set()和this.$set()源码解析

前言 我们在日常项目开发过程中,有时候我们对数组或者对象进行了一些操作后,发现页面数据没有更新到。这个时候就会有疑问,why? 如果我们在看文档有这样一个api,以下内容: Vue.set()和this.$set()实现原理 Vue.set()的源码:... 这里是省略的代码 import { set } from '../observer/index'...

python 异常处理、进程

目录: 异常处理 python进程 python并发之多进程 一、异常处理(try...except...) 1、程序中难免出现错误,而错误分成两种: a.语法错误: View Code b.逻辑错误(逻辑错误) View Code 2、异常定义:异常就是程序运行时发生错误的信号。 在python中,错误触发的异常,是以异常追踪信息、异常类型、异常值三...

事件对象

1.什么是事件对象: 官方解释:event 对象代表事件的状态,比如键盘按键的状态,鼠标的位置,鼠标按钮的状态 简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象 event,它有很多属性和方法。 2.事件对象的使用语法: eventTarget.onclick=function( event ){ //这个 e...

Centos7进不了图形化界面(亲测有效)

进入root用户 systemctl get-default //获取当前的默认target systemctl set-default graphical.target multi-user.target:设置当前的target,可选值有graphical.target,multi-user.target进入图形化界面multi_user.target:...