neo4j-nvl-skill

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

  • Rendering a Neo4j graph in a browser (vanilla JS, React, Vite) with custom interactions, rendering, or data shapes
  • Visualizing
    driver.executeQuery
    results as an interactive graph
  • 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
    GraphVisualization
    from
    @neo4j-ndl/react
    (Neo4j Needle / NDL design system) — wraps NVL with default Neo4j styling. See Use NVL or the Needle Component? below.
  • Python / Jupyter notebook graph visualization
    neo4j/python-graph-visualization
    (the Python port of NVL)
  • 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
    neo4j-gds-skill
    or
    neo4j-aura-graph-analytics-skill
  • GraphQL API
    neo4j-graphql-skill

  • 带有默认样式和行为的预定义嵌入图视图,无需自定义交互 → 使用
    @neo4j-ndl/react
    中的
    GraphVisualization
    (Neo4j Needle / NDL设计系统)——该组件封装了NVL并提供默认Neo4j样式。详见下方的【选择NVL还是Needle组件?】。
  • Python / Jupyter Notebook图可视化 → 使用
    neo4j/python-graph-visualization
    (NVL的Python移植版本)
  • 编写/优化Cypher查询 → 使用
    neo4j-cypher-skill
  • 驱动配置 / executeQuery / 会话管理 → 使用
    neo4j-driver-javascript-skill
  • 仅服务端数据获取,无需渲染 → 使用
    neo4j-driver-javascript-skill
  • 执行GDS算法 → 使用
    neo4j-gds-skill
    neo4j-aura-graph-analytics-skill
  • GraphQL API → 使用
    neo4j-graphql-skill

Use NVL or the Needle Component?

选择NVL还是Needle组件?

NeedUse
Embed a graph view with default Neo4j styling, no custom interactions or rendering
GraphVisualization
from
@neo4j-ndl/react
(Neo4j Needle / NDL design system) — wraps NVL and accepts records shaped
{ id, labels, properties: { key: { stringified, type } } }
(
NeoNode
)
Custom interactions, custom rendering, non-standard data shapes, or framework-agnostic embeddingThis 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样式的图视图,无需自定义交互或渲染使用
@neo4j-ndl/react
中的
GraphVisualization
(Neo4j Needle / NDL设计系统)——封装了NVL,接收格式为
{ id, labels, properties: { key: { stringified, type } } }
NeoNode
类型数据
需要自定义交互、自定义渲染、非标准数据结构,或与框架无关的嵌入方式直接使用本技能中的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
@neo4j-nvl/react
. The published peerDependency range still permits React 18, but mixing major versions is not recommended — target 19.
@neo4j-nvl/layout-workers
is a transitive dependency — never install directly.
neo4j-driver
is a peer of
@neo4j-nvl/base
only when using
nvlResultTransformer
.
Starter 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封装组件(可选)
依赖要求:使用
@neo4j-nvl/react
需要React 19。已发布的peerDependency范围仍允许React 18,但不建议混合使用主版本——优先选择React 19。
@neo4j-nvl/layout-workers
是间接依赖,请勿直接安装。仅当使用
nvlResultTransformer
时,
neo4j-driver
才是
@neo4j-nvl/base
的对等依赖。
启动模板:https://github.com/neo4j-devtools/nvl-boilerplates —— 官方提供的各框架脚手架;优先使用这些模板而非手动搭建。
许可证:NVL采用Neo4j可视化库许可证——仅可用于Neo4j产品,不能用于其他图数据库后端。

Pick the Right Paradigm

选择合适的实现方式

NeedUse
React app, default interactions
<InteractiveNvlWrapper>
from
@neo4j-nvl/react
React app, custom interaction wiring
<BasicNvlWrapper>
+ own handlers via
ref
Vanilla JS, standard interactions
NVL
+
@neo4j-nvl/interaction-handlers
Vanilla JS, fully custom event logic
NVL
+
container.addEventListener
+
nvl.getHits()
Static PNG/SVG image export
<StaticPictureWrapper>
or
nvl.saveToFile()
/
nvl.saveToSvg()

需求推荐方案
React应用,使用默认交互使用
@neo4j-nvl/react
中的
<InteractiveNvlWrapper>
React应用,自定义交互逻辑使用
<BasicNvlWrapper>
+ 通过
ref
绑定自定义处理器
原生JS应用,使用标准交互使用
NVL
+
@neo4j-nvl/interaction-handlers
原生JS应用,完全自定义事件逻辑使用
NVL
+
container.addEventListener
+
nvl.getHits()
导出静态PNG/SVG图片使用
<StaticPictureWrapper>
nvl.saveToFile()
/
nvl.saveToSvg()

Pick the Right Renderer

选择合适的渲染器

RendererMax nodesDetailUse case
'canvas'
(default)
~1,000Full captions, icons, arrows, pixel-perfect hit-testingDetail investigation, small graphs
'webgl'
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

渲染器最大节点数细节表现适用场景
'canvas'
(默认)
~1000完整标题、图标、箭头、像素级命中检测细节探究、小型图
'webgl'
100,000+标签保真度降低(受GPU最大纹理尺寸限制)大规模模式探索
javascript
const nvl = new NVL(container, nodes, rels, { renderer: 'webgl' })
nvl.setRenderer('canvas')   // 运行时切换渲染器

Container Setup

容器配置

The container must have an explicit
width
AND
height
. Missing height → container collapses to
0
→ graph invisible. Most-reported NVL bug.
html
<!-- ❌ height defaults to 0; graph invisible -->
<div id="viz"></div>

<!-- ✅ explicit dimensions -->
<div id="viz" style="width: 100%; height: 600px;"></div>

容器必须设置明确的
width
height
。未设置高度会导致容器高度为
0
,图不可见——这是NVL最常被报告的问题。
html
<!-- ❌ 高度默认为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()
NVL
constructor signature:
new NVL(frame, nvlNodes?, nvlRels?, options?, callbacks?)
. All but
frame
are optional and default to empty.

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)
带配置选项和回调函数的示例:
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()
NVL
构造函数签名:
new NVL(frame, nvlNodes?, nvlRels?, options?, callbacks?)
。除
frame
外,其余参数均为可选,默认值为空。

Vanilla — Interaction Handlers

原生JS —— 交互处理器

Compose handlers onto an existing
NVL
instance. Each handler registers callbacks via
.updateCallback(name, fn)
and must be torn down with
.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:
click.removeCallback('onCanvasClick')
. Passing
true
instead of a function enables the event with a no-op (useful for default selection behavior).

将处理器组合到已有的
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')
。传入
true
而非函数表示启用事件但不执行任何操作(适用于默认选择行为)。

React — InteractiveNvlWrapper

React —— InteractiveNvlWrapper

Pre-wires every interaction handler. Toggle events with
mouseEventCallbacks
(function = on + callback;
true
= on, no-op;
false
/omit = off).
tsx
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>
  )
}
ref
resolves to the underlying
NVL
instance — call any method on it:
nvlRef.current?.fit([])
,
nvlRef.current?.setRenderer('webgl')
,
nvlRef.current?.saveToFile()
.

预配置了所有交互处理器。通过
mouseEventCallbacks
切换事件(传入函数表示启用并绑定回调;
true
表示启用但无回调;
false
/省略表示禁用)。
tsx
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>
  )
}
ref
指向底层的
NVL
实例——可以调用其任意方法:
nvlRef.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
IncludeMethods<NVL>
— use when building custom interaction logic in React.
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>
  )
}

未配置任何交互。通过
ref
可以访问
NVL
的所有方法(类型为
IncludeMethods<NVL>
)——适用于在React中构建自定义交互逻辑的场景。
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/base
exports a
ResultTransformer
for the JS driver that deduplicates nodes/relationships across any record shape.
javascript
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/base
导出了适用于JS驱动的
ResultTransformer
,可以对任意记录结构中的节点/关系进行去重。
javascript
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-skill

Updating the Graph

更新图数据

MethodBehavior
addAndUpdateElementsInGraph(nodes, rels)
Insert new; update existing by id (only specified fields)
updateElementsInGraph(nodes, rels)
Update existing only; ignores unknown ids
addElementsToGraph(nodes, rels)
Insert only; throws on existing id
removeNodesWithIds(ids)
Remove nodes; adjacent relationships auto-removed
removeRelationshipsWithIds(ids)
Remove relationships
setNodePositions(nodes, updateLayout?)
Override positions; optionally re-run layout
restart(options?, retainPositions?)
Restart with new options; positions optional
Diff updates use
PartialNode
/
PartialRelationship
— only
id
is required:
javascript
nvl.updateElementsInGraph(
  [{ id: '1', color: '#f00', selected: true }],   // PartialNode
  [{ id: '12', width: 4 }]                         // PartialRelationship
)

方法行为
addAndUpdateElementsInGraph(nodes, rels)
插入新元素;根据id更新现有元素(仅更新指定字段)
updateElementsInGraph(nodes, rels)
仅更新现有元素;忽略未知id
addElementsToGraph(nodes, rels)
仅插入新元素;若id已存在则抛出错误
removeNodesWithIds(ids)
删除节点;自动删除关联的关系
removeRelationshipsWithIds(ids)
删除关系
setNodePositions(nodes, updateLayout?)
覆盖节点位置;可选重新运行布局算法
restart(options?, retainPositions?)
使用新配置重启;可选保留节点位置
增量更新使用
PartialNode
/
PartialRelationship
类型——仅需指定
id
javascript
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.
getHits()
resolves which node/relationship is under a pointer event.
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')
})
HitTargetNode
/
HitTargetRelationship
carry
data
,
pointerCoordinates
,
distance
,
insideNode
(nodes only). See references/api-surface.md.

当不使用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('命中画布')
})
HitTargetNode
/
HitTargetRelationship
包含
data
pointerCoordinates
distance
insideNode
(仅节点有)等属性。详见references/api-surface.md

Common Mistakes

常见错误

MistakeFix
Container with no
height
→ invisible graph
Set explicit
width
and
height
on the container
Pass
driver.executeQuery
result directly
Use
nvlResultTransformer
and consume
{ nodes, relationships }
WebGL for small label-rich graphsUse
'canvas'
; labels are fully supported
Canvas for 10k+ nodesSwitch to
'webgl'
via
renderer
option or
setRenderer
New
NVL
per React render
Use
<InteractiveNvlWrapper>
/
<BasicNvlWrapper>
or wrap in
useEffect
+
destroy()
Forgetting
nvl.destroy()
on teardown
Call
destroy()
on unmount; React wrappers handle this automatically
Vanilla handlers not torn downCall
.destroy()
on every interaction before
nvl.destroy()
Worker construction blocked (strict CSP / sandboxed runtime / older bundler)
nvlOptions: { disableWebWorkers: true }
(NVL has a non-worker fallback)
Telemetry enabled in regulated env
nvlOptions: { disableTelemetry: true }
Layout never settlesPin anchor nodes with
pinNode(id)
; tune
layoutTimeLimit
selectOnClick
fires double
Toggle once at mount; don't flip
interactionOptions
per render
Hit test misses near node edgePass
{ hitNodeMarginWidth: N }
to
getHits
Captions missing on WebGLGPU max texture size exceeded; fall back to Canvas or shrink captions

错误修复方案
容器未设置
height
→ 图不可见
为容器设置明确的
width
height
直接传入
driver.executeQuery
结果
使用
nvlResultTransformer
并获取
{ nodes, relationships }
对小型富标签图使用WebGL使用
'canvas'
渲染器;该渲染器完全支持标签显示
对10000+节点使用Canvas通过
renderer
选项或
setRenderer
切换为
'webgl'
React每次渲染都创建新的
NVL
实例
使用
<InteractiveNvlWrapper>
/
<BasicNvlWrapper>
,或在
useEffect
中创建并调用
destroy()
销毁时忘记调用
nvl.destroy()
在卸载时调用
destroy()
;React封装组件会自动处理此操作
原生JS处理器未销毁在调用
nvl.destroy()
前销毁所有交互处理器
Worker构建被阻止(严格CSP / 沙箱运行时 / 旧版打包工具)设置
nvlOptions: { disableWebWorkers: true }
(NVL提供非Worker fallback方案)
受监管环境中启用了遥测设置
nvlOptions: { disableTelemetry: true }
布局无法稳定使用
pinNode(id)
固定锚点节点;调整
layoutTimeLimit
selectOnClick
触发两次
在挂载时仅切换一次;不要在每次渲染时修改
interactionOptions
节点边缘附近的命中检测失败
getHits
中传入
{ hitNodeMarginWidth: N }
WebGL中缺少标题超出GPU最大纹理尺寸;切换为Canvas或缩小标题

References

参考资料

Load on demand:
  • references/api-surface.md — complete
    NVL
    method table;
    Node
    ,
    Relationship
    ,
    NvlOptions
    ,
    LayoutOptions
    ,
    ExternalCallbacks
    ,
    HitTargets
    ,
    NvlMouseEvent
    ,
    StyledCaption
    ,
    Point
    ; every interaction-handler class + its options + its callback signatures; React
    <InteractiveNvlWrapper>
    /
    <BasicNvlWrapper>
    /
    <StaticPictureWrapper>
    props;
    MouseEventCallbacks
    and
    KeyboardEventCallbacks
    shapes; named exports inventory;
    nvlResultTransformer
    signature
  • references/troubleshooting.md — zero-height container, build-tool-agnostic
    disableWebWorkers
    fallback, Canvas/WebGL trade-offs + WebGL2 note, WebGL texture-size cap,
    onWebGLContextLost
    recovery, telemetry opt-out, memory leaks, stuck layouts, double selection, hit-margin tuning, license restriction
Canonical web documentation (use
WebFetch
when references above are insufficient):

按需加载:
  • references/api-surface.md —— 完整的
    NVL
    方法表;
    Node
    Relationship
    NvlOptions
    LayoutOptions
    ExternalCallbacks
    HitTargets
    NvlMouseEvent
    StyledCaption
    Point
    类型定义;所有交互处理器类及其配置选项、回调签名;React组件
    <InteractiveNvlWrapper>
    /
    <BasicNvlWrapper>
    /
    <StaticPictureWrapper>
    的属性;
    MouseEventCallbacks
    KeyboardEventCallbacks
    结构;命名导出清单;
    nvlResultTransformer
    签名
  • references/troubleshooting.md —— 零高度容器问题、与打包工具无关的
    disableWebWorkers
    fallback方案、Canvas/WebGL权衡及WebGL2说明、WebGL纹理尺寸限制、
    onWebGLContextLost
    恢复方法、遥测退出选项、内存泄漏、布局停滞、重复选择、命中边距调整、许可证限制
官方Web文档(当上述参考资料不足时使用):

Checklist

检查清单

  • Container has explicit
    width
    AND
    height
    CSS
  • Correct paradigm chosen from the decision table (vanilla / handlers / React)
  • Renderer matches expected node count (Canvas ≲1k / WebGL 100k+)
  • Driver
    executeQuery
    results piped through
    nvlResultTransformer
  • database
    specified on every
    executeQuery
    call (delegate to
    neo4j-driver-javascript-skill
    )
  • All interaction handlers
    .destroy()
    -ed before
    nvl.destroy()
    on teardown
  • nvl.destroy()
    called on React unmount (manual instances only — wrappers handle it)
  • disableTelemetry: true
    set when in regulated / offline environments
  • disableWebWorkers: true
    set when bundler / CSP blocks worker construction
  • Graph updates use
    addAndUpdateElementsInGraph
    /
    updateElementsInGraph
    — not
    restart
  • License compatible: target is a Neo4j product
  • 容器已设置明确的
    width
    height
    CSS样式
  • 根据决策表选择了正确的实现方式(原生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
    /
    updateElementsInGraph
    —— 而非
    restart
  • 许可证兼容:目标应用为Neo4j产品