1. 下载 mermaid.min.js
从https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js下载。
放置到一个本地位置,比如我这里的 “D:/mermaid.min.js”
2. 下面代码保存xx.html,与上述下载的文件在同一位置,用浏览器打开。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Mermaid 离线生产力工具</title>
<script src="./mermaid.min.js"></script>
<style>
body { display: flex; height: 100vh; margin: 0; font-family: -apple-system, "Segoe UI", sans-serif; overflow: hidden; background: #282c34; }
#input { width: 40%; height: 100%; box-sizing: border-box; padding: 20px; font-family: 'Cascadia Code', 'Consolas', monospace; background: #282c34; color: #abb2bf; border: none; outline: none; font-size: 14px; resize: none; line-height: 1.6; }
#right-pane { width: 60%; display: flex; flex-direction: column; background: #fff; }
#toolbar { padding: 12px 20px; background: #f8f9fa; border-bottom: 1px solid #ddd; display: flex; gap: 12px; align-items: center; }
#output-container { flex: 1; padding: 40px; overflow: auto; display: flex; justify-content: center; align-items: flex-start; background: #fff; }
button { padding: 8px 16px; cursor: pointer; border: 1px solid #ccc; border-radius: 4px; font-weight: 600; font-size: 13px; transition: all 0.2s; }
button:hover { background: #eee; border-color: #999; }
.btn-png { background: #107c10; color: white; border: none; }
.btn-png:hover { background: #0b5a0b; }
.btn-clear { margin-left: auto; background: #fff; color: #d9534f; border-color: #d9534f; }
.btn-clear:hover { background: #d9534f; color: #fff; }
.hint { font-size: 11px; color: #888; }
</style>
</head>
<body>
<textarea id="input" placeholder="在此输入 Mermaid 代码..." spellcheck="false">
graph LR
A[输入代码] --> B{渲染图表}
B --> C(导出 PNG)
B --> D(导出 SVG)
style C fill:#e1f5fe,stroke:#01579b
style D fill:#fff3e0,stroke:#e65100
</textarea>
<div id="right-pane">
<div id="toolbar">
<button class="btn-png" onclick="downloadPNG()">保存为 PNG (推荐)</button>
<button onclick="downloadSVG()">保存为 SVG</button>
<button class="btn-clear" onclick="clearAll()">清空</button>
<span class="hint">※ SVG 建议用 Chrome 打开查看</span>
</div>
<div id="output-container">
<div id="output" class="mermaid"></div>
</div>
</div>
<script>
const input = document.getElementById('input');
const output = document.getElementById('output');
mermaid.initialize({
startOnLoad: false,
theme: 'default',
flowchart: { useMaxWidth: false, htmlLabels: false } // 禁用 HTML 标签以提高 SVG 兼容性
});
const render = async () => {
const code = input.value.trim();
if (!code) { output.innerHTML = ""; return; }
try {
output.removeAttribute('data-processed');
output.innerHTML = code;
await mermaid.run({ nodes: [output] });
} catch (e) { }
};
function processSVG() {
const svgEl = output.querySelector('svg');
if (!svgEl) return null;
const bBox = svgEl.getBBox();
const padding = 25;
const w = bBox.width + padding * 2;
const h = bBox.height + padding * 2;
const cloned = svgEl.cloneNode(true);
cloned.setAttribute('viewBox', `${bBox.x - padding} ${bBox.y - padding} ${w} ${h}`);
cloned.setAttribute('width', w);
cloned.setAttribute('height', h);
cloned.style.backgroundColor = "white";
// 增强版样式补丁:强制对齐文字
const style = document.createElementNS("http://www.w3.org/2000/svg", "style");
style.textContent = `
text {
font-family: 'Segoe UI', Arial, sans-serif !important;
font-size: 14px !important;
dominant-baseline: central !important;
text-anchor: middle !important;
}
.node rect, .node circle, .node polygon { fill: #ffffff !important; stroke: #333333 !important; }
.edgePath path { stroke: #333333 !important; }
`;
cloned.insertBefore(style, cloned.firstChild);
return { cloned, w, h };
}
async function downloadPNG() {
const data = processSVG();
if (!data) return;
const zoom = 2;
const canvas = document.createElement('canvas');
canvas.width = data.w * zoom;
canvas.height = data.h * zoom;
const ctx = canvas.getContext('2d');
const img = new Image();
const xml = new XMLSerializer().serializeToString(data.cloned);
const url = URL.createObjectURL(new Blob([xml], {type: 'image/svg+xml;charset=utf-8'}));
img.onload = () => {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const a = document.createElement('a');
a.download = `chart-${Date.now()}.png`;
a.href = canvas.toDataURL('image/png', 1.0);
a.click();
URL.revokeObjectURL(url);
};
img.src = url;
}
function downloadSVG() {
const data = processSVG();
if (!data) return;
const xml = new XMLSerializer().serializeToString(data.cloned);
const blob = new Blob([xml], {type: 'image/svg+xml;charset=utf-8'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.download = `chart-${Date.now()}.svg`;
a.href = url;
a.click();
setTimeout(() => URL.revokeObjectURL(url), 100);
}
function clearAll() {
if(confirm("确定要清空所有代码吗?")) {
input.value = "";
render();
}
}
let timer;
input.addEventListener('input', () => {
clearTimeout(timer);
timer = setTimeout(render, 500);
});
window.onload = render;
</script>
</body>
</html>
3.在chrome内打开,效果图如下:

不满意:使用chrome查看导入的svg不错位,使用bindview等图片查看工具文字会错位。
233

被折叠的 条评论
为什么被折叠?



