# rasir-x6-arch **Repository Path**: rasir/rasir-x6-arch ## Basic Information - **Project Name**: rasir-x6-arch - **Description**: 基于antv/x6的架构设计工具 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 7 - **Forks**: 3 - **Created**: 2022-08-17 - **Last Updated**: 2024-11-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### AUTH 作者:rasir [源码地址](https://gitee.com/rasir/rasir-x6-arch) [文档地址](http://rasir.gitee.io/rasir-x6-arch-doc/#/) ### 前言 这是一款基于`antv/x6`的用于系统架构设计可视化的一款工具。 ### 效果图 ![效果图](./md_images/preview.png) ### 快速上手 #### 说明 本组件是在`react`框架下的前端组件,推荐`react@16.8`以上版本。推荐使用`umijs@3.x`脚手架。其他必要依赖见下文。 目前,作品还有很多需要完善的地方,有些兼容没有处理,推荐使用 mac + 谷歌最新浏览器。这样能体验到更好的滚动效果。 #### 安装方式 通过 npm 安装 `npm i @rasir/x6-arch -S` #### 必要依赖 ``` "dependencies": { "@antv/x6": "^1.33.1", "ahooks": "^3.7.0" }, "peerDependencies": { "antd": ">=4.x", "react": ">=16.14.0", "react-dom": ">=16.14.0" }, ``` #### 使用方式 ```tsx import React from 'react'; import ReactDOM from 'react-dom'; // 自定义的节点配置组件 import AppModule from './AppModule'; import moduleConfig from './moduleConfig'; import Arch from '../src'; import registerList from './register'; import 'antd/dist/antd.css'; import './index.less'; import appIcon from './icon/app.png'; .... import bmsIcon from './icon/bms.png'; const data = { "lanes": [ { "id": "user", "name": "用户层", "height": 120 }, { "id": "access", "name": "接入层", "height": 150 }, { "id": "app", "name": "应用逻辑层", "height": 200 }, { "id": "store", "name": "存储层", "height": 150 } ], "nodes": [ { "id": "1", "x": 100, "y": 180, "name": "ARCH-VIEW-DUBBO-K8S-SIT", "moduleType": "bmr", "preId": "access" }, { "id": "2", "x": 100, "y": 380, "name": "ARCH-VIEW-DUBBO-K8S-SIT", "moduleType": "tidb", "preId": "app" }, { "id": "3", "x": 300, "y": 380, "name": "ARCH-VIEW-DUBBO-K8S-SIT", "moduleType": "browser", "preId": "app" }, { "id": "4", "x": 300, "y": 30, "name": "ARCH-VIEW-DUBBO-K8S-SIT", "moduleType": "app", "preId": "user" }, { "moduleType": "jetty", "name": "ceshi2222", "x": 450, "y": 380, "preId": "app", "id": "1flj7sg14", "label": "Jetty", "icon": "jetty", "value": "jetty", "type": "node", "image": "jettyModule", "bgImage": "innerSystem" }, { "moduleType": "jetty", "name": "ceshi11111", "x": 600, "y": 380, "preId": "app", "id": "1flj7sg1422", "label": "Jetty", "icon": "jetty", "value": "jetty", "type": "node", "image": "jettyModule", "bgImage": "innerSystem" }, ], "links": [{ "source": "1", "target": "2" }] } const config: ModuleConfig = { search: { placeholder: '请输入组件名称', }, options: [ { label: '用户层组件', value: 'userLayer', children: [ { label: 'USER', icon: 'user', moduleType: 'user', moduleImage: 'user', value: 'user', target: ['user'], moduleProp: () => [ { type: 'INPUT', label: '用户名称', name: 'name', inputProps: { allowClear: true, placeholder: '请输入用户名称', className: 'search-input', }, rules: [ { required: true, message: '请选择使用时长', }, ], }, ] as ModuleFormItem[], }, { label: 'APP', icon: 'app', value: 'app', moduleProp: (data, form) => (), }, ], }, { label: '云主机', value: 'clound', children: [ { label: 'Jetty', icon: 'jetty', value: 'jetty', moduleProp: [], }, { label: 'Nginx', icon: 'nginx', value: 'nginx', moduleProp: [], }, { label: 'Other', icon: 'other', value: 'other', moduleProp: [], }, ], }, { label: '裸金属', value: 'mate', children: [ { label: 'BMS', icon: 'bms', value: 'bms', moduleProp: [], }, ], }, { label: 'K8S容器', value: 'k8s', children: [ { label: 'Dubbo', icon: 'dubbo', value: 'dubbo', moduleProp: [], }, { label: 'SpringBoot', icon: 'springboot', value: 'springboot', moduleProp: [], }, { label: 'NODEJS', icon: 'nodejs', value: 'nodejs', moduleProp: [], }, { label: 'PYTHON', icon: 'python', value: 'python', moduleProp: [], }, { label: 'Jetty', icon: 'jetty', value: 'jetty', moduleProp: [], }, { label: 'Nginx', icon: 'nginx', value: 'nginx', moduleProp: [], }, ], }, { label: '中间件', value: 'middelwear', children: [ { label: 'Redis', icon: 'redis', value: 'redis', moduleProp: [], }, { label: 'Kafka', icon: 'kafka', value: 'kafka', moduleProp: [], }, { label: 'Zookeeper', icon: 'zookeeper', value: 'zookeeper', moduleProp: [], }, ], }, { label: '数据库', value: 'database', children: [ { label: 'MySQL', icon: 'mysql', value: 'mysql', moduleProp: [], }, ], }, ], }; const assets = { appIcon, bmsIcon, .... } const App = () => { const onCreateNode = (nodeData) => { const { name } = nodeData; return Promise.resolve({ id: '100', name, moduleType: 'user', systemType: 'inner', preId: 'user', shape: 'arch-node', }); }; return ( hello} registerList={registerList} defaultNodeShape="arch-node" onCreateNode={onCreateNode} cache={false} /> ); }; ReactDOM.render(, document.getElementById('root')); ``` #### 自定义抽屉中的内容 ```tsx import { Form, Input } from 'antd'; import { FormInstance } from 'antd/es/form/Form'; import React, { useEffect } from 'react'; interface AppModuleProps { data?: any; form: FormInstance; [key: string]: any; } const { Item: FormItem } = Form; const AppModule: React.FC = function (props) { const { form, data } = props; useEffect(() => { if (data) { form?.setFieldsValue(data); } else { form?.resetFields(); } }, [data]); return (
); }; export default AppModule; ``` #### 注意 iconfont 不再需要另外引入 ### 功能说明 - 生成节点,拖拽左侧组件到右侧,会有弹窗让用户填写相关信息然后生成节点。 - 调整节点尺寸,单击节点,出现工具端口,拖动端口调整节点尺寸。 - 右键删除节点 右键点击节点,在右键菜单中点击删除。触发 `onRemoveNode` - 右键编辑节点 右键单击节点,在右键菜单中点击编辑,在弹窗中对数据进行编辑。但是节点层级和组件类型不能编辑,触发 `onUpdateNode` - 调整层级高度,鼠标移入层级下侧拖拽线,点击鼠标左键进行拖动对层级高度进行调整。 - 生成连线,在画布中从源端节点的端口拖拽连线到目标节点的端口。相同两个节点不能有重复的连线,生成节点前会调用 `onAddLink` - 删除连线,鼠标移入链接出现删除按钮。点击按钮会触发 `onRemoveLink` - 组件过滤,在左侧搜索框中输入内容,对下面的组件模版进行过滤 - 撤销重做,画布上的操作都可以通过撤销重做来操作。会触发 `onUndoOrRedo` 回调 - 放大 最多放大到当前画布的 `1.5` 倍 - 缩小 最小缩小到当前画布的 `0.5` 倍 - 全屏 展开整个编辑器到全屏操作 - 取消全屏 - 本地导入数据 在弹窗中拖入 `ArchData` 结构的 `.json` 文件 - 本地导出数据 生成 `ArchData` 结果的`.json` 文件 - 本地导出图片 将画布区域生成 `png` 图片 - 上传数据 触发 `onSave` - 复制节点 左键单击节点,再点击复制节点按钮,节点信息将放入剪贴板中 - 粘贴节点 点击粘贴节点按钮,将触发 `onCreateNode` - 删除节点 左键单击节点,再点击删除节点按钮。触发 `onRemoveNode` - 清理缓存 点击清理缓存,将清除缓存数据,并触发 `reload` ,而使用 `data` 传入的数据 ### 快捷键 - 复制节点到剪贴板 `ctrl+c/commond+c` - 粘贴节点 `ctrl+v/commond+v` - 撤销 `ctrl+z/commond+z` - 重做 `ctrl+shift+z/commond+shift+z` - 删除节点 `backspace/backspace` - 放大 `ctrl+1/commond+1` - 缩小` ctrl+2/commond+2` - 清理缓存 `ctrl+e/commond+e` ### API | 参数 | 说明 | 类型 | 默认值 | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------ | | `assets` | 图片资源键值对 | `Object` | `{}` | | `data` | 需要加载的数据,如果要更新数据,需要获取数据后,清理掉缓存 | `ArchData` | `undefined` | | `moduleConfig` | 画布左侧的组件模版,包含申请组件需要填写的数据 | `ModuleConfig` | `undefined` | | `cache` | 是否使用 indexdb 缓存数据,`autoSaveInterval > 0`时生效 | `boolean` | `undefined` | | `autoSaveInterval` | 数据自动保存的间隔时间 默认为 `0`,为 `0` 时不自动保存。单位为 ms | `number` | `0` | | `showActions` | 是否显示功能按钮 | `boolean` | `true` | | `actions` | 显示功能键分类 | `ActionTypes[]` | `undefined` | | `appendActions` | 功能键右侧添加额外的组件 | `React.ReactNode` | `undefined` | | `registerList` | 需要注册的节点和线条的样式 | `Register[]` | `undefined` | | `defaultEdgeShape` | 默认生成线条的样式名称 | `string` | `laneEdge` | | `defaultNodeShape` | 默认生成节点的样式名称 | `string` | `undefined` | | `moduleNodeShape` | 左侧模型节点样式名称 | `string` | `moduleNode` | | `drawerRootNode` | 节点编辑弹窗根节点 | `false \| string \| HTMLElement \| (() => HTMLElement);` | `undefined` | | `onAddLink` | 在画布中添加链接的回调,返回 `promise`。如果 `resolve(true)` 则建立链接,如果 `resolve(false)`则不会产生链接。 | `(link: Edge) => Promise` | `undefined` | | `onRemoveLink` | 在画布中移除链接的回调,返回 `promise`。如果 `resolve(true)` 则移除链接,如果 `resolve(false)`则不会移除链接。 | `(links: Edge[]) => Promise` | `undefined` | | `onRemoveNode` | 在画布中移除节点的回调,返回 `promise`。如果 `resolve(true)` 则移除节点,如果 `resolve(false)`则不会移除节点。 | `(nodes: Node[]) => Promise` | `undefined` | | `onCreateNode` | 在画布中新建节点的回调,返回 `promise`。如果 `resolve(data)` 则创建新节点,如果 `resolve(false)`则不会创建节点。 | `(nodeData: NodeData) => Promise` | `undefined` | | `onUpdateNode` | 在画布中编辑节点的回调,返回 `promise`。如果 `resolve(data)` 则更新节点数据,如果 `resolve(false)`则不会更新节点数据。 | `(nodeData: NodeData) => Promise` | `undefined` | | `onUndoOrRedo` | 在画布中撤销和重做的回调。因为数据是之前已经产生过的,不需要用户再次确认,但可能存在与后端的交互,所以开放给开发者进行处理。节点数据更新不会放入撤销和重做队列中 | `(type: 'undo' \| 'redo',graph: Graph,args: { cmds: any[]; options: any }) => Promise` | `undefined` | | `onSave` | 将画布中数据保存至后端,返回 `promise`。如果 `resolve(true)` 则保存成功,如果 `resolve(false)`则保存失败。 | `(data: ArchData) => Promise` | `undefined` | | `onAutoSave` | 每隔一段时间自动将数据同步出来 | `(data: ArchData) => any` | `undefined` | | `onChange` | 节点和连线发生变化时的回调 | `(data: ArchData) => any` | `undefined` | ### ArchData 输入数据结构 | 参数 | 说明 | 类型 | | -------- | ------------ | ------------ | | `width` | 画布宽度 | `number` | | `height` | 画布高度 | `number` | | `lanes` | 节点层级配置 | `NodeData[]` | | `nodes` | 组件节点 | `NodeData[]` | | `links` | 组件连线 | `LinkData[]` | ### NodeData 数据结构 | 参数 | 说明 | 类型 | | ------------ | -------------------------- | ---------------- | | `id` | 节点 ID (必需) | `string` | | `name` | 节点名称 (必需) | `string` | | `type` | 节点类型 (必需) | `"lane"\|"node"` | | `width` | 节点宽度 | `number` | | `height` | 节点高度 | `number` | | `zIndex` | 节点层级 默认 1 | `number` | | `x` | 节点 x 坐标 | `number` | | `y` | 节点 y 坐标 | `number` | | `moduleType` | 节点组件类型 (必需) | `string` | | `preId` | 节点所在层级的 ID (必需) | `string` | ### ActionTypes ``` type ActionTypes = 'RE_UN_DO' | 'ZOOM' | 'EXPORT_DATA' | 'IMPORT_DATA' | 'EXPORT_IMG'| 'SUBMIT' | 'COPY' | 'PASTE' | 'DELETE' | 'CLEAR' ``` | 参数 | 说明 | | ------------- | ------------------ | | `RE_UN_DO` | 撤销/重做 | | `ZOOM` | 放大/缩小/全屏 | | `EXPORT_DATA` | 导出数据 | | `IMPORT_DATA` | 导入数据 | | `EXPORT_IMG` | 导出图片 | | `SUBMIT` | 上传数据,保存数据 | | `COPY` | 复制节点 | | `PASTE` | 粘贴节点 | | `DELETE` | 删除节点 | | `CLEAR` | 清理缓存 | ` ` ### Register `NODE 是节点;EDGE是线条`
`type Register = { name: string; options: any; type: 'NODE' | 'EDGE'; handler: NodeHanlder; };` ### LinkData 数据结构 | 参数 | 说明 | 类型 | | -------- | ---------------------- | ------------------- | | `source` | 链接源端节点 ID | `string \| number` | | `target` | 链接目标端节点 ID | `string \| number ` | | `zIndex` | 链接所在层次(非必需) | `number` | ### ModuleConfig 左侧组件类型定义 | 参数 | 说明 | 类型 | | --------- | ------------------------------------ | ------------------------------------ | | `title` | 左侧组件标题 | `string` | | `search` | 是否需要搜索组件,以及搜索功能的配置 | `undefined\|{placeholder?: string;}` | | `options` | 左侧组件 | `ModuleGropuItem[]` | #### ModuleGropuItem | 参数 | 说明 | 类型 | | ---------- | -------- | -------------------- | | `label` | 显示内容 | `string` | | `value` | 标记 | `string` | | `children` | 组件群 | `ModuleConfigItem[]` | #### ModuleConfigItem | 参数 | 说明 | 类型 | | ------------- | ------------------------------------------------------------------------------------------------------------ | -------------------- | | `label` | 显示内容 | `string` | | `value` | 标记 | `string` | | `moduleImage` | 图标 可根据`assets[moduleImage]\|\| assets[${moduleType ? moduleType : value}Module\|\|moduleImage `获取图片 | `ModuleConfigItem[]` | | `target` | 组件只能放入哪些层级,如果为 undefined 或者[]默认可以放入所有层级 | `string[]` | | `moduleProp` | 组件模版参数表单使用 | `ModulePropItem[]` | #### ModulePropItem | 参数 | 说明 | 类型 | | ----------- | --------------------- | ----- | | `InputProp` | antd 表单录入组件属性 | `any` | | `...` | antd FormItem 属性 | `any` | ### V1.1.0 修改 1. 修改了 iconfont 引入方式,不再需要手动引入。 2. 增加了功能键的可选,可以只使用部分功能键。 3. 删除预置的内部系统和外部系统图标。 4. 去除内置节点样式,让用户自定义节点样式,保留默认边。 5. 可自定义泳道样式 ### V1.2.0 新增功能 1. 新增 onChange 事件,节点和连线发生变化时都将出发 onChange。 2. 可以通过鼠标滚动或拖拽画布空白处调整当前视窗。不兼容 IE