irr-gh 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,42 +1,859 @@
1
- # irr-gh
2
-
3
- This template should help get you started developing with Vue 3 in Vite.
4
-
5
- ## Recommended IDE Setup
6
-
7
- [VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
8
-
9
- ## Recommended Browser Setup
10
-
11
- - Chromium-based browsers (Chrome, Edge, Brave, etc.):
12
- - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
13
- - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
14
- - Firefox:
15
- - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
16
- - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
17
-
18
- ## Type Support for `.vue` Imports in TS
19
-
20
- TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
21
-
22
- ## Customize configuration
23
-
24
- See [Vite Configuration Reference](https://vite.dev/config/).
25
-
26
- ## Project Setup
27
-
28
- ```sh
29
- bun install
30
- ```
31
-
32
- ### Compile and Hot-Reload for Development
33
-
34
- ```sh
35
- bun dev
36
- ```
37
-
38
- ### Type-Check, Compile and Minify for Production
39
-
40
- ```sh
41
- bun run build
42
- ```
1
+ # irr-gh - 灌溉系统概化图组件
2
+
3
+ 基于 Vue 3 + AntV G6 v5 的灌溉系统概化图可视化组件库。
4
+
5
+ ## 目录
6
+
7
+ - [安装](#安装)
8
+ - [快速开始](#快速开始)
9
+ - [布局系统](#布局系统)
10
+ - [布局方向](#布局方向)
11
+ - [布局规则](#布局规则)
12
+ - [布局间距配置](#布局间距配置)
13
+ - [组件配置](#组件配置)
14
+ - [Props 属性](#props-属性)
15
+ - [Events 事件](#events-事件)
16
+ - [Slots 插槽](#slots-插槽)
17
+ - [API 方法](#api-方法)
18
+ - [数据操作](#数据操作)
19
+ - [视图控制](#视图控制)
20
+ - [布局操作](#布局操作)
21
+ - [导出与保存](#导出与保存)
22
+ - [事件监听](#事件监听)
23
+ - [数据结构](#数据结构)
24
+ - [业务数据结构](#业务数据结构)
25
+ - [实体类型](#实体类型)
26
+ - [G6 图数据结构](#g6-图数据结构)
27
+ - [工具栏](#工具栏)
28
+ - [主题配置](#主题配置)
29
+ - [Hook 使用](#hook-使用)
30
+ - [布局辅助工具](#布局辅助工具)
31
+ - [完整示例](#完整示例)
32
+
33
+ ---
34
+
35
+ ## 安装
36
+
37
+ ```bash
38
+ npm install irr-gh
39
+ # 或
40
+ pnpm add irr-gh
41
+ #
42
+ bun add irr-gh
43
+ ```
44
+
45
+ ## 快速开始
46
+
47
+ ```vue
48
+ <script setup lang="ts">
49
+ import { ref } from 'vue'
50
+ import { IrrigationGraph } from 'irr-gh'
51
+ import 'irr-gh/style.css'
52
+ import type { IrrigationData } from 'irr-gh'
53
+
54
+ const graphRef = ref()
55
+
56
+ // 示例数据
57
+ const data: IrrigationData = {
58
+ canals: [
59
+ { id: 'main', name: '主干渠', type: 'canal', level: 1 },
60
+ { id: 'branch-1', name: '支渠1', type: 'canal', parentId: 'main', bankSide: 'left' }
61
+ ],
62
+ points: [
63
+ { id: 'sluice-1', name: '闸门1', type: 'sluice', canalId: 'main', chainage: 0 },
64
+ { id: 'sluice-2', name: '闸门2', type: 'sluice', canalId: 'main', chainage: 100 }
65
+ ]
66
+ }
67
+
68
+ function handleReady(graph: unknown) {
69
+ console.log('图渲染完成', graph)
70
+ }
71
+ </script>
72
+
73
+ <template>
74
+ <IrrigationGraph
75
+ ref="graphRef"
76
+ :data="data"
77
+ :enable-minimap="true"
78
+ :fit-view="true"
79
+ :show-toolbar="true"
80
+ @ready="handleReady"
81
+ />
82
+ </template>
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 布局系统
88
+
89
+ ### 布局方向
90
+
91
+ 组件支持两种布局方向:
92
+
93
+ | 布局类型 | 值 | 说明 |
94
+ |---------|------|------|
95
+ | 横向布局 | `'horizontal'` | 主干渠从左到右水平排列,支渠向上/下垂直分叉 |
96
+ | 纵向布局 | `'vertical'` | 主干渠从上到下垂直排列,支渠向左/右水平分叉 |
97
+
98
+ ### 布局规则
99
+
100
+ #### 1. 主干渠方向决定布局
101
+ - **横向布局**:主干渠从左到右水平绘制
102
+ - **纵向布局**:主干渠从上到下垂直绘制
103
+
104
+ #### 2. 支渠垂直相交原则
105
+ 支渠始终与父级渠道垂直相交:
106
+
107
+ **横向布局时:**
108
+ - 父级水平 → 子级垂直
109
+ - 左岸(`bankSide: 'left'`)→ 向上分叉
110
+ - 右岸(`bankSide: 'right'`)→ 向下分叉
111
+
112
+ **纵向布局时:**
113
+ - 父级垂直 → 子级水平
114
+ - 左岸(`bankSide: 'left'`)→ 向左分叉
115
+ - 右岸(`bankSide: 'right'`)→ 向右分叉
116
+
117
+ #### 3. 主干渠居中
118
+ 主干渠自动居中到画布中心位置。
119
+
120
+ ### 布局间距配置
121
+
122
+ ```typescript
123
+ interface LayoutSpacing {
124
+ /** 主渠方向节点间距 */
125
+ main: number // 默认: 150
126
+ /** 支渠方向节点间距 */
127
+ branch: number // 默认: 120
128
+ /** 分支偏移距离 */
129
+ branchOffset: number // 默认: 80
130
+ }
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 组件配置
136
+
137
+ ### Props 属性
138
+
139
+ | 属性 | 类型 | 默认值 | 说明 |
140
+ |------|------|--------|------|
141
+ | `width` | `number` | - | 画布宽度(不设置则自适应容器) |
142
+ | `height` | `number` | - | 画布高度(不设置则自适应容器) |
143
+ | `data` | `IrrigationData` | - | 业务数据(原始格式) |
144
+ | `graphData` | `IrrigationGraphData` | - | G6图数据(已转换格式) |
145
+ | `layout` | `LayoutConfig` | - | 布局配置 |
146
+ | `theme` | `ThemeConfig` | - | 主题配置 |
147
+ | `tooltip` | `TooltipConfig` | - | Tooltip配置 |
148
+ | `enableDrag` | `boolean` | `true` | 是否启用拖拽 |
149
+ | `enableZoom` | `boolean` | `true` | 是否启用缩放 |
150
+ | `enableBrush` | `boolean` | `false` | 是否启用框选 |
151
+ | `enableMinimap` | `boolean` | `false` | 是否启用小地图 |
152
+ | `fitView` | `boolean` | `true` | 是否适应画布 |
153
+ | `fitViewPadding` | `number \| number[]` | - | 适应画布的内边距 |
154
+ | `readonly` | `boolean` | `false` | 是否只读模式 |
155
+ | `showToolbar` | `boolean` | `false` | 是否显示内置工具栏 |
156
+ | `enabledToolbarActions` | `ToolbarActions` | 全部启用 | 启用的工具栏功能 |
157
+
158
+ #### ToolbarActions 配置
159
+
160
+ ```typescript
161
+ interface ToolbarActions {
162
+ zoomIn?: boolean // 放大按钮
163
+ zoomOut?: boolean // 缩小按钮
164
+ fitView?: boolean // 适应视图按钮
165
+ save?: boolean // 保存按钮
166
+ export?: boolean // 导出按钮
167
+ print?: boolean // 打印按钮
168
+ layout?: boolean // 布局切换按钮
169
+ }
170
+ ```
171
+
172
+ ### Events 事件
173
+
174
+ | 事件名 | 参数 | 说明 |
175
+ |--------|------|------|
176
+ | `ready` | `(graph: Graph)` | 图渲染完成 |
177
+ | `itemClick` | `({ type: string, item: unknown })` | 节点/边点击 |
178
+ | `itemDblClick` | `({ type: string, item: unknown })` | 节点/边双击 |
179
+ | `itemContextMenu` | `({ type: string, item: unknown, event: MouseEvent })` | 节点/边右键菜单 |
180
+ | `selectionChange` | `({ nodes: string[], edges: string[] })` | 选中状态变化 |
181
+ | `canvasClick` | `(event: MouseEvent)` | 画布点击 |
182
+ | `dataChange` | `(data: IrrigationGraphData)` | 数据变化 |
183
+
184
+ ### Slots 插槽
185
+
186
+ | 插槽名 | 参数 | 说明 |
187
+ |--------|------|------|
188
+ | `toolbar` | `{ zoomIn, zoomOut, fitView }` | 自定义工具栏 |
189
+ | `loading` | - | 自定义加载状态 |
190
+ | `default` | - | 默认插槽,用于额外内容 |
191
+
192
+ ---
193
+
194
+ ## API 方法
195
+
196
+ 通过 `ref` 获取组件实例调用方法:
197
+
198
+ ```vue
199
+ <script setup>
200
+ const graphRef = ref()
201
+
202
+ // 调用方法
203
+ graphRef.value?.zoomIn()
204
+ </script>
205
+
206
+ <template>
207
+ <IrrigationGraph ref="graphRef" />
208
+ </template>
209
+ ```
210
+
211
+ ### 数据操作
212
+
213
+ | 方法 | 签名 | 说明 |
214
+ |------|------|------|
215
+ | `render` | `(data: IrrigationGraphData) => Promise<void>` | 渲染G6格式数据 |
216
+ | `renderFromData` | `(data: IrrigationData, direction?: LayoutDirection) => Promise<void>` | 从业务数据渲染 |
217
+ | `updateData` | `(data: Partial<IrrigationGraphData>) => Promise<void>` | 更新数据 |
218
+ | `addNode` | `(node: IrrigationNodeData) => Promise<void>` | 添加节点 |
219
+ | `addEdge` | `(edge: IrrigationEdgeData) => Promise<void>` | 添加边 |
220
+ | `removeNode` | `(nodeId: string) => Promise<void>` | 删除节点 |
221
+ | `removeEdge` | `(edgeId: string) => Promise<void>` | 删除边 |
222
+ | `updateNode` | `(nodeId: string, data: Partial<IrrigationNodeData>) => Promise<void>` | 更新节点 |
223
+ | `updateEdge` | `(edgeId: string, data: Partial<IrrigationEdgeData>) => Promise<void>` | 更新边 |
224
+ | `getData` | `() => IrrigationGraphData` | 获取当前图数据 |
225
+
226
+ ### 视图控制
227
+
228
+ | 方法 | 签名 | 说明 |
229
+ |------|------|------|
230
+ | `zoomIn` | `() => void` | 放大视图 |
231
+ | `zoomOut` | `() => void` | 缩小视图 |
232
+ | `zoomTo` | `(ratio: number) => void` | 缩放到指定比例 |
233
+ | `fitView` | `() => void` | 适应视图 |
234
+ | `focusNode` | `(nodeId: string) => void` | 聚焦到指定节点 |
235
+
236
+ ### 布局操作
237
+
238
+ | 方法 | 签名 | 说明 |
239
+ |------|------|------|
240
+ | `changeLayout` | `(type: 'horizontal' \| 'vertical') => Promise<void>` | 切换布局方向 |
241
+ | `changeLayoutDirection` | `(data: IrrigationData, direction: LayoutDirection) => Promise<void>` | 使用新布局方向重新渲染 |
242
+ | `setLayout` | `(layout: LayoutConfig) => Promise<void>` | 设置G6布局配置 |
243
+
244
+ ### 导出与保存
245
+
246
+ | 方法 | 签名 | 说明 |
247
+ |------|------|------|
248
+ | `save` | `() => string` | 保存为JSON字符串 |
249
+ | `load` | `(json: string) => Promise<void>` | 从JSON加载 |
250
+ | `toImage` | `(config?: ExportConfig) => Promise<string>` | 导出为图片(Base64) |
251
+ | `downloadImage` | `(config?: ExportConfig) => Promise<void>` | 下载图片 |
252
+ | `print` | `() => void` | 打印 |
253
+
254
+ #### ExportConfig 配置
255
+
256
+ ```typescript
257
+ interface ExportConfig {
258
+ fileName?: string // 文件名,默认: 'irrigation-graph'
259
+ format?: 'png' | 'jpg' | 'svg' | 'pdf' // 导出格式
260
+ backgroundColor?: string // 背景色
261
+ scale?: number // 缩放比例
262
+ }
263
+ ```
264
+
265
+ ### 事件监听
266
+
267
+ | 方法 | 签名 | 说明 |
268
+ |------|------|------|
269
+ | `on` | `(type: InteractionEventType, handler: Function) => void` | 监听事件 |
270
+ | `off` | `(type: InteractionEventType, handler?: Function) => void` | 移除事件监听 |
271
+
272
+ #### 可监听的事件类型
273
+
274
+ ```typescript
275
+ type InteractionEventType =
276
+ | 'node:click' | 'node:dblclick' | 'node:contextmenu'
277
+ | 'node:mouseenter' | 'node:mouseleave'
278
+ | 'node:dragstart' | 'node:drag' | 'node:dragend'
279
+ | 'edge:click' | 'edge:dblclick' | 'edge:contextmenu'
280
+ | 'edge:mouseenter' | 'edge:mouseleave'
281
+ | 'canvas:click' | 'canvas:dragstart' | 'canvas:drag' | 'canvas:dragend'
282
+ | 'combo:click' | 'combo:dblclick'
283
+ ```
284
+
285
+ ---
286
+
287
+ ## 数据结构
288
+
289
+ ### 业务数据结构
290
+
291
+ ```typescript
292
+ interface IrrigationData {
293
+ /** 河渠沟列表 */
294
+ canals: CanalEntity[]
295
+ /** 点位实体列表 */
296
+ points: PointEntityUnion[]
297
+ /** 连接关系(可选,如不提供则自动生成) */
298
+ connections?: ConnectionData[]
299
+ }
300
+ ```
301
+
302
+ ### 实体类型
303
+
304
+ #### 渠道实体 (CanalEntity)
305
+
306
+ ```typescript
307
+ interface CanalEntity {
308
+ id: string // 唯一标识
309
+ name: string // 名称
310
+ type: 'canal' // 实体类型
311
+ parentId?: string // 父级河渠沟ID
312
+ forkChainage?: number // 上级分岔口桩号
313
+ bankSide?: 'left' | 'right' | 'center' // 岸别
314
+ startChainage?: number // 起始桩号
315
+ endChainage?: number // 终止桩号
316
+ level?: number // 河渠等级
317
+ properties?: Record<string, unknown> // 扩展属性
318
+ }
319
+ ```
320
+
321
+ #### 点位实体类型
322
+
323
+ | 类型 | 说明 | 特有属性 |
324
+ |------|------|----------|
325
+ | `sluice` | 闸门 | `sluiceType`, `designFlow` |
326
+ | `pumpStation` | 泵站 | `capacity`, `pumpType` |
327
+ | `reservoir` | 水库 | `storageCapacity`, `normalLevel` |
328
+ | `dispatchUnit` | 调度单元 | `controlArea` |
329
+ | `dispatchNode` | 调度节点 | `nodeFunction` |
330
+ | `auxiliary` | 辅助节点 | `auxiliaryType` (`fork`/`end`/`junction`) |
331
+
332
+ #### 点位实体基础结构
333
+
334
+ ```typescript
335
+ interface PointEntity {
336
+ id: string // 唯一标识
337
+ name: string // 名称
338
+ type: EntityType // 实体类型
339
+ canalId: string // 所属河渠沟ID
340
+ chainage: number // 桩号位置
341
+ bankSide?: 'left' | 'right' | 'center' // 岸别
342
+ properties?: Record<string, unknown> // 扩展属性
343
+ }
344
+ ```
345
+
346
+ #### 辅助节点 (用于支渠分叉)
347
+
348
+ ```typescript
349
+ interface AuxiliaryNodeEntity extends PointEntity {
350
+ type: 'auxiliary'
351
+ auxiliaryType: 'fork' | 'end' | 'junction' // 分叉点/结束点/汇合点
352
+ branchCanalId?: string // 关联的支渠ID(分叉点使用)
353
+ autoGenerated?: boolean // 是否自动生成
354
+ }
355
+ ```
356
+
357
+ ### G6 图数据结构
358
+
359
+ ```typescript
360
+ interface IrrigationGraphData {
361
+ nodes?: IrrigationNodeData[]
362
+ edges?: IrrigationEdgeData[]
363
+ combos?: IrrigationComboData[]
364
+ }
365
+
366
+ interface IrrigationNodeData extends NodeData {
367
+ entityType: EntityType // 业务实体类型
368
+ businessData?: IrrigationEntity // 原始业务数据
369
+ nodeShape?: 'rect' | 'circle' | 'ellipse' | 'diamond' | 'image'
370
+ styleConfig?: NodeStyleConfig
371
+ labelConfig?: LabelStyleConfig
372
+ }
373
+
374
+ interface IrrigationEdgeData extends EdgeData {
375
+ edgeShape?: 'line' | 'polyline' | 'quadratic' | 'cubic' | 'arc'
376
+ connectionType?: 'flow' | 'control' | 'supply'
377
+ styleConfig?: EdgeStyleConfig
378
+ labelConfig?: LabelStyleConfig
379
+ }
380
+ ```
381
+
382
+ ---
383
+
384
+ ## 工具栏
385
+
386
+ ### 内置工具栏
387
+
388
+ 通过 `showToolbar` 属性启用内置工具栏:
389
+
390
+ ```vue
391
+ <IrrigationGraph
392
+ :show-toolbar="true"
393
+ :enabled-toolbar-actions="{
394
+ zoomIn: true,
395
+ zoomOut: true,
396
+ fitView: true,
397
+ save: true,
398
+ export: true,
399
+ print: true,
400
+ layout: true
401
+ }"
402
+ />
403
+ ```
404
+
405
+ ### 自定义工具栏
406
+
407
+ 使用 `toolbar` 插槽自定义工具栏:
408
+
409
+ ```vue
410
+ <IrrigationGraph ref="graphRef">
411
+ <template #toolbar="{ zoomIn, zoomOut, fitView }">
412
+ <div class="my-toolbar">
413
+ <button @click="zoomIn">放大</button>
414
+ <button @click="zoomOut">缩小</button>
415
+ <button @click="fitView">适应</button>
416
+ <button @click="graphRef?.changeLayout('horizontal')">横向</button>
417
+ <button @click="graphRef?.changeLayout('vertical')">纵向</button>
418
+ </div>
419
+ </template>
420
+ </IrrigationGraph>
421
+ ```
422
+
423
+ ---
424
+
425
+ ## 主题配置
426
+
427
+ ### 默认样式常量
428
+
429
+ ```typescript
430
+ // 渠道/边的默认宽度
431
+ export const CANAL_WIDTH = 10
432
+
433
+ // 渠道默认颜色
434
+ export const CANAL_COLOR = '#1890ff'
435
+ ```
436
+
437
+ ### 辅助节点样式
438
+
439
+ 辅助节点(分叉点、结束点、汇合点)样式与渠道保持一致:
440
+ - **形状**:正方形(rect)
441
+ - **尺寸**:10 × 10 像素(与渠道宽度一致)
442
+ - **颜色**:与渠道颜色一致(#1890ff)
443
+ - **无边框、无圆角**
444
+
445
+ ### 节点形状类型
446
+
447
+ 支持以下节点形状:
448
+
449
+ | 形状 | 值 | 说明 |
450
+ |------|------|------|
451
+ | 矩形 | `'rect'` | 默认形状,可设置圆角 radius |
452
+ | 圆形 | `'circle'` | 圆形节点 |
453
+ | 菱形 | `'diamond'` | 菱形节点 |
454
+ | 椭圆 | `'ellipse'` | 椭圆节点 |
455
+ | 图片 | `'image'` | 使用图片作为节点,需配置 img 属性 |
456
+ | 自定义 | `'custom'` | 自定义节点形状 |
457
+
458
+ ### 默认节点样式映射
459
+
460
+ | 实体类型 | 默认形状 | 填充色 | 边框色 |
461
+ |----------|----------|--------|--------|
462
+ | sluice (闸门) | rect | #fffbe6 | #faad14 |
463
+ | pumpStation (泵站) | rect | #f6ffed | #52c41a |
464
+ | reservoir (水库) | circle | #e6fffb | #13c2c2 |
465
+ | dispatchUnit (调度单元) | diamond | #f9f0ff | #722ed1 |
466
+ | dispatchNode (调度节点) | circle | #fff0f6 | #eb2f96 |
467
+ | auxiliary (辅助节点) | rect | #1890ff | #1890ff |
468
+
469
+ ### 图片类型节点
470
+
471
+ 点位节点支持使用图片,通过 `styleConfig.img` 配置:
472
+
473
+ ```typescript
474
+ // 业务数据中的节点配置(推荐方式)
475
+ const sluiceWithImage: SluiceEntity = {
476
+ id: 'gate-1',
477
+ name: '进水闸',
478
+ type: 'sluice',
479
+ canalId: 'canal-1',
480
+ chainage: 0,
481
+ sluiceType: 'inlet',
482
+ // 通过 nodeConfig 指定节点渲染样式
483
+ nodeConfig: {
484
+ shape: 'image',
485
+ img: '/head.png',
486
+ width: 48,
487
+ height: 48
488
+ }
489
+ }
490
+
491
+ // 其他类型的图片配置
492
+ const pumpStationWithImage: PumpStationEntity = {
493
+ id: 'pump-1',
494
+ name: '泵站',
495
+ type: 'pumpStation',
496
+ canalId: 'canal-1',
497
+ chainage: 100,
498
+ capacity: 500,
499
+ pumpType: 'lift',
500
+ nodeConfig: {
501
+ shape: 'image',
502
+ img: '/pump-station.png',
503
+ width: 48,
504
+ height: 48
505
+ }
506
+ }
507
+
508
+ // 普通矩形节点配置
509
+ const sluiceWithRect: SluiceEntity = {
510
+ id: 'gate-2',
511
+ name: '普通闸门',
512
+ type: 'sluice',
513
+ canalId: 'canal-1',
514
+ chainage: 200,
515
+ sluiceType: 'other',
516
+ nodeConfig: {
517
+ shape: 'rect',
518
+ width: 48,
519
+ height: 36,
520
+ fill: '#fffbe6',
521
+ stroke: '#faad14'
522
+ }
523
+ }
524
+
525
+ // G6图数据(转换后)
526
+ const nodeData: IrrigationNodeData = {
527
+ id: 'gate-1',
528
+ entityType: 'sluice',
529
+ nodeShape: 'image', // 从 nodeConfig.shape 得到
530
+ styleConfig: {
531
+ img: '/head.png', // 从 nodeConfig.img 得到
532
+ width: 48,
533
+ height: 48,
534
+ fill: '#fffbe6',
535
+ stroke: '#faad14'
536
+ },
537
+ data: { label: '进水闸' },
538
+ businessData: sluiceWithImage // 保留原始业务数据
539
+ }
540
+ ```
541
+
542
+ ### 边/渠道样式
543
+
544
+ 默认渠道样式:
545
+ - **宽度**:10 像素
546
+ - **颜色**:#1890ff
547
+ - **无箭头**:默认不显示箭头
548
+
549
+ 连接类型样式:
550
+
551
+ | 连接类型 | 颜色 | 宽度 | 样式 |
552
+ |----------|------|------|------|
553
+ | flow (水流) | #1890ff | 10px | 实线 |
554
+ | control (控制) | #faad14 | 3px | 虚线 [8, 4] |
555
+ | supply (供水) | #52c41a | 3px | 虚线 [6, 4] |
556
+
557
+ ### 主题配置接口
558
+
559
+ ```typescript
560
+ interface ThemeConfig {
561
+ name?: 'light' | 'dark' | 'custom'
562
+ nodeStyle?: Partial<Record<EntityType, NodeStyleConfig>>
563
+ edgeStyle?: EdgeStyleConfig
564
+ backgroundColor?: string
565
+ }
566
+
567
+ interface NodeStyleConfig {
568
+ fill?: string // 填充色
569
+ stroke?: string // 边框色
570
+ lineWidth?: number // 边框宽度
571
+ opacity?: number // 透明度
572
+ radius?: number // 圆角半径
573
+ width?: number // 宽度
574
+ height?: number // 高度
575
+ shadowColor?: string // 阴影颜色
576
+ shadowBlur?: number // 阴影模糊度
577
+ }
578
+
579
+ interface EdgeStyleConfig {
580
+ stroke?: string // 线条颜色
581
+ lineWidth?: number // 线条宽度
582
+ lineDash?: number[] // 虚线配置
583
+ opacity?: number // 透明度
584
+ endArrow?: boolean // 结束箭头
585
+ startArrow?: boolean // 起始箭头
586
+ }
587
+ ```
588
+
589
+ ### 使用示例
590
+
591
+ ```vue
592
+ <IrrigationGraph
593
+ :theme="{
594
+ name: 'custom',
595
+ backgroundColor: '#f5f5f5',
596
+ nodeStyle: {
597
+ sluice: { fill: '#1890ff', stroke: '#0050b3' },
598
+ pumpStation: { fill: '#52c41a', stroke: '#237804' },
599
+ reservoir: { fill: '#722ed1', stroke: '#391085' }
600
+ },
601
+ edgeStyle: {
602
+ stroke: '#333',
603
+ lineWidth: 2
604
+ }
605
+ }"
606
+ />
607
+ ```
608
+
609
+ ---
610
+
611
+ ## Hook 使用
612
+
613
+ 可以直接使用 `useIrrigationGraph` Hook 获得更灵活的控制:
614
+
615
+ ```vue
616
+ <script setup lang="ts">
617
+ import { ref } from 'vue'
618
+ import { useIrrigationGraph } from 'irr-gh'
619
+
620
+ const containerRef = ref<HTMLElement | null>(null)
621
+
622
+ const {
623
+ graph,
624
+ manager,
625
+ state,
626
+ initialized,
627
+ loading,
628
+ init,
629
+ render,
630
+ renderFromData,
631
+ changeLayoutDirection,
632
+ zoomIn,
633
+ zoomOut,
634
+ fitView,
635
+ getData,
636
+ save,
637
+ load,
638
+ toImage,
639
+ downloadImage,
640
+ print,
641
+ on,
642
+ off,
643
+ destroy
644
+ } = useIrrigationGraph({
645
+ container: containerRef,
646
+ width: 1200,
647
+ height: 800,
648
+ data: myData,
649
+ layoutDirection: 'horizontal',
650
+ autoInit: true,
651
+ options: {
652
+ enableDrag: true,
653
+ enableZoom: true,
654
+ enableMinimap: true
655
+ }
656
+ })
657
+ </script>
658
+
659
+ <template>
660
+ <div ref="containerRef" style="width: 100%; height: 600px;"></div>
661
+ </template>
662
+ ```
663
+
664
+ ### Hook 配置选项
665
+
666
+ ```typescript
667
+ interface UseIrrigationGraphOptions {
668
+ container: Ref<HTMLElement | null> // 容器元素引用
669
+ width?: number // 画布宽度
670
+ height?: number // 画布高度
671
+ data?: IrrigationData // 初始业务数据
672
+ graphData?: IrrigationGraphData // 初始G6数据
673
+ options?: Partial<GraphOptions> // 图配置选项
674
+ autoInit?: boolean // 是否自动初始化(默认true)
675
+ layoutDirection?: LayoutDirection // 初始布局方向(默认horizontal)
676
+ }
677
+ ```
678
+
679
+ ---
680
+
681
+ ## 布局辅助工具
682
+
683
+ 组件暴露了 `layoutUtils` 对象,提供布局辅助函数:
684
+
685
+ ```typescript
686
+ // 通过组件实例访问
687
+ graphRef.value?.layoutUtils
688
+
689
+ // 可用方法
690
+ layoutUtils.getNodePosition(node) // 获取节点位置
691
+ layoutUtils.setNodePosition(node, x, y) // 设置节点位置
692
+ layoutUtils.alignNodesHorizontally(nodes, alignType) // 水平对齐
693
+ layoutUtils.alignNodesVertically(nodes, alignType) // 垂直对齐
694
+ layoutUtils.distributeNodesHorizontally(nodes, spacing) // 水平等距分布
695
+ layoutUtils.distributeNodesVertically(nodes, spacing) // 垂直等距分布
696
+ layoutUtils.moveNodes(nodes, deltaX, deltaY) // 批量移动节点
697
+ layoutUtils.getNodesBoundingBox(nodes) // 获取节点边界框
698
+ layoutUtils.centerNodesToPosition(nodes, x, y) // 居中节点到位置
699
+ layoutUtils.centerNodesToCanvas(nodes, width, height) // 居中节点到画布
700
+ layoutUtils.flipNodes(nodes, axis) // 翻转节点
701
+ layoutUtils.rotateNodes90(nodes, clockwise) // 旋转90度
702
+ layoutUtils.getNodesByCanalId(data, canalId) // 按渠道ID获取节点
703
+ layoutUtils.getConnectedNodes(data, nodeId) // 获取相邻节点
704
+ layoutUtils.autoAdjustSpacing(nodes, direction, spacing) // 自动调整间距
705
+ ```
706
+
707
+ ---
708
+
709
+ ## 完整示例
710
+
711
+ ```vue
712
+ <script setup lang="ts">
713
+ import { ref, onMounted } from 'vue'
714
+ import { IrrigationGraph } from 'irr-gh'
715
+ import 'irr-gh/style.css'
716
+ import type { IrrigationData } from 'irr-gh'
717
+
718
+ const graphRef = ref()
719
+
720
+ // 完整示例数据
721
+ const demoData: IrrigationData = {
722
+ canals: [
723
+ { id: 'main', name: '总干渠', type: 'canal', level: 1 },
724
+ { id: 'branch-A', name: 'A支渠', type: 'canal', parentId: 'main', bankSide: 'left', level: 2 },
725
+ { id: 'branch-B', name: 'B支渠', type: 'canal', parentId: 'main', bankSide: 'right', level: 2 }
726
+ ],
727
+ points: [
728
+ // 总干渠上的点位
729
+ { id: 'intake', name: '进水闸', type: 'sluice', canalId: 'main', chainage: 0 },
730
+ { id: 'fork-A', name: 'A分叉', type: 'auxiliary', auxiliaryType: 'fork', canalId: 'main', chainage: 100, branchCanalId: 'branch-A' },
731
+ { id: 'pump-1', name: '1号泵站', type: 'pumpStation', canalId: 'main', chainage: 200 },
732
+ { id: 'fork-B', name: 'B分叉', type: 'auxiliary', auxiliaryType: 'fork', canalId: 'main', chainage: 300, branchCanalId: 'branch-B' },
733
+ { id: 'outlet', name: '出水闸', type: 'sluice', canalId: 'main', chainage: 400 },
734
+
735
+ // A支渠上的点位
736
+ { id: 'sluice-A1', name: 'A1闸门', type: 'sluice', canalId: 'branch-A', chainage: 0 },
737
+ { id: 'reservoir-A', name: 'A水库', type: 'reservoir', canalId: 'branch-A', chainage: 50 },
738
+
739
+ // B支渠上的点位
740
+ { id: 'sluice-B1', name: 'B1闸门', type: 'sluice', canalId: 'branch-B', chainage: 0 },
741
+ { id: 'dispatch-B', name: 'B调度单元', type: 'dispatchUnit', canalId: 'branch-B', chainage: 50 }
742
+ ]
743
+ }
744
+
745
+ // 事件处理
746
+ function handleReady(graph: unknown) {
747
+ console.log('图渲染完成')
748
+ }
749
+
750
+ function handleItemClick({ type, item }: { type: string; item: unknown }) {
751
+ console.log(`点击了${type}:`, item)
752
+ }
753
+
754
+ function handleCanvasClick(event: MouseEvent) {
755
+ console.log('画布点击', event)
756
+ }
757
+
758
+ // API 操作示例
759
+ function switchToHorizontal() {
760
+ graphRef.value?.changeLayout('horizontal')
761
+ }
762
+
763
+ function switchToVertical() {
764
+ graphRef.value?.changeLayout('vertical')
765
+ }
766
+
767
+ function exportImage() {
768
+ graphRef.value?.downloadImage({ fileName: 'irrigation-diagram' })
769
+ }
770
+ </script>
771
+
772
+ <template>
773
+ <div class="app">
774
+ <IrrigationGraph
775
+ ref="graphRef"
776
+ :data="demoData"
777
+ :enable-minimap="true"
778
+ :fit-view="true"
779
+ :show-toolbar="true"
780
+ :enabled-toolbar-actions="{
781
+ zoomIn: true,
782
+ zoomOut: true,
783
+ fitView: true,
784
+ save: true,
785
+ export: true,
786
+ print: true,
787
+ layout: true
788
+ }"
789
+ @ready="handleReady"
790
+ @item-click="handleItemClick"
791
+ @canvas-click="handleCanvasClick"
792
+ />
793
+ </div>
794
+ </template>
795
+
796
+ <style>
797
+ .app {
798
+ width: 100vw;
799
+ height: 100vh;
800
+ }
801
+ </style>
802
+ ```
803
+
804
+ ---
805
+
806
+ ## 类型导出
807
+
808
+ ```typescript
809
+ // 从 irr-gh 导入类型
810
+ import type {
811
+ // 业务数据类型
812
+ IrrigationData,
813
+ CanalEntity,
814
+ PointEntityUnion,
815
+ SluiceEntity,
816
+ PumpStationEntity,
817
+ ReservoirEntity,
818
+ DispatchUnitEntity,
819
+ DispatchNodeEntity,
820
+ AuxiliaryNodeEntity,
821
+ ConnectionData,
822
+ EntityType,
823
+ BankSide,
824
+
825
+ // 图数据类型
826
+ IrrigationGraphData,
827
+ IrrigationNodeData,
828
+ IrrigationEdgeData,
829
+ IrrigationComboData,
830
+
831
+ // 配置类型
832
+ GraphOptions,
833
+ LayoutConfig,
834
+ ThemeConfig,
835
+ TooltipConfig,
836
+ ExportConfig,
837
+ NodeStyleConfig,
838
+ EdgeStyleConfig,
839
+ LabelStyleConfig,
840
+
841
+ // Props类型
842
+ IrrigationGraphProps,
843
+
844
+ // 布局类型
845
+ LayoutDirection,
846
+ LayoutSpacing,
847
+
848
+ // 事件类型
849
+ InteractionEventType,
850
+ InteractionEventHandler,
851
+ InteractionEventParams
852
+ } from 'irr-gh'
853
+ ```
854
+
855
+ ---
856
+
857
+ ## License
858
+
859
+ MIT