|
|
@@ -38,6 +38,21 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
color: #eee;
|
|
|
overflow: hidden;
|
|
|
}}
|
|
|
+ /* 自定义滚动条 */
|
|
|
+ ::-webkit-scrollbar {{
|
|
|
+ width: 6px;
|
|
|
+ height: 6px;
|
|
|
+ }}
|
|
|
+ ::-webkit-scrollbar-track {{
|
|
|
+ background: transparent;
|
|
|
+ }}
|
|
|
+ ::-webkit-scrollbar-thumb {{
|
|
|
+ background: rgba(255,255,255,0.2);
|
|
|
+ border-radius: 3px;
|
|
|
+ }}
|
|
|
+ ::-webkit-scrollbar-thumb:hover {{
|
|
|
+ background: rgba(255,255,255,0.3);
|
|
|
+ }}
|
|
|
#container {{
|
|
|
display: flex;
|
|
|
height: 100vh;
|
|
|
@@ -1330,7 +1345,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
const layerConfig = [
|
|
|
{{ name: "帖子点", layer: 0, color: "rgba(243, 156, 18, 0.08)", stroke: "rgba(243, 156, 18, 0.3)" }},
|
|
|
{{ name: "帖子标签", layer: 1, color: "rgba(52, 152, 219, 0.08)", stroke: "rgba(52, 152, 219, 0.3)" }},
|
|
|
- {{ name: "人设", layer: 2, color: "rgba(155, 89, 182, 0.08)", stroke: "rgba(155, 89, 182, 0.3)" }}
|
|
|
+ {{ name: "人设匹配", layer: 2, color: "rgba(155, 89, 182, 0.08)", stroke: "rgba(155, 89, 182, 0.3)" }}
|
|
|
];
|
|
|
|
|
|
// 绘制三层圆形背景
|
|
|
@@ -1659,6 +1674,14 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
const linkIndex = links.indexOf(d);
|
|
|
highlightEdge(d, linkIndex);
|
|
|
showEdgeInfo(d);
|
|
|
+ // 边联动:如果边涉及人设节点,联动人设树和关系图
|
|
|
+ const sourceNode = typeof d.source === "object" ? d.source : nodes.find(n => n.id === d.source);
|
|
|
+ const targetNode = typeof d.target === "object" ? d.target : nodes.find(n => n.id === d.target);
|
|
|
+ if (sourceNode && sourceNode.source === "人设") {{
|
|
|
+ handleNodeClick(sourceNode.节点ID, sourceNode.节点名称);
|
|
|
+ }} else if (targetNode && targetNode.source === "人设") {{
|
|
|
+ handleNodeClick(targetNode.节点ID, targetNode.节点名称);
|
|
|
+ }}
|
|
|
}})
|
|
|
.on("mouseover", function(event, d) {{
|
|
|
d3.select(this.parentNode).select(".link")
|
|
|
@@ -1765,6 +1788,10 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
event.stopPropagation();
|
|
|
highlightNode(d);
|
|
|
showNodeInfo(d);
|
|
|
+ // 人设节点联动:高亮人设树 + 显示关系图
|
|
|
+ if (d.source === "人设") {{
|
|
|
+ handleNodeClick(d.节点ID, d.节点名称);
|
|
|
+ }}
|
|
|
}});
|
|
|
|
|
|
// 更新位置
|
|
|
@@ -2298,16 +2325,64 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
showTreeNodeDetail(nodeData, inEdges, outEdges);
|
|
|
}}
|
|
|
|
|
|
- // 显示关系子图
|
|
|
+ // 显示关系子图(先显示,这样容器高度才正确)
|
|
|
renderEgoGraph(clickedNodeId, clickedNodeName);
|
|
|
|
|
|
- // 高亮右侧图中对应节点
|
|
|
+ // 滚动人设树到对应节点位置(放在关系图显示后,高度才准确)
|
|
|
+ if (clickedD3Node) {{
|
|
|
+ // 用 setTimeout 确保 DOM 更新完成
|
|
|
+ setTimeout(() => {{
|
|
|
+ const treeContainer = document.getElementById("tree-container");
|
|
|
+ const containerHeight = treeContainer.clientHeight;
|
|
|
+ // D3树布局中 x 是垂直方向(因为是水平树)
|
|
|
+ const nodeY = clickedD3Node.x + 25; // 加上treeGroup的transform偏移
|
|
|
+ const targetScroll = nodeY - containerHeight / 2;
|
|
|
+ treeContainer.scrollTo({{
|
|
|
+ top: Math.max(0, targetScroll),
|
|
|
+ behavior: "smooth"
|
|
|
+ }});
|
|
|
+ }}, 50);
|
|
|
+ }}
|
|
|
+
|
|
|
+ // 高亮右侧图中对应节点及其相关节点和边
|
|
|
if (g) {{
|
|
|
- const graphNode = g.selectAll(".node").filter(n => n.节点ID === clickedNodeId);
|
|
|
- if (!graphNode.empty()) {{
|
|
|
+ // 收集相关节点ID(点击的节点及其直接连接的节点)
|
|
|
+ const relatedNodeIds = new Set([clickedNodeId]);
|
|
|
+ // 找所有与该节点相连的边
|
|
|
+ g.selectAll(".link-group").each(function(d) {{
|
|
|
+ const srcId = typeof d.source === "object" ? d.source.id : d.source;
|
|
|
+ const tgtId = typeof d.target === "object" ? d.target.id : d.target;
|
|
|
+ if (srcId === clickedNodeId || tgtId === clickedNodeId) {{
|
|
|
+ relatedNodeIds.add(srcId);
|
|
|
+ relatedNodeIds.add(tgtId);
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+
|
|
|
+ // 检查是否有相关节点在图中
|
|
|
+ const hasRelatedNodes = g.selectAll(".node").filter(n => relatedNodeIds.has(n.id)).size() > 0;
|
|
|
+
|
|
|
+ if (hasRelatedNodes) {{
|
|
|
+ // 高亮相关节点,变灰其他
|
|
|
+ g.selectAll(".node")
|
|
|
+ .classed("dimmed", n => !relatedNodeIds.has(n.id))
|
|
|
+ .classed("highlighted", n => relatedNodeIds.has(n.id));
|
|
|
+ // 高亮相关边
|
|
|
+ g.selectAll(".link-group").each(function(d) {{
|
|
|
+ const srcId = typeof d.source === "object" ? d.source.id : d.source;
|
|
|
+ const tgtId = typeof d.target === "object" ? d.target.id : d.target;
|
|
|
+ const isRelated = srcId === clickedNodeId || tgtId === clickedNodeId;
|
|
|
+ d3.select(this)
|
|
|
+ .classed("dimmed", !isRelated)
|
|
|
+ .classed("highlighted", isRelated);
|
|
|
+ // 显示相关的跨层边
|
|
|
+ if (isRelated) {{
|
|
|
+ d3.select(this).style("display", "block");
|
|
|
+ }}
|
|
|
+ }});
|
|
|
+ }} else {{
|
|
|
+ // 点击的节点不在图中,全部变灰
|
|
|
g.selectAll(".node").classed("dimmed", true).classed("highlighted", false);
|
|
|
g.selectAll(".link-group").classed("dimmed", true).classed("highlighted", false);
|
|
|
- graphNode.classed("dimmed", false).classed("highlighted", true);
|
|
|
}}
|
|
|
}}
|
|
|
}}
|
|
|
@@ -2386,6 +2461,34 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
`;
|
|
|
document.getElementById("detailContent").innerHTML = html;
|
|
|
|
|
|
+ // 高亮右侧人设匹配区域
|
|
|
+ if (g) {{
|
|
|
+ const relatedNodeIds = new Set([srcNodeId, tgtNodeId]);
|
|
|
+ const hasRelatedNodes = g.selectAll(".node").filter(n => relatedNodeIds.has(n.id)).size() > 0;
|
|
|
+
|
|
|
+ if (hasRelatedNodes) {{
|
|
|
+ // 高亮相关节点
|
|
|
+ g.selectAll(".node")
|
|
|
+ .classed("dimmed", n => !relatedNodeIds.has(n.id))
|
|
|
+ .classed("highlighted", n => relatedNodeIds.has(n.id));
|
|
|
+ // 高亮相关边
|
|
|
+ g.selectAll(".link-group").each(function(d) {{
|
|
|
+ const sid = typeof d.source === "object" ? d.source.id : d.source;
|
|
|
+ const tid = typeof d.target === "object" ? d.target.id : d.target;
|
|
|
+ const isRelated = (sid === srcNodeId && tid === tgtNodeId) ||
|
|
|
+ (sid === tgtNodeId && tid === srcNodeId) ||
|
|
|
+ relatedNodeIds.has(sid) || relatedNodeIds.has(tid);
|
|
|
+ d3.select(this)
|
|
|
+ .classed("dimmed", !isRelated)
|
|
|
+ .classed("highlighted", isRelated);
|
|
|
+ }});
|
|
|
+ }} else {{
|
|
|
+ // 全部变灰
|
|
|
+ g.selectAll(".node").classed("dimmed", true).classed("highlighted", false);
|
|
|
+ g.selectAll(".link-group").classed("dimmed", true).classed("highlighted", false);
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+
|
|
|
// 在关系图中展示这条边和两个节点
|
|
|
const edgeData = {{
|
|
|
边类型: edgeType,
|