Bootstrap

G6可视化编排自定义节点样式和自定义线条

先上图:

 自定义节点样式

 

 自定义边

在this.graph = new G6.Graph内的defaultEdge内引用自定义线条type:"hvh"

      defaultEdge: {
        type: 'hvh',
      },

    G6.registerEdge('hvh', {
      setState(name, value, item) {
        const group = item.getContainer();
        const shape = group.get('children')[0]; // 顺序根据 draw 时确定
        if (name === 'active') {
          if (value) {
            shape.attr('stroke', 'lightgrey');
          } else {
            shape.attr('stroke', 'darkgrey');
          }
        }
        if (name === 'selected') {
          if (value) {
            shape.attr('lineWidth', 4);
          } else {
            shape.attr('lineWidth', 3);
          }
        }
      },
      draw(cfg, group) {
        const startPoint = cfg.startPoint;
        const endPoint = cfg.endPoint;
        const Ydiff = endPoint.y - startPoint.y;
        const Xdiff = endPoint.x - startPoint.x;
        let path = [];
        //  根据节点之间的距离,调整线
        if ((Ydiff <= 30 && Ydiff > 0) || (Ydiff >= -30 && Ydiff < 0)) {
          path = [
            ['M', startPoint.x, startPoint.y],
            ['L', endPoint.x, endPoint.y],
          ];
        } else if (Xdiff >= 35 && Ydiff <= 0) {
          path = [
            ['M', startPoint.x, startPoint.y],
            ['L', startPoint.x + 10, startPoint.y],
            ['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 10, startPoint.y],
            ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y - 10],
            ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y + 10],
            ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y,],
            ['L', endPoint.x + (-15), endPoint.y],
            ['L', endPoint.x, endPoint.y],
          ]
        } else if (Xdiff >= 35 && Ydiff > 0) {
          path = [
            ['M', startPoint.x, startPoint.y],
            ['L', startPoint.x + 10, startPoint.y],
            ['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 10, startPoint.y],
            ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y + 10],
            ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y - 10],
            ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y,],
            ['L', endPoint.x + (-15), endPoint.y],
            ['L', endPoint.x, endPoint.y],
          ]
        } else if (Xdiff < 35 && Ydiff >= 0) {
          path = [
            ['M', startPoint.x, startPoint.y], // 起点
            ['L', startPoint.x + 13, startPoint.y],  // 第一个定拐点 x变化y不变
            ['Q', startPoint.x + 20, startPoint.y, startPoint.x + 20, startPoint.y + 7],
            ['L', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y - 12],
            ['Q', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y, startPoint.x + 10, endPoint.y / 3 + 2 / 3 * startPoint.y],
            ['L', endPoint.x / 3 + 2 / 3 * startPoint.x - 9, endPoint.y / 3 + 2 / 3 * startPoint.y], // 第2个拐点x 自由变化 三分之几处  y方向不变// 三分之一处
            ['L', endPoint.x + (-20), endPoint.y / 3 + 2 / 3 * startPoint.y],
            ['Q', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y, endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y + 10],
            ['L', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y + 10],
            ['L', endPoint.x + (-30), endPoint.y - 10],
            ['Q', endPoint.x + (-30), endPoint.y, endPoint.x + (-20), endPoint.y],
            ['L', endPoint.x + (-20), endPoint.y],
            ['L', endPoint.x, endPoint.y]
          ]
        } else if (Xdiff < 35 && Ydiff < 0) {
          path = [
            ['M', startPoint.x, startPoint.y], // 起点
            ['L', startPoint.x + 13, startPoint.y],  // 第一个定拐点 x变化y不变
            ['Q', startPoint.x + 20, startPoint.y, startPoint.x + 20, startPoint.y - 7],
            ['L', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y + 12],
            ['Q', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y, startPoint.x + 10, endPoint.y / 3 + 2 / 3 * startPoint.y],
            ['L', endPoint.x / 3 + 2 / 3 * startPoint.x + 9, endPoint.y / 3 + 2 / 3 * startPoint.y], // 第2个拐点x 自由变化 三分之几处  y方向不变// 三分之一处
            ['L', endPoint.x + (-25), endPoint.y / 3 + 2 / 3 * startPoint.y],
            ['Q', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y, endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y - 10],
            ['L', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y - 10],
            ['L', endPoint.x + (-30), endPoint.y + 10],
            ['Q', endPoint.x + (-30), endPoint.y, endPoint.x + (-20), endPoint.y],
            ['L', endPoint.x + (-20), endPoint.y],
            ['L', endPoint.x, endPoint.y]
          ]
        }
        const shape = group.addShape('path', {
          attrs: {
            path,
            endArrow: {
              path: 'M 0,0 L 12,6 L 9,0 L 12,-6 Z',
              fill: 'darkgrey',
            },
            shadowColor: 'darkgreygrey',
            shadowBlur: 10,
            shadowOffsetY: 5,
            shadowOffsetX: 5,
            lineAppendWidth: 10,
            lineWidth: 3,
            stroke: 'darkgrey',
            lineJoin: 'round'
          }
        });
        return shape;
      }
    });

线条可拖拽

  modes: {
        default: [{
          type: 'drag-node',
          //  updateEdge: true,
          //  shouldUpdate: (e) => {
          //    return true
          //  }
        }, 'drag-canvas', 'drag-add-edge',
        {
          type: 'zoom-canvas',
          sensitivity: 2.5,
        },],
      },
    G6.registerBehavior('drag-add-edge', {
      getEvents() {
        return {
          'node:mousedown': 'onNodeMousedown',
          'node:mouseup': 'onNodeMouseup',
          'edge:mouseup': 'onEdgeMouseup',
          "mousemove": 'onMousemove',
        };
      },
      onNodeMousedown(event) {
        const self = this;
        // 交互过程中的信息
        self.evtInfo = {
          action: null,
          node: event.item,
          target: event.target
        };
        if (self.evtInfo.target && self.evtInfo.target.attrs.fill) {
          if (self.evtInfo.target.attrs.fill === '#72CC4A') {
            self.evtInfo.action = 'drawEdge';
          }
        }
        if (self.evtInfo && self.evtInfo.action) {
          self[self.evtInfo.action].start.call(self, event);
        }
      },
      onNodeMouseup(event) {
        const self = this;
        if (self.evtInfo && self.evtInfo.action) {
          self[self.evtInfo.action].stop.call(self, event);
        }
      },
      onEdgeMouseup(event) {
        const self = this;
        if (self.evtInfo && self.evtInfo.action === 'drawEdge') {
          self[self.evtInfo.action].stop.call(self, event);
        }
      },
      onMousemove(event) {
        const self = this;
        if (self.evtInfo && self.evtInfo.action) {
          self[self.evtInfo.action].move.call(self, event);
        }
      },
      drawEdge: {
        graph: this.graph,
        isMoving: false,
        currentLine: null,
        start(event) {
          const self = this;
          // 处理线条目标点
          if (self.evtInfo.node.getAnchorPoints() && self.evtInfo.node.getAnchorPoints().length) {
            // 获取距离指定坐标最近的一个锚点
            const sourceAnchor = self.evtInfo.node.getLinkPoint({
              x: event.x,
              y: event.y
            });
            self.drawEdge.currentLine = self.graph.addItem('edge', {
              // 起始节点
              source: self.evtInfo.node.getModel().id,
              sourceAnchor: sourceAnchor ? sourceAnchor.anchorIndex : '',
              // 终止节点/位置
              target: {
                x: event.x,
                y: event.y
              },
              type: 'hvh',
            });
            self.drawEdge.isMoving = true;
          }
        },
        move(event) {
          const self = this;
          if (self.drawEdge.isMoving && self.drawEdge.currentLine) {
            self.graph.updateItem(self.drawEdge.currentLine, {
              target: {
                x: event.x,
                y: event.y
              }
            });
          }
        },
        stop(event) {
          const self = this;
          if (self.drawEdge.isMoving) {
            if (self.drawEdge.currentLine === event.item) {
              // 画线过程中点击则移除当前画线
              self.graph.removeItem(event.item);
            }
            else if (event.item._cfg.model.label === '起点') {
              self.graph.removeItem(self.drawEdge.currentLine);
            } else {
              const targetNode = event.item;
              let targetAnchor = null;
              // 锚点数据
              // 处理线条目标点
              if (targetNode.getAnchorPoints() && targetNode.getAnchorPoints().length) {
                // 获取距离指定坐标最近的一个锚点
                targetAnchor = targetNode.getLinkPoint({ x: event.x, y: event.y });
              }
              self.graph.updateItem(self.drawEdge.currentLine, {
                target: targetNode.getModel().id,
                targetAnchor: targetAnchor ? targetAnchor.anchorIndex : ''
              });
            }
            // const { detectAllCycles } = Algorithm;
            // if (detectDirectedCycle(this.graph)) {
            //   self.graph.removeItem(self.drawEdge.currentLine);
            // }
          }
          self.drawEdge.currentLine = null;
          self.drawEdge.isMoving = false;
          self.evtInfo = null;
        }
      }
    }
    );

自定义节点样式

    G6.registerNode('rectNode', {
      draw: (cfg, group,) => {
        const color = cfg.error ? '#5B8FF9' : '#9EC9FF';
        const r = 2;
        //最外面的那层
        const shape = group.addShape('rect', {
          draggable: true,
          attrs: {
            x: 0,
            y: 0,
            width: 250,
            height: 90,
            stroke: color,
            radius: r,
          },
          name: 'main-box',
        });
        /* 右边边的小圆点 */
        group.addShape('circle', {
          attrs: {
            x: 252,
            y: 90 / 2,
            r: 4,
            fill: "#72CC4A",
          },
          name: 'left-dot-shape',
        });
        /* 左边的小圆点 */
        group.addShape('circle', {
          attrs: {
            x: 0,
            y: 90 / 2,
            r: 4,
            fill: "#72CC4A",
          },
          name: 'left-dot-shape',
        });
        //里面的那层
        group.addShape('rect', {
          draggable: true,
          attrs: {
            x: 0,
            y: 0,
            width: 250,
            height: 30,
            fill: color,
            radius: [r, r, 0, 0],
          },
          name: 'title-box',
        });
        group.addShape('rect', {
          draggable: true,
          attrs: {
            x: 0,
            y: 30,
            width: 250,
            height: 60,
            fill: '#fff',
            radius: [r, r, 0, 0],
          },
          name: 'title-box',
        });
        // title text
        group.addShape('text', {
          attrs: {
            textBaseline: 'top',
            y: 5,
            x: 30,
            lineHeight: 50,
            text: "[用例]:" + cfg.label,
            fill: '#fff',
          },
          name: 'title',
        });
        cfg.panels.forEach((item, index) => {
          // name text
          group.addShape('text', {
            attrs: {
              textBaseline: 'top',
              y: 40,
              x: 24 + index * 140,
              lineHeight: 30,
              text: item.title,
              fill: 'rgba(0,0,0, 0.4)',
            },
            name: `index-title-${index}`,
          });

          // value text
          group.addShape('text', {
            attrs: {
              textBaseline: 'top',
              y: 60,
              x: 24 + index * 140,
              lineHeight: 30,
              text: item.value,
              fill: '#595959',
            },
            name: `index-title-${index}`,
          });
        });
        return shape;
      },
    });

;