@lingkkkk/atlas-mindmap 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PERFORMANCE.md +159 -0
- package/README.md +161 -0
- package/dist/index.cjs +2048 -0
- package/dist/index.css +237 -0
- package/dist/index.d.ts +486 -0
- package/dist/index.global.js +2053 -0
- package/dist/index.js +2035 -0
- package/package.json +43 -0
package/PERFORMANCE.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Atlas Mind Map 性能测试与技术评审报告
|
|
2
|
+
|
|
3
|
+
> 包:`@lingkkkk/atlas-mindmap@0.1.0`<br>
|
|
4
|
+
> 原始数据生成时间:2026-08-29T12:24:30.479Z<br>
|
|
5
|
+
> Schema:v2 · Commit:`733e4467c800643b6551f4adfc7d1129559d08ca`
|
|
6
|
+
|
|
7
|
+
## 执行摘要
|
|
8
|
+
|
|
9
|
+
本次在真实有界面 Chromium 中完成 9 个规模的生产构建测试,成功测得的最大规模为 **100,000 个节点**。全部请求规模均成功完成,没有浏览器崩溃、fixture 数量错误或控制台错误。
|
|
10
|
+
|
|
11
|
+
最大规模 100,000 节点:启动同步阶段判定 **阻断**;启动 GC 后 JS heap 29.72 MB;全图 Fit 47.6 FPS / 帧 P95 33.21 ms,判定 **可用**;100% 聚焦编辑 116.7 FPS / 帧 P95 10.51 ms;样式同步 mutation P95 0.47 ms、mutation 至渲染帧 P95 9.03 ms,文本更新 P95 46.97 ms,拖拽改父级成功。聚焦交互判定:**流畅(未见明显卡顿)**;跨启动/总览/交互的总体判定:**阻断**。
|
|
12
|
+
|
|
13
|
+
启动阻断规模:50,000、100,000;聚焦交互“降级”规模:无;聚焦交互“阻断”规模:无;总体阻断规模:50,000、100,000。启动阻断不等于进入画布后的拖拽卡顿,两者必须分开评审。结论只适用于下述机器、浏览器、视口与数据形状,不外推为所有终端的通用 SLA。
|
|
14
|
+
|
|
15
|
+
## 测试环境
|
|
16
|
+
|
|
17
|
+
| 项目 | 值 |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| 操作系统 | darwin 23.6.0 (arm64) |
|
|
20
|
+
| CPU | Apple M1 Max · 10 logical cores |
|
|
21
|
+
| 物理内存 | 32.0 GB |
|
|
22
|
+
| Node / pnpm | v22.12.0 / 10.33.0 |
|
|
23
|
+
| Chromium | 151.0.7922.34 · headed |
|
|
24
|
+
| 视口 / DPR | 1440 × 900 / 1 |
|
|
25
|
+
| 采样 | 每视图 120 帧;每操作 7 次 |
|
|
26
|
+
| 空白页 JS heap 基线 | 0.57 MB |
|
|
27
|
+
| 被测运行时 | packages/atlas-mindmap/dist/index.js bundled into the production playground |
|
|
28
|
+
| ESM | 71.72 KiB raw / 15.79 KiB gzip |
|
|
29
|
+
| IIFE | 76.00 KiB raw / 16.06 KiB gzip |
|
|
30
|
+
| CSS | 5.66 KiB raw / 1.71 KiB gzip |
|
|
31
|
+
|
|
32
|
+
## 方法与口径
|
|
33
|
+
|
|
34
|
+
- 数据集:Deterministic normalized XMind-semantic breadth-first 4-ary tree with topic kind, markers, labels, and task data; maximum depth 9; exact requested count. Measures the post-import renderer model, not .xmind ZIP/content.json parsing or attachment decode.
|
|
35
|
+
- 内存:Chromium Runtime.getHeapUsage after HeapProfiler.collectGarbage; JS heap only.
|
|
36
|
+
- 全图:Fit complete layout, warm 20 frames, then collect requestAnimationFrame and Canvas metrics.
|
|
37
|
+
- 聚焦:Center a deepest representative topic at 100% scale, warm 20 frames, then collect metrics.
|
|
38
|
+
- 公共 facade 先构建为 `dist/index.js`,production playground 显式 alias 到该产物后再测试;不是直接从私有 workspace runtime 源码采样。
|
|
39
|
+
- 节点数据是与 XMind topic 语义等价的规范化后模型(含 kind、markers、labels、task),因此适用于评估导入完成后的布局和 Canvas 渲染;首次渲染时间不包含真实 `.xmind` ZIP 解压、`content.json` 解析、图片或附件解码。
|
|
40
|
+
- 每个规模使用新的页面;启动内存采样前显式执行 CDP GC;先预热 20 帧再采样。
|
|
41
|
+
- 浏览器真实触发 pointer pan、wheel zoom 和 pointer drag-reparent,并校验 camera、scale、parentId 和总节点数。
|
|
42
|
+
- 分级阈值:Smooth >=55 FPS/P95 <=20 ms/edit <=50 ms; usable >=30 FPS/P95 <=50 ms/edit <=100 ms; blocking on a >250 ms synchronous startup/edit operation or failed integrity.
|
|
43
|
+
- FPS 受显示器刷新率上限影响;本机是高刷新率环境,因此同时以帧 P95 和同步操作 P95 作为主要判断依据。
|
|
44
|
+
|
|
45
|
+
## 核心容量指标:首次渲染、堆内存与 DOM
|
|
46
|
+
|
|
47
|
+
| 节点数 | 首次渲染时间 ms | 强制 GC 后 JS 堆内存 MB | 页面 DOM 元素数 | Topic DOM 元素数 |
|
|
48
|
+
| ---: | ---: | ---: | ---: | ---: |
|
|
49
|
+
| 100 | 84.10 | 1.49 | 110 | 0 |
|
|
50
|
+
| 500 | 66.80 | 1.69 | 110 | 0 |
|
|
51
|
+
| 1,000 | 65.90 | 1.85 | 110 | 0 |
|
|
52
|
+
| 2,000 | 75.50 | 2.17 | 110 | 0 |
|
|
53
|
+
| 5,000 | 104.90 | 3.20 | 110 | 0 |
|
|
54
|
+
| 10,000 | 153.70 | 5.23 | 110 | 0 |
|
|
55
|
+
| 20,000 | 242.00 | 7.56 | 110 | 0 |
|
|
56
|
+
| 50,000 | 565.50 | 15.87 | 110 | 0 |
|
|
57
|
+
| 100,000 | 971.40 | 29.72 | 110 | 0 |
|
|
58
|
+
|
|
59
|
+
- **首次渲染时间**使用页面导航起点的同一 Performance Timeline,并在 Canvas renderer 首次绘制完成时记录 Performance API 时间戳;包含脚本加载、页面启动、fixture 构建、文档规范化、首次布局和首次 Canvas 绘制,不包含浏览器 compositor/present 到显示器的硬件延迟。
|
|
60
|
+
- **堆内存**是每个规模使用全新页面,并由 CDP 强制 GC 后读取的 V8 JS heap;不包含 Chromium 进程、GPU surface、字体缓存及操作系统原生内存。
|
|
61
|
+
- **DOM 元素数**在 renderer 首次绘制完成后、任何测试交互前,通过 document.querySelectorAll('*') 统计页面中的 Element;其中 Topic DOM 元素数始终为 0。DOM 数量不是思维导图节点数量:节点存放在紧凑模型和 typed arrays 中,由单个 Canvas 按视口绘制,因此 DOM 不随 100–100,000 个节点线性增长。原始 JSON 中另保留交互结束后的 CDP DOM node 总数,二者不混用。
|
|
62
|
+
|
|
63
|
+
## 启动、布局与内存
|
|
64
|
+
|
|
65
|
+
| 节点数 | 状态 | Fixture ms | 初始布局 ms | 导航至首帧 ms | JS heap MB | 相对空白页 MB | 启动判定 | DOM 口径 |
|
|
66
|
+
| ---: | --- | ---: | ---: | ---: | ---: | ---: | --- | --- |
|
|
67
|
+
| 100 | 成功 | 10.90 | 0.80 | 84.10 | 1.49 | 0.92 | 流畅 | Elements 110 / topic 0 |
|
|
68
|
+
| 500 | 成功 | 11.30 | 0.60 | 66.80 | 1.69 | 1.12 | 流畅 | Elements 110 / topic 0 |
|
|
69
|
+
| 1,000 | 成功 | 15.50 | 1.70 | 65.90 | 1.85 | 1.28 | 流畅 | Elements 110 / topic 0 |
|
|
70
|
+
| 2,000 | 成功 | 23.80 | 2.30 | 75.50 | 2.17 | 1.60 | 流畅 | Elements 110 / topic 0 |
|
|
71
|
+
| 5,000 | 成功 | 48.50 | 6.20 | 104.90 | 3.20 | 2.63 | 流畅 | Elements 110 / topic 0 |
|
|
72
|
+
| 10,000 | 成功 | 87.20 | 8.10 | 153.70 | 5.23 | 4.67 | 流畅 | Elements 110 / topic 0 |
|
|
73
|
+
| 20,000 | 成功 | 167.60 | 13.20 | 242.00 | 7.56 | 6.99 | 流畅 | Elements 110 / topic 0 |
|
|
74
|
+
| 50,000 | 成功 | 458.60 | 25.10 | 565.50 | 15.87 | 15.30 | 阻断 | Elements 110 / topic 0 |
|
|
75
|
+
| 100,000 | 成功 | 813.80 | 46.30 | 971.40 | 29.72 | 29.15 | 阻断 | Elements 110 / topic 0 |
|
|
76
|
+
|
|
77
|
+
JS heap 是 V8 对页面 JavaScript 对象的统计,不包含 GPU Canvas surface、Chromium 进程本身、字体缓存与操作系统分配,因此不能等同于应用总 RSS。`topic DOM = 0` 表明节点没有一节点一 DOM 的线性膨胀。
|
|
78
|
+
|
|
79
|
+
## 全图 Fit 渲染
|
|
80
|
+
|
|
81
|
+
| 节点数 | 缩放 | FPS | 帧 P95 ms | Cull P95 ms | Draw P95 ms | 中位绘制节点/率 | 判定 |
|
|
82
|
+
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
|
|
83
|
+
| 100 | 18.2540% | 120.0 | 9.30 | 0.10 | 0.70 | 100 (100.000%) | 流畅 |
|
|
84
|
+
| 500 | 3.6378% | 120.0 | 9.30 | 0.10 | 0.40 | 500 (100.000%) | 流畅 |
|
|
85
|
+
| 1,000 | 1.8181% | 119.4 | 9.30 | 0.10 | 0.60 | 1,000 (100.000%) | 流畅 |
|
|
86
|
+
| 2,000 | 0.9088% | 120.0 | 9.30 | 0.10 | 0.90 | 2,000 (100.000%) | 流畅 |
|
|
87
|
+
| 5,000 | 0.3635% | 119.9 | 9.00 | 0.10 | 2.00 | 5,000 (100.000%) | 流畅 |
|
|
88
|
+
| 10,000 | 0.1817% | 120.0 | 8.90 | 0.10 | 1.41 | 10,000 (100.000%) | 流畅 |
|
|
89
|
+
| 20,000 | 0.0909% | 119.9 | 8.70 | 0.10 | 2.80 | 20,000 (100.000%) | 流畅 |
|
|
90
|
+
| 50,000 | 0.0363% | 90.9 | 16.91 | 0.30 | 7.20 | 50,000 (100.000%) | 流畅 |
|
|
91
|
+
| 100,000 | 0.0182% | 47.6 | 33.21 | 0.50 | 25.30 | 100,000 (100.000%) | 可用 |
|
|
92
|
+
|
|
93
|
+
全图视图会把完整布局压缩进视口,LOD 会关闭文字和复杂连线;它代表缩略总览,而不是可读编辑比例。中位绘制节点率用于核对空间索引与 overscan 的实际候选量。
|
|
94
|
+
|
|
95
|
+
## 聚焦编辑与结构修改
|
|
96
|
+
|
|
97
|
+
| 节点数 | 聚焦 FPS / 帧P95 ms | 中位绘制节点 | 样式同步/至渲染帧 P95 ms | 文本P95 ms | 新增P95 ms | 移动P95 ms | 实际拖拽 | 综合 | 卡顿判断 |
|
|
98
|
+
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- | --- |
|
|
99
|
+
| 100 | 119.9 / 9.30 | 14 | 0.47 / 9.30 | 1.04 | 0.47 | 0.95 | 成功 / 7.56 ms | 流畅 | 未见明显卡顿 |
|
|
100
|
+
| 500 | 119.4 / 9.40 | 14 | 0.51 / 8.87 | 2.41 | 0.81 | 0.74 | 成功 / 5.11 ms | 流畅 | 未见明显卡顿 |
|
|
101
|
+
| 1,000 | 114.3 / 11.43 | 14 | 0.50 / 9.50 | 1.48 | 1.12 | 0.95 | 成功 / 3.93 ms | 流畅 | 未见明显卡顿 |
|
|
102
|
+
| 2,000 | 116.5 / 9.71 | 14 | 0.40 / 8.87 | 2.51 | 3.06 | 1.38 | 成功 / 5.58 ms | 流畅 | 未见明显卡顿 |
|
|
103
|
+
| 5,000 | 120.0 / 9.30 | 14 | 0.44 / 9.50 | 7.44 | 4.82 | 3.74 | 成功 / 10.98 ms | 流畅 | 未见明显卡顿 |
|
|
104
|
+
| 10,000 | 117.4 / 9.92 | 14 | 0.40 / 12.65 | 7.99 | 8.72 | 4.76 | 成功 / 6.88 ms | 流畅 | 未见明显卡顿 |
|
|
105
|
+
| 20,000 | 114.6 / 12.70 | 14 | 0.67 / 9.19 | 16.15 | 10.07 | 9.41 | 成功 / 14.61 ms | 流畅 | 未见明显卡顿 |
|
|
106
|
+
| 50,000 | 118.0 / 9.31 | 14 | 0.47 / 11.21 | 26.80 | 22.24 | 27.86 | 成功 / 32.99 ms | 流畅 | 未见明显卡顿 |
|
|
107
|
+
| 100,000 | 116.7 / 10.51 | 14 | 0.47 / 9.03 | 46.97 | 44.66 | 43.58 | 成功 / 41.34 ms | 流畅 | 未见明显卡顿 |
|
|
108
|
+
|
|
109
|
+
- 样式同步值只统计 `updateTopic()` mutation 返回;“至渲染帧”另统计 mutation 到下一次 Canvas renderer rAF 完成,避免把 0.x ms 误写成可见结果延迟。两者都不替换全量 layout。
|
|
110
|
+
- 文本、新增、移动会同步重建布局与空间索引,因此规模增大时它们比换色更容易成为瓶颈。
|
|
111
|
+
- 实际拖拽列中的毫秒值只统计 pointer-up 到 parentId 可观察变更完成的时间;拖动手势本身包含人为注入的多步移动,不把手势持续时间当作程序延迟。
|
|
112
|
+
|
|
113
|
+
## 真实指针操作完整性
|
|
114
|
+
|
|
115
|
+
| 节点数 | 平移 | 平移帧P95 ms | 缩放 | 缩放帧P95 ms | 拖拽改父级 | 拖拽帧P95 ms |
|
|
116
|
+
| ---: | --- | ---: | --- | ---: | --- | ---: |
|
|
117
|
+
| 100 | 成功 | 9.06 | 成功 | 9.30 | 成功 | 9.30 |
|
|
118
|
+
| 500 | 成功 | 9.20 | 成功 | 9.30 | 成功 | 9.30 |
|
|
119
|
+
| 1,000 | 成功 | 9.20 | 成功 | 9.30 | 成功 | 10.36 |
|
|
120
|
+
| 2,000 | 成功 | 9.12 | 成功 | 11.54 | 成功 | 9.38 |
|
|
121
|
+
| 5,000 | 成功 | 8.94 | 成功 | 9.30 | 成功 | 9.30 |
|
|
122
|
+
| 10,000 | 成功 | 8.66 | 成功 | 9.30 | 成功 | 9.20 |
|
|
123
|
+
| 20,000 | 成功 | 8.80 | 成功 | 9.30 | 成功 | 11.76 |
|
|
124
|
+
| 50,000 | 成功 | 9.26 | 成功 | 9.30 | 成功 | 15.78 |
|
|
125
|
+
| 100,000 | 成功 | 9.10 | 成功 | 9.56 | 成功 | 13.48 |
|
|
126
|
+
|
|
127
|
+
每项“成功”都表示状态实际变化且最终模型节点数保持不变;不是只检查事件是否发出。
|
|
128
|
+
|
|
129
|
+
## 样式与图标性能评审
|
|
130
|
+
|
|
131
|
+
节点 fill、border、color、shape、fontWeight 等样式在 Canvas 中只影响可见候选的绘制状态。当前实现已增加视觉更新快路径,颜色/边框/圆角/标记元数据修改不会重建 100,000 节点布局;成本近似 **O(当前视口绘制节点数)**,通常不会成为主要性能问题。`fontSize` 当前也按视觉属性处理并受已有节点框裁剪;如果未来要求字号改变节点几何,应提供显式批量 relayout,而不是每次输入都全量重排。
|
|
132
|
+
|
|
133
|
+
图标策略决定性能边界:推荐缓存 Canvas Path2D,或把图标一次 decode 后放入有容量上限的 bitmap atlas;按 `icon + size + DPR` 复用;低缩放 LOD 隐藏图标;帧循环内不创建 Image/SVG/Promise。禁止为每个节点挂 DOM/SVG,也不要让 100,000 个远程图片同时解码。v0.1.0 保存 markers/image 等 XMind 数据字段,但**不宣称已完成任意远程图片的高性能图标渲染**;这部分应以受控插件和缓存预算实现。
|
|
134
|
+
|
|
135
|
+
## 技术结论与上线建议
|
|
136
|
+
|
|
137
|
+
1. 20,000 节点是主要验收档:应同时满足聚焦编辑、真实拖拽与结构变更阈值;回归测试优先看 frame P95、text/move P95 与 heap,而不是只看平均 FPS。
|
|
138
|
+
2. 50,000–100,000 节点应保留 Canvas + typed-array layout + spatial index + LOD;默认打开聚焦分支或折叠层级,避免把可读编辑和全图总览混为一谈。
|
|
139
|
+
3. 50,000+ 的 fixture/normalization 已触发 >250 ms 启动阻断线;公司产品上线前应把数据准备移到 Worker、采用分批导入/渐进可见,或先加载折叠骨架,不能用“进入画布后拖拽流畅”掩盖首屏主线程阻塞。
|
|
140
|
+
4. 样式面板应合并连续输入:颜色预览可逐帧重绘,几何属性采用 debounce/提交时重排;主题切换只重绘。
|
|
141
|
+
5. 图标和用户图片必须设置缓存总量、像素预算和淘汰策略。业务侧导入 XMind 时先只保存元数据,按视口懒加载资源。
|
|
142
|
+
6. CI 建议用固定浏览器/机器保存基线;同环境下 JS heap 增长 >20%、聚焦帧 P95 >20 ms、结构编辑 P95 >100 ms、启动同步阶段 >250 ms 或指针完整性失败时阻断发布。
|
|
143
|
+
|
|
144
|
+
## 限制与适用边界
|
|
145
|
+
|
|
146
|
+
- 主表是最大深度 9 的确定性 4 叉树;现有 demo 另有 20,001 节点、深度 200 的目录森林用于栈安全和深层导航,但两种拓扑不混入同一增长曲线。
|
|
147
|
+
- 单机单次资格测试会受温度、后台进程、显示刷新率和 Chromium 版本影响;正式容量承诺应在目标公司设备上重复至少 3 次并报告中位数/置信区间。
|
|
148
|
+
- JS heap 不含 GPU/进程 RSS;Canvas 绘制时间不等同于完整 compositor/present 时间。
|
|
149
|
+
- 本测试使用短文本和确定性 markers/task 分布。超长文本测量、公式、大图、实时协作与插件代码需要单独 workload。
|
|
150
|
+
- 本测试没有把合成树表述为真实文件导入测试;如需评审“打开 .xmind 文件到首帧”的端到端耗时,应在导入器完成后另建真实文件 corpus,单独统计解压、解析、资源解码和规范化阶段。
|
|
151
|
+
- 报告没有为失败或浏览器不支持的指标填估算数;原始 JSON 是唯一数据源,CSV/Markdown 均由它确定性生成。
|
|
152
|
+
|
|
153
|
+
## 复现
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pnpm install --frozen-lockfile
|
|
157
|
+
pnpm benchmark:browser --counts=100,500,1000,2000,5000,10000,20000,50000,100000 --output=docs/performance/results/2026-08-29-atlas-mindmap.json
|
|
158
|
+
pnpm benchmark:report --input=docs/performance/results/2026-08-29-atlas-mindmap.json --csv=docs/performance/results/2026-08-29-atlas-mindmap.csv --markdown=docs/performance/2026-08-29-atlas-mindmap-performance-report.md
|
|
159
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @lingkkkk/atlas-mindmap
|
|
2
|
+
|
|
3
|
+
A framework-agnostic Canvas mind-map runtime for plain JavaScript and TypeScript. It keeps topic
|
|
4
|
+
data in a normalized store, geometry in typed arrays, viewport lookup in a spatial index, and topic
|
|
5
|
+
rendering on one Canvas. The package has zero runtime dependencies and includes ESM, CommonJS,
|
|
6
|
+
browser-IIFE, type declarations, and CSS builds.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @lingkkkk/atlas-mindmap
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## ESM / plain JavaScript
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import { MindMap } from '@lingkkkk/atlas-mindmap'
|
|
18
|
+
import '@lingkkkk/atlas-mindmap/styles.css'
|
|
19
|
+
|
|
20
|
+
const map = new MindMap({
|
|
21
|
+
container: '#mindmap',
|
|
22
|
+
document: {
|
|
23
|
+
id: 'root',
|
|
24
|
+
text: 'Product',
|
|
25
|
+
children: [
|
|
26
|
+
{ id: 'research', text: 'Research' },
|
|
27
|
+
{ id: 'delivery', text: 'Delivery' },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
theme: 'dark',
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The host needs an explicit size:
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
#mindmap { width: 100%; height: 720px; }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## TypeScript
|
|
41
|
+
|
|
42
|
+
Types ship with the package. The root export includes `MindMap`, `MindMapEngine`, `TopicStore`,
|
|
43
|
+
`MindMapLayout`, `CanvasRenderer`, `Camera`, document/topic types, metrics, and the plugin contract.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { MindMap, type TopicInput } from '@lingkkkk/atlas-mindmap'
|
|
47
|
+
|
|
48
|
+
const mapDocument: TopicInput = { id: 'root', text: 'Typed map', children: [] }
|
|
49
|
+
const map = new MindMap({ container: document.querySelector('#mindmap')!, document: mapDocument })
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## CommonJS
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
const { MindMap, MindMapEngine } = require('@lingkkkk/atlas-mindmap')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Load `node_modules/@lingkkkk/atlas-mindmap/dist/index.css` with your bundler or HTML stylesheet.
|
|
59
|
+
|
|
60
|
+
## CDN / browser IIFE
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<link rel="stylesheet" href="https://unpkg.com/@lingkkkk/atlas-mindmap@0.1.0/dist/index.css">
|
|
64
|
+
<div id="mindmap" style="height:720px"></div>
|
|
65
|
+
<script src="https://unpkg.com/@lingkkkk/atlas-mindmap@0.1.0/dist/index.global.js"></script>
|
|
66
|
+
<script>
|
|
67
|
+
const map = new AtlasMindMap.MindMap({
|
|
68
|
+
container: '#mindmap',
|
|
69
|
+
document: { id: 'root', text: 'CDN map', children: [] }
|
|
70
|
+
})
|
|
71
|
+
</script>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 20,000-topic data
|
|
75
|
+
|
|
76
|
+
Build large trees iteratively so application setup does not recurse through user-controlled depth:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
function makeTree(count = 20_000, branching = 4) {
|
|
80
|
+
const root = { id: 'topic-0', text: '20,000 topic map', children: [] }
|
|
81
|
+
const queue = [root]
|
|
82
|
+
let cursor = 0
|
|
83
|
+
for (let id = 1; id < count; id += 1) {
|
|
84
|
+
const parent = queue[cursor]
|
|
85
|
+
const topic = { id: `topic-${id}`, text: `Topic ${id}`, children: [] }
|
|
86
|
+
parent.children.push(topic)
|
|
87
|
+
queue.push(topic)
|
|
88
|
+
if (parent.children.length === branching) cursor += 1
|
|
89
|
+
}
|
|
90
|
+
return root
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const map = new MindMap({ container: '#mindmap', document: makeTree() })
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The live HUD reports total/layout/rendered topics, render rate, FPS, frame P95, Canvas cull/draw,
|
|
97
|
+
layout time, zoom, DOM count, and JS heap when Chromium exposes it.
|
|
98
|
+
|
|
99
|
+
## Editing, keyboard, and view controls
|
|
100
|
+
|
|
101
|
+
- Click a topic to select it; double-click or press F2/Space to edit.
|
|
102
|
+
- Press **Enter** after focusing a topic to create and edit a sibling.
|
|
103
|
+
- Press **Tab** after focusing a topic to create and edit a child.
|
|
104
|
+
- Drag a topic onto another topic to reparent it; drag blank Canvas space to pan.
|
|
105
|
+
- Mouse wheel zooms around the pointer. `fitView()`, `resetView()`, `zoomIn()`, and `zoomOut()` are
|
|
106
|
+
also public.
|
|
107
|
+
- `addTopic`, `addSibling`, `updateTopic`, `moveTopic`, `deleteTopic`, `undo`, `redo`, `search`,
|
|
108
|
+
`collapse`, `expand`, `expandAll`, JSON import/export, and theme switching are public APIs.
|
|
109
|
+
|
|
110
|
+
## Themes and node styles
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
map.setTheme('light')
|
|
114
|
+
map.updateTopic('research', {
|
|
115
|
+
style: {
|
|
116
|
+
fill: '#38bdf8',
|
|
117
|
+
border: '#0ea5e9',
|
|
118
|
+
color: '#082f49',
|
|
119
|
+
fontWeight: 700,
|
|
120
|
+
shape: 'pill',
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Visual-only updates invalidate Canvas without replacing the complete layout. Text and structural
|
|
126
|
+
changes rebuild geometry. For a continuous color picker, coalesce changes to one update per
|
|
127
|
+
animation frame; debounce geometry-changing controls until input commit.
|
|
128
|
+
|
|
129
|
+
## Safe icon and image strategy
|
|
130
|
+
|
|
131
|
+
Version 0.1.0 stores XMind-compatible `markers` and `image` metadata, but does not claim arbitrary
|
|
132
|
+
remote-image icon rendering as a completed feature. A high-volume icon plugin should use cached
|
|
133
|
+
`Path2D` objects or a decoded bitmap atlas, key the cache by icon/size/DPR, cap its pixel budget,
|
|
134
|
+
hide icons in low-zoom LOD, and never allocate an Image, SVG, or Promise inside the frame loop.
|
|
135
|
+
Do not create one DOM/SVG icon per topic.
|
|
136
|
+
|
|
137
|
+
## Lifecycle
|
|
138
|
+
|
|
139
|
+
Call `destroy()` when unmounting a page or component. It cancels animation frames and timers,
|
|
140
|
+
disconnects observers, removes listeners, destroys plugins, and removes the runtime DOM:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
map.destroy()
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Performance evidence
|
|
147
|
+
|
|
148
|
+
See [PERFORMANCE.md](./PERFORMANCE.md) for the 100/500/1,000/2,000/5,000/10,000/20,000/50,000/
|
|
149
|
+
100,000-topic headed-Chromium qualification, environment, interaction checks, memory scope, and
|
|
150
|
+
limitations. The report distinguishes full-map overview from 100% focused editing.
|
|
151
|
+
|
|
152
|
+
## Browser support
|
|
153
|
+
|
|
154
|
+
Use current evergreen browsers with Canvas 2D, typed arrays, `requestAnimationFrame`, Pointer
|
|
155
|
+
Events, and modern ES2020 support. `ResizeObserver` has a window-resize fallback. CommonJS and ESM
|
|
156
|
+
entry points require Node 18+ when imported by build tooling.
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
UNLICENSED. Publication makes the package installable; it does not grant redistribution or source
|
|
161
|
+
license rights beyond the npm terms and the owner's explicit agreement.
|