feat: 添加 Mermaid 图表缩放功能

- 图表容器宽度占满,只留文章边距(margin: 20px -20px)
- 添加缩放控制按钮:放大、缩小、重置
- 支持 Ctrl+滚轮缩放
- 缩放范围:50%-300%,步进 25%
- 响应式适配:移动端自动调整边距和按钮大小
- 夜间模式适配缩放控制按钮样式
This commit is contained in:
2026-01-24 23:36:12 +08:00
parent d59c5ba07d
commit a163e7a2a0
2 changed files with 272 additions and 13 deletions

View File

@@ -5147,7 +5147,7 @@ void 0;
// ---------- 样式增强 ----------
/**
* 应用容器样式
* 应用容器样式并添加缩放控制
* @param {HTMLElement} container - 图表容器
*/
applyStyles(container) {
@@ -5161,9 +5161,88 @@ void 0;
// 确保 SVG 响应式
const svg = container.querySelector('svg');
if (svg) {
svg.style.maxWidth = '100%';
svg.style.width = '100%';
svg.style.height = 'auto';
}
// 添加缩放功能
this.addZoomControls(container);
},
/**
* 添加缩放控制按钮
* @param {HTMLElement} container - 图表容器
*/
addZoomControls(container) {
// 创建内部容器包裹 SVG
const svg = container.querySelector('svg');
if (!svg) return;
// 创建内部容器
const inner = document.createElement('div');
inner.className = 'mermaid-container-inner';
// 将 SVG 移到内部容器
container.appendChild(inner);
inner.appendChild(svg);
// 创建缩放控制
const controls = document.createElement('div');
controls.className = 'mermaid-zoom-controls';
controls.innerHTML = `
<button class="mermaid-zoom-btn" data-action="zoom-out" title="缩小"></button>
<span class="mermaid-zoom-level">100%</span>
<button class="mermaid-zoom-btn" data-action="zoom-in" title="放大">+</button>
<button class="mermaid-zoom-btn" data-action="zoom-reset" title="重置">⟲</button>
`;
container.appendChild(controls);
// 缩放状态
let scale = 1;
const minScale = 0.5;
const maxScale = 3;
const step = 0.25;
// 更新缩放显示
const updateZoom = () => {
inner.style.transform = `scale(${scale})`;
controls.querySelector('.mermaid-zoom-level').textContent = Math.round(scale * 100) + '%';
};
// 绑定按钮事件
controls.addEventListener('click', (e) => {
const btn = e.target.closest('.mermaid-zoom-btn');
if (!btn) return;
const action = btn.dataset.action;
if (action === 'zoom-in' && scale < maxScale) {
scale = Math.min(scale + step, maxScale);
updateZoom();
} else if (action === 'zoom-out' && scale > minScale) {
scale = Math.max(scale - step, minScale);
updateZoom();
} else if (action === 'zoom-reset') {
scale = 1;
updateZoom();
}
});
// 鼠标滚轮缩放(按住 Ctrl
container.addEventListener('wheel', (e) => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
const delta = e.deltaY > 0 ? -step : step;
const newScale = Math.max(minScale, Math.min(maxScale, scale + delta));
if (newScale !== scale) {
scale = newScale;
updateZoom();
}
}
}, { passive: false });
},
// ---------- 主题切换监听 ----------

202
style.css
View File

@@ -913,21 +913,81 @@ article .wp-block-separator {
background: var(--color-foreground);
border-radius: 8px;
padding: 20px;
margin: 20px 0;
margin: 20px -20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow-x: auto;
max-width: 100%;
overflow: hidden;
position: relative;
opacity: 0;
animation: mermaidFadeIn 0.3s ease-in-out forwards;
}
.mermaid-container-inner {
overflow: auto;
transform-origin: top left;
transition: transform 0.3s ease;
}
.mermaid-container svg {
width: 100% !important;
height: auto !important;
max-width: 100%;
display: block;
}
/* 缩放控制按钮 */
.mermaid-zoom-controls {
position: absolute;
top: 10px;
right: 10px;
display: flex;
gap: 5px;
z-index: 10;
background: rgba(255, 255, 255, 0.9);
border-radius: 6px;
padding: 5px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
html.darkmode .mermaid-zoom-controls {
background: rgba(30, 30, 30, 0.9);
}
.mermaid-zoom-btn {
width: 32px;
height: 32px;
border: none;
background: transparent;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #5e72e4;
transition: all 0.2s;
}
.mermaid-zoom-btn:hover {
background: rgba(94, 114, 228, 0.1);
}
.mermaid-zoom-btn:active {
transform: scale(0.95);
}
.mermaid-zoom-level {
display: flex;
align-items: center;
padding: 0 8px;
font-size: 13px;
color: #666;
min-width: 50px;
justify-content: center;
}
html.darkmode .mermaid-zoom-level {
color: #aaa;
}
/* Mermaid 淡入动画 */
@keyframes mermaidFadeIn {
from {
@@ -942,7 +1002,42 @@ article .wp-block-separator {
/* 文章卡片内的 Mermaid 图表 */
article.card .mermaid-container {
margin: 20px 0;
margin: 20px -20px;
}
/* 响应式调整 */
@media screen and (max-width: 768px) {
.mermaid-container {
margin: 15px -15px;
padding: 15px;
}
article.card .mermaid-container {
margin: 15px -15px;
}
}
@media screen and (max-width: 480px) {
.mermaid-container {
margin: 10px -10px;
padding: 10px;
}
article.card .mermaid-container {
margin: 10px -10px;
}
.mermaid-zoom-controls {
top: 5px;
right: 5px;
padding: 3px;
}
.mermaid-zoom-btn {
width: 28px;
height: 28px;
font-size: 16px;
}
}
/* Mermaid 错误提示样式 */
@@ -16629,24 +16724,85 @@ html.darkmode .mermaid-error-container .error-code code {
padding: 20px;
margin: 20px 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow-x: auto;
max-width: 100%;
overflow: hidden;
position: relative;
margin: 20px -20px;
transition: opacity 0.3s ease-in;
}
.mermaid-container-inner {
overflow: auto;
transform-origin: top left;
transition: transform 0.3s ease;
}
.mermaid-container svg {
width: 100% !important;
height: auto !important;
max-width: 100%;
display: block;
}
/* 缩放控制按钮 */
.mermaid-zoom-controls {
position: absolute;
top: 10px;
right: 10px;
display: flex;
gap: 5px;
z-index: 10;
background: rgba(255, 255, 255, 0.9);
border-radius: 6px;
padding: 5px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
html.darkmode .mermaid-zoom-controls {
background: rgba(30, 30, 30, 0.9);
}
.mermaid-zoom-btn {
width: 32px;
height: 32px;
border: none;
background: transparent;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #5e72e4;
transition: all 0.2s;
}
.mermaid-zoom-btn:hover {
background: rgba(94, 114, 228, 0.1);
}
.mermaid-zoom-btn:active {
transform: scale(0.95);
}
.mermaid-zoom-level {
display: flex;
align-items: center;
padding: 0 8px;
font-size: 13px;
color: #666;
min-width: 50px;
justify-content: center;
}
html.darkmode .mermaid-zoom-level {
color: #aaa;
}
/* ---------- 卡片内的 Mermaid 图表 ---------- */
.card .mermaid-container,
.post-card .mermaid-container,
.comment-content .mermaid-container {
padding: 15px;
margin: 15px 0;
margin: 15px -15px;
}
/* ---------- 夜间模式适配 ---------- */
@@ -16659,15 +16815,39 @@ html.darkmode .mermaid-container {
@media screen and (max-width: 768px) {
.mermaid-container {
padding: 15px;
margin: 15px 0;
margin: 15px -15px;
border-radius: calc(var(--card-radius) * 0.8);
}
.card .mermaid-container,
.post-card .mermaid-container,
.comment-content .mermaid-container {
margin: 15px -15px;
}
}
@media screen and (max-width: 480px) {
.mermaid-container {
padding: 10px;
margin: 10px 0;
margin: 10px -10px;
}
.card .mermaid-container,
.post-card .mermaid-container,
.comment-content .mermaid-container {
margin: 10px -10px;
}
.mermaid-zoom-controls {
top: 5px;
right: 5px;
padding: 3px;
}
.mermaid-zoom-btn {
width: 28px;
height: 28px;
font-size: 16px;
}
}