dom-mindmap
v0.1.1
Published
An interactive mind map library for the browser
Maintainers
Readme
dom-mindmap
交互式思维导图(Mind Map)浏览器库,纯 TypeScript / DOM 实现,不依赖 canvas / 不依赖前端框架。节点文本由 CSS 控制样式,只有连线用 SVG。
在线演示
为什么不用 canvas
主流思维导图库(mind-elixir、jsmind 等)用 canvas / SVG-text 绘制节点:性能高,但有几个痛点:
- 节点内不能放任意 HTML:图标、表单、按钮、Tooltip、富文本都得自己实现绘制
- 样式靠 JS 计算:改个圆角、改个 hover 颜色都要重画
- 无障碍访问差:屏幕阅读器扫不到节点文本
- 测试困难:很难用常规 DOM 断言
dom-mindmap 反过来:节点用真 DOM 渲染(每个节点就是一个 div),只有连线用 SVG。节点的样式、交互、内容都可以用 CSS / 框架原生方式做,库本身只管理布局、拖拽、缩放、展开收起。
代价:节点数特别多(万级)时不如纯 canvas 高效。但 99% 业务场景(产品脑图、文档目录、知识图谱缩略)都在百级到千级以内,纯 DOM 完全够用。
安装
bun add dom-mindmap使用
import { MindMap } from 'dom-mindmap'
import 'dom-mindmap/style.css'
const mindmap = new MindMap({
container: document.getElementById('app')!,
})
mindmap.data(
{
id: 'root',
label: 'Root',
children: [
{ id: 'a', label: 'A' },
{ id: 'b', label: 'B' },
],
},
false // 默认不展开子节点
)
mindmap.render()
mindmap.fixCenter()懒加载
import type { TreeData } from 'dom-mindmap'
const data: TreeData = {
id: 'root', label: 'API',
children: [
{
id: 'users', label: '用户',
// 没有 children + 有 loadChildren = 出现 + 按钮,点击触发加载
loadChildren: async (data) => {
const res = await fetch(`/api/menu/${data.id}/children`).then((r) => r.json())
return res.items as TreeData[]
},
},
],
}
mindmap.data(data, true)
mindmap.render()加载期间节点旁显示 loading 旋转,加载完成后自动展开。
缩放 / 居中
mindmap.zoom(0.2) // 当前 + 0.2(相对)
mindmap.zoom(-0.2) // 当前 - 0.2
mindmap.zoomTo(1) // 100%
mindmap.zoomTo(1.5, { x: 100, y: 100 }) // 以 (100,100) 为锚点放大
mindmap.fixCenter() // 把根节点居中
mindmap.fixCenter('node-id') // 把指定节点居中(自动展开祖先)
mindmap.fixCenter('node-id', true) // 带动画滚轮缩放默认需要按住 Ctrl / Cmd / Alt。
API
new MindMap(options)
| 选项 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| container | string \| HTMLElement | 必填 | 容器元素或元素 ID |
| width | string \| number | 100% | 宽度 |
| height | string \| number | 100% | 高度 |
| zoomMax | number | 3 | 最大缩放比例 |
| zoomMin | number | 0.4 | 最小缩放比例 |
| panelSize | [number, number] | [20000, 20000] | 画板尺寸 |
MindMap.data(data, defaultExpanded?)
设置思维导图数据。defaultExpanded 默认为 false,根节点始终展开。
MindMap.render()
渲染思维导图。
MindMap.fixCenter(nodeId?, animate?)
将指定节点居中,默认居中根节点。
MindMap.zoom(delta, point?)
相对当前比例缩放。
MindMap.zoomTo(ratio, point?)
缩放到指定比例。
MindMap.registerAction(name, action)
注册右键菜单动作,供 TreeData.actions 中通过字符串引用。
MindMap.destroy()
销毁实例并清理资源。
样式定制
当前样式通过 style.css 中的具体选择器硬编码,尚未提供 CSS 变量。需要自定义时,可直接覆盖对应选择器,例如:
.mindmap-node-label {
background: #fff;
border-color: #d6dde6;
}
.mindmap path {
stroke: #3d5ec2;
}架构
container (用户提供)
└─ box (overflow:auto,承载滚动;监听 mousedown / wheel)
└─ panel (大画板,transform: scale 做缩放;transform-origin: center)
└─ content (节点树容器,垂直居中)
├─ 节点 DOM 树 (递归嵌套 div)
└─ svg (绝对定位铺满 content,画连线)渲染策略:
- 节点用纯 DOM 渲染,浏览器自动算出宽度高度
- 渲染完节点后读取真实坐标,用 SVG path 画贝塞尔连线
- 展开 / 收起 / 懒加载后:重渲该节点 + 整树重绘 SVG path
已知限制
- 节点数过多(万级)会卡:DOM 节点数撑住性能上限。需要超大数据请配合
loadChildren做按需加载,不要一次性塞进children - 暂不支持节点编辑(双击改名):可通过监听节点 DOM 的
click事件自行实现 - 暂不支持节点拖拽移动 / 重排:未来版本规划
- 触屏手势未实现:当前只支持鼠标拖拽和滚轮缩放
- 尚未暴露公开事件 API:
node:click、node:contextmenu、node:toggle等事件暂未实现
开发
# 安装依赖
bun install
# 启动演示
bun run dev
# 构建库(纯 Bun,输出 JS/CSS)
bun run build:lib
# 生成 TypeScript 类型声明(需 Node.js 兼容环境)
bun run build:types
# 构建演示
bun run build:demo
# 类型检查
bun run typecheck发布
发布到 npm 前,请执行 prepublishOnly 脚本,确保同时构建库产物和类型声明:
bun run prepublishOnly
npm publish --registry https://registry.npmjs.org/License
MIT © 2026 Liu Xiaosong
