手摸手使用G6实现(轻)图编辑应用系列-自定义边、箭头

2,525 阅读3分钟

我正在参加「掘金·启航计划」

系列文章:

前言

上一节,自定义了节点,接下来通过自定义边、箭头来实现效果

边分析

  • 整个拓扑中边涉及自环、直线、曲线
  • 边样式以及文字样式
  • 鼠标移入边,显示边背景的交互(由于上一节自定义节点没有涉及更新操作,通过此功能介绍一下)
  • 鼠标移入节点,边样式也会有所变化

边实现

由于边的背景需要额外添加,所以需要继承内置边进行扩展自定义边;涉及自环、直线、曲线,需要自定义三个内置边,接下来拿直线作为例子

G6.registerEdge('customLine', {}, 'line',);

afterDraw 方法

  • 实现思路
    • 内置边默认边的关键图形name都为edge-shape
    • 得到关键图形的shape,进而获取其样式属性
    • 使用关键图形的样式属性作为 path 的属性,加一个层级低的shape
  • 代码实现
afterDraw(cfg, group){
    const keyShape = group.find(item => item.get('name') === 'edge-shape');
    const style = keyShape.attr();
    const path = group.addShape('path',{
      attrs:{
        ...style,
        lineWidth: 10,
        stroke: '#a23ade',
        opacity: 0.8,
        endArrow: false,
        startArrow: false
      },
      zIndex: -1,
      name: 'edge-bk-shape'
    })
    path.hide();
    group.sort();
};

afterUpdate 方法

  • 实现思路
    • 由于拖动节点时,会触发update方法,边的path会变化,需要同步处理边背景保持同步变化,否则边背景一直都在初始化时边的位置
  • 代码实现
afterUpdate(cfg, node){
    const group = node.getContainer();
    const keyShape = group.find(item => item.get('name') === 'edge-shape');
    const edgeBk = group.find(item => item.get('name') === 'edge-bk-shape');
    edgeBk.attr('path', keyShape.attr('path'));
};

setState 方法

  • 实现思路

    • 通过graph.setItemState给边设置不同状态值,针对状态值做出相应效果
    • 大概就是通过获取图形分组,根据设置的图形name找到指定图形,改变属性值
  • 代码实现

setState = (name, value, item) => {
    const group = item.getContainer();
    if(name === 'activeEdge'){
        const shape = group.find(child=> child.get('name') === 'edge-bk-shape')
        if(value){
            shape.show();
        }else{
            shape.hide();
        }
     }
    if (name === 'active') {
        const shape = group.find(child=> child.get('name') === 'edge-shape')
        if (value) {
            shape.attr(Object.assign(this.getArrowStyle(edgeModel, value), styleObj.activeLine));
        } else {
            shape.attr(Object.assign(this.getArrowStyle(edgeModel, value), styleObj.inactiveLine));
        }
};

边以及文字样式

  • 通过默认边配置列举常用样式配置
defaultEdge: {
    type: 'customLine',
    style: {
      // 边箭头
      startArrow: false,
      endArrow: true,
      // 边样式
      stroke: '#A3A5A9',
      lineWidth: 1,
      cursor: 'pointer',
      lineDash: undefined,
    },
    // 边上文本配置
    labelCfg: {
      // autoRotate: true, // 文本根据边方向旋转
      style:{
        // textAlign: 'center',
        // textBaseline: 'center',
        fill: '#606266',
        fontSize: 10,
        fontWeight: 300,
        fontFamily: '',
        cursor: 'pointer',
        background: {
          //文字背景
          fill: '#FFFFFF',
          stroke: '#E6E8EC',
          padding: [4, 2, 2, 2],
        },
      }
    },
  },

箭头分析

箭头样式与默认G6箭头不同,需要自定义实现

箭头实现

  • G6内有默认箭头、内置箭头、自定义箭头
    • 默认箭头
    • 内置箭头
      • 官方封装的工具方法,支持宽度、长度、偏移量入参,最终转换为path路径
    • 自定义箭头
      • 通过 path 进行绘制箭头路径
      • 绘制箭头的坐标系和自定义节点时的坐标一致
      • 例子
        defaultEdge: {
          style: {
            endArrow: {
              // 自定义箭头指向(0, 0),尾部朝向 x 轴正方向的 path
              path: 'M 0,0 L 20,10 L 20,-10 Z',
              // 箭头的偏移量,正值代表向 x 轴负方向移动,如下图
              // d: 10,
            },
          },
        },
      

customArrow.png

  • 代码实现
defaultEdge: {
    style: {
      // 边箭头
      startArrow: false,
      endArrow: {
          /// 使用内置箭头实现
          path: G6.Arrow.vee(6, 10, 0),
          d: 0
      }
    },
  },

结尾

截至到此,自定义边、箭头实现完成,下一节会介绍实现自定义行为的步骤

希望看完的朋友可以点个喜欢/关注,您的支持是对我最大的鼓励