Commit b9257356 authored by 郭铭瑶's avatar 郭铭瑶 🤘

删除边及选择性高亮功能

parent 2227c5ee
...@@ -11,7 +11,7 @@ export default { ...@@ -11,7 +11,7 @@ export default {
GET_RELATIONS: '/relations', GET_RELATIONS: '/relations',
POST_SUBJECT: '/subject', POST_SUBJECT: '/subject',
POST_NODE: '/node/relation', POST_NODE: '/node/relation',
DELETE_RELATION: '/node/relation', DELETE_RELATION: '/node/relation/{id}',
GET_NODES: '/node/relations', GET_NODES: '/node/relations',
DELETE_NODE: '/node/{id}', DELETE_NODE: '/node/{id}',
GET_SYSTEMS: '/systems', GET_SYSTEMS: '/systems',
......
...@@ -6,9 +6,15 @@ ...@@ -6,9 +6,15 @@
<n-tag <n-tag
v-for="n in nodeList" v-for="n in nodeList"
:key="n.name" :key="n.name"
class="tag"
:class="{
on: curTagKey === n.key,
'click-able': n.key.indexOf('Property') >= 0,
}"
size="small" size="small"
round round
:color="n.color || defaultColor" :color="n.color || defaultColor"
@click="onTagClick(n)"
> >
{{ `${n.name}(${n.val})` }} {{ `${n.name}(${n.val})` }}
</n-tag> </n-tag>
...@@ -48,7 +54,7 @@ export default { ...@@ -48,7 +54,7 @@ export default {
}, },
}, },
}, },
emits: ['link', 'add', 'del', 'branch', 'curNode'], emits: ['link', 'add', 'del', 'branch', 'curNode', 'del-link'],
setup(props, ctx) { setup(props, ctx) {
const colorList = { const colorList = {
default: 'skyblue', default: 'skyblue',
...@@ -89,9 +95,19 @@ export default { ...@@ -89,9 +95,19 @@ export default {
title: '删除', title: '删除',
}, },
] ]
const curTagKey = ref(null)
const setCurNode = (type) => { const setCurNode = (type) => {
if (type.nodeLabel !== 'Subject') {
curTagKey.value = null
}
ctx.emit('curNode', type) ctx.emit('curNode', type)
} }
const handleLinkClick = (d) => {
if (d.target.nodeLabel === 'System') {
ctx.emit('del-link', d)
}
}
function init() { function init() {
if (!container.value) return if (!container.value) return
...@@ -124,7 +140,8 @@ export default { ...@@ -124,7 +140,8 @@ export default {
props.config, props.config,
menuData, menuData,
colorList, colorList,
setCurNode setCurNode,
handleLinkClick
) )
} }
setLegend(data) setLegend(data)
...@@ -152,13 +169,13 @@ export default { ...@@ -152,13 +169,13 @@ export default {
case 'Property_property': case 'Property_property':
return '属性' return '属性'
case 'Property_produce': case 'Property_produce':
return '生产' return '生产行为'
case 'Property_manage': case 'Property_manage':
return '管理' return '管理行为'
case 'Property_service': case 'Property_service':
return '服务' return '服务行为'
case 'Property_use': case 'Property_use':
return '使用' return '使用行为'
default: default:
return '未知' return '未知'
} }
...@@ -206,6 +223,7 @@ export default { ...@@ -206,6 +223,7 @@ export default {
const nodeResult = [] const nodeResult = []
for (const key in nodeKey) { for (const key in nodeKey) {
nodeResult.push({ nodeResult.push({
key,
name: switchName(key), name: switchName(key),
val: nodeKey[key], val: nodeKey[key],
color: { color: {
...@@ -228,6 +246,17 @@ export default { ...@@ -228,6 +246,17 @@ export default {
nodeList.value = nodeResult nodeList.value = nodeResult
linkList.value = linkResult linkList.value = linkResult
} }
function onTagClick({ key }) {
if (key.indexOf('Property') < 0) return
if (curTagKey.value === key) {
curTagKey.value = null
} else {
curTagKey.value = key
}
if (!instance.setHighlights(curTagKey.value)) {
curTagKey.value = null
}
}
return { return {
colorList, colorList,
container, container,
...@@ -239,6 +268,8 @@ export default { ...@@ -239,6 +268,8 @@ export default {
textColor: '#fff', textColor: '#fff',
borderColor: '#a5abb6', borderColor: '#a5abb6',
}, },
curTagKey,
onTagClick,
} }
}, },
} }
...@@ -253,6 +284,17 @@ export default { ...@@ -253,6 +284,17 @@ export default {
position absolute position absolute
top 10px top 10px
left 14px left 14px
.tag
cursor not-allowed
box-sizing border-box
border 2px solid transparent
&.click-able
cursor pointer
&.on
&:hover
box-shadow 0 0 4px 1px rgba(0,0,0,0.3)
&.on
border-color rgba(0,0,0,0.3)
</style> </style>
<style lang="stylus"> <style lang="stylus">
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
@curNode="curNode = $event" @curNode="curNode = $event"
@del="deleteNode" @del="deleteNode"
@link="showLinkDrawer = true" @link="showLinkDrawer = true"
@del-link="deleteLink"
/> />
<Side style="grid-area: side" /> <Side style="grid-area: side" />
<Footer <Footer
...@@ -282,6 +283,32 @@ export default { ...@@ -282,6 +283,32 @@ export default {
}) })
} }
function deleteLink(data) {
const { source, target } = data
dialog.error({
title: '删除关联',
content: `确定是否删除 '${source.propertyName}_${target.systemName}' 关联关系?`,
positiveText: '确定',
negativeText: '取消',
maskClosable: false,
onPositiveClick: () => {
ajax
.delete({
url: api.DELETE_RELATION.replace('{id}', data.id),
})
.then(() => {
graphData.value = {
nodes: graphData.value.nodes,
links: graphData.value.links.filter(
(link) => link.id != data.id
),
}
message.success('删除成功!')
})
},
})
}
const subjectFormRef = ref(null) const subjectFormRef = ref(null)
const showSubjectDrawer = ref(false) const showSubjectDrawer = ref(false)
const subjectData = ref({ subjectName: null }) const subjectData = ref({ subjectName: null })
...@@ -425,6 +452,7 @@ export default { ...@@ -425,6 +452,7 @@ export default {
rules, rules,
curNode, curNode,
deleteNode, deleteNode,
deleteLink,
showSubjectDrawer, showSubjectDrawer,
subjectFormRef, subjectFormRef,
subjectData, subjectData,
......
...@@ -109,9 +109,18 @@ const defaultConfig = { ...@@ -109,9 +109,18 @@ const defaultConfig = {
let menu = null let menu = null
export default class RelationGraph { export default class RelationGraph {
constructor(selector, data, configs = {}, menuData, colorList, setCurNode) { constructor(
selector,
data,
configs = {},
menuData,
colorList,
setCurNode,
handleLinkClick
) {
this.menuData = menuData this.menuData = menuData
this.setCurNode = setCurNode this.setCurNode = setCurNode
this.handleLinkClick = handleLinkClick
const mapW = selector.offsetWidth const mapW = selector.offsetWidth
const mapH = selector.offsetHeight const mapH = selector.offsetHeight
...@@ -134,7 +143,7 @@ export default class RelationGraph { ...@@ -134,7 +143,7 @@ export default class RelationGraph {
// 需要高亮的node和link // 需要高亮的node和link
this.dependsNode = [] this.dependsNode = []
this.dependsLinkAndText = [] this.dependsLink = []
this.tooltip = d3 this.tooltip = d3
.select('body') .select('body')
...@@ -233,6 +242,7 @@ export default class RelationGraph { ...@@ -233,6 +242,7 @@ export default class RelationGraph {
}) })
.on('click', function (e, d) { .on('click', function (e, d) {
console.log('线click') console.log('线click')
self.handleLinkClick(d)
}) })
.attr('fill', (d) => d.color || this.config.linkColor) .attr('fill', (d) => d.color || this.config.linkColor)
...@@ -321,6 +331,9 @@ export default class RelationGraph { ...@@ -321,6 +331,9 @@ export default class RelationGraph {
// self.tooltip.style('opacity', 0) // self.tooltip.style('opacity', 0)
}) })
.on('click', function (e, d) { .on('click', function (e, d) {
//阻止事件冒泡 阻止事件默认行为
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true)
e.preventDefault ? e.preventDefault() : (e.returnValue = false)
// self.tooltip.style('opacity', 0) // self.tooltip.style('opacity', 0)
if (menu && menu.curNodeData == d) { if (menu && menu.curNodeData == d) {
self.closeMenu(true) self.closeMenu(true)
...@@ -332,9 +345,6 @@ export default class RelationGraph { ...@@ -332,9 +345,6 @@ export default class RelationGraph {
self.openMenu(this, d, ['del', 'branch']) self.openMenu(this, d, ['del', 'branch'])
} }
} }
//阻止事件冒泡 阻止事件默认行为
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true)
e.preventDefault ? e.preventDefault() : (e.returnValue = false)
}) })
.on('contextmenu', function (e) { .on('contextmenu', function (e) {
// 取消鼠标右键菜单默认行为 // 取消鼠标右键菜单默认行为
...@@ -429,7 +439,7 @@ export default class RelationGraph { ...@@ -429,7 +439,7 @@ export default class RelationGraph {
.nodes(this.config.nodes) .nodes(this.config.nodes)
.force('link', d3.forceLink(this.config.links)) .force('link', d3.forceLink(this.config.links))
.force('charge', null) .force('charge', null)
.alpha(0.1) .alpha(0.3)
.restart() .restart()
} }
...@@ -448,6 +458,9 @@ export default class RelationGraph { ...@@ -448,6 +458,9 @@ export default class RelationGraph {
d d
) )
} }
if (this.curHighlightKey) {
this.setHighlights(this.curHighlightKey)
}
} }
clearFixedPosition() { clearFixedPosition() {
this.curActiveNode && (this.curActiveNode.fx = null) this.curActiveNode && (this.curActiveNode.fx = null)
...@@ -570,42 +583,44 @@ export default class RelationGraph { ...@@ -570,42 +583,44 @@ export default class RelationGraph {
if (obj) { if (obj) {
const objIndex = obj.index const objIndex = obj.index
this.dependsNode = this.dependsNode.concat([objIndex]) this.dependsNode = this.dependsNode.concat([objIndex])
this.dependsLinkAndText = this.dependsLinkAndText.concat([objIndex]) this.dependsLink = []
this.config.links.forEach((link) => { this.config.links.forEach((link) => {
if (objIndex == link.source.index) { if (objIndex == link.source.index) {
this.dependsNode = this.dependsNode.concat([link.target.index]) this.dependsNode.push(link.target.index)
this.dependsLink.push(link.index)
} else if (objIndex == link.target.index) { } else if (objIndex == link.target.index) {
this.dependsNode = this.dependsNode.concat([link.source.index]) this.dependsNode.push(link.source.index)
this.dependsLink.push(link.index)
} }
}) })
/** 二级节点也要展示 不展示可以删除 */ /** 二级节点也要展示 不展示可以删除 */
const secondNodes = this.dependsNode.filter((e) => e !== objIndex) const secondNodes = this.dependsNode.filter((e) => e !== objIndex)
this.dependsLinkAndText.push(...secondNodes)
this.config.links.forEach((link) => { this.config.links.forEach((link) => {
if (secondNodes.indexOf(link.source.index) >= 0) { if (secondNodes.indexOf(link.source.index) >= 0) {
this.dependsNode = this.dependsNode.concat([link.target.index]) this.dependsNode.push(link.target.index)
this.dependsLink.push(link.index)
} else if (secondNodes.indexOf(link.target.index) >= 0) { } else if (secondNodes.indexOf(link.target.index) >= 0) {
this.dependsNode = this.dependsNode.concat([link.source.index]) this.dependsNode.push(link.source.index)
this.dependsLink.push(link.index)
} }
}) })
this.dependsNode = Array.from(new Set(this.dependsNode))
this.dependsLink = Array.from(new Set(this.dependsLink))
// 隐藏节点 // 隐藏节点
this.SVG.selectAll('circle') this.SVG.selectAll('circle')
.filter((d) => this.dependsNode.indexOf(d.index) == -1) .filter((d) => this.dependsNode.indexOf(d.index) == -1)
.transition() .transition()
.style('opacity', 0.1) .style('opacity', 0.3)
// 隐藏线 // 隐藏线
this.SVG.selectAll('.edge') this.SVG.selectAll('.edge')
.filter( .filter((d) => this.dependsLink.indexOf(d.index) == -1)
(d) =>
this.dependsLinkAndText.indexOf(d.source.index) == -1 &&
this.dependsLinkAndText.indexOf(d.target.index) == -1
)
.transition() .transition()
.style('opacity', 0.1) .style('opacity', 0.3)
} else { } else {
// 取消高亮 // 取消高亮
// 恢复隐藏的线 // 恢复隐藏的线
...@@ -615,7 +630,7 @@ export default class RelationGraph { ...@@ -615,7 +630,7 @@ export default class RelationGraph {
this.SVG.selectAll('.edge').transition().style('opacity', 1) this.SVG.selectAll('.edge').transition().style('opacity', 1)
this.dependsNode = [] this.dependsNode = []
this.dependsLinkAndText = [] this.dependsLink = []
} }
} }
...@@ -633,17 +648,64 @@ export default class RelationGraph { ...@@ -633,17 +648,64 @@ export default class RelationGraph {
return d.index != sourceIndex && d.index != targetIndex return d.index != sourceIndex && d.index != targetIndex
}) })
.transition() .transition()
.style('opacity', 0.1) .style('opacity', 0.3)
// 隐藏线 // 隐藏线
this.SVG.selectAll('.edge') this.SVG.selectAll('.edge')
.filter((d) => d.id != obj.id) .filter((d) => d.id != obj.id)
.transition() .transition()
.style('opacity', 0.1) .style('opacity', 0.3)
} else { } else {
this.SVG.selectAll('circle').transition().style('opacity', 1) this.SVG.selectAll('circle').transition().style('opacity', 1)
this.SVG.selectAll('.edge').transition().style('opacity', 1) this.SVG.selectAll('.edge').transition().style('opacity', 1)
} }
} }
setHighlights(key) {
this.curHighlightKey = key
this.config.isHighLight = false
this.SVG.selectAll('circle').transition().style('opacity', 1)
this.SVG.selectAll('.edge').transition().style('opacity', 1)
this.dependsNode = []
this.dependsLink = []
if (!key || this.curActiveNode.nodeLabel !== 'Subject') {
this.curHighlightKey = null
this.config.isHighLight = true
key = null
// return false
}
this.highlightObject(this.curActiveNode)
this.dependsNode = [this.curActiveNode.index]
this.config.links.forEach((link) => {
const index = this.dependsLink.indexOf(link.index)
if (index < 0) return
if (link.target._label_key != key && link.source._label_key != key) {
this.dependsLink.splice(index, 1)
} else if (
link.target._label_key == key &&
link.source.id != this.curActiveNode.id
) {
this.dependsLink.splice(index, 1)
} else {
this.dependsNode.push(link.target.index)
this.dependsNode.push(link.source.index)
}
})
// 隐藏节点
this.SVG.selectAll('circle')
.filter((d) => this.dependsNode.indexOf(d.index) < 0)
.transition()
.style('opacity', 0.3)
// 隐藏线
this.SVG.selectAll('.edge')
.filter((d) => this.dependsLink.indexOf(d.index) < 0)
.transition()
.style('opacity', 0.3)
return true
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment