Files
dsProject/dsLightRag/static/mind_map.html

347 lines
18 KiB
HTML
Raw Normal View History

2025-08-14 15:45:08 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>初中数学典型题思维导图</title>
<!-- 引入jsmind资源 -->
<link rel="stylesheet" type="text/css" href="./jsmind/jsmind.css" />
<script type="text/javascript" src="./jsmind/jsmind.js"></script>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
display: flex;
flex-direction: column;
background-color: #f5f5f5;
}
.controls {
margin: 10px;
padding: 10px;
background-color: #e9ecef;
border-radius: 4px;
}
#mindmap-container {
flex: 1;
width: 100%;
overflow: hidden;
}
button { margin-right: 10px; padding: 6px 12px; cursor: pointer; }
#status { margin-left: 10px; color: #666; }
/* 增强的强制右对齐样式 */
.jm-mindmap-container { justify-content: flex-end !important; }
.jm-node-container { flex-direction: row-reverse !important; }
.jm-node-wrap { float: right !important; }
.jm-line-container { justify-content: flex-end !important; }
.jm-right { display: flex !important; }
.jm-left { display: none !important; }
/* 根节点子节点强制右对齐终极方案 */
.jm-root > .jm-node-container > .jm-node-wrap {
float: right !important;
clear: right !important;
position: relative !important;
left: auto !important;
right: 0 !important;
}
/* 修改连接线起点位置 */
.jm-root > .jm-node-container > .jm-line-container {
justify-content: flex-end !important;
padding-left: 0 !important;
padding-right: 20px !important;
}
/* 掌握状态复选框样式 */
.mastery-checkbox { display: none; }
.mastery-checkbox + .mastery-icon { margin-right: 8px; cursor: pointer; }
.mastery-checkbox:not(:checked) + .mastery-icon::before { content: '❌'; color: #ff4d4f; }
.mastery-checkbox:checked + .mastery-icon::before { content: '✅'; color: #52c41a; }
</style>
</head>
<body>
<div class="controls">
<button onclick="addNode()">添加节点</button>
<button onclick="deleteNode()">删除节点</button>
<button onclick="saveMindMap()">保存数据</button>
<button onclick="resetMindMap()">重置画布</button>
<span id="status"></span>
</div>
<div id="mindmap-container"></div>
<script>
// 思维导图初始化配置
const mindMapOptions = {
container: 'mindmap-container',
theme: 'primary',
editable: true,
default_direction: 'right',
mode: 'full',
support_html: true // 添加HTML支持
};
// 初中数学典型题与解题思路数据
// 将军饮马问题及变形数据
const initialData = {
"meta": { "name": "将军饮马问题及变形解题思路", "author": "jsmind" },
"format": "node_tree",
"data": {
"id": "root",
"topic": "<a href='https://mp.weixin.qq.com/s?__biz=MzI1NjYzNjE1NQ==&mid=2247540913&idx=2&sn=7a061ec4c7dbbcc94b8bf2fa7d93f4c9&chksm=ea21c525dd564c33b578037e893e5190b92841f3db0837191864591bb3da0e10d8af7ce5da10&scene=27' target='_blank'>将军饮马问题及变形</a>",
"direction": "right",
"children": [
{
"id": "basic_model",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='basic_model'> <span class='mastery-icon'></span> 【类型一】 两定一动基本型",
"direction": "right",
"children": [
{ "id": "basic_feature", "topic": "特点两定点A、B位于直线l同侧在l上找一点P使PA+PB最短", "direction": "right" },
{ "id": "basic_solution", "topic": "解题思路作A关于直线l的对称点A'连接A'B交l于点PP即为所求", "direction": "right" },
{ "id": "basic_case", "topic": "典型案例牧马人从A地出发到河边饮水后到B地怎样走路径最短", "direction": "right" }
]
},
{
"id": "two_points_one_line",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='two_points_one_line'> <span class='mastery-icon'></span> 【类型二】 两次对称型",
"direction": "right",
"children": [
{ "id": "two_points_feature", "topic": "特点定点A、B位于平面内有两条相交直线l、m在l、m上分别找点P、Q使AP+PQ+QB最短", "direction": "right" },
{ "id": "two_points_solution", "topic": "解题思路分别作A关于l的对称点A'B关于m的对称点B'连接A'B'交l于P交m于Q", "direction": "right" },
{ "id": "two_points_case", "topic": "典型案例:台球两次反弹后撞击目标球,求反弹路径", "direction": "right" }
]
},
{
"id": "polygon_model",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='polygon_model'> <span class='mastery-icon'></span> 【类型三】 平移型",
"direction": "right",
"children": [
{ "id": "polygon_feature", "topic": "特点:在多边形边上找一点或多点,使路径之和最短", "direction": "right" },
{ "id": "polygon_solution", "topic": "解题思路:利用多边形对称性,通过多次作对称点转化为直线距离问题", "direction": "right" },
{ "id": "polygon_case", "topic": "典型案例矩形ABCD中E为AB上一点在BC、CD上分别找点P、Q使EP+PQ+QA最短", "direction": "right" }
]
},
{
"id": "angle_model",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='angle_model'> <span class='mastery-icon'></span> 【类型四】 点到直线垂线段最短",
"direction": "right",
"children": [
{ "id": "angle_feature", "topic": "特点定点A在∠MON内部在OM、ON上分别找点B、C使△ABC周长最短", "direction": "right" },
{ "id": "angle_solution", "topic": "解题思路分别作A关于OM、ON的对称点A'、A''连接A'A''交OM于B交ON于C", "direction": "right" },
{ "id": "angle_case", "topic": "典型案例:锐角三角形内一点到三边距离之和最短问题", "direction": "right" }
]
}
,
{
"id": "angle_model5",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='angle_model'> <span class='mastery-icon'></span> 【类型五】 三动点“将军饮马”问题",
"direction": "right",
"children": [
{ "id": "angle_feature", "topic": "特点定点A在∠MON内部在OM、ON上分别找点B、C使△ABC周长最短", "direction": "right" },
{ "id": "angle_solution", "topic": "解题思路分别作A关于OM、ON的对称点A'、A''连接A'A''交OM于B交ON于C", "direction": "right" },
{ "id": "angle_case", "topic": "典型案例:锐角三角形内一点到三边距离之和最短问题", "direction": "right" }
]
}
,
{
"id": "angle_model6",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='angle_model'> <span class='mastery-icon'></span> 【类型六】 相对运动思想的运用",
"direction": "right",
"children": [
{ "id": "angle_feature", "topic": "特点定点A在∠MON内部在OM、ON上分别找点B、C使△ABC周长最短", "direction": "right" },
{ "id": "angle_solution", "topic": "解题思路分别作A关于OM、ON的对称点A'、A''连接A'A''交OM于B交ON于C", "direction": "right" },
{ "id": "angle_case", "topic": "典型案例:锐角三角形内一点到三边距离之和最短问题", "direction": "right" }
]
}
,
{
"id": "angle_model7",
"topic": "<input type='checkbox' class='mastery-checkbox' data-id='angle_model'> <span class='mastery-icon'></span> 【类型七】 先找“河”,再“饮马”",
"direction": "right",
"children": [
{ "id": "angle_feature", "topic": "特点定点A在∠MON内部在OM、ON上分别找点B、C使△ABC周长最短", "direction": "right" },
{ "id": "angle_solution", "topic": "解题思路分别作A关于OM、ON的对称点A'、A''连接A'A''交OM于B交ON于C", "direction": "right" },
{ "id": "angle_case", "topic": "典型案例:锐角三角形内一点到三边距离之和最短问题", "direction": "right" }
]
}
]
}
};
// 创建思维导图实例
const jm = new jsMind(mindMapOptions);
// 初始化函数
function init() {
// 彻底清除所有可能相关的本地存储数据
localStorage.removeItem('mindMapData');
localStorage.removeItem('savedMindMap');
localStorage.removeItem('jsmind_state');
// 尝试从本地存储加载数据
const savedData = localStorage.getItem('mindMapData');
if (savedData) {
try {
const data = JSON.parse(savedData);
jm.show(data);
updateStatus('已加载保存的数据');
return;
} catch (e) {
updateStatus('加载保存数据失败,使用初始数据');
}
}
// 使用初始数据
jm.show(initialData);
}
// 状态更新函数
function updateStatus(message) {
const statusElement = document.getElementById('status');
if (statusElement) {
statusElement.textContent = message;
setTimeout(() => { statusElement.textContent = ''; }, 3000);
}
}
// 保存思维导图数据到本地存储
function saveMindMapData() {
const mindData = jm.get_data();
localStorage.setItem('mindMapData', JSON.stringify(mindData));
}
// 添加节点功能
function addNode() {
const selectedNode = jm.get_selected_node();
if (!selectedNode) {
updateStatus('请先选择一个节点');
return;
}
const newNodeId = Date.now().toString();
const newNodeText = prompt('请输入新节点内容:', '新节点');
if (!newNodeText) return;
// 关键修复使用jsmind原生支持的side参数移除direction和position
jm.add_node(selectedNode, newNodeId, newNodeText, {
side: 'right' // 这是jsmind库控制节点位置的原生参数
});
saveMindMapData();
updateStatus('节点添加成功');
}
// 删除节点功能
function deleteNode() {
const selectedNode = jm.get_selected_node();
if (!selectedNode || selectedNode.isroot) {
updateStatus('不能删除根节点');
return;
}
jm.remove_node(selectedNode.id);
saveMindMapData();
updateStatus('节点已删除');
}
// 保存思维导图
function saveMindMap() {
saveMindMapData();
updateStatus('思维导图已保存到本地存储');
}
// 重置思维导图
function resetMindMap() {
if (confirm('确定要重置思维导图吗?当前数据将丢失')) {
localStorage.removeItem('mindMapData');
jm.show(initialData);
updateStatus('思维导图已重置');
}
}
// 页面加载完成后初始化
window.onload = function() {
init();
// Fixed: Use reliable timeout instead of unsupported event listener
setTimeout(initMasteryCheckboxes, 50);
};
// 初始化掌握状态复选框
function initMasteryCheckboxes() {
// 从本地存储加载掌握状态
const masteryStates = JSON.parse(localStorage.getItem('masteryStates') || '{}');
// 添加重试机制确保节点加载完成
const initializeNodes = () => {
let nodesInitialized = 0;
const totalNodes = Object.keys(masteryStates).length;
Object.keys(masteryStates).forEach(id => {
const checkbox = document.querySelector(`.mastery-checkbox[data-id='${id}']`);
if (checkbox) {
checkbox.checked = masteryStates[id];
// 重试获取节点直到成功或超时
let attempts = 0;
const maxAttempts = 5;
const tryGetNode = () => {
const node = jm.get_node(id);
if (node) {
nodesInitialized++;
if (checkbox.checked) {
jm.collapse_node(node);
// 确保子节点也被收起
if (node.children && node.children.length > 0) {
node.children.forEach(childId => {
const childNode = jm.get_node(childId);
if (childNode) jm.collapse_node(childNode);
});
}
} else {
jm.expand_node(node);
}
} else if (attempts < maxAttempts) {
attempts++;
setTimeout(tryGetNode, 200); // 200ms后重试
}
};
tryGetNode();
}
});
};
initializeNodes();
// 为所有复选框添加事件监听
document.addEventListener('click', function(e) {
if (e.target.classList.contains('mastery-icon')) {
const checkbox = e.target.previousElementSibling;
if (checkbox && checkbox.classList.contains('mastery-checkbox')) {
checkbox.checked = !checkbox.checked;
saveMasteryState(checkbox.dataset.id, checkbox.checked);
const node = jm.get_node(checkbox.dataset.id);
if (node) {
if (checkbox.checked) {
jm.collapse_node(node);
// 收起所有子节点
if (node.children && node.children.length > 0) {
node.children.forEach(childId => {
const childNode = jm.get_node(childId);
if (childNode) jm.collapse_node(childNode);
});
}
} else {
jm.expand_node(node);
}
}
}
}
});
}
// 保存掌握状态到本地存储
function saveMasteryState(modelId, isMastered) {
const masteryStates = JSON.parse(localStorage.getItem('masteryStates') || '{}');
masteryStates[modelId] = isMastered;
localStorage.setItem('masteryStates', JSON.stringify(masteryStates));
}
</script>
</body>
</html>