修改Highcharts组织结构图鼠标追踪:hover节点显示全部关联节点
实现Highcharts组织结构图多级关联节点鼠标追踪
要实现悬停节点时显示所有多级父节点和子节点,需要自定义鼠标事件处理逻辑,递归遍历并控制节点和连线的可见性。以下是修改后的完整代码:
修改后的JavaScript代码
Highcharts.chart('container', { chart: { height: 600, inverted: true }, title: { text: 'Highcharts Org Chart' }, accessibility: { point: { descriptionFormatter: function (point) { var nodeName = point.toNode.name, nodeId = point.toNode.id, nodeDesc = nodeName === nodeId ? nodeName : nodeName + ', ' + nodeId, parentDesc = point.fromNode.id; return point.index + '. ' + nodeDesc + ', reports to ' + parentDesc + '.'; } } }, series: [{ type: 'organization', name: 'Highsoft', keys: ['from', 'to'], data: [ ['Shareholders', 'Board'], ['Board', 'CEO'], ['CEO', 'CTO'], ['CEO', 'CPO'], ['CEO', 'CSO'], ['CEO', 'HR'], ['CTO', 'Product'], ['CTO', 'Web'], ['CSO', 'Sales'], ['HR', 'Market'], ['CSO', 'Market'], ['HR', 'Market'], ['CTO', 'Market'] ], levels: [{ level: 0, color: 'silver', dataLabels: { color: 'black' }, height: 25 }, { level: 1, color: 'silver', dataLabels: { color: 'black' }, height: 25 }, { level: 2, color: '#980104' }, { level: 4, color: '#359154' }], nodes: [{ id: 'Shareholders' }, { id: 'Board' }, { id: 'CEO', title: 'CEO', name: 'Atle Sivertsen', image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2022/06/30081411/portrett-sorthvitt.jpg' }, { id: 'HR', title: 'CFO', name: 'Anne Jorunn Fjærestad', color: '#007ad0', image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2020/03/17131210/Highsoft_04045_.jpg' }, { id: 'CTO', title: 'CTO', name: 'Christer Vasseng', image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2020/03/17131120/Highsoft_04074_.jpg' }, { id: 'CPO', title: 'CPO', name: 'Torstein Hønsi', image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2020/03/17131213/Highsoft_03998_.jpg' }, { id: 'CSO', title: 'CSO', name: 'Anita Nesse', image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2020/03/17131156/Highsoft_03834_.jpg' }, { id: 'Product', name: 'Product developers' }, { id: 'Web', name: 'Web devs, sys admin' }, { id: 'Sales', name: 'Sales team' }, { id: 'Market', name: 'Marketing team', column: 5 }], colorByPoint: false, color: '#007ad0', dataLabels: { color: 'white' }, borderColor: 'white', nodeWidth: 65, // 自定义鼠标事件 point: { events: { mouseOver: function() { const series = this.series; const allNodes = series.nodeLookup; const allPoints = series.points; const targetNode = this.toNode || this.fromNode; // 递归收集所有祖先节点 const getAncestors = (node) => { const ancestors = []; const parentPoints = allPoints.filter(p => p.toNode.id === node.id); parentPoints.forEach(p => { const parentNode = p.fromNode; ancestors.push(parentNode); ancestors.push(...getAncestors(parentNode)); }); return ancestors; }; // 递归收集所有后代节点 const getDescendants = (node) => { const descendants = []; const childPoints = allPoints.filter(p => p.fromNode.id === node.id); childPoints.forEach(p => { const childNode = p.toNode; descendants.push(childNode); descendants.push(...getDescendants(childNode)); }); return descendants; }; const relatedNodes = [targetNode, ...getAncestors(targetNode), ...getDescendants(targetNode)]; const relatedNodeIds = new Set(relatedNodes.map(n => n.id)); // 隐藏非关联节点和连线 Object.values(allNodes).forEach(node => { node.graphic.attr('opacity', relatedNodeIds.has(node.id) ? 1 : 0.1); if (node.dataLabel) { node.dataLabel.attr('opacity', relatedNodeIds.has(node.id) ? 1 : 0); } }); allPoints.forEach(point => { point.graphic.attr('opacity', relatedNodeIds.has(point.fromNode.id) && relatedNodeIds.has(point.toNode.id) ? 1 : 0.1 ); }); }, mouseOut: function() { const series = this.series; const allNodes = series.nodeLookup; const allPoints = series.points; // 恢复所有节点和连线可见 Object.values(allNodes).forEach(node => { node.graphic.attr('opacity', 1); if (node.dataLabel) { node.dataLabel.attr('opacity', 1); } }); allPoints.forEach(point => { point.graphic.attr('opacity', 1); }); } } } }], tooltip: { outside: false }, exporting: { allowHTML: true, sourceWidth: 800, sourceHeight: 600 } });
核心逻辑说明
- 递归收集关联节点:
getAncestors函数向上遍历所有父级节点,直到根节点getDescendants函数向下遍历所有子级节点,直到叶子节点
- 控制可见性:
- 鼠标悬停时,将非关联节点和连线设置为半透明(opacity:0.1),隐藏非关联节点的标签
- 鼠标移出时,恢复所有元素的完全可见状态
CSS和HTML代码保持原代码不变即可。
内容的提问来源于stack exchange,提问作者elina
相关产品推荐
相关产品推荐

