THREEJS相关3d-force-graph 3d力导图使用

3d-force-graph 一个生成力导图的插件,但是api文档不是很友好,网上教程也很少几乎找不到,写完一个例子所以记录一下自己用到的一些api的配置使用,最开始看官方例子最简单,建议初学者先看官方例子熟悉配置,再参考这边的配置,最后深入可以研究threejs结合起来可扩展性还是很强的
3d力导图3d-force-graph github地址
在这里插入图片描述使用ThreeJS / WebGL进行3D渲染,使用d3-force-3d或ngraph作为底层物理引擎。
它要使用需要对THREE.js有基本的了解

注意:
它的最新版有所不同,以前的bug也改进了,以前graph.refresh()有这个方法但是更新有问题,修改nodeOpacity等反而可以触发更新。现在.refresh()可以更新整个图谱,修改node属性只能更新节点。包括新增了一些方法。

本文档不保证适合最新版,最好的办法是上手并查阅官方文档,英语不好翻译软件翻译一下也够用了

引入

script可直接引入,npm 可通过npm install --save 3d-force-graph安装再通过import引入。我试了几台电脑npm 都会报错不能引入,cnpm就没有问题.。但是cnpm引入three可能会出问题,最好使用npm
在这里插入图片描述

使用

第一次接触最好看官方github上的例子开始着手,上手熟悉属性,后续再根据需求和官方文档开发

vue 中的使用

 initGraph(){
    this.elem = document.getElementById('3d-graph');
    let WIDTH = document.getElementById('3d-graph').clientWidth;
    let HEIGHT = document.getElementById('3d-graph').clientHeight;
    let colors = {	//定义数组,方便操作节点颜色。例初始随机色,点击节点,节点及其相连节点变亮,其他节点变暗,可查看官方例子,有专门的讲这一点的
        caNodes : [],	
        mainLinks : [],
    };
    this.Graph = ForceGraph3D()
    (this.elem)	//数据格式{nodes:[{id:1,..},{id:2,..}...],links:[{source:1,target:2,..}...]}
        // .jsonUrl('../datasets/block.json')	//引入json文件数据
        .graphData(this.graphData)		//引入其他数据,更新数据也可用this.Graph.graphData(this.graphData)
        .backgroundColor('rgba(0,0,0,0)')
        .nodeLabel((node)=>{	//鼠标移上节点展示数据
            return node.id;	//可采用`<p style="">${node.name}<p>`dom元素模式
        })
        .nodeRelSize(4);	//可用于更新数据和修改节点大小,只能存数字,需要用方法可以使用nodeVal()
        .linkLabel((link)=>{//鼠标移上连线展示信息
            // console.log(link);
            let label = '';
            return label;
        })
        // .nodeAutoColorBy('id')	//节点随机色
        .nodeColor((node)=>{	//自定义色
        })
        // .nodeOpacity(0.75)	//节点透明度
        .linkColor((link)=>{	//连线颜色
        })
        .linkWidth((link)=>colors.mainLinks.indexOf(link)!=-1 ? 3 : 1)	//如果是主连线,其宽度为3否则为1
        .width(WIDTH)
        .height(HEIGHT)
        .onNodeHover(node => this.elem.style.cursor = node ? 'pointer' : null)
        .onNodeClick(node => {
            // this.handleCamera(node); 相机操作,比如拉近
            
            this.Graph.nodeRelSize(4);//(最新版用refresh更新)修改节点大小/半径,并更新。如果修改了颜色用这个方法可以触发更新才能看到效果,
            
        })
        .onLinkHover(link => this.elem.style.cursor = link ? 'pointer' : null)
        .onLinkClick(link=>{
           
        });
     //修改节点连线长度,同d3引擎用法,如果要调整物理引擎需要对d3有一定了解再参考官方提供的配置项
    this.Graph.d3Force('link').distance(this.space); 
},

初始化之后会遇到不同的需求去修改初始化后的属性

// 调整拉近相机,官方例子上有,修改distance大小即修改相机拉近距离
  handleCamera(node){
     
       const distance = 600;
       const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z);
       this.Graph.cameraPosition(
           { x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, // new position
           node, // lookAt ({ x, y, z })
           3000  // ms transition duration
       );
   },
   // 播放/暂停
   runCanvas(){
       this.run = !this.run;
	   !this.run?this.Graph.pauseAnimation():this.Graph.resumeAnimation();
   },

添加其他three模型进入3d-force-graph场景,要先安装three再引入

npm install three -S
import * as THREE from 'three'
//或者
var THREE = require("three");

再引入相关的渲染插件。一般可以不通过npm 安装,直接放入文件夹再引入。如此处节点上显示2d字体

import CSS2DObject,CSS2DRenderer} from '../utils/THREE/CSS2DRenderer.js
render() {	//两个render需要对three.js有一定了解
   requestAnimationFrame(this.render);
   this.twoDRenderer.render(this.Graph.scene(), this.Graph.camera());

 },
 render2D() {  	//CSS2DRenderer
   let a = document.getElementById("3d-graph");
   this.twoDRenderer = new THREE.CSS2DRenderer();
   this.twoDRenderer.setSize(a.clientWidth, a.clientWidth);
   this.twoDRenderer.domElement.style.position = "absolute";
   this.twoDRenderer.domElement.style.top = "0px";
   this.twoDRenderer.domElement.style.pointerEvents= "none";
   //this.twoDRenderer.domElement.style.zIndex = -1;
   //一般情况下2d字体在3d-graph下面是有一个div放置的,可能会出现看不到的情况,
   //调整z-index和样式或者直接加pointerEvents:none就可以解决,每个人遇到的情况都不同,比如我用z-index有些地方这样写可行有的就不行。
   //还有如果使用3drenderer其本质还是dom,但是3drenderer会存在景深层级比z-index更高,这种情况下去掉景深perspective,z-index:-1可以正常,但是dom不会随控制器缩放而缩放。可以给canvas一个样式pointer-events:none,使canvas可穿透,但是canvas点击事件会失效,可以尝试取消dom的点击事件,canvas即可正常(提供一种解决方案,具体视情况而定)
   a.appendChild(this.twoDRenderer.domElement);	
   this.twoDRenderer.render(this.Graph.scene(), this.Graph.camera());
   /* let grid = new THREE.GridHelper(1000, 50, 0x64FE00, 0x0C291F); //网格辅助,大小,行距,中心线颜色,网格线条颜色
         this.Graph.scene().add(grid); */
 },

如果需要在原有力导图的基础上,添加别的模型或者需要将球体换成别的自定义three模型。例如原api没有提供的长显示文字信息,只有鼠标移上才能显示相关信息。可以调用上面的创建2d文字方法
在这里插入图片描述
需要graph配置时定义

 this.Graph = ForceGraph3D()
 (this.elem)
     // .jsonUrl('../datasets/block.json')
     .graphData(this.graphData)
     .backgroundColor('rgba(0,0,0,0)')
	 .nodeThreeObjectExtend(true)	//函数,属性或布尔值,用于在使用自定义nodeThreeObject(false)或扩展它时是否替换默认节点(true)。如果false或者不设置会使nodeThreeObject返回的模型替换原有的球体节点
	 .nodeThreeObject(node => {
	     this.twoDRenderer.setSize( WIDTH, HEIGHT ); //按情况,如出现更新后文字不随节点动必要,不断更新size,防止位置会出现错乱。如果没出现可以去掉这个
	     return this.createAttackLabel(node); //返回需要的模型,这里是字体模型
	 })
	......

createAttackLabel(node){	//成功后需要在对应的位置下面去找创建的2drender的dom下面就看到了。由于可能出现被canvas覆盖的情况,所以有些时候会以为自己没有添加成功,需要通过z-index设置让文字显现出来且不影响图谱交互
   let labelDiv = document.createElement('div');
   labelDiv.className = 'attackLabel';
   labelDiv.id = node.id;
   labelDiv.textContent = node.name;
   let label = new THREE.CSS2DObject( labelDiv );   
   label.position.set(0,25,0);
   return label;
},

相比于2d字体其实用three-spritetext会更好,也更简单,有近大远小的空间感。但是精灵字体会比2d字体性能更差,可酌情选择(3d字体需要下载字体文件,占用空间和加载性能最好不要用)

import SpriteText from 'three-spritetext';
 //添加文字
addSpriteText(node){
     const sprite = new SpriteText(node.id);
     sprite.color = '#fff';
     sprite.textHeight = 10;
     sprite.position.set(0,12,0);
     return sprite;
 },
 //......使用
  this.Graph = ForceGraph3D()
(this.elem)
     .nodeThreeObject(node=>{
          return this.addSpriteText(node);
     })
     .nodeThreeObjectExtend((node=>{
         return true
     }))

这里我用的是默认的d3引擎,如果需要实现更深入的重力引力等调整需要对d3力导图有一定的了解,对照官方文档和d3写法,就可以找到解决问题的方案。如果需要做更多的3d效果可以参考three.js,

  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 61
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值