简介:这是一款为 Draw.io 桌面版量身打造的 Mermaid 图表生成插件,面向需要在绘图工具中快速绘制流程图、时序图、甘特图、状态图、类图和饼状图的开发与文档工程师。插件以 JavaScript 编写,安装后可直接在 Draw.io 形状中编写 Mermaid 脚本,双击编辑、失焦重绘,并将配置项映射为形状属性,方便低代码方式维护复杂图表。对于需要频繁维护架构图、项目排期图或接口时序图的团队,能显著减少重复排版工作量。资源压缩包约 1.98MB,共 45 个文件;其中 8 个 mmd 示例脚本、5 个 js 源码、2 个 ts 类型文件、3 个 drawio 演示文件,另有 png/gif 预览图、md/json/yml 配置与文档等,目录区分 vscode 插件扩展与 drawio_desktop 桌面插件场景,便于二次开发和迁移。已有 1296 人学习下载。对希望提升 Draw.io 自动化绘图效率、或研究 Mermaid 集成方案的开发者,这是一份可直接运行并参照改写的完整插件模板。
1. 给 Drawio 桌面端插上 Mermaid 引擎:一个插件把两个画图世界打通
Mermaid 是用文本描述图表的那套语法,Drawio 是桌面端最顺手的画图工具,而 drawio_mermaid_plugin 要做的,就是让这两者在一份文档里直接对话:在 Drawio 里打开插件对话框,粘贴一段 Mermaid 代码,点一下生成,一张可编辑的矢量图就落到当前画布上。以前从 Mermaid 代码到 Drawio 图形,中间隔着截图、导出、手动重画三条路,每一步都在丢矢量信息和时间成本。这个插件把链路压成一步,特别适合两类人:一类是文档里已经堆了大量 Mermaid 代码、想继续在 Drawio 里做精细排版的人;另一类是对 Mermaid 语法熟悉、但不想把 Drawio 的工具栏从头学一遍的新手。下面从加载机制、实际接入、踩坑和定制四个角度把它拆开讲透。
2. 从加载到渲染:先弄清这个插件在 Drawio 里的运行骨架
用插件的抱怨大多出在同一个地方:不知道它是什么,所以出了问题也不知道该查哪。Drawio 桌面版本质上是 Electron 打包的网页应用,插件系统允许你在启动时挂一段自定义 JavaScript,通过钩子函数往菜单、右键菜单和画布事件里塞东西。这个 Mermaid 插件的整体思路就是:启动时注册一个菜单入口,点击后弹出一个输入框,把用户粘贴的 Mermaid 文本交给渲染器,生成图片对象后插入当前文档页。全程不依赖外部网络,也不开新窗口,所有动作都发生在 Drawio 自己的运行时里。
2.1 插件的本质:Drawio 的插件系统与入口函数
要理解它怎么工作,先要接受一个事实:Drawio 的插件不是一个安装包,就是一个 JS 文件。这个 JS 文件在启动时被 Drawio 运行时扫描并以某种方式加载。常见做法是在Extras → Plugins菜单里把文件路径加进去,下次启动自动加载。插件脚本里暴露一个构造类,类里面带上init、destroy之类的方法,Drawio 在初始化阶段找到入口函数后调用它,同时把editorUi这个上下文对象传进来。拿到了editorUi,就等于拿到了访问菜单栏、工具栏、当前画布编辑器的钥匙。
从我平时读这类插件源码的顺序来看,第一步一定是找构造函数里做了什么。比如这个 Mermaid 插件,构造函数里大概率会做三件事:调用父类初始化、注册菜单项、定义渲染相关的回调函数。第二步是看它注册菜单时用的哪个 API,因为不同版本的 Drawio 对addMenuItem的支持有差异,版本不对会让菜单压根不出现。最后才是看渲染部分,因为那一块决定了一张图从文本到画布经历了什么。
2.2 渲染管线:Mermaid 代码到图形要经过哪几层
从一段 Mermaid 文本变成 Drawio 画布上的图形,中间是一条固定的管线:代码输入 → 安全校验 → 语法解析 → 渲染成 SVG → 转换成 Drawio 可识别的图片数据 → 插入画布。每一层都有单独出问题的可能。
安全校验这层很多人会忽略。Mermaid 的securityLevel参数默认是strict,它会在解析阶段过滤掉带有脚本风险的内容。如果插件作者为了方便把securityLevel设成了loose,一旦代码来源不可控,XSS 风险就直接进到 Drawio 文档里了。我见过某团队内部把插件改成loose之后,一张流程图里的 link 属性就带了一个可执行的javascript:伪协议,虽然没出大事,但这种默认行为不该被轻易关掉。
解析和渲染是 Mermaid 库自己的职责。插件调用mermaid.parse检查语法,再调用mermaid.render得到 SVG 字符串。这步完成后再做一次格式转换:把 SVG 的字符串编码成 data URI,交给 Drawio 的图片创建接口。这儿的坑在于 SVG 本身有宽高和 viewBox 的概念,如果插件在插入前没有正确设置尺寸,Drawio 会把图片按默认尺寸丢进来,出现缩放比例异常。
2.3 源码走读:入口脚本、构建产物与资源文件
这类插件的目录结构一般分四块:源码目录、构建配置、产物目录和说明文档。源码目录里通常有一个入口脚本负责插件生命周期,另外会有一个对话框页面或者用 JS 动态创建 UI 的实现。构建配置一般是package.json里的一段build脚本,把入口文件连同 Mermaid 库一起打包成一个独立 JS 文件,输出到build目录。Drawio 最终加载的是这个打包产物,不是源码。
我看别人的插件项目,习惯先打开package.json看用了哪些依赖。如果它把 Mermaid 打进产物,说明离线也能跑;如果它走 CDN 动态加载,那离线环境就会直接空白。这个插件从使用场景看,应该是打包进产物里的,因为 Drawio 桌面版大多是内网或离线环境在使用,硬依赖 CDN 等于自断后路。打包产物本身也不要改动,改源码后重新构建比直接在产物上改可靠得多,否则下次构建又把你手工加的东西清掉了。
3. 动手接入:从 Clone 项目到画出第一张 Mermaid 图
理论讲得再多,不如自己跑一次。这一章按实际操作路径走一遍,目标是让插件在你的 Drawio 桌面版上正常工作,并画出第一张流程图。全程大概需要二十分钟,大部分时间花在环境检查和构建上。
3.1 环境准备:Node 版本、Drawio 桌面版与 JDK
先看依赖。构建插件用的 Node 版本建议 16 以上,太老的版本在打包 Mermaid 时会语法报错。我自己的习惯是先跑一次node -v,如果不满足就直接用nvm切到合适的版本,避免在环境问题上浪费时间。
然后是 Drawio 桌面版。插件加载的机制在近几个大版本里没怎么变过,但是太老的版本缺少插件 API 的某些方法,导致加载时报undefined is not a function。我一般会建议至少使用当前主流稳定版本,具体版本号不重要,重要的是抽屉菜单里能看到Plugins这一项。确认之后,按下面顺序操作:
git clone <项目仓库地址> drawio-mermaid-plugin cd drawio-mermaid-plugin npm install npm run build构建完成后,检查build目录下是否生成了一个独立的.js文件,文件名一般是drawio-mermaid-plugin.js这类。如果构建报错,八成是 Node 版本不匹配或者某个依赖安装失败,先看控制台输出的错误指向哪个模块,再去补装。
3.2 最小示例:三步插入一张流程图
构建好之后,把插件文件加载进 Drawio。路径是Extras → Plugins → 添加,选中build目录下生成的 JS 文件,然后按提示重启软件。重启后新建一个空白文档,打开Extras菜单,应该能看到多出一个 Mermaid 相关的菜单项。
点击菜单项,弹出对话框,粘贴下面这段最基础的流程图代码:
graph LR A[需求提出] --> B{可行性评估} B -->|通过| C[进入开发] B -->|不通过| D[退回补充]点击生成或插入按钮,画布上会出现一张带两个分支的流程图。到这一步,说明插件的主链路已经通了。这个最小示例的意义在于:它覆盖了输入、解析、渲染、插入四个关键环节,如果哪一环断了,图不会完整出现,而且大概率可以在开发者工具里看到对应的报错信息。
3.3 可调参数:主题、方向、缩放与代码安全
插件能跑通之后,建议把精力放在参数调优上。Mermaid 的渲染行为集中在初始化配置里,常见做法是插件入口处有一段这样的配置:
mermaid.initialize({ startOnLoad: false, theme: 'default', // default / forest / dark / neutral securityLevel: 'strict', flowchart: { curve: 'linear', // basis / linear / monotoneX htmlLabels: false }, fontSize: 14 });theme控制整体配色,dark适合深色文档,forest的绿调比较适合技术绘图。curve控制连线的弯曲方式,linear是直线折角,basis是平滑曲线,这个看你的绘图习惯。htmlLabels我建议保持false,因为开启后标签里的 HTML 可以直接执行,和 Drawio 文档的 XML 结构叠加容易产生解析冲突。真正要谨慎的是securityLevel,保持strict不动,除非你确认所有 Mermaid 代码都来自可信来源。
4. 避坑记录:渲染空白、乱码、失真的四类翻车现场
这一个插件我在不同机器和不同版本组合下跑过不少次,踩过的坑大致集中在四类。写出来按「现象 → 原因 → 解决」排列,适合直接对照排查。
4.1 图形空白:解析失败时到底该看什么
现象是点击插入后,画布上出现一个空对象,里面什么内容都没有。第一次遇到时很容易去翻 Drawio 的配置,实际上问题往往出在更早的环节——Mermaid 解析。
原因大概率是代码里有语法错误,或者插件的错误提示没有正确回传。我见过更隐蔽的情况:代码里包含了一个插件作者没预料到的字符组合,Mermaid 解析器静默失败,没有抛异常,也没有返回 SVG。
解决的第一个动作是打开开发者工具。Drawio 桌面版基于 Electron,直接按Ctrl+Shift+I就能看到 Console 面板。插件在调用mermaid.parse时如果失败,一般会把错误console.error出来,那行报错会直接告诉你解析失败的具体行列位置。我一般的排查顺序是:先把代码粘到 Mermaid 官网的在线编辑器跑一遍,确认语法没问题;再在插件的对话框里点预览(如果插件有预览功能);最后才去动代码逻辑。
4.2 中文变方块:字体、Markdown 与 HTML 标签
现象是图形结构正常,但所有中文字符都显示成方框。这不是 Drawio 的问题,是 Mermaid 渲染 SVG 时的默认字体栈不包含中文字体,导致字体回落失败。
原因有两条路可走:一条是 Mermaid 初始化参数里设置fontFamily,指定带上中文字体的优先列表;另一条是注入全局 CSS,覆盖 SVG 内部的字体声明。我更推荐前者,因为直接写在初始化逻辑里,改一处就全局生效。
fontFamily: 'PingFang SC, Microsoft YaHei, Noto Sans SC, sans-serif'如果你用的 Drawio 文档里混排了图标、公式或者特殊字符,还有可能遇到第二层问题:某些字符在字体层面能显示,但在关系到图片编码格式时丢失。这种情况比较少见,遇到就不要纠结,先确认系统确实装了对应字体,再用上面这段配置做一次渲染对比。
4.3 导出模糊:scale 与像素比设置
现象是插入的图在画布上正常,一旦放大或者导出成 PNG,边缘明显发虚,文字糊成一片。
原因分两类:一类是插件把图以位图形式(比如 PNG data URI)插入,位图本身没有矢量特性,放大自然糊;另一类是虽然用了 SVG 格式,但渲染时设置的默认尺寸和实际 viewBox 不匹配,导致显示被拉伸。
解决要看插件支持的图片类型。我一般会优先选 SVG 形式插入,Drawio 支持把 SVG 的 data URI 当图片对象放进来,放大不丢细节。如果插件设计上强制走位图,那要找到渲染阶段设置scale参数的位置。这个参数决定 SVG 转为位图时的采样倍率,从 1 调到 2,导出清晰度会有肉眼可见的提升,代价是文件体积变大。如果插件里没有暴露这个参数,那就直接在源码里把默认值改掉,重新构建。
4.4 插件加载失败:桌面版升级后的兼容问题
现象是升级 Drawio 桌面版之后,菜单入口消失,或者在启动时直接报 JS 加载错误。
原因是 Drawio 的插件 API 在版本升级时有过调整,老插件调用的一些 DOM 节点结构变了,或者某个方法名被修改。插件加载过程本身也有坑:插件文件路径里如果带中文或者特殊字符,Electron 的文件读取会出问题,插件在启动时静默失败。
解决的顺序是:先确认路径没有中文,把插件文件放到一个纯英文目录再试。如果路径没问题,就打开开发者工具,切到 Console 看启动时的报错。大多数情况会指向一个具体的方法名或属性名,顺着这个报错去插件源码里搜对应的调用位置,替换成新版本的 API 写法,重新构建。插件的兼容性维护其实不复杂,核心是每次桌面版大版本升级后,第一时间做一次启动验证。
5. 定制改造:换主题、换渲染器、加图表类型的正确姿势
插件跑顺只是开始,真正让它贴合自己的使用习惯,需要动源码重新构建。这一章讲三个最常用的改造方向:修改初始化参数、注入自定义样式、处理不同图表类型的尺寸适配。
5.1 修改初始化参数:从 mermaid.initialize 入手
所有和渲染风格相关的配置都在mermaid.initialize里。全局主题切换最直观,theme换成dark或forest立竿见影,但要精确控制颜色,得用themeVariables:
mermaid.initialize({ startOnLoad: false, theme: 'dark', themeVariables: { primaryColor: '#42b883', primaryTextColor: '#1a202c', primaryBorderColor: '#2d3a4b', lineColor: '#5b7a9d', secondaryColor: '#35495e', fontFamily: 'PingFang SC, Microsoft YaHei, sans-serif' } });primaryColor是节点主背景色,lineColor是连线颜色,secondaryColor常用于分支或旁路节点。我一般会先在小范围验证一遍配色,再固定到源码里,因为 Mermaid 主题变量的层级在不同版本略有差异,直接改完构建后如果没生效,先看是不是变量名不对。
5.2 注入自定义主题与 CSS
初始化参数能覆盖的颜色有限,真要动连线样式、标签字体大小、节点圆角这些细节,得在渲染完成后操作 SVG 的 DOM。Mermaid 的render回调拿到的是 SVG 字符串,把它转成 DOM 元素,再改样式,最后再转回字符串插入画布。常见做法是这样:
const svgStr = await mermaid.render('graphDiv', code); const doc = new DOMParser().parseFromString(svgStr, 'image/svg+xml'); const svgEl = doc.documentElement; // 统一调小标签字号 svgEl.querySelectorAll('.edgeLabel').forEach(el => { el.style.fontSize = '12px'; }); svgEl.querySelectorAll('.node rect').forEach(el => { el.setAttribute('rx', '6'); el.setAttribute('rx', '6'); }); const finalSvg = new XMLSerializer().serializeToString(svgEl);注意new DOMParser().parseFromString在 Electron 的渲染进程里是可用的,不需要额外引入解析库。这种改法比在 Mermaid 配置里硬调样式更灵活,因为你能精准选中某个 class 或某个标签做覆盖。.edgeLabel是 Mermaid 给边标签生成的 class,.label一般出现在节点内部文本容器上。
5.3 图表类型扩展:Flowchart、Sequence、Gantt 在 Drawio 里的表现差异
Mermaid 本身支持流程图、时序图、甘特图、类图、状态图等多类图表,但放进 Drawio 之后表现差异很大。流程图和状态图是横向或纵向展开,插入后手动拖一拖就对齐了。时序图默认方向是纵向渲染,如果参与者太多,容易超出画布可视范围,这种我会在 Mermaid 代码里显式声明direction LR,把纵向改成横向,插入后比例更自然。
甘特图是重灾区,因为它的时间轴天然很宽,渲染出来的 SVG 往往是标准画布的好几倍宽。插件插入时如果按原始尺寸放,画布会瞬间多出一个巨大的对象。处理办法有两个:一个是在插件插入逻辑里对宽高做一次缩放,比如超过某个阈值就统一按原始尺寸的 80% 缩;另一个是在 Mermaid 代码层面控制gantt图的日期范围粒度,减少时间跨度。后一种改的是图的逻辑,治本;前一种改的是视觉比例,治标。
另外说一类图表:类图。Mermaid 的 classDiagram 生成的节点形状和 Drawio 原生 UML 类的填充方式不一样,插入后如果还想继续编辑节点属性,得先在 Drawio 里把图片转为可编辑图形。这个过程会丢失部分 Mermaid 的样式,属于格式转换的固有限制,不要试图通过改插件完全消除。
6. 保留可编辑性的技巧:让 Mermaid 源码随图走
插件生成的是图片对象,图片放进画布后,源码只存在于插件对话框的内存里,文档保存后它就丢了。等到下次想改图,只能凭记忆重新输入一遍 Mermaid 代码,这个体验相当糟糕。我的习惯是让源代码跟着 Drawio 文档一起存下来,做法是把 Mermaid 代码写进单元格的自定义属性里。
// 插入图片对象后,把源码编码后挂到 cell 属性上 img.setAttribute('mermaidSource', encodeURIComponent(code));encodeURIComponent这一步不能省,Mermaid 代码里往往有#、>、{这些特殊字符,直接存进 XML 属性会造成文档结构解析错误。挂在 cell 属性上之后,.drawio文件里会多出一段自定义属性,下次打开文档时这段代码依然在。要再次编辑,只需要在插件里注册一个右键菜单项,读取选中图形的mermaidSource属性,解码后回填到对话框里,重新渲染替换原图。
这样做的额外好处是文档可追溯。同一张图,不同版本之间的 Mermaid 代码差异可以直接用文本 diff 工具对比出来,比对着截图回忆改了什么要可靠得多。我现在每张用插件生成的图都会强制走一遍这个属性挂载流程,对话框里渲染成功的第一件事不是插图,而是先把源码写进 cell。将来团队里有人接手这张图,看到属性面板里的mermaidSource,马上就能知道这个图形的逻辑源头在哪里。希望这个习惯也帮到你。
本文还有配套的精品资源,点击获取