起因:
由于项目的需求要把大模型返回的 markdown 数据变成思维导图,并且看到了秘塔搜索的思维导图之后markmap就这样的进过了我的生活
官方网站: markmap
依赖包下载:
npm i markmap-common markmap-lib markmap-toolbar markmap-view
第一步:首先你需要一个svg的标签作为你的思维导图的容器
<svg id="markMap"></svg>
第二步:你需要再页面引入markmap
import {Transformer} from "markmap-lib";
import { Toolbar } from "markmap-toolbar";
import {loadCSS, loadJS, Markmap} from "markmap-view";
第三步:如何将你的markdom渲染成思维导图?
假设你已经拿到了大模型返回的markdom数据
\n# 中国武器大全\n## **导弹武器**\n - 蓝箭7反坦克导弹[[1]]\n - 巨浪-2(JL-2/CSS-N-4)[[1]]\n - M-9/东风-15/CSS-6[[1]]\n - 飞腾-2000(FT-2000)[[1]]\n - 前卫-1(QW-1)[[1]]\n - M11[[1]]\n - 空地-88(KD-88)[[1]]\n - 猎鹰-60(LY-60)[[1]]\n - 陆盾2000(LD2000)[[1]]\n - 红箭73(HJ-73)[[1]]\n - 鹰击1(YJ-1/C-101)[[1]]\n - 鹰击-62(YJ-62/C-602)[[1]]\n - J-201[[1]]\n - 霹雳-6(PL-6)[[1]]
1、首先我们需要把我们 Markdown 数据转化成 markmap 可渲染的数据,这时候就需要使用我们刚刚引用的markmap-lib,markmap-lib的作用就是把我们的 Markdown 数据转化成 markmap 可渲染的数据.
const transformer = new Transformer();
//this.initValue就是我们的markdom数据,此方法就是转换markdom数据,可以打印root查看数据结构
const { root, features } = transformer.transform(this.initValue);
const { styles, scripts } = transformer.getUsedAssets(features);
2.先在我们需要把我们获取的渲染数据root,渲染到我们svg标签上,这时候就需要用到markmap-view了
if (styles) loadCSS(styles);
if (scripts) loadJS(scripts, { getMarkmap: () => markmap });
const svgEl = document.querySelector('#markMap');
const mm= Markmap.create(svgEl, undefined, root);
其实到这里我们就可以获取一个转换后的思维导图了,但是项目还需要将思维导图转换成PNG、JPG、PDF三种格式所以应用了第二个插件 html2canvas
1.我们先要获取到思维导图svg标签的父元素
<div ref="markMap">
<svg id="markMap"></svg>
</div>
2.现在我们就可以直接转换为图片格式了
const svg = this.$refs.markMap
html2canvas(svg,{
scale: 3,//下载的图片或者pdf可能不太清晰,可以在这调节图片的大小
dpi: 300,
imageQuality: 0.9,
}).then((canvas) => {
// 创建一个图片元素
let img = new Image();
if(type=='png'){
img.src = canvas.toDataURL('image/png');
// 下载图片
let link = document.createElement('a');
link.href = img.src;
link.download = `exported-image.${type}`;
link.click();
}else if(type=='jpg'){
img.src = canvas.toDataURL('image/jpeg');
// 下载图片
let link = document.createElement('a');
link.href = img.src;
link.download = `exported-image.${type}`;
link.click();
}else if (type=='pdf'){
let contentWidth = canvas.width;
let contentHeight = canvas.height;
let pdfWidth = 595.28; // A4 width in pixels
let pdfHeight = (pdfWidth / contentWidth) * contentHeight;
let pageData = canvas.toDataURL('image/jpeg',1.0);
let PDF = new JsPDF('p', 'pt', 'a4');
let scale = pdfWidth / contentWidth;
PDF.addImage( pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);
let remainingHeight = pdfHeight;
while (remainingHeight < contentHeight) {
PDF.addPage();
let offsetY = -remainingHeight * scale;
PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);
remainingHeight += pdfHeight;
}
PDF.save('export.pdf'); //直接下载
}
});
3.现在我们就可以实现导出的功能了,但是在此项目在出现了bug
问题描述:在思维导图放大时当思维导图超出元素时,就会出现导出图片不全的情况
解决方案:参考了秘塔搜索,引入markmap自带的工具栏,其中有个按键是复原思维导图大小的操作,在导出前js代码模拟点击事件将思维导图回复至最初比例,并导出,应为项目设计图没有这三个按钮所以我们需要将他们隐藏设置opacity:0
参考图片:
//展示XMind
initXMind(){
const transformer = new Transformer();
const { root, features } = transformer.transform(this.initValue);
const { styles, scripts } = transformer.getUsedAssets(features);
const toolbar = new Toolbar();
if (styles) loadCSS(styles);
if (scripts) loadJS(scripts, { getMarkmap: () => markmap });
let options={}
const svgEl = document.querySelector('#markMap');
const mm= Markmap.create(svgEl, undefined, root);
toolbar.setBrand(false); // 隐藏 toolbar 中 markmap 的logo和url
toolbar.attach(mm);
toolbar.setItems(['zoomIn', 'zoomOut', 'fit']); // 重新设置默认的功能模块,添加导图导航栏
this.$refs.markMap.append(toolbar.render());
},
zoonIn(){
//xmind缩放自适应
let element=document.querySelector('.mm-toolbar').lastChild
element.click()
},
exportPng(type) {
this.$nextTick(async ()=>{
await this.zoonIn() //自适应后的代码需要延时一下不然没效果
setTimeout(()=>{
const svg = this.$refs.markMap
html2canvas(svg,{
scale: 3,
dpi: 300,
imageQuality: 0.9,
}).then((canvas) => {
// 创建一个图片元素
let img = new Image();
if(type=='png'){
img.src = canvas.toDataURL('image/png');
// 下载图片
let link = document.createElement('a');
link.href = img.src;
link.download = `exported-image.${type}`;
link.click();
}else if(type=='jpg'){
img.src = canvas.toDataURL('image/jpeg');
// 下载图片
let link = document.createElement('a');
link.href = img.src;
link.download = `exported-image.${type}`;
link.click();
}else if (type=='pdf'){
let contentWidth = canvas.width;
let contentHeight = canvas.height;
let pdfWidth = 595.28; // A4 width in pixels
let pdfHeight = (pdfWidth / contentWidth) * contentHeight;
let pageData = canvas.toDataURL('image/jpeg',1.0);
let PDF = new JsPDF('p', 'pt', 'a4');
let scale = pdfWidth / contentWidth;
PDF.addImage( pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);
let remainingHeight = pdfHeight;
while (remainingHeight < contentHeight) {
PDF.addPage();
let offsetY = -remainingHeight * scale;
PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);
remainingHeight += pdfHeight;
}
PDF.save('export.pdf'); //直接下载
}
});
},1000)
})
},
至此就是实现导出的全部代码
4、项目中还有在思维导图添加了注脚功能,不能放项目图片参考秘塔搜索
我们来看一下实现思路(此思路不是最好的)
我们反过来看一下大模型返回的markdom数据,我们将 [[数字]] 定义为注脚
\n# 中国武器大全\n## **导弹武器**\n - 蓝箭7反坦克导弹[[1]]\n - 巨浪-2(JL-2/CSS-N-4)[[1]]\n - M-9/东风-15/CSS-6[[1]]\n - 飞腾-2000(FT-2000)[[1]]\n - 前卫-1(QW-1)[[1]]\n - M11[[1]]\n - 空地-88(KD-88)[[1]]\n - 猎鹰-60(LY-60)[[1]]\n - 陆盾2000(LD2000)[[1]]\n - 红箭73(HJ-73)[[1]]\n - 鹰击1(YJ-1/C-101)[[1]]\n - 鹰击-62(YJ-62/C-602)[[1]]\n - J-201[[1]]\n - 霹雳-6(PL-6)[[1]]
所以我在获取markdom数据时将[[ 和 ]]替换成a标签
//展示XMind
initXMind(){
const transformer = new Transformer();
const { root, features } = transformer.transform(this.initValue);
const { styles, scripts } = transformer.getUsedAssets(features);
const toolbar = new Toolbar();
if (styles) loadCSS(styles);
if (scripts) loadJS(scripts, { getMarkmap: () => markmap });
let options={}
const svgEl = document.querySelector('#markMap');
const mm= Markmap.create(svgEl, undefined, root);
toolbar.setBrand(false); // 隐藏 toolbar 中 markmap 的logo和url
toolbar.attach(mm);
toolbar.setItems(['zoomIn', 'zoomOut', 'fit']); // 重新设置默认的功能模块
this.$refs.markMap.append(toolbar.render());
document.querySelectorAll('a').forEach(ele=>{
ele.setAttribute('class','aClass')
ele.addEventListener('mouseover',()=>{
ele.style.background='#0456B4'
})
ele.addEventListener('mouseout',()=>{
ele.style.background='#d0d5dd'
})
})
},
//思维导图接口
async mindMapping(id){
const res =await mindMapping({result_id:id})
if(res.code==200){
let regex = '[[';
let regexRight = ']]';
let aStar=`<a href="javascript:;" style=" display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
font-size: 12px;
text-align: center;
background-color: #d0d5dd;
color: #fff !important;
text-align: center;
font-size: 9px;
text-decoration: none !important;
vertical-align: middle;
margin: 0 2px 3px;
cursor: pointer;
line-height: 16px;">`
let aEnd=`</a >`
let pattern = (/\[\[\d+\]\]/g);
let msg=res.data.split(pattern)
let str=res.data.replaceAll(regex,aStar)
this.initValue=str.replaceAll(regexRight,aEnd)
this.$nextTick(async ()=>{
await this.initXMind()
let domList=document.querySelectorAll('.aClass')
domList.forEach(item=>{
//在此添加注脚点击事件
item.addEventListener('click',(e)=>{
e.preventDefault();
this.internetAnswer.list[Number(item.innerText)-1] && this.preview(this.internetAnswer.list[Number(item.innerText)-1])
})
})
})
}
},
标签:思维,const,导图,let,markmap,link,toolbar
From: https://blog.csdn.net/m0_69454976/article/details/140642168