main
HuangHai 7 days ago
parent 29e5ed8b09
commit 086a8e627d

@ -6,7 +6,7 @@
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="GOOGLE" />
<option name="myDocStringFormat" value="Google" />
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

@ -210,22 +210,32 @@
<div class="example-item" onclick="fillExample('总结一下各年代的名将')">
总结一下各年代的名将
</div>
<div class="example-item" onclick="fillExample('项羽犯了哪些重要错误?')">
<div class="example-item" onclick="fillExample('项羽犯了哪些重要错误?')">
项羽犯了哪些重要错误?
</div>
<div class="example-item" onclick="fillExample('刘邦最终成功是因为什么?')">
<div class="example-item" onclick="fillExample('刘邦最终成功是因为什么?')">
刘邦最终成功是因为什么?
</div>
<div class="example-item" onclick="fillExample('什么是龙相?')">
什么是龙相?
</div>
</div>
</div>
<div class="example-category">
<h3>生成关系图谱示例【成品演示】</h3>
<div class="example-list">
<a href="./temp/relation_1d104eb9f61a41ebbc1935e4944d9fb5.html">刘帮集团的人物关系图</a>
<a href="./temp/relation_c364556b55a64aa68279eea99db3392f.html">秦汉时期主要的人物关系图</a>
</div>
</div>
<div class="example-category">
<h3>生成关系图谱示例</h3>
<h3>生成关系图谱示例【即时生成】</h3>
<div class="example-list">
<button id="relationBtn1" onclick="generateRelation('生成刘帮集团的人物关系图')"
style="background-color:#9c27b0">
<span class="icon">👥</span>生成刘帮集团的人物关系图
</button>
<button id="relationBtn2" onclick="generateRelation('生成秦汉时期主要的人物关系图')"
<button id="relationBtn2" onclick="generateRelation('生成秦汉时期主要的人物关系图')"
style="background-color:#9c27b0">
<span class="icon">👥</span>生成秦汉时期主要的人物关系图
</button>

@ -0,0 +1,374 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>秦汉时期人物关系图谱</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
background: linear-gradient(135deg, #0a1a3a, #1a3a6a);
font-family: "Microsoft YaHei", sans-serif;
color: white;
}
#title {
position: absolute;
top: 20px;
width: 100%;
text-align: center;
font-size: 36px;
font-weight: bold;
background: linear-gradient(90deg, #ff8a00, #e52e71);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 10px rgba(255,255,255,0.3);
z-index: 10;
}
#graph-container {
position: absolute;
width: 70%;
height: 100%;
}
#info-panel {
position: absolute;
right: 0;
top: 0;
width: 30%;
height: 100%;
background: rgba(10, 26, 58, 0.8);
padding: 20px;
box-sizing: border-box;
overflow-y: auto;
border-left: 1px solid #2a4a7a;
}
#legend {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(10, 26, 58, 0.8);
padding: 10px;
border-radius: 5px;
border: 1px solid #2a4a7a;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
filter: drop-shadow(0 0 5px rgba(255,255,255,0.5));
}
.link {
stroke-opacity: 0.6;
}
.node text {
dominant-baseline: central;
text-anchor: middle;
fill: white;
font-size: 10px;
pointer-events: none;
}
.node.selected {
stroke: gold;
stroke-width: 3px;
filter: drop-shadow(0 0 10px gold);
}
#tooltip {
position: absolute;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 5px;
pointer-events: none;
font-size: 12px;
max-width: 200px;
display: none;
}
.layout-btn {
position: absolute;
top: 80px;
left: 20px;
padding: 8px 12px;
background: rgba(42, 74, 122, 0.7);
color: white;
border: 1px solid #4a8aff;
border-radius: 4px;
cursor: pointer;
z-index: 10;
}
.layout-btn:hover {
background: rgba(74, 138, 255, 0.7);
}
</style>
</head>
<body>
<div id="title">秦汉时期人物关系图谱</div>
<div id="graph-container"></div>
<div id="info-panel">
<h2 id="selected-node">选择节点查看详情</h2>
<div id="node-details"></div>
<h3>相关关系</h3>
<div id="node-relations"></div>
</div>
<div id="legend">
<div><span style="color: #ff7f0e;"></span> 政治关系</div>
<div><span style="color: #1f77b4;"></span> 军事关系</div>
<div><span style="color: #2ca02c;"></span> 个人关系</div>
</div>
<div id="tooltip"></div>
<button class="layout-btn" id="force-layout">力导向布局</button>
<button class="layout-btn" id="radial-layout" style="top: 120px;">辐射状布局</button>
<button class="layout-btn" id="circular-layout" style="top: 160px;">环形布局</button>
<button class="layout-btn" id="grid-layout" style="top: 200px;">网格布局</button>
<script>
// 数据定义
const graphData = {
"nodes": [
{"id": "刘邦", "type": "person", "desc": "汉高祖,汉朝开国皇帝", "rank": 5},
{"id": "秦始皇", "type": "person", "desc": "中国第一个皇帝,统一六国", "rank": 5},
{"id": "项羽", "type": "person", "desc": "西楚霸王,刘邦的主要对手", "rank": 4},
{"id": "张良", "type": "person", "desc": "汉初三杰之一,刘邦的重要谋士", "rank": 4},
{"id": "萧何", "type": "person", "desc": "汉初三杰之一,刘邦的丞相", "rank": 4},
{"id": "韩信", "type": "person", "desc": "汉初三杰之一,著名军事家", "rank": 4},
{"id": "吕后", "type": "person", "desc": "刘邦的皇后,汉朝第一位皇后", "rank": 3},
{"id": "李斯", "type": "person", "desc": "秦朝丞相,协助秦始皇统一六国", "rank": 3},
{"id": "蒙恬", "type": "person", "desc": "秦朝名将,修筑长城", "rank": 3},
{"id": "扶苏", "type": "person", "desc": "秦始皇长子,被胡亥害死", "rank": 2},
{"id": "胡亥", "type": "person", "desc": "秦二世,秦始皇幼子", "rank": 2},
{"id": "吕不韦", "type": "person", "desc": "秦朝丞相,传说为秦始皇生父", "rank": 2},
{"id": "陈胜", "type": "person", "desc": "秦末农民起义领袖", "rank": 2},
{"id": "吴广", "type": "person", "desc": "秦末农民起义领袖", "rank": 2},
{"id": "项梁", "type": "person", "desc": "项羽的叔父,反秦领袖", "rank": 2}
],
"links": [
{"source": "刘邦", "target": "秦始皇", "type": "political", "desc": "刘邦的命运与秦始皇关于天子气的预言相关联"},
{"source": "刘邦", "target": "项羽", "type": "military", "desc": "楚汉相争的主要对手"},
{"source": "刘邦", "target": "张良", "type": "personal", "desc": "君臣关系,张良为刘邦重要谋士"},
{"source": "刘邦", "target": "萧何", "type": "personal", "desc": "君臣关系,萧何为刘邦丞相"},
{"source": "刘邦", "target": "韩信", "type": "personal", "desc": "君臣关系,后猜忌韩信"},
{"source": "刘邦", "target": "吕后", "type": "personal", "desc": "夫妻关系"},
{"source": "秦始皇", "target": "李斯", "type": "political", "desc": "君臣关系,李斯为秦朝丞相"},
{"source": "秦始皇", "target": "蒙恬", "type": "military", "desc": "君臣关系,蒙恬为秦朝名将"},
{"source": "秦始皇", "target": "扶苏", "type": "personal", "desc": "父子关系"},
{"source": "秦始皇", "target": "胡亥", "type": "personal", "desc": "父子关系"},
{"source": "秦始皇", "target": "吕不韦", "type": "personal", "desc": "传说为父子关系"},
{"source": "项羽", "target": "项梁", "type": "personal", "desc": "叔侄关系"},
{"source": "项羽", "target": "刘邦", "type": "military", "desc": "楚汉相争的主要对手"},
{"source": "张良", "target": "秦始皇", "type": "political", "desc": "张良曾试图刺杀秦始皇"},
{"source": "陈胜", "target": "吴广", "type": "military", "desc": "共同领导农民起义"},
{"source": "陈胜", "target": "刘邦", "type": "political", "desc": "刘邦响应陈胜起义"}
]
};
// 颜色映射
const colorMap = {
"person": "#e6550d",
"organization": "#756bb1",
"event": "#9ecae1"
};
const linkColorMap = {
"political": "#ff7f0e",
"military": "#1f77b4",
"personal": "#2ca02c"
};
// 创建SVG画布
const width = document.getElementById('graph-container').clientWidth;
const height = window.innerHeight;
const svg = d3.select("#graph-container")
.append("svg")
.attr("width", width)
.attr("height", height);
// 创建力导向布局
const simulation = d3.forceSimulation(graphData.nodes)
.force("link", d3.forceLink(graphData.links).id(d => d.id).distance(100))
.force("charge", d3.forceManyBody().strength(-500))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(d => Math.sqrt(d.rank) * 10 + 10));
// 绘制连线
const link = svg.append("g")
.selectAll("line")
.data(graphData.links)
.enter().append("line")
.attr("class", "link")
.attr("stroke", d => linkColorMap[d.type])
.attr("stroke-width", 2);
// 创建节点组
const node = svg.append("g")
.selectAll("g")
.data(graphData.nodes)
.enter().append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", nodeClicked)
.on("mouseover", showTooltip)
.on("mouseout", hideTooltip);
// 添加3D效果节点
node.append("circle")
.attr("r", d => Math.sqrt(d.rank) * 10 + 10)
.attr("fill", d => colorMap[d.type])
.attr("class", "node");
// 添加节点文字
node.append("text")
.attr("dy", 4)
.text(d => d.id);
// 更新力导向布局
simulation.on("tick", () => {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node
.attr("transform", d => `translate(${d.x},${d.y})`);
});
// 拖拽函数
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
// 节点点击事件
function nodeClicked(event, d) {
// 移除之前选中的节点样式
d3.selectAll(".node").classed("selected", false);
// 添加当前选中节点样式
d3.select(event.currentTarget).select("circle").classed("selected", true);
// 更新右侧面板信息
document.getElementById("selected-node").textContent = d.id;
let detailsHtml = `
<p><strong>类型:</strong> ${d.type}</p>
<p><strong>描述:</strong> ${d.desc}</p>
<p><strong>重要性:</strong> ${d.rank}/5</p>
`;
document.getElementById("node-details").innerHTML = detailsHtml;
// 查找相关关系
let relationsHtml = "";
const relatedLinks = graphData.links.filter(link =>
link.source.id === d.id || link.target.id === d.id
);
relatedLinks.forEach(link => {
const otherNode = link.source.id === d.id ? link.target : link.source;
relationsHtml += `
<div class="relation-item">
<p><strong>与 ${otherNode} 的关系:</strong> ${link.desc}</p>
<p><small>关系类型: ${link.type}</small></p>
</div>
`;
});
document.getElementById("node-relations").innerHTML = relationsHtml || "<p>无相关关系</p>";
}
// 工具提示函数
function showTooltip(event, d) {
const tooltip = d3.select("#tooltip");
tooltip
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px")
.style("display", "block")
.html(`
<strong>${d.id}</strong><br/>
${d.desc}
`);
}
function hideTooltip() {
d3.select("#tooltip").style("display", "none");
}
// 布局切换功能
document.getElementById("force-layout").addEventListener("click", () => {
simulation.force("center", d3.forceCenter(width / 2, height / 2))
.force("charge", d3.forceManyBody().strength(-500))
.alpha(1).restart();
});
document.getElementById("radial-layout").addEventListener("click", () => {
const centerX = width / 2;
const centerY = height / 2;
const radius = Math.min(width, height) / 3;
graphData.nodes.forEach((node, i) => {
const angle = (i * 2 * Math.PI) / graphData.nodes.length;
node.fx = centerX + radius * Math.cos(angle);
node.fy = centerY + radius * Math.sin(angle);
});
simulation.alpha(1).restart();
});
document.getElementById("circular-layout").addEventListener("click", () => {
const centerX = width / 2;
const centerY = height / 2;
const radius = Math.min(width, height) / 3;
const rings = Math.ceil(Math.sqrt(graphData.nodes.length));
graphData.nodes.forEach((node, i) => {
const ring = Math.floor(i / (graphData.nodes.length / rings)) + 1;
const angle = (i * 2 * Math.PI) / (graphData.nodes.length / rings);
node.fx = centerX + (radius * ring / rings) * Math.cos(angle);
node.fy = centerY + (radius * ring / rings) * Math.sin(angle);
});
simulation.alpha(1).restart();
});
document.getElementById("grid-layout").addEventListener("click", () => {
const cols = Math.ceil(Math.sqrt(graphData.nodes.length));
const cellWidth = width / (cols + 1);
const cellHeight = height / (Math.ceil(graphData.nodes.length / cols) + 1);
graphData.nodes.forEach((node, i) => {
const row = Math.floor(i / cols);
const col = i % cols;
node.fx = (col + 1) * cellWidth;
node.fy = (row + 1) * cellHeight;
});
simulation.alpha(1).restart();
});
</script>
</body>
</html>
Loading…
Cancel
Save