学习过程中有一张PPT上的内容是以思维导图的形式存在的,也确实应该这样记,于是我开始寻找如何在hexo中插入思维导图,但折腾一圈没太合适的,最后我基于markmap和另外几个markdown的库整合了一下做了一个简单的hexo导图插件。

效果展示

{"t":"heading","d":1,"p":{"lines":[0,1]},"v":"思维导图?","c":[{"t":"heading","d":2,"p":{"lines":[1,2]},"v":"使用现有的插件或组件?","c":[{"t":"heading","d":3,"p":{"lines":[2,3]},"v":"Mermaid:更偏向流程图"},{"t":"heading","d":3,"p":{"lines":[3,4]},"v":"Kityminder","c":[{"t":"heading","d":4,"p":{"lines":[4,5]},"v":"现成hexo插件有些小问题。"},{"t":"heading","d":4,"p":{"lines":[5,6]},"v":"二次开发,失败"}]}]},{"t":"heading","d":2,"p":{"lines":[6,7]},"v":"找寻相关项目?","c":[{"t":"heading","d":3,"p":{"lines":[7,8]},"v":"Markmap大法!","c":[{"t":"heading","d":4,"p":{"lines":[8,9]},"v":"直接弄,失败"},{"t":"heading","d":4,"p":{"lines":[9,10]},"v":"使用jsdom,失败"},{"t":"heading","d":4,"p":{"lines":[10,11]},"v":"寻找现成库,成功"}]}]},{"t":"heading","d":2,"p":{"lines":[11,12]},"v":"咕咕咕咕咕咕咕咕咕咕咕咕"},{"t":"heading","d":2,"p":{"lines":[12,13]},"v":"凑一下行数让版面好看点"}]}

本插件已经发至Github与NPM,使用npm install hexo-markmap安装,具体见Github的README哦~

脑 洞 大 发

一开始想到了mermaid,但是他更偏向于流程图之属性,也找到了有其他大佬基于百度的kityminder开发的hexo-simple-mindmap,但是和我的需求还是有点差异,本来想自己试试能不能基于kityminder二次开发呢,经过尝试后发现并不行,也许是我比较垃圾吧。。不过说真的kityminder的文档真的……一言难尽。

最后我发现了Markmap这个好东西,其实就是Markdown+mindMap组合的一个词,目的也和我想达到的效果一样,然而应用就让我折腾了好久,作为小白渣渣的我不禁一直怀疑人生……根据官方文档的提示,实现我们想要的效果需要他的两个组件:

{"t":"heading","d":1,"p":{"lines":[0,1]},"v":"Markmap","c":[{"t":"heading","d":2,"p":{"lines":[1,2]},"v":"markmap-lib:转换MD格式到插件格式"},{"t":"heading","d":2,"p":{"lines":[2,3]},"v":"markmap-view:展示成文字"}]}

那就用呗,那咋用啊,根据官网的提示,你需要搞这两步:
先引入lib,然后再转换markdown格式,获取assets
1
2
3
4
5
6
7
8
9
10
11
12
import { Transformer } from 'markmap-lib';

const transformer = new Transformer();

// 1. transform markdown
const { root, features } = transformer.transform(markdown);

// 2. get assets
// either get assets required by used features
const { styles, scripts } = transformer.getUsedAssets(features);
// or get all possible assets that could be used later
const { styles, scripts } = transformer.getAssets(features);

把上一步的结果拿过来,然后引入view库渲染。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// load with <script>
const { markmap } = window;
// or with ESM
import * as markmap from 'markmap-view';

const { Markmap, loadCSS, loadJS } = markmap;

// 1. load assets
if (styles) loadCSS(styles);
if (scripts) loadJS(scripts, { getMarkmap: () => markmap });

// 2. create markmap
// `options` is optional, i.e. `undefined` can be passed here
Markmap.create('#markmap', options, root);

所以其实我的思路也应该很清晰了,就是把这些玩意封装出来,暴露一下传入markdown的接口,然后返回或创建思维导图就行了。

但是我觉得这样不好(我是sb……)。

因为作为生成网页为核心的Hexo,我相当于把这些工作都交给客户端去做了,那这样首先多引入了3个文件(markup-lib,markup-view,还有他们的底层支持d3js)

而且因为我要封装,肯定还会有一个文件以及n多处理。

因此我想到了一个·绝·妙·的·想·法·,为什么不能让本地生成出来svg,然后直接交给网页呢,顶多留一个js做一些放大缩小的处理等等。

但是这玩意似乎也没给啥这样的说法,并且他对于这两个部分的模块的文档仅仅只有上面这两段代码(好熟悉的感觉……)

峰 回 路 转

所以我就简单想了一下思路,我可以利用jsdom来搞一个,这玩意就相当于node环境下一个模拟的无头浏览器。

but经过多次尝试,可能是因为异步引入文件的原因总是无法引用想要的东西……于是放弃……

只能回来到刚开始的地方了,就按照原先的方法按部就班吧!然鹅不知道我当时咋想的写了一个异常不优雅的写法……

简单来说就是把标签的内容传给这边后,拼装成一个createMap(contents)的函数,插入到html中……然后再通过路由引入我封装好的js进行绘制。

异常不优雅……于是我也不想继续完善了,就另辟蹊径吧……其实也没辟到啥蹊径,最后找到了markdown-it-markmap

他相当于给markdown-it这个md解析器加了一个能解析为markmap格式的解析器,这样我们解析的部分就能放到后端进行了。

然后根据他的说明简单引入一下文件就完事儿了。

1
2
3
4
5
6
7
8
9
<script src="https://cdn.jsdelivr.net/npm/d3@5"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-lib@0.7.4/dist/browser/view.min.js"></script>
<script>
const mindmaps = document.querySelectorAll('.markmap-svg');

for(const mindmap of mindmaps) {
markmap.markmap(mindmap, JSON.parse(mindmap.innerHTML));
}
</script>

所以最后折腾半天还是成为了调包侠

唉就这样吧,反正写出来了,又不是不能用.jpg。