关于自定义节点,点击节点高亮的疑问 #6013
ltdys posted onGitHub
Describe the bug / 问题描述
版本:"@antv/g6": "^4.8.24", 需求: 点击节点,canvas出现遮罩层,只凸显节点相邻的下游和上游全链路(包括节点、边,箭头),点击其它节点,之前点击的恢复初始化样式,被点击的高亮。节点是自定义节点。 实现:点击节点后,通过节点寻找到节点相邻的下游和上游全链路,循环所有的节点,不在这些链路之路的,改变背景色,添加透明度,来实现模拟的遮罩效果 问题:1、使用graph.clearItemStates(node)或graph.clearItemStates(edge)后,拖拽或缩放会出现绘制多个节点的情况 2、点击节点改变节点的样式,再次点击无法恢复回来。试了使用update或者updateItem都没成功。
Reproduction link / 重现链接
No response
Steps to Reproduce the Bug or Issue / 重现步骤
// 高亮边(祖先节点) this.graph.on('node:click', (e) => { if (e.target.get('name') === 'collapse-icon') return const item = e.item; const target = e.target const model = item.getModel()
this.clearAllStats()
const currentNodes = this.graph.findById(model.id)
const neighborNodes = currentNodes.getNeighbors()
const currentEdges = this.graph.findById(model.id).getEdges()
let allEdges = []
let allNodes = []
this.graph.setAutoPaint(false);
// 获取所有的父节点(包含祖先节点)
const parentIds = this.findAllAncestors(this.mockData.children, model.id)
let parentEdges = []
let parentNodes = []
for (let parentId of parentIds) {
const findNodes = this.graph.findById(parentId)
const findEdges = findNodes.getEdges()[0]
parentNodes.push(findNodes)
parentEdges.push(findEdges)
}
// 所有的边
allEdges = [...parentEdges, ...currentEdges]
allEdges.forEach(connectedNode => {
this.graph.setItemState(connectedNode, 'highlight', true);
})
this.graph.getEdges().forEach(edge => {
if (!allEdges.includes(edge)) {
this.graph.setItemState(edge, 'inactive', true);
}
})
allNodes = [...[currentNodes], ...neighborNodes, ...parentNodes]
this.graph.getNodes().forEach(node => {
const getrect = node.getKeyShape()
const updateNodeId = node.getModel().id
const updateNode = this.graph.findById(updateNodeId)
// 这里要改变节点的样式,这样是可以成功的。但是点击其它的节点后,不知道怎么恢复回来
if (!allNodes.includes(node)) {
getrect.attr({
fill: 'rgba(0, 0, 0, 0.5)',
stroke: '#000',
filter: 'blur(5px)',
opacity: 0.2
})
}
this.graph.paint(); // 触发重绘
this.graph.setAutoPaint(true); // 恢复自动重绘
});
// 自定义节点的代码 G6.registerNode('flow-rect', { shapeType: 'flow-rect', draw: function drawShape(cfg, group) { let { name = '', beforeRatio, afterRatio, tipInfo, nodeStyleName, inactive } = cfg; nodeStyleName = nodeStyleName || 'nodeStyle1' if (inactive) nodeStyleName = 'nodeStyleInactive' const useNodeStyle = nodeStyle[nodeStyleName]
let w = 253;
if (name === '资产分发指标') w = 180
let h = 44; // 44 68 104
if (beforeRatio) h = 68
if (beforeRatio && tipInfo) h = 104
const rectConfig = {
width: w,
height: h,
lineWidth: 1,
fontSize: 12,
fill: useNodeStyle.bgColor, // 背景色
stroke: useNodeStyle.borderColor, // 边框色
radius: [0, 8, 8, 0],
opacity: 1,
};
const nodeOrigin = {
x: -rectConfig.width / 2,
y: -rectConfig.height / 2,
};
const textConfig = {
textAlign: 'left',
textBaseline: 'bottom',
};
const rect = group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: nodeOrigin.y,
...rectConfig,
},
});
const rectBBox = rect.getBBox();
// name
const nameText = group.addShape('text', {
attrs: {
...textConfig,
x: nodeOrigin.x + 12,
y: nodeOrigin.y + 20 + 12, // 20行高
text: name.length > 28 ? name.substr(0, 28) + '...' : name,
fontSize: 14,
fontWeight: '600',
opacity: 1,
fill: '#333333',
cursor: 'pointer',
fontFamily: 'PingFangSC, PingFang SC'
},
name: 'name-shape',
});
if (beforeRatio) {
// 占比前
const beforeRatioText = group.addShape('text', {
attrs: {
...textConfig,
x: nodeOrigin.x + 12,
y: nameText.getBBox().maxY + 26,
text: beforeRatio,
fontSize: 18,
fontWeight: 'bold',
fill: '#121736',
opacity: 1,
fontFamily: 'QiFu-Sans-Std, QiFu-Sans-Std'
},
})
// 前一天,后一天
const dateText = group.addShape('text', {
attrs: {
...textConfig,
x: beforeRatioText.getBBox().maxX + 4,
y: nameText.getBBox().maxY + 23,
text: this.getDateText(),
fontSize: 12,
fontWeight: 600,
fill: '#121736',
opacity: 1,
fontFamily: 'PingFangSC, PingFang SC'
},
});
group.addShape('image', {
attrs: {
x: dateText.getBBox().maxX + 2,
y: nameText.getBBox().maxY + 12,
width: 9,
height: 10,
img: downImageData,
},
name: 'image-shape',
});
// 占比后
group.addShape('text', {
attrs: {
...textConfig,
x: dateText.getBBox().maxX + 7 + 5,
y: nameText.getBBox().maxY + 24,
text: afterRatio,
fontSize: 12,
fill: '#FF0000',
opacity: 1,
},
});
}
if (tipInfo) {
// tip背景色
group.addShape('rect', {
attrs: {
width: this.getTextSize(tipInfo, 12) + 32,
height: 30,
x: nodeOrigin.x + 12,
y: rectBBox.maxY - 40,
fill: '#ffffff',
radius: 6,
},
name: 'rect-shape-tiptext'
})
// icon
group.addShape('image', {
attrs: {
x: nodeOrigin.x + 20,
y: rectBBox.maxY - 32,
width: 10,
height: 10,
img: warningImageData,
},
name: 'image-shape-warning',
});
// tip
group.addShape('text', {
attrs: {
...textConfig,
x: nodeOrigin.x + 34,
y: rectBBox.maxY - 20,
text: tipInfo,
fontSize: 12,
fill: 'red',
stroke: '#ffffff',
opacity: 1,
},
})
}
// left border
const leftRect = group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: nodeOrigin.y,
width: 2,
height: rectBBox.height,
radius: 0,
fill: useNodeStyle.borderLeftColor,
},
});
cfg.children &&
group.addShape('marker', {
attrs: {
x: w / 2,
y: 0,
r: 6,
cursor: 'pointer',
symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
stroke: '#fff',
lineWidth: 1,
fill: '#333333',
},
// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
name: 'collapse-icon',
modelId: cfg.name,
});
return rect;
},
setState(name, value, item) {
if (name === 'collapsed') {
const marker = item.get('group').find((ele) => ele.get('name') === 'collapse-icon');
const icon = value ? G6.Marker.expand : G6.Marker.collapse;
marker.attr('symbol', icon);
}
},
getDateText() {
let result = ''
switch (_dateType) {
case 'day':
result = '比前一天'
break;
case 'week':
result = '比前一周'
break;
case 'month':
result = '比前一月'
break;
}
return result
},
getTextSize(text, fontSize) {
const span = document.createElement('span')
const result = {}
result.width = span.offsetWidth
result.height = span.offsetWidth
span.style.visibility = 'hidden'
span.style.fontSize = fontSize + 'px'
document.body.appendChild(span)
if (typeof span.textContent !== 'undefined') {
span.textContent = text
} else {
span.innerText = text
}
result.width = span.offsetWidth - result.width
result.height = span.offsetHeight - result.height
span.parentNode.removeChild(span)
return result.width
},
});
// 清空所有节点和边 clearAllStats() { this.graph.setAutoPaint(false); this.graph.getNodes().forEach((node) => { this.graph.clearItemStates(node); }); this.graph.getEdges().forEach((edge) => { this.graph.clearItemStates(edge); }); this.graph.paint(); this.graph.setAutoPaint(true); },
G6 Version / G6 版本
4.x
Operating System / 操作系统
Windows
Browser / 浏览器
Chrome
Additional context / 补充说明
求大佬指教,或者找个demo让我看下也好,卡住了不知道该怎么改。