Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
vue-flow-editor
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2023-12-01 17:13:01 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
5e8e98d2bbb09d6683cfbd6838b31bee0426af76
5e8e98d2
1 parent
365b468a
优化:根据节点不同类型,连接线颜色调整
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
350 additions
and
2 deletions
doc/data.js
src/behavior/drag-edge.ts
src/shape/edge.ts
src/shape/edge1.ts
src/shape/index.ts
src/utils/styles.ts
doc/data.js
View file @
5e8e98d
/*
* @Date: 2023-10-27 09:29:48
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-1
1-23 17:55:22
* @LastEditTime: 2023-1
2-01 16:47:11
* @FilePath: /vue-flow-editor/doc/data.js
* @Description: 初始化结构,数据都是固定的
*/
...
...
src/behavior/drag-edge.ts
View file @
5e8e98d
...
...
@@ -131,11 +131,16 @@ export function dragEdge(G6, option: OptionType) {
if
(
this
.
origin
.
targetNode
)
{
const
addModel
=
{
class
:
'flow'
,
shape
:
"flow-polyline-round1"
,
source
:
this
.
origin
.
sourceNode
.
get
(
'id'
),
target
:
this
.
origin
.
targetNode
.
get
(
'id'
),
sourceAnchor
:
this
.
origin
.
sourceAnchor
,
targetAnchor
:
this
.
origin
.
targetAnchor
,
}
// TAG: 修改连接线颜色 开始出去的线和连接到抄送节点的颜色是灰色
if
(
this
.
origin
.
sourceNode
.
get
(
'id'
)
===
'start-node'
||
this
.
origin
.
targetNode
.
get
(
'model'
).
control
===
'cc'
)
{
addModel
.
shape
=
'flow-polyline-round'
}
if
(
this
.
graph
.
executeCommand
)
{
this
.
graph
.
executeCommand
(
'add'
,
{
type
:
'edge'
,
...
...
src/shape/edge.ts
View file @
5e8e98d
src/shape/edge1.ts
0 → 100644
View file @
5e8e98d
import
{
GraphStyle
}
from
"@/utils/styles"
;
import
editorStyle
from
"../util/defaultStyle"
;
import
{
G6
}
from
"@/g6/g6"
;
const
deepMix
=
G6
.
Util
.
deepMix
const
uniqBy
=
(
arr
,
key
)
=>
{
const
result
=
[];
arr
.
forEach
(
i
=>
{
if
(
!
result
.
find
(
r
=>
r
[
key
]
===
i
[
key
]))
result
.
push
(
i
)
});
return
result
;
};
export
function
registerEdge1
(
G6
)
{
G6
.
registerEdge
(
'flow-polyline-round1'
,
{
options
:
{
style
:
{
...
GraphStyle
.
default
.
defaultEdge1
.
style
,
},
stateStyles
:
{
...
GraphStyle
.
default
.
edgeStateStyles
,
}
},
setState
(
name
,
value
,
item
)
{
const
shape
=
item
.
get
(
'keyShape'
);
if
(
!
shape
)
{
return
;
}
const
itemStateStyle
=
item
.
getStateStyle
(
name
);
const
stateStyle
=
this
.
getStateStyle
(
name
,
value
,
item
);
const
styles
=
deepMix
({},
stateStyle
,
itemStateStyle
);
if
(
value
)
{
// 如果设置状态,在原本状态上叠加绘图属性
console
.
warn
(
styles
);
shape
.
attr
(
styles
);
}
else
{
// 取消状态时重置所有状态,依次叠加仍有的状态
const
style
=
item
.
getCurrentStatesStyle
();
// 如果默认状态下没有设置attr,在某状态下设置了,需要重置到没有设置的状态
G6
.
Util
.
each
(
styles
,
(
val
,
attr
)
=>
{
if
(
!
style
[
attr
])
{
style
[
attr
]
=
null
;
}
});
shape
.
attr
(
style
);
}
},
drawShape
(
cfg
,
group
)
{
this
.
group
=
group
;
const
shapeStyle
=
this
.
getShapeStyle
(
cfg
);
const
shape
=
group
.
addShape
(
'path'
,
{
className
:
'edge-shape'
,
attrs
:
shapeStyle
});
return
shape
;
},
drawLabel
(
cfg
,
group
)
{
const
labelCfg
=
cfg
.
labelCfg
||
{};
const
labelStyle
=
this
.
getLabelStyle
(
cfg
,
labelCfg
,
group
);
const
label
=
group
.
addShape
(
'text'
,
{
attrs
:
labelStyle
});
const
labelBBox
=
label
.
getBBox
();
group
.
addShape
(
'rect'
,
{
className
:
'edge-labelRect'
,
attrs
:
{
x
:
labelBBox
.
x
-
editorStyle
.
edgeLabelRectPadding
/
2
,
y
:
labelBBox
.
y
-
editorStyle
.
edgeLabelRectPadding
/
2
,
width
:
labelBBox
.
width
+
editorStyle
.
edgeLabelRectPadding
,
height
:
labelBBox
.
height
+
editorStyle
.
edgeLabelRectPadding
,
fill
:
'#fff'
,
stroke
:
'#fff'
,
}
});
group
.
toBack
();
label
.
toFront
();
return
label
;
},
afterUpdate
(
cfg
,
item
)
{
const
label
=
item
.
getContainer
().
findByClassName
(
'edge-label'
);
const
labelRect
=
item
.
getContainer
().
findByClassName
(
'edge-labelRect'
);
if
(
label
)
{
const
labelBBox
=
label
.
getBBox
();
labelRect
.
attr
({
x
:
labelBBox
.
x
-
editorStyle
.
edgeLabelRectPadding
/
2
,
y
:
labelBBox
.
y
-
editorStyle
.
edgeLabelRectPadding
/
2
,
width
:
labelBBox
.
width
+
editorStyle
.
edgeLabelRectPadding
,
height
:
labelBBox
.
height
+
editorStyle
.
edgeLabelRectPadding
,
});
}
},
getShapeStyle
(
cfg
)
{
cfg
=
this
.
getPathPoints
(
cfg
);
const
startPoint
=
cfg
.
startPoint
;
const
endPoint
=
cfg
.
endPoint
;
const
controlPoints
=
this
.
getControlPoints
(
cfg
);
let
points
=
[
startPoint
];
if
(
controlPoints
)
{
points
=
points
.
concat
(
controlPoints
);
}
points
.
push
(
endPoint
);
const
path
=
this
.
getPath
(
points
);
let
style
=
this
.
options
.
style
;
if
(
cfg
.
reverse
)
style
=
{...
style
,
lineDash
:
[
1
,
3
]};
else
style
=
{...
style
,
lineDash
:
null
};
return
{
path
,
...
style
,
endArrow
:
{
path
:
'M 0,0 L -10,-4 S -8 0,-10 4 Z'
,
}
}
},
getPath
(
points
)
{
const
path
=
[];
for
(
let
i
=
0
;
i
<
points
.
length
;
i
++
)
{
const
point
=
points
[
i
];
if
(
i
===
0
)
{
path
.
push
([
'M'
,
point
.
x
,
point
.
y
]);
}
else
if
(
i
===
points
.
length
-
1
)
{
path
.
push
([
'L'
,
point
.
x
,
point
.
y
]);
}
else
{
const
prevPoint
=
points
[
i
-
1
];
let
nextPoint
=
points
[
i
+
1
];
let
cornerLen
=
5
;
if
(
Math
.
abs
(
point
.
y
-
prevPoint
.
y
)
>
cornerLen
||
Math
.
abs
(
point
.
x
-
prevPoint
.
x
)
>
cornerLen
)
{
if
(
prevPoint
.
x
===
point
.
x
)
{
path
.
push
([
'L'
,
point
.
x
,
point
.
y
>
prevPoint
.
y
?
point
.
y
-
cornerLen
:
point
.
y
+
cornerLen
]);
}
else
if
(
prevPoint
.
y
===
point
.
y
)
{
path
.
push
([
'L'
,
point
.
x
>
prevPoint
.
x
?
point
.
x
-
cornerLen
:
point
.
x
+
cornerLen
,
point
.
y
]);
}
}
const
yLen
=
Math
.
abs
(
point
.
y
-
nextPoint
.
y
);
const
xLen
=
Math
.
abs
(
point
.
x
-
nextPoint
.
x
);
if
(
yLen
>
0
&&
yLen
<
cornerLen
)
{
cornerLen
=
yLen
;
}
else
if
(
xLen
>
0
&&
xLen
<
cornerLen
)
{
cornerLen
=
xLen
;
}
if
(
prevPoint
.
x
!==
nextPoint
.
x
&&
nextPoint
.
x
===
point
.
x
)
{
path
.
push
([
'Q'
,
point
.
x
,
point
.
y
,
point
.
x
,
point
.
y
>
nextPoint
.
y
?
point
.
y
-
cornerLen
:
point
.
y
+
cornerLen
]);
}
else
if
(
prevPoint
.
y
!==
nextPoint
.
y
&&
nextPoint
.
y
===
point
.
y
)
{
path
.
push
([
'Q'
,
point
.
x
,
point
.
y
,
point
.
x
>
nextPoint
.
x
?
point
.
x
-
cornerLen
:
point
.
x
+
cornerLen
,
point
.
y
]);
}
}
}
return
path
;
},
getControlPoints
(
cfg
)
{
if
(
!
cfg
.
sourceNode
)
{
return
cfg
.
controlPoints
;
}
return
this
.
polylineFinding
(
cfg
.
sourceNode
,
cfg
.
targetNode
,
cfg
.
startPoint
,
cfg
.
endPoint
,
15
);
},
getExpandedBBox
(
bbox
,
offset
)
{
return
0
===
bbox
.
width
&&
0
===
bbox
.
height
?
bbox
:
{
centerX
:
bbox
.
centerX
,
centerY
:
bbox
.
centerY
,
minX
:
bbox
.
minX
-
offset
,
minY
:
bbox
.
minY
-
offset
,
maxX
:
bbox
.
maxX
+
offset
,
maxY
:
bbox
.
maxY
+
offset
,
height
:
bbox
.
height
+
2
*
offset
,
width
:
bbox
.
width
+
2
*
offset
,
};
},
getExpandedPort
(
bbox
,
point
)
{
return
Math
.
abs
(
point
.
x
-
bbox
.
centerX
)
/
bbox
.
width
>
Math
.
abs
(
point
.
y
-
bbox
.
centerY
)
/
bbox
.
height
?
{
x
:
point
.
x
>
bbox
.
centerX
?
bbox
.
maxX
:
bbox
.
minX
,
y
:
point
.
y
}
:
{
x
:
point
.
x
,
y
:
point
.
y
>
bbox
.
centerY
?
bbox
.
maxY
:
bbox
.
minY
};
},
combineBBoxes
(
sBBox
,
tBBox
)
{
const
minX
=
Math
.
min
(
sBBox
.
minX
,
tBBox
.
minX
),
minY
=
Math
.
min
(
sBBox
.
minY
,
tBBox
.
minY
),
maxX
=
Math
.
max
(
sBBox
.
maxX
,
tBBox
.
maxX
),
maxY
=
Math
.
max
(
sBBox
.
maxY
,
tBBox
.
maxY
);
return
{
centerX
:
(
minX
+
maxX
)
/
2
,
centerY
:
(
minY
+
maxY
)
/
2
,
minX
:
minX
,
minY
:
minY
,
maxX
:
maxX
,
maxY
:
maxY
,
height
:
maxY
-
minY
,
width
:
maxX
-
minX
,
};
},
getBBoxFromVertexes
(
sPoint
,
tPoint
)
{
const
minX
=
Math
.
min
(
sPoint
.
x
,
tPoint
.
x
),
maxX
=
Math
.
max
(
sPoint
.
x
,
tPoint
.
x
),
minY
=
Math
.
min
(
sPoint
.
y
,
tPoint
.
y
),
maxY
=
Math
.
max
(
sPoint
.
y
,
tPoint
.
y
);
return
{
centerX
:
(
minX
+
maxX
)
/
2
,
centerY
:
(
minY
+
maxY
)
/
2
,
maxX
:
maxX
,
maxY
:
maxY
,
minX
:
minX
,
minY
:
minY
,
height
:
maxY
-
minY
,
width
:
maxX
-
minX
,
};
},
vertexOfBBox
(
bbox
)
{
return
[{
x
:
bbox
.
minX
,
y
:
bbox
.
minY
},
{
x
:
bbox
.
maxX
,
y
:
bbox
.
minY
},
{
x
:
bbox
.
maxX
,
y
:
bbox
.
maxY
},
{
x
:
bbox
.
minX
,
y
:
bbox
.
maxY
}];
},
crossPointsByLineAndBBox
(
bbox
,
centerPoint
)
{
let
crossPoints
=
[];
if
(
!
(
centerPoint
.
x
<
bbox
.
minX
||
centerPoint
.
x
>
bbox
.
maxX
))
crossPoints
=
crossPoints
.
concat
([{
x
:
centerPoint
.
x
,
y
:
bbox
.
minY
},
{
x
:
centerPoint
.
x
,
y
:
bbox
.
maxY
}]);
if
(
!
(
centerPoint
.
y
<
bbox
.
minY
||
centerPoint
.
y
>
bbox
.
maxY
))
crossPoints
=
crossPoints
.
concat
([{
x
:
bbox
.
minX
,
y
:
centerPoint
.
y
},
{
x
:
bbox
.
maxX
,
y
:
centerPoint
.
y
}]);
return
crossPoints
;
},
getConnectablePoints
(
sBBox
,
tBBox
,
sPoint
,
tPoint
)
{
const
lineBBox
=
this
.
getBBoxFromVertexes
(
sPoint
,
tPoint
);
const
outerBBox
=
this
.
combineBBoxes
(
sBBox
,
tBBox
);
const
sLineBBox
=
this
.
combineBBoxes
(
sBBox
,
lineBBox
);
const
tLineBBox
=
this
.
combineBBoxes
(
tBBox
,
lineBBox
);
let
points
=
[];
points
=
points
.
concat
(
this
.
vertexOfBBox
(
sLineBBox
),
this
.
vertexOfBBox
(
tLineBBox
),
this
.
vertexOfBBox
(
outerBBox
));
const
centerPoint
=
{
x
:
outerBBox
.
centerX
,
y
:
outerBBox
.
centerY
};
[
outerBBox
,
sLineBBox
,
tLineBBox
,
lineBBox
].
forEach
(
bbox
=>
{
points
=
points
.
concat
(
this
.
crossPointsByLineAndBBox
(
bbox
,
centerPoint
))
});
points
.
push
({
x
:
sPoint
.
x
,
y
:
tPoint
.
y
});
points
.
push
({
x
:
tPoint
.
x
,
y
:
sPoint
.
y
});
return
points
},
filterConnectablePoints
(
points
,
bbox
)
{
return
points
.
filter
(
point
=>
point
.
x
<=
bbox
.
minX
||
point
.
x
>=
bbox
.
maxX
||
point
.
y
<=
bbox
.
minY
||
point
.
y
>=
bbox
.
maxY
)
},
AStar
(
points
,
sPoint
,
tPoint
,
sBBox
,
tBBox
)
{
const
openList
=
[
sPoint
];
const
closeList
=
[];
points
=
uniqBy
(
this
.
fillId
(
points
),
'id'
);
points
.
push
(
tPoint
);
let
endPoint
;
while
(
openList
.
length
>
0
)
{
let
minCostPoint
;
openList
.
forEach
((
p
,
i
)
=>
{
if
(
!
p
.
parent
)
p
.
f
=
0
;
if
(
!
minCostPoint
)
minCostPoint
=
p
;
if
(
p
.
f
<
minCostPoint
.
f
)
minCostPoint
=
p
;
});
if
(
minCostPoint
.
x
===
tPoint
.
x
&&
minCostPoint
.
y
===
tPoint
.
y
)
{
endPoint
=
minCostPoint
;
break
;
}
openList
.
splice
(
openList
.
findIndex
(
o
=>
o
.
x
===
minCostPoint
.
x
&&
o
.
y
===
minCostPoint
.
y
),
1
);
closeList
.
push
(
minCostPoint
);
const
neighbor
=
points
.
filter
(
p
=>
(
p
.
x
===
minCostPoint
.
x
||
p
.
y
===
minCostPoint
.
y
)
&&
!
(
p
.
x
===
minCostPoint
.
x
&&
p
.
y
===
minCostPoint
.
y
)
&&
!
this
.
crossBBox
([
sBBox
,
tBBox
],
minCostPoint
,
p
));
neighbor
.
forEach
(
p
=>
{
const
inOpen
=
openList
.
find
(
o
=>
o
.
x
===
p
.
x
&&
o
.
y
===
p
.
y
);
const
currentG
=
this
.
getCost
(
p
,
minCostPoint
);
if
(
closeList
.
find
(
o
=>
o
.
x
===
p
.
x
&&
o
.
y
===
p
.
y
))
{
}
else
if
(
inOpen
)
{
if
(
p
.
g
>
currentG
)
{
p
.
parent
=
minCostPoint
;
p
.
g
=
currentG
;
p
.
f
=
p
.
g
+
p
.
h
;
}
}
else
{
p
.
parent
=
minCostPoint
;
p
.
g
=
currentG
;
let
h
=
this
.
getCost
(
p
,
tPoint
);
if
(
this
.
crossBBox
([
tBBox
],
p
,
tPoint
))
{
h
+=
(
tBBox
.
width
/
2
+
tBBox
.
height
/
2
);
//如果穿过bbox则增加该点的预估代价为bbox周长的一半
}
p
.
h
=
h
;
p
.
f
=
p
.
g
+
p
.
h
;
openList
.
push
(
p
)
}
});
}
if
(
endPoint
)
{
const
result
=
[];
result
.
push
({
x
:
endPoint
.
x
,
y
:
endPoint
.
y
});
while
(
endPoint
.
parent
)
{
endPoint
=
endPoint
.
parent
;
result
.
push
({
x
:
endPoint
.
x
,
y
:
endPoint
.
y
});
}
return
result
.
reverse
();
}
return
[];
},
crossBBox
(
bboxes
,
p1
,
p2
)
{
for
(
let
i
=
0
;
i
<
bboxes
.
length
;
i
++
)
{
const
bbox
=
bboxes
[
i
];
if
(
p1
.
x
===
p2
.
x
&&
bbox
.
minX
<
p1
.
x
&&
bbox
.
maxX
>
p1
.
x
)
{
if
(
p1
.
y
<
bbox
.
maxY
&&
p2
.
y
>=
bbox
.
maxY
||
p2
.
y
<
bbox
.
maxY
&&
p1
.
y
>=
bbox
.
maxY
)
return
true
}
else
if
(
p1
.
y
===
p2
.
y
&&
bbox
.
minY
<
p1
.
y
&&
bbox
.
maxY
>
p1
.
y
)
{
if
(
p1
.
x
<
bbox
.
maxX
&&
p2
.
x
>=
bbox
.
maxX
||
p2
.
x
<
bbox
.
maxX
&&
p1
.
x
>=
bbox
.
maxX
)
return
true
}
}
return
false
;
},
getCost
(
p1
,
p2
)
{
return
Math
.
abs
(
p1
.
x
-
p2
.
x
)
+
Math
.
abs
(
p1
.
y
-
p2
.
y
);
},
getPointBBox
(
t
)
{
return
{
centerX
:
t
.
x
,
centerY
:
t
.
y
,
minX
:
t
.
x
,
minY
:
t
.
y
,
maxX
:
t
.
x
,
maxY
:
t
.
y
,
height
:
0
,
width
:
0
};
},
fillId
(
points
)
{
points
.
forEach
(
p
=>
{
p
.
id
=
p
.
x
+
'-'
+
p
.
y
;
});
return
points
;
},
polylineFinding
(
sNode
,
tNode
,
sPort
,
tPort
,
offset
)
{
const
sourceBBox
=
sNode
&&
sNode
.
getBBox
()
?
sNode
.
getBBox
()
:
this
.
getPointBBox
(
sPort
);
const
targetBBox
=
tNode
&&
tNode
.
getBBox
()
?
tNode
.
getBBox
()
:
this
.
getPointBBox
(
tPort
);
const
sBBox
=
this
.
getExpandedBBox
(
sourceBBox
,
offset
);
const
tBBox
=
this
.
getExpandedBBox
(
targetBBox
,
offset
);
const
sPoint
=
this
.
getExpandedPort
(
sBBox
,
sPort
);
const
tPoint
=
this
.
getExpandedPort
(
tBBox
,
tPort
);
let
points
=
this
.
getConnectablePoints
(
sBBox
,
tBBox
,
sPoint
,
tPoint
);
points
=
this
.
filterConnectablePoints
(
points
,
sBBox
);
points
=
this
.
filterConnectablePoints
(
points
,
tBBox
);
const
polylinePoints
=
this
.
AStar
(
points
,
sPoint
,
tPoint
,
sBBox
,
tBBox
);
return
polylinePoints
;
},
},
'polyline'
);
}
src/shape/index.ts
View file @
5e8e98d
/*
* @Date: 2023-10-27 09:29:59
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-1
1-14 11:17:2
0
* @LastEditTime: 2023-1
2-01 17:11:3
0
* @FilePath: /vue-flow-editor/src/shape/index.ts
* @Description: 文件描述
*/
import
{
registerAnchor
}
from
"@/shape/anchor"
;
import
{
registerEdge
}
from
"@/shape/edge"
;
import
{
registerEdge1
}
from
"@/shape/edge1"
;
// TAG:新增一条彩色的连接线
// TAG: 自定义节点 - 引入节点
import
{
registerActivity
}
from
"@/shape/activity"
;
import
{
registerControl
}
from
"@/shape/control"
;
...
...
@@ -14,6 +15,7 @@ import {registerControl} from "@/shape/control";
export
function
registerShape
(
G6
)
{
registerAnchor
(
G6
)
registerEdge
(
G6
)
registerEdge1
(
G6
)
registerActivity
(
G6
)
registerControl
(
G6
)
}
...
...
src/utils/styles.ts
View file @
5e8e98d
...
...
@@ -83,6 +83,15 @@ export const GraphStyle = {
cursor
:
'pointer'
,
},
},
defaultEdge1
:
{
// TAG:新增彩色连接线
shape
:
'flow-polyline-round1'
,
style
:
{
stroke
:
'#CB7FE3'
,
lineWidth
:
1
,
lineAppendWidth
:
10
,
cursor
:
'pointer'
,
},
},
defaultNode
:
{
shape
:
'rect'
,
size
:
[
120
,
40
],
...
...
Please
register
or
login
to post a comment