jtopo 实现一键布局

article/2025/8/14 19:11:56

           最近很忙、也很懒,一堆烦心事,jtopo后面不准备再深究了,本身东西也不多,做出的新功能,新特效也都写到博客中来了,今天给大家分享最近研究的一个新技能——jtopo一键布局,写给大家、也写给自己。

        因为jtopo天然不支持节点对其,所以很不友好,但甲方往往需要的是理想化的操作,所以一键布局显得尤为必要,还是老规矩,先看效果,再说实现。

        这里完全不需要手动去拖动节点,只需要点击按钮,即可实现自动布局成树形结构,用到的思想就是递归函数,会的小伙伴们可以止步了,下面详细说说是怎么实现的。

         想要实现自动布局,第一步当然是要先拿到所有的节点了,然后再找到根节点,放到指定的位置,再依次排布它的子节点,所有的节点都这样排列完成后,就能得到我们想要的树形布局,思路有了,下来就该动手实现了。

//一键布局(顺序布局)
function Auto_position(){let nodes = editor.utils.getAllNodes();let nodes_tree=[],childs=[];nodes.map(function(item,index){if(item.inLinks.length<1){nodes_tree.push(item)}else{childs.push(item)}});//递归填充树状数据结构for (let i = 0; i < nodes_tree.length; i++) {find_child(nodes_tree[i],childs)}let start_point={"x":0,"y":0};start_point.x = editor.scene.translateX//-(childs.length/2*editor.config.nodeDefaultWidth);start_point.y = editor.scene.translateY;//重新设置节点新坐标for (let i = 0; i < nodes_tree.length; i++) {           set_location(Object.assign({},start_point),nodes_tree[i],nodes_tree.length);start_point.x +=editor.config.nodeDefaultWidth*5;}
}

        这里自定义了两个递归函数,一个是find_child,另外一个是set_location。find_child用来查找每个节点的子节点,最终拼装成树形数据结构(这里给每个节点都增加了cnode属性,存储当前节点的所有子节点),具体实现如下:

//查找指定节点的父节点
function find_child(node,all)
{node.cnode=[];let outlines = node.outLinks;for (let i = 0; i < outlines.length; i++) {let cnode_id = outlines[i].nodeDst;let cnodes = []all.map(function(t,c_index){if (t.nodeId==cnode_id) {cnodes.push(t);}});if (cnodes.length>0) {node.cnode.push(cnodes[0]);find_child(cnodes[0],all);}}
}

代码很短很简洁,主要的思路是根据传进来的节点node,查找到它的所有子节点填装到cnodes数组中去,再去判断每个子节点有无孙子节点,如果有,继续套入当前方法,直到最终的末级节点。最终的结果是每个node结构底下都会多出一个cnode的树形,存储了当前节点的子节点的集合。

         到这里我们基本上已经完了数据的建模,整个数据结构都已经出来了,接下来要做的是去重新布局。

        假设,我们拿到了任意的一个节点,并且知道这个节点的坐标,那么我们就可以确定它的子节点的坐标,其实也简单,我们只需要给x轴一个偏移量,y轴增加一个固定值即可,想想,子节点就在父节点的下方,难道不是吗?这里我们分了两种情况,一种是有两个子节点,一种是有多个子节点,这种做的目的是为了只有两个子节点时,让节点的y轴位置偏移小一点,最终的效果是二次折线是直角连接,代码如下:

//设置当前节点的坐标到指定位置
function set_location(location,node,brothers_cout){let his,laster;//只有两个节点时直角连线if (brothers_cout == 2) {location.y -= 2.25*editor.config.nodeDefaultWidth;his = points.find(a=>a.x==location.x && a.y > (location.y/3));while (his) {laster = his; location.x =laster.x + 5*editor.config.nodeDefaultWidth; his = points.find(a=>a.x==location.x && a.y > (location.y/3));}   }else{his = points.find(a=>a.y==location.y && a.x > (location.x-5*editor.config.nodeDefaultWidth));while (his) {laster = his; location.x =laster.x + 5*editor.config.nodeDefaultWidth; his = points.find(a=>a.x > (location.x-5*editor.config.nodeDefaultWidth) && a.y==location.y);}}node.x=location.x;node.y=location.y;//console.log(location);points.push(node);location.y +=6*editor.config.nodeDefaultWidth;let outlinks = editor.utils.getAllLinks();let x_h = (node.cnode.length-1)*5*editor.config.nodeDefaultWidth/2;location.x -= x_hfor (let i = 0; i < node.cnode.length; i++) {set_location(Object.assign({},location),node.cnode[i],node.cnode.length);//创建新的连线let lin = outlinks.find(a=>a.nodeSrc == node.nodeId && a.nodeDst == node.cnode[i].nodeId)[0];if (lin) {self.link = new JTopo.FlexionalLink(node, node.cnode[i])self.link.lineType = 'flexLine'self.link.lineWidth = editor.config.linkDefaultWidthself.link.strokeColor = editor.config.linkFillColorself.link.arrowsRadius = 10;self.link.linkAlpha = editor.config.linkAlphaself.link.linkStrokeColor = editor.config.linkStrokeColorself.link.linkFillColor = editor.config.linkFillColorself.link.linkShadow = editor.config.linkShadowself.link.linkShadowColor = editor.config.linkShadowColorself.link.linkFont = editor.config.linkFontself.link.fontColor = editor.config.linkFontColorself.link.bid = lin.bid;self.link.nodeDst = lin.nodeDst;self.link.nodeSrc = lin.nodeSrc;self.link.text = lin.text;self.link.textA = lin.textA;self.link.textZ = lin.textZ;self.link.linkArrowsRadius = editor.config.linkArrowsRadiusself.link.linkDefaultWidth = editor.config.linkDefaultWidthself.link.linkOffsetGap = editor.config.linkOffsetGapself.link.linkDirection = editor.config.linkDirectioneditor.scene.add(self.link)editor.scene.remove(lin)}location.x +=5*editor.config.nodeDefaultWidth;}//修正父节点的坐标resetParent_location(node);
}

这里需要注意的一点是节点间的连线,因为我们是自动布局,所以之前的连线不再适用,这里就重新绘制了(for循环里边的部分就是绘制连线,同时删除了之前老的连线),最后一行resetParent_location(node);是为了二次反馈修复父节点的坐标,因为存在如下的情形:

子节点的坐标没有问题,但父节点偏到了一边,所以需要二次反馈矫正。二次反馈矫正的思路是找到父节点的所有亲兄弟节点,算出他们的中心位置节点的坐标,然后赋值给当前的父节点:

//二次修复父节点坐标
function resetParent_location(node){let outlinks = editor.utils.getAllLinks();let lin = outlinks.find(a=>a.nodeDst == node.nodeId)[0];if (!lin) {return;}let nodes = editor.utils.getAllNodes();let parent = nodes.find(a=>a.nodeId == lin.nodeSrc);if (!parent) {return}else{parent = parent[0];}let x_s = [];parent.cnode.map(function(t,i){x_s.push(t.x);});let x = Math.min.apply(null,x_s) + (Math.max.apply(null,x_s) - Math.min.apply(null,x_s))/2;parent.x = x;
}

             所有的这些可以封装到一个js模块中,当哪里需要的时候,可以直接调用Auto_position()方法,即可实现我们想要的效果,好了,有问题的小伙伴可以留言给我,看到会及时回复的,如果觉得博主的代码有用,别忘了点赞加关注哦~!


http://chatgpt.dhexx.cn/article/cFLWLHiW.shtml

相关文章

jtopo简单实例

原贴地址 http://cn-arthurs.iteye.com/blog/2009345 说明: jtopo是一个基于canvas的js拓扑图形组件.比canvasexpress容易多了. 可以方便地加点,加连线,加鼠标事件,拖曳. 号称跨浏览器,不过实际上不支持ie678,加上excanvas.js也没用,除非像canvasexpress那样使用chrome插件. …

Vue — jTopo

近期在Vue项目中使用jTopo来制作集群节点拓扑图&#xff0c;官网http://www.jtopo.com/ 使用vue-cli搭建的模块化开发项目&#xff0c;使用第三方库最好的方式就是通过npm install xxx安装&#xff0c;然后在项目 里import xxx来使用&#xff1b;但是在JTopo官网上并没有发现有…

【Vue引入JTopo及所遇到的问题】

Vue引入JTopo及所遇到的问题 前言一、方案选型二、使用步骤三、总结 前言 项目过程中总是会遇到稀奇古怪的需求&#xff0c;这不&#xff0c;咱老大又让我画一个系统拓扑图放在首页&#xff0c;要求部分数据需从后端获取&#xff0c;动态展示在页面上。对于一个后端人猿来说&a…

Vue+JTopo(一)

1.下载js jtopo 更新下载 (不知道为什么网站被封禁了……在这提供下我现在用的 jtopo-1.4.4_trial-esm-min.js) 链接&#xff1a;https://pan.baidu.com/s/18V1HKwAuxzWM19RD4axGOg 提取码&#xff1a;0304 2.引用 文件放在public/js文件夹下&#xff0c;在index.hml内引用。…

jTopo(一)

jTopo(一) 一、jTopo是什么 jTopo&#xff08;Javascript Topology library)是一款完全基于HTML5 Canvas的关系、拓扑图形化界面开发工具包。 jTopo关注于数据的图形展示&#xff0c;它是面向开发人员的&#xff0c;需要进行二次开发。 使用jTopo很简单&#xff0c;可以快速…

windows10下安装MSYS2+MinGW64

1.下载msys2&#xff0c;官方地址&#xff1a;http://www.msys2.org/&#xff0c;这里选择64位的安装器 2.安装完成之后&#xff0c;先别启动msys2&#xff0c;在 安装根目录/etc/pacman.d/ 下找到mirrorlist.mingw32、mirrorlist.mingw64和mirrorlist.msys并进行修改。 mirr…

Win10 下安装 MSYS2

什么是 MSYS2 MSYS2 &#xff08;Minimal SYStem 2&#xff09; 是一个MSYS的独立改写版本&#xff0c;主要用于 shell 命令行开发环境。同时它也是一个在Cygwin &#xff08;POSIX 兼容性层&#xff09; 和 MinGW-w64&#xff08;从"MinGW-生成"&#xff09;基础上…

【msys2】使用msys2下载工具的旧版本

背景 苯人在计组实验中使用了msys2来安装verilator工具&#xff0c;结果最新版本的verilator有bug&#xff0c;几经探索找到了利用msys2下载旧版本工具的方法&#xff08;还可以将现有工具更新为旧版本&#xff09; 步骤 现以安装旧版本的verilator为例讲解方法。 这是msys…

【Window环境下使用MSYS2搭建CMake + MinGW环境】

目录标题 安装CMakecmake 测试 MSYS2下载MSYS2安装MSYS2修改软件下载源 MSYS2下安装MinGW配置MinGW配置到环境变量 hello world测试 安装CMake Cmake下载地址:https://cmake.org/download/,下一个windows压缩包就好了&#xff0c;因为我比较喜欢自己来配置&#xff0c;免得不知…

用MSYS2安装mingw

文章目录 前言卸载mingw安装MSYS2 前言 安装MSYS2的原因是&#xff0c;在windows安装protobuf时&#xff0c;想用mingw编译protobuf的库&#xff0c;而protobuf的官方手册只给出一句&#xff1a; To build from source using Cygwin or MinGW, follow the Unix installation i…

【VSCode】【msys2】VS Code + msys2配置Windows下C/C++开发环境

【VSCode】【msys2】VS Code msys2配置Windows下C/C开发环境 一、Msys2配置 1. 下载msys2, 网址&#xff1a;https://www.msys2.org/ 2. 安装msys2-x86_64-xxxx.exe 这里没什难度&#xff0c;记住安装路径就好&#xff0c;一路next就装好了。 3. 安装gcc 3.1. 更新msys2…

Msys2记录

MSYS2 ​ MSYS2是MSYS的升级版&#xff0c;集成了pacman和Mingw-w64的Cygwin升级版&#xff0c;提供了Mingw-w64的GNU工具&#xff0c;包括GCC&#xff0c;同时移植了Arch Linux的软件包管理系统pacman&#xff0c;具备了Cygwin的POSIX API&#xff0c;理论上在Linux上的程序使…

msys2在windows10系统的安装

测试系统: windows 10 首先需要msys2的安装包,可以去官网下载安装包 官网地址: http://www.msys2.org/ 本次下载的是 msys2-x86_64-20180531.exe 注意:1.msys2不可以安装在FAT*分区    2.msys2不能安装在win XP系统上 1.双击msys2-x86_64-20180531.exe,并点击下一步选择安…

MSYS2使用教程——win10系统64位安装msys2最新版(msys2-x86_xxxx.exe)

一、安装 测试系统: windows 10 首先需要msys2的安装包,可以去官网下载安装包 官网地址: http://www.msys2.org/ 本次下载的是 msys2-x86_64-latest.exe 注意: 1. msys2不可以安装在FAT*分区 2. msys2不能安装在win XP系统上 指定好安装路径&#xff08;一般D根目录即可&#…

初步使用MSYS2

在此镜像站点下载&#xff0c; https://mirror.tuna.tsinghua.edu.cn/help/msys2/ 根据资料&#xff0c; MSYS2 &#xff08;Minimal SYStem 2&#xff09; 是一个MSYS的独立改写版本&#xff0c;主要用于 shell 命令行开发环境。同时它也是一个在Cygwin &#xff08;POSIX …

超详细教程:windows安装MSYS2(mingw gcc)——更新于2021.11

目录 安装 MSYS2官网&#xff1a;https://www.msys2.org/ 安装 下载安装程序&#xff08;官网首页有&#xff09;&#xff1a;msys2-x86_64-20210725.exe 或 CSDN&#xff1a;https://download.csdn.net/download/ymzhu385/45988277运行安装程序。MSYS2 需要 64 位 Windows 7…

Argparse 教程

官方文档 argparse --- 命令行选项、参数和子命令解析器 — Python 3.10.2 文档 别人的笔记Argparse 教程 — Python 3.10.2 文档https://docs.python.org/zh-cn/3/howto/argparse.html#id1完整的argparse的API argparse --- 命令行选项、参数和子命令解析器 — Python 3.8…

python argparse

argparse 模块可以让人轻松编写用户友好的命令行接口。程序定义它需要的参数&#xff0c;然后 argparse 将弄清如何从 sys.argv 解析出那些参数。 argparse 模块还会自动生成帮助和使用手册&#xff0c;并在用户给程序传入无效参数时报出错误信息。 使用argparse从命令行传入参…

python argparse type_python argparse详解

1.argparse模块作用 用于解析命令行参数 2.位置参数和可选参数 运行以下代码: import argparse parser = argparse.ArgumentParser() args = parser.parse_args() 运行结果: 参数为-h或--help时,parser.parse_args()会输出命令行的位置参数position arguments和可选参数opti…

Python3中使用argparse模块解析命令行参数

argparse是Python的一个标准模块&#xff0c;用于解析命令行参数&#xff0c;即解析sys.argv中定义的参数。实现在&#xff1a;https://github.com/python/cpython/blob/main/Lib/argparse.py argparse模块还会自动生成帮助和使用信息&#xff0c;即在最后加-h或--help。当用户…