npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rasir/x6-arch

v1.2.10

Published

基于antv/x6的架构设计工具

Downloads

4

Readme

AUTH

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

前言

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

效果图

效果图

快速上手

说明

本组件是在react框架下的前端组件,推荐[email protected]以上版本。推荐使用[email protected]脚手架。其他必要依赖见下文。

目前,作品还有很多需要完善的地方,有些兼容没有处理,推荐使用 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 | 需要加载的数据,如果要更新数据,需要获取数据后,清理掉缓存 | 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<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) => 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