// 全局元素索引(将由Python动态注入) // const elementIndex = {}; // 显示元素详情模态框 function showElementDetail(elementId) { const elem = elementIndex[elementId]; if (!elem) return; // 创建模态框 const modal = document.createElement('div'); modal.className = 'element-modal-backdrop'; modal.onclick = function(e) { if (e.target === modal) { document.body.removeChild(modal); } }; // 创建模态框内容 const modalContent = document.createElement('div'); modalContent.className = 'element-modal-content'; modalContent.onclick = function(e) { e.stopPropagation(); }; // 构建内容 let html = ''; html += ''; modalContent.innerHTML = html; modal.appendChild(modalContent); document.body.appendChild(modal); } // 跳转到元素详情(Tab3) function jumpToElement(elementId) { // 关闭模态框 const modal = document.querySelector('.element-modal-backdrop'); if (modal) { modal.remove(); } // 切换到Tab3 switchTab('tab3'); // 等待DOM更新后滚动到元素 setTimeout(function() { const elemItem = document.querySelector('[data-elem-id="' + elementId + '"]'); if (elemItem) { // 展开所有父级容器 let parent = elemItem.parentElement; while (parent) { if (parent.classList.contains('collapsed')) { parent.classList.remove('collapsed'); } parent = parent.parentElement; } // 滚动到元素并高亮 elemItem.scrollIntoView({ behavior: 'smooth', block: 'center' }); elemItem.classList.add('highlight-pulse'); setTimeout(function() { elemItem.classList.remove('highlight-pulse'); }, 2000); } }, 100); } // Tab切换功能 function switchTab(tabId) { // 隐藏所有tab内容 const allTabs = document.querySelectorAll('.tab-content'); allTabs.forEach(tab => { tab.style.display = 'none'; }); // 移除所有tab的active类 const allTabButtons = document.querySelectorAll('.tab'); allTabButtons.forEach(btn => { btn.classList.remove('active'); }); // 显示选中的tab内容 document.getElementById(tabId).style.display = 'block'; // 给选中的tab按钮添加active类 if (event && event.target) { event.target.classList.add('active'); } else { // 程序化切换时,手动添加active类 document.querySelectorAll('.tab').forEach((btn, idx) => { if ((tabId === 'tab1' && idx === 0) || (tabId === 'tab2' && idx === 1) || (tabId === 'tab3' && idx === 2) || (tabId === 'tab4' && idx === 3) || (tabId === 'tab5' && idx === 4)) { btn.classList.add('active'); } }); } // 如果切换到tab4,重新绘制连线 if (tabId === 'tab4') { setTimeout(() => { drawAllConnections(); }, 100); } // Tab5 不在切换时自动绘制连线,只在点击卡片时绘制 } // 展开/收起段落功能 function toggleCollapse(element) { const listItem = element.closest('.paragraph-item'); if (!listItem.classList.contains('collapsible')) { return; } listItem.classList.toggle('collapsed'); } // 展开/收起段落详细内容 function toggleDetails(element) { const detailsContainer = element.closest('.paragraph-item') .querySelector('.paragraph-details'); if (detailsContainer) { detailsContainer.classList.toggle('collapsed'); const toggleBtn = element.closest('.paragraph-header') .querySelector('.details-toggle-btn'); if (detailsContainer.classList.contains('collapsed')) { toggleBtn.innerHTML = ' 查看详细内容'; } else { toggleBtn.innerHTML = ' 隐藏详细内容'; } } } // Tab3: 展开/收起第一层级(实质/形式) function toggleLevel1(element) { element.classList.toggle('collapsed'); } // Tab3: 展开/收起第二层级(具体元素/具体概念/抽象概念) function toggleLevel2(element) { element.classList.toggle('collapsed'); } // Tab3: 展开/收起分类组 function toggleCategoryGroup(element) { const categoryGroup = element.closest('.category-group'); if (categoryGroup && categoryGroup.classList.contains('collapsible')) { categoryGroup.classList.toggle('collapsed'); } } // Tab3: 展开/收起二级分类组 function toggleSubcategoryGroup(element) { const subcategoryGroup = element.closest('.subcategory-group'); if (subcategoryGroup && subcategoryGroup.classList.contains('collapsible')) { subcategoryGroup.classList.toggle('collapsed'); } } // Tab3: 展开/收起元素详情 function toggleElementDetails(element) { const elementItem = element.closest('.element-item'); const detailsContainer = elementItem.querySelector('.element-details'); if (detailsContainer) { event.stopPropagation(); elementItem.classList.toggle('expanded'); detailsContainer.classList.toggle('collapsed'); } } // Tab3: 全部展开/收起所有层级 function toggleAllLevels(expand) { // 第一层级 const level1Headers = document.querySelectorAll('.level1-header'); level1Headers.forEach(header => { if (expand) { header.classList.remove('collapsed'); } else { header.classList.add('collapsed'); } }); // 第二层级 const level2Headers = document.querySelectorAll('.level2-header'); level2Headers.forEach(header => { if (expand) { header.classList.remove('collapsed'); } else { header.classList.add('collapsed'); } }); // 分类组 const categoryGroups = document.querySelectorAll('.category-group.collapsible'); categoryGroups.forEach(group => { if (expand) { group.classList.remove('collapsed'); } else { group.classList.add('collapsed'); } }); // 二级分类组 const subcategoryGroups = document.querySelectorAll('.subcategory-group.collapsible'); subcategoryGroups.forEach(group => { if (expand) { group.classList.remove('collapsed'); } else { group.classList.add('collapsed'); } }); } // 旧版本兼容:保持toggleAllCategories函数 function toggleAllCategories(expand) { toggleAllLevels(expand); } // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', function() { console.log('脚本结果可视化页面已加载'); // 初始化Tab4连线图 if (document.getElementById('tab4')) { initializeRelationshipGraph(); } }); // ===== Tab4 关系图功能 ===== // 初始化关系图 function initializeRelationshipGraph() { // 延迟执行以确保DOM完全加载 setTimeout(() => { // 初始状态:隐藏所有右侧节点 resetRelationshipView(); // 监听窗口大小变化,重新绘制连线 window.addEventListener('resize', debounce(() => { if (selectedSubstanceId && relationshipData[selectedSubstanceId]) { drawSelectedSubstanceConnections(selectedSubstanceId, relationshipData[selectedSubstanceId]); } }, 300)); }, 100); } // 绘制所有连线 function drawAllConnections() { if (typeof relationshipData === 'undefined') { return; } const svg = document.getElementById('relationship-svg'); if (!svg) return; // 清空现有连线 svg.innerHTML = ''; // 遍历所有实质点 Object.keys(relationshipData).forEach(substanceId => { const relations = relationshipData[substanceId]; // 绘制到灵感点的连线 relations.inspiration.forEach(rel => { // 兼容新结构(支撑)和旧结构(相似度分数) const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'inspiration', score); }); // 绘制到目的点的连线 relations.purpose.forEach(rel => { const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'purpose', score); }); // 绘制到关键点的连线 relations.keypoint.forEach(rel => { const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'keypoint', score); }); }); } // 绘制单条连线 function drawConnection(sourceId, targetId, type, score) { const svg = document.getElementById('relationship-svg'); if (!svg) return; const sourceNode = document.querySelector(`.substance-node[data-id="${sourceId}"]`); const targetNode = document.querySelector(`.target-node[data-id="${targetId}"]`); if (!sourceNode || !targetNode) return; // 获取节点位置 const sourceRect = sourceNode.getBoundingClientRect(); const targetRect = targetNode.getBoundingClientRect(); const containerRect = svg.parentElement.getBoundingClientRect(); // 计算相对于SVG容器的位置 const x1 = sourceRect.right - containerRect.left; const y1 = sourceRect.top + sourceRect.height / 2 - containerRect.top; const x2 = targetRect.left - containerRect.left; const y2 = targetRect.top + targetRect.height / 2 - containerRect.top; // 创建贝塞尔曲线路径 const midX = (x1 + x2) / 2; const path = `M ${x1} ${y1} Q ${midX} ${y1}, ${midX} ${(y1 + y2) / 2} T ${x2} ${y2}`; // 创建path元素 const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); pathElement.setAttribute('d', path); pathElement.setAttribute('class', `connection-line ${type}`); pathElement.setAttribute('fill', 'none'); pathElement.setAttribute('data-source', sourceId); pathElement.setAttribute('data-target', targetId); pathElement.setAttribute('data-type', type); pathElement.setAttribute('data-score', score); svg.appendChild(pathElement); } // 高亮相关关系 function highlightRelationships(substanceId) { if (typeof relationshipData === 'undefined') { return; } // 清除之前的高亮 clearHighlights(); // 高亮当前实质点 const substanceNode = document.querySelector(`.substance-node[data-id="${substanceId}"]`); if (substanceNode) { substanceNode.classList.add('highlighted'); } // 获取相关关系 const relations = relationshipData[substanceId]; if (!relations) return; // 高亮相关的目标点 [...relations.inspiration, ...relations.purpose, ...relations.keypoint].forEach(rel => { const targetNode = document.querySelector(`.target-node[data-id="${rel.target}"]`); if (targetNode) { targetNode.classList.add('highlighted'); } }); // 高亮相关的连线 const lines = document.querySelectorAll(`.connection-line[data-source="${substanceId}"]`); lines.forEach(line => { line.classList.add('highlighted'); }); } // 清除所有高亮 function clearHighlights() { // 清除节点高亮 document.querySelectorAll('.node.highlighted').forEach(node => { node.classList.remove('highlighted'); }); // 清除连线高亮 document.querySelectorAll('.connection-line.highlighted').forEach(line => { line.classList.remove('highlighted'); }); } // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // ===== Tab4 新增:点击选择实质点功能 ===== let selectedSubstanceId = null; // 选择实质点,展示关联关系 function selectSubstance(substanceId) { if (typeof relationshipData === 'undefined') { return; } // 如果点击已选中的实质点,不做处理 if (selectedSubstanceId === substanceId) { return; } selectedSubstanceId = substanceId; // 显示重置按钮 const resetBtn = document.querySelector('.reset-btn'); if (resetBtn) { resetBtn.style.display = 'block'; } // 获取关系数据 const relations = relationshipData[substanceId]; if (!relations) return; // 收集所有关联的节点ID const relatedNodeIds = new Set(); // 添加灵感点 relations.inspiration.forEach(rel => { relatedNodeIds.add(rel.target); }); // 添加目的点 relations.purpose.forEach(rel => { relatedNodeIds.add(rel.target); }); // 添加关键点 relations.keypoint.forEach(rel => { relatedNodeIds.add(rel.target); }); // 添加关联的实质点 relations.substance.forEach(rel => { relatedNodeIds.add(rel.target); }); // 高亮左侧选中的实质点 document.querySelectorAll('.substance-node').forEach(node => { if (node.getAttribute('data-id') === substanceId) { node.classList.add('selected'); node.classList.remove('dimmed'); } else { node.classList.remove('selected'); node.classList.add('dimmed'); } }); // 右侧节点:只显示关联的节点 document.querySelectorAll('.target-node').forEach(node => { const nodeId = node.getAttribute('data-id'); if (relatedNodeIds.has(nodeId)) { node.classList.add('visible'); node.classList.remove('hidden'); } else { node.classList.remove('visible'); node.classList.add('hidden'); } }); // 根据右侧节点的可见性,控制section的显示 document.querySelectorAll('.target-section').forEach(section => { const visibleNodes = section.querySelectorAll('.target-node.visible'); if (visibleNodes.length > 0) { section.classList.add('has-visible-nodes'); section.classList.remove('all-hidden'); } else { section.classList.remove('has-visible-nodes'); section.classList.add('all-hidden'); } }); // 重新绘制连线(只绘制选中实质点的连线) drawSelectedSubstanceConnections(substanceId, relations); } // 重置视图 function resetRelationshipView() { selectedSubstanceId = null; // 隐藏重置按钮 const resetBtn = document.querySelector('.reset-btn'); if (resetBtn) { resetBtn.style.display = 'none'; } // 左侧实质点:移除所有高亮和变暗 document.querySelectorAll('.substance-node').forEach(node => { node.classList.remove('selected', 'dimmed'); }); // 右侧节点:隐藏所有节点 document.querySelectorAll('.target-node').forEach(node => { node.classList.remove('visible'); node.classList.add('hidden'); }); // 隐藏所有section document.querySelectorAll('.target-section').forEach(section => { section.classList.remove('has-visible-nodes'); section.classList.add('all-hidden'); }); // 清空连线 const svg = document.getElementById('relationship-svg'); if (svg) { svg.innerHTML = ''; } } // 绘制选中实质点的连线 function drawSelectedSubstanceConnections(substanceId, relations) { const svg = document.getElementById('relationship-svg'); if (!svg) return; // 清空现有连线 svg.innerHTML = ''; // 绘制到灵感点的连线 relations.inspiration.forEach(rel => { // 兼容新结构(支撑)和旧结构(相似度分数) const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'inspiration', score); }); // 绘制到目的点的连线 relations.purpose.forEach(rel => { const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'purpose', score); }); // 绘制到关键点的连线 relations.keypoint.forEach(rel => { const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawConnection(substanceId, rel.target, 'keypoint', score); }); // 绘制到其他实质点的连线 relations.substance.forEach(rel => { drawConnection(substanceId, rel.target, 'substance', rel.common_count / 10); }); } // ===== Tab4 新版支撑关系图功能 ===== let selectedSupportSubstanceId = null; let selectedSupportTargetId = null; // 选择实质点(新版) function selectSubstance(substanceId) { if (typeof supportRelationships === 'undefined') { console.error('supportRelationships not defined'); return; } // 如果点击已选中的实质点,不做处理 if (selectedSupportSubstanceId === substanceId) { return; } selectedSupportSubstanceId = substanceId; selectedSupportTargetId = null; // 清空画布 clearSupportCanvas(); // 获取关系数据 const relations = supportRelationships.substance_to_target[substanceId]; if (!relations) { console.error('No relations found for substance:', substanceId); return; } // 高亮选中的实质点,其他变暗 document.querySelectorAll('.substance-card').forEach(card => { if (card.getAttribute('data-id') === substanceId) { card.classList.add('selected'); card.classList.remove('dimmed'); } else { card.classList.remove('selected'); card.classList.add('dimmed'); } }); // 清除所有目标点的状态 document.querySelectorAll('.target-card').forEach(card => { card.classList.remove('selected', 'dimmed', 'highlighted'); }); // 根据关系数据高亮相关的目标点 const relatedTargets = new Set(); relations.inspiration.forEach(rel => { relatedTargets.add(rel.target_id); }); relations.purpose.forEach(rel => { relatedTargets.add(rel.target_id); }); relations.keypoint.forEach(rel => { relatedTargets.add(rel.target_id); }); // 高亮相关的目标点,其他变暗 document.querySelectorAll('.target-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (relatedTargets.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed'); } else { card.classList.add('dimmed'); card.classList.remove('highlighted'); } }); // 绘制支撑关系(使用Sankey风格或树状结构) drawSupportRelationships(substanceId, relations); } // 选择目标点(反向查看) function selectTarget(targetType, targetIndex) { if (typeof supportRelationships === 'undefined') { console.error('supportRelationships not defined'); return; } const targetId = `${targetType}-${targetIndex}`; // 如果点击已选中的目标点,不做处理 if (selectedSupportTargetId === targetId) { return; } selectedSupportSubstanceId = null; selectedSupportTargetId = targetId; // 清空画布 clearSupportCanvas(); // 获取反向关系数据 const relations = supportRelationships.target_to_substance[targetId]; if (!relations) { console.error('No relations found for target:', targetId); return; } // 清除所有实质点的状态 document.querySelectorAll('.substance-card').forEach(card => { card.classList.remove('selected', 'dimmed', 'highlighted'); }); // 高亮选中的目标点,其他变暗 document.querySelectorAll('.target-card').forEach(card => { if (card.getAttribute('data-id') === targetId) { card.classList.add('selected'); card.classList.remove('dimmed'); } else { card.classList.remove('selected'); card.classList.add('dimmed'); } }); // 收集所有支撑该目标点的实质点ID const supportingSubstances = new Set(); relations.concrete_elements.forEach(item => supportingSubstances.add(item.substance_id)); relations.concrete_concepts.forEach(item => supportingSubstances.add(item.substance_id)); relations.abstract_concepts.forEach(item => supportingSubstances.add(item.substance_id)); // 高亮支撑的实质点,其他变暗 document.querySelectorAll('.substance-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (supportingSubstances.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed'); } else { card.classList.add('dimmed'); card.classList.remove('highlighted'); } }); // 绘制反向支撑关系 drawReverseSupportRelationships(targetId, relations); } // 绘制支撑关系(实质点 → 目标点) function drawSupportRelationships(substanceId, relations) { const canvas = document.getElementById('support-canvas'); if (!canvas) return; // 清空并移除占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'none'; } // 创建可视化内容 let html = '
\n'; html += '
支撑关系
\n'; // 显示来源实质点 const substanceData = supportRelationships.substance_to_target[substanceId]; html += '
\n'; html += '
\n'; html += `
${substanceData.type || '实质点'}
\n`; html += `
${substanceData.name || substanceId}
\n`; html += '
\n'; html += '
\n'; // 显示支撑的目标点(分类) html += '
\n'; if (relations.inspiration && relations.inspiration.length > 0) { html += '
\n'; html += '
灵感点
\n'; relations.inspiration.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } if (relations.purpose && relations.purpose.length > 0) { html += '
\n'; html += '
目的点
\n'; relations.purpose.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } if (relations.keypoint && relations.keypoint.length > 0) { html += '
\n'; html += '
关键点
\n'; relations.keypoint.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } html += '
\n'; html += '
\n'; // 插入到画布 canvas.insertAdjacentHTML('beforeend', html); } // 绘制反向支撑关系(目标点 ← 实质点) function drawReverseSupportRelationships(targetId, relations) { const canvas = document.getElementById('support-canvas'); if (!canvas) return; // 清空并移除占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'none'; } // 创建可视化内容 let html = '
\n'; html += '
被以下实质点支撑
\n'; // 显示目标点 html += '
\n'; html += '
\n'; html += `
目标点
\n`; html += `
${targetId}
\n`; html += '
\n'; html += '
\n'; // 显示支撑的实质点(分类) html += '
\n'; if (relations.concrete_elements && relations.concrete_elements.length > 0) { html += '
\n'; html += '
具体元素
\n'; relations.concrete_elements.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } if (relations.concrete_concepts && relations.concrete_concepts.length > 0) { html += '
\n'; html += '
具体概念
\n'; relations.concrete_concepts.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } if (relations.abstract_concepts && relations.abstract_concepts.length > 0) { html += '
\n'; html += '
抽象概念
\n'; relations.abstract_concepts.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } html += '
\n'; html += '
\n'; // 插入到画布 canvas.insertAdjacentHTML('beforeend', html); } // 清空支撑关系画布 function clearSupportCanvas() { const canvas = document.getElementById('support-canvas'); if (!canvas) return; // 移除所有flow相关元素 const flows = canvas.querySelectorAll('.support-flow'); flows.forEach(flow => flow.remove()); // 重新显示占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'flex'; } } // ===== Tab5 实质与形式双向支撑关系图功能 ===== let selectedLeftTargetType = null; // 左侧选题点类型:inspiration/keypoint/purpose let selectedLeftTargetIdx = null; // 左侧选题点索引 let selectedTab5SubstanceId = null; // 选中的实质点ID (Tab5专用) let selectedFormId = null; // 选中的形式点ID let selectedRightTargetType = null; // 右侧选题点类型:inspiration/keypoint/purpose let selectedRightTargetIdx = null; // 右侧选题点索引 // 选择左侧选题点(来自实质点支撑关系) function selectLeftTarget(targetType, targetIdx) { if (typeof tab5Relationships === 'undefined') { console.error('tab5Relationships not defined'); return; } // 如果点击已选中的目标点,重置显示所有元素 if (selectedLeftTargetType === targetType && selectedLeftTargetIdx === targetIdx) { resetTab5Selection(); return; } // 重置其他选择 resetTab5Selection(); selectedLeftTargetType = targetType; selectedLeftTargetIdx = targetIdx; // 高亮选中的目标点 document.querySelectorAll('.tab5-left-targets .target-card').forEach(card => { const dataType = card.getAttribute('data-type'); const dataId = card.getAttribute('data-id'); const fullId = `${targetType}-${targetIdx}`; if (dataId === fullId) { card.classList.add('selected'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('selected'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); // 形式点全部隐藏 document.querySelectorAll('.tab5-forms .form-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 右侧选题点全部隐藏 document.querySelectorAll('.tab5-right-targets .target-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 获取反向关系:哪些实质点支撑这个目标点(直接使用完整的targetIdx) const targetId = `${targetType}-${targetIdx}`; const supportingSubstances = tab5Relationships.target_from_substance[targetId]; if (supportingSubstances && supportingSubstances.length > 0) { // 高亮支撑的实质点 const substanceIds = new Set(supportingSubstances.map(s => s.substance_id)); document.querySelectorAll('.tab5-substances .substance-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (substanceIds.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('highlighted'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); } // 绘制连线(只连接当前显示的卡片) setTimeout(() => { drawFormAllConnections(); }, 50); } // 选择实质点 function selectSubstance(substanceId) { if (typeof tab5Relationships === 'undefined') { console.error('tab5Relationships not defined'); return; } // 如果点击已选中的实质点,重置显示所有元素 if (selectedTab5SubstanceId === substanceId) { resetTab5Selection(); return; } // 重置其他选择 resetTab5Selection(); selectedTab5SubstanceId = substanceId; // 高亮选中的实质点 document.querySelectorAll('.tab5-substances .substance-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (cardId === substanceId) { card.classList.add('selected'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('selected'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); // 形式点全部隐藏(先全部隐藏,后面再显示有关联的) document.querySelectorAll('.tab5-forms .form-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 右侧选题点全部隐藏 document.querySelectorAll('.tab5-right-targets .target-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 获取这个实质点支撑的选题点 const relations = tab5Relationships.substance_to_target[substanceId]; if (relations) { const leftTargets = new Set(); relations.inspiration.forEach(rel => leftTargets.add(rel.target_id)); relations.purpose.forEach(rel => leftTargets.add(rel.target_id)); relations.keypoint.forEach(rel => leftTargets.add(rel.target_id)); // 高亮左侧相关选题点 document.querySelectorAll('.tab5-left-targets .target-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (leftTargets.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('highlighted'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); } // 高亮支撑这个实质点的形式点(反向关系) const supportingForms = tab5Relationships.substance_from_form[substanceId]; if (supportingForms && supportingForms.length > 0) { const formIds = new Set(supportingForms.map(f => f.form_id)); document.querySelectorAll('.tab5-forms .form-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (formIds.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } // 注意:这里不对其他形式点再次隐藏,因为已经在前面全部隐藏了 }); } // 绘制连线(只连接当前显示的卡片) setTimeout(() => { drawFormAllConnections(); }, 50); } // 选择形式点 function selectForm(formId) { if (typeof tab5Relationships === 'undefined') { console.error('tab5Relationships not defined'); return; } // 如果点击已选中的形式点,重置显示所有元素 if (selectedFormId === formId) { resetTab5Selection(); return; } // 重置其他选择 resetTab5Selection(); selectedFormId = formId; // 高亮选中的形式点 document.querySelectorAll('.tab5-forms .form-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (cardId === formId) { card.classList.add('selected'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('selected'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); // 实质点全部隐藏(先全部隐藏,后面再显示有关联的) document.querySelectorAll('.tab5-substances .substance-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 左侧选题点全部隐藏 document.querySelectorAll('.tab5-left-targets .target-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 获取这个形式点支撑的选题点 const relations = tab5Relationships.form_to_target[formId]; if (relations) { const rightTargets = new Set(); relations.inspiration.forEach(rel => rightTargets.add(rel.target_id)); relations.purpose.forEach(rel => rightTargets.add(rel.target_id)); relations.keypoint.forEach(rel => rightTargets.add(rel.target_id)); // 高亮右侧相关选题点 document.querySelectorAll('.tab5-right-targets .target-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (rightTargets.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('highlighted'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); } // 高亮这个形式点支撑的实质点 const supportedSubstances = tab5Relationships.form_to_substance[formId]; if (supportedSubstances && supportedSubstances.length > 0) { const substanceIds = new Set(supportedSubstances.map(s => s.substance_id)); document.querySelectorAll('.tab5-substances .substance-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (substanceIds.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } // 注意:这里不对其他实质点再次隐藏,因为已经在前面全部隐藏了 }); } // 绘制连线(只连接当前显示的卡片) setTimeout(() => { drawFormAllConnections(); }, 50); } // 选择右侧选题点(来自形式点支撑关系) function selectRightTarget(targetType, targetIdx) { if (typeof tab5Relationships === 'undefined') { console.error('tab5Relationships not defined'); return; } // 如果点击已选中的目标点,重置显示所有元素 if (selectedRightTargetType === targetType && selectedRightTargetIdx === targetIdx) { resetTab5Selection(); return; } // 重置其他选择 resetTab5Selection(); selectedRightTargetType = targetType; selectedRightTargetIdx = targetIdx; // 高亮选中的目标点 document.querySelectorAll('.tab5-right-targets .target-card').forEach(card => { const dataType = card.getAttribute('data-type'); const dataId = card.getAttribute('data-id'); const fullId = `${targetType}-${targetIdx}`; if (dataId === fullId) { card.classList.add('selected'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('selected'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); // 实质点全部隐藏 document.querySelectorAll('.tab5-substances .substance-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 左侧选题点全部隐藏 document.querySelectorAll('.tab5-left-targets .target-card').forEach(card => { card.classList.add('hidden'); card.classList.remove('selected', 'highlighted', 'dimmed'); }); // 获取反向关系:哪些形式点支撑这个目标点(直接使用完整的targetIdx) const targetId = `${targetType}-${targetIdx}`; const supportingForms = tab5Relationships.target_from_form[targetId]; if (supportingForms && supportingForms.length > 0) { // 高亮支撑的形式点 const formIds = new Set(supportingForms.map(f => f.form_id)); document.querySelectorAll('.tab5-forms .form-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (formIds.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed', 'hidden'); } else { card.classList.remove('highlighted'); card.classList.add('hidden'); card.classList.remove('dimmed'); } }); } // 绘制连线(只连接当前显示的卡片) setTimeout(() => { drawFormAllConnections(); }, 50); } // 重置Tab5所有选择 function resetTab5Selection() { selectedLeftTargetType = null; selectedLeftTargetIdx = null; selectedSubstanceId = null; selectedFormId = null; selectedRightTargetType = null; selectedRightTargetIdx = null; // 清除所有高亮、选中和隐藏状态 document.querySelectorAll('#tab5 .target-card, #tab5 .substance-card, #tab5 .form-card').forEach(card => { card.classList.remove('selected', 'dimmed', 'highlighted', 'hidden'); }); // 清除所有连线 const svg = document.getElementById('tab5-connection-svg'); if (svg) { svg.innerHTML = ''; } } // 选择目标点(反向查看) function selectFormTarget(targetType, targetId) { if (typeof formSupportRelationships === 'undefined') { console.error('formSupportRelationships not defined'); return; } let fullTargetId; if (targetType === 'substance') { fullTargetId = `substance-${targetId}`; } else { fullTargetId = `${targetType}-${targetId}`; } // 如果点击已选中的目标点,不做处理 if (selectedFormTargetId === fullTargetId) { return; } selectedFormId = null; selectedFormTargetId = fullTargetId; // 清空画布 clearFormSupportCanvas(); // 获取反向关系数据 const relations = formSupportRelationships.target_to_form[fullTargetId]; if (!relations) { console.error('No relations found for target:', fullTargetId); return; } // 清除所有形式点的状态 document.querySelectorAll('.form-card').forEach(card => { card.classList.remove('selected', 'dimmed', 'highlighted'); }); // 高亮选中的目标点,其他变暗 document.querySelectorAll('#tab5 .target-card').forEach(card => { if (card.getAttribute('data-id') === fullTargetId) { card.classList.add('selected'); card.classList.remove('dimmed'); } else { card.classList.remove('selected'); card.classList.add('dimmed'); } }); // 收集所有支撑该目标点的形式点ID const supportingForms = new Set(); if (relations.concrete_element_forms) { relations.concrete_element_forms.forEach(item => supportingForms.add(item.form_id)); } if (relations.concrete_concept_forms) { relations.concrete_concept_forms.forEach(item => supportingForms.add(item.form_id)); } if (relations.overall_forms) { relations.overall_forms.forEach(item => supportingForms.add(item.form_id)); } if (relations.forms) { relations.forms.forEach(item => supportingForms.add(item.form_id)); } // 高亮支撑的形式点,其他变暗 document.querySelectorAll('.form-card').forEach(card => { const cardId = card.getAttribute('data-id'); if (supportingForms.has(cardId)) { card.classList.add('highlighted'); card.classList.remove('dimmed'); } else { card.classList.add('dimmed'); card.classList.remove('highlighted'); } }); // 绘制反向支撑关系 drawReverseFormSupportRelationships(fullTargetId, relations); } // 绘制形式点支撑关系(形式点 → 目标点) function drawFormSupportRelationships(formId, relations) { const canvas = document.getElementById('form-support-canvas'); if (!canvas) return; // 清空并移除占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'none'; } // 创建可视化内容 let html = '
\n'; html += '
支撑关系
\n'; // 显示来源形式点 html += '
\n'; html += '
\n'; html += `
${relations.type || '形式点'}
\n`; html += `
${relations.name || formId}
\n`; html += '
\n'; html += '
\n'; // 显示支撑的目标点(分类) html += '
\n'; if (relations.inspiration && relations.inspiration.length > 0) { html += '
\n'; html += '
灵感点
\n'; relations.inspiration.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } if (relations.purpose && relations.purpose.length > 0) { html += '
\n'; html += '
目的点
\n'; relations.purpose.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } if (relations.keypoint && relations.keypoint.length > 0) { html += '
\n'; html += '
关键点
\n'; relations.keypoint.forEach(rel => { html += `
\n`; html += `
${rel.point}
\n`; // 兼容新结构(支撑理由)和旧结构(相似度分数) if (rel.support_reason !== undefined) { html += `
支撑
\n`; } else if (rel.avg_score !== undefined) { const score = (rel.avg_score * 100).toFixed(0); html += `
相似度: ${score}%
\n`; } html += '
\n'; }); html += '
\n'; } if (relations.substance && relations.substance.length > 0) { html += '
\n'; html += '
实质点
\n'; relations.substance.forEach(rel => { const score = (rel.avg_score * 100).toFixed(0); let flowClass = ''; if (rel.type === '具体元素') { flowClass = 'concrete-element-flow'; } else if (rel.type === '具体概念') { flowClass = 'concrete-concept-flow'; } else if (rel.type === '抽象概念') { flowClass = 'abstract-concept-flow'; } html += `
\n`; html += `
${rel.name} (${rel.type})
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } html += '
\n'; html += '
\n'; // 插入到画布 canvas.insertAdjacentHTML('beforeend', html); } // 绘制反向形式点支撑关系(目标点 ← 形式点) function drawReverseFormSupportRelationships(targetId, relations) { const canvas = document.getElementById('form-support-canvas'); if (!canvas) return; // 清空并移除占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'none'; } // 创建可视化内容 let html = '
\n'; html += '
被以下形式点支撑
\n'; // 显示目标点 html += '
\n'; html += '
\n'; html += `
目标点
\n`; html += `
${targetId}
\n`; html += '
\n'; html += '
\n'; // 显示支撑的形式点(分类) html += '
\n'; if (relations.concrete_element_forms && relations.concrete_element_forms.length > 0) { html += '
\n'; html += '
具体元素形式
\n'; relations.concrete_element_forms.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } if (relations.concrete_concept_forms && relations.concrete_concept_forms.length > 0) { html += '
\n'; html += '
具体概念形式
\n'; relations.concrete_concept_forms.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } if (relations.overall_forms && relations.overall_forms.length > 0) { html += '
\n'; html += '
整体形式
\n'; relations.overall_forms.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name}
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } if (relations.forms && relations.forms.length > 0) { html += '
\n'; html += '
形式点
\n'; relations.forms.forEach(item => { const score = (item.score * 100).toFixed(0); html += `
\n`; html += `
${item.name} (${item.type})
\n`; html += `
相似度: ${score}%
\n`; html += '
\n'; }); html += '
\n'; } html += '
\n'; html += '
\n'; // 插入到画布 canvas.insertAdjacentHTML('beforeend', html); } // 清空形式点支撑关系画布 function clearFormSupportCanvas() { const canvas = document.getElementById('form-support-canvas'); if (!canvas) return; // 移除所有flow相关元素 const flows = canvas.querySelectorAll('.support-flow'); flows.forEach(flow => flow.remove()); // 重新显示占位文本 const placeholder = canvas.querySelector('.placeholder-text'); if (placeholder) { placeholder.style.display = 'flex'; } } // ===== Tab5 连线绘制功能 ===== // 绘制Tab5所有连线 function drawFormAllConnections() { if (typeof tab5Relationships === 'undefined') { console.log('tab5Relationships not defined, skipping connection drawing'); return; } const svg = document.getElementById('tab5-connection-svg'); if (!svg) { console.log('SVG container not found'); return; } // 清空现有连线 svg.innerHTML = ''; // 1. 绘制左侧选题点到实质点的连线(反向关系) drawLeftTargetToSubstanceConnections(svg); // 2. 绘制实质点到形式点的连线(支撑关系) drawSubstanceToFormConnections(svg); // 3. 绘制形式点到右侧选题点的连线 drawFormToRightTargetConnections(svg); } // 绘制左侧选题点到实质点的连线 function drawLeftTargetToSubstanceConnections(svg) { const targetFromSubstance = tab5Relationships.target_from_substance; Object.keys(targetFromSubstance).forEach(targetId => { const substances = targetFromSubstance[targetId]; substances.forEach(substanceData => { const sourceCard = document.querySelector(`.tab5-left-targets .target-card[data-id="${targetId}"]`); const targetCard = document.querySelector(`.tab5-substances .substance-card[data-id="${substanceData.substance_id}"]`); if (sourceCard && targetCard && !sourceCard.classList.contains('hidden') && !targetCard.classList.contains('hidden')) { drawTab5Connection( svg, sourceCard, targetCard, 'left-target-substance', targetId, substanceData.substance_id, { score: substanceData.score, substanceName: substanceData.name, type: substanceData.type } ); } }); }); } // 绘制实质点到形式点的连线 function drawSubstanceToFormConnections(svg) { const formToSubstance = tab5Relationships.form_to_substance; Object.keys(formToSubstance).forEach(formId => { const substances = formToSubstance[formId]; substances.forEach(substanceData => { const sourceCard = document.querySelector(`.tab5-substances .substance-card[data-id="${substanceData.substance_id}"]`); const targetCard = document.querySelector(`.tab5-forms .form-card[data-id="${formId}"]`); if (sourceCard && targetCard && !sourceCard.classList.contains('hidden') && !targetCard.classList.contains('hidden')) { drawTab5Connection( svg, sourceCard, targetCard, 'substance-form', substanceData.substance_id, formId, { substanceName: substanceData.name, formName: tab5Relationships.form_to_target[formId]?.name || '' } ); } }); }); } // 绘制形式点到右侧选题点的连线 function drawFormToRightTargetConnections(svg) { const formToTarget = tab5Relationships.form_to_target; Object.keys(formToTarget).forEach(formId => { const relations = formToTarget[formId]; // 绘制到灵感点的连线 relations.inspiration.forEach(rel => { const sourceCard = document.querySelector(`.tab5-forms .form-card[data-id="${formId}"]`); const targetCard = document.querySelector(`.tab5-right-targets .target-card[data-id="${rel.target_id}"]`); if (sourceCard && targetCard && !sourceCard.classList.contains('hidden') && !targetCard.classList.contains('hidden')) { // 兼容新结构(支撑)和旧结构(相似度分数) const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawTab5Connection( svg, sourceCard, targetCard, 'form-inspiration', formId, rel.target_id, { score: score, point: rel.point, formName: relations.name } ); } }); // 绘制到目的点的连线 relations.purpose.forEach(rel => { const sourceCard = document.querySelector(`.tab5-forms .form-card[data-id="${formId}"]`); const targetCard = document.querySelector(`.tab5-right-targets .target-card[data-id="${rel.target_id}"]`); if (sourceCard && targetCard && !sourceCard.classList.contains('hidden') && !targetCard.classList.contains('hidden')) { // 兼容新结构(支撑)和旧结构(相似度分数) const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawTab5Connection( svg, sourceCard, targetCard, 'form-purpose', formId, rel.target_id, { score: score, point: rel.point, formName: relations.name } ); } }); // 绘制到关键点的连线 relations.keypoint.forEach(rel => { const sourceCard = document.querySelector(`.tab5-forms .form-card[data-id="${formId}"]`); const targetCard = document.querySelector(`.tab5-right-targets .target-card[data-id="${rel.target_id}"]`); if (sourceCard && targetCard && !sourceCard.classList.contains('hidden') && !targetCard.classList.contains('hidden')) { // 兼容新结构(支撑)和旧结构(相似度分数) const score = rel.avg_score !== undefined ? rel.avg_score : (rel.support_reason !== undefined ? 1.0 : 0.5); drawTab5Connection( svg, sourceCard, targetCard, 'form-keypoint', formId, rel.target_id, { score: score, point: rel.point, formName: relations.name } ); } }); }); } // 绘制单条Tab5连线 function drawTab5Connection(svg, sourceCard, targetCard, connectionType, sourceId, targetId, metadata) { const svgContainer = svg.parentElement; const containerRect = svgContainer.getBoundingClientRect(); const sourceRect = sourceCard.getBoundingClientRect(); const targetRect = targetCard.getBoundingClientRect(); // 计算连线起点和终点 let x1, y1, x2, y2; if (connectionType === 'left-target-substance') { // 左侧选题点到实质点:从右边连到左边 x1 = sourceRect.right - containerRect.left; y1 = sourceRect.top + sourceRect.height / 2 - containerRect.top; x2 = targetRect.left - containerRect.left; y2 = targetRect.top + targetRect.height / 2 - containerRect.top; } else if (connectionType === 'substance-form') { // 实质点到形式点:从右边连到左边 x1 = sourceRect.right - containerRect.left; y1 = sourceRect.top + sourceRect.height / 2 - containerRect.top; x2 = targetRect.left - containerRect.left; y2 = targetRect.top + targetRect.height / 2 - containerRect.top; } else { // 形式点到右侧选题点:从右边连到左边 x1 = sourceRect.right - containerRect.left; y1 = sourceRect.top + sourceRect.height / 2 - containerRect.top; x2 = targetRect.left - containerRect.left; y2 = targetRect.top + targetRect.height / 2 - containerRect.top; } // 创建贝塞尔曲线路径 const midX = (x1 + x2) / 2; const path = `M ${x1} ${y1} Q ${midX} ${y1}, ${midX} ${(y1 + y2) / 2} T ${x2} ${y2}`; // 创建path元素 const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); pathElement.setAttribute('d', path); pathElement.setAttribute('class', `tab5-connection-line ${connectionType}`); pathElement.setAttribute('fill', 'none'); pathElement.setAttribute('stroke-width', '2'); pathElement.setAttribute('data-source-id', sourceId); pathElement.setAttribute('data-target-id', targetId); pathElement.setAttribute('data-connection-type', connectionType); // 保存元数据以供点击时使用 pathElement.setAttribute('data-metadata', JSON.stringify(metadata)); // 添加点击事件 pathElement.style.cursor = 'pointer'; pathElement.addEventListener('click', function(e) { e.stopPropagation(); showConnectionDetail(connectionType, sourceId, targetId, metadata); }); // 添加hover效果 pathElement.addEventListener('mouseenter', function() { this.setAttribute('stroke-width', '4'); this.style.filter = 'drop-shadow(0 0 6px rgba(0,0,0,0.3))'; }); pathElement.addEventListener('mouseleave', function() { this.setAttribute('stroke-width', '2'); this.style.filter = 'none'; }); svg.appendChild(pathElement); } // 显示连线详情模态框 function showConnectionDetail(connectionType, sourceId, targetId, metadata) { // 创建模态框 const modal = document.createElement('div'); modal.className = 'connection-modal-backdrop'; modal.onclick = function(e) { if (e.target === modal) { document.body.removeChild(modal); } }; // 创建模态框内容 const modalContent = document.createElement('div'); modalContent.className = 'connection-modal-content'; modalContent.onclick = function(e) { e.stopPropagation(); }; // 构建内容 let html = ''; html += ''; modalContent.innerHTML = html; modal.appendChild(modalContent); document.body.appendChild(modal); }