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