代码分享-Markmap 自定义导出图片按钮
时间:2025-11-7 13:42 作者:wanzi 分类: vue
一、什么是 Markmap
Markmap 是一个将 Markdown 转换为交互式思维导图的开源工具。
核心库是 markmap-lib,可用于网页端(包括 Vue / React / 原生 HTML)渲染 Markdown。
常用库:
-
markmap-lib:负责解析 Markdown 并生成数据结构。
-
markmap-view:负责实际在页面中渲染交互式 SVG 思维导图。
-
markmap-toolbar(可选):提供放大、折叠、导出等操作按钮。
<script type="module">
const {createApp, ref, onMounted, onUpdated} = Vue;
createApp({
setup() {
const svgRef = ref(null);
const markdown = ref('');
let mm = null;
const update = async () => {
const transformer = new markmap.Transformer()
const {root} = transformer.transform(markdown.value);
await mm.setData(root);
mm.fit();
};
const renderFile = async () => {
const urlParams = new URLSearchParams(window.location.search);
const fileName = urlParams.get('file');
const taskId = urlParams.get('task_id');
if (!fileName) {
layui.layer.closeAll()
return layui.layer.msg('访问出错');
}
try {
const mdStr = await http.get(`/api/tasks/video/${taskId}/files/${fileName}`, {
responseType: 'text'
});
markdown.value = mdStr
mm = markmap.Markmap.create(svgRef.value)
update()
markmap.Toolbar.defaultItems = ["zoomIn", "zoomOut", "fit", "recurse", "dark", "saveAsImage"];
const toolbar = new markmap.Toolbar()
toolbar.register({
id: 'saveAsImage',
title: '保存为图片',
content: markmap.Toolbar.icon(
'M4 7h3l2-3h6l2 3h3a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2zm8 3a4 4 0 1 1 0 8 4 4 0 0 1 0-8z',
),
onClick: async () => {
if (!mm?.svg) {
console.warn('[markmap] SVG not available');
return;
}
const svgEl = mm.svg._groups[0][0];
const {width, height} = svgEl.getBoundingClientRect();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width * 2;
canvas.height = height * 2;
ctx.scale(2, 2);
const svgData = new XMLSerializer().serializeToString(svgEl);
const svgBase64 = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgData);
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob((blob) => {
const link = document.createElement('a');
link.download = 'markmap.png';
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);
}, 'image/png');
canvas.remove();
};
img.src = svgBase64;
}
});
toolbar.render();
toolbar.attach(mm);
const el = toolbar.el;
// const {el} =markmap.Toolbar.create(mm);
el.style.position = 'absolute';
el.style.bottom = '0.5rem';
el.style.right = '0.5rem';
document.getElementById('toolbar').append(el);
} catch (error) {
layui.layer.msg('查看文件失败: ' + error.message, {icon: 2});
}
};
onMounted(() => {
renderFile();
});
onUpdated(update);
return {
svgRef
}
}
}).mount('#app');
</script>
