工程写作:Markdown 插入示意图

    3 Mar, 2025

    在 Markdown 工程写作中,经常会有插入 UML,流程图,架构图等示意图的需求。本文推荐两种工具以及对应的 Markdown 处理库、Visual Studio Code Markdown 扩展插件。

    在编写一些重要文档时需要插入一些示意图,如统计图、UML、流程图等,经常遇到 Markdown 图片和文本分离的问题,在 Markdown 中管理图片是比较麻烦的事,尤其是像统计图、UML 等需要频繁更新、版本管理的图片。

    对于这类问题,我推荐的方案是 TTD (text-to-diagram). 现在有很多开源的免费的 TTD Generator,如 Mermaid.jsPlantUMLGraphViz. 它们允许你使用文本形式的 DSL 代码去绘制图形,一般来说一份代码对应一种图像,非常利于文档中的插图。 你可以在这里去体验它们.

    在这里我主要讨论 PlantUML、Graphviz 两种插件以及对应的不同情景。

    PlantUML

    PlantUML 是老牌的、工业级的 UML 绘图工具,提供的 UML 也是最全的,很多教科书、学术论文等专业场景都采用的 PlantUML。因为“大而全”,所以它的学习曲线较为陡峭,文档内容也非常多,需要仔细研读。

    这是 PlantUML 的在线体验地址,以及文档地址

    我们写一个简单的图书馆系统的用例图,输入以下 PlantUML 代码:

    @startuml
    left to right direction
    
    actor 读者 as Reader
    actor 图书管理员 as Librarian
    
    rectangle 图书馆管理系统 {
      usecase "搜索图书" as UC1
      usecase "借阅图书" as UC2
      usecase "归还图书" as UC3
      usecase "管理图书信息" as UC4
      usecase "生成借阅报告" as UC5
    
      Reader --> UC1
      Reader --> UC2
      Reader --> UC3
    
      Librarian --> UC4
      Librarian --> UC5
    
      UC2 .> UC1 : <<include>>  // 借阅前需搜索
      UC3 .> UC1 : <<include>>  // 归还前需搜索
      UC5 .> UC2 : <<extend>>   // 报告可扩展借阅细节
    }
    @enduml
    

    它生成的用例图如下:

    它生成的图像 UI 都有上个世纪的风格,比较适合对样貌美观性不高的场景,如教科书、论文等,好在可以自己选择主题。

    但是 PlantUML 是基于 Java 编写的,运行它需要提供 Java 运行环境并放在后端中运行。但官方也把它打包成了一个 图像生成的 Web 服务器,把它部署在自己的服务器上就可以了。

    使用 PlantUML Web 服务器的方法很简单,你只需要把要生成的 PlantUML 代码压缩、编码成 URL 参数,再传递给服务器即可。

    就比如上面的 PlantUML,把代码编码,生成

    VPBBIiD058RtWRp3eVjQ.....
    

    然后就可以生成引用图片的 URL 了

    ![](https://www.plantuml.com/plantuml/VPBBIiD058RtWRp3eVjQ.....)
    

    VSCode 集成

    PlantUML 有官方 VSCode 插件,可以添加对其相关代码和语言的支持,当然也可以在 Markdown 预览视图中添加图像预览支持,只需要在 markdown 中编写代码,在预览中自动生成图像,就像这样。

    Unified.js 集成

    如果需要和开源文档处理器 unified.js 集成,我编写了一个 remark 插件 remark-refer-plantuml,可以在 Markdown 文档语法树中自动完成识别、编码并替换成图像 URL 引用的这一过程。

    Graphviz

    Graphviz 是一个基础插图生成库,使用 DSL 来定义、生成图像,用算法自动排列节点和边,特别适合生成复杂的图表。

    比如,用 Graphviz 写一个红黑树:

    digraph RedBlackTree {
        node [shape=circle, style=filled, fontcolor=white];
    
        10 [fillcolor=black];
        5 [fillcolor=red];
        15 [fillcolor=red];
        3 [fillcolor=black];
        7 [fillcolor=black];
        12 [fillcolor=black];
        18 [fillcolor=black];
    
        10 -> 5;
        10 -> 15;
        5 -> 3;
        5 -> 7;
        15 -> 12;
        15 -> 18;
    }
    

    渲染效果图如下:

    RedBlackTree 10 10 5 5 10->5 15 15 10->15 3 3 5->3 7 7 5->7 12 12 15->12 18 18 15->18

    或者写一个归并排序分治算法的流程示意图

    MergeSort array 4  2  5  1  3 split1 4  2  5   |   1  3 array->split1 split2_1 4  2  |  5 split1->split2_1 split2_2 1  |  3 split1->split2_2 split3_1 4  |  2 split2_1->split3_1 5 5 split2_1->5 1 1 split2_2->1 3 3 split2_2->3 4 4 split3_1->4 2 2 split3_1->2 merge1_1 2  4 merge2 2  4  5 merge1_1->merge2 merge1_2 1  3 merge3 1  2  3  4  5 merge1_2->merge3 merge2->merge3 5->merge2 1->merge1_2 3->merge1_2 4->merge1_1 2->merge1_1

    Graphviz 的绘图功能也十分强大,根据代码生成 SVG 图像,但由于是底层库,对样式、布局算法等细节还需要自己手动完成,如果有自定义需求,通常需要二次开发。

    Graphviz 是使用 C、C++ 语言进行开发的。也可以编译成 WASM,允许你直接在浏览器前端、Node.js 中使用。WASM 包有 Viz.jshpcc-js-wasm 等。

    VSCode 集成

    VSCode 有对 Graphviz 语言的插件。不过,对在 VSCode Markdown 中预览视图的支持的插件不多,且缺乏维护。

    所以我写了一个 VSCode 插件:Markdown Graphviz Preview.

    Unified.js 集成

    同样,我也写了一个 rehype 插件 rehype-graphviz-diagram,可以与 unified.js 文档处理集成。