跳转到内容

思维导图

下载 .tgz
版本v0.1.0
大小133 KB
分类文档
平台全平台
运行方式纯前端(无独立进程)
下载量2
标签mindmap · 思维导图 · 脑图
SHA-256f34b646d5addc48aa4f65845810a7b19bc8bc297e0a2697d98876d5cc5843898

思维导图插件(simple-mind-map,非内置,市场化按需安装)。UI 是纯 TypeScript (没有框架)——插件机制不挑框架:画板是 React、这个是 vanilla、宿主是 Vue。

为什么是 simple-mind-map

先做的 mind-elixir 版本被用户一句话否了:「不能放在节点上拖动」。mind-elixir 是纯自动布局,拖节点只能改父子关系、不能挪位置。simple-mind-map 有 enableFreeDrag——节点直接拖到想放的地方,坐标记在节点自己的 customLeft/customTop 上、随内容一起存。代价是它是引擎不是 App:工具栏、 菜单一概没有,得自建(本插件那条工具栏就是)。

提供什么

  • 文件类型 xinghan.mindmap::mind(.mind,storage:‘text’):整块编辑区一张 导图。存 simple-mind-map 官方结构 {root, layout},导出/换渲染器/拷进别的 simple-mind-map 应用零转换。
  • 字段类型「思维导图」(typeKey mindmap,基础类型 text,「插件字段」组): 单元格里放一张导图 —— 双击弹 1120×680 模态框,显式「保存」才回写(不保存不 落库),⌘S 同样保存。cell 值 {"summary":"产品规划 · 12 个节点","doc":{…}}, summary 首键(baseType=text 靠它排序),宿主 summaryPath 投影到网格与未装插件 端;doc 与 .mind 文件同构,字段与文件之间整份可互拷。maxBytes 1MB。
  • 自建工具栏:撤销/重做 · 插入子节点/同级/删除 · 格式刷/概要/关联线/外框 · 图标/备注/标签/超链接/图片 · 结构 · 自由拖拽开关 · 配置侧栏 · 禅模式 · 适应画布/缩放。图标按钮都带自绘 tooltip(名字 + 快捷键)。
  • 右侧配置侧栏(对齐官方 demo 那一栏,六块共用一栏、顶部标签切换): · 节点样式:形状/字体/字号/粗斜下划删除线/文字色/填充与渐变/边框色·粗细·线型/ 圆角/内边距,多选时逐个下发 · 基础样式:画布背景、连线风格·颜色·粗细·折线圆角·箭头、二级与子级节点间距、 关联线与概要连线样式 · 主题:官方主题包 57 套(simple-mind-map-plugin-themes)+「跟随宿主」。 预览卡片是用主题自身配置画的 CSS 缩略图 —— 官方封面图有 636KB,不进产物 · 结构:9 种布局的 SVG 缩略图画廊 · 大纲:整棵树可直接改文字,点行跳到画布节点 · 设置:自由拖拽、鼠标滚轮、展开按钮常显、新建节点行为、按键即进入编辑 (本机偏好,不落盘) 快捷键走库自带:Tab 子节点、Enter 同级、Delete 删除、⌘Z/⌘⇧Z 撤销重做、方向键 导航(KeyboardNavigation 插件)。
  • 保存语义同画板:改动 → 10s 防抖自动保存(文件视图);⌘S 立即落库 + toast; 页面隐藏/卸载 flush;「改了没」以内容签名为准 —— 平移缩放、换主题都不标脏, 撤销回落库态自动归位「已保存」。
  • 主题跟宿主日夜实时切(根节点用品牌色 --ring,卡片/边框用 --card/--border); theme 与 view 都不落盘:它们是渲染态,写进文件会串味、还会让「拖一下画布」 变成一次内容改动。
  • 产物:JS ~370KB(gzip 107KB),无字体无 CDN,离线可用。

结构

plugin.json            # fieldTypes: mindmap / fileTypes: xinghan.mindmap::mind (icon network)
ui/src/
  mind/codec.ts        # 文件内容解析/序列化 + 内容签名(只留 root+layout)
  mind/cellValue.ts    # 字段 cell 值编解码 + 摘要文本(根标题 · N 个节点)
  mind/theme.ts        # 宿主 shadcn token → simple-mind-map themeConfig
  MindCanvas.ts        # 共用画布外壳:引擎实例 + 自建工具栏
  MindApp.ts           # 文件视图:加载 + 10s 防抖自动保存 + 状态条
  MindFieldApp.ts      # 字段编辑器:模态框内,显式保存 resolveModal
  main.ts              # hash 路由:#/field=字段编辑器,其余=文件视图
  lib/host.ts          # 宿主桥(与其它插件同模式)

节点图片是一进一出两道(mind/assets.ts):落库存 xh-asset://<ref>,但 SVG 的 <image> 加载不了这种协议 —— 直接存引用会渲染成裂图(用户实测)。所以加载 时 hydrate(readAsset → blob URL 交给引擎),保存时 dehydrate(blob → 引用), getDoc() 出口统一换回引用形态,签名/落库/cell 值三处一致,不会因为 blob URL 每次都不同而把「没改过」判成脏。

两步操作的三个工具(格式刷 / 关联线 / 外框)必须有反馈,否则第一下点击看着 就是「没反应」(用户实测点名):进模式后按钮点亮 + 画布顶部常驻提示 + Esc 取消; 模式是否还在只有引擎知道(连线完成、点空白退出格式刷都不发我们能听的事件),所以 每次交互后照 painter.isInPainter / associativeLine.isCreatingLine 对账一次。 外框还有个上游坑:addOuterFrame 会把根节点过滤掉 —— 只选根节点时它静默什么都不 做,我们提前拦下来给提示。连线完成时上游会往控制台丢一条 Cannot read properties of null (reading 'uid')(它自己的 creatingStartNode 清空 时序问题),不影响结果。

别再试的两条路(都踩过):在 node_tree_render_end 里逐节点 setStyle 上 分支色 → 再触发渲染 → 栈溢出;官方 RainbowLines 插件把颜色写进节点数据还 addHistory → 一打开文件就被标脏。真要彩虹分支,得当作「用户显式选的内容」做。

协同 v1 单机(最后保存者赢);升级位:PluginRoom 中继广播节点操作。 未装插件兜底:宿主默认文本编辑器打开原始 JSON,数据不锁死。

开发

pnpm --filter @xinghan/plugin-mindmap typecheck
pnpm --filter @xinghan/plugin-mindmap test
pnpm --filter @xinghan/plugin-mindmap ui:build
node scripts/plugin-install-local.mjs packages/plugins/mindmap   # 装进 ~/xinghan/plugins

脱宿主自查:ui/dist/index.html?xhDebug=1&xht=dark 直接开(空图、不落库,状态机 照跑),配 playwright 探针量交互最快。

怎么安装

  1. 下载安装包 —— 点上面的按钮拿到 xinghan.mindmap.tgz。要在内网用,就把这个文件拷进去。
  2. 打开客户端 —— 右上角 插件市场 → 右上角 「从本地安装」。
  3. 选中文件 —— 解包到 ~/xinghan/plugins/ 后热加载,不用重启应用。

完整的内网 / 离线说明见 离线与内网安装。