antv/x6 2.x 搭建流程图编辑页面(1)

进来闲来无事,看到x6 2.x版本也更新了有几个月了,便想着熟悉下2.x版本

一、首先搭建项目基础框架。

// yarn 方式
yarn create @vitejs/app v3-ts --template vue-ts
cd v3-ts
yarn
yarn dev

// npm 
npm init @vitejs/app v3-ts --template vue-ts
cd v3-ts
npm install 
npm run dev

二、下载antv/x6以及对应所需要的插件包

package.json
{
  "@antv/x6": "^2.0.0",
  "@antv/x6-plugin-clipboard": "^2.0.0", // 如果使用剪切板功能,需要安装此包
  "@antv/x6-plugin-history": "^2.0.0", // 如果使用撤销重做功能,需要安装此包
  "@antv/x6-plugin-keyboard": "^2.0.0", // 如果使用快捷键功能,需要安装此包
  "@antv/x6-plugin-minimap": "^2.0.0", // 如果使用小地图功能,需要安装此包
  "@antv/x6-plugin-scroller": "^2.0.0", // 如果使用滚动画布功能,需要安装此包
  "@antv/x6-plugin-selection": "^2.0.0", // 如果使用框选功能,需要安装此包
  "@antv/x6-plugin-snapline": "^2.0.0", // 如果使用对齐线功能,需要安装此包
  "@antv/x6-plugin-dnd": "^2.0.0", // 如果使用 dnd 功能,需要安装此包
  "@antv/x6-plugin-stencil": "^2.0.0", // 如果使用 stencil 功能,需要安装此包
  "@antv/x6-plugin-transform": "^2.0.0", // 如果使用图形变换功能,需要安装此包
  "@antv/x6-plugin-export": "^2.0.0", // 如果使用图片导出功能,需要安装此包
  "@antv/x6-react-components": "^2.0.0", // 如果使用配套 UI 组件,需要安装此包
  "@antv/x6-react-shape": "^2.0.0", // 如果使用 react 渲染功能,需要安装此包
  "@antv/x6-vue-shape": "^2.0.0" // 如果使用 vue 渲染功能,需要安装此包
}

三、新建graph文件夹。并创建index.ts文件用来封装画布、侧边栏stencil组件、插件、快捷键与事件。

graph/index.ts
import { Graph, Shape} from "@antv/x6";

export default class FlowGraph {
  public static graph: Graph;

  public static init() {
    this.graph = new Graph({
      container: document.getElementById("graph-container")!,
      background: {
        color: "#fff",
      },
      grid: true,
      mousewheel: {
        enabled: true,
        zoomAtMousePosition: true,
        modifiers: "ctrl",
        minScale: 0.5,
        maxScale: 3,
      },
      connecting: {
        router: {
          name: "manhattan",
          args: {
            padding: 1,
          },
        },
        connector: {
          name: "rounded",
          args: {
            radius: 8,
          },
        },
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: false,
        snap: {
          radius: 20,
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#A2B1C3",
                strokeWidth: 2,
                targetMarker: {
                  name: "block",
                  width: 12,
                  height: 8,
                },
              },
            },
            zIndex: 0,
          });
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet;
        },
      },
      highlighting: {
        magnetAdsorbed: {
          name: "stroke",
          args: {
            attrs: {
              fill: "#5F95FF",
              stroke: "#5F95FF",
            },
          },
        },
      },
    });
    return this.graph;
  }
}

四、页面进行基础布局,并初始化画布。

App.vue





  • 此时画布创建成功,效果如下图:
    antv/x6 2.x 搭建流程图编辑页面(1)_第1张图片
  • 接下来来完善侧边栏stencil组件

五、初始化侧边栏stencil组件

graph/index.ts
import { Graph, Shape } from "@antv/x6";
import { Stencil } from "@antv/x6-plugin-stencil";

export default class FlowGraph {
    public static graph: Graph;
    public static stencil: Stencil;

  public static init() {
    this.graph = new Graph({
      container: document.getElementById("graph-container")!,
      background: {
        color: "#fff",
      },
      grid: true,
      mousewheel: {
        enabled: true,
        zoomAtMousePosition: true,
        modifiers: "ctrl",
        minScale: 0.5,
        maxScale: 3,
      },
      connecting: {
        router: {
          name: "manhattan",
          args: {
            padding: 1,
          },
        },
        connector: {
          name: "rounded",
          args: {
            radius: 8,
          },
        },
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: false,
        snap: {
          radius: 20,
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#A2B1C3",
                strokeWidth: 2,
                targetMarker: {
                  name: "block",
                  width: 12,
                  height: 8,
                },
              },
            },
            zIndex: 0,
          });
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet;
        },
      },
      highlighting: {
        magnetAdsorbed: {
          name: "stroke",
          args: {
            attrs: {
              fill: "#5F95FF",
              stroke: "#5F95FF",
            },
          },
        },
      },
    });
    this.initStencil();
    return this.graph;
    }
    
    public static initStencil() {
        this.stencil = new Stencil({
          title: "流程图",
          target: this.graph,
          search(cell, keyword) {
            return (cell as any).label.indexOf(keyword) !== -1;
          },
          placeholder: "Search by shape name",
          notFoundText: "Not Found",
          stencilGraphWidth: 280,
          stencilGraphHeight: 180,
          collapsable: true,
          groups: [
            {
              title: "基础流程图",
              name: "group1",
            },
            {
              title: "系统设计图",
              name: "group2",
              graphHeight: 250,
              layoutOptions: {
                rowHeight: 70,
              },
            },
          ],
          layoutOptions: {
            columns: 3,
            columnWidth: 80,
            rowHeight: 55,
          },
        });
        document.getElementById("stencil")!.appendChild(this.stencil.container);
    }
}

六、此时可以在graph目录下新建shape.ts来注册更多不同类型的节点

graph/shape.ts
import { Graph } from "@antv/x6";

const ports = {
  groups: {
    top: {
      position: "top",
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: "#5F95FF",
          strokeWidth: 1,
          fill: "#fff",
          style: {
            visibility: "hidden",
          },
        },
      },
    },
    right: {
      position: "right",
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: "#5F95FF",
          strokeWidth: 1,
          fill: "#fff",
          style: {
            visibility: "hidden",
          },
        },
      },
    },
    bottom: {
      position: "bottom",
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: "#5F95FF",
          strokeWidth: 1,
          fill: "#fff",
          style: {
            visibility: "hidden",
          },
        },
      },
    },
    left: {
      position: "left",
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: "#5F95FF",
          strokeWidth: 1,
          fill: "#fff",
          style: {
            visibility: "hidden",
          },
        },
      },
    },
  },
  items: [
    {
      group: "top",
    },
    {
      group: "right",
    },
    {
      group: "bottom",
    },
    {
      group: "left",
    },
  ],
};
Graph.registerNode(
  "custom-rect",
  {
    inherit: "rect",
    width: 66,
    height: 36,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: "#5F95FF",
        fill: "#EFF4FF",
      },
      text: {
        fontSize: 12,
        fill: "#262626",
      },
    },
    ports: { ...ports },
  },
  true
);

Graph.registerNode(
  "custom-polygon",
  {
    inherit: "polygon",
    width: 66,
    height: 36,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: "#5F95FF",
        fill: "#EFF4FF",
      },
      text: {
        fontSize: 12,
        fill: "#262626",
      },
    },
    ports: {
      ...ports,
      items: [
        {
          group: "top",
        },
        {
          group: "bottom",
        },
      ],
    },
  },
  true
);

Graph.registerNode(
  "custom-circle",
  {
    inherit: "circle",
    width: 45,
    height: 45,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: "#5F95FF",
        fill: "#EFF4FF",
      },
      text: {
        fontSize: 12,
        fill: "#262626",
      },
    },
    ports: { ...ports },
  },
  true
);

Graph.registerNode(
  "custom-image",
  {
    inherit: "rect",
    width: 52,
    height: 52,
    markup: [
      {
        tagName: "rect",
        selector: "body",
      },
      {
        tagName: "image",
      },
      {
        tagName: "text",
        selector: "label",
      },
    ],
    attrs: {
      body: {
        stroke: "#5F95FF",
        fill: "#5F95FF",
      },
      image: {
        width: 26,
        height: 26,
        refX: 13,
        refY: 16,
      },
      label: {
        refX: 3,
        refY: 2,
        textAnchor: "left",
        textVerticalAnchor: "top",
        fontSize: 12,
        fill: "#fff",
      },
    },
    ports: { ...ports },
  },
  true
);

七、初始化侧边栏stencil组件内的节点。

graph/index.ts
import { Graph, Shape } from "@antv/x6";
import { Stencil } from "@antv/x6-plugin-stencil";
import './shape'

export default class FlowGraph {
  public static graph: Graph;
  public static stencil: Stencil;

  // 初始化画布
  public static init() {
    this.graph = new Graph({
      container: document.getElementById("graph-container")!,
      background: {
        color: "#fff",
      },
      grid: true,
      mousewheel: {
        enabled: true,
        zoomAtMousePosition: true,
        modifiers: "ctrl",
        minScale: 0.5,
        maxScale: 3,
      },
      connecting: {
        router: {
          name: "manhattan",
          args: {
            padding: 1,
          },
        },
        connector: {
          name: "rounded",
          args: {
            radius: 8,
          },
        },
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: false,
        snap: {
          radius: 20,
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#A2B1C3",
                strokeWidth: 2,
                targetMarker: {
                  name: "block",
                  width: 12,
                  height: 8,
                },
              },
            },
            zIndex: 0,
          });
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet;
        },
      },
      highlighting: {
        magnetAdsorbed: {
          name: "stroke",
          args: {
            attrs: {
              fill: "#5F95FF",
              stroke: "#5F95FF",
            },
          },
        },
      },
    });
      this.initStencil();
      this.initShape()
    return this.graph;
  }

  // 初始化侧边栏stencil组件
  public static initStencil() {
    this.stencil = new Stencil({
      title: "流程图",
      target: this.graph,
      search(cell, keyword) {
        return (cell as any).label.indexOf(keyword) !== -1;
      },
      placeholder: "Search by shape name",
      notFoundText: "Not Found",
      stencilGraphWidth: 280,
      stencilGraphHeight: 180,
      collapsable: true,
      groups: [
        {
          title: "基础流程图",
          name: "group1",
        },
        {
          title: "系统设计图",
          name: "group2",
          graphHeight: 250,
          layoutOptions: {
            rowHeight: 70,
          },
        },
      ],
      layoutOptions: {
        columns: 3,
        columnWidth: 80,
        rowHeight: 55,
      },
    });
    document.getElementById("stencil")!.appendChild(this.stencil.container);
  }

  // 初始化stencil组件内的节点
  public static initShape() {
    const { graph } = this;
    const r1 = graph.createNode({
      shape: "custom-rect",
      label: "开始",
      attrs: {
        body: {
          rx: 20,
          ry: 26,
        },
      },
    });
    const r2 = graph.createNode({
      shape: "custom-rect",
      label: "过程",
    });
    const r3 = graph.createNode({
      shape: "custom-rect",
      attrs: {
        body: {
          rx: 6,
          ry: 6,
        },
      },
      label: "可选过程",
    });
    const r4 = graph.createNode({
      shape: "custom-polygon",
      attrs: {
        body: {
          refPoints: "0,10 10,0 20,10 10,20",
        },
      },
      label: "决策",
    });
    const r5 = graph.createNode({
      shape: "custom-polygon",
      attrs: {
        body: {
          refPoints: "10,0 40,0 30,20 0,20",
        },
      },
      label: "数据",
    });
    const r6 = graph.createNode({
      shape: "custom-circle",
      label: "连接",
    });
    this.stencil.load([r1, r2, r3, r4, r5, r6], "group1");

    const imageShapes = [
      {
        label: "Client",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg",
      },
      {
        label: "Http",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg",
      },
      {
        label: "Api",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg",
      },
      {
        label: "Sql",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg",
      },
      {
        label: "Clound",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg",
      },
      {
        label: "Mq",
        image:
          "https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg",
      },
    ];
    const imageNodes = imageShapes.map((item) =>
      graph.createNode({
        shape: "custom-image",
        label: item.label,
        attrs: {
          image: {
            "xlink:href": item.image,
          },
        },
      })
    );
    this.stencil.load(imageNodes, "group2");
  }
}

  • 此时页面效果如下:
    antv/x6 2.x 搭建流程图编辑页面(1)_第2张图片

接下来需要完善 快捷键与事件Toolbar 工具栏、以及节点属性配置。具体看下篇文章。

你可能感兴趣的:(React,Vue,antv/x6,流程图,javascript,前端)