前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >markmap 核心原理解析

markmap 核心原理解析

原创
作者头像
brzhang
修改2023-11-29 11:09:17
7530
修改2023-11-29 11:09:17
举报
文章被收录于专栏:玩转全栈玩转全栈

内容提要,学习本文,你会学到:

  • markmap这个库实现的核心技术原理
  • 一种抽象思想,结构化数据转化为另外一种呈现的方式

Markmap 是一个非常有用的工具,它可以将 Markdown 文本转换成交互式的思维导图,我在工作中经常会用到这个工具,比如:

  • 在会议中使用 Markdown 记录要点,然后转换成思维导图,以便更直观地查看讨论的结构和关键点。
  • 将学习笔记转换成思维导图,方便后续直观的复习,毕竟文字的东西不如图容易记忆。

因此之前就了解了下这个工具的实现原理,今天整理了下之前的笔记,写了出来。

学习本文,我们不仅仅可以了解markmap这个库实现的技术原理,今天更重要的其实是,学会一种思想,即Markdown 由于其结构化的特性,可以很容易地被解析成 AST(抽象语法树),这为转换成各种不同格式提供了可能,今天markdown可以转换为 思维导图,明天就可以转换为PPT,这里面透露这的道理,我想表达的意思是,其实他们是相通的。先剧透一下,如下图。

Markmap实现的核心原理

先不讲这么多了,先来了解一下,markmap 的核心技术原理,markmap是开源的,其github地址在此,https://github.com/markmap/markmap ,6k的点赞,然后其issue也不多,让我没法拒绝去扒开他的原理一探究竟。

它的实现原理基于几个关键的技术点:

  1. Markdown 解析:Markmap 使用 Markdown 解析器(如 marked 或其他库)来解析输入的 Markdown 文本,将其转换成一个抽象语法树(AST)。这个 AST 描述了 Markdown 文本的结构,包括标题、列表、代码块等。
  2. 树形结构转换:将 Markdown 的 AST 转换成树形结构,这个结构更适合用来表示思维导图。在这个过程中,通常会将 Markdown 中的标题转换成思维导图的主节点和子节点。
  3. SVG 渲染:使用 D3.js 或类似的库来将树形结构渲染成 SVG 图形。D3.js 提供了强大的数据可视化工具,可以用来创建和操作 SVG 元素,从而生成动态的、可交互的思维导图。
  4. 交互性:Markmap 允许用户与生成的思维导图进行交互,比如展开或折叠节点,这通常是通过监听 DOM 事件并相应地更新 SVG 元素来实现的。

下面是这个过程的序列图

实际上,我们不难发现,树形结构转换就是这个库的重点即,怎么讲markdown结果的文本转换最终转换为可渲染成svg的语言的,带着这个重点,我们去看一看,他是如何实现的。

这个过程涉及到遍历 AST 并创建一个节点树,其中每个节点代表一个思维导图的节点。为了极度的简化,我整理出了一个简化的 JavaScript 伪代码,描述了这个转换过程的核心逻辑:

代码语言:javascript
复制
function transformASTToTree(ast) {
  const rootNode = createNode('root');
  let currentNode = rootNode;

  for (const item of ast) {
    switch (item.type) {
      case 'heading':
        // 根据标题级别确定节点的深度
        const level = item.depth;
        // 如果当前标题级别更深,就创建一个子节点
        if (level > currentNode.level) {
          const childNode = createNode(item.text, level);
          currentNode.children.push(childNode);
          currentNode = childNode;
        } else {
          // 如果标题级别不深或者相同,就回溯到正确的父级
          while (currentNode.level >= level) {
            currentNode = currentNode.parent;
          }
          const siblingNode = createNode(item.text, level);
          currentNode.children.push(siblingNode);
          currentNode = siblingNode;
        }
        break;
      // 处理其他类型的节点...
    }
  }

  return rootNode;
}

function createNode(text, level = 0) {
  return {
    text,
    level,
    children: [],
    parent: null
  };
}

其整个过程可以使用下面的序列图表示:

以上就是这个库的核心原理。

思考一点有意思的

其实不难发现,还有一些库是将markdown转换为PPT,他们的思路都貌似出奇的一致,markdown其实是一种结构话的标记语言,那么,他就可以转化为 ast,然后通过ast转化为其他的语言,所以,这种思路很重要,那么markdown借助ast还可能萌发出什么新的玩法呢,我想大概可以有一下的玩法:

  • 将 Markdown 转换为代码注释或文档,甚至是基于特定模板的代码框架。
  • Markdown 中嵌入的数据可以通过 AST 转换成图表或其他可视化元素。
  • Markdown 文档可以转换成交互式的 Web 应用,实际上 vite里面已经支持,感兴趣的可以了解下。

这里之给出一个markdown转代码的示例,比如我们有一个这样的markdown文件

代码语言:javascript
复制
# Class: Car

## Properties

- `string` color
- `int` year

## Methods

### Method: start

- Description: Start the car engine.
- Returns: `void`

### Method: getColor

- Description: Get the color of the car.
- Returns: `string`

我们就可以写一个工具

代码语言:javascript
复制
import re

# 假设的 Markdown 文本
markdown_text = """
# Class: Car

## Properties

- `string` color
- `int` year

## Methods

### Method: start

- Description: Start the car engine.
- Returns: `void`

### Method: getColor

- Description: Get the color of the car.
- Returns: `string`
"""

# 解析类名
class_match = re.search(r'# Class: (\\w+)', markdown_text)
class_name = class_match.group(1) if class_match else 'UnknownClass'

# 解析属性
properties = re.findall(r'- `(\\w+)` (\\w+)', markdown_text)

# 解析方法
methods = re.findall(r'### Method: (\\w+).*?- Returns: `(\\w+)`', markdown_text, re.DOTALL)

# 生成代码
code = f"class {class_name}:\\n"
code += "    def __init__(self):\\n"
for prop_type, prop_name in properties:
    code += f"        self.{prop_name} = None  # Expected type: {prop_type}\\n"

for method_name, return_type in methods:
    return_statement = 'pass' if return_type == 'void' else f'return None  # Expected type: {return_type}'
    code += f"\\n    def {method_name}(self):\\n"
    code += f"        {return_statement}\\n"

print(code)

下面是我们转换的结果,基本上就实现了将markdown转化为代码,虽然我们取巧,并没有用ast,但是思路上实际是一致,解析里面结构化的信息,来做转化。

将虽然,这种方式不见得比我们直接写代码来的快,但是毕竟这里打开了另外一种思路。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Markmap实现的核心原理
  • 思考一点有意思的
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档