topology-graph-vue
v1.1.1
Published
High-performance Vue 3 topology graph component library based on PixiJS v8, supporting 50,000+ nodes at 60 FPS
Maintainers
Readme
TopologyGraph Vue
高性能 Vue 3 拓扑图组件库,基于 PixiJS v8,支持 50,000+ 节点 60 FPS 渲染。
特性
- 🚀 极致性能: LOD 多级降级渲染 + 空间索引裁剪 + 对象池复用 + GPU 预览模式 + Float32Array 力导向迭代,5W+ 节点流畅运行
- 🎨 丰富图形: 5 种节点形状 (圆/矩形/菱形/六边形/星形) × 3 种线型 (实线/虚线/点线) × 5 种曲线 (直线/贝塞尔/弧线/阶梯HV/VH)
- 📦 插件化架构: Vue 插件全局注册 + provide/inject 子组件协作,Minimap / SelectionBox / Toolbar 即插即用
- 🔧 完整 TypeScript: 全程类型覆盖,构建自动生成
.d.ts声明文件 - 🎯 丰富交互: 拖拽/缩放/框选(空间索引加速)/多选/撤销重做/搜索聚焦
- 🎨 双主题: 亮色 / 暗色主题一键切换,运行时可自定义覆盖
- 📐 4 种布局: 力导向(Barnes-Hut 近似) / 树形(4 方向展开) / 径向 / 环形
- 📚 LOD 渲染: 4 级降级(detail → normal → simple → dot),缩放时自动切换渲染精度
- ✏️ 自定义绘制: 通过
drawNode/drawLine回调完全覆盖默认渲染,内置图片加载缓存和绘制工具集 - 🎬 连线动画: 流动 / 快速流动 / 脉冲 / 虚线流动 4 种动画效果
- 📸 高清截图导出: RenderTexture 精确裁剪视口区域,支持 PNG/JPEG/WebP 格式,自动适配设备像素比
- 🔄 运行时配置热更新:
setOptions()支持动态修改 LOD 阶梯表、性能参数、主题、样式等全部配置项 - 🧠 智能历史管理: 大数据量(>10000 节点) 自动禁用撤销以节省内存,快照数量自适应限制
安装
npm install topology-graph-vue依赖要求:
- Node.js >= 18.0.0
- Vue ^3.3.0 || ^3.4.0 || ^3.5.0
- PixiJS ^8.17.1 (自动安装)
快速开始
方式一:全局注册 (推荐)
import { createApp } from 'vue'
import TopologyGraph from 'topology-graph-vue'
import 'topology-graph-vue/style.css'
const app = createApp(App)
app.use(TopologyGraph)
app.mount('#app')全局注册后可在模板中直接使用:
| 组件 | 说明 |
|------|------|
| <TopologyGraph> | 主组件(画布 + API 注入) |
| <TopologyGraphMinimap> | 小地图 |
| <TopologyGraphSelectionBox> | 选区操作框 |
| <TopologyGraphToolbar> | 浮动工具栏 |
<template>
<TopologyGraph @ready="onReady">
<TopologyGraphMinimap position="right-bottom" />
<TopologyGraphSelectionBox />
</TopologyGraph>
</template>方式二:按需引入
<script setup>
import { TopologyGraph, Minimap, SelectionBox } from 'topology-graph-vue'
import 'topology-graph-vue/style.css'
</script>
<template>
<TopologyGraph @ready="onReady">
<Minimap position="right-bottom" />
<SelectionBox />
</TopologyGraph>
</template>完整示例
<script setup>
import { ref } from 'vue'
import {
TopologyGraph,
Minimap,
SelectionBox,
GraphToolbar,
} from 'topology-graph-vue'
import 'topology-graph-vue/style.css'
const graphApi = ref(null)
function onReady(api) {
graphApi.value = api
// 设置数据(兼容 relation-graph JSON 格式)
api.setJsonData({
nodes: [
{ id: '1', text: '节点1' },
{ id: '2', text: '节点2' },
{ id: '3', text: '节点3' },
],
lines: [
{ from: '1', to: '2' },
{ from: '2', to: '3' },
{ from: '1', to: '3' },
],
})
// 应用力导向布局
api.applyLayout({ type: 'force' })
// 运行时动态调整 LOD 配置
api.setOptions({
lodTiers: [
{ minScale: 1.0, nodeMode: 'detail', lineMode: 'detail', nodeDowngradeThreshold: 200, lineDowngradeThreshold: 400 },
{ minScale: 0.3, nodeMode: 'normal', lineMode: 'normal', nodeDowngradeThreshold: 500, lineDowngradeThreshold: 1000 },
{ minScale: 0.2, nodeMode: 'simple', lineMode: 'simple', nodeDowngradeThreshold: 2000, lineDowngradeThreshold: 4000 },
{ minScale: 0.008, nodeMode: 'dot', lineMode: 'simple', nodeDowngradeThreshold: 30000, lineDowngradeThreshold: 30000 },
],
perfConfig: {
nodeTextMinScale: 0.3,
lineTextMinScale: 0.3,
hoverColorMinScale: 0.3,
},
})
}
</script>
<template>
<div style="width: 100vw; height: 100vh;">
<TopologyGraph :options="{ theme: 'light', enableHistory: true }" @ready="onReady">
<GraphToolbar position="top-right" />
<Minimap :width="200" :height="150" position="right-bottom" />
<SelectionBox />
</TopologyGraph>
</div>
</template>设计亮点
| 特性 | 实现 |
|------|------|
| Core 层解耦 | src/core/ 零 Vue 依赖,可通过 TopologyGraphCore 在非 Vue 环境独立使用 |
| 按需渲染 | 非持续 rAF,通过 requestRender(force) 调度,仅变化时重绘 |
| GPU 预览模式 | Pan/Zoom 时只改 Container transform,零 CPU 渲染开销 |
| 空间索引加速 | 均匀网格哈希 (SpatialGrid) 用于视口裁剪和碰撞检测 |
| 力导向性能 | Float32Array 存储速度 + Barnes-Hut 四叉树近似 O(n log n) |
| 对象池复用 | Graphics(1000) + Text(500),大场景零 GC 抖动 |
| 兼容迁移 | JSON 格式兼容 relation-graph |
API 参考
组件
TopologyGraph(主组件)
内含 PixiJS Canvas + provide/inject 机制。子组件必须放在其插槽内。
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| width | number | — | 画布宽度 (px) |
| height | number | — | 画布高度 (px) |
| theme | 'light' \| 'dark' | 'light' | 主题 |
| devMode | boolean | false | 显示性能面板 |
| options | Partial<TopologyOptions> | {} | 运行时配置选项 |
width/height未设置时默认为父容器尺寸。options变化时通过watch(deep)自动调用setOptions()同步。
Events
| 事件 | 参数 | 说明 |
|------|------|------|
| ready | (api: GraphApi) | 实例就绪,返回完整 API 对象 |
| node-click | (node: GraphNode, event: MouseEvent) | 节点点击 |
| node-dblclick | (node: GraphNode, event: MouseEvent) | 节点双击 |
| node-hover | (node: GraphNode \| null, event: MouseEvent) | 节点悬停 (离开时 node 为 null) |
| line-click | (line: GraphLine, event: MouseEvent) | 连线点击 |
| line-dblclick | (line: GraphLine, event: MouseEvent) | 连线双击 |
| line-hover | (line: GraphLine \| null, event: MouseEvent) | 连线悬停 |
| node-delete | (node: GraphNode) | 节点删除 (单个/批量均触发) |
| node-drag-start | (node: GraphNode) | 节点拖拽开始 |
| node-drag-move | (node: GraphNode, dx, dy) | 节点拖拽中,dx/dy 为累计位移 |
| node-drag-end | (node: GraphNode, dx, dy) | 节点拖拽结束 |
| selection-change | (selectedIds: Set<string>) | 选中变化 (含 Esc 取消) |
| selectionbox-show | (bounds: SelectionBounds, nodeIds: string[]) | 选区框显示 |
| selectionbox-close | — | 选区框关闭 |
| canvas-click | (event, targetType, target?) | 画布点击 (区分 node/line/canvas) |
| canvas-contextmenu | (event, targetType, target?) | 画布右键 |
| canvas-drag-start | — | 画布拖拽开始 |
| canvas-drag-move | (dx, dy) | 画布拖拽中 |
| canvas-drag-end | (dx, dy) | 画布拖拽结束 |
| canvas-zoom | (scale: number) | 缩放结束 |
| viewport-change | (viewport: Viewport) | 视口变化 |
| data-change | ({ nodes: number, lines: number }) | 数据变化 |
Slots
| 插槽 | 说明 | |------|------| | default | 子组件 (Minimap / SelectionBox / GraphToolbar) | | overlay | 自定义叠加层 DOM |
Minimap(小地图)
独立 Canvas 2D 离屏渲染的缩略图导航。支持拖拽平移 + 滚轮缩放 + 点击跳转。
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| width | number | 200 | 宽度 (px) |
| height | number | 150 | 高度 (px) |
| position | MinimapPosition | 'right-bottom' | 位置 |
| dotSize | number | — | 节点半径覆盖 (px) |
| viewportColor | string | — | 视口框颜色 |
| backgroundColor | string | — | 背景颜色 |
MinimapPosition 可选值: 'left-top' \| 'right-top' \| 'left-bottom' \| 'right-bottom' \| 'top-center' \| 'bottom-center' \| 'left-center' \| 'right-center'
SelectionBox(选区操作框)
框选节点后显示操作面板,含选中计数、删除按钮、拖拽移动功能。无需绑定 props/events。
Slots (作用域)
| 插槽 | 参数 | 说明 |
|------|------|------|
| toolbar | { selectedCount, isDragging, onDelete } | 工具栏扩展 |
| default | { selectedCount, isDragging, onDelete } | 内容区域扩展 |
GraphToolbar(浮动工具栏)
14 个功能按钮的悬浮工具栏,可自定义布局和方位定位。
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| position | string | 'top-right' | 8 个方位之一 |
| direction | 'horizontal' \| 'vertical' | 'horizontal' | 排列方向 |
| layout | ButtonId[][] | 见下方 | 按钮二维数组布局 |
默认 layout:
[
['zoomIn', 'scale', 'zoomOut'],
['fitView', 'resetView', 'fullscreen'],
['force', 'tree:top', 'tree:bottom', 'tree:left', 'tree:right', 'radial', 'circle'],
['download', 'import'],
]ButtonId 全部可选值:
| ID | 功能 | ID | 功能 | |----|------|-----|------| | zoomIn | 放大 | resetView | 重置视图 | | zoomOut | 缩小 | fullscreen | 全屏切换 | | scale | 缩放百分比显示 | force | 力导向布局 | | fitView | 适应全部 | tree:top/bottom/left/right | 树形 4 方向 | | download | 导出图片 | circle | 环形布局 | | import | 导入 JSON | radial | 径向布局 |
GraphApi (@ready 回调)
@ready 事件返回的完整 API 对象,约 50 个成员。
响应式状态
| 属性 | 类型 | 说明 |
|------|------|------|
| stats | Ref<PerfStats> | 性能统计 (fps/frameTime/renderTime/nodeCount/scale 等) |
| isDarkTheme | Ref<boolean> | 当前是否暗色主题 |
| canUndo | Ref<boolean> | 是否可撤销 |
| canRedo | Ref<boolean> | 是否可重做 |
数据操作
| 方法 | 说明 |
|------|------|
| generateTestData(count) | 生成随机测试数据 |
| setJsonData(data, append?) | 导入 JSON (兼容 relation-graph 格式,append=true 则追加) |
| getJsonData() | 导出当前数据为 JSON |
数据查询与删除
| 方法 | 说明 |
|------|------|
| getNodes() | 获取所有节点数组 |
| getLines() | 获取所有连线数组 |
| getNodeById(id) | 按 ID 查找节点 |
| getLineById(id) | 按 ID 查找连线 |
| removeNodeById(id) | 删除节点 (同时删除关联连线) |
| removeLineById(id) | 删除连线 |
| dataUpdated() | 强制刷新渲染 (直接修改节点/连线属性后调用) |
视图控制
| 方法 | 说明 |
|------|------|
| resetView() | 重置视图 (scale=1, 居中) |
| fitView() | 自适应视图 (包含所有节点) |
| zoomIn() | 放大一级 |
| zoomOut() | 缩小一级 |
| zoomTo(scale?) | 缩放到指定比例 (默认 1.0) |
| getViewport() | 获取当前视口 { x, y, scale, width, height } |
| setViewport(x, y, scale) | 设置视口位置和缩放 |
| toggleFullscreen() | 全屏切换 |
| getViewInfo() | 获取详细视口信息 (含边界范围等) |
布局
| 方法 | 说明 |
|------|------|
| applyLayout(options) | 应用布局算法 |
LayoutOptions 参数:
| 参数 | 类型 | 默认值 | 适用布局 | 说明 |
|------|------|--------|----------|------|
| type | 'force' \| 'tree' \| 'center' \| 'circle' | 'force' | 全部 | 布局类型 |
| iterations | number | 300 | force | 力导向迭代次数 |
| repulsion | number | 2000 | force | 节点斥力强度 (推荐 2000~10000) |
| springLength | number | 60 | force | 弹簧自然长度 (推荐 50~300) |
| springK | number | 0.1 | force | 弹簧刚度系数 (推荐 0.02~0.15) |
| damping | number | 0.3 | force | 速度阻尼 (推荐 0.2~0.6) |
| direction | 'top' \| 'bottom' \| 'left' \| 'right' | 'bottom' | tree | 树形展开方向 |
| levelDistance | number \| number[] | 120 | tree | 层级间距 (数字或逐层数组) |
| minPerWidth | number | 30 | tree | 同层最小间距 |
| maxPerWidth | number | 200 | tree | 同层最大间距 |
| fixedRootNode | boolean | false | tree | 固定根节点位置 |
| startAngle | number | 0 | center/circle | 起始角度 (弧度) |
| angleStep | 'auto' \| number | 'auto' | center/circle | 角度间距 |
聚焦与搜索
| 方法 | 说明 |
|------|------|
| focusOnNode(nodeId) | 平移+缩放到指定节点居中 (带动画) |
| flashNode(nodeId, duration?) | 节点闪烁效果 (默认 600ms) |
| searchAndFlyTo(query) | 按文本搜索节点并飞向首个匹配 |
选择管理
| 方法 | 说明 |
|------|------|
| selectAll() | 选中全部节点 |
| clearSelection() | 清除选择 |
| deleteSelected() | 删除当前选中节点及关联连线 |
| moveSelectedNodesBy(dx, dy) | 批量移动选中节点 |
| saveCurrentHistory() | 手动保存历史快照 |
聚焦高亮
| 方法 | 说明 |
|------|------|
| focusNodeById(id) | 高亮指定节点 (清除其他节点高亮) |
| focusLineById(id) | 高亮指定连线 (清除其他连线高亮) |
| cancelFocus() | 清除所有聚焦高亮 |
| isFocusing() | 是否处于聚焦状态 |
| setEditingNodes(ids) | 设置编辑选框 (空数组隐藏,与选中状态独立) |
样式控制
| 方法 | 说明 |
|------|------|
| toggleTheme() | 切换亮色/暗色主题 |
| setNodeShape(shape) | 设置节点形状 ('circle' \| 'rect' \| 'diamond' \| 'hexagon' \| 'star') |
| setLineStyle(style) | 设置连线样式 ('solid' \| 'dashed' \| 'dotted') |
| setLineCurve(curve) | 设置曲线类型 ('straight' \| 'bezier' \| 'arc' \| 'step-hv' \| 'step-vh') |
| setLineWidth(w) | 设置全局连线宽度倍率 |
| setCustomDrawCallbacks(callbacks) | 注册自定义绘制回调 |
| applyFilter(color?, text?) | 颜色/文字筛选高亮 |
历史记录
| 方法 | 说明 |
|------|------|
| undo() | 撤销上一步操作 |
| redo() | 重做下一步操作 |
大图 (>10000 节点 或 >20000 连线) 自动禁用以节省内存。
导出
| 方法 | 说明 |
|------|------|
| downloadAsImage(filename?, options?) | 下载当前视口可见区域为图片 |
ImageExportOptions:
{
format?: 'image/png' | 'image/jpeg' | 'image/webp' // 默认 'image/webp'
quality?: number // 0~1,JPEG/WebP 有效 (默认 0.85)
}使用 RenderTexture 精确裁剪到视口可见区域,输出分辨率 = 视口逻辑尺寸 × 设备像素比 (dpr)。无论世界坐标分布多广,导出的图片始终与屏幕所见一致。
配置方法
| 方法 | 说明 |
|------|------|
| setOptions(options) | 动态修改配置 (运行时生效,覆盖默认值) |
| updateLODConfig(config) | 更新 LOD 详细配置 |
| setDirectSelection(enabled) | 设置直接框选模式 (true=左键拖拽框选; false=Shift+左键) |
小地图
| 属性/方法 | 类型 | 说明 |
|-----------|------|------|
| minimapNodes | ShallowRef<MinimapNode[]> | 小地图节点数据 |
| getNodesForMinimap() | () => MinimapNode[] | 获取小地图简化节点列表 |
选区框状态
| 属性 | 类型 | 说明 |
|------|------|------|
| selBoxVisible | Ref<boolean> | 选区框是否显示 |
| selBoxBounds | Ref<SelectionBounds> | 选区边界 |
| selBoxCount | Ref<number> | 选中节点数 |
| updateSelectionBounds() | void | 手动触发选区框更新 |
TopologyOptions (配置选项)
通过组件 options prop 或 setOptions() 传入,支持运行时热更新。
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| width | number | — | 画布宽度 |
| height | number | — | 画布高度 |
| theme | 'light' \| 'dark' | 'light' | 主题 |
| enableHistory | boolean | true | 启用撤销/重做 |
| nodeShape | NodeShape | 'circle' | 默认节点形状 |
| nodeSize | number | 60 | 默认节点半径 |
| lineStyle | LineStyle | 'solid' | 默认连线样式 |
| lineCurve | LineCurve | 'straight' | 默认曲线类型 |
| lineWidth | number | 1 | 全局连线宽度倍率 |
| lineFontSize | number | 0 | 全局连线文字大小 (0=自动计算) |
| zoomStep | number | 0.05 | 缩放步长比例 |
| gridColor | string | — | 网格颜色 (CSS 色) |
| gridSubColor | string | — | 子网格颜色 |
| canvasBackground | string | — | 画布背景颜色 |
| focusZoom | number | — | 聚焦目标缩放比例 |
| lodTiers | LODTier[] | — | LOD 阶梯表 (覆盖默认 4 级) |
| lodConfig | Partial<LODConfig> | — | LOD 详细配置 |
| perfConfig | object | — | 性能参数 (见下方) |
| themes | Record<'light'\|'dark', Partial<ThemeConfig>> | — | 自定义主题覆盖 |
| hoverNodeHighlight | boolean | false | hover 高亮节点 |
| hoverNodeLineHighlight | boolean | false | hover 高亮关联边 |
| hoverLineHighlight | boolean | false | hover 高亮边 |
| clickNodeHighlight | boolean | false | click 高亮节点 |
| clickNodeLineHighlight | boolean | false | click 高亮关联边 |
| clickLineHighlight | boolean | false | click 高亮边 |
perfConfig 支持的字段:
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| nodeTextMinScale | number | 0.5 | 显示节点文字的最小缩放比例 |
| lineTextMinScale | number | 0.5 | 显示连线文字的最小缩放比例 |
| hoverColorMinScale | number | 0.5 | hover 变色的最小缩放比例 |
| ... | ... | ... | 更多字段见 DEFAULT_PERF_CONFIG |
lodTiers 示例:
{
lodTiers: [
{ minScale: 1.0, nodeMode: 'detail', lineMode: 'detail', nodeDowngradeThreshold: 200, lineDowngradeThreshold: 400 },
{ minScale: 0.5, nodeMode: 'normal', lineMode: 'normal', nodeDowngradeThreshold: 500, lineDowngradeThreshold: 1000 },
{ minScale: 0.2, nodeMode: 'simple', lineMode: 'simple', nodeDowngradeThreshold: 2000, lineDowngradeThreshold: 4000 },
{ minScale: 0.008, nodeMode: 'dot', lineMode: 'simple', nodeDowngradeThreshold: 30000, lineDowngradeThreshold: 30000 },
]
}数据类型
GraphNode
interface GraphNode {
id: string
text: string // 显示文本
x: number // 世界坐标 X
y: number // 世界坐标 Y
radius: number // 半径 (px, 世界坐标单位)
color: string // CSS 颜色字符串
shape?: NodeShape // 'circle' | 'rect' | 'diamond' | 'hexagon' | 'star'
icon?: string // 图标 URL
selected?: boolean // 是否选中
hovered?: boolean // 是否悬停
highlighted?: boolean // 是否高亮
borderColor?: string // 边框颜色
borderWidth?: number // 边框宽度
fontColor?: string // 文字颜色 (覆盖主题默认)
fontSize?: number // 文字大小 px (覆盖默认计算值)
opacity?: number // 透明度 0~1
fixed?: boolean // 固定位置 (力导向不受影响)
disabledDrag?: boolean // 禁止拖拽
flashing?: boolean // 正在闪烁
expanded?: boolean // 树形展开状态
data?: any // 用户自定义数据
}GraphLine
interface GraphLine {
id: string
source: string // 起始节点 ID
target: string // 目标节点 ID
text?: string // 连线标签文本
color: string // CSS 颜色
width: number // 线宽 (世界坐标单位)
directed: boolean // 是否有方向
style?: LineStyle // 'solid' | 'dashed' | 'dotted'
curve?: LineCurve // 'straight' | 'bezier' | 'arc' | 'step-hv' | 'step-vh'
animation?: LineAnimation // 0=无 | 1=流动 | 2=快速流动 | 3=脉冲 | 4=虚线流动
animationSpeed?: number // 动画速度倍率 (默认 1.0)
fontColor?: string // 文字颜色
fontSize?: number // 文字大小 px
opacity?: number
showStartArrow?: boolean // 起点箭头
showEndArrow?: boolean // 终点箭头
fromJunctionPoint?: JunctionPoint // 起始接入点
toJunctionPoint?: JunctionPoint // 终止接入点
data?: any
}JunctionPoint 可选值: 'border' | 'left' | 'right' | 'top' | 'bottom' | 'ltrb' | 'tb' | 'lr'
GraphJsonData (导入格式)
兼容 relation-graph 字段名,支持混合使用:
interface GraphJsonData {
rootId?: string
nodes: Array<{
id: string; text?: string; name?: string; x?; y?; radius?;
width?: number // 自动转换为 radius = width / 2
color?; shape?; icon?; fontColor?; borderColor?
borderWidth?; opacity?; fixed?; disabledDrag?; data?
}>
lines: Array<{
id?; from?; to?; source?; target? // 支持 from/to 和 source/target 两套字段名
text?; label?; color?; fontColor?; fontSize?; lineWidth?
style?; curve?; animation?; animationSpeed?
showEndArrow?; showStartArrow?; directed?; data?
}>
}自定义绘制
通过 setCustomDrawCallbacks 覆盖节点/边的默认渲染管线:
api.setCustomDrawCallbacks({
drawNode(ctx) {
// ctx.node - 当前节点数据 (GraphNode)
// ctx.graphics - PixiJS Graphics 对象
// ctx.screenX, ctx.screenY - 屏幕坐标 (已应用视口变换)
// ctx.screenRadius - 屏幕半径 (已应用缩放)
// ctx.viewportScale - 当前缩放比例
// ctx.nodeMode - LOD 模式 ('detail' | 'simple' | 'dot')
// ctx.draw - DrawHelpers 绘制工具集
// ctx.drawDefault() - 回退到默认渲染
const { node, screenX, screenY, screenRadius, draw } = ctx
// 示例:带图标的自定义节点
if (node.icon || node.data?.icon) {
draw.drawImage(node.icon || node.data?.icon,
screenX - screenRadius, screenY - screenRadius, screenRadius * 2)
} else {
draw.drawCircle(screenX, screenY, screenRadius, node.color)
}
draw.drawText(node.text, screenX, screenY + screenRadius + 8, { fontSize: 12 })
},
drawLine(ctx) {
// ctx.line - 当前边数据 (GraphLine)
// ctx.graphics - PixiJS Graphics 对象
// ctx.sourceScreenX/Y - 起点屏幕坐标
// ctx.targetScreenX/Y - 终点屏幕坐标
// ctx.lineWidth - 实际线宽 (考虑缩放)
// ctx.lineColor - 线颜色 (PixiJS 数字格式)
// ctx.viewportScale - 当前缩放
// ctx.nodeMode - LOD 模式
// ctx.draw - DrawHelpers
// ctx.drawDefault() - 回退默认渲染
}
})DrawHelpers (绘制工具集)
| 方法 | 签名 | 说明 |
|------|------|------|
| loadImage | (url: string) => Promise<boolean> | 加载并缓存图片,返回是否成功 |
| drawImage | (url, x, y, w?, h?) => boolean | 绘制已缓存图片,失败返回 false |
| drawCircle | (x, y, radius, fillStyle?) => void | 绘制填充圆 |
| drawRect | (x, y, w, h, fillStyle?) => void | 绘制填充矩形 |
| drawText | (text, x, y, options?) => void | 绘制文字 (fontSize/color/align) |
fillStyle支持 CSS 颜色 ('#ff0000') 或 PixiJS 数字颜色 (0xff0000)。
事件系统
核心类 TopologyGraphCore (继承 EventEmitter) 支持的事件:
| 事件 | 参数 | 说明 |
|------|------|------|
| node-click | (node, event) | 节点点击 |
| node-dblclick | (node, event) | 节点双击 |
| node-hover | (node \| null, event) | 节点悬停 (离开时 null) |
| node-delete | (node: GraphNode) | 节点删除 |
| node-drag-start | (node: GraphNode) | 节点拖拽开始 |
| node-drag-move | (node, dx, dy) | 拖拽中累计位移 |
| node-drag-end | (node, dx, dy) | 拖拽结束总位移 |
| line-click | (line, event) | 连线点击 |
| line-dblclick | (line, event) | 连线双击 |
| line-hover | (line \| null, event) | 连线悬停 |
| selection-change | (selectedIds: Set<string>) | 选择变化 |
| selectionbox-show | (bounds, nodeIds[]) | 选区框显示 |
| selectionbox-close | — | 选区框关闭 |
| canvas-click | (event, targetType, target?) | 画布点击 |
| canvas-contextmenu | (event, targetType, target?) | 右键菜单 |
| canvas-drag-start | — | 画布拖拽开始 |
| canvas-drag-move | (dx, dy) | 画布拖拽中 |
| canvas-drag-end | (dx, dy) | 画布拖拽结束 |
| canvas-zoom | (scale: number) | 缩放结束 |
| viewport-change | (viewport: Viewport) | 视口变化 |
| data-change | ({ nodes, lines }) | 数据变化 |
| perf-stats | (stats: PerfStats) | 性能统计更新 |
| history-change | ({ canUndo, canRedo }) | 历史状态变化 |
| layout-start | — | 布局开始 |
| layout-end | — | 布局结束 |
| options-change | (options: TopologyOptions) | 配置变更 |
监听方式:
// Vue 组件: @事件名
<TopologyGraph @node-click="(node) => console.log(node.text)" />
// Core API: .on()
graph.on('node-click', (node) => console.log(node.text))
graph.on('node-hover', (node) => {
if (!node) console.log('离开节点')
})Window 级别拖拽:
node-drag-*和canvas-drag-*事件注册在window上,即使鼠标离开画布也能持续接收事件,确保拖拽不卡顿。
底层 API (非 Vue 场景)
import { TopologyGraphCore } from 'topology-graph-vue'
// 不依赖 Vue 的纯 JS 用法
const canvas = document.getElementById('canvas') as HTMLCanvasElement
const graph = await TopologyGraphCore.create(canvas, {
width: 800,
height: 600,
theme: 'light',
})
graph.setJsonData({ nodes: [...], lines: [...] })
graph.applyLayout({ type: 'force' })
graph.fitView()
graph.on('node-click', (node) => console.log('clicked:', node.id))Composable (底层桥接)
import { useTopologyGraph } from 'topology-graph-vue'直接操作 DOM 引用的低级 composable。一般不需要手动使用,TopologyGraph 组件内部已经集成。
构建产物
dist/
├── index.js # ESM bundle
├── index.umd.cjs # UMD bundle (CommonJS 兼容)
├── topology-graph-vue.css # 样式文件
└── types/ # TypeScript 声明文件
├── *.d.ts # 所有类型声明
└── components/*.d.ts # 组件声明构建特性:
- ESM + UMD 双格式输出
vite-plugin-dts自动生成类型声明vite-plugin-obfuscator代码混淆 (生产环境)- 版本号占位符
__VERSION__替换 - 外部依赖:
vue,pixi.js(不打包进 bundle)
独立 HTML 打包 (Demo/预览):
dist-standalone/index.html # 单文件 HTML (内联所有 JS/CSS/SVG)npm run build:standalone # 构建
npm run preview:standalone # 预览开发
# 安装依赖 (Node >= 18, 推荐 Volta 固定 20.20.0)
npm install
# 开发服务器 (端口 5173)
npm run dev
# 库模式构建 (ESM + UMD)
npm run build
# 独立 HTML 构建
npm run build:standalone
# 类型检查
npm run typecheck
# 代码质量
npm run lint # ESLint 检查 + 自动修复
npm run format # Prettier 格式化
# 发布 (standard-version 生成 CHANGELOG)
npm run release项目脚本
| 脚本 | 作用 |
|------|------|
| scripts/clean-js.cjs | 清理 dist 中 vue-tsc 生成的冗余 .js/.map 文件 |
| scripts/flatten-dts.cjs | 将嵌套 d.ts 扁平化到 dist/ 根目录 |
| scripts/gen-icon.cjs | 代码生成 user.png 图标 (64x64 人形轮廓) |
性能调优指南
LOD 阶梯表调优
LOD (Level of Detail) 根据缩放比例自动切换渲染精度:
| minScale | 节点模式 | 边模式 | 效果 | |----------|---------|--------|------| | >= 1.0 | detail (详情) | detail (详情) | 显示图标/文字/边框/箭头 | | >= 0.5 | normal (普通) | normal (普通) | 仅文字,无边框细节 | | >= 0.2 | simple (简化) | simple (简化) | 无文字,纯色填充 | | < 0.008 | dot (点状) | simple | 极小圆点,大量节点场景 |
关键阈值:
nodeDowngradeThreshold: 该模式下最大渲染节点数,超出则降级lineDowngradeThreshold: 该模式下最大渲染连线数
力导向参数建议
| 参数 | 默认值 | 节点少 (<500) | 节点多 (>5000) | |------|--------|---------------|----------------| | repulsion | 2000 | 1000~2000 | 5000~10000 | | springLength | 60 | 40~80 | 80~150 | | springK | 0.1 | 0.05~0.1 | 0.02~0.08 | | damping | 0.3 | 0.2~0.3 | 0.4~0.6 | | iterations | 300 | 100~200 | 300~500 |
Changelog
详见 CHANGELOG.md。
