|
@@ -437,7 +437,10 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
.edge-label-bg {{
|
|
.edge-label-bg {{
|
|
|
fill: rgba(0,0,0,0.7);
|
|
fill: rgba(0,0,0,0.7);
|
|
|
}}
|
|
}}
|
|
|
- .link.match {{
|
|
|
|
|
|
|
+ .link.match-same {{
|
|
|
|
|
+ stroke: #e94560;
|
|
|
|
|
+ }}
|
|
|
|
|
+ .link.match-similar {{
|
|
|
stroke: #e94560;
|
|
stroke: #e94560;
|
|
|
stroke-dasharray: 5,5;
|
|
stroke-dasharray: 5,5;
|
|
|
}}
|
|
}}
|
|
@@ -623,7 +626,11 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
<div class="legend-grid">
|
|
<div class="legend-grid">
|
|
|
<div class="legend-item">
|
|
<div class="legend-item">
|
|
|
<div class="legend-line" style="background: #e94560;"></div>
|
|
<div class="legend-line" style="background: #e94560;"></div>
|
|
|
- <span>匹配</span>
|
|
|
|
|
|
|
+ <span>相同(≥0.8)</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="legend-item">
|
|
|
|
|
+ <div class="legend-line" style="background: linear-gradient(90deg, #e94560 0%, #e94560 40%, transparent 40%, transparent 60%, #e94560 60%);"></div>
|
|
|
|
|
+ <span>相似(0.5-0.8)</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="legend-item">
|
|
<div class="legend-item">
|
|
|
<div class="legend-line" style="background: #9b59b6;"></div>
|
|
<div class="legend-line" style="background: #9b59b6;"></div>
|
|
@@ -898,7 +905,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
const postNodes = nodes.filter(n => n.source === "帖子");
|
|
const postNodes = nodes.filter(n => n.source === "帖子");
|
|
|
const personaNodes = nodes.filter(n => n.source === "人设" && !n.是否扩展);
|
|
const personaNodes = nodes.filter(n => n.source === "人设" && !n.是否扩展);
|
|
|
const expandedNodes = nodes.filter(n => n.source === "人设" && n.是否扩展);
|
|
const expandedNodes = nodes.filter(n => n.source === "人设" && n.是否扩展);
|
|
|
- const matchLinks = links.filter(l => l.type === "匹配");
|
|
|
|
|
|
|
+ const matchLinks = links.filter(l => l.type.startsWith("匹配_"));
|
|
|
|
|
|
|
|
// 更新匹配列表(按分数降序)
|
|
// 更新匹配列表(按分数降序)
|
|
|
updateMatchList(matchLinks, nodes);
|
|
updateMatchList(matchLinks, nodes);
|
|
@@ -1346,14 +1353,14 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
.force("link", d3.forceLink(links).id(d => d.id)
|
|
.force("link", d3.forceLink(links).id(d => d.id)
|
|
|
.distance(d => {{
|
|
.distance(d => {{
|
|
|
// 跨层连线距离
|
|
// 跨层连线距离
|
|
|
- if (d.type === "匹配" || d.type === "属于") {{
|
|
|
|
|
|
|
+ if (d.type.startsWith("匹配_") || d.type === "属于") {{
|
|
|
return 150; // 跨层边
|
|
return 150; // 跨层边
|
|
|
}}
|
|
}}
|
|
|
return 60; // 同层边
|
|
return 60; // 同层边
|
|
|
}})
|
|
}})
|
|
|
.strength(d => {{
|
|
.strength(d => {{
|
|
|
// 跨层边力度弱一些,不要拉扯节点出层
|
|
// 跨层边力度弱一些,不要拉扯节点出层
|
|
|
- if (d.type === "匹配" || d.type === "属于") {{
|
|
|
|
|
|
|
+ if (d.type.startsWith("匹配_") || d.type === "属于") {{
|
|
|
return 0.03;
|
|
return 0.03;
|
|
|
}}
|
|
}}
|
|
|
return 0.1;
|
|
return 0.1;
|
|
@@ -1373,7 +1380,8 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
|
|
|
|
|
// 边类型到CSS类的映射
|
|
// 边类型到CSS类的映射
|
|
|
const edgeTypeClass = {{
|
|
const edgeTypeClass = {{
|
|
|
- "匹配": "match",
|
|
|
|
|
|
|
+ "匹配_相同": "match-same",
|
|
|
|
|
+ "匹配_相似": "match-similar",
|
|
|
"分类共现(跨点)": "category-cross",
|
|
"分类共现(跨点)": "category-cross",
|
|
|
"分类共现(点内)": "category-intra",
|
|
"分类共现(点内)": "category-intra",
|
|
|
"标签共现": "tag-cooccur",
|
|
"标签共现": "tag-cooccur",
|
|
@@ -1695,16 +1703,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
// 绘制可见的边
|
|
// 绘制可见的边
|
|
|
const link = linkG.append("line")
|
|
const link = linkG.append("line")
|
|
|
.attr("class", d => "link " + getEdgeClass(d.type))
|
|
.attr("class", d => "link " + getEdgeClass(d.type))
|
|
|
- .attr("stroke-width", d => d.type === "匹配" ? 2.5 : 1.5)
|
|
|
|
|
- .attr("stroke-dasharray", d => {{
|
|
|
|
|
- // 匹配边根据相似度设置虚实线
|
|
|
|
|
- if (d.type === "匹配" && d.边详情 && d.边详情.相似度 !== undefined) {{
|
|
|
|
|
- const score = d.边详情.相似度;
|
|
|
|
|
- if (score >= 0.8) return null; // >= 0.8 实线
|
|
|
|
|
- if (score >= 0.5) return "6,4"; // 0.5-0.8 虚线
|
|
|
|
|
- }}
|
|
|
|
|
- return null; // 默认实线
|
|
|
|
|
- }});
|
|
|
|
|
|
|
+ .attr("stroke-width", d => d.type.startsWith("匹配_") ? 2.5 : 1.5);
|
|
|
|
|
|
|
|
// 判断是否为跨层边(根据源和目标节点的层级)- 赋值给全局变量
|
|
// 判断是否为跨层边(根据源和目标节点的层级)- 赋值给全局变量
|
|
|
isCrossLayerEdge = function(d) {{
|
|
isCrossLayerEdge = function(d) {{
|
|
@@ -1716,7 +1715,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
|
|
|
|
|
// 设置跨层边的初始可见性(匹配边始终显示,其他跨层边默认隐藏)
|
|
// 设置跨层边的初始可见性(匹配边始终显示,其他跨层边默认隐藏)
|
|
|
linkG.each(function(d) {{
|
|
linkG.each(function(d) {{
|
|
|
- if (d.type === "匹配") {{
|
|
|
|
|
|
|
+ if (d.type.startsWith("匹配_")) {{
|
|
|
d3.select(this).style("display", "block"); // 匹配边始终显示
|
|
d3.select(this).style("display", "block"); // 匹配边始终显示
|
|
|
}} else if (isCrossLayerEdge(d) && !showCrossLayerEdges) {{
|
|
}} else if (isCrossLayerEdge(d) && !showCrossLayerEdges) {{
|
|
|
d3.select(this).style("display", "none");
|
|
d3.select(this).style("display", "none");
|
|
@@ -1724,7 +1723,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
}});
|
|
}});
|
|
|
|
|
|
|
|
// 为匹配边添加分数标签
|
|
// 为匹配边添加分数标签
|
|
|
- const edgeLabels = linkG.filter(d => d.type === "匹配" && d.边详情 && d.边详情.相似度)
|
|
|
|
|
|
|
+ const edgeLabels = linkG.filter(d => d.type.startsWith("匹配_") && d.边详情 && d.边详情.相似度)
|
|
|
.append("g")
|
|
.append("g")
|
|
|
.attr("class", "edge-label-group");
|
|
.attr("class", "edge-label-group");
|
|
|
|
|
|
|
@@ -1763,7 +1762,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
.on("mouseout", function(event, d) {{
|
|
.on("mouseout", function(event, d) {{
|
|
|
d3.select(this.parentNode).select(".link")
|
|
d3.select(this.parentNode).select(".link")
|
|
|
.attr("stroke-opacity", 0.7)
|
|
.attr("stroke-opacity", 0.7)
|
|
|
- .attr("stroke-width", d.type === "匹配" ? 2.5 : 1.5);
|
|
|
|
|
|
|
+ .attr("stroke-width", d.type.startsWith("匹配_") ? 2.5 : 1.5);
|
|
|
}});
|
|
}});
|
|
|
|
|
|
|
|
// 绘制节点
|
|
// 绘制节点
|
|
@@ -2025,7 +2024,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
const lTgt = typeof link.target === "object" ? link.target.id : link.target;
|
|
const lTgt = typeof link.target === "object" ? link.target.id : link.target;
|
|
|
|
|
|
|
|
// 帖子->标签 的匹配边
|
|
// 帖子->标签 的匹配边
|
|
|
- if (link.type === "匹配") {{
|
|
|
|
|
|
|
+ if (link.type.startsWith("匹配_")) {{
|
|
|
if ((lSrc === sourceId && lTgt === detail.标签节点1) ||
|
|
if ((lSrc === sourceId && lTgt === detail.标签节点1) ||
|
|
|
(lSrc === targetId && lTgt === detail.标签节点2)) {{
|
|
(lSrc === targetId && lTgt === detail.标签节点2)) {{
|
|
|
highlightLinkIndices.add(i);
|
|
highlightLinkIndices.add(i);
|
|
@@ -2057,7 +2056,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
|
|
|
const lTgt = typeof link.target === "object" ? link.target.id : link.target;
|
|
const lTgt = typeof link.target === "object" ? link.target.id : link.target;
|
|
|
|
|
|
|
|
// 匹配边
|
|
// 匹配边
|
|
|
- if (link.type === "匹配") {{
|
|
|
|
|
|
|
+ if (link.type.startsWith("匹配_")) {{
|
|
|
if ((lSrc === sourceId && lTgt === detail.源人设节点) ||
|
|
if ((lSrc === sourceId && lTgt === detail.源人设节点) ||
|
|
|
(lSrc === targetId && lTgt === detail.目标人设节点)) {{
|
|
(lSrc === targetId && lTgt === detail.目标人设节点)) {{
|
|
|
highlightLinkIndices.add(i);
|
|
highlightLinkIndices.add(i);
|