irr-gh

灌溉系统概化图组件
6,796
Install
npm install irr-gh
Latest Version:1.4.2
Vue:3
License:MIT
Last Updated:Oct 19, 2026
Links: npm
Maintainer: eriver

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,内核零改动。


边样式自定义

边由转换器根据渠道/点位关系自动生成,可用以下层级覆盖样式(优先级从高到低):

  1. 演进级:EvolutionManager/TimelineApplier 按报警级别、流向叠加报警色/渐变(见「数据演进」)。
  2. 渠道级 (Canal):在 IrrigationElement.style 配置该渠(kind ∈ river/canal/ditch)下所有自动生成边的默认样式。
  3. 全局级 (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

kgraph

简易流程图绘制工具

3,211
vue-c3

vue-c3 is a reusable vue component for c3 charts

60,819 79
@mx-sose-front/mx-sose-graph

A Vue3 graph visualization plugin library

7,983
vue-neo4j

Neo4j connector for Vue

2,597 73

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