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
6ddd03b6
Commit
6ddd03b6
authored
Aug 25, 2021
by
郭铭瑶
🤘
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
主体客体区分形状&编辑节点&添加标签
parent
a5189eeb
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
409 additions
and
80 deletions
+409
-80
api.js
src/ajax/api.js
+4
-2
edit.svg
src/assets/images/edit.svg
+1
-0
d3.vue
src/components/d3.vue
+42
-23
main.vue
src/components/main.vue
+220
-20
main.js
src/main.js
+2
-0
useD3.js
src/util/useD3.js
+140
-35
No files found.
src/ajax/api.js
View file @
6ddd03b6
...
...
@@ -8,14 +8,16 @@ switch (process.env.NODE_ENV) {
export
default
{
BASE_URL
,
GET_SUBJECTS
:
'/subjects/v2'
,
PUT_SUBJECT
:
'/subject/{id}'
,
GET_RELATIONS
:
'/relations'
,
POST_SUBJECT
:
'/subject'
,
POST_NODE
:
'/node/relation/v2'
,
DELETE_RELATION
:
'/node/relation/{id}'
,
GET_NODES
:
'/node/relations'
,
DELETE_NODE
:
'/node/{id}'
,
PUT_NODE
:
'/node/{nodeType}/{id}'
,
GET_SYSTEMS
:
'/systems'
,
POST_LINK_SUBJECTS
:
'/node/relations'
,
GET_TAGS
:
'/label/classification'
,
GET_TAG_CLASS
:
'/label/classification'
,
GET_TAGS
:
'/labels'
,
POST_TAGS
:
'/node/labels'
,
}
src/assets/images/edit.svg
0 → 100644
View file @
6ddd03b6
<?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=
"1629870391503"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"2057"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"200"
height=
"200"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M729.483636 995.607273H218.996364A127.301818 127.301818 0 0 1 91.810909 868.421818V233.658182A127.301818 127.301818 0 0 1 218.996364 106.472727h382.952727a29.090909 29.090909 0 1 1 0 58.181818H218.996364a69.003636 69.003636 0 0 0-69.003637 69.003637v634.763636a69.003636 69.003636 0 0 0 69.003637 69.003637h510.487272a69.003636 69.003636 0 0 0 69.003637-69.003637v-400.290909a29.090909 29.090909 0 0 1 58.181818 0v400.290909a127.301818 127.301818 0 0 1-127.185455 127.185455z"
fill=
"#ffffff"
p-id=
"2058"
></path><path
d=
"M514.792727 569.250909a29.090909 29.090909 0 0 1-28.974545-31.883636C488.727273 506.298182 500.363636 402.269091 529.105455 368.290909l254.836363-303.709091a99.607273 99.607273 0 1 1 152.552727 128l-254.836363 303.709091c-28.509091 33.978182-129.047273 63.767273-159.185455 72.029091a28.974545 28.974545 0 0 1-7.68 0.930909zM860.16 87.156364a41.309091 41.309091 0 0 0-31.650909 14.778181l-254.836364 303.709091c-8.494545 10.123636-18.036364 50.734545-24.552727 93.090909 41.192727-13.847273 79.476364-30.254545 87.970909-40.378181l254.836364-303.709091a41.309091 41.309091 0 0 0-31.650909-67.956364z"
fill=
"#ffffff"
p-id=
"2059"
></path></svg>
\ No newline at end of file
src/components/d3.vue
View file @
6ddd03b6
...
...
@@ -40,6 +40,7 @@ import branch from '@/assets/images/branch.svg'
import
link
from
'@/assets/images/link.svg'
import
add
from
'@/assets/images/add.svg'
import
del
from
'@/assets/images/delete.svg'
import
edit
from
'@/assets/images/edit.svg'
export
default
{
name
:
'D3'
,
props
:
{
...
...
@@ -54,7 +55,7 @@ export default {
}
,
}
,
}
,
emits
:
[
'link'
,
'add'
,
'del'
,
'branch'
,
'curNode'
,
'del-link'
],
emits
:
[
'link'
,
'add'
,
'del'
,
'
edit'
,
'
branch'
,
'curNode'
,
'del-link'
],
setup
(
props
,
ctx
)
{
const
colorList
=
{
default
:
'skyblue'
,
...
...
@@ -76,6 +77,12 @@ export default {
// action: (d) => ctx.emit('branch', d),
// title: '分支',
//
}
,
{
key
:
'edit'
,
icon
:
edit
,
action
:
(
d
)
=>
ctx
.
emit
(
'edit'
,
d
),
title
:
'编辑'
,
}
,
{
key
:
'link'
,
icon
:
link
,
...
...
@@ -96,27 +103,49 @@ export default {
}
,
]
const
curTagKey
=
ref
(
null
)
const
setCurNode
=
(
typ
e
)
=>
{
if
(
typ
e
.
nodeLabel
!==
'Subject'
)
{
const
setCurNode
=
(
nod
e
)
=>
{
if
(
nod
e
.
nodeLabel
!==
'Subject'
)
{
curTagKey
.
value
=
null
}
ctx
.
emit
(
'curNode'
,
typ
e
)
ctx
.
emit
(
'curNode'
,
nod
e
)
}
const
handleLinkClick
=
(
d
)
=>
{
if
(
d
.
target
.
nodeLabel
===
'System'
)
{
const
{
nodeLabel
}
=
d
.
target
if
(
nodeLabel
===
'System'
||
nodeLabel
===
'Subject'
)
{
ctx
.
emit
(
'del-link'
,
d
)
}
}
const
showBranch
=
(
d
)
=>
{
ctx
.
emit
(
'branch'
,
d
)
}
function
init
()
{
if
(
!
container
.
value
)
return
const
data
=
{
links
:
props
.
data
.
links
,
nodes
:
props
.
data
.
nodes
.
map
((
node
)
=>
{
const
data
=
transData
(
props
.
data
)
if
(
instance
)
{
updateGraph
(
props
.
data
)
}
else
{
instance
=
new
RelationGraph
(
container
.
value
,
data
,
props
.
config
,
menuData
,
colorList
,
setCurNode
,
handleLinkClick
,
showBranch
)
}
setLegend
(
data
)
}
function
transData
(
data
)
{
return
{
links
:
data
.
links
,
nodes
:
data
.
nodes
.
map
((
node
)
=>
{
let
key
=
node
.
nodeLabel
if
(
key
===
'Property'
)
{
const
relation
=
props
.
data
.
links
.
find
((
link
)
=>
{
...
...
@@ -134,21 +163,10 @@ export default {
return
node
}
),
}
if
(
instance
)
{
instance
.
update
(
data
)
}
else
{
instance
=
new
RelationGraph
(
container
.
value
,
data
,
props
.
config
,
menuData
,
colorList
,
setCurNode
,
handleLinkClick
,
showBranch
)
}
setLegend
(
data
)
function
updateGraph
(
data
)
{
instance
.
update
(
transData
(
data
))
}
function
setKey
(
key
)
{
...
...
@@ -269,6 +287,7 @@ export default {
colorList
,
container
,
setKey
,
updateGraph
,
nodeList
,
linkList
,
defaultColor
:
{
...
...
src/components/main.vue
View file @
6ddd03b6
...
...
@@ -9,6 +9,7 @@
@
add=
"openAddDrawer"
@
curNode=
"curNode = $event"
@
del=
"deleteNode"
@
edit=
"openEditDrawer"
@
link=
"openLinkDrawer"
@
del-link=
"deleteLink"
/>
...
...
@@ -50,7 +51,30 @@
:options=
"relationOptions"
/>
</n-form-item>
<n-form-item
label=
"所属系统"
path=
"systemId"
>
<template
v-if=
"getTagName(data.relationId) === '标签'"
>
<n-form-item
label=
"标签分类"
path=
"classification"
>
<n-select
v-model:value=
"data.classification"
placeholder=
"请选择"
:options=
"tagClassOptions"
/>
</n-form-item>
<n-form-item
label=
"标签名称"
path=
"tag"
>
<n-select
v-model:value=
"data.tag"
placeholder=
"请选择"
filterable
tag
:options=
"tagOptions"
/>
</n-form-item>
<n-form-item
path=
"isPositive"
:show-label=
"false"
>
<n-checkbox
v-model:checked=
"data.isPositive"
>
是否为积极的标签
</n-checkbox
>
</n-form-item>
</
template
>
<n-form-item
v-else
label=
"所属系统"
path=
"systemId"
>
<n-select
v-model:value=
"data.systemIds"
placeholder=
"请选择"
...
...
@@ -141,7 +165,7 @@
</n-drawer-content>
</n-drawer>
<n-drawer
v-model:show=
"showLinkDrawer"
:width=
"340"
placement=
"left"
>
<n-drawer-content
title=
"
连接
要素"
closable
>
<n-drawer-content
title=
"
关联
要素"
closable
>
<n-form
ref=
"linkFormRef"
:model=
"linkData"
:rules=
"rules"
size=
"small"
>
<n-form-item
path=
"sourceNodeId"
label=
"源要素"
>
<n-select
...
...
@@ -171,6 +195,50 @@
</n-form>
</n-drawer-content>
</n-drawer>
<n-drawer
v-model:show=
"showEditDrawer"
:width=
"340"
placement=
"left"
>
<n-drawer-content
title=
"编辑节点"
closable
>
<n-form
ref=
"editFormRef"
:model=
"editData"
:rules=
"rules"
size=
"small"
>
<
template
v-if=
"curNode.nodeLabel === 'Subject'"
>
<n-form-item
path=
"subjectName"
label=
"名称"
>
<n-input
v-model:value=
"editData.subjectName"
placeholder=
"请输入"
@
keydown
.
enter
.
prevent
/>
</n-form-item>
<n-form-item
path=
"subjectType"
label=
"类型"
>
<n-select
v-model:value=
"editData.subjectType"
placeholder=
"请选择"
:options=
"[
{ label: '主体', value: '1' },
{ label: '客体', value: '2' },
]"
/>
</n-form-item>
</
template
>
<
template
v-else-if=
"curNode.nodeLabel === 'Property'"
>
<n-form-item
label=
"节点名称"
path=
"propertyName"
>
<n-input
v-model:value=
"editData.propertyName"
placeholder=
"请输入"
@
keydown
.
enter
.
prevent
/>
</n-form-item>
</
template
>
<n-space
justify=
"end"
>
<n-button
:loading=
"isLoading"
size=
"small"
type=
"primary"
@
click=
"editNode"
>
提交
</n-button>
</n-space>
</n-form>
</n-drawer-content>
</n-drawer>
</template>
<
script
setup
>
...
...
@@ -219,13 +287,30 @@ function fetchSubjects() {
}
fetchSubjects
()
const
tagClassOptions
=
ref
([])
const
tagOptions
=
ref
([])
function
fetchTags
()
{
ajax
.
get
({
url
:
api
.
GET_TAG_CLASS
,
})
.
then
((
res
)
=>
{
const
data
=
res
.
data
.
content
tagClassOptions
.
value
=
data
.
map
((
e
)
=>
({
label
:
e
.
classification
,
value
:
e
.
classification
,
}))
})
ajax
.
get
({
url
:
api
.
GET_TAGS
,
})
.
then
((
res
)
=>
{
console
.
log
(
'tags'
,
res
.
data
.
content
)
const
data
=
(
res
.
data
&&
res
.
data
.
content
)
||
[]
tagOptions
.
value
=
data
.
map
((
e
)
=>
({
label
:
e
.
labelName
,
value
:
e
.
id
,
}))
})
}
fetchTags
()
...
...
@@ -302,31 +387,80 @@ function setLabelKey(key) {
d3Ref
.
value
.
setKey
(
key
)
}
function
getTagName
(
relationId
)
{
if
(
!
relationId
)
return
null
const
tag
=
relationOptions
.
value
.
find
((
e
)
=>
e
.
value
===
relationId
)
return
tag
&&
tag
.
label
}
function
submitNewNode
(
e
)
{
e
.
preventDefault
()
formRef
.
value
.
validate
((
errors
)
=>
{
formRef
.
value
.
validate
(
async
(
errors
)
=>
{
if
(
!
errors
)
{
isLoading
.
value
=
true
const
{
nodeId
,
subjectName
,
subjectType
}
=
curSubject
.
value
ajax
.
post
({
const
tagData
=
[]
const
otherData
=
[]
formData
.
value
.
forEach
((
item
)
=>
{
if
(
getTagName
(
item
.
relationId
)
===
'标签'
)
{
tagData
.
push
(
item
)
}
else
{
otherData
.
push
(
item
)
}
})
if
(
otherData
.
length
>
0
)
{
await
ajax
.
post
({
url
:
api
.
POST_NODE
,
params
:
{
subjectId
:
nodeId
,
subjectName
,
subjectType
,
propertyList
:
formData
.
value
,
propertyList
:
otherData
.
map
((
item
)
=>
({
propertyName
:
item
.
propertyName
,
systemIds
:
item
.
systemIds
,
relationId
:
item
.
relationId
,
})),
},
})
.
then
(()
=>
{
}
if
(
tagData
.
length
>
0
)
{
await
ajax
.
post
({
url
:
api
.
POST_TAGS
,
params
:
{
subjectId
:
nodeId
,
subjectName
,
subjectType
,
relationId
:
tagData
[
0
].
relationId
,
labelList
:
tagData
.
map
((
item
)
=>
{
let
obj
=
{
id
:
null
,
labelName
:
item
.
tag
,
}
if
(
tagOptions
.
value
.
findIndex
((
e
)
=>
e
.
value
==
item
.
tag
)
>=
0
)
{
obj
=
{
id
:
item
.
tag
,
labelName
:
null
,
}
}
return
{
classification
:
item
.
classification
,
isPositive
:
item
.
isPositive
,
...
obj
,
}
}),
},
})
}
fetchSubordinates
({
nodeId
:
nodeId
,
nodeId
,
nodeLabel
:
'Subject'
,
})
isLoading
.
value
=
false
showDrawer
.
value
=
false
message
.
success
(
'提交成功'
)
})
message
.
success
(
'新增成功'
)
}
})
}
...
...
@@ -366,9 +500,12 @@ function deleteNode(data) {
function
deleteLink
(
data
)
{
const
{
source
,
target
}
=
data
const
name
=
`'
${
source
.
propertyName
||
target
.
subjectName
}
_
${
target
.
systemName
||
source
.
subjectName
}
'`
dialog
.
error
({
title
:
'删除关联'
,
content
:
`确定是否删除
'
${
source
.
propertyName
}
_
${
target
.
systemName
}
'
关联关系?`
,
content
:
`确定是否删除
${
name
}
关联关系?`
,
positiveText
:
'确定'
,
negativeText
:
'取消'
,
maskClosable
:
false
,
...
...
@@ -410,7 +547,7 @@ const addSubject = (e) => {
fetchSubjects
()
isLoading
.
value
=
false
showSubjectDrawer
.
value
=
false
message
.
success
(
'
提交
成功'
)
message
.
success
(
'
新增
成功'
)
})
}
})
...
...
@@ -467,7 +604,7 @@ const linkSubject = (e) => {
})
isLoading
.
value
=
false
showLinkDrawer
.
value
=
false
message
.
success
(
'
提交
成功'
)
message
.
success
(
'
关联
成功'
)
})
}
})
...
...
@@ -497,7 +634,21 @@ const rules = {
relationId
:
[
{
required
:
true
,
message
:
'请选择从属类型'
,
message
:
'请选择从属关系'
,
trigger
:
[
'change'
,
'blur'
],
},
],
classification
:
[
{
required
:
true
,
message
:
'请选择标签分类'
,
trigger
:
[
'change'
,
'blur'
],
},
],
tag
:
[
{
required
:
true
,
message
:
'请选择标签名称'
,
trigger
:
[
'change'
,
'blur'
],
},
],
...
...
@@ -553,7 +704,7 @@ function openSubjectDrawer() {
function
openLinkDrawer
()
{
showLinkDrawer
.
value
=
true
linkData
.
value
=
{
sourceNodeId
:
null
,
sourceNodeId
:
curSubject
.
value
.
nodeId
,
targetNodeId
:
null
,
}
}
...
...
@@ -567,6 +718,55 @@ function addNewItem() {
function
deleteItem
(
i
)
{
formData
.
value
.
splice
(
i
,
1
)
}
const
editData
=
ref
(
null
)
const
showEditDrawer
=
ref
(
false
)
const
editFormRef
=
ref
(
null
)
function
openEditDrawer
(
d
)
{
editData
.
value
=
d
showEditDrawer
.
value
=
true
}
function
editNode
(
e
)
{
e
.
preventDefault
()
editFormRef
.
value
.
validate
((
errors
)
=>
{
if
(
!
errors
)
{
isLoading
.
value
=
true
const
{
nodeLabel
,
nodeId
}
=
curNode
.
value
let
params
=
{}
if
(
nodeLabel
===
'Subject'
)
{
params
=
{
subjectName
:
editData
.
value
.
subjectName
,
subjectType
:
editData
.
value
.
subjectType
,
}
}
else
if
(
nodeLabel
===
'Property'
)
{
params
=
{
propertyName
:
editData
.
value
.
propertyName
,
}
}
ajax
.
put
({
url
:
api
.
PUT_NODE
.
replace
(
'{nodeType}'
,
nodeLabel
).
replace
(
'{id}'
,
nodeId
),
params
,
})
.
then
(()
=>
{
graphData
.
value
.
nodes
.
forEach
((
node
)
=>
{
if
(
node
.
nodeId
===
nodeId
)
{
for
(
const
key
in
params
)
{
node
[
key
]
=
params
[
key
]
}
}
})
d3Ref
.
value
.
updateGraph
(
graphData
.
value
)
isLoading
.
value
=
false
showEditDrawer
.
value
=
false
message
.
success
(
'编辑成功'
)
})
}
})
}
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
src/main.js
View file @
6ddd03b6
...
...
@@ -11,6 +11,7 @@ import {
NForm
,
NFormItem
,
NInput
,
NCheckbox
,
NInputGroup
,
NSelect
,
NMessageProvider
,
...
...
@@ -29,6 +30,7 @@ const naive = create({
NForm
,
NFormItem
,
NInput
,
NCheckbox
,
NInputGroup
,
NSelect
,
NMessageProvider
,
...
...
src/util/useD3.js
View file @
6ddd03b6
...
...
@@ -34,11 +34,11 @@ function textWrap(text, width) {
text
.
each
(
function
()
{
const
text
=
d3
.
select
(
this
),
words
=
text
.
text
().
split
(
''
).
reverse
(),
lineHeight
=
1.
2
,
// ems
lineHeight
=
1.
1
,
// ems
dy
=
0
,
x
=
text
.
attr
(
'x'
)
let
y
=
text
.
attr
(
'y'
)
let
y
=
+
text
.
attr
(
'y'
)
+
4
if
(
words
.
length
>
4
&&
words
.
length
<=
8
)
{
y
=
+
y
-
4
...
...
@@ -85,8 +85,8 @@ function polygonPoints(cx, cy, r, n) {
let
a
=
Math
.
PI
/
2
+
alpha
/
2
let
points
=
''
for
(
let
i
=
0
;
i
<
n
;
i
++
)
{
x
=
cx
+
r
*
Math
.
cos
(
a
)
y
=
cy
+
r
*
Math
.
sin
(
a
)
const
x
=
cx
+
r
*
Math
.
cos
(
a
)
const
y
=
cy
+
r
*
Math
.
sin
(
a
)
points
+=
x
+
','
+
y
+
','
a
+=
alpha
}
...
...
@@ -103,7 +103,7 @@ const defaultConfig = {
chargeStrength
:
300
,
// 万有引力
collide
:
80
,
// 碰撞力的大小 (节点之间的间距)
alphaDecay
:
0.1
,
// 控制力学模拟衰减率
r
:
36
,
// 圈圈的半径 [30 - 45]
r
:
40
,
// 圈圈的半径 [30 - 45]
nodeColor
:
'skyblue'
,
// 圈圈节点背景颜色
fontColor
:
'#2c3e50'
,
// 圈圈内文字的颜色
linkSrc
:
30
,
// 划线时候的弧度
...
...
@@ -207,7 +207,7 @@ export default class RelationGraph {
d3
.
selectAll
(
'.node-text'
)
.
text
((
d
)
=>
(
key
&&
d
[
key
])
||
'无'
)
// .text((d) => (key && d[key]) || d[d.nodeLabel.toLowerCase() + 'Name'])
.
call
(
textWrap
,
this
.
config
.
r
*
1.
8
)
.
call
(
textWrap
,
this
.
config
.
r
*
1.
6
)
}
initPatterns
()
{
...
...
@@ -239,7 +239,7 @@ export default class RelationGraph {
.
append
(
'text'
)
.
attr
(
'class'
,
'node-text'
)
.
attr
(
'x'
,
this
.
config
.
r
)
.
attr
(
'y'
,
this
.
config
.
r
)
// edit
.
attr
(
'y'
,
this
.
config
.
r
)
.
attr
(
'text-anchor'
,
'middle'
)
.
attr
(
'dominant-baseline'
,
'middle'
)
.
attr
(
'fill'
,
'#000'
)
...
...
@@ -313,27 +313,72 @@ export default class RelationGraph {
.
text
((
d
)
=>
d
.
name
)
}
initCircles
(
circleWrapper
)
{
const
self
=
this
// 给圈圈节点添加g便于后面添加menu
if
(
circleWrapper
)
{
this
.
circlesWrapper
=
circleWrapper
initCircles
(
wrappers
)
{
if
(
this
.
config
.
others
.
length
===
0
)
return
if
(
wrappers
)
{
this
.
circleWrappers
=
wrappers
}
else
{
this
.
circlesWrapper
=
this
.
relMap_g
// 给节点添加g便于后面添加menu
this
.
circleWrappers
=
this
.
relMap_g
.
selectAll
(
'g.circle-wrapper'
)
.
data
(
this
.
config
.
node
s
)
.
data
(
this
.
config
.
other
s
)
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'circle-wrapper'
)
.
attr
(
'class'
,
'circle-wrapper
node
'
)
.
raise
()
}
// 6.关系图添加用于显示圈圈的节点
this
.
circles
&&
this
.
circles
.
remove
()
this
.
circles
=
this
.
circle
sWrapper
this
.
circles
=
this
.
circle
Wrappers
.
append
(
'circle'
)
.
attr
(
'class'
,
'.circle'
)
.
attr
(
'r'
,
this
.
config
.
r
)
this
.
addEvent
(
this
.
circles
)
}
initSquares
(
wrappers
)
{
if
(
this
.
config
.
subjects
.
length
===
0
)
return
if
(
wrappers
)
{
this
.
squareWrappers
=
wrappers
}
else
{
this
.
squareWrappers
=
this
.
relMap_g
.
selectAll
(
'g.square-wrapper'
)
.
data
(
this
.
config
.
subjects
)
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'square-wrapper'
)
.
raise
()
}
this
.
squares
&&
this
.
squares
.
remove
()
this
.
squares
=
this
.
squareWrappers
.
append
(
'polygon'
).
attr
(
'class'
,
'square'
)
this
.
addEvent
(
this
.
squares
)
}
initPentagons
(
wrappers
)
{
if
(
this
.
config
.
objects
.
length
===
0
)
return
if
(
wrappers
)
{
this
.
pentagonWrappers
=
wrappers
}
else
{
this
.
pentagonWrappers
=
this
.
relMap_g
.
selectAll
(
'g.pentagon-wrapper'
)
.
data
(
this
.
config
.
objects
)
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'pentagon-wrapper'
)
.
raise
()
}
this
.
pentagons
&&
this
.
pentagons
.
remove
()
this
.
pentagons
=
this
.
pentagonWrappers
.
append
(
'polygon'
)
.
attr
(
'class'
,
'pentagons'
)
this
.
addEvent
(
this
.
pentagons
)
}
addEvent
(
graph
)
{
if
(
!
graph
)
return
const
self
=
this
graph
.
attr
(
'class'
,
'node'
)
.
style
(
'cursor'
,
'pointer'
)
.
attr
(
'fill'
,
(
d
)
=>
`url(#
${
d
.
id
}
)`
)
...
...
@@ -374,8 +419,10 @@ export default class RelationGraph {
self
.
closeMenu
(
true
)
if
(
d
.
nodeLabel
===
'Subject'
)
{
self
.
openMenu
(
this
,
d
)
}
else
if
(
d
.
nodeLabel
===
'System'
)
{
self
.
openMenu
(
this
,
d
,
[
'del'
])
}
else
{
self
.
openMenu
(
this
,
d
,
[
'del'
,
'
branch
'
])
self
.
openMenu
(
this
,
d
,
[
'del'
,
'
edit
'
])
}
}
})
...
...
@@ -404,17 +451,20 @@ export default class RelationGraph {
// 要取消节点,请将节点 .fx和节点 .fy设置为空,或删除这些属性。
d
.
fx
=
e
.
x
d
.
fy
=
e
.
y
d
.
x
=
e
.
x
d
.
y
=
e
.
y
})
.
on
(
'end'
,
(
e
,
d
)
=>
{
// 让alpha目标值值恢复为默认值0,停止力模型
if
(
!
e
.
active
)
this
.
simulation
.
alphaTarget
(
0
)
d
.
fx
=
e
.
x
d
.
fy
=
e
.
y
d
.
x
=
e
.
x
d
.
y
=
e
.
y
})
)
// 文字折行
this
.
SVG
.
selectAll
(
'text.node-text'
).
call
(
textWrap
,
this
.
config
.
r
*
1.
8
)
this
.
SVG
.
selectAll
(
'text.node-text'
).
call
(
textWrap
,
this
.
config
.
r
*
1.
5
)
}
// 创建力学模拟器
...
...
@@ -445,26 +495,53 @@ export default class RelationGraph {
}
update
(
data
)
{
const
{
nodes
,
link
s
}
=
this
.
transformData
(
data
)
const
{
links
,
nodes
,
subjects
,
objects
,
other
s
}
=
this
.
transformData
(
data
)
this
.
config
.
nodes
=
[...
nodes
]
this
.
config
.
links
=
[...
links
]
this
.
config
.
subjects
=
[...
subjects
]
this
.
config
.
objects
=
[...
objects
]
this
.
config
.
others
=
[...
others
]
console
.
log
(
'update'
,
this
.
config
)
this
.
initPatterns
()
this
.
initLinks
()
const
updateNodes
=
this
.
relMap_g
.
selectAll
(
'g.circle-wrapper'
)
.
data
(
this
.
config
.
nodes
)
updateNodes
.
exit
().
remove
()
const
newCircles
=
this
.
relMap_g
.
selectAll
(
'g.circle-wrapper'
).
data
(
others
)
newCircles
.
exit
().
remove
()
this
.
initCircles
(
updateNod
es
newCircl
es
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'circle-wrapper'
)
.
merge
(
updateNodes
)
.
merge
(
newCircles
)
.
raise
()
)
const
newSquares
=
this
.
relMap_g
.
selectAll
(
'g.square-wrapper'
)
.
data
(
subjects
)
newSquares
.
exit
().
remove
()
this
.
initSquares
(
newSquares
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'square-wrapper'
)
.
merge
(
newSquares
)
.
raise
()
)
const
newPentagons
=
this
.
relMap_g
.
selectAll
(
'g.pentagon-wrapper'
)
.
data
(
objects
)
newPentagons
.
exit
().
remove
()
this
.
initPentagons
(
newPentagons
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'pentagon-wrapper'
)
.
merge
(
newPentagons
)
.
raise
()
)
...
...
@@ -564,9 +641,12 @@ export default class RelationGraph {
this
.
initLinks
()
this
.
initCircles
()
this
.
initPentagons
()
this
.
initSquares
()
}
ticked
()
{
const
{
r
}
=
this
.
config
// 7.1 修改每条容器edge的位置
this
.
edges
.
attr
(
'transform'
,
(
d
)
=>
getTransform
(
d
.
source
,
d
.
target
,
getDis
(
d
.
source
,
d
.
target
))
...
...
@@ -596,7 +676,6 @@ export default class RelationGraph {
return
'rotate(0)'
}
})
// 7.4 修改线中装文本矩形rect的位置
this
.
rects
.
attr
(
'x'
,
function
(
d
)
{
return
getDis
(
d
.
source
,
d
.
target
)
/
2
-
d3
.
select
(
this
).
attr
(
'width'
)
/
2
...
...
@@ -604,6 +683,14 @@ export default class RelationGraph {
// 5.修改节点的位置
this
.
circles
.
attr
(
'cx'
,
(
d
)
=>
d
.
x
).
attr
(
'cy'
,
(
d
)
=>
d
.
y
)
this
.
squares
.
attr
(
'x'
,
(
d
)
=>
d
.
x
-
r
)
.
attr
(
'y'
,
(
d
)
=>
d
.
y
-
r
)
.
attr
(
'points'
,
(
d
)
=>
polygonPoints
(
d
.
x
,
d
.
y
,
r
,
6
))
this
.
pentagons
.
attr
(
'x'
,
(
d
)
=>
d
.
x
-
r
)
.
attr
(
'y'
,
(
d
)
=>
d
.
y
-
r
)
.
attr
(
'points'
,
(
d
)
=>
polygonPoints
(
d
.
x
,
d
.
y
,
r
,
10
))
// 让menu随圆圈移动
this
.
circles
.
each
(
function
()
{
...
...
@@ -612,7 +699,25 @@ export default class RelationGraph {
const
self
=
d3
.
select
(
this
)
const
cx
=
self
.
attr
(
'cx'
)
const
cy
=
self
.
attr
(
'cy'
)
menuEle
.
attr
(
'transform'
,
`translate(
${
cx
}
,
${
cy
}
)`
)
menuEle
.
attr
(
'transform'
,
`translate(
${
cx
}
,
${
cy
}
)`
).
raise
()
}
})
this
.
squares
.
each
(
function
()
{
const
menuEle
=
d3
.
select
(
this
.
nextSibling
)
if
(
!
menuEle
.
empty
())
{
const
self
=
d3
.
select
(
this
)
const
cx
=
+
self
.
attr
(
'x'
)
+
r
const
cy
=
+
self
.
attr
(
'y'
)
+
r
menuEle
.
attr
(
'transform'
,
`translate(
${
cx
}
,
${
cy
}
)`
).
raise
()
}
})
this
.
pentagons
.
each
(
function
()
{
const
menuEle
=
d3
.
select
(
this
.
nextSibling
)
if
(
!
menuEle
.
empty
())
{
const
self
=
d3
.
select
(
this
)
const
cx
=
+
self
.
attr
(
'x'
)
+
r
const
cy
=
+
self
.
attr
(
'y'
)
+
r
menuEle
.
attr
(
'transform'
,
`translate(
${
cx
}
,
${
cy
}
)`
).
raise
()
}
})
}
...
...
@@ -650,7 +755,7 @@ export default class RelationGraph {
this
.
dependsLink
=
Array
.
from
(
new
Set
(
this
.
dependsLink
))
// 隐藏节点
this
.
SVG
.
selectAll
(
'
circl
e'
)
this
.
SVG
.
selectAll
(
'
.nod
e'
)
.
filter
((
d
)
=>
this
.
dependsNode
.
indexOf
(
d
.
index
)
==
-
1
)
.
transition
()
.
style
(
'opacity'
,
0.2
)
...
...
@@ -663,7 +768,7 @@ export default class RelationGraph {
}
else
{
// 取消高亮
// 恢复隐藏的线
this
.
SVG
.
selectAll
(
'
circl
e'
).
transition
().
style
(
'opacity'
,
1
)
this
.
SVG
.
selectAll
(
'
.nod
e'
).
transition
().
style
(
'opacity'
,
1
)
// 恢复隐藏的线
this
.
SVG
.
selectAll
(
'.edge'
).
transition
().
style
(
'opacity'
,
1
)
...
...
@@ -676,7 +781,7 @@ export default class RelationGraph {
highlightLinks
(
obj
)
{
if
(
obj
)
{
// 隐藏节点
this
.
SVG
.
selectAll
(
'
circl
e'
)
this
.
SVG
.
selectAll
(
'
.nod
e'
)
.
filter
((
d
)
=>
{
const
sourceIndex
=
this
.
config
.
nodes
.
findIndex
(
(
e
)
=>
e
.
id
==
obj
.
source
.
id
...
...
@@ -695,7 +800,7 @@ export default class RelationGraph {
.
transition
()
.
style
(
'opacity'
,
0.1
)
}
else
{
this
.
SVG
.
selectAll
(
'
circl
e'
).
transition
().
style
(
'opacity'
,
1
)
this
.
SVG
.
selectAll
(
'
.nod
e'
).
transition
().
style
(
'opacity'
,
1
)
this
.
SVG
.
selectAll
(
'.edge'
).
transition
().
style
(
'opacity'
,
1
)
}
}
...
...
@@ -703,7 +808,7 @@ export default class RelationGraph {
setHighlights
(
key
)
{
this
.
curHighlightKey
=
key
this
.
config
.
isHighLight
=
false
this
.
SVG
.
selectAll
(
'
circl
e'
).
transition
().
style
(
'opacity'
,
1
)
this
.
SVG
.
selectAll
(
'
.nod
e'
).
transition
().
style
(
'opacity'
,
1
)
this
.
SVG
.
selectAll
(
'.edge'
).
transition
().
style
(
'opacity'
,
1
)
this
.
dependsNode
=
[]
this
.
dependsLink
=
[]
...
...
@@ -733,7 +838,7 @@ export default class RelationGraph {
})
// 隐藏节点
this
.
SVG
.
selectAll
(
'
circl
e'
)
this
.
SVG
.
selectAll
(
'
.nod
e'
)
.
filter
((
d
)
=>
this
.
dependsNode
.
indexOf
(
d
.
index
)
<
0
)
.
transition
()
.
style
(
'opacity'
,
0.2
)
...
...
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