Blame view

HHECS.Web/src/components/MapModule/flow/graph/index.js 15.2 KB
胡菁 authored
1
2
3
4
5
6
7
// import { Addon, FunctionExt, Graph, Shape } from "@antv/x6";
import { FunctionExt, Graph, Shape } from "@antv/x6";
import { getImg } from "../index.js";
import graphData from "./data/data";
import { customPorts } from "./ports";
import "./shape";
const insertCss = require("insert-css");
胡菁 authored
8
9
10
11
12
13
14

insertCss(`
  @keyframes ant-line {
    to {
        stroke-dashoffset: -1000
    }
  }
胡菁 authored
15
`);
胡菁 authored
16
17

export default class FlowGraph {
胡菁 authored
18
19
  static graph = null;
  static stencil = null;
胡菁 authored
20
21
22
23
24
25
26
27
28
29
30
31
32

  /**
   * 初始化方法
   * @param {*} dom 画板容器
   * @param {*} width 容器宽度
   * @param {*} height 容器高度
   * @param {*} flag 默认为true,传入false只实例化画板
   * @returns
   */
  static init(dom, width = 1200, height = 900, flag = true) {
    // 初始化 流程图画板
    this.graph = new Graph({
      background: {
胡菁 authored
33
        color: "#f4f4f4", // 设置画布背景颜色
胡菁 authored
34
35
36
37
38
39
40
41
      },
      container: dom,
      width: width,
      height: height,
      autoResize: true,
      grid: {
        size: 10,
        visible: true,
胡菁 authored
42
        type: "doubleMesh",
胡菁 authored
43
44
        args: [
          {
胡菁 authored
45
46
            color: "#cccccc",
            thickness: 1,
胡菁 authored
47
48
          },
          {
胡菁 authored
49
            color: "#5F95FF",
胡菁 authored
50
            thickness: 1,
胡菁 authored
51
52
53
            factor: 4,
          },
        ],
胡菁 authored
54
55
56
57
58
      },
      scroller: {
        enabled: false,
        pageVisible: false,
        pageBreak: false,
胡菁 authored
59
        pannable: false,
胡菁 authored
60
61
62
63
64
65
66
67
      },
      // 开启画布缩放
      mousewheel: {
        enabled: true,
        // modifiers: ['ctrl', 'meta'],
        minScale: 0.1,
        maxScale: 10,
        // 当鼠标滚轮滚动时触发缩放
胡菁 authored
68
        zoomOnMouseWheel: true,
胡菁 authored
69
70
71
72
73
74
75
76
      },
      interacting: {
        nodeMovable: false, // 节点是否可以被移动。
        edgeMovable: false, // 边是否可以被移动。
        edgeLabelMovable: false, // 边的标签是否可以被移动。
        arrowheadMovable: false, // 边的起始/终止箭头是否可以被移动
        vertexMovable: false, // 边的路径点是否可以被移动。
        vertexAddable: false, // 是否可以添加边的路径点。
胡菁 authored
77
        vertexDeletable: false, // 边的路径点是否可以被删除。
胡菁 authored
78
79
80
81
82
83
84
85
86
      },
      connecting: {
        snap: true, // 是否自动吸附
        allowMulti: true, // 是否允许在相同的起始节点和终止之间创建多条边
        allowNode: false, // 是否允许边链接到节点(非节点上的链接桩)
        allowBlank: false, // 是否允许连接到空白点
        allowLoop: false, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点,
        allowEdge: false, // 是否允许边链接到另一个边
        highlight: false, // 拖动边时,是否高亮显示所有可用的连接桩或节点
胡菁 authored
87
88
        connectionPoint: "anchor", // 指定连接点
        anchor: "center", // 指定被连接的节点的锚点
胡菁 authored
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        createEdge() {
          // X6 的 Shape 命名空间中内置 Edge、DoubleEdge、ShadowEdge 三种边
          return new Shape.DoubleEdge({
            attrs: {
              // line: {
              //   // stroke: '#5F95FF',
              //   // strokeWidth: 4,
              //   // targetMarker: {
              //   //   name: 'classic',
              //   //   size: 8,
              //   // },
              //   stroke: '#1890ff',
              //   strokeDasharray: 5,
              //   targetMarker: null,//block classic diamond cross async path circle circlePlus ellipse
              //   style: {
              //     animation: 'ant-line 30s infinite linear',
              //   },
              // },
              line: {
                strokeWidth: 4,
胡菁 authored
109
                stroke: "#cfe7f2",
胡菁 authored
110
111
                strokeDasharray: 0,
                style: {
胡菁 authored
112
                  animation: "ant-line 0s infinite linear",
胡菁 authored
113
                },
胡菁 authored
114
                targetMarker: null, // 去掉箭头
胡菁 authored
115
116
              },
              outline: {
胡菁 authored
117
118
119
                stroke: "#456d89",
                strokeWidth: 7,
              },
胡菁 authored
120
121
            },
            router: {
胡菁 authored
122
              name: "metro",
胡菁 authored
123
124
              args: {
                offset: 32,
胡菁 authored
125
126
127
128
                direction: "H",
              },
            },
          });
胡菁 authored
129
130
131
132
133
        },
        validateConnection({
          sourceView,
          targetView,
          sourceMagnet,
胡菁 authored
134
          targetMagnet,
胡菁 authored
135
136
        }) {
          if (sourceView === targetView) {
胡菁 authored
137
            return false;
胡菁 authored
138
139
          }
          if (!sourceMagnet) {
胡菁 authored
140
            return false;
胡菁 authored
141
142
          }
          if (!targetMagnet) {
胡菁 authored
143
            return false;
胡菁 authored
144
          }
胡菁 authored
145
146
          return true;
        },
胡菁 authored
147
148
149
      },
      highlighting: {
        magnetAvailable: {
胡菁 authored
150
          name: "stroke",
胡菁 authored
151
152
153
154
          args: {
            padding: 4,
            attrs: {
              strokeWidth: 4,
胡菁 authored
155
156
157
158
              stroke: "rgba(223,234,255)",
            },
          },
        },
胡菁 authored
159
160
161
      },
      // 开启拖拽平移(防止冲突,按下修饰键并点击鼠标才能触发画布拖拽)
      panning: {
胡菁 authored
162
        enabled: true,
胡菁 authored
163
164
165
166
167
168
169
170
171
        // modifiers: 'shift'
      },
      resizing: true,
      rotating: true,
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
胡菁 authored
172
        showNodeSelectionBox: true,
胡菁 authored
173
174
175
176
      },
      snapline: true,
      history: true,
      clipboard: {
胡菁 authored
177
        enabled: true,
胡菁 authored
178
179
      },
      keyboard: {
胡菁 authored
180
        enabled: true,
胡菁 authored
181
182
183
184
      },
      embedding: {
        enabled: true,
        findParent({ node }) {
胡菁 authored
185
          const bbox = node.getBBox();
胡菁 authored
186
187
          return this.getNodes().filter((node) => {
            // 只有 data.parent 为 true 的节点才是父节点
胡菁 authored
188
            const data = node.getData();
胡菁 authored
189
            if (data && data.parent) {
胡菁 authored
190
191
              const targetBBox = node.getBBox();
              return bbox.isIntersectWithRect(targetBBox);
胡菁 authored
192
            }
胡菁 authored
193
194
195
196
197
            return false;
          });
        },
      },
    });
胡菁 authored
198
199
    if (!flag) {
      // this.graph.centerContent()
胡菁 authored
200
201
      this.graph.hideGrid(); // 返显渲染的时候 隐藏网格
      return this.graph;
胡菁 authored
202
203
204
205
206
207
208
    }
    // this.initStencil()
    // this.initShape()
    // this.initGraphShape()
    // this.initEvent()
    // return this.graph
  }
胡菁 authored
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  //   // 初始化根节点
  //   static initStencil() {
  //     this.stencil = new Addon.Stencil({
  //       target: this.graph,
  //       stencilGraphWidth: 280,
  //       search: { rect: true },
  //       collapsable: true,
  //       groups: [
  //         {
  //           name: 'basic',
  //           title: '基础节点',
  //           graphHeight: 180
  //         },
  //         {
  //           name: 'custom-image',
  //           title: '系统设计图',
  //           graphHeight: 600
  //         }
  //         // {
  //         //   name: 'combination',
  //         //   title: '组合节点',
  //         //   layoutOptions: {
  //         //     columns: 1,
  //         //     marginX: 60,
  //         //   },
  //         //   graphHeight: 260,
  //         // },
  //         // {
  //         //   name: 'group',
  //         //   title: '节点组',
  //         //   graphHeight: 100,
  //         //   layoutOptions: {
  //         //     columns: 1,
  //         //     marginX: 60,
  //         //   },
  //         // },
  //       ]
  //     })
  //     const stencilContainer = document.querySelector('#stencil')
  //     stencilContainer?.appendChild(this.stencil.container)
  //   }
胡菁 authored
250
251
  // 初始化具体每个根节点下不同类型节点
  static initShape() {
胡菁 authored
252
    const { graph } = this;
胡菁 authored
253
254
    // 基础节点
    const r1 = graph.createNode({
胡菁 authored
255
      shape: "flow-chart-rect",
胡菁 authored
256
257
258
      attrs: {
        body: {
          rx: 24,
胡菁 authored
259
          ry: 24,
胡菁 authored
260
261
        },
        text: {
胡菁 authored
262
263
264
265
          text: "起始节点",
        },
      },
    });
胡菁 authored
266
    const r2 = graph.createNode({
胡菁 authored
267
      shape: "flow-chart-rect",
胡菁 authored
268
269
      attrs: {
        text: {
胡菁 authored
270
271
272
273
          text: "流程节点",
        },
      },
    });
胡菁 authored
274
    const r3 = graph.createNode({
胡菁 authored
275
      shape: "flow-chart-rect",
胡菁 authored
276
277
278
279
      width: 52,
      height: 52,
      angle: 45,
      attrs: {
胡菁 authored
280
        "edit-text": {
胡菁 authored
281
          style: {
胡菁 authored
282
283
            transform: "rotate(-45deg)",
          },
胡菁 authored
284
285
        },
        text: {
胡菁 authored
286
287
288
          text: "判断节点",
          transform: "rotate(-45deg)",
        },
胡菁 authored
289
290
291
292
293
      },
      ports: {
        groups: {
          top: {
            position: {
胡菁 authored
294
              name: "top",
胡菁 authored
295
              args: {
胡菁 authored
296
297
298
                dx: -26,
              },
            },
胡菁 authored
299
300
301
          },
          right: {
            position: {
胡菁 authored
302
              name: "right",
胡菁 authored
303
              args: {
胡菁 authored
304
305
306
                dy: -26,
              },
            },
胡菁 authored
307
308
309
          },
          bottom: {
            position: {
胡菁 authored
310
              name: "bottom",
胡菁 authored
311
              args: {
胡菁 authored
312
313
314
                dx: 26,
              },
            },
胡菁 authored
315
316
317
          },
          left: {
            position: {
胡菁 authored
318
              name: "left",
胡菁 authored
319
              args: {
胡菁 authored
320
321
322
323
324
325
326
                dy: 26,
              },
            },
          },
        },
      },
    });
胡菁 authored
327
    const r4 = graph.createNode({
胡菁 authored
328
      shape: "flow-chart-rect",
胡菁 authored
329
330
331
332
333
      width: 70,
      height: 70,
      attrs: {
        body: {
          rx: 35,
胡菁 authored
334
          ry: 35,
胡菁 authored
335
336
        },
        text: {
胡菁 authored
337
338
339
340
          text: "链接节点",
        },
      },
    });
胡菁 authored
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
    // // 组合节点
    // const c1 = graph.createNode({
    //   shape: 'flow-chart-image-rect'
    // })
    // const c2 = graph.createNode({
    //   shape: 'flow-chart-title-rect'
    // })
    // const c3 = graph.createNode({
    //   shape: 'flow-chart-animate-text'
    // })
    // // 节点组
    // const g1 = graph.createNode({
    //   shape: 'groupNode',
    //   attrs: {
    //     text: {
    //       text: 'Group Name'
    //     }
    //   },
    //   data: {
    //     parent: true
    //   }
    // })
胡菁 authored
363
364
365
    // 系统设计图
    const imgs = [
      {
胡菁 authored
366
        image: getImg("ldb.png"),
胡菁 authored
367
368
      },
      {
胡菁 authored
369
        image: getImg("wft1.png"),
胡菁 authored
370
371
      },
      {
胡菁 authored
372
        image: getImg("wft2.png"),
胡菁 authored
373
374
      },
      {
胡菁 authored
375
        image: getImg("wft3.png"),
胡菁 authored
376
377
      },
      {
胡菁 authored
378
        image: getImg("wft4.png"),
胡菁 authored
379
380
      },
      {
胡菁 authored
381
        image: getImg("wft5.png"),
胡菁 authored
382
383
      },
      {
胡菁 authored
384
        image: getImg("lqt.png"),
胡菁 authored
385
386
      },
      {
胡菁 authored
387
        image: getImg("lqb-o.png"),
胡菁 authored
388
389
      },
      {
胡菁 authored
390
        image: getImg("ldb-o.png"),
胡菁 authored
391
392
      },
      {
胡菁 authored
393
        image: getImg("bh.png"),
胡菁 authored
394
395
      },
      {
胡菁 authored
396
        image: getImg("f1.png"),
胡菁 authored
397
398
      },
      {
胡菁 authored
399
        image: getImg("f2.png"),
胡菁 authored
400
401
      },
      {
胡菁 authored
402
403
404
        image: getImg("f3.png"),
      },
    ];
胡菁 authored
405
    const imgNodes = imgs.map((item) => {
胡菁 authored
406
407
408
409
410
411
412
      return graph.createNode({
        // shape: 'flow-chart-image-rect-custom',
        // attrs: {
        //   image: {
        //     'xlink:href': item.image,
        //   }
        // }
胡菁 authored
413
        shape: "image", // 可选值:Rect Circle Ellipse Polygon Polyline Path Image HTML TextBlock BorderedImage EmbeddedImage InscribedImage Cylinder
胡菁 authored
414
415
416
417
        imageUrl: item.image,
        attrs: {
          image: {
            // fill: 'yellow',
胡菁 authored
418
          },
胡菁 authored
419
420
421
        },
        width: 52,
        height: 52,
胡菁 authored
422
423
424
425
426
        ports: { ...customPorts },
      });
    });
    this.stencil.load([r1, r2, r3, r4], "basic");
    this.stencil.load(imgNodes, "custom-image");
胡菁 authored
427
428
429
430
431
432
    // this.stencil.load([c1, c2, c3], 'combination')
    // this.stencil.load([g1], 'group')
  }

  // 根据json渲染节点和边
  static initGraphShape(gd = graphData) {
胡菁 authored
433
434
435
    console.log(gd);
    var data = null;
    data = gd;
胡菁 authored
436
    // setInterval(() => {
胡菁 authored
437
438
439
440
441
    console.log(data.cells[0].position.x);
    data.cells[0].position.x += 1;
    this.graph.fromJSON(data);
    const nodes = this.graph.getNodes();
    console.log(nodes);
胡菁 authored
442
443
444
445
446
447
448

    // }, 100);
  }

  // 连接桩显示时机
  static showPorts(ports, show) {
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
胡菁 authored
449
      ports[i].style.visibility = show ? "visible" : "hidden";
胡菁 authored
450
451
452
453
454
    }
  }

  // 事件相关
  static initEvent() {
胡菁 authored
455
456
    const { graph } = this;
    const container = document.getElementById("container");
胡菁 authored
457
    // 右键编辑文本
胡菁 authored
458
459
460
461
462
    graph.on("node:contextmenu", ({ cell, view }) => {
      console.log(view.container);
      const oldText = cell.attr("text/text");
      cell.attr("text/style/display", "none");
      const elem = view.container.querySelector(".x6-edit-text");
胡菁 authored
463
      if (elem) {
胡菁 authored
464
465
        elem.innerText = oldText;
        elem.focus();
胡菁 authored
466
467
      }
      const onBlur = () => {
胡菁 authored
468
469
470
        cell.attr("text/text", elem.innerText);
        cell.attr("text/style/display", "inline-block");
      };
胡菁 authored
471
      if (elem) {
胡菁 authored
472
473
474
475
        elem.addEventListener("blur", () => {
          onBlur();
          elem.removeEventListener("blur", onBlur);
        });
胡菁 authored
476
      }
胡菁 authored
477
    });
胡菁 authored
478
    // 鼠标移入 显示连接桩
胡菁 authored
479
    graph.on(
胡菁 authored
480
      "node:mouseenter",
胡菁 authored
481
      FunctionExt.debounce(() => {
胡菁 authored
482
483
        const ports = container.querySelectorAll(".x6-port-body");
        this.showPorts(ports, true);
胡菁 authored
484
485
      }),
      500
胡菁 authored
486
    );
胡菁 authored
487
    // 鼠标移出 隐藏连接桩
胡菁 authored
488
489
490
491
    graph.on("node:mouseleave", () => {
      const ports = container.querySelectorAll(".x6-port-body");
      this.showPorts(ports, false);
    });
胡菁 authored
492
胡菁 authored
493
494
495
496
497
    graph.on("node:collapse", ({ node, e }) => {
      e.stopPropagation();
      node.toggleCollapse();
      const collapsed = node.isCollapsed();
      const cells = node.getDescendants();
胡菁 authored
498
      cells.forEach((n) => {
胡菁 authored
499
        if (collapsed) {
胡菁 authored
500
          n.hide();
胡菁 authored
501
        } else {
胡菁 authored
502
          n.show();
胡菁 authored
503
        }
胡菁 authored
504
505
      });
    });
胡菁 authored
506
    // backspace
胡菁 authored
507
508
    graph.bindKey("delete", () => {
      const cells = graph.getSelectedCells();
胡菁 authored
509
      if (cells.length) {
胡菁 authored
510
        graph.removeCells(cells);
胡菁 authored
511
      }
胡菁 authored
512
    });
胡菁 authored
513
    // 鼠标动态添加/删除小工具。
胡菁 authored
514
    graph.on("edge:mouseenter", ({ cell }) => {
胡菁 authored
515
516
517
518
519
520
521
522
523
524
525
526
      /**
       * EdgeTool
       * vertices 路径点工具,在路径点位置渲染一个小圆点,拖动小圆点修改路径点位置,双击小圆点删除路径点,在边上单击添加路径点。
       * segments 线段工具。在边的每条线段的中心渲染一个工具条,可以拖动工具条调整线段两端的路径点的位置。
       * boundary 根据边的包围盒渲染一个包围边的矩形。注意,该工具仅仅渲染一个矩形,不带任何交互。
       * button 在指定位置处渲染一个按钮,支持自定义按钮的点击交互。
       * button-remove 在指定的位置处,渲染一个删除按钮,点击时删除对应的边。
       * source-arrowhead--target-arrowhead 在边的起点或终点渲染一个图形(默认是箭头),拖动该图形来修改边的起点或终点。
       * edge-editor 提供边上文本编辑功能。
       */
      cell.addTools([
        {
胡菁 authored
527
          name: "vertices",
胡菁 authored
528
          args: {
胡菁 authored
529
            attrs: { fill: "#007acc" },
胡菁 authored
530
531
532
533
534
535
536
537
538
            // 移动路径点过程中的吸附半径。当路径点与邻近的路径点的某个坐标 (x, y) 距离在半径范围内时,将当前路径点的对应坐标 (x, y) 吸附到邻居路径的路径点。
            snapRadius: 20,
            // 在边上按下鼠标时,是否可以添加新的路径点。
            addable: false,
            // 是否可以通过双击移除路径点。
            removable: false,
            // 是否自动移除冗余的路径点。
            removeRedundancies: false,
            // 是否阻止工具上的鼠标事件冒泡到边视图上。阻止后鼠标与工具交互时将不会触发边的 mousedown、mousemove 和 mouseup 事件。
胡菁 authored
539
540
541
542
543
544
545
546
            stopPropagation: false,
          },
        },
      ]);
    });
    graph.on("edge:mouseleave", ({ cell }) => {
      cell.removeTools();
    });
胡菁 authored
547
548
  }
}