4.8 群组

2021-12-28  本文已影响0人  skoll

简介

1 .相关的一堆节点的集合
2 .他这里也仅仅是做了一些最简单的操作,如果想要实现复杂的部分,就要自定义节点结构,或者整个节点我可以直接用react这种方式实现.然后整个react里面我写各种复杂的功能,可能我一个点里面还能选日期什么的,这种发挥就可以完全不受原来框架的限制,自由发挥了

嵌套节点

<!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>
    <script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
</head>
<body>
    <h3>基本图形和属性</h3>
    <div id="container">

    </div>
    <script>
        const graph=new X6.Graph({
            container:document.getElementById('container'),
            width:800,
            height:600,
            grid:true,
        })
        
        const parent=graph.addNode({
            x:40,
            y:40,
            width:360,
            height:160,
            zIndex:1,
            //注意,这个是有层级结构后特有的,父级的层级一定要在子集下面,index要大于子集
            label:"父级元素",
            attrs:{
                label:{
                    refY:0,
                    refX:0,
                    fontSize:12,
                },
                body:{
                    fill:"#fffbe6",
                    stroke:"#ffe7ba"
                }
            }
        })
        

        const target=graph.createNode({
            x:80,
            y:100,
            width:80,
            height:40,
            label:"孩子",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    fill:"#fff",
                    fontSize:12,
                }
            }
        })

        const source=graph.createNode({
            x:280,
            y:80,
            width:80,
            height:40,
            label:"孩子2",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    refY:10,
                    fontSize:12,
                }
            }
        })

        //不用添加到整个graph里面addNode.而是要往他的父级里面插入
        parent.addChild(target)
        parent.addChild(source)

        //已经添加到父元素里面了,我直接连接子元素也是可以的,他也会自动更新到父级元素里面,跟随父元素自动拖拽
        graph.addEdge({
            target,
            source,
            //只要是连线的地方,竟然必须是target,source这样的原来的字,换了都不行,简直顶
            vertices: [
                { x: 120, y: 60 },
                { x: 200, y: 100 },
            ],
        })


  
    </script>
</body>
</html>

拖入拖出父节点

1 .

<!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>
    <script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
</head>
<body>
    <h3>基本图形和属性</h3>
    <div id="container">

    </div>
    <script>
        const graph=new X6.Graph({
            container:document.getElementById('container'),
            width:800,
            height:600,
            grid:true,
            embedding:{
                //定制插入属性,可以插入一个节点到另一个节点称为他的子节点
                enabled:true,
                findParent({node}){
                    //找到之前的前面的标志位,在下方其实是加了一个parent:true的标志位,标示只能往这个里面拖拽
                    const box=node.getBBox()
                    //要插入的节点

                    //this.getNodes:找到当前所有的父元素
                    return this.getNodes().filter((node)=>{
                        const data=node.getData()
                        if(data&&data.parent){
                            return box.isIntersectWithRect(node.getBBox())
                        }
                        return false
                    })
                }
            },
            //拖拽进入的时候父级元素的表现,默认是自己的操作
            highlighting:{
                embedding:{
                    name:"stroke",
                    args:{
                        padding:-1,
                        attrs:{
                            stroke:"#73d13d"
                        }
                    }
                }
            },
            //限制节点移动,子节点不能移出父节点,大节点不能移出画布
            translating:{
                //restrict:true,
                //全部节点不能移出画布
                //restrict:{
                //    x:0,
                //    y:0,
                //    width:100,
                //    height:100,
                //},
                //只能在这个给定的矩形区域内移动,
                restrict(view){
                    
                    //获取到的是当前拖动的节点
                    const cell=view.cell
                    console.log('v',cell.data)
                    if(cell.isNode()){
                        //保证当前拖动的节点类型,而不是线条
                        const parent=cell.getParent()
                        console.log(cell.data.translate,'ddd')
                        if(parent&&cell.data.translate==false){
                            return parent.getBBox()
                            //如果有父节点,大小限制在父节点的范围内

                            //也就是只有设置标志为translate为false的元素,才不能脱离父元素
                        }return null
                    }return null

                }
            }
        })
        
        const parent=graph.addNode({
            x:40,
            y:40,
            width:360,
            height:160,
            zIndex:1,
            //注意,这个是有层级结构后特有的,父级的层级一定要在子集下面,index要大于子集
            label:"父级元素",
            attrs:{
                label:{
                    refY:0,
                    refX:0,
                    fontSize:12,
                },
                body:{
                    fill:"#fffbe6",
                    stroke:"#ffe7ba"
                }
            },
            data:{
                parent:true
            }
        })
        

        const target=graph.createNode({
            x:80,
            y:100,
            width:80,
            height:40,
            label:"孩子",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    fill:"#fff",
                    fontSize:12,
                }
            },
            data:{
                translate:false,
            }
        })

        const source=graph.createNode({
            x:280,
            y:80,
            width:80,
            height:40,
            label:"孩子2",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    refY:10,
                    fontSize:12,
                }
            },
            data:{
                translate:true,
            }
        })

        //不用添加到整个graph里面addNode.而是要往他的父级里面插入
        parent.addChild(target)
        parent.addChild(source)

        graph.on('node:change:parent',({node})=>{
            console.log('变动')
            node.attr({
                label:{
                    text:'Child在外面'
                }
            })
        })

       
    </script>
</body>
</html>

自动扩展/收缩父节点,按照ctrl才能拖出

<!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>
    <script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
</head>
<body>
    <h3>基本图形和属性</h3>
    <div id="container">

    </div>
    <script>
        const graph=new X6.Graph({
            container:document.getElementById('container'),
            width:800,
            height:600,
            grid:true,
            embedding:{
                enabled:true,
            },
            highlighting:{
                embedding:{
                    name:"stroke",
                    args:{
                        padding:-1,
                        attrs:{
                            stroke:"#73d13d"
                        }
                    }
                }
            }          
        })
        
        const parent=graph.addNode({
            x:40,
            y:40,
            width:360,
            height:160,
            zIndex:1,
            //注意,这个是有层级结构后特有的,父级的层级一定要在子集下面,index要大于子集
            label:"父级元素",
            attrs:{
                label:{
                    refY:0,
                    refX:0,
                    fontSize:12,
                },
                body:{
                    fill:"#fffbe6",
                    stroke:"#ffe7ba"
                }
            },
            data:{
                parent:true
            }
        })
        

        const target=graph.createNode({
            x:80,
            y:100,
            width:80,
            height:40,
            label:"孩子",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    fill:"#fff",
                    fontSize:12,
                }
            },
            data:{
                translate:false,
            }
        })

        const source=graph.createNode({
            x:280,
            y:80,
            width:80,
            height:40,
            label:"孩子2",
            zIndex:10,
            attrs:{
                body:{
                    stroke:"none",
                    fill:"#47c769"
                },
                label:{
                    refY:10,
                    fontSize:12,
                }
            },
            data:{
                translate:true,
            }
        })

        //不用添加到整个graph里面addNode.而是要往他的父级里面插入
        parent.addChild(target)
        parent.addChild(source)

        let ctrlPressed=false
        const embedPadding=20

        graph.on('node:change:parent',({node})=>{
            console.log('父级关系发生变动')
            node.attr({
                label:{
                    text:'Child在外面'
                }
            })
        })

        graph.on('node:embedding',({e})=>{
            ctrlPressed=e.metaKey||e.ctrlKey
            //当前是拖拽情况,如果按下了ctrl辅助键位,设置下这个标志位
        })

        graph.on('node:embedding',({e})=>{
            ctrlPressed=false
        })

        graph.on('node:change:position',({node,options})=>{
            //所有的逻辑都在某一个节点移动的时候触发
            const parent=node.getParent()

            if(parent&&parent.isNode()){
                console.log(parent)

                //获取父节点的原本大小
                let originSize=parent.prop('originSize')
                if(originSize==null){
                    //第一次的时候设置初始大小,之后就可以不用每次都用函数调用了
                    originSize=parent.getSize()
                    parent.prop('originSize',originSize)
                }

                let originPosition=parent.prop('originPosition')
                if(originPosition==null){
                    originPosition=parent.getPosition()
                    parent.prop('originPosition',originPosition)
                }

                console.log(originPosition,originSize)
                let x=originPosition.x
                let y=originPosition.y

                let cornerX=originPosition.x+originSize.width
                let cornerY=originPosition.y+originSize.height

                let hasChange=false
                //大小是否发生了变化做一个标志位   

                //先找到自己元素的父亲,然后父亲在他的儿子里面找最大边界
                const children=parent.getChildren()

                //if(children){
                    //那这种不是子节点越多,性能压力越大么?为啥不是以单个节点的位置来算
                    //果然要遍历全部的,不然一个拖拽会把别的给搞出去.也就是说任何一个拖动,都不能把别的给搞出去,但是这只是缩小的问题,可以缩小的时候在检测
                    //https://x6.antv.vision/zh/examples/node/group#expand-shrink
                //}

                if(node&&node.isNode()){
                    //还要给所有操作的字元素添加一个标记
                    const bbox=node.getBBox()
                    const corner=bbox.getCorner()
                    //当前拖拽节点的位置

                    if(bbox.x<x){
                        x=bbox.y
                        //仅仅是这里需要做检测.x往小缩的时候,在检查是否有其余的在这个里面
                        //或者维护一个最右边的边界值,现在有一个默认的最小高度,最小宽度.但是这个还要加上不被拖拽的,或者现在的阶段就不应该去思考优化的问题

                        hasChange=true
                    }

                    if(bbox.y<y){
                        y=bbox.y
                        hasChange=true
                    }

                    if(corner.x>cornerX){
                        cornerX=corner.x
                        hasChange=true
                    }

                    if(corner.y>cornerY){
                        cornerY=corner.y
                        hasChange=true
                    }
                }

                if(hasChange){
                    //如果有变化的话,更新父级元素的大小
                    parent.prop(
                        {
                            position:{x,y},
                            //还要重设他的位置
                            size:{
                                width:cornerX-x,height:cornerY-y
                            }

                        }    
                    )
                }
            }
        })

       
    </script>
</body>
</html>

嵌套节点

1 .使用constructor之后就不行了.奇怪.难道现在的语法只支持这样写?

class Group extends X6.Node {
            collapsed = false
            expandSize= { width: 100, height:100 }    
 }

2 .而不支持这样写?

class Group extends X6.Node{
            constructor(){
                super()
                this.collapsed=false
                this.expandSize={
                    width:100,
                    height:100
                }
            }      
 }

3 .但是看起来这两种,是都会把这个值绑定到继承之后的值,生成他的一个新属性的..
4 .首先看下官方社区有没有这方面的文档吧.https://github.com/antvis/X6/issues/1007 果然发现,应该是这一条,问题来了,这俩人研究了半天,最后没解决...给出的例子根本就和继承没关系
5 .子类继承父类,子类必须在 constructor 中调用 super() 之后才能使用 this 这条怎么不适用了呢?
6 .目前合理的解释.第一种写法虽然没写,但是默认有一个这样的操作

class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}

7 .而我自己写的,漏掉了传父类参数这一步.看上面给的例子感觉也是这个问题

最后结果,感觉还是不错的

<!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>
    <script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
</head>
<body>
    <h3>基本图形和属性</h3>
    <div id="container">

    </div>
    <script>
        const graph=new X6.Graph({
            container:document.getElementById('container'),
            width:800,
            height:600,
            grid:true,  
        })
        
        //创建带有方法的结构,就不能用register方法了
        class Group extends X6.Node {
            collapsed = false
            expandSize= { width: 100, height:100 }

            postprocess() {
              this.toggleCollapse(false)
            }
          
            isCollapsed() {
              return this.collapsed
            }
          
            toggleCollapse(collapsed) {
              const target = collapsed == null ? !this.collapsed : collapsed
              if (target) {
                this.attr('buttonSign', { d: 'M 1 5 9 5 M 5 1 5 9' })
                this.expandSize = this.getSize()
                this.resize(100, 32)
              } else {
                this.attr('buttonSign', { d: 'M 2 5 8 5' })
                if (this.expandSize) {
                  this.resize(this.expandSize.width, this.expandSize.height)
                  //缩起来的大小
                }
              }
              this.collapsed = target
            }
          }

        //自定义节点的表现
        Group.config({
            markup:[
                {
                    tagName:'rect',
                    selector:'body'
                },
                {
                    tagName:'text',
                    selector:'label'
                },
                {
                    tagName:'g',
                    selector:'buttonGroup',
                    children:[
                        {
                            tagName:'rect',
                            selector:'button',
                            attrs:{
                                'pointer-events':'visiblePainted',
                            }
                        },
                        {
                            tagName:'path',
                            selector:'buttonSign',
                            attrs:{
                                fill:"none",
                                'pointer-events':'none'
                            }
                        }
                    ]
                },
            ],
            attrs:{
                body:{
                    refWidth:"100%",
                    refHeight:'100%',
                    strokeWidth:1,
                    fill:"#fff",
                    stroke:'none'
                },
                buttonGroup:{
                    refX:8,
                    refY:8
                }       ,
                button:{
                    height:14,
                    width:16,
                    rx:2,
                    ry:2,
                    fill:'#f5f5f5',
                    stroke:'#ccc',
                    cursor:'pointer',
                    event:'node:collapse'
                    //节点自定义的事件,点击这个按钮会触发的,理论上这可以是click
                },
                buttonSign:{
                    refX:3,
                    refY:3,
                    stroke:"#808080"
                },
                label:{
                    fontSize:12,
                    fill:"#fff",
                    refX:32,
                    refY:10,
                }
            }
        })

        function createGroup(id,x,y,width,height,fill){
            console.log('body',fill)
            const group=new Group({
                x,
                y,
                width,
                height,
                attrs:{
                    body:{fill},
                    label:{text:id}
                }
            })
            graph.addNode(group)
            return group
        }

        //感觉是继承关系导致了不能用这种操作么,直接全写试试,而且也真的有写法上的错误,还是不要这样简写了
        function createNode(id,x,y,width,height,fill){
            return graph.addNode({
                x,
                y,
                width,
                height,
                attrs:{
                    body:{
                        fill:fill,
                    },
                    label:{
                        text:id,
                    }
                }
            })
        }
        //创建节点



        function createEdge(id,source,target,vertices){
            return graph.addEdge({
                id,
                source,
                target,
                vertices,
                label:id,
                attrs:{
                    label:{
                        fontSize:12,
                    }
                }
            })
        }
        //创建边


        const a = createGroup('a', 100, 40, 420, 240, '#fffbe6', '#ffe7ba')
        const aa = createGroup('aa', 150, 100, 160, 120, '#47C769', 'none')
        const aaa = createGroup('aaa', 180, 150, 100, 50, '#3199FF', 'none')
        const c = createNode('c节点', 400, 180, 60, 40, 'orange')
        //创建4个组


        a.addChild(aa)
        aa.addChild(aaa)
        a.addChild(c)
        

        graph.on('node:collapse',({node})=>{
            node.toggleCollapse()
            //做表现上的改变,按钮收缩,并且body大小变为定义的大小

            //隐藏所有子节点
            const collapsed=node.isCollapsed()
            //定义收起函数
            const collapse=(parent)=>{
                const cells=parent.getChildren()

                if(cells){
                    cells.forEach((cell)=>{
                        if(collapsed){
                            cell.hide()
                        }else{
                            cell.show()
                        }

                        if(cell instanceof Group){
                            //如果子节点还是一个组的话,也执行这个逻辑
                            if(!cell.isCollapsed()){
                                collapse(cell)
                            }
                        }
                    })

                   
                }
            }
            collapse(node)
        })

    </script>
</body>
</html>

群组连线

1 .群组里面的节点和外面连线,收起群组的时候,默认是线会消失的,但是为了好看,要临时加一条收起的rect出来的连线


image.png
image.png
上一篇下一篇

猜你喜欢

热点阅读