其他
在浏览器中用 NVL 渲染 Neo4j…
适用场景:需要浏览器中渲染 Neo4j 图、把 driver.executeQuery 结果可视化,并自定义缩放/平移/拖拽/点击/悬停/框选/套索/键盘交互时。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 39/100 ×0.15
适用场景
在浏览器中用 NVL 渲染 Neo4j 特定
解决思路
- 安装依赖:`npm install @neo4j-nvl/base`(核心必需),按需 `npm install @neo4j-nvl/interaction-handlers`(vanilla JS 标准交互)和 `npm install @neo4j-nvl/react`(React 包装器)。
- React 包装器 peer 要求:`@neo4j-nvl/react` 目标 React 19;已发布 peerDependency 虽仍允许 React 18,但不建议混用主版本。
- `@neo4j-nvl/layout-workers` 是传递依赖,绝不直接安装。
- `neo4j-driver` 只有在使用 `nvlResultTransformer` 时才是 `@neo4j-nvl/base` 的 peer。
- 优先使用官方 starter templates:https://github.com/neo4j-devtools/nvl-boilerplates 中按框架提供的脚手架,优于手写初始化。
- 确认许可证:NVL 采用 Neo4j Visualization Library License,仅用于 Neo4j 产品,不能对其他图后端使用。
- 选范式:React 默认交互用 `<InteractiveNvlWrapper>` from `@neo4j-nvl/react`。
- 选范式:React 自定义交互接线用 `<BasicNvlWrapper>` + 通过 `ref` 自己实现 handlers。
- 选范式:vanilla JS 标准交互用 `NVL` + `@neo4j-nvl/interaction-handlers`。
- 选范式:vanilla JS 完全自定义事件逻辑用 `NVL` + `container.addEventListener` + `nvl.getHits()`。
- 选范式:静态 PNG/SVG 图片导出用 `<StaticPictureWrapper>` 或 `nvl.saveToFile()` / `nvl.saveToSvg()`。
- 选渲染器:默认 `'canvas'`,最多约 1,000 节点,支持完整 captions、icons、arrows、像素级 hit-testing,适合细节调查和小图。
- 选渲染器:`'webgl'` 支持 100,000+ 节点,但 label 保真度降低(受 GPU 最大纹理尺寸限制),适合大规模模式探索。
- 运行时切换渲染器:`new NVL(container, nodes, rels, { renderer: 'webgl' })` 后用 `nvl.setRenderer('canvas')`。
- 容器必须显式设置 `width` 和 `height`;缺 height 会塌缩为 0 导致图不可见,这是 NVL 最常见 bug。
- 正确容器示例:`<div id="viz" style="width: 100%; height: 600px;"></div>`;错误示例:`<div id="viz"></div>`。
- Vanilla 基础:`import { NVL } from '@neo4j-nvl/base'`,获取 `const container = document.getElementById('viz')`,构造 `nodes = [{ id: '1' }, { id: '2' }]` 与 `relationships = [{ id: '12', from: '1', to: '2', type: 'KNOWS' }]`,再 `const nvl = new NVL(container, nodes, relationships)`。
- Vanilla 选项:可传 `initialZoom`、`minZoom`、`maxZoom`、`layout: 'forceDirected'`、`renderer: 'canvas'`、`styling: { defaultNodeColor: '#0e86d4', defaultRelationshipColor: '#888' }` 等。
- Vanilla 回调:可传 `onInitialization`、`onLayoutDone: () => nvl.fit([])`、`onError` 等。
- `NVL` 构造签名:`new NVL(frame, nvlNodes?, nvlRels?, options?, callbacks?)`;除 `frame` 外都可选且默认空。
- Vanilla 卸载时始终调用 `nvl.destroy()`。
- Vanilla 交互:从 `@neo4j-nvl/interaction-handlers` 导入 `ZoomInteraction, PanInteraction, DragNodeInteraction, ClickInteraction, HoverInteraction, BoxSelectInteraction, LassoInteraction, KeyboardInteraction`。
- 在已有 `NVL` 实例上组合 handlers:`new ZoomInteraction(nvl)`、`new PanInteraction(nvl)`、`new DragNodeInteraction(nvl)`、`new ClickInteraction(nvl, { selectOnClick: true })`、`new HoverInteraction(nvl, { drawShadowOnHover: true })`。
- 每个 interaction handler 通过 `.updateCallback(name, fn)` 注册回调,并且必须用 `.destroy()` 销毁。
- 点击回调示例:`click.updateCallback('onNodeClick', (node, hits, evt) => ...)`、`click.updateCallback('onRelationshipClick', ...)`、`click.updateCallback('onCanvasClick', ...)`。
- 悬停、拖拽、缩放回调示例:`hover.updateCallback('onHover', (el, hits, evt) => ...)`、`drag.updateCallback('onDragEnd', (nodes, evt) => savePositions(nodes))`、`zoom.updateCallback('onZoom', (level) => ...)`。
- Vanilla handlers 卸载:先对每个 handler 调用 `.destroy()`,然后调用 `nvl.destroy()`。
- 不移除 handler 而禁用某事件:`click.removeCallback('onCanvasClick')`;传 `true` 而不是函数可用 no-op 启用该事件(用于默认选择行为)。
- React 默认交互:使用 `<InteractiveNvlWrapper>`,它预接线所有 interaction handler;用 `mouseEventCallbacks` 开关事件:函数=开启并回调,`true`=开启但 no-op,`false`/省略=关闭。
- React 使用 `InteractiveNvlWrapper` 时定义 `nvlOptions: NvlOptions = { initialZoom: 1, renderer: 'canvas' }`。
- React 定义 `mouseEventCallbacks: MouseEventCallbacks`,可包含 `onNodeClick`、`onRelationshipClick`、`onCanvasClick`、`onHover`、`onDragEnd`、`onZoom: true`、`onPan: true`。
- React 容器外层设置 `style={{ width: '100%', height: 600 }}`,并把 `ref`、`nodes`、`rels`、`nvlOptions`、`interactionOptions={{ selectOnClick: true, drawShadowOnHover: true }}`、`mouseEventCallbacks`、`onInitializationError` 传给 `<InteractiveNvlWrapper>`。
- `InteractiveNvlWrapper` 的 `ref` 解析为底层 `NVL` 实例,可调用任意方法:`nvlRef.current?.fit([])`、`nvlRef.current?.setRenderer('webgl')`、`nvlRef.current?.saveToFile()`。
- React 自定义交互:使用 `<BasicNvlWrapper>`,它不接线交互;`ref` 通过 `IncludeMethods<NVL>` 暴露全部 NVL 方法。
- BasicNvlWrapper 示例:外层 `div` 设置 `width: '100%', height: 400`,传 `ref`、`nodes`、`rels`、`nvlOptions={{ initialZoom: 2 }}`、`nvlCallbacks={{ onLayoutDone: () => nvlRef.current?.fit([]) }}`;按钮调用 `nvlRef.current?.fit(['1', '2'])`。
- 接入 Neo4j driver 结果:`@neo4j-nvl/base` 导出 `ResultTransformer`,即 `nvlResultTransformer`,用于 JS driver,可在任意 record shape 中跨记录去重 nodes/relationships。
- 用 driver 取图:`import neo4j from 'neo4j-driver'`,`import { NVL, nvlResultTransformer } from '@neo4j-nvl/base'`,创建 `driver` 后调用 `driver.executeQuery('MATCH (a)-[r]-(b) RETURN a, r, b LIMIT 25', {}, { database: 'neo4j', resultTransformer: nvlResultTransformer })`,解构 `{ nodes, relationships }` 再 `new NVL(document.getElementById('viz'), nodes, relationships)`。
- 不要把原始 `EagerResult` 直接传给 NVL;原始 records 不是 Node/Relationship 对象;必须使用 `nvlResultTransformer` 消费 `{ nodes, relationships }`。
- Driver 生命周期、session 管理、Integer 处理、TypeScript 类型转到 `neo4j-driver-javascript-skill`。
- 图更新:`addAndUpdateElementsInGraph(nodes, rels)` 插入新元素,并按 id 更新已有元素(只更新指定字段)。
- 图更新:`updateElementsInGraph(nodes, rels)` 只更新已有元素,忽略未知 id。
- 图更新:`addElementsToGraph(nodes, rels)` 只插入,遇到已存在 id 抛错。
- 图更新:`removeNodesWithIds(ids)` 删除节点,相邻 relationships 自动删除。
- 图更新:`removeRelationshipsWithIds(ids)` 删除 relationships。
- 图更新:`setNodePositions(nodes, updateLayout?)` 覆盖位置,可选重新运行 layout。
- 图更新:`restart(options?, retainPositions?)` 用新 options 重启,位置可选保留。
- Diff 更新使用 `PartialNode` / `PartialRelationship`,只需 `id` 必填;示例 `nvl.updateElementsInGraph([{ id: '1', color: '#f00', selected: true }], [{ id: '12', width: 4 }])`。
- 手动 hit testing:不使用 interaction-handlers 时用 `getHits()` 解析指针下的 node/relationship。
- `getHits` 示例:`container.addEventListener('click', (evt) => { const { nvlTargets } = nvl.getHits(evt, ['node', 'relationship'], { hitNodeMarginWidth: 4 }); const hitNode = nvlTargets.nodes[0]; const hitRel = nvlTargets.relationships[0]; if (hitNode) ... else if (hitRel) ... else ... })`。
- `HitTargetNode` / `HitTargetRelationship` 带有 `data`、`pointerCoordinates`、`distance`、`insideNode`(仅节点);更多见 `references/api-surface.md`。
- 避免错误:容器无 `height` 导致图不可见,设置显式 `width` 和 `height`。
- 避免错误:直接传 `driver.executeQuery` 结果,改用 `nvlResultTransformer` 并消费 `{ nodes, relationships }`。
- 避免错误:小图且 label 丰富时用 WebGL,应使用 `'canvas'`,它完整支持 labels。
- 避免错误:10k+ 节点用 Canvas,应切换 `'webgl'`,通过 `renderer` option 或 `setRenderer`。
- 避免错误:每次 React render 都新建 `NVL`,应使用 `<InteractiveNvlWrapper>` / `<BasicNvlWrapper>`,或在 `useEffect` 中创建并 `destroy()`。
- 避免错误:teardown 忘记 `nvl.destroy()`,应在 unmount 时调用;React wrappers 会自动处理。
- 避免错误:vanilla handlers 未销毁,应在 `nvl.destroy()` 前对每个 interaction 调用 `.destroy()`。
- 避免错误:worker 构造被严格 CSP / 沙箱运行时 / 旧 bundler 阻止,设置 `nvlOptions: { disableWebWorkers: true }`,NVL 有非 worker fallback。
- 避免错误:受监管环境启用 telemetry,设置 `nvlOptions: { disableTelemetry: true }`。
- 避免错误:layout 永不收敛,用 `pinNode(id)` 固定锚节点并调优 `layoutTimeLimit`。
- 避免错误:`selectOnClick` 触发两次,挂载时只切换一次,不要每次 render 翻转 `interactionOptions`。
- 避免错误:hit test 在节点边缘附近漏命中,向 `getHits` 传 `{ hitNodeMarginWidth: N }`。
- 避免错误:WebGL 上 captions 缺失,通常是超过 GPU 最大纹理尺寸;回退 Canvas 或缩小 captions。
- 按需加载参考:`references/api-surface.md` 包含完整 `NVL` 方法表、`Node`、`Relationship`、`NvlOptions`、`LayoutOptions`、`ExternalCallbacks`、`HitTargets`、`NvlMouseEvent`、`StyledCaption`、`Point`、每个 interaction-handler 类及 options/callback 签名、React wrappers props、`MouseEventCallbacks` 与 `KeyboardEventCallbacks` shape、named exports、`nvlResultTransformer` 签名。
- 按需加载参考:`references/troubleshooting.md` 包含 zero-height container、`disableWebWorkers` fallback、Canvas/WebGL trade-offs 与 WebGL2、WebGL texture-size cap、`onWebGLContextLost` recovery、telemetry opt-out、memory leaks、stuck layouts、double selection、hit-margin tuning、license restriction。
- 官方文档不够时用 `WebFetch` 获取:https://neo4j.com/docs/nvl/current/(用户指南)、https://neo4j.com/docs/api/nvl/current/(TypeDoc API)、https://neo4j.com/docs/api/nvl/current/examples.html(可运行示例)、https://github.com/neo4j-devtools/nvl-boilerplates(starter templates)、https://github.com/neo4j/python-graph-visualization(Python port,仅在 JS/browser 路径用本技能)。
- Checklist:容器有显式 `width` AND `height` CSS。
- Checklist:已按决策表选择正确范式(vanilla / handlers / React)。
- Checklist:渲染器匹配预期节点数(Canvas ≲1k / WebGL 100k+)。
- Checklist:driver `executeQuery` 结果经过 `nvlResultTransformer`。
- Checklist:每次 `executeQuery` 调用都指定 `database`(委托 `neo4j-driver-javascript-skill`)。
- Checklist:teardown 时所有 interaction handlers 在 `nvl.destroy()` 前已 `.destroy()`。
- Checklist:React unmount 时手动实例调用 `nvl.destroy()`;wrappers 自动处理。
- Checklist:受监管/离线环境设置 `disableTelemetry: true`。
- Checklist:bundler/CSP 阻止 worker 时设置 `disableWebWorkers: true`。
- Checklist:图更新使用 `addAndUpdateElementsInGraph` / `updateElementsInGraph`,而不是 `restart`。
- Checklist:许可证兼容,目标为 Neo4j 产品。
适用边界 · 注意事项
- 需要默认 Neo4j 样式、无自定义交互或渲染的嵌入式图视图时,改用 `@neo4j-ndl/react` 的 `GraphVisualization`,不要用 NVL 重复做样式。
- Python/Jupyter notebook 图可视化、Cypher 编写/优化、driver 生命周期/session/executeQuery 设置、服务端无渲染数据获取、GDS 算法执行、GraphQL API 应转对应 `neo4j-*` 技能。
- 目标不是 Neo4j 产品或要对其他图后端使用时不可用;NVL 许可证仅允许用于 Neo4j 产品。