1.2.10 • Published 2 years ago

@rasir/x6-arch v1.2.10

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

AUTH

作者:rasir 源码地址 文档地址

前言

这是一款基于antv/x6的用于系统架构设计可视化的一款工具。

效果图

效果图

快速上手

说明

本组件是在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"
  },

使用方式

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) =>
          (<AppModule form={form} data={data} />),
        },
      ],
    },
    {
      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 (
    <Arch
      data={data}
      moduleConfig={moduleConfig}
      assets={assets}
      appendActions={<div>hello</div>}
      registerList={registerList}
      defaultNodeShape="arch-node"
      onCreateNode={onCreateNode}
      cache={false}
    />
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

自定义抽屉中的内容

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<AppModuleProps> = function (props) {
  const { form, data } = props;

  useEffect(() => {
    if (data) {
      form?.setFieldsValue(data);
    } else {
      form?.resetFields();
    }
  }, [data]);

  return (
    <Form form={form}>
      <FormItem
        name="name"
        label="APP名称"
        rules={[
          {
            required: true,
            message: '请填写app名称',
          },
        ]}
      >
        <Input placeholder="请填写app名称"></Input>
      </FormItem>
    </Form>
  );
};

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需要加载的数据,如果要更新数据,需要获取数据后,清理掉缓存ArchDataundefined
moduleConfig画布左侧的组件模版,包含申请组件需要填写的数据ModuleConfigundefined
cache是否使用 indexdb 缓存数据,autoSaveInterval > 0时生效booleanundefined
autoSaveInterval数据自动保存的间隔时间 默认为 0,为 0 时不自动保存。单位为 msnumber0
showActions是否显示功能按钮booleantrue
actions显示功能键分类ActionTypes[]undefined
appendActions功能键右侧添加额外的组件React.ReactNodeundefined
registerList需要注册的节点和线条的样式Register[]undefined
defaultEdgeShape默认生成线条的样式名称stringlaneEdge
defaultNodeShape默认生成节点的样式名称stringundefined
moduleNodeShape左侧模型节点样式名称stringmoduleNode
drawerRootNode节点编辑弹窗根节点false \| string \| HTMLElement \| (() => HTMLElement);undefined
onAddLink在画布中添加链接的回调,返回 promise<boolaen>。如果 resolve(true) 则建立链接,如果 resolve(false)则不会产生链接。(link: Edge) => Promise<boolean>undefined
onRemoveLink在画布中移除链接的回调,返回 promise<boolaen>。如果 resolve(true) 则移除链接,如果 resolve(false)则不会移除链接。(links: Edge[]) => Promise<boolean>undefined
onRemoveNode在画布中移除节点的回调,返回 promise<boolaen>。如果 resolve(true) 则移除节点,如果 resolve(false)则不会移除节点。(nodes: Node[]) => Promise<boolean>undefined
onCreateNode在画布中新建节点的回调,返回 promise<NodeData>。如果 resolve(data) 则创建新节点,如果 resolve(false)则不会创建节点。(nodeData: NodeData) => Promise<NodeData>undefined
onUpdateNode在画布中编辑节点的回调,返回 promise<NodeData>。如果 resolve(data) 则更新节点数据,如果 resolve(false)则不会更新节点数据。(nodeData: NodeData) => Promise<NodeData>undefined
onUndoOrRedo在画布中撤销和重做的回调。因为数据是之前已经产生过的,不需要用户再次确认,但可能存在与后端的交互,所以开放给开发者进行处理。节点数据更新不会放入撤销和重做队列中(type: 'undo' \| 'redo',graph: Graph,args: { cmds: any[]; options: any }) => Promise<boolean>undefined
onSave将画布中数据保存至后端,返回 promise<boolean>。如果 resolve(true) 则保存成功,如果 resolve(false)则保存失败。(data: ArchData) => Promise<boolean>undefined
onAutoSave每隔一段时间自动将数据同步出来(data: ArchData) => anyundefined
onChange节点和连线发生变化时的回调(data: ArchData) => anyundefined

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节点层级 默认 1number
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链接源端节点 IDstring \| number
target链接目标端节点 IDstring \| 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

参数说明类型
InputPropantd 表单录入组件属性any
...antd FormItem 属性any

V1.1.0 修改

  1. 修改了 iconfont 引入方式,不再需要手动引入。
  2. 增加了功能键的可选,可以只使用部分功能键。
  3. 删除预置的内部系统和外部系统图标。
  4. 去除内置节点样式,让用户自定义节点样式,保留默认边。
  5. 可自定义泳道样式

V1.2.0 新增功能

  1. 新增 onChange 事件,节点和连线发生变化时都将出发 onChange。
  2. 可以通过鼠标滚动或拖拽画布空白处调整当前视窗。不兼容 IE
1.2.0

2 years ago

1.1.1

2 years ago

1.0.2

2 years ago

1.1.0

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago

1.2.8

2 years ago

1.2.7

2 years ago

1.2.6

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.2

2 years ago

1.1.3

2 years ago

1.2.1

2 years ago

1.1.2

2 years ago

1.2.9

2 years ago

1.2.10

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago