Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
R
relation-graph
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
郭铭瑶
relation-graph
Commits
c4768c68
Commit
c4768c68
authored
Aug 16, 2021
by
郭铭瑶
🤘
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
连接subject功能&去除拖拽物理作用力
parent
cee5ea2c
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
172 additions
and
57 deletions
+172
-57
api.js
src/ajax/api.js
+1
-0
link.svg
src/assets/images/link.svg
+1
-0
d3.vue
src/components/d3.vue
+8
-8
main.vue
src/components/main.vue
+132
-37
useD3.js
src/util/useD3.js
+30
-12
No files found.
src/ajax/api.js
View file @
c4768c68
...
...
@@ -15,4 +15,5 @@ export default {
GET_NODES
:
'/node/relations'
,
DELETE_NODE
:
'/node/{id}'
,
GET_SYSTEMS
:
'/systems'
,
POST_LINK_SUBJECTS
:
'/node/relations'
,
}
src/assets/images/link.svg
0 → 100644
View file @
c4768c68
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1629110949117"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"2116"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"128"
height=
"128"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M529.322667 635.946667a42.666667 42.666667 0 0 0-23.168 55.765333 42.666667 42.666667 0 0 1-9.258667 46.506667l-120.661333 120.704a85.333333 85.333333 0 0 1-120.661334 0L165.034667 768.426667a85.333333 85.333333 0 0 1 0-120.704L285.866667 527.061333a43.221333 43.221333 0 0 1 46.549333-9.258666 42.666667 42.666667 0 0 0 32.554667-78.890667 129.450667 129.450667 0 0 0-139.434667 27.818667l-120.832 120.661333a170.922667 170.922667 0 0 0 0 241.365333l90.538667 90.496a170.666667 170.666667 0 0 0 241.322666 0l120.704-120.661333a128.341333 128.341333 0 0 0 27.776-139.52 42.666667 42.666667 0 0 0-55.722666-23.125333z"
p-id=
"2117"
fill=
"#ffffff"
></path><path
d=
"M330.965333 692.949333a43.136 43.136 0 0 0 60.330667 0l331.904-331.861333a42.666667 42.666667 0 0 0-60.330667-60.330667l-331.904 331.861334a42.666667 42.666667 0 0 0 0 60.330666z"
p-id=
"2118"
fill=
"#ffffff"
></path><path
d=
"M919.296 195.157333l-90.496-90.496a170.922667 170.922667 0 0 0-241.365333 0l-120.704 120.661334a128.256 128.256 0 0 0-27.776 139.477333 42.666667 42.666667 0 1 0 78.890666-32.597333 42.666667 42.666667 0 0 1 9.258667-46.336l120.661333-120.661334a85.333333 85.333333 0 0 1 120.704 0l90.496 90.496a85.333333 85.333333 0 0 1 0 120.704L738.133333 496.853333a43.306667 43.306667 0 0 1-46.549333 9.258667 42.666667 42.666667 0 0 0-32.64 78.890667 129.109333 129.109333 0 0 0 139.52-27.776l120.661333-120.661334a170.965333 170.965333 0 0 0 0.170667-241.408z"
p-id=
"2119"
fill=
"#ffffff"
></path></svg>
\ No newline at end of file
src/components/d3.vue
View file @
c4768c68
...
...
@@ -31,7 +31,7 @@
import
RelationGraph
from
'@/util/useD3.js'
import
{
watch
,
ref
}
from
'vue'
import
branch
from
'@/assets/images/branch.svg'
import
more
from
'@/assets/images/more
.svg'
import
link
from
'@/assets/images/link
.svg'
import
add
from
'@/assets/images/add.svg'
import
del
from
'@/assets/images/delete.svg'
export
default
{
...
...
@@ -48,7 +48,7 @@ export default {
}
,
}
,
}
,
emits
:
[
'
more
'
,
'add'
,
'del'
,
'branch'
,
'curNode'
],
emits
:
[
'
link
'
,
'add'
,
'del'
,
'branch'
,
'curNode'
],
setup
(
props
,
ctx
)
{
const
colorList
=
{
default
:
'skyblue'
,
...
...
@@ -70,12 +70,12 @@ export default {
action
:
(
d
)
=>
ctx
.
emit
(
'branch'
,
d
),
title
:
'分支'
,
}
,
//
{
// key: 'more
',
// icon: more
,
// action: (d) => ctx.emit('more
', d),
// title: '更多
',
//
}
,
{
key
:
'link
'
,
icon
:
link
,
action
:
(
d
)
=>
ctx
.
emit
(
'link
'
,
d
),
title
:
'连接
'
,
}
,
{
key
:
'add'
,
icon
:
add
,
...
...
src/components/main.vue
View file @
c4768c68
...
...
@@ -10,6 +10,7 @@
@
add=
"openAddDrawer"
@
curNode=
"curNode = $event"
@
del=
"deleteNode"
@
link=
"showLinkDrawer = true"
/>
<Side
style=
"grid-area: side"
/>
<Footer
...
...
@@ -22,7 +23,7 @@
/>
</div>
<n-drawer
v-model:show=
"showDrawer"
:width=
"400"
placement=
"left"
>
<n-drawer-content
title=
"新增节点"
>
<n-drawer-content
title=
"新增
附属
节点"
>
<n-form
ref=
"formRef"
:model=
"formData"
:rules=
"rules"
>
<n-form-item
path=
"propertyName"
label=
"节点名称"
>
<n-input
...
...
@@ -54,7 +55,7 @@
</n-drawer-content>
</n-drawer>
<n-drawer
v-model:show=
"showSubjectDrawer"
:width=
"400"
placement=
"left"
>
<n-drawer-content
title=
"新增
Suject
"
>
<n-drawer-content
title=
"新增
主体
"
>
<n-form
ref=
"subjectFormRef"
:model=
"subjectData"
:rules=
"rules"
>
<n-form-item
path=
"subjectName"
label=
"名称"
>
<n-input
...
...
@@ -71,6 +72,32 @@
</n-form>
</n-drawer-content>
</n-drawer>
<n-drawer
v-model:show=
"showLinkDrawer"
:width=
"400"
placement=
"left"
>
<n-drawer-content
title=
"连接主体"
>
<n-form
ref=
"linkFormRef"
:model=
"linkData"
:rules=
"rules"
>
<n-form-item
path=
"sourceNodeId"
label=
"源主体"
>
<n-select
v-model:value=
"linkData.sourceNodeId"
placeholder=
"请选择"
:options=
"subjectOptions"
disabled
/>
</n-form-item>
<n-form-item
path=
"targetNodeId"
label=
"目标主体"
>
<n-select
v-model:value=
"linkData.targetNodeId"
placeholder=
"请选择"
:options=
"subjectOptions"
/>
</n-form-item>
<n-space
justify=
"end"
>
<n-button
:loading=
"isLoading"
type=
"primary"
@
click=
"linkSubject"
>
提交
</n-button>
</n-space>
</n-form>
</n-drawer-content>
</n-drawer>
</
template
>
<
script
>
...
...
@@ -79,10 +106,9 @@ import Nav from './nav.vue'
import
Side
from
'./side.vue'
import
Footer
from
'./footer.vue'
import
mockData
from
'@/util/mock.js'
import
{
ref
}
from
'vue'
import
{
ref
,
watch
}
from
'vue'
import
{
ajax
,
api
}
from
'@/ajax'
import
{
useMessage
,
useDialog
}
from
'naive-ui'
export
default
{
name
:
'Main'
,
components
:
{
D3
,
Nav
,
Side
,
Footer
},
...
...
@@ -102,7 +128,7 @@ export default {
const
relationOptions
=
ref
([])
const
systemOptions
=
ref
([])
const
graphData
=
ref
({
nodes
:
[],
links
:
[]
})
const
subject
Node
s
=
ref
([])
const
subject
Option
s
=
ref
([])
function
fetchSubjects
()
{
ajax
...
...
@@ -111,9 +137,13 @@ export default {
})
.
then
((
res
)
=>
{
console
.
log
(
'subject'
,
res
.
data
.
content
)
subjectNodes
.
value
=
res
.
data
.
content
const
data
=
res
.
data
.
content
subjectOptions
.
value
=
data
.
map
((
item
)
=>
({
label
:
item
.
subjectName
,
value
:
item
.
nodeId
,
}))
graphData
.
value
=
{
nodes
:
[...
subjectNodes
.
value
],
nodes
:
[...
data
],
links
:
[],
}
})
...
...
@@ -289,6 +319,95 @@ export default {
graphData
.
value
=
res
.
data
.
content
})
}
const
showLinkDrawer
=
ref
(
false
)
const
linkData
=
ref
({
sourceNodeId
:
null
,
targetNodeId
:
null
,
})
watch
(
()
=>
curNode
.
value
,
(
cur
)
=>
{
linkData
.
value
=
{
sourceNodeId
:
cur
&&
cur
.
nodeId
,
targetNodeId
:
null
,
}
}
)
const
linkFormRef
=
ref
(
null
)
const
linkSubject
=
(
e
)
=>
{
e
.
preventDefault
()
linkFormRef
.
value
.
validate
((
errors
)
=>
{
if
(
!
errors
)
{
isLoading
.
value
=
true
ajax
.
post
({
url
:
api
.
POST_LINK_SUBJECTS
,
params
:
linkData
.
value
,
})
.
then
(()
=>
{
fetchSubordinates
({
nodeId
:
linkData
.
value
.
sourceNodeId
,
nodeLabel
:
'Subject'
,
})
isLoading
.
value
=
false
showLinkDrawer
.
value
=
false
message
.
success
(
'提交成功'
)
})
}
})
}
const
rules
=
{
subjectName
:
[
{
required
:
true
,
message
:
'请输入名称'
,
trigger
:
[
'input'
,
'blur'
],
},
],
propertyName
:
[
{
required
:
true
,
message
:
'请输入节点名称'
,
trigger
:
[
'input'
,
'blur'
],
},
],
relationId
:
[
{
required
:
true
,
message
:
'请选择从属类型'
,
trigger
:
[
'change'
,
'blur'
],
},
],
systemId
:
[
{
required
:
true
,
message
:
'请选择所属系统'
,
trigger
:
[
'change'
,
'blur'
],
},
],
sourceNodeId
:
[
{
required
:
true
,
message
:
'请选择源主体'
,
trigger
:
[
'change'
,
'blur'
],
},
],
targetNodeId
:
[
{
required
:
true
,
message
:
'请选择目标主体'
,
trigger
:
[
'change'
,
'blur'
],
},
{
validator
(
_
,
value
)
{
return
value
!==
linkData
.
value
.
sourceNodeId
},
trigger
:
[
'blur'
,
'change'
],
message
:
'目标主体不能与源主体相同'
,
},
],
}
return
{
formRef
,
formData
,
...
...
@@ -303,36 +422,7 @@ export default {
openAddDrawer
,
d3Ref
,
setLabelKey
,
rules
:
{
subjectName
:
[
{
required
:
true
,
message
:
'请输入名称'
,
trigger
:
[
'input'
,
'blur'
],
},
],
propertyName
:
[
{
required
:
true
,
message
:
'请输入节点名称'
,
trigger
:
[
'input'
,
'blur'
],
},
],
relationId
:
[
{
required
:
true
,
message
:
'请选择从属类型'
,
trigger
:
[
'input'
,
'blur'
],
},
],
systemId
:
[
{
required
:
true
,
message
:
'请选择所属系统'
,
trigger
:
[
'input'
,
'blur'
],
},
],
},
rules
,
curNode
,
deleteNode
,
showSubjectDrawer
,
...
...
@@ -340,6 +430,11 @@ export default {
subjectData
,
addSubject
,
searchNodes
,
showLinkDrawer
,
linkFormRef
,
linkData
,
linkSubject
,
subjectOptions
,
}
},
}
...
...
src/util/useD3.js
View file @
c4768c68
...
...
@@ -34,10 +34,19 @@ function textWrap(text, width) {
text
.
each
(
function
()
{
const
text
=
d3
.
select
(
this
),
words
=
text
.
text
().
split
(
''
).
reverse
(),
lineHeight
=
1
,
// ems
x
=
text
.
attr
(
'x'
),
y
=
text
.
attr
(
'y'
),
dy
=
0
lineHeight
=
1.2
,
// ems
dy
=
0
,
x
=
text
.
attr
(
'x'
)
let
y
=
text
.
attr
(
'y'
)
if
(
words
.
length
>
4
&&
words
.
length
<=
8
)
{
y
=
+
y
-
4
}
else
if
(
words
.
length
>
8
&&
words
.
length
<=
10
)
{
y
=
+
y
-
8
}
else
if
(
words
.
length
>
10
)
{
y
=
+
y
-
12
}
let
word
,
line
=
[],
...
...
@@ -73,11 +82,11 @@ const defaultConfig = {
links
:
[],
// 线数组
isHighLight
:
true
,
// 是否启动 鼠标 hover 到节点上高亮与节点有关的节点,其他无关节点透明的功能
isScale
:
true
,
// 是否启用缩放平移zoom功能
scaleExtent
:
[
0.
2
,
1.5
],
// 缩放的比例尺
scaleExtent
:
[
0.
6
,
1.5
],
// 缩放的比例尺
chargeStrength
:
-
100
,
// 万有引力
collide
:
80
,
// 碰撞力的大小 (节点之间的间距)
alphaDecay
:
0.4
,
// 控制力学模拟衰减率
r
:
3
4
,
// 圈圈的半径 [30 - 45]
r
:
3
6
,
// 圈圈的半径 [30 - 45]
nodeColor
:
'skyblue'
,
// 圈圈节点背景颜色
fontColor
:
'#2c3e50'
,
// 圈圈内文字的颜色
linkSrc
:
30
,
// 划线时候的弧度
...
...
@@ -191,8 +200,9 @@ export default class RelationGraph {
.
attr
(
'y'
,
this
.
config
.
r
)
// edit
.
attr
(
'text-anchor'
,
'middle'
)
.
attr
(
'dominant-baseline'
,
'middle'
)
.
attr
(
'fill'
,
this
.
config
.
fontColor
)
.
style
(
'font-size'
,
this
.
config
.
r
/
3.8
)
.
attr
(
'fill'
,
'#000'
)
.
style
(
'font-size'
,
12
)
.
style
(
'font-weight'
,
'normal'
)
.
text
((
d
)
=>
d
[
d
.
nodeLabel
.
toLowerCase
()
+
'Name'
])
}
...
...
@@ -271,8 +281,7 @@ export default class RelationGraph {
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'circle-wrapper'
)
// .merge(this.circlesWrapper)
this
.
circlesWrapper
.
exit
().
remove
()
// 6.关系图添加用于显示圈圈的节点
this
.
circles
=
this
.
circlesWrapper
.
append
(
'circle'
)
...
...
@@ -399,16 +408,25 @@ export default class RelationGraph {
this
.
initLinks
()
this
.
initCircles
()
const
{
x
=
this
.
config
.
width
/
2
,
y
=
this
.
config
.
height
/
2
}
=
this
.
curActiveNode
||
{}
this
.
simulation
.
force
(
'link'
,
d3
.
forceLink
(
this
.
config
.
links
))
.
nodes
(
this
.
config
.
nodes
)
.
force
(
'link'
,
d3
.
forceLink
(
this
.
config
.
links
))
.
force
(
'charge'
,
null
)
.
force
(
'center'
,
d3
.
forceCenter
(
x
,
y
))
.
alpha
(
1
)
.
restart
()
const
timer
=
setTimeout
(()
=>
{
this
.
simulation
.
force
(
'link'
,
null
)
clearTimeout
(
timer
)
},
200
)
}
openMenu
(
self
,
d
,
types
)
{
this
.
setCurNode
(
d
)
this
.
curActiveNode
=
d
menu
=
new
RadialMenu
().
radius
(
38
).
thickness
(
30
).
appendTo
(
self
.
parentNode
)
if
(
!
types
)
{
menu
.
show
(
this
.
menuData
,
d
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment