I open sourced a mind map

Online address: wanglin2.github.io/mind-map/#/…

Warehouse address: github.com/wanglin2/mi…

origin

My initial understanding of mind maps comes from my wife. She likes to use mind maps to record various things. After reading a lot, as a front-end, she will be curious about how this thing is realized. So I searched the Internet and saw an introduction to the basic structure of mind maps—a layout algorithm for logical structure diagrams. Being able to write articles is the biggest motivation for me to do this.

So I started to do it without much thought. After all, I just planned to make a supporting demo for an article at first, which of course brought a lot of problems later.

The basic design is that the core library is implemented using pure js, so that it can be used across frameworks; one main class + several functional classes, through the event mechanism, easy to expand; do not do UI interface things, only do logic, provide relevant APIs for users to call, and then use Vue2+ElementUI to implement the dem o interface.

The main difficulty in the process of doing it is the realization of several layout structures. The layout is actually to calculate the position of all nodes on the canvas. In addition to the idea of ​​the logical structure diagram, which is based on the article on the Internet, it also realizes the mind map, organization structure diagram, and directory organization diagram.

So it didn’t take long, and I finished it and wrote this article on the technical point analysis of Web mind map implementation . Then, the response was very general, so I didn’t write the second part of the plan at the end of the article. This demo will most likely lie in github like other demos and will not be updated again.

So far, as a mind map demo, it can actually be used, but there are two big problems:

1. The performance is very poor, and the operation is very stuck when the number of nodes is too large;

2. The function is very simple and there are many bugs;

The ending is that my wife hates it and continues to use her Xmind.

process

Function

做完后,因为发到了 npm ,并且文档写的还算比较详细,所以时不时会收到一些 star ,但是继续维护是当收到 issue 开始的,收到第一个 issue 还是很激动的,毕竟这代表真的有人在用,虽然我自己都觉得这个东西很草率。

后续就是有人提了 bug ,我就改 bug ,有人提了需求,合理的话,我就加功能,渐渐地,issue 越来越多,有来自国内的,也有来自国外的,于是功能慢慢完整,bug 也逐渐减少。概要、节点拖拽、小地图、水印、关联线、多种节点形状、多种连线类型、导入导出支持 markdown ,xmind、键盘导航、节点富文本编辑、支持触摸事件、支持更多结构等等,你能想到的一个思维导图的功能基本都具备了。

前面提到做之前并没有进行太多思考和设计,于是在功能膨胀的时候,维护就会很痛苦,会感觉代码很乱,内部方法内部变量没有和暴露出去的变量方法做区分,有些类的代码量过于庞大,有些逻辑过于混乱,不够清晰,有些地方实现不合理,总之,问题很多,但是又不愿重构。

其中有一些比较好的建议,比如希望能按需引入一些功能,因为有些场景可能只做一个展示的功能,并不需要各种操作的逻辑,那么引入完整的代码其实没有必要,于是我果断改成了插件化的架构,得益于一个功能一个类和事件机制,改成插件非常简单,不要在主类默认引入所有类,改成按需引入进行实例化就行了,后续新增的非核心功能都可以做成插件,其他开发者也可以开发插件,虽然目前还没有。

又比如支持节点富文本编辑和自定义节点内容,因为实现是基于 svg 的,最初只能给整个节点的所有文本一起应用文本样式,不能针对部分文本,考虑到这也是一个比较实用的功能,于是就尝试用 svg 的 foreignObject 标签嵌入 html 实现富文本展示,使用Quill编辑器实现编辑,这个功能做完后,又想到反正节点中都部分嵌入了 html 了,不如再开放一下,允许整个节点完全使用用户自定义的 html 内容,这个做完后,其实可以大大扩展使用场景,就我自己而言,公司项目里做组织架构图基本上可以百分之九十还原设计稿。

性能

因为众多的 issue ,功能和 bug 的问题已经解决的差不多了,但是还有一个很重要的问题,就是性能。

性能为什么差,原因很简单,因为最初我的做法是把 svg 当 canvas 用,数据驱动视图,数据改变了,就删除所有节点,然后重新创建,这样实现是非常简单,但是根本没法用,毕竟就算用 canvas 你也得做点优化,结果就是几十个节点已经卡的不行了,作为一个 demo 都无法接受,于是我当时做了一定的优化,节选一下我前面提到的文章里的内容:

所以笔者最后采用的方法的是不再每次都完全重新渲染,而是按需进行渲染,比如点击节点激活该节点的时候,不需要重新渲染其他节点,只需要重新渲染被点击的节点就可以了,又比如某个节点收缩或展开时,其他节点只是位置需要变化,节点内容并不需要重新渲染,所以只需要重新计算其他节点的位置并把它们移动过去即可,这样额外的好处是还可以让它们通过动画的方式移动过去,其他相关的操作也是如此,尽量只更新必要的节点和进行必要的操作,改造完后虽然还是会存在一定卡顿的现象,但是相比之前已经好了很多。

进行了这些优化以后,只能说有点用处,但不多,其他很多操作还是需要全量渲染,尤其是常用的前进后退,意味着前进或回退一次,整个思维导图都会清空再重新创建,非常慢,体验很差,于是在用户提了几次这个问题后,我就决定要解决这个问题。

很多问题都是当时想不到,后面就会突然来灵感,也可能是看多了 Vue 虚拟 dom 的 diff 算法,想到 Vue 可以通过 key 来复用节点,那么我是不是也可以根据 id 来复用,于是我创建了一个节点缓存池,将所有创建过的节点实例都缓存起来,然后每次渲染时通过数据唯一的 id 来检查是否存在可复用节点,如果没有,那就代表是新增的节点,创建新节点并添加到缓存;如果有,那么就判断节点数据是否发生了改变,没有改变直接复用,发生了改变那么判断是否可以进行更新,如果更新成本高也是重新创建;另外会创建一个本次渲染的缓存和上一次的缓存,用于找出被删除的节点;当然,为了避免缓存节点数量无限膨胀,也通过 lru 缓存算法来管理。

除了这个大优化,我还仔细阅读和梳理了渲染部分的代码逻辑,然后做了一些小优化,比如改成异步渲染节点,让页面可以在节点渲染时响应其他操作,而不是完全卡死;又比如将渲染任务放到队列中,在下一个事件循环里进行处理,合并掉一些中间状态;又比如避免没有必要的函数调用,因为一些看着没有影响的函数调用也会耗费时间,等等,通过这一系列的优化,卡顿问题有了很大的改善,但毕竟每个节点仍是 dom 元素,所以当节点数量达到一定量级的时候还是会存在问题,但是一个思维导图几千个节点的场景我觉得毕竟是少数,其实已经可以满足绝大部分使用场景,至少后面基本没有用户提到性能的问题。

文档

最开始文档是直接写在 github 的 README 里,因为比较长,所以阅读和查找都非常不方便,于是就准备搞一个文档页面,考虑过使用 VuePress 之类的文档生成器,但我想把文档和 demo 做在一个项目里,所以都不太能满足我的需求,于是打算自己简单设计一个。

首先布局和常见的文档页面一样,上面标题栏,下面分为三部分,左侧是目录列表,中间是文档,右侧是文档的标题列表。

然后支持国际化,因为早期就有人帮我把文档翻译成了英文。

基本实现原理是每种语言一个文件夹,文件夹内是文档,文档用 markdown 来编写,写完后通过 Node.js 使用markdown-it + highlight.js 编译成 html ,最后再拼接成 Vue 单文件:

image-20230720112925872.png

为了在文档里实现在线预览的功能,我还使用了@vue/repl,因为它是把代码数据存储在 url 里,所以很方便,只要使用 iframe 嵌入就 url 就可以了。

接下来就是用 nodejs 遍历文档目录,根据一定规则生成路由列表:

image-20230720141442131.png

最后再把这个路由列表添加到 VueRouter 里即可,实现很简单,效果也不错:

image-20230720142241513.png

定位的转变

最开始的定位是一个纯 js 库,用于帮助和加快思维导图功能的开发,但是在线 demo 功能其实也很完整,当做一个思维导图工具来使用也是完全没有问题的,同时也确实有人在直接用它,于是我就慢慢的去除了贴在它上面的 demo 标签,把项目分成了两部分:

image-20230720143444856.png

虽然目前市面上思维导图的产品很多,百度一下会发现有非常多的选择,但是商业产品,即使最初免费,最终往往也会走向收费,或者对免费版各种限制,要么就是走向倒闭。所以我相信做一个开源的思维导图工具是有一定价值的,即使相比商业软件,有些功能无法实现,比如云端同步、在线协作、手机 APP 等,但是思维导图场景,做一个单机软件也是完全可以接受的。

然后考虑到目前在线版是运行在 github page上,国内访问可能有点慢,同时数据是保存在浏览器的 localStorage 里,如果图片多了,那么是很容易超出存储限制的,于是我就花了几天时间来入门 Electron,最后做了一个简单的客户端,实现过程可以移步这篇文章我的第一个Electron应用

最后,为了看着更正式一点,我又做了一个首页:

image-20230720144505481.png

其实还想过买一个域名,租个服务器,但是要花钱的事情,想了想还是算了,毕竟这个项目可能连这个成本都收不回来。

推广

等到功能差不多稳定了,就会想推广的事情,毕竟做了一个自己觉得不错的东西,还是希望能有更多人能看到和使用,另外就是酒香也怕巷子深,不主动去推广,那肯定没啥人知道,有时看到 github 里其他一些开源的思维导图库,它们有那么多星星,我就很羡慕,虽然各方面都不输它们,但是实际情况就是如此。

关于推广,我实在是没啥好的经验和途径,只做了这些:一是产出思维导图相关的文章,比如遇到一些实现难点或有意思的功能点时会写篇文章,然后发到各个技术社区;二是写纯广告文,发到我的公众号,然后朋友圈分享一下;最后就是去问答社区在思维导图相关的问题下进行推荐。

这些操作下来,效果非常有限。目前想到的就是看看能不能去一些英文社区推荐推荐,如果有这方面经验的朋友,欢迎评论区分享一下~

现状

接下来说一下目前的现状和各项数据,这个项目到目前为止,维护了差不多两年时间,目前一共提交了 500 多次代码,核心库代码量差不多有 1 万多行,star 数量 500 不到,issue 数量 150 多,pr 差不多是 10 个,然后贡献者除了我是 5 个,搞了个交流群,目前有 100 多人,在线版访问次数和客户端下载次数目前没办法统计,最后 npm 的总下载次数是 11000 多次:

image-20230720151452561.png

这个数据虽然非常普通,但也是我所有开源的项目里数据最好的了。

短期的目标是希望 star 数量能到 1k,可能短期也完不成,长期的目标是希望能做成开源界最好的思维导图,不得不说,野心挺大。

收获

技术

技术方面很难量化,你要说它具体给我带来了什么帮助,其实我也说不出来,但是确实比我在公司做的项目要难上很多,很多功能点实现起来也是有点难度的,比如各种布局结构的算法,尤其是鱼骨图,前后做了好几次才做出来,比如一直困扰我的性能优化的问题,比如节点编辑、键盘导航、关联线、支持各种格式的导入导出、在 canvas 中模拟 css 背景属性等等,很多看着简单的功能,实现起来其实都不简单。

所以能给我带来些许安慰,安慰自己是一个有一些能力和技术追求的前端,没有纯粹的混吃等死。

对于找工作的帮助

如果放在前几年可能对于找工作是有一点帮助的,但是目前的环境,它确实没啥帮助,大部分仍旧是已读不回,即使在面试过程中,虽然我表达出了这个项目其实比公司的项目更复杂,但是面试官仍然更想了解在公司所做的项目,公司的项目简单是客观现实,很多时候想通过这些开源的东西来给自己加分,但是基本盘不行,其实也改变不了结局,所以还是要想办法挖掘公司项目的亮点。

另外即使你东西做的好,你也得表达的好才行,于我而言,东西就摆在这里,代码、demo,你完全可以看的到,但是于面试官而言,他可能并没有那么多时间去看,很多东西在他眼里也并不难,所以你得清晰的表达出你的东西的亮点和难点,因为大部分时候,你表达不出来,那就相当于没有。

¥收益

绝大部分的开源项目想要赚钱我觉得都是很困难的,所以我也没抱什么期望,但是目前我也在 README 和文档上挂了打赏的二维码,还是有一些热心的朋友,偶尔喝杯咖啡的钱还是够的。

其实这也是我想推广的原因之一,毕竟用户基数大了了,愿意给你打赏的人的比例肯定也会增加。

心得

最后就是一些琐碎的心得。

1.翻译真的很累,目前基本上是使用机翻,即使这样我也觉得累,以后再也不吐槽其他开源项目没有中文翻译了。

2.不要把用户想的什么都知道,以前总觉得为什么其他产品的帮助文档要写的这么详细,明明很多一看就知道的功能也要写,但实际上,很多人他就是不知道,比如 Windows 系统该下载什么后缀名的文件,Mac 系统该下载什么,有人他就是不知道,所以不要想当然,有精力的情况下还是尽量要完善文档,除了开发文档,使用文档也是必不可少的。

3.很多问题没做之前觉得很复杂,等你开始做,发现是有点难度,但其实远远没有你想象的那么难,比如小地图、关联线、节点形状、Xmind 格式导入导出等等,最开始都觉得好复杂,不想做不想做,最后做出来发现也就这样,所以勇敢的迈出第一步把。

4.很多问题当时想不出来,怎么都想不出来,不妨放一放,过一段时间再来做,你会发现可能会突然灵光乍现,然后就顺利解决了,比如性能优化、鱼骨图的实现等等,我都是尝试一次做不出来,那就过段时间再试,因为短时间,你可能都是同一种思维,跳不出去,那么就很难解决。

5.开源项目的协议很重要,一定要显式的指定。

6.有些功能是要进行取舍的,比如最开始支持节点的过渡动画效果,也就是节点位置变化了是会移动过去,而不是直接闪现过去,但是一直有 bug 解决不了,就是快速操作的话,因为上一次节点的移动还没有结束,又开始下一次,导致节点位置错乱,这个问题尝试了很多次都无法彻底解决,于是最后就舍弃了,因为它只是一个锦上添花的功能,但是带来了显式的 bug ,那么还不如不要。

还有一个例子就是节点激活的样式,最开始所有样式都支持设置为激活的样式,包括一些会改变节点大小的样式,比如文字大小,这样会导致激活节点操作也要重新渲染节点所有内容,计算节点大小,调整其他节点位置,导致性能很差,全选非常慢,所以考虑过后,激活样式只允许修改不影响节点大小的属性,这样舍弃的只是一个不是很重要的功能,但是带来的好处是很明显的,现在全选非常的快。

7. A person’s strength is limited. For example, there is a problem I have been unable to solve, which is to zoom the canvas with the specified center point. Later, a netizen helped me solve it successfully. The code he submitted was actually very simple, but I couldn’t figure it out after thinking about it many times. For example, I didn’t support exporting Xmind files at the beginning, because after I tried it, I found that the Xmind software could not be opened after decompressing and compressing the Xmind file. , Later, a person in the group found out that the reason was that the folder could not be compressed after decompression, but the file had to be compressed, so don't underestimate the power of cooperation.

8. Maintaining an open source project is really exhausting. You have to solve and answer all kinds of questions. Some people come up and ask you this and that. Obviously, there are some problems that you only need to try a little more. You can find out by reading the document, or you can solve the problem with Baidu. Of course, if you are willing to give him a little reward first, I believe he will be happy to solve your problem.

that's all.

Guess you like

Origin juejin.im/post/7257922419319406648