347 lines
18 KiB
HTML
347 lines
18 KiB
HTML
<!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于点P,P即为所求", "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> |