vue+d3v6实现动态知识图谱可视化展示

一、前言

之前的博客:对Neo4j导出数据做知识图谱可视化 D3库实现

之前博客做的知识图谱可视化只是在html上直接写的页面,而且d3还使用的是v4版本的库。

但是当项目复杂的情况下(前端项目越来越复杂了),比如要在系统中加入其他图表进行综合大屏展示,显然不是一个很好的选择,于是决定用vue重构一下代码,把图可视化作为一个组件来维护,顺便再用一下新版本的d3。同时之前的项目存在一个致命的问题,就是动态更新,即当页面已经有图谱展示的情况下,查询新的数据时,无法正常展示(节点全跑到左上角去了)

下图是向基于nodejs搭建neo4j后端服务请求数据后,更新视图出现的问题:(Vue重构后,代码不变的情况下可以解决该问题)

在这里插入图片描述

二、d3@v6相关链接参考

下面附上供学习和参考的链接:

目前d3已经到v6版本了(更新是真滴快),关于新版d3的改动说明的链接我放在了上面供参考。虽然更新了很多东西,但总的来说原来的代码其实改动不大,比如新版的d3移除了d3.eventv4版本需要注意。

三、代码详细介绍

1. 页面结构(2021年5月更新)

首先页面的整体结构如下,分为2D和3D图谱展示两个页面,其中2D知识图谱除了展示还实现了各种图交互功能;而3D知识图谱采用了第三方模块,底层使用 D3+Three 实现视图渲染,直接截图展示:
在这里插入图片描述

2. 代码结构(2021年5月新增)

这次对代码结构作了大改,变化挺大的,文件夹对应关系如下:

  • 组件存放在 components 文件夹
    • d3graph.vue —— 2D图谱展示组件
    • threeGraph.vue —— 3D图谱展示组件
    • gSearch.vue —— 搜索组件,目前主要通过require代替后台请求
  • 页面存放在 views 文件夹
    • 2dView.vue —— 2D图谱展示页面
    • 3dView.vue —— 3D图谱展示页面
  • d3插件存放在 plugins 文件夹
    • d3-context-menu.js —— 右键菜单事件注册及回调函数
    • d3-context-menu.scss —— 右键菜单样式文件
  • 路由存放在 router 文件夹
    • index.js —— 路由较少,就2个页面
  • 静态图数据存放在 data 文件夹
  • storeassets 文件夹暂时不用

3. 功能及代码介绍

接下来介绍关于图可视化的基本功能与交互事件:

1)d3初始化(2021年5月更新)

d3初始化,包括数据解析、数据渲染及响应式数据初始化,在新版本代码将数据解析分离出来,放到 2dView.vue 页面中 。现在d3初始化分为数据渲染和状态初始化两个任务。

旧版本:

// d3初始化,包括数据解析、数据渲染
d3init () {
   
  // this.graph存放json数据
  this.d3jsonParser(this.graph)
  this.d3render()
  // 数据初始化(节点状态)
  this.nodeState = 0
  this.states = ['on', 'on', 'on', 'on']
}

新版本:

// d3初始化,包括数据解析、数据渲染
d3init () {
   
  this.links = this.data.links
  this.nodes = this.data.nodes
  this.svgDom = d3.select('#svg')  // 获取svg的DOM元素
  // this.d3jsonParser(this.graph)
  this.d3render()
  // 数据状态初始化
  this.stateInit()
},
  • d3jsonParser:对请求的json数据进行解析,分别格式化为节点和关系数据,解析后存放到 this.links(关系显示数据) / this.nodes(节点显示数据) / this.data(全部图数据)
d3jsonParser (json) {
   
  const nodes =[]
  const links = [] // 存放节点和关系
  const nodeSet = [] // 存放去重后nodes的id

  // 使用vue直接通过require获取本地json,不再需要使用d3.json获取数据
  // d3.json('./../data/records.json', function (error, data) {
   
  //   if (error) throw error
  //   graph = data
  //   console.log(graph[0].p)
  // })

  for (let item of json) {
   
    for (let segment of item.p.segments) {
   
      // 重新更改data格式
      if (nodeSet.indexOf(segment.start.identity) == -1) {
   
        nodeSet.push(segment.start.identity)
        nodes.push({
   
          id: segment.start.identity,
          label: segment.start.labels[0],
          properties: segment.start.properties
        })
      }
      if (nodeSet.indexOf(segment.end.identity) == -1) {
   
        nodeSet.push(segment.end.identity)
        nodes.push({
   
          id: segment.end.identity,
          label: segment.end.labels[0],
          properties: segment.end.properties
        })
      }
      links.push({
   
        source: segment.relationship.start,
        target: segment.relationship.end,
        type: segment.relationship.type,
        properties: segment.relationship.properties
      })
    }
  }
  console.log(nodes)
  console.log(links)
  this.links = links
  this.nodes = nodes
  this.data = {
    nodes, links }
  // return { nodes, links }
}
  • d3render代码部分较多,包括了DOM挂载、事件绑定、以及D3视图渲染,在下面一一进行介绍

2)图查询更新视图(2021年5月更新)

该按钮模拟了向后台请求数据的功能,获取新的数据后,更新图展示部分,重新渲染视图,解决了原博客在动态更新这一块的问题。

在这里插入图片描述
旧版(暂时保留图片):
在这里插入图片描述

目前查询暂用require本地数据代替后台请求数据,gSearch.vue 将数据传给页面,并执行数据解析的任务;而 d3graph.vue 组件通过 watch 监听当前的数据变化,更新后通过 this.d3init() 重新渲染页面。

gSearch.vue 模拟后台查询:

query () {
   
  // console.log(typeof this.mode)
  if (this.data.length <= 20) {
   
    this.data = require('../data/top5.json')
  } else {
   
    this.data = require('../data/records.json')
  }
  this.$emit('getData', this.data)
}

d3graph.vue 监听数据变化:

watch: {
   
  // 当请求到新的数据时,重新渲染
  data (newData, oldData) {
   
    console.log(newData, oldData)
    // 移除svg和元素注册事件,防止内存泄漏
    this.svgDom.on('.', null)
    this.svgDom.selectAll('*').on('.', null)
    this.d3init()
  }
}

3)平移与缩放(2021年5月更新)

  • 按住鼠标在空白位置移动可以移动视图的相对位置
  • 鼠标滚轮完成视图的放大和缩小

下图展示将视图通过缩放、拖拽和平移来调整图谱布局,使展示结果更加清晰。
在这里插入图片描述

事件直接在svg视图部分注册,通过标签的translate和scale属性实现平移和缩放:

var svg = d3.select("#svg1")
  // 给画布绑定zoom事件(缩放、平移)
  .call(d3.zoom().on('zoom', function(event) {
   
    // console.log(event)
    var scale = event.transform.k,
        translate = [event.transform.x, event.transform.y]

	// 视图矫正,暂不使用
    // if (this.svgTranslate) {
   
    //     translate[0] += this.svgTranslate[0]
    //     translate[1] += this.svgTranslate[1]
    // }

    // if (this.svgScale) {
   
    //     scale *= this.svgScale
    // }

    svg.attr('transform', 'translate(' + translate[0] + ', ' + translate[1] + ') scale(' + scale + ')');
  }))
  .append('g')
  .
  • 76
    点赞
  • 261
    收藏
    觉得还不错? 一键收藏
  • 84
    评论
根据提供的引用内容,您提供的代码片段似乎是C语言的代码。根据您的问题,您遇到了编译错误。要解决这个问题,您可以尝试以下几个步骤: 1. 检查代码中是否存在拼写错误或语法错误。编译错误通常是由于代码中的错误导致的。请确保您的代码中没有任何拼写错误,并且所有的语法都是正确的。 2. 检查是否缺少头文件。在C语言中,您需要包含所需的头文件来使用特定的函数和库。请确保您的代码中包含了所需的头文件,并且这些头文件的路径是正确的。 3. 检查是否缺少库文件。有时候,编译错误可能是由于缺少所需的库文件而引起的。请确保您的代码中包含了所需的库文件,并且这些库文件的路径是正确的。 4. 检查编译命令是否正确。编译C语言代码时,您需要使用正确的编译命令来编译代码。请确保您使用的编译命令是正确的,并且所有的参数都是正确的。 以下是一个示例的C语言代码,用于创建和读取共享内存: 创建共享内存: ```c #include <stdio.h> #include <stdlib.h> #include <sys/shm.h> int main(int argc, char* argv[]) { key_t key = ftok(argv[1], 1); if (-1 == key) { perror("ftok err"); return 1; } int shmid = shmget(key, atoi(argv[2]), IPC_CREAT | 0644); if (-1 == shmid) { perror("shmget err"); return 1; } printf("shmid:%d\n", shmid); return 0; } ``` 读取共享内存: ```c #include <stdio.h> #include <stdlib.h> #include <sys/shm.h> int main(int argc, char* argv[]) { int shmid = atoi(argv[1]); if (-1 == shmctl(shmid, IPC_RMID, NULL)) { perror("shmctl err"); return 1; } return 0; } ``` 请注意,这只是一个示例代码,您需要根据您的具体需求进行修改和适应。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值