mtdv logo

核心概念

阅读时间约 15 分钟

节点

节点即画布中的一系列形状,可以是矩形,圆形,多边形等,我们可以根据业务需要自定义节点的形状。

内置节点

为了方便业务方的需求,更快的接入画布到业务中,我们提供了多种内置的节点,可以直接通过数据配置的方式直接接入。

基础节点

base-node

通用属性配置

// 所有节点通用属性
interface NodeData extends NodeConfig {
    type: string; // 节点类型
    id: string; // 节点的唯一标识
    clientX?: number;
    clientY?: number;
    x?: number; // 节点位置的 x 值
    y?: number; // 节点位置的 y 值
    color: string; // 默认绘制的 hover, port高亮的值
    fillColor: string; // 节点填充颜色
    strokeColor: string; // 节点边的颜色
    title: string; // 节点名称
    outputs?: number[][]; // 出口节点位置
    inputs?: number[][]; // 入口节点位置
    width?: number; // 节点宽度
    height?: number; // 节点高度
    outPortFillColor: string; // port的填充色
    portColor: string; // port默认颜色
    baseNodeCfg: Partial<baseNodeCfg>; // baseNode属性
    cardNodeCfg: Partial<cardNodeCfg>; // cardNode属性
    [key: string]: any; // 可能存在一些自定义的属性值
}

基础节点配置

// base节点属性
interface baseNodeCfg {
    type: 'block' | 'icon' | 'blockText';
    status: 'notReady' | 'success' | 'inProgress' | 'failure' | 'stop' | 'lock' | 'special';
    icon: string; // icon的类
    blockTitle: string; // 
    subTitle: string;// 第二行的文案 title对应第一行的文案
    statusIcon: string; // 状态icon
    statusFillColor: string; // 状态颜色
    blockFillColor: string; // 左侧块状填充色
    description: string;
    leftFillWidth: number;
    leftIconColor: string;
    statusDesc: string;
}

卡片节点

card-node

卡片节点配置

interface cardNodeCfg {
    panels: object[] | string[]; // 下面展示文案
    icon: string; // 头部icon
    iconColor: string; // icon颜色
    subTitle: string; // 右侧文案
    color: string; // 文字颜色
}

如何使用 icon

icon 我们是使用的公司提供的 iconfont,具体的项目地址是iconfont.sankuai.com,具体的使用方式跟其他字体图标一致,直接使用 class 即可。

如何自定义节点

首先,我们需要绘制出节点的形状,以下面的节点为例,我们分步演示如何画出一个节点。

node-demo

第一步:定义节点的关键形状。

function createNode (group, config, width, height) {
    const { strokeColor, fillColor } = cfg;
    // 外边框
    const keyShape = group.addShape('rect', {
        attrs: {
            x: 0, // 相对坐标
            y: 0, // 相对坐标
            width: width, // 节点宽
            height: height, // 节点高
            stroke: strokeColor, // 外边框颜色
            fill: fillColor, // 填充颜色
            radius: 2 // 半径
        }
    });

    return keyShape;
}

G6 中,每个节点都必须有一个关键形状,我们可以将其理解为节点的外部轮廓。我们通过group.addShape()方法来定义关键形状,这里我们定义了矩形react,也可以定义其他形状,然后在第二个参数中传入配置即可。

createNode函数中的前两个参数groupconfig会在此函数执行的时候由 G6 传入相关配置,group为 G6 的概念,代表一组图形,config代表我们配置节点的参数,比如我们配置节点的时候这样配置{strokeColor: '#ff0000', fillColor: '#00ff00'},则渲染的时候就会渲染出外边框是红色,填充色为绿色的图形。

第二步:在 group 里定义左边底色

group.addShape('rect', {
    attrs: {
        x: 0,
        y: 0,
        width: h - 1.5,
        height: h,
        fill: strokeColor,
        radius: [2, 0, 0, 2]
    },
    draggable: true
});

第三步,我们给节点加上文字描述,作为节点名称

// 文字
const textShape = group.addShape('text', {
    attrs: {
        x: (height - 14) / 2 + height,
        y: 9,
        width: width - height - (height - 14) / 2,
        fill: 'rgba(0, 0, 0, 0.92)',
        fontSize: 13,
        textBaseline: 'top',
        text: name
    }
});

第四步,我们给节点加上一个图片标签,美观的同时也让其更有意义

// 增加左侧图片
const image =
    'data:image/png;base64,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';
group.addShape('image', {
    attrs: {
        x: (height - 16) / 2,
        y: (height - 16) / 2,
        width: 16,
        height: 16,
        img: image
    },
    draggable: true
});

至此,我们就创建了一个节点,只要配置好数据,我们就能在画布上展示一系列这样的节点了。

port

节点与节点之间,如果要产生关系,需要通过连线来表示,要想将两个节点相连,需要通过 port 进行操作,所以一个节点需要分别有入线port以及出线port,否则其就是一个孤立的节点,不会与其他节点产生关系。

port-demo

如何绘制 port

绘制 port 非常简单,只需要在节点数据中配置即可,我们通过下面的例子讲解:

上面的例子中,将鼠标移到节点上,你会发现上边有两个入线port,下边有三个出线port,那如何设置呢?其实很简单,只需要如下配置即可:

const config = {
    type: 'rectNode',
    id: 'node1', // String,该节点存在则必须,节点的唯一标识
    x: 100, // Number,可选,节点位置的 x 值
    y: 20, // Number,可选,节点位置的 y 值
    color: '#1ea565',
    fillColor: '#ffffffc0',
    strokeColor: '#1ea565',
    name: '节点1',
    inputs: [[0, 0.5]], // 以左上角坐标为(0,0),右下角坐标为(1,1)
    outputs: [
        [1, 0],
        [1, 0.5],
        [1, 1],
    ],
}

可以看到,我们在component对象里配置了两个数组,分别为inputsoutputs,每个数组项就是一个 port,这里只需要传入portId以及name即可,port的位置会以节点边框的宽度进行平分,达到视觉上的美观。

上一节讲到,节点与之间的关系通过连线来表示,那如何配置连线呢?我们通过以下例子进行说明。

可以看到,节点 1 与节点 2 通过连线表明他们之间有某种关系,要实现连线,我们可以如下配置:

{
    edges: [
        {
            source: "node4",
            // String,必须,起始点 id
            target: "node1",
            // String,必须,目标点 id
            sourceAnchorIndex: 0,
            // 所在outputs的下标
            targetAnchorIndex: 0,
            // outputs的长度 + 所在inputs的下标
            style: {
                endArrow: {
                    path: "M 0,0 L 20,10 L 20,-10 Z",
                    d: 5,
                    fill: "#f00",
                    stroke: "#0f0",
                    opacity: 0.5,
                    lineWidth: 3
                    // ...
                }
            },
            type: "cubic"
        }
    ]
}

flow-graph-g6内置的连线,我们只需要简单配置即可实现常规的业务需求。

内置连线

base-line

如何配置内置连线

线段通用配置

interface EdgeData
    extends EdgeConfig {
    type: string; // 边类型
    source: string; // 起始节点 id
    target: string; // 目标节点 id
    sourceAnchorIndex?: number; // 起始点port索引
    targetAnchorIndex?: number; // 目标点port索引
    style?: EdgeStyle; // 线的样式
    label?: string; // 线的文本
    labelCfg: labelCfg; // 文本配置项
    [key
        :
        string
        ]:
        any; // 可能存在一些自定义的属性值
    baseLineCfg?: Partial<baseLineCfg>; // 自定义线段配置
}

自定义线段配置

interface baseLineCfg {
    type: 'rect' | 'rectText' | 'rectIcon' | 'icon' | 'dash' | 'statusText' | 'normal'; // 边类型
    rectStrokeColor: string; // 矩形border颜色
    rectFillColor: string; // 矩形填充色
    rectRadius: number; // 默认为10 rect、rectText、rectIcon下生效
    rectWidth: number; // 不建议使用
    rectHeight: number; // 不建议使用
    iconColor: string;
    textColor: string;
    icon: string; // icon的类
    label: string; // 展示文案
    showDashed: boolean; // 是否展示虚线
    statusFillColor: string; // 状态颜色 type为statusText时生效
}

除了初始化配置,我们还可以手动将两个节点相连,现在您就可以用鼠标将节点 2 与节点 3 相连,动手体验感受更加深刻。

如何自定义边

除了内置的线段 line、Polyline、Quadratic、Cubic、Arc、Loop 之外,我们还可以自定义边,那如何进行边的自定义,我们通过以下例子进行说明

edge-demo

第一步:定义边的关键形状。

G6.registerEdge('hvh', {
    draw (cfg, group) {
        const startPoint = cfg.startPoint;
        const endPoint = cfg.endPoint;
        const shape = group.addShape('path', {
            attrs: {
                stroke: '#333',
                path: [
                    ['M', startPoint.x, startPoint.y],
                    ['L', endPoint.x / 2 + (1 / 2) * startPoint.x, startPoint.y], // 三分之一处
                    ['L', endPoint.x / 2 + (1 / 2) * startPoint.x, endPoint.y], // 三分之二处
                    ['L', endPoint.x, endPoint.y],
                ],
            },
            // must be assigned in G6 3.3 and later versions. it can be any value you want
            name: 'path-shape',
        });
        return shape;
    },
});

第二步:指定边的类型。

{
    edges: [
        {
            id: "edge1",
            target: "node2",
            source: "node1",
            type: "hvh"
        },
        {
            id: "edge2",
            target: "node3",
            source: "node1",
            type: "hvh"
        }
    ],
}

事件系统

与 flow-graph-g6 的交互过程中,所有数据都是通过事件传递的。flow-graph-g6 封装了 11 种事件,每种事件对应着不同的动作,详情见下表:

动作事件
拖动节点开始nodeDragStart
拖动节点结束nodeDragEnd
鼠标悬浮节点nodeHover
鼠标从节点上移除nodeUnHover
右键单击节点nodeRightClick
选中节点(左键单击节点)nodeSelect
节点由选中态变为非选中态nodeUnselect
鼠标悬浮 portportHover
创建连线edgeCreate
左键单击连线edgeClick
右键单击连线edgeRightClick
鼠标悬浮连线edgeHover
鼠标离开连线edgeUnHover
点击画布canvasClick

监听事件

flow-graph-g6 通过 graphUtil 导出所有事件的事件名,每一个Flow实例都会维护一个自己的eventemitter3实例,因此我们可以使用eventemitter3的方法来绑定以及解绑事件。我们可以通过flow.bus获取flow实例的eventemitter3实例,所以我们就可以通过flow.bus.on方法监听事件,通过flow.bus.off方法解绑事件。

我们通过给节点加一个选中事件的例子进行演示:

上面的例子中,用鼠标左键点击节点,就会弹出一个浏览器原生 alert 框,里面显示点击的节点名称。要配置这样的功能,核心代码只要以下几行:

import { graphUtil } from '@ss/mtdv-graph-flow';

const flow = new Flow({/*...*/ })
const { events } = graphUtil;
flow.bus.on(events.nodeSelect, e => {
    alert(`您点击了${e.model.name}`);
});

插件机制

G6 中,如果想要改变节点或边的状态,一种方式是在注册节点的时候声明状态,然后在需要改变状态的地方调用graph.setItemState方法。flow-graph-g6 中分别对节点和边进行了一些状态的声明,具体如下:

node:

状态描述
selected节点被选择后的状态
hover节点被 hover 的状态
highlight节点高亮态,用来区分正常节点
failHighlight另一种高亮态,颜色与 highlight 有所区分
portHighlightport 高亮状态
default正常状态

edge:

状态描述
selected边被选中后的状态
hover边被 hover 后的状态
unHover边取消选中后的状态
highlight边高亮状态,用来区分正常节点
default正常状态

这些状态主要是改变节点或边的颜色,用来区分业务上不同的类型。我们可通过初始化节点的时候对节点的颜色进行配置;对于边的颜色,目前只支持通过注册复写的形式进行配置。

下面演示如何通过配置区分节点的状态展示:

如上面的例子所示,当我们用鼠标点击节点,会发现节点展示的状态并不一致,节点 1 展示偏绿色,节点 2 展示偏蓝色。

这里我们只需要在配置节点的时候声明不同的颜色即可。

{
    nodes: [
        // 节点1
        {
            // ...
            color: '#1ea565',
            // ...
        },
        // 节点2
        {
            // ...
            color: '#1239C7',
            // ...
        }
    ]
}

但是有时候我们希望做到更加精细的配置,此时就可以通过插件的方式注册或重写状态,这样你就可以随心所欲地定制不同状态的展现形式了。