neo4j-nvl-skill
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWhen to Use
适用场景
- Rendering a Neo4j graph in a browser (vanilla JS, React, Vite) with custom interactions, rendering, or data shapes
- Visualizing results as an interactive graph
driver.executeQuery - Wiring zoom, pan, drag, click, hover, lasso, or box-select interactions
- Embedding NVL inside an existing app and synchronizing graph state
- 在浏览器(原生JS、React、Vite)中渲染Neo4j图,支持自定义交互、渲染逻辑或数据结构
- 将结果可视化为交互式图
driver.executeQuery - 配置缩放、平移、拖拽、点击、悬停、套索选择或框选交互
- 在现有应用中嵌入NVL并同步图状态
When NOT to Use
不适用场景
- Pre-styled embedded graph view with default behavior, no custom interactions → from
GraphVisualization(Neo4j Needle / NDL design system) — wraps NVL with default Neo4j styling. See Use NVL or the Needle Component? below.@neo4j-ndl/react - Python / Jupyter notebook graph visualization → (the Python port of NVL)
neo4j/python-graph-visualization - Writing/optimizing Cypher →
neo4j-cypher-skill - Driver setup / executeQuery / sessions →
neo4j-driver-javascript-skill - Server-side data fetching with no rendering →
neo4j-driver-javascript-skill - GDS algorithm execution → or
neo4j-gds-skillneo4j-aura-graph-analytics-skill - GraphQL API →
neo4j-graphql-skill
- 带有默认样式和行为的预定义嵌入图视图,无需自定义交互 → 使用中的
@neo4j-ndl/react(Neo4j Needle / NDL设计系统)——该组件封装了NVL并提供默认Neo4j样式。详见下方的【选择NVL还是Needle组件?】。GraphVisualization - Python / Jupyter Notebook图可视化 → 使用(NVL的Python移植版本)
neo4j/python-graph-visualization - 编写/优化Cypher查询 → 使用
neo4j-cypher-skill - 驱动配置 / executeQuery / 会话管理 → 使用
neo4j-driver-javascript-skill - 仅服务端数据获取,无需渲染 → 使用
neo4j-driver-javascript-skill - 执行GDS算法 → 使用或
neo4j-gds-skillneo4j-aura-graph-analytics-skill - GraphQL API → 使用
neo4j-graphql-skill
Use NVL or the Needle Component?
选择NVL还是Needle组件?
| Need | Use |
|---|---|
| Embed a graph view with default Neo4j styling, no custom interactions or rendering | |
| Custom interactions, custom rendering, non-standard data shapes, or framework-agnostic embedding | This skill — use NVL directly |
If the answer is the first row, install and use the Needle component instead of NVL — do not duplicate styling work.
| 需求 | 推荐方案 |
|---|---|
| 嵌入带有默认Neo4j样式的图视图,无需自定义交互或渲染 | 使用 |
| 需要自定义交互、自定义渲染、非标准数据结构,或与框架无关的嵌入方式 | 直接使用本技能中的NVL |
如果你的需求符合第一行,请安装并使用Needle组件而非NVL,避免重复样式开发。
Install
安装
bash
npm install @neo4j-nvl/base # core (required)
npm install @neo4j-nvl/interaction-handlers # standard interactions (optional, vanilla JS)
npm install @neo4j-nvl/react # React wrappers (optional)Peer requirements: React 19 for . The published peerDependency range still permits React 18, but mixing major versions is not recommended — target 19. is a transitive dependency — never install directly. is a peer of only when using .
@neo4j-nvl/react@neo4j-nvl/layout-workersneo4j-driver@neo4j-nvl/basenvlResultTransformerStarter templates: https://github.com/neo4j-devtools/nvl-boilerplates — official per-framework scaffolds; prefer these over hand-rolled setups.
License: NVL ships under the Neo4j Visualization Library License — for use with Neo4j products only. Cannot be used against other graph backends.
bash
npm install @neo4j-nvl/base # 核心库(必填)
npm install @neo4j-nvl/interaction-handlers # 标准交互组件(可选,原生JS)
npm install @neo4j-nvl/react # React封装组件(可选)依赖要求:使用需要React 19。已发布的peerDependency范围仍允许React 18,但不建议混合使用主版本——优先选择React 19。是间接依赖,请勿直接安装。仅当使用时,才是的对等依赖。
@neo4j-nvl/react@neo4j-nvl/layout-workersnvlResultTransformerneo4j-driver@neo4j-nvl/base启动模板:https://github.com/neo4j-devtools/nvl-boilerplates —— 官方提供的各框架脚手架;优先使用这些模板而非手动搭建。
许可证:NVL采用Neo4j可视化库许可证——仅可用于Neo4j产品,不能用于其他图数据库后端。
Pick the Right Paradigm
选择合适的实现方式
| Need | Use |
|---|---|
| React app, default interactions | |
| React app, custom interaction wiring | |
| Vanilla JS, standard interactions | |
| Vanilla JS, fully custom event logic | |
| Static PNG/SVG image export | |
| 需求 | 推荐方案 |
|---|---|
| React应用,使用默认交互 | 使用 |
| React应用,自定义交互逻辑 | 使用 |
| 原生JS应用,使用标准交互 | 使用 |
| 原生JS应用,完全自定义事件逻辑 | 使用 |
| 导出静态PNG/SVG图片 | 使用 |
Pick the Right Renderer
选择合适的渲染器
| Renderer | Max nodes | Detail | Use case |
|---|---|---|---|
| ~1,000 | Full captions, icons, arrows, pixel-perfect hit-testing | Detail investigation, small graphs |
| 100,000+ | Reduced label fidelity (bound by GPU max texture size) | Large-scale pattern exploration |
javascript
const nvl = new NVL(container, nodes, rels, { renderer: 'webgl' })
nvl.setRenderer('canvas') // swap at runtime| 渲染器 | 最大节点数 | 细节表现 | 适用场景 |
|---|---|---|---|
| ~1000 | 完整标题、图标、箭头、像素级命中检测 | 细节探究、小型图 |
| 100,000+ | 标签保真度降低(受GPU最大纹理尺寸限制) | 大规模模式探索 |
javascript
const nvl = new NVL(container, nodes, rels, { renderer: 'webgl' })
nvl.setRenderer('canvas') // 运行时切换渲染器Container Setup
容器配置
The container must have an explicit AND . Missing height → container collapses to → graph invisible. Most-reported NVL bug.
widthheight0html
<!-- ❌ height defaults to 0; graph invisible -->
<div id="viz"></div>
<!-- ✅ explicit dimensions -->
<div id="viz" style="width: 100%; height: 600px;"></div>容器必须设置明确的和。未设置高度会导致容器高度为,图不可见——这是NVL最常被报告的问题。
widthheight0html
<!-- ❌ 高度默认为0;图不可见 -->
<div id="viz"></div>
<!-- ✅ 设置明确尺寸 -->
<div id="viz" style="width: 100%; height: 600px;"></div>Vanilla — Base Library
原生JS —— 基础库
javascript
import { NVL } from '@neo4j-nvl/base'
const container = document.getElementById('viz')
const nodes = [{ id: '1' }, { id: '2' }]
const relationships = [{ id: '12', from: '1', to: '2', type: 'KNOWS' }]
const nvl = new NVL(container, nodes, relationships)With options + callbacks:
javascript
import { NVL } from '@neo4j-nvl/base'
const options = {
initialZoom: 1.0,
minZoom: 0.1,
maxZoom: 8,
layout: 'forceDirected',
renderer: 'canvas',
styling: { defaultNodeColor: '#0e86d4', defaultRelationshipColor: '#888' }
}
const callbacks = {
onInitialization: () => console.log('NVL ready'),
onLayoutDone: () => nvl.fit([]),
onError: (err) => console.error('NVL error', err)
}
const nvl = new NVL(container, nodes, relationships, options, callbacks)
// On teardown — always:
nvl.destroy()NVLnew NVL(frame, nvlNodes?, nvlRels?, options?, callbacks?)framejavascript
import { NVL } from '@neo4j-nvl/base'
const container = document.getElementById('viz')
const nodes = [{ id: '1' }, { id: '2' }]
const relationships = [{ id: '12', from: '1', to: '2', type: 'KNOWS' }]
const nvl = new NVL(container, nodes, relationships)带配置选项和回调函数的示例:
javascript
import { NVL } from '@neo4j-nvl/base'
const options = {
initialZoom: 1.0,
minZoom: 0.1,
maxZoom: 8,
layout: 'forceDirected',
renderer: 'canvas',
styling: { defaultNodeColor: '#0e86d4', defaultRelationshipColor: '#888' }
}
const callbacks = {
onInitialization: () => console.log('NVL已就绪'),
onLayoutDone: () => nvl.fit([]),
onError: (err) => console.error('NVL错误', err)
}
const nvl = new NVL(container, nodes, relationships, options, callbacks)
// 销毁时必须执行:
nvl.destroy()NVLnew NVL(frame, nvlNodes?, nvlRels?, options?, callbacks?)frameVanilla — Interaction Handlers
原生JS —— 交互处理器
Compose handlers onto an existing instance. Each handler registers callbacks via and must be torn down with .
NVL.updateCallback(name, fn).destroy()javascript
import { NVL } from '@neo4j-nvl/base'
import {
ZoomInteraction, PanInteraction, DragNodeInteraction,
ClickInteraction, HoverInteraction, BoxSelectInteraction,
LassoInteraction, KeyboardInteraction
} from '@neo4j-nvl/interaction-handlers'
const nvl = new NVL(container, nodes, relationships)
const zoom = new ZoomInteraction(nvl)
const pan = new PanInteraction(nvl)
const drag = new DragNodeInteraction(nvl)
const click = new ClickInteraction(nvl, { selectOnClick: true })
const hover = new HoverInteraction(nvl, { drawShadowOnHover: true })
click.updateCallback('onNodeClick', (node, hits, evt) => console.log('node', node.id))
click.updateCallback('onRelationshipClick', (rel, hits, evt) => console.log('rel', rel.id))
click.updateCallback('onCanvasClick', (evt) => console.log('canvas'))
hover.updateCallback('onHover', (el, hits, evt) => el && console.log('over', el.id))
drag.updateCallback('onDragEnd', (nodes, evt) => savePositions(nodes))
zoom.updateCallback('onZoom', (level) => console.log('zoom', level))
// Teardown — destroy all handlers, then the NVL instance
function teardown() {
for (const h of [zoom, pan, drag, click, hover]) h.destroy()
nvl.destroy()
}Disable an event without removing the handler: . Passing instead of a function enables the event with a no-op (useful for default selection behavior).
click.removeCallback('onCanvasClick')true将处理器组合到已有的实例中。每个处理器通过注册回调函数,并且必须通过销毁。
NVL.updateCallback(name, fn).destroy()javascript
import { NVL } from '@neo4j-nvl/base'
import {
ZoomInteraction, PanInteraction, DragNodeInteraction,
ClickInteraction, HoverInteraction, BoxSelectInteraction,
LassoInteraction, KeyboardInteraction
} from '@neo4j-nvl/interaction-handlers'
const nvl = new NVL(container, nodes, relationships)
const zoom = new ZoomInteraction(nvl)
const pan = new PanInteraction(nvl)
const drag = new DragNodeInteraction(nvl)
const click = new ClickInteraction(nvl, { selectOnClick: true })
const hover = new HoverInteraction(nvl, { drawShadowOnHover: true })
click.updateCallback('onNodeClick', (node, hits, evt) => console.log('节点', node.id))
click.updateCallback('onRelationshipClick', (rel, hits, evt) => console.log('关系', rel.id))
click.updateCallback('onCanvasClick', (evt) => console.log('画布'))
hover.updateCallback('onHover', (el, hits, evt) => el && console.log('悬停在', el.id))
drag.updateCallback('onDragEnd', (nodes, evt) => savePositions(nodes))
zoom.updateCallback('onZoom', (level) => console.log('缩放级别', level))
// 销毁流程 —— 先销毁所有处理器,再销毁NVL实例
function teardown() {
for (const h of [zoom, pan, drag, click, hover]) h.destroy()
nvl.destroy()
}无需移除处理器即可禁用事件:。传入而非函数表示启用事件但不执行任何操作(适用于默认选择行为)。
click.removeCallback('onCanvasClick')trueReact — InteractiveNvlWrapper
React —— InteractiveNvlWrapper
Pre-wires every interaction handler. Toggle events with (function = on + callback; = on, no-op; /omit = off).
mouseEventCallbackstruefalsetsx
import { InteractiveNvlWrapper } from '@neo4j-nvl/react'
import type { MouseEventCallbacks, NvlOptions } from '@neo4j-nvl/react'
import { useRef } from 'react'
import type { NVL } from '@neo4j-nvl/base'
export function GraphView({ nodes, rels }) {
const nvlRef = useRef<NVL>(null)
const nvlOptions: NvlOptions = { initialZoom: 1, renderer: 'canvas' }
const mouseEventCallbacks: MouseEventCallbacks = {
onNodeClick: (node, hits, evt) => console.log('node', node.id),
onRelationshipClick: (rel, hits, evt) => console.log('rel', rel.id),
onCanvasClick: (evt) => console.log('canvas'),
onHover: (el, hits, evt) => el && console.log('hover', el.id),
onDragEnd: (nodes, evt) => persist(nodes),
onZoom: true, // enable, no callback
onPan: true
}
return (
<div style={{ width: '100%', height: 600 }}>
<InteractiveNvlWrapper
ref={nvlRef}
nodes={nodes}
rels={rels}
nvlOptions={nvlOptions}
interactionOptions={{ selectOnClick: true, drawShadowOnHover: true }}
mouseEventCallbacks={mouseEventCallbacks}
onInitializationError={(err) => console.error('NVL init', err)}
/>
</div>
)
}refNVLnvlRef.current?.fit([])nvlRef.current?.setRenderer('webgl')nvlRef.current?.saveToFile()预配置了所有交互处理器。通过切换事件(传入函数表示启用并绑定回调;表示启用但无回调;/省略表示禁用)。
mouseEventCallbackstruefalsetsx
import { InteractiveNvlWrapper } from '@neo4j-nvl/react'
import type { MouseEventCallbacks, NvlOptions } from '@neo4j-nvl/react'
import { useRef } from 'react'
import type { NVL } from '@neo4j-nvl/base'
export function GraphView({ nodes, rels }) {
const nvlRef = useRef<NVL>(null)
const nvlOptions: NvlOptions = { initialZoom: 1, renderer: 'canvas' }
const mouseEventCallbacks: MouseEventCallbacks = {
onNodeClick: (node, hits, evt) => console.log('节点', node.id),
onRelationshipClick: (rel, hits, evt) => console.log('关系', rel.id),
onCanvasClick: (evt) => console.log('画布'),
onHover: (el, hits, evt) => el && console.log('悬停', el.id),
onDragEnd: (nodes, evt) => persist(nodes),
onZoom: true, // 启用,无回调
onPan: true
}
return (
<div style={{ width: '100%', height: 600 }}>
<InteractiveNvlWrapper
ref={nvlRef}
nodes={nodes}
rels={rels}
nvlOptions={nvlOptions}
interactionOptions={{ selectOnClick: true, drawShadowOnHover: true }}
mouseEventCallbacks={mouseEventCallbacks}
onInitializationError={(err) => console.error('NVL初始化错误', err)}
/>
</div>
)
}refNVLnvlRef.current?.fit([])nvlRef.current?.setRenderer('webgl')nvlRef.current?.saveToFile()React — BasicNvlWrapper + Ref
React —— BasicNvlWrapper + Ref
No interactions wired. The ref exposes every NVL method via — use when building custom interaction logic in React.
IncludeMethods<NVL>tsx
import { BasicNvlWrapper } from '@neo4j-nvl/react'
import type { NVL } from '@neo4j-nvl/base'
import { useRef } from 'react'
export function MiniGraph({ nodes, rels }) {
const nvlRef = useRef<NVL>(null)
return (
<div style={{ width: '100%', height: 400 }}>
<BasicNvlWrapper
ref={nvlRef}
nodes={nodes}
rels={rels}
nvlOptions={{ initialZoom: 2 }}
nvlCallbacks={{ onLayoutDone: () => nvlRef.current?.fit([]) }}
/>
<button onClick={() => nvlRef.current?.fit(['1', '2'])}>Zoom to 1,2</button>
</div>
)
}未配置任何交互。通过可以访问的所有方法(类型为)——适用于在React中构建自定义交互逻辑的场景。
refNVLIncludeMethods<NVL>tsx
import { BasicNvlWrapper } from '@neo4j-nvl/react'
import type { NVL } from '@neo4j-nvl/base'
import { useRef } from 'react'
export function MiniGraph({ nodes, rels }) {
const nvlRef = useRef<NVL>(null)
return (
<div style={{ width: '100%', height: 400 }}>
<BasicNvlWrapper
ref={nvlRef}
nodes={nodes}
rels={rels}
nvlOptions={{ initialZoom: 2 }}
nvlCallbacks={{ onLayoutDone: () => nvlRef.current?.fit([]) }}
/>
<button onClick={() => nvlRef.current?.fit(['1', '2'])}>缩放至节点1、2</button>
</div>
)
}Wiring a Neo4j Driver Result
对接Neo4j驱动结果
@neo4j-nvl/baseResultTransformerjavascript
import neo4j from 'neo4j-driver'
import { NVL, nvlResultTransformer } from '@neo4j-nvl/base'
const driver = neo4j.driver(process.env.NEO4J_URI,
neo4j.auth.basic(process.env.NEO4J_USERNAME, process.env.NEO4J_PASSWORD))
const { nodes, relationships } = await driver.executeQuery(
'MATCH (a)-[r]-(b) RETURN a, r, b LIMIT 25',
{},
{ database: 'neo4j', resultTransformer: nvlResultTransformer }
)
const nvl = new NVL(document.getElementById('viz'), nodes, relationships)javascript
// ❌ raw EagerResult — records are not Node/Relationship objects
const result = await driver.executeQuery('MATCH (a)-[r]-(b) RETURN a, r, b')
new NVL(container, result.records, []) // breaks
// ✅ use the transformer
const { nodes, relationships } = await driver.executeQuery(
'MATCH (a)-[r]-(b) RETURN a, r, b',
{},
{ database: 'neo4j', resultTransformer: nvlResultTransformer }
)
new NVL(container, nodes, relationships)For driver lifecycle, session management, Integer handling, and TypeScript types → .
neo4j-driver-javascript-skill@neo4j-nvl/baseResultTransformerjavascript
import neo4j from 'neo4j-driver'
import { NVL, nvlResultTransformer } from '@neo4j-nvl/base'
const driver = neo4j.driver(process.env.NEO4J_URI,
neo4j.auth.basic(process.env.NEO4J_USERNAME, process.env.NEO4J_PASSWORD))
const { nodes, relationships } = await driver.executeQuery(
'MATCH (a)-[r]-(b) RETURN a, r, b LIMIT 25',
{},
{ database: 'neo4j', resultTransformer: nvlResultTransformer }
)
const nvl = new NVL(document.getElementById('viz'), nodes, relationships)javascript
// ❌ 直接传入原始EagerResult —— 记录不是Node/Relationship对象
const result = await driver.executeQuery('MATCH (a)-[r]-(b) RETURN a, r, b')
new NVL(container, result.records, []) // 会报错
// ✅ 使用转换器
const { nodes, relationships } = await driver.executeQuery(
'MATCH (a)-[r]-(b) RETURN a, r, b',
{},
{ database: 'neo4j', resultTransformer: nvlResultTransformer }
)
new NVL(container, nodes, relationships)关于驱动生命周期、会话管理、整数处理和TypeScript类型,请参考。
neo4j-driver-javascript-skillUpdating the Graph
更新图数据
| Method | Behavior |
|---|---|
| Insert new; update existing by id (only specified fields) |
| Update existing only; ignores unknown ids |
| Insert only; throws on existing id |
| Remove nodes; adjacent relationships auto-removed |
| Remove relationships |
| Override positions; optionally re-run layout |
| Restart with new options; positions optional |
Diff updates use / — only is required:
PartialNodePartialRelationshipidjavascript
nvl.updateElementsInGraph(
[{ id: '1', color: '#f00', selected: true }], // PartialNode
[{ id: '12', width: 4 }] // PartialRelationship
)| 方法 | 行为 |
|---|---|
| 插入新元素;根据id更新现有元素(仅更新指定字段) |
| 仅更新现有元素;忽略未知id |
| 仅插入新元素;若id已存在则抛出错误 |
| 删除节点;自动删除关联的关系 |
| 删除关系 |
| 覆盖节点位置;可选重新运行布局算法 |
| 使用新配置重启;可选保留节点位置 |
增量更新使用 / 类型——仅需指定:
PartialNodePartialRelationshipidjavascript
nvl.updateElementsInGraph(
[{ id: '1', color: '#f00', selected: true }], // PartialNode
[{ id: '12', width: 4 }] // PartialRelationship
)Hit Testing (Manual)
手动命中检测
Use when NOT using the interaction-handlers package. resolves which node/relationship is under a pointer event.
getHits()javascript
const nvl = new NVL(container, nodes, rels)
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) console.log('hit node', hitNode.data.id)
else if (hitRel) console.log('hit rel', hitRel.data.id)
else console.log('hit canvas')
})HitTargetNodeHitTargetRelationshipdatapointerCoordinatesdistanceinsideNode当不使用interaction-handlers包时适用。可判断指针事件下方对应的节点/关系。
getHits()javascript
const nvl = new NVL(container, nodes, rels)
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) console.log('命中节点', hitNode.data.id)
else if (hitRel) console.log('命中关系', hitRel.data.id)
else console.log('命中画布')
})HitTargetNodeHitTargetRelationshipdatapointerCoordinatesdistanceinsideNodeCommon Mistakes
常见错误
| Mistake | Fix |
|---|---|
Container with no | Set explicit |
Pass | Use |
| WebGL for small label-rich graphs | Use |
| Canvas for 10k+ nodes | Switch to |
New | Use |
Forgetting | Call |
| Vanilla handlers not torn down | Call |
| Worker construction blocked (strict CSP / sandboxed runtime / older bundler) | |
| Telemetry enabled in regulated env | |
| Layout never settles | Pin anchor nodes with |
| Toggle once at mount; don't flip |
| Hit test misses near node edge | Pass |
| Captions missing on WebGL | GPU max texture size exceeded; fall back to Canvas or shrink captions |
| 错误 | 修复方案 |
|---|---|
容器未设置 | 为容器设置明确的 |
直接传入 | 使用 |
| 对小型富标签图使用WebGL | 使用 |
| 对10000+节点使用Canvas | 通过 |
React每次渲染都创建新的 | 使用 |
销毁时忘记调用 | 在卸载时调用 |
| 原生JS处理器未销毁 | 在调用 |
| Worker构建被阻止(严格CSP / 沙箱运行时 / 旧版打包工具) | 设置 |
| 受监管环境中启用了遥测 | 设置 |
| 布局无法稳定 | 使用 |
| 在挂载时仅切换一次;不要在每次渲染时修改 |
| 节点边缘附近的命中检测失败 | 在 |
| WebGL中缺少标题 | 超出GPU最大纹理尺寸;切换为Canvas或缩小标题 |
References
参考资料
Load on demand:
- references/api-surface.md — complete method table;
NVL,Node,Relationship,NvlOptions,LayoutOptions,ExternalCallbacks,HitTargets,NvlMouseEvent,StyledCaption; every interaction-handler class + its options + its callback signatures; ReactPoint/<InteractiveNvlWrapper>/<BasicNvlWrapper>props;<StaticPictureWrapper>andMouseEventCallbacksshapes; named exports inventory;KeyboardEventCallbackssignaturenvlResultTransformer - references/troubleshooting.md — zero-height container, build-tool-agnostic fallback, Canvas/WebGL trade-offs + WebGL2 note, WebGL texture-size cap,
disableWebWorkersrecovery, telemetry opt-out, memory leaks, stuck layouts, double selection, hit-margin tuning, license restrictiononWebGLContextLost
Canonical web documentation (use when references above are insufficient):
WebFetch- https://neo4j.com/docs/nvl/current/ — user guide (installation, base library, interaction handlers, React wrappers)
- https://neo4j.com/docs/api/nvl/current/ — TypeDoc API reference
- https://neo4j.com/docs/api/nvl/current/examples.html — runnable examples
- https://github.com/neo4j-devtools/nvl-boilerplates — official starter templates per supported framework
- https://github.com/neo4j/python-graph-visualization — Python port of NVL (use this skill only for the JavaScript/browser path)
按需加载:
- references/api-surface.md —— 完整的方法表;
NVL、Node、Relationship、NvlOptions、LayoutOptions、ExternalCallbacks、HitTargets、NvlMouseEvent、StyledCaption类型定义;所有交互处理器类及其配置选项、回调签名;React组件Point/<InteractiveNvlWrapper>/<BasicNvlWrapper>的属性;<StaticPictureWrapper>和MouseEventCallbacks结构;命名导出清单;KeyboardEventCallbacks签名nvlResultTransformer - references/troubleshooting.md —— 零高度容器问题、与打包工具无关的fallback方案、Canvas/WebGL权衡及WebGL2说明、WebGL纹理尺寸限制、
disableWebWorkers恢复方法、遥测退出选项、内存泄漏、布局停滞、重复选择、命中边距调整、许可证限制onWebGLContextLost
官方Web文档(当上述参考资料不足时使用):
- https://neo4j.com/docs/nvl/current/ —— 用户指南(安装、基础库、交互处理器、React封装组件)
- 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 —— 官方提供的各支持框架启动模板
- https://github.com/neo4j/python-graph-visualization —— NVL的Python移植版本(本技能仅适用于JavaScript/浏览器场景)
Checklist
检查清单
- Container has explicit AND
widthCSSheight - Correct paradigm chosen from the decision table (vanilla / handlers / React)
- Renderer matches expected node count (Canvas ≲1k / WebGL 100k+)
- Driver results piped through
executeQuerynvlResultTransformer - specified on every
databasecall (delegate toexecuteQuery)neo4j-driver-javascript-skill - All interaction handlers -ed before
.destroy()on teardownnvl.destroy() - called on React unmount (manual instances only — wrappers handle it)
nvl.destroy() - set when in regulated / offline environments
disableTelemetry: true - set when bundler / CSP blocks worker construction
disableWebWorkers: true - Graph updates use /
addAndUpdateElementsInGraph— notupdateElementsInGraphrestart - License compatible: target is a Neo4j product
- 容器已设置明确的和
widthCSS样式height - 根据决策表选择了正确的实现方式(原生JS / 交互处理器 / React)
- 渲染器与预期节点数量匹配(Canvas ≲1000 / WebGL 100000+)
- 驱动结果已通过
executeQuery处理nvlResultTransformer - 每次调用都指定了
executeQuery(参考database)neo4j-driver-javascript-skill - 销毁时,所有交互处理器都在前调用了
nvl.destroy().destroy() - React卸载时调用了(仅手动创建的实例需要——封装组件会自动处理)
nvl.destroy() - 在受监管/离线环境中设置了
disableTelemetry: true - 当打包工具/CSP阻止Worker构建时设置了
disableWebWorkers: true - 图更新使用/
addAndUpdateElementsInGraph—— 而非updateElementsInGraphrestart - 许可证兼容:目标应用为Neo4j产品