首页 > 其他分享 >基于markmap实现思维导图

基于markmap实现思维导图

时间:2024-07-23 18:00:41浏览次数:15  
标签:思维 const 导图 let markmap link toolbar

起因:

由于项目的需求要把大模型返回的 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

相关文章

  • 片集 - 思维(博弈论,etc.) - 1
    欢迎来看“片”(的简介)由于-\(看片\)-生涯转瞬即逝,于是我选择对“\(片\)”进行一定的总结:相信你一定看懂了由于开始的时间有一点晚,就姑且认为我以后会慢慢补充吧......\(P6970\)\([NEERC2016]\)\(Game\)\(on\)\(Graph\)解:博弈论首先,我们有更原始的问题:\(A\),\(B\)......
  • selenium需要学习哪些知识,给出导图
    编程语言基础(如Python)基本语法数据类型控制结构(如条件语句、循环)函数定义与使用面向对象编程概念(类、对象、继承等)Selenium基础汇总元素定位ID定位Name定位ClassName定位TagName定位LinkText定位PartialLinkText定位XPath定位(重点掌握)CSS选择器定位(重点掌......
  • 架构与思维:秒杀和竞拍的业务架构,永不过时的话题
    1互联网架构越来越复杂?为啥感觉互联网架构越来越复杂了,早期我们的系统,可能也就那么少部分人使用,大都是一些后台管理系统。所以不用考虑很多东西,比如:流量少,无需考虑并发问题数据少,不用考虑什么索引优化、分库分表访问不集中,不用考虑缓存、过载保护如果数据不重要,不用考虑安......
  • 这个容易忽略的思维方式,是改变生活的关键
    在文章的开头,我想先跟你分享一个有趣的实验。2015年,剑桥大学和斯坦福大学做过一项实验。他们先让参与者A做一套大五人格的测试。然后,他们让A的亲朋好友来回答一套问卷,测试他们对A的了解程度。与此同时,他们将A在社交媒体上的行为(主要是点赞)输入电脑,让算法也来做这套问卷。......
  • 题解:2024牛客多校赛第二场 A Floor Tiles(思维)
    2024NowcoderMulti-UniversityTrainingContest2ProblemA.FloorTiles题目大意给你两种正方形图案,分别为以下两种:再给你三个整数\(N,M,K\),表示你需要用这两种图案,拼成一个\(N\)列\(M\)行的矩形。由于这两种图案十分特殊,他们能无缝衔接在一起。因此你需要让这个矩......
  • 解题思维
    拿到一道题,先审题:题目中会有关键的语句,提示你往哪里想。“询问最大……的最小值”“最小……的最大值”(前者更常见一些):考虑二分棋盘格子,尤其是涉及“相邻”的操作的:考虑黑白染色跑网络流对于一个森林,考虑建立一个虚点,把它变成一颗树对于按指定顺序balabla……,有时考虑倍增......
  • 各种图(流程图,思维导图,UML,拓扑图,ER图)简介
    原文链接:https://blog.51cto.com/jiqing9006/3284733流程图1.定义:流程图是对过程、算法、流程的一种图像表示,在技术设计、交流及商业简报等领域有广泛的应用。2.案例  3.计算机语言只是一种工具。光学习语言的规则还不够,最重要的是学会针对各种类型的问题,拟定出有效的解......
  • PC XMind v24.01.14362 解锁版安装教程 (全球领先的商业思维导图软件)
    前言XMind是一款专业的全球领先的商业思维导图软件,在国内使用广泛,拥有强大的功能、包括思维管理、商务演示、与办公软件协同工作等功能。它采用全球先进的EclipseRCP软件架构,是集思维导图与头脑风暴于一体的可视化思考工具,能用来捕捉想法、理清思路、管理复杂信息并促进团队协......
  • 信创学习笔记(四),信创之数据库DB思维导图
    创作不易只因热爱!!热衷分享,一起成长!“你的鼓励就是我努力付出的动力”一.信创学习回顾1.信创内容信创内容思维导图2.信创之CPU芯片架构信创之CPU芯片架构思维导图3.信创之操作系统OS信创之操作系统OS思维导图二.信创之国产数据库DB思维导图用一张图学习......
  • 架构与思维:微服务架构的思想本质
    我们为什么需要微服务架构,它一定是为了解决我们某些问题才出现了。这篇文章我们讨论下微服务架构模式所解决的问题,带来的挑战,以及他的核心思想本质。1早期的服务架构上图是一个典型的服务分层架构:Client:调用方是browserweb或者App应用层:实现计算层的业务逻辑,从上游数据层......