Ant X6 简单流程图运用

官方小demo地址

官方文档

效果图:
在这里插入图片描述

Code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- import CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.1/lib/theme-chalk/index.css">
    <style>
        .dnd-rect {
            width: 100px;
            height: 40px;
            border: 2px solid #31d0c6;
            text-align: center;
            line-height: 40px;
            margin: 16px;
            cursor: move;
        }

        .el-drawer__body {
            padding: 20px;
        }

        .el-drawer__body {
            flex: 1;
        }

        .demo-drawer__content {
            display: flex;
            flex-direction: column;
            height: 100%;
        }

        .el-drawer__body>* {
            box-sizing: border-box;
        }

        .demo-drawer__content form {
            flex: 1;
        }

        .demo-drawer__footer {
            display: flex;
        }

        .demo-drawer__footer button {
            flex: 1;
        }
    </style>
</head>

<body>
    <div id='app'>
        <div data-type="rect" class="dnd-rect" onmousedown="drag(event)">
            Rect
        </div>
        <div id="container"></div>

        <el-drawer title="编辑节点" :before-close="handleCloseNode" :visible.sync="drawerNode" direction="rtl"
            custom-class="demo-drawer" ref="drawerNode">
            <div class="demo-drawer__content">
                <el-form :model="FormNode" label-position="top">
                    <el-form-item label="名称" :label-width="formLabelWidth" required>
                        <el-input v-model="FormNode.name" autocomplete="off"></el-input>
                    </el-form-item>
                    <el-form-item label="描述" :label-width="formLabelWidth">
                        <el-input v-model="FormNode.description" autocomplete="off"></el-input>
                    </el-form-item>
                    <el-form-item label="权限类型" :label-width="formLabelWidth">
                        <el-select v-model="FormNode.authorityType" placeholder="请选择权限类型">
                            <el-option label="用户" value="1"></el-option>
                            <el-option label="角色" value="2"></el-option>
                            <el-option label="组织/部门" value="3"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="审核人">
                        <el-row :gutter="20">
                            <el-col :span="21">
                                <el-input v-model="FormNode.authorityTarget" disabled placeholder="请选择审核人">
                                </el-input>
                            </el-col>
                            <el-col :span="2">
                                <el-button icon="el-icon-edit" type="primary" @click="SelectAuthorityTarget">
                                </el-button>
                            </el-col>
                        </el-row>
                    </el-form-item>
                </el-form>
            </div>
        </el-drawer>


        <!-- /------------分割线--------------/ -->
        <el-drawer title="编辑边" :before-close="handleCloseEdge" :visible.sync="drawerEdge" direction="rtl"
            custom-class="demo-drawer" ref="drawerEdge">
            <div class="demo-drawer__content">
                <el-form :model="FormEdge" label-position="top">
                    <el-form-item label="名称" :label-width="formLabelWidth" required>
                        <el-input v-model="FormEdge.name" autocomplete="off"></el-input>
                    </el-form-item>
                    <el-form-item label="描述" :label-width="formLabelWidth">
                        <el-input v-model="FormEdge.description" autocomplete="off"></el-input>
                    </el-form-item>
                    <el-form-item label="条件类型" :label-width="formLabelWidth">
                        <el-select v-model="FormEdge.conditionType" placeholder="请选择权限类型">
                            <el-option label="同意" value="1"></el-option>
                            <el-option label="驳回" value="2"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="附加条件" :label-width="formLabelWidth">
                        <el-input v-model="FormEdge.additionCondition" autocomplete="off"></el-input>
                    </el-form-item>
                </el-form>
            </div>
        </el-drawer>

    </div>

    <!-- import Antv X6 -->
    <script src="https://unpkg.com/@antv/x6@1.17.2/dist/x6.js"></script>
    <!-- import Vue before Element -->
    <script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
    <!-- import JavaScript -->
    <script src="https://unpkg.com/element-ui@2.15.1/lib/index.js"></script>
    <!-- import axios -->
    <script src="https://unpkg.com/axios@0.21.1/dist/axios.min.js"></script>
    <script script>
        var vm = new Vue({
            el: '#app',
            data() {
                return {
                    drawerNode: false, // 展开编辑节点菜单
                    drawerEdge: false, // 展开编辑边菜单
                    formLabelWidth: '80px',
                    FormNode: {
                        id: '',
                        name: '',
                        description: '',
                        stepType: "1",
                        authorityType: "1",
                        authorityTarget: "",
                        authorityTargetIds: [],
                    },

                    FormEdge: {
                        id: '',
                        name: '',
                        description: "",
                        startStepId: "",
                        endStepId: "",
                        conditionType: "1",
                        additionCondition: "",
                    },
                };
            },
            methods: {
                SelectAuthorityTarget: function () {
                    switch (this.FormNode.authorityType) {
                        case "1":
                            console.log("111");
                            break;
                        case "2":
                            console.log("222");
                            break;
                        case "3":
                            console.log("333");
                            break;
                        default:
                            break;
                    }
                },

                handleCloseNode(done) {
                    done();
                },

                handleCloseEdge(done) {
                    done();
                },
            }
        })
        // 定义节点
        X6.Graph.registerNode(
            'algo-node', {
                inherit: 'rect',
                width: 120,
                height: 50,
                ports: {
                    groups: {
                        in: {
                            position: 'top',
                            attrs: {
                                circle: {
                                    r: 5,
                                    magnet: true,
                                    stroke: '#ccc',
                                    strokeWidth: 1,
                                    fill: '#fff',
                                    style: {
                                        visibility: 'hidden',
                                    },
                                },
                            },
                        },
                        out: {
                            position: 'bottom',
                            attrs: {
                                circle: {
                                    r: 5,
                                    magnet: true,
                                    stroke: '#ccc',
                                    strokeWidth: 1,
                                    fill: '#fff',
                                    style: {
                                        visibility: 'hidden',
                                    },
                                },
                            },
                        },
                    },
                },
            },
            true,
        )

        // 定义边
        X6.Graph.registerConnector(
            'algo-edge',
            (source, target) => {
                const offset = 4
                const control = 80
                const v1 = {
                    x: source.x,
                    y: source.y + offset + control
                }
                const v2 = {
                    x: target.x,
                    y: target.y - offset - control
                }

                return `M ${source.x} ${source.y}
                        L ${source.x} ${source.y + offset}
                        C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${target.x} ${target.y - offset}
                        L ${target.x} ${target.y}
                        `
            },
            true,
        )

        // 初始化画布
        const graph = new X6.Graph({
            container: document.getElementById('container'),
            width: 1800,
            height: 800,
            history: true,
            selecting: true,
            background: {
                color: '#fffbe6', // 设置画布背景颜色
            },
            grid: {
                size: 10, // 网格大小 10px
                visible: true, // 渲染网格背景
            },
            panning: true,
            mousewheel: true,
            // resizing: true, // 选中调整大小
            connecting: {
                snap: true,
                allowBlank: false,
                allowLoop: false,
                highlight: true,
                sourceAnchor: 'bottom',
                targetAnchor: 'center',
                connectionPoint: 'anchor',
                connector: 'algo-edge',
                // 连接线
                createEdge() {
                    return graph.createEdge({
                        attrs: {
                            line: {
                                stroke: '#808080',
                                strokeWidth: 1,
                                targetMarker: {
                                    name: 'block',
                                    args: {
                                        size: '6',
                                    },
                                },
                            },
                        },
                    })
                },
                // 验证链接桩磁力
                // 如果不是in 也就是out分组时 可以进行连接 否则当作拖动节点
                // 当前out连接桩已连接的数量 当大于定义数时 验证返回错误
                // validateMagnet({
                //     cell,
                //     magnet
                // }) {
                //     if (magnet.getAttribute('port-group') !== 'in') {
                //         let count = 0
                //         const connectionCount = magnet.getAttribute('connection-count')
                //         const max = connectionCount ? parseInt(connectionCount, 10) : Number.MAX_SAFE_INTEGER
                //         const outgoingEdges = graph.getOutgoingEdges(cell)
                //         if (outgoingEdges) {
                //             outgoingEdges.forEach((edge) => {
                //                 const edgeView = graph.findViewByCell(edge)
                //                 if (edgeView.sourceMagnet === magnet) {
                //                     count += 1
                //                 }
                //             })
                //         }
                //         return count < max
                //     }
                //     return false
                // },
                // 验证连接
                validateConnection({
                    sourceView,
                    targetView,
                    sourceMagnet,
                    targetMagnet
                }) {
                    // 只能从输出链接桩创建连接
                    if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
                        return false
                    }

                    // 只能连接到输入链接桩
                    if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
                        return false
                    }

                    // 判断目标链接桩是否可连接
                    const portId = targetMagnet.getAttribute('port')
                    const node = targetView.cell
                    const port = node.getPort(portId)
                    if (port && port.connected) {
                        return false
                    }
                    return true
                }
            }
        });

        // 拖拽时使用
        const dnd = new X6.Addon.Dnd({
            target: graph,
            scaled: false,
            animation: true,
        })

        // 移入显示连接桩
        const changePortsVisible = (visible) => {
            const ports = container.querySelectorAll(
                '.x6-port-body',
            )
            for (let i = 0, len = ports.length; i < len; i = i + 1) {
                ports[i].style.visibility = visible ? 'visible' : 'hidden'
            }
        }
        graph.on('node:mouseenter', () => {
            changePortsVisible(true)
        })
        graph.on('node:mouseleave', () => {
            changePortsVisible(false)
        })

        // 拖入节点
        function drag(e) {
            console.log(e);
            var node = graph.createNode({
                shape: 'algo-node',
                x: 120,
                y: 50,
                label: 'Hello',
                attrs: {
                    label: {
                        text: 'Node',
                        fill: '#6a6c8a',
                    },
                    body: {
                        fill: '#fff',
                        stroke: '#31d0c6',
                        strokeWidth: 2,
                    },
                },
                data: {
                    tag: "edit-node",
                },
                ports: [{
                        group: 'in',
                    },
                    {
                        group: 'out',
                        attrs: {
                            circle: {
                                magnet: true,
                                // connectionCount: 1, // 自定义属性,控制连接桩可连接多少条边
                            }
                        }
                    },
                ],
            })
            dnd.start(node, e)
        }

        // 节点和边的移入删除按钮
        graph.on('node:mouseenter', ({
            node
        }) => {
            if (node.data.tag === "edit-node") {
                node.addTools({
                    name: 'button-remove',
                    args: {
                        x: 0,
                        y: 0,
                        offset: {
                            x: 10,
                            y: 15
                        },
                    },
                })
            }
        })
        graph.on('node:mouseleave', ({
            node
        }) => {
            if (node.data.tag === "edit-node") {
                node.removeTools()
            }
        })
        graph.on('edge:mouseenter', ({
            edge
        }) => {
            edge.addTools({
                name: 'button-remove',
                args: {
                    x: 0,
                    y: 0,
                    offset: {
                        x: 0,
                        y: 0
                    },
                },
            })
        })
        graph.on('edge:mouseleave', ({
            edge
        }) => {
            edge.removeTools()
        })

        // 监听改变选中节点时 改变对应的样式
        graph.on('selection:changed', (args = {
            added,
            removed,
            selected,
        }) => {
            args.selected.forEach((cell) => {
                if (cell.isNode()) {
                    cell.attr('body', {
                        fill: '#ffd591',
                    })
                } else {
                    cell.attr('line/stroke', '#ffa940')
                }
            })
            args.removed.forEach((cell) => {
                if (cell.isNode()) {
                    cell.attr('body', {
                        fill: '#fff',
                    })
                } else {
                    cell.attr('line/stroke', '#808080')
                }
            })
        })

        //监听节点和边的单击
        graph.on('cell:click', ({
            e,
            x,
            y,
            cell,
            view
        }) => {
            if (cell.isNode()) {
                if (cell.data.tag === "edit-node") {
                    vm.drawerEdge = false;
                    vm.drawerNode = !vm.drawerNode;
                    if (vm.drawerNode) {
                        console.log(cell);
                        if (cell.data == null) {
                            cell.data = {
                                id: '',
                                name: '',
                                description: '',
                                stepType: "1",
                                authorityType: "1",
                                authorityTarget: "",
                                authorityTargetIds: [],
                            }
                        }
                        cell.data.id = cell.id;
                        vm.FormNode = cell.data;
                    }
                }
            } else {
                vm.drawerNode = false;
                vm.drawerEdge = !vm.drawerEdge;
                if (vm.drawerEdge) {
                    console.log(cell);
                    if (cell.data == null) {
                        cell.data = {
                            id: '',
                            name: '',
                            description: "",
                            startStepId: "",
                            endStepId: "",
                            conditionType: "1",
                            additionCondition: "",
                        }
                    }
                    cell.data.id = cell.id;
                    vm.FormEdge = cell.data;
                }
            }


        })

        // 初始化 添加节点和边
        const begin = graph.addNode({
            shape: 'algo-node',
            x: -50,
            y: -260,
            label: '提交审核',
            attrs: {
                body: {
                    fill: '#fff',
                    stroke: '#87C7F4',
                    strokeWidth: 2,
                },
            },
            ports: [{
                group: 'out',
                attrs: {
                    circle: {
                        magnet: true,
                        // connectionCount: 1, // 自定义属性,控制连接桩可连接多少条边
                    }
                }
            }, ],
            data: {
                tag: "",
            },
        })
        const end = graph.addNode({
            shape: 'algo-node',
            x: -50,
            y: 260,
            label: '审核结束',
            attrs: {
                body: {
                    fill: '#fff',
                    stroke: '#87C7F4',
                    strokeWidth: 2,
                },
            },
            ports: [{
                group: 'in',
            }, ],
            data: {
                tag: "",
            },
        })
        graph.addEdge({
            source: {
                cell: begin,
                port: begin.ports.items[0].id
            },
            target: {
                cell: end,
                port: end.ports.items[0].id
            },
            attrs: {
                line: {
                    stroke: '#808080',
                    strokeWidth: 1,
                    targetMarker: {
                        name: 'block',
                        args: {
                            size: '6',
                        },
                    },
                },
            },
        })

        graph.centerContent()
    </script>


    <!-- 
    g.getNodes() 所有节点 节点中data 中可以存放自定义信息
    g.getEdges() 所有边 source 起始点id     target 结束点id
    g.toJson() 转json
	-->
</body>

</html>
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值