irr-gh
irr-gh - 灌溉系统概化图组件
基于 Vue 3 + AntV G6 v5 的灌溉系统概化图可视化组件库。
目录
安装
npm install irr-gh
# 或
pnpm add irr-gh
# 或
bun add irr-gh
快速开始
组件导入方式
<script setup lang="ts">
import { ref } from 'vue'
import { IrrigationGraph } from 'irr-gh'
import 'irr-gh/style.css'
import type { IrrigationData } from 'irr-gh'
const graphRef = ref()
// 示例数据
const data: IrrigationData = {
lines: [
{ id: 'main', name: '主干渠', type: 'canal', level: 1 },
{ id: 'branch-1', name: '支渠1', type: 'canal', parentId: 'main', bankSide: 'left' }
],
points: [
{ id: 'sluice-1', name: '闸门1', type: 'sluice', canalId: 'main', chainage: 0 },
{ id: 'sluice-2', name: '闸门2', type: 'sluice', canalId: 'main', chainage: 100 }
]
}
function handleReady(graph: unknown) {
console.log('图渲染完成', graph)
}
</script>
<template>
<IrrigationGraph
ref="graphRef"
:data="data"
:enable-minimap="true"
:fit-view="true"
:show-toolbar="true"
@ready="handleReady"
/>
</template>
全局注册方式
您也可以在 main.js/main.ts 中全局注册组件:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import IrrGh from 'irr-gh'
import 'irr-gh/style.css'
const app = createApp(App)
// 全局注册组件
app.use(IrrGh)
app.mount('#app')
之后就可以在任何组件中直接使用 <IrrigationGraph> 组件,无需单独导入:
<script setup lang="ts">
import { ref } from 'vue'
import type { IrrigationData } from 'irr-gh'
const graphRef = ref()
// 示例数据
const data: IrrigationData = {
lines: [
{ id: 'main', name: '主干渠', type: 'canal', level: 1 },
{ id: 'branch-1', name: '支渠1', type: 'canal', parentId: 'main', bankSide: 'left' }
],
points: [
{ id: 'sluice-1', name: '闸门1', type: 'sluice', canalId: 'main', chainage: 0 },
{ id: 'sluice-2', name: '闸门2', type: 'sluice', canalId: 'main', chainage: 100 }
]
}
function handleReady(graph: unknown) {
console.log('图渲染完成', graph)
}
</script>
<template>
<IrrigationGraph
ref="graphRef"
:data="data"
:enable-minimap="true"
:fit-view="true"
:show-toolbar="true"
@ready="handleReady"
/>
</template>
布局系统
布局方向
组件支持两种布局方向:
| 布局类型 | 值 | 说明 |
|---|---|---|
| 横向布局 | 'horizontal' |
主干渠从左到右水平排列,支渠向上/下垂直分叉 |
| 纵向布局 | 'vertical' |
主干渠从上到下垂直排列,支渠向左/右水平分叉 |
布局规则
1. 主干渠方向决定布局
- 横向布局:主干渠从左到右水平绘制
- 纵向布局:主干渠从上到下垂直绘制
2. 连接与分叉原则
- 上下游延续 (
bankSide: 'center'):子渠道继续沿父级渠道方向在同一轴线上延续连接。 - 支渠分叉 (
bankSide: 'left' | 'right'):支渠与父级渠道垂直相交。
横向布局时:
center→ 继续水平延续left(左岸) → 向上垂直分叉right(右岸) → 向下垂直分叉
纵向布局时:
center→ 继续垂直延续left(左岸) → 向左水平分叉right(右岸) → 向右水平分叉
3. 主干渠居中
主干渠自动居中到画布中心位置。
布局间距配置
interface LayoutSpacing {
/** 主渠方向节点间距 */
main: number // 默认: 150
/** 支渠方向节点间距 */
branch: number // 默认: 120
/** 分支偏移距离 */
branchOffset: number // 默认: 80
}
组件配置
Props 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
config |
IrrigationGraphConfig |
- | (推荐)结构化配置对象,收敛全部能力;与扁平 props 共存时 config 覆盖 |
width |
number |
- | 画布宽度(不设置则自适应容器) |
height |
number |
- | 画布高度(不设置则自适应容器) |
data |
IrrigationData |
- | 业务数据(原始格式) |
graphData |
IrrigationGraphData |
- | G6图数据(已转换格式) |
layout |
LayoutConfig |
- | 布局配置 |
theme |
ThemeConfig |
- | 主题配置 |
tooltip |
TooltipConfig |
- | Tooltip配置 |
dataPanel |
DataPanelConfig |
- | 常显数据面板配置 |
enableDrag |
boolean |
true |
是否启用拖拽 |
enableZoom |
boolean |
true |
是否启用缩放 |
enableBrush |
boolean |
false |
是否启用框选 |
enableMinimap |
boolean |
false |
是否启用小地图 |
fitView |
boolean |
true |
是否适应画布 |
fitViewPadding |
number | number[] |
- | 适应画布的内边距 |
readonly |
boolean |
false |
是否只读模式 |
showToolbar |
boolean |
false |
是否显示内置工具栏 |
enabledToolbarActions |
ToolbarActions |
全部启用 | 启用的工具栏功能 |
evolution |
EvolutionConfig |
- | 演进功能配置 |
evolutionData |
EvolutionData |
- | 演进数据 |
推荐:扁平 props 保留用于向后兼容,新用法请直接使用
config对象, 把散落的配置按域收敛(size / data / layout / theme / interaction / toolbar / tooltip / dataPanel / evolution)。
结构化 config(推荐写法)
<script setup>
import { ref } from 'vue'
const config = ref({
data: { business: myBusiData }, // 业务格式;或 { graph: myGraphData } 传 G6 格式
theme: { backgroundColor: '#fff' },
interaction: { // 交互相关开关
enableDrag: true,
enableZoom: true,
enableBrush: false,
enableMinimap: false,
fitView: true,
readonly: false,
},
toolbar: {
showToolbar: true,
actions: {
zoomIn: true,
zoomOut: true,
fitView: true,
export: true,
config: true,
align: true, // 对齐 / 分布(含均匀分布),默认 true
},
},
dataPanel: { enabled: false },
evolution: {
config: { enabled: false, interval: 2000, loop: true, autoPlay: false },
data: undefined,
},
})
</script>
<template>
<IrrigationGraph :config="config" @ready="onReady" />
</template>
IrrigationGraphConfig 顶层分类:
| 配置路径 | 说明 | 对应旧扁平 props |
|---|---|---|
size.width / size.height |
画布尺寸 | width / height |
data.business / data.graph |
图数据(二选一,graph 优先) | data / graphData |
layout |
布局配置 | layout |
theme |
主题配置 | theme |
tooltip |
Tooltip 配置 | tooltip |
dataPanel |
常显数据面板 | dataPanel |
interaction.enableDrag · enableZoom · enableBrush · enableMinimap · fixElementSize · fitView · autoResize · fitViewPadding · readonly |
交互开关 | 同名扁平 props |
toolbar.showToolbar · toolbar.actions |
工具栏显隐与动作 | showToolbar / enabledToolbarActions |
evolution.config / evolution.data |
演进配置与数据 | evolution / evolutionData |
ToolbarActions 配置
interface ToolbarActions {
zoomIn?: boolean // 放大按钮
zoomOut?: boolean // 缩小按钮
fitView?: boolean // 适应视图按钮
save?: boolean // 保存按钮
export?: boolean // 导出按钮
print?: boolean // 打印按钮
layout?: boolean // 布局切换按钮
config?: boolean // 配置面板按钮
align?: boolean // 对齐/分布功能(含各种对齐与均匀分布),默认 true
getData?: ((data: IrrigationGraphData) => void) | boolean // 获取数据回调
}
DataPanelConfig 配置
常显数据面板配置,仅在点位节点上显示,当启用时会自动禁用 Tooltip。
interface DataPanelConfig {
enabled?: boolean // 是否启用,默认 false
formatter?: (data: IrrigationNodeData) => string // 自定义内容格式化(返回 HTML 字符串)
offsetX?: number // 水平偏移,默认 10
offsetY?: number // 垂直偏移,默认 -10
}
使用示例:
<script setup>
import { ref } from 'vue'
const dataPanelConfig = ref({
enabled: true,
formatter: (nodeData) => {
const label = nodeData.data?.label || nodeData.id
const kind = nodeData.businessData?.kind || '未知类型'
return `
<div style="font-weight: bold; color: #1890ff;">${label}</div>
<div style="color: #666; font-size: 11px;">类型: ${kind}</div>
<div style="color: #999; font-size: 10px;">状态: 正常</div>
`
},
offsetX: 0,
offsetY: -15
})
</script>
<template>
<IrrigationGraph :data="data" :data-panel="dataPanelConfig" />
</template>
Events 事件
| 事件名 | 参数 | 说明 |
|---|---|---|
ready |
(graph: Graph) |
图渲染完成 |
itemClick |
({ type: string, item: unknown }) |
节点/边点击 |
itemDblClick |
({ type: string, item: unknown }) |
节点/边双击 |
itemContextMenu |
({ type: string, item: unknown, event: MouseEvent }) |
节点/边右键菜单 |
selectionChange |
({ nodes: string[], edges: string[] }) |
选中状态变化 |
canvasClick |
(event: MouseEvent) |
画布点击 |
evolutionChange |
(params: EvolutionEventParams) |
演进状态/时间点变化 |
dataChange |
(data: IrrigationGraphData) |
数据变化 |
Slots 插槽
| 插槽名 | 参数 | 说明 |
|---|---|---|
toolbar |
{ zoomIn, zoomOut, fitView } |
自定义工具栏 |
loading |
- | 自定义加载状态 |
default |
- | 默认插槽,用于额外内容 |
API 方法
通过 ref 获取组件实例调用方法:
<script setup>
const graphRef = ref()
// 调用方法
graphRef.value?.zoomIn()
</script>
<template>
<IrrigationGraph ref="graphRef" />
</template>
数据操作
| 方法 | 签名 | 说明 |
|---|---|---|
render |
(data: IrrigationGraphData) => Promise<void> |
渲染G6格式数据 |
renderFromData |
(data: IrrigationData, direction?: LayoutDirection) => Promise<void> |
从业务数据渲染 |
updateData |
(data: Partial<IrrigationGraphData>) => Promise<void> |
更新数据 |
addNode |
(node: IrrigationNodeData) => Promise<void> |
添加节点 |
addEdge |
(edge: IrrigationEdgeData) => Promise<void> |
添加边 |
removeNode |
(nodeId: string) => Promise<void> |
删除节点 |
removeEdge |
(edgeId: string) => Promise<void> |
删除边 |
updateNode |
(nodeId: string, data: Partial<IrrigationNodeData>) => Promise<void> |
更新节点 |
updateEdge |
(edgeId: string, data: Partial<IrrigationEdgeData>) => Promise<void> |
更新边 |
setEvolutionData |
(data: EvolutionData) => void |
设置/更新演进数据 |
getEvolutionManager |
() => EvolutionManager |
获取演进管理器实例 |
getData |
() => IrrigationGraphData |
获取当前图数据 |
视图控制
| 方法 | 签名 | 说明 |
|---|---|---|
zoomIn |
() => void |
放大视图 |
zoomOut |
() => void |
缩小视图 |
zoomTo |
(ratio: number) => void |
缩放到指定比例 |
fitView |
() => void |
适应视图 |
focusNode |
(nodeId: string) => void |
聚焦到指定节点 |
布局操作
| 方法 | 签名 | 说明 |
|---|---|---|
changeLayout |
(type: 'horizontal' | 'vertical') => Promise<void> |
切换布局方向 |
changeLayoutDirection |
(data: IrrigationData, direction: LayoutDirection) => Promise<void> |
使用新布局方向重新渲染 |
setLayout |
(layout: LayoutConfig) => Promise<void> |
设置G6布局配置 |
导出与保存
| 方法 | 签名 | 说明 |
|---|---|---|
save |
() => string |
保存为JSON字符串 |
load |
(json: string) => Promise<void> |
从JSON加载 |
toImage |
(config?: ExportConfig) => Promise<string> |
导出为图片(Base64) |
downloadImage |
(config?: ExportConfig) => Promise<void> |
下载图片 |
print |
() => void |
打印 |
ExportConfig 配置
interface ExportConfig {
fileName?: string // 文件名,默认: 'irrigation-graph'
format?: 'png' | 'jpg' | 'svg' | 'pdf' // 导出格式
backgroundColor?: string // 背景色
scale?: number // 缩放比例
}
事件监听
| 方法 | 签名 | 说明 |
|---|---|---|
on |
(type: InteractionEventType, handler: Function) => void |
监听事件 |
off |
(type: InteractionEventType, handler?: Function) => void |
移除事件监听 |
可监听的事件类型
type InteractionEventType =
| 'node:click' | 'node:dblclick' | 'node:contextmenu'
| 'node:mouseenter' | 'node:mouseleave'
| 'node:dragstart' | 'node:drag' | 'node:dragend'
| 'edge:click' | 'edge:dblclick' | 'edge:contextmenu'
| 'edge:mouseenter' | 'edge:mouseleave'
| 'canvas:click' | 'canvas:dragstart' | 'canvas:drag' | 'canvas:dragend'
| 'combo:click' | 'combo:dblclick'
数据结构
自 1.0 起,业务侧 I/O 采用标准化灌溉契约(
domain/irrigation/schema的IrrigationInput), 通过normalize(脏值清洗)→adapter(IrrigationInput → TopoData)接入通用拓扑内核。 旧的connections/nodeConfig/edgeConfig/SluiceEntity/entityType接口已废弃。
标准化灌溉输入 (IrrigationInput)
interface IrrigationInput {
elements: IrrigationElement[] // 全部实体/辅助点(点/线/面统一,几何由 kind 推导)
buffers: IrrigationCombo[] // 空间容器(调度单元缓冲面)
groups: IrrigationGroup[] // 高亮围框(纯展示)
}
统一实体 (IrrigationElement)
实体类型 kind(线 / 点 / 面)、几何形态 geometry、空间容器(buffers/groups)
是三个正交维度:geometry 由 kind 推导默认值,可覆盖(同一种实体在不同比例尺
下可以是点图标或面)。
// 事实实体类型(去重收口)
type EntityKind =
| 'river' | 'canal' | 'ditch' // 线:河道 / 渠道 / 沟道
| 'sluice' | 'pumpStation' | 'weir' // 点:闸门 / 泵站 / 堰坝
| 'reservoir' | 'pond' // 面:水库 / 水池(蓄水)
| 'catchment' | 'contourBand' | 'fieldUnit' | 'subsurfaceUnit' // 面:集水区/等高带/田块单元/地下单元
type GeoType = 'point' | 'line' | 'area' // 几何形态
type AuxKind = 'start' | 'end' | 'fork' | 'afflux' | 'stream' // 辅助拓扑节点
interface IrrigationElement {
id: string
name: string
discriminator: 'entity' | 'aux' // 事实实体 / 辅助拓扑节点
kind: EntityKind | AuxKind // 实体类型(收口枚举)
geometry: GeoType // 点/线/面(默认由 kind 推导)
onHost?: { entityId: string; chainage?: number; bankSide?: BankSide; offset?: { x: number; y: number } } // 宿主定位(线实体用 chainage/bankSide;面实体用 offset 相对偏移)
standalone?: boolean // 独立设施(水池/水库等不依附渠道)
// 线实体(kind: river/canal/ditch)特有渠系字段
base?: boolean
parentId?: string
forkChainage?: number
startChainage?: number
endChainage?: number
level?: number
targetId?: string
targetChainage?: number
targetBankSide?: 'left' | 'right' | 'center'
targetFacilityId?: string
facilityEnd?: 'start' | 'end'
drawType?: 'virtual' | 'actual'
ctrlTargetId?: string
style?: Record<string, unknown> // 样式(shape/img/label*,与 g6 对齐)
[key: string]: https://github.com/your-username/irr-gh/blob/HEAD/unknown // 其余扩展
}
样式示例(用 style 替代旧 nodeConfig;shape 支持 rect/circle/image/diamond):
const pointWithImage: IrrigationElement = {
id: 'slu-1', name: '进水闸1', discriminator: 'entity', kind: 'sluice', geometry: 'point',
onHost: { entityId: 'canal-A', chainage: 0 }, standalone: false,
style: { shape: 'image', img: '/head.png', width: 48, height: 48 }
}
const pumpRect: IrrigationElement = {
id: 'pump-1', name: '提水泵站1', discriminator: 'entity', kind: 'pumpStation', geometry: 'point',
onHost: { entityId: 'canal-B', chainage: 100 }, standalone: false,
style: { shape: 'rect', width: 60, height: 40, fill: '#ffccc7', stroke: '#ff4d4f', radius: 8 }
}
规范化与适配(canonical 为源头,引擎直接消费)
// 1. 规范输入(canonical = IrrigationInput)直接交给组件 / hook / adapter:
// IrrigationGraph 的 data / useIrrigationGraph 的 data / toTopoDataFromIrrigation
// 均可传 canonical IrrigationInput 或 legacy IrrigationData(自适应)。
// 2. 引擎(routine transformDataWithLayout)直接读取 canonical 字段
// (kind / onHost / standalone / geometry);legacy 由入口 normalizeIrrigation 归并。
const canon = normalizeIrrigation(rawIrrigationData) // dirty → canonical
const topo = toTopoDataWithLayout(canon, "horizontal") // canonical → TopoData
canalId === "undefined"(历史脏值)会被清洗为standalone: true,定位统一收进onHost: { entityId, … };- 源头契约优先用 canonical
IrrigationInput(elements/buffers/groups);legacy 数据仍被容忍,入口自动归一。 - 引擎与 g6 运行时统一经
@/core/topo/canonical访问器读取 canonical 字段(kind/onHost/standalone/geometry), 不携带任何 legacy 影子。
点位宿主泛化(点可挂线,也可挂水库 / 水池)
onHost.entityId 指向任意实体,不限于河渠沟:
- 线宿主(river/canal/ditch):用
chainage+bankSide在渠系上定位,参与渠道线性布局; - 面宿主 / 非线宿主(reservoir/pond 等,或独立设施点):由
Positioner.placeAreaHostedPoints单独定位,不参与渠道线性布局。坐标优先级offset>anchor> 辐射默认 (绕宿主中心均分角度、半径spacing.branch;同宿主多点位自动均匀辐射, 并避让已挂线子点位所占方位——如溢流堰在水库东侧时,自由点不会落在该扇区而与之重叠)。
宿主非线实体的点位与其宿主之间会生成一条灰色虚线归属边
(connectionType: 'host',stroke: #8c8c8c、lineDash: [4, 4]、无箭头,不带标签故不参与标签收敛)。
定位优先级:onHost.offset > anchor(绝对坐标)> 辐射默认(绕宿主中心均分角、半径一个主间距,自动避让已挂线子点位方位)。示例:
const gateOnReservoir: IrrigationElement = {
id: 'slu-2', name: '水库进水闸', discriminator: 'entity',
kind: 'sluice', geometry: 'point',
onHost: { entityId: 'reservoir-1', offset: { x: -90, y: 0 } },
style: { shape: 'image', img: '/head.png', width: 48, height: 48 }
}
分类依据是「宿主不是线实体」,而非几何形态,因此独立设施点被宿主挂靠的情况同样覆盖(合理推广)。 已知限制:链式托管(宿主本身也是被托管点位)受收集顺序影响,可能触发告警并降级为兜底定位。
宿主自动对齐(Positioner.alignHostFacilities):若某宿主任一子点位由渠道线性布局
定位(如溢流堰 = 渠首),引擎会把该宿主对齐到这些子点位的轴线(水平布局同 y、置于其上游侧,
垂直布局同 x、置于其上方)。这解决了「绝对 anchor 无法跟随运行时画布中心,导致宿主与子点位
中心不平行」的问题。仅作用于由兜底定位的宿主(未被任何线 targetFacilityId 挂接),
因此不影响被线挂接的既有设施。
双角色实体:面宿主点位同时可以作为某条线的端点设施。当线声明 targetFacilityId
指向它(facilityEnd: 'start' 作为渠首、缺省作为渠尾)时,该点位:
- 由渠道线性布局定位(成为该线节点序列的首/末节点),并生成
线 ↔ 点位的flow边; - 仍保留与宿主之间的灰色虚线归属边(
connectionType: 'host'); - 不再进入
placeAreaHostedPoints,避免二次定位覆盖渠道布局算出的坐标。
典型场景:水库 —(灰虚线)— 溢流堰 —(flow)— 总干渠(溢流堰既属于水库,又是总干渠的源头)。
实现口径:IndexBuilder.attachFacilityPoints 的候选集 = 独立设施点 ∪ 面宿主点位;
但兜底名单 unattachedFacilities 仍只收独立设施点,未挂线的面宿主点位仍由
placeAreaHostedPoints 定位。
通用拓扑数据 (TopoData)
interface TopoData {
nodes: TopoNode[] // kind: entity/aux/buffer; shape/风格经归一
edges: TopoEdge[] // source/target + connectionType
combos?: TopoCombo[] // memberIds
groups?: TopoGroup[] // 高亮围框
}
内核只消费 TopoData,对业务不可知;替换行业只需新增 adapter + applier + presets,内核零改动。
边样式自定义
边由转换器根据渠道/点位关系自动生成,可用以下层级覆盖样式(优先级从高到低):
- 演进级:
EvolutionManager/TimelineApplier按报警级别、流向叠加报警色/渐变(见「数据演进」)。 - 渠道级 (Canal):在
IrrigationElement.style配置该渠(kind ∈ river/canal/ditch)下所有自动生成边的默认样式。 - 全局级 (Theme):通过
theme配置默认样式。
可配置样式属性(与 G6 对齐)
interface EdgeStyle {
stroke?: string // 线条颜色,如 '#ff4d4f'
lineWidth?: number // 线条宽度
lineDash?: number[] // 虚线配置,如 [5, 5]
opacity?: number // 透明度
endArrow?: boolean // 是否显示结束箭头
labelText?: string // 自定义标签内容
labelFontSize?: number // 标签字号
labelFill?: string // 标签颜色
router?: object // 正交路由配置(分叉连接线)
}
使用示例
// 在渠道上配置默认红色加粗样式
const canal: IrrigationElement = {
id: 'main-canal',
name: '输沙渠',
kind: 'canal',
geometry: 'line',
style: { stroke: '#ff4d4f', lineWidth: 6 },
}
工具栏
内置工具栏
通过 showToolbar 属性启用内置工具栏:
<IrrigationGraph
:show-toolbar="true"
:enabled-toolbar-actions="{
zoomIn: true,
zoomOut: true,
fitView: true,
save: true,
export: true,
print: true,
layout: true
}"
/>
自定义工具栏
使用 toolbar 插槽自定义工具栏:
<IrrigationGraph ref="graphRef">
<template #toolbar="{ zoomIn, zoomOut, fitView }">
<div class="my-toolbar">
<button @click="zoomIn">放大</button>
<button @click="zoomOut">缩小</button>
<button @click="fitView">适应</button>
<button @click="graphRef?.changeLayout('horizontal')">横向</button>
<button @click="graphRef?.changeLayout('vertical')">纵向</button>
</div>
</template>
</IrrigationGraph>
主题配置
默认样式常量
// 渠道/边的默认宽度
export const CANAL_WIDTH = 10
// 渠道默认颜色
export const CANAL_COLOR = '#1890ff'
辅助节点样式
辅助节点(分叉点、结束点、汇合点)样式与渠道保持一致:
- 形状:正方形(rect)
- 尺寸:10 × 10 像素(与渠道宽度一致)
- 颜色:与渠道颜色一致(#1890ff)
- 无边框、无圆角
节点形状类型
支持以下节点形状:
| 形状 | 值 | 说明 |
|---|---|---|
| 矩形 | 'rect' |
默认形状,可设置圆角 radius |
| 圆形 | 'circle' |
圆形节点 |
| 菱形 | 'diamond' |
菱形节点 |
| 椭圆 | 'ellipse' |
椭圆节点 |
| 图片 | 'image' |
使用图片作为节点,需配置 img 属性 |
| 自定义 | 'custom' |
自定义节点形状 |
默认节点样式映射
| 实体类型 | 默认形状 | 填充色 | 边框色 |
|---|---|---|---|
| sluice (闸门) | rect | #fffbe6 | #faad14 |
| pumpStation (泵站) | rect | #f6ffed | #52c41a |
| reservoir (水库) | circle | #e6fffb | #13c2c2 |
| dispatchUnit (调度单元) | diamond | #f9f0ff | #722ed1 |
| dispatchNode (调度节点) | circle | #fff0f6 | #eb2f96 |
| auxiliary (辅助节点) | rect | #1890ff | #1890ff |
图片类型节点
点位节点支持使用图片,通过 IrrigationElement.style 配置 shape: 'image' 与 img:
const gateWithImage: IrrigationElement = {
id: 'gate-1',
name: '进水闸',
discriminator: 'entity',
kind: 'sluice',
geometry: 'point',
onHost: { entityId: 'canal-1', chainage: 0 },
standalone: false,
style: { shape: 'image', img: '/head.png', width: 48, height: 48 },
}
const pumpWithImage: IrrigationElement = {
id: 'pump-1',
name: '泵站',
discriminator: 'entity',
kind: 'pumpStation',
geometry: 'point',
onHost: { entityId: 'canal-1', chainage: 100 },
standalone: false,
style: { shape: 'image', img: '/pump-station.png', width: 48, height: 48 },
}
// 普通矩形节点
const gateWithRect: IrrigationElement = {
id: 'gate-2',
name: '普通闸门',
discriminator: 'entity',
kind: 'sluice',
geometry: 'point',
onHost: { entityId: 'canal-1', chainage: 200 },
standalone: false,
style: {
shape: 'rect',
width: 48,
height: 36,
fill: '#fffbe6',
stroke: '#faad14',
},
}
// 转换后的 G6 节点:nodeShape 由 style.shape 得到,img 由 style.img 得到
const nodeData: IrrigationNodeData = {
id: 'gate-1',
nodeShape: 'image',
style: { img: '/head.png', width: 48, height: 48, stroke: '#faad14' },
data: { label: '进水闸' },
businessData: gateWithImage, // 保留原始业务数据
}
边/渠道样式
默认渠道样式:
- 宽度:10 像素
- 颜色:#1890ff
- 无箭头:默认不显示箭头
连接类型样式:
| 连接类型 | 颜色 | 宽度 | 样式 |
|---|---|---|---|
| flow (水流) | #1890ff | 10px | 实线 |
| control (控制) | #faad14 | 3px | 虚线 [8, 4] |
| supply (供水) | #52c41a | 3px | 虚线 [6, 4] |
主题配置接口
interface ThemeConfig {
name?: 'light' | 'dark' | 'custom'
nodeStyle?: Partial<Record<EntityType, NodeStyleConfig>>
edgeStyle?: EdgeStyleConfig
backgroundColor?: string
}
interface NodeStyleConfig {
fill?: string // 填充色
stroke?: string // 边框色
lineWidth?: number // 边框宽度
opacity?: number // 透明度
radius?: number // 圆角半径
width?: number // 宽度
height?: number // 高度
shadowColor?: string // 阴影颜色
shadowBlur?: number // 阴影模糊度
}
interface EdgeStyleConfig {
stroke?: string // 线条颜色
lineWidth?: number // 线条宽度
lineDash?: number[] // 虚线配置
opacity?: number // 透明度
endArrow?: boolean // 结束箭头
startArrow?: boolean // 起始箭头
}
使用示例
<IrrigationGraph
:theme="{
name: 'custom',
backgroundColor: '#f5f5f5',
nodeStyle: {
sluice: { fill: '#1890ff', stroke: '#0050b3' },
pumpStation: { fill: '#52c41a', stroke: '#237804' },
reservoir: { fill: '#722ed1', stroke: '#391085' }
},
edgeStyle: {
stroke: '#333',
lineWidth: 2
}
}"
/>
Hook 使用
可以直接使用 useIrrigationGraph Hook 获得更灵活的控制:
<script setup lang="ts">
import { ref } from 'vue'
import { useIrrigationGraph } from 'irr-gh'
const containerRef = ref<HTMLElement | null>(null)
const {
graph,
manager,
state,
initialized,
loading,
init,
render,
renderFromData,
changeLayoutDirection,
zoomIn,
zoomOut,
fitView,
getData,
save,
load,
toImage,
downloadImage,
print,
on,
off,
destroy
} = useIrrigationGraph({
container: containerRef,
width: 1200,
height: 800,
data: myData,
layoutDirection: 'horizontal',
autoInit: true,
options: {
enableDrag: true,
enableZoom: true,
enableMinimap: true
}
})
</script>
<template>
<div ref="containerRef" style="width: 100%; height: 600px;"></div>
</template>
Hook 配置选项
interface UseIrrigationGraphOptions {
container: Ref<HTMLElement | null> // 容器元素引用
width?: number // 画布宽度
height?: number // 画布高度
data?: IrrigationData // 初始业务数据
graphData?: IrrigationGraphData // 初始G6数据
options?: Partial<GraphOptions> // 图配置选项
autoInit?: boolean // 是否自动初始化(默认true)
layoutDirection?: LayoutDirection // 初始布局方向(默认horizontal)
}
布局辅助工具
组件暴露了 layoutUtils 对象,提供布局辅助函数:
// 通过组件实例访问
graphRef.value?.layoutUtils
// 可用方法
layoutUtils.getNodePosition(node) // 获取节点位置
layoutUtils.setNodePosition(node, x, y) // 设置节点位置
layoutUtils.alignNodesHorizontally(nodes, alignType) // 水平对齐
layoutUtils.alignNodesVertically(nodes, alignType) // 垂直对齐
layoutUtils.distributeNodesHorizontally(nodes, spacing) // 水平等距分布
layoutUtils.distributeNodesVertically(nodes, spacing) // 垂直等距分布
layoutUtils.moveNodes(nodes, deltaX, deltaY) // 批量移动节点
layoutUtils.getNodesBoundingBox(nodes) // 获取节点边界框
layoutUtils.centerNodesToPosition(nodes, x, y) // 居中节点到位置
layoutUtils.centerNodesToCanvas(nodes, width, height) // 居中节点到画布
layoutUtils.flipNodes(nodes, axis) // 翻转节点
layoutUtils.rotateNodes90(nodes, clockwise) // 旋转90度
layoutUtils.getNodesByCanalId(data, canalId) // 按渠道ID获取节点
layoutUtils.getConnectedNodes(data, nodeId) // 获取相邻节点
layoutUtils.autoAdjustSpacing(nodes, direction, spacing) // 自动调整间距
数据演进
组件内置了数据演进功能,支持展示随时间变化的节点状态(如水位报警)和边状态(如流向、流量渐变)。
核心特性
- 时序播放:支持自动/手动播放时间序列数据。
- 报警级别映射:根据
alarmLevel自动更新节点填充色、边框色和呼吸灯效果(阴影)。 - 边渐变色流向:支持根据流向(正向/反向)自动计算边渐变方向,并根据状态实时更新。
- 自定义数据面板:演进过程中的业务数据可在常显面板中实时展示。
演进配置 (EvolutionConfig)
interface EvolutionConfig {
enabled?: boolean // 是否启用
interval?: number // 播放速度(毫秒/帧),默认 2000
loop?: boolean // 是否循环播放
autoPlay?: boolean // 是否自动播放
alarmStyles?: Partial<AlarmStyleMap> // 覆盖默认报警样式
defaultGradient?: EdgeGradientConfig // 边默认渐变配置
}
数据结构
interface EvolutionData {
timePoints: EvolutionTimePoint[]
}
interface EvolutionTimePoint {
timestamp: number | string // 时间戳或 ISO 字符串
label?: string // 时间显示标签,如 "08:00"
nodeStates?: Record<string, NodeEvolutionState> // 节点状态映射
edgeStates?: Record<string, EdgeEvolutionState> // 边状态映射
}
interface NodeEvolutionState {
alarmLevel?: 'normal' | 'warning' | 'error' | 'critical'
data?: Record<string, unknown> // 实时业务数据
style?: NodeEvolutionStyle // 自定义样式覆盖
}
interface EdgeEvolutionState {
flowDirection?: 'forward' | 'backward' // 流向
gradient?: { startColor: string; endColor: string } // 渐变配置
}
使用示例
<script setup>
import { ref } from 'vue'
import { createEvolutionMockData } from './mock'
const evolutionConfig = {
enabled: true,
interval: 1500,
loop: true
}
const evolutionData = createEvolutionMockData()
</script>
<template>
<IrrigationGraph
:data="baseData"
:evolution="evolutionConfig"
:evolution-data="evolutionData"
/>
</template>
完整示例
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { IrrigationGraph } from 'irr-gh'
import 'irr-gh/style.css'
import type { IrrigationData } from 'irr-gh'
const graphRef = ref()
// 完整示例数据
const demoData: IrrigationData = {
lines: [
{ id: 'main', name: '总干渠', type: 'canal', level: 1 },
{ id: 'branch-A', name: 'A支渠', type: 'canal', parentId: 'main', bankSide: 'left', level: 2 },
{ id: 'branch-B', name: 'B支渠', type: 'canal', parentId: 'main', bankSide: 'right', level: 2 }
],
points: [
// 总干渠上的点位
{ id: 'intake', name: '进水闸', type: 'sluice', canalId: 'main', chainage: 0 },
{ id: 'fork-A', name: 'A分叉', type: 'auxiliary', auxiliaryType: 'fork', canalId: 'main', chainage: 100, branchId: 'branch-A' },
{ id: 'pump-1', name: '1号泵站', type: 'pumpStation', canalId: 'main', chainage: 200 },
{ id: 'fork-B', name: 'B分叉', type: 'auxiliary', auxiliaryType: 'fork', canalId: 'main', chainage: 300, branchId: 'branch-B' },
{ id: 'outlet', name: '出水闸', type: 'sluice', canalId: 'main', chainage: 400 },
// A支渠上的点位
{ id: 'sluice-A1', name: 'A1闸门', type: 'sluice', canalId: 'branch-A', chainage: 0 },
{ id: 'reservoir-A', name: 'A水库', type: 'reservoir', canalId: 'branch-A', chainage: 50 },
// B支渠上的点位
{ id: 'sluice-B1', name: 'B1闸门', type: 'sluice', canalId: 'branch-B', chainage: 0 },
{ id: 'dispatch-B', name: 'B调度单元', type: 'dispatchUnit', canalId: 'branch-B', chainage: 50 }
]
}
// 事件处理
function handleReady(graph: unknown) {
console.log('图渲染完成')
}
function handleItemClick({ type, item }: { type: string; item: unknown }) {
console.log(`点击了${type}:`, item)
}
function handleCanvasClick(event: MouseEvent) {
console.log('画布点击', event)
}
// API 操作示例
function switchToHorizontal() {
graphRef.value?.changeLayout('horizontal')
}
function switchToVertical() {
graphRef.value?.changeLayout('vertical')
}
function exportImage() {
graphRef.value?.downloadImage({ fileName: 'irrigation-diagram' })
}
</script>
<template>
<div class="app">
<IrrigationGraph
ref="graphRef"
:data="demoData"
:enable-minimap="true"
:fit-view="true"
:show-toolbar="true"
:enabled-toolbar-actions="{
zoomIn: true,
zoomOut: true,
fitView: true,
save: true,
export: true,
print: true,
layout: true
}"
@ready="handleReady"
@item-click="handleItemClick"
@canvas-click="handleCanvasClick"
/>
</div>
</template>
<style>
.app {
width: 100vw;
height: 100vh;
}
</style>
类型导出
// 通用拓扑契约(topograph/core 入口)
import type {
TopoData, TopoNode, TopoEdge, TopoCombo, TopoGroup,
LayoutEngine, LayoutStrategy,
} from 'irr-gh/core'
// 灌溉适配层(topograph/irrigation 入口)
import {
normalizeIrrigation,
toTopoData, toTopoDataFromIrrigation,
type IrrigationInput, IrrigationElement, IrrigationCombo, IrrigationGroup,
} from 'irr-gh/irrigation'
// 根入口(组件 + 图管理 + Hook)
import {
IrrigationGraph, EvolutionTimeline,
IrrigationGraphManager, createGraphManager,
useIrrigationGraph, useConfigPanel,
// 图数据类型
type IrrigationGraphData, IrrigationNodeData, IrrigationEdgeData,
// 演进数据类型
type EvolutionData, EvolutionConfig, EvolutionTimePoint, EvolutionEventParams,
// 配置与 Props
type IrrigationGraphProps, GraphOptions, LayoutConfig, ThemeConfig, DataPanelConfig,
// 布局与交互
type LayoutDirection, LayoutSpacing, InteractionEventType, InteractionEventHandler,
} from 'irr-gh'
License
MIT
Related Packages
Version History
| Version | Released | License |
|---|---|---|
| 1.4.2 | MIT | |
| 1.4.1 | MIT | |
| 1.4.0 | MIT | |
| 1.3.0 | MIT | |
| 1.2.0 | MIT | |
| 1.1.0 | MIT | |
| 1.0.1 | MIT | |
| 1.0.0 | MIT | |
| 0.1.40 | MIT | |
| 0.1.39 | MIT | |
| 0.1.38 | MIT | |
| 0.1.37 | MIT | |
| 0.1.36 | MIT | |
| 0.1.35 | MIT | |
| 0.1.34 | MIT | |
| 0.1.33 | MIT | |
| 0.1.32 | MIT | |
| 0.1.31 | MIT | |
| 0.1.30 | MIT | |
| 0.1.29 | MIT | |
| 0.1.28 | MIT | |
| 0.1.27 | MIT | |
| 0.1.26 | MIT | |
| 0.1.25 | MIT | |
| 0.1.24 | MIT | |
| 0.1.23 | MIT | |
| 0.1.22 | MIT | |
| 0.1.21 | MIT | |
| 0.1.20 | MIT | |
| 0.1.19 | MIT |
Showing the latest 30 of 49. See every release on npm