美文网首页
4.8 群组

4.8 群组

作者: skoll | 来源:发表于2021-12-28 09:56 被阅读0次

    简介

    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

    相关文章

      网友评论

          本文标题:4.8 群组

          本文链接:https://www.haomeiwen.com/subject/nijyqrtx.html