From 66df8348be3b62ccb513822f39810b39d5b32e4a Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Sun, 25 Jan 2026 01:30:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=20Mermaid=20?= =?UTF-8?q?=E6=8B=96=E6=8B=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7.1 改进拖拽响应:使用 requestAnimationFrame 优化性能,避免频繁的 DOM 操作 - 7.2 优化拖拽视觉反馈:增强光标样式,添加跨浏览器的文本选择禁用 - 7.3 智能启用拖拽:检测图表是否需要拖拽,未缩放且完全可见时自动禁用 需求:13.1, 13.2, 13.3, 13.4, 13.5 --- argontheme.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++----- style.css | 15 +++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/argontheme.js b/argontheme.js index 85b4f11..f026d1d 100644 --- a/argontheme.js +++ b/argontheme.js @@ -5775,12 +5775,47 @@ void 0; let startY = 0; let scrollLeft = 0; let scrollTop = 0; + let rafId = null; + let pendingX = 0; + let pendingY = 0; + + // 需求 13.5: 智能启用拖拽 - 检查图表是否需要拖拽 + const checkDragEnabled = () => { + const svgElement = inner.querySelector('svg'); + if (!svgElement) return false; + + // 如果图表未缩放且完全可见,禁用拖拽 + const containerRect = container.getBoundingClientRect(); + const svgRect = svgElement.getBoundingClientRect(); + const isFullyVisible = svgRect.width <= containerRect.width && + svgRect.height <= containerRect.height; + const isNotZoomed = Math.abs(scale - 1) < 0.01; + + return !(isFullyVisible && isNotZoomed); + }; + + // 需求 13.3: 使用 requestAnimationFrame 优化拖拽性能 + const updateDragPosition = () => { + if (!isDragging) { + rafId = null; + return; + } + + inner.scrollLeft = scrollLeft - pendingX; + inner.scrollTop = scrollTop - pendingY; + + rafId = requestAnimationFrame(updateDragPosition); + }; inner.addEventListener('mousedown', (e) => { // 只响应左键 if (e.button !== 0) return; + // 需求 13.5: 检查是否需要启用拖拽 + if (!checkDragEnabled()) return; + isDragging = true; + // 需求 13.1: 改变鼠标光标为抓手样式 inner.classList.add('dragging'); startX = e.pageX - inner.offsetLeft; @@ -5788,7 +5823,13 @@ void 0; scrollLeft = inner.scrollLeft; scrollTop = inner.scrollTop; + // 需求 13.2: 禁用文本选择 e.preventDefault(); + + // 启动 RAF 循环 + if (!rafId) { + rafId = requestAnimationFrame(updateDragPosition); + } }); document.addEventListener('mousemove', (e) => { @@ -5798,17 +5839,21 @@ void 0; const x = e.pageX - inner.offsetLeft; const y = e.pageY - inner.offsetTop; - const walkX = (x - startX) * 2; - const walkY = (y - startY) * 2; - - inner.scrollLeft = scrollLeft - walkX; - inner.scrollTop = scrollTop - walkY; + // 更新待处理的位置,由 RAF 循环处理 + pendingX = (x - startX) * 2; + pendingY = (y - startY) * 2; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; + // 需求 13.4: 恢复正常光标 inner.classList.remove('dragging'); + // 取消 RAF 循环 + if (rafId) { + cancelAnimationFrame(rafId); + rafId = null; + } } }); @@ -5816,6 +5861,13 @@ void 0; inner.addEventListener('dragstart', (e) => { e.preventDefault(); }); + + // 需求 13.2: 禁用文本选择 + inner.addEventListener('selectstart', (e) => { + if (isDragging) { + e.preventDefault(); + } + }); // 需求 12.5: 双击智能缩放 // 双击图表时,如果当前是默认大小则放大到 2 倍,否则重置到 1 倍 diff --git a/style.css b/style.css index f9c8fd1..277ca1c 100644 --- a/style.css +++ b/style.css @@ -1053,7 +1053,6 @@ html.darkmode .mermaid-zoom-controls { html.darkmode .mermaid-zoom-level { color: #aaa; } -} /* 按钮 tooltip */ .mermaid-zoom-btn[title] { @@ -1114,16 +1113,28 @@ html.darkmode .mermaid-hint { backdrop-filter: blur(10px); } -/* 拖拽时的光标 */ +/* 拖拽时的光标和视觉反馈 */ +/* 需求 13.1, 13.2, 13.4: 优化拖拽视觉反馈 */ .mermaid-container-inner.dragging { cursor: grabbing !important; user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; } .mermaid-container-inner:not(.dragging) { cursor: grab; } +/* 拖拽时禁用 SVG 内的文本选择 */ +.mermaid-container-inner.dragging svg { + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + /* Mermaid 淡入动画 */ @keyframes mermaidFadeIn { from {