用Markdown制作Mermaid图表的方法

876 阅读4分钟

美人鱼图和流程图已经越来越受到重视,尤其是GitHub宣布它们在Markdown中得到了原生支持。让我们来看看它们是什么,如何使用它们,以及同样重要的:为什么

就像你可能想把你的CodePen演示直接嵌入你的文档源中一样,让你的图表与你的文本相邻,有助于防止它们腐烂--也就是说,与你的文档的状态不同步。就像代码中无用的、过时的或有误导性的注释在客观上比没有注释更糟糕一样,图表也是如此。

Mermaid图表与Jamstack静态网站生成器搭配得很好,后者的受欢迎程度在不断提高。这种搭配是很自然的。虽然Mermaid图表不是Markdown独有的,但它们是受Markdown启发的。使用Markdown提供的同样的标记抽象来记录代码,Mermaid可以用同样的方式来输出图表和流程图。而Markdown对于Jamstack和静态网站就像花生酱对于果冻一样。

如果你的网站是用Markdown编写的,并被处理成HTML,而且你有足够的控制力来添加一些自定义的JavaScript,那么你就可以使用我们在本文中所涉及的想法来满足你自己的需求,并且用Mermaid来实现图表,方便地与你的Markdown其他部分一起使用。"图表即代码 "是一个术语吗?它应该是。

例如,假设你正在开发一个漂亮的新产品,你想以甘特图的形式提供一个路线图(或其他类型--例如流程图、序列图和类图)。有了Mermaid,你可以用一小撮行来做这个。

gantt
  title My Product Roadmap
  dateFormat  YYYY-MM-DD
  section Cool Feature
  A task           :a1, 2022-02-25, 30d
  Another task     :after a1, 20d
  section Rad Feature
  Task in sequence :2022-03-04, 12d
  Task, No. 2      :24d

这将呈现一个漂亮的SVG图表,就像这样。

Showing a Mermaid diagram of a roadmap in shades of purple.

9行代码就可以得到一个成熟的甘特图,可以用于产品路线图等。

**专业提示:**Mermaid有一个实时编辑器,可以让你在mermaid.live上尝试一下,不需要承诺。

在Markdown中的Mermaid图表

Mermaid与Markdown配合得很好,因为它只是把自己表现为另一个有围栏的代码块,只使用mermaid 语言的语法集。例如,这个代码块。

```mermaid
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```

...产生一个HTML<pre> 元素,里面是代码块的内容。

<pre class="mermaid"><code>graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;</code></pre>

如果你使用的是符合CommonMark规范的Markdown处理器,它将更像这样。

<pre><code class="language-mermaid">graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
</code></pre>

Mermaid API的默认行为期望一个直接包含内容的<div class="mermaid"> 标签--所以,没有<code><span> (像来自语法高亮器),你可能在从Markdown到HTML的转换中看到。

用JavaScript进行修饰

通过一点JavaScript,我们可以合理地将Markdown生成的HTML,细化为Mermaid所针对的<div class="mermaid"> 。值得注意的是 $element.textContent在这里是有目的的。Markdown会对Mermaid使用的特定字符进行HTML编码(比如将> 转换成&gt; )。它还会过滤掉任何错误的HTML元素,这些元素是<pre> 的后代。

// select <pre class="mermaid"> _and_ <pre><code class="language-mermaid">
document.querySelectorAll("pre.mermaid, pre>code.language-mermaid").forEach($el => {
  // if the second selector got a hit, reference the parent <pre>
  if ($el.tagName === "CODE")
    $el = $el.parentElement
  // put the Mermaid contents in the expected <div class="mermaid">
  // plus keep the original contents in a nice <details>
  $el.outerHTML = `
    <div class="mermaid">${$el.textContent}</div>
    <details>
      <summary>Diagram source</summary>
      <pre>${$el.textContent}</pre>
    </details>
  `
})

现在,我们的HTML已经被正确地格式化了,让我们来实现Mermaid来进行渲染。

使用Mermaid

Mermaid是以npm包的形式发布的,所以你可以通过使用包感知CDN(如unpkg)来获取一个副本。你将会希望使用经过缩减的代码(例如:mermaid.min.js ),而不是默认导出的mermaid.core.js 。例如。

<script src="https://unpkg.com/mermaid@8.14.0/dist/mermaid.min.js"></script>

Mermaid是ESM就绪的,所以你也可以使用Skypack来加载它。

<script type="module">
  import mermaid from "https://cdn.skypack.dev/mermaid@8.14.0";
</script>

如果你想保持简单,你可以在这里停止。默认情况下,当文件准备好时,Mermaid会自动初始化自己。只要你在加载Mermaid之前,用前面提到的JavaScript做了Markdown-to-HTML的微调,你就会一切就绪。

然而,Mermaid有几个值得配置的设置。

// initialize Mermaid to [1] log errors, [2] have loose security for first-party
// authored diagrams, and [3] respect a preferred dark color scheme
mermaid.initialize({
  logLevel: "error", // [1]
  securityLevel: "loose", // [2]
  theme: (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) ?
    "dark" :
    "default" // [3]
})
  1. logLevel 将使你对可能出现的任何错误有更多的了解。如果你想看到更多的信息,你可以选择一个更粗略的级别(或者相反)。
  2. securityLevel图源的信任程度有关。如果是编写的内容,那么 ,就可以了。如果是用户生成的内容,最好保留默认的 。"loose" "strict"
  3. theme 改变渲染图表的风格。通过查询首选的颜色方案和利用三元操作符,我们可以适当地指定 。"dark"