关于前端:g6-核心概念

28次阅读

共计 7831 个字符,预计需要花费 20 分钟才能阅读完成。

      // 创立 G6 图实例
      const graph = new G6.Graph({
        container: 'mountNode', // 指定图画布的容器 id,与第 9 行的容器对应
        // 画布宽高
        width: 800,
        height: 500,
      });
      // 读取数据
      graph.data(data);
      // 渲染图
     graph.render();
    // 监听
    graph.on()

Graph 对象的生命周期为:初始化 —> 加载数据 —> 渲染 —> 更新 —> 销毁。

必要配置项

下面代码中实例化 Graph 的局部应用了三个必要的配置项:

  • container
  • widthheight

罕用配置项

应用 canvas 或 svg 渲染
  • renderer
自适应画布
  • fitView
  • fitViewPadding
  • fitCenter
全局元素配置
  • defaultNode
  • defaultEdge
  • nodeStateStyles
  • edgeStateStyles
布局相干
  • layout
交互行为相干
  • modes
动画相干
  • animate
  • animateCfg
插件
  • plugins

图形

每个图元素由图形(Shape)组成,且都会有本人的惟一要害图形(keyShape)。

图形 Shape

  • circle:圆;
  • rect:矩形;
  • ellipse:椭圆;
  • polygon:多边形;
  • fan:扇形;
  • image:图片;
  • marker:标记;
  • path:门路;
  • text:文本;
  • dom(svg):DOM

各图形 Shape 的通用办法

attr(name)

获取实例的属性值。

attr(name, value)

更新实例的单个绘图属性。

attr({…})

批量更新实例绘图属性。

KeyShape

代表元素的图形

group

  • addGroup(cfgs)
  • addShape(type, cfgs)

变换

  • 获取以后矩阵:getMatrix();
  • 设置矩阵:setMatrix(matrix) 或 attr(‘matrix’, matrix);
  • 重置矩阵:resetMatrix()。

图元素

图的元素(Item)蕴含图上的节点 Node、边 Edge 和 Combo 三大类。

  • 款式属性,通过 style 字段对象进行配置,和元素的要害图形相干,例如 fillstroke
  • 其余属性,例如 idtype,不能在元素状态扭转是进行扭转,可通过 graph.updateItem 进行手动更新。

节点

G6 的内置节点包含 circle,rect,ellipse,diamond,triangle,star,image,modelRect。这些内置节点的默认款式别离如下图所示。

定义形式


// 1  
defaultNode: {
    type: 'circle',
    // 其余配置
  }

//2
graph.node((node) => {
  return {
    id: node.id,
    type: 'rect',
    style: {fill: 'blue',},
  };
});

graph.data(data);
graph.render();

//3
const data = {
  nodes: [
    {
      id: 'node_circle',
      x: 100,
      y: 100,
      type: 'circle',
      label: 'circle',
    },]
}

自定义


G6.registerNode(
  'nodeName',
  {
    options: {style: {},
      stateStyles: {hover: {},
        selected: {},},
    },
    /**
     * 绘制节点,蕴含文本
     * @param  {Object} cfg 节点的配置项
     * @param  {G.Group} group 图形分组,节点中图形对象的容器
     * @return {G.Shape} 返回一个绘制的图形作为 keyShape,通过 node.get('keyShape') 能够获取。* 对于 keyShape 可参考文档 外围概念 - 节点 / 边 /Combo- 图形 Shape 与 keyShape
     */
    draw(cfg, group) {},
    /**
     * 绘制后的附加操作,默认没有任何操作
     * @param  {Object} cfg 节点的配置项
     * @param  {G.Group} group 图形分组,节点中图形对象的容器
     */
    afterDraw(cfg, group) {},
    /**
     * 更新节点,蕴含文本
     * @override
     * @param  {Object} cfg 节点的配置项
     * @param  {Node} node 节点
     */
    update(cfg, node) {},
    /**
     * 更新节点后的操作,个别同 afterDraw 配合应用
     * @override
     * @param  {Object} cfg 节点的配置项
     * @param  {Node} node 节点
     */
    afterUpdate(cfg, node) {},
    /**
     * 响应节点的状态变动。* 在须要应用动画来响应状态变动时须要被复写,其余款式的响应参见下文提及的 [配置状态款式] 文档
     * @param  {String} name 状态名称
     * @param  {Object} value 状态值
     * @param  {Node} node 节点
     */
    setState(name, value, node) {},
    /**
     * 获取锚点(相干边的连入点)* @param  {Object} cfg 节点的配置项
     * @return {Array|null} 锚点(相干边的连入点)的数组, 如果为 null,则没有控制点
     */
    getAnchorPoints(cfg) {},},
  // 继承内置节点类型的名字,例如基类 'single-node',或 'circle', 'rect' 等
  // 当不指定该参数则代表不继承任何内置节点类型
  extendedNodeName,
);

连贯形式


// 接入点
    anchorPoints: [[0, 1],
        [0.5, 1],
      ],

jsx 写法

<[group|shape] [key]="value" style={{[key]: value }}>
  <[more tag] /> ...
  <text>value</text>
</[group|shape]>

  • line:直线,不反对控制点;
  • polyline:折线,反对多个控制点;
  • arc:圆弧线;
  • quadratic:二阶贝塞尔曲线;
  • cubic:三阶贝塞尔曲线;
  • cubic-vertical:垂直方向的三阶贝塞尔曲线,不思考用户从内部传入的控制点;
  • cubic-horizontal:程度方向的三阶贝塞尔曲线,不思考用户从内部传入的控制点;
  • loop:自环。

定义形式: 与节点相似

箭头:

// 默认
style: {
  endArrow: true,
  startArrow: true
}
// 内置 6 种
endArrow: {
// 应用内置箭头门路函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)path: G6.Arrow.triangle(10, 20, 25),
d: 25
}
// 自定义箭头
// 只有内置箭头和自定义箭头能够配置款式
style: {
  endArrow: {
    path: 'M 0,0 L 20,10 L 20,-10 Z',
    d: 5,
    fill: '#f00',
    stroke: '#0f0',
    opacity: 0.5,
    lineWidth: 3,
    // ...
  },
}

自定义: 同节点

combo

G6 的内置 Combo 包含 circle 和 rect 两种类型

对于相熟图可视化类库的用户来说,节点分组是十分实用的一个性能

G6 曾经存在一个节点分组 Node Group 性能,但它的机制无奈反对一些较简单的性能,例如:带有节点分组的图布局、自定义 Combo、嵌套节点分组的平均 padding、节点与分组的边、分组与分组的边、空的节点分组等

{
  nodes: [
    {
      id: 'node1',
      comboId: 'comboA' // node1 属于 comboA
    },
    {
      id: 'node2',
      comboId: 'comboB' // node2 属于 comboB
    },
    {id: 'node3' // node3 不属于任何 combo},
    // ...
  ],
  edges: [// ...],
  combos: [
    { // 定义 comboA
      id: 'comboA',
      label: 'A',
      parentId: 'comboC'
    },
    { // 定义 comboB
      id: 'comboB',
      parentId: 'comboB'
    },
    { // 定义 comboC,这是一个空的 combo
      id: 'comboC'
    },
    // ...
  ]
}

其余内容: 相似与节点

高级款式

背景

 defaultNode: {
    position: 'left',
    style: {
      background: {
        fill: '#ffffff',
        stroke: 'green',
        padding: [3, 2, 3, 2],
        radius: 2,
        lineWidth: 3,
      },
    },

三种形式更新文本款式


// 1. 实例化默认
  defaultNode: {
    type: 'node',
    labelCfg: {
      style: {
        fill: '#fff',
        fontSize: 14,
      },
    },
  },
// 2. 数据指定
const data = {
  nodes: [
    {
      id: 'node1',
      label: 'node1',
      labelCfg: {
        style: {
          fill: '#fff',
          fontSize: 12,
        },
      },
    },
  ],
};
// 3.update/updateItem

graph.updateItem(node, {
  // 节点的款式
  style: {stroke: 'blue',},
  // 节点上文本的款式
  labelCfg: {
    style: {
      fill: '#fff',
      fontSize: 12,
    },
  },
});

渐变色 / 纹理

操作

更新款式

更新节点边: 三种形式

层级

所有节点会绘制在所有边的下层

先绘制图形在后绘制图形后边

toFront()toBack()

显示 / 暗藏

show()/hide()

多条边

自定义边 edgeType

锁定 / 解锁

lock()unlock()hasLocked()

不可拖动

不可缩放

图布局

个别布局

  • Random Layout:随机布局;
  • Force Layout:G6 4.0 反对的经典力导向布局,反对 GPU 并行计算;
  • Force Layout:援用 d3 的经典力导向布局;
  • Fruchterman Layout:Fruchterman 布局,一种力导布局;
  • Circular Layout:环形布局;
  • Radial Layout:辐射状布局;
  • MDS Layout:高维数据降维算法布局;
  • Dagre Layout:档次布局;
  • Concentric Layout:同心圆布局;
  • Grid Layout:网格布局;
  • Combo Force Layout:_V3.5 新增。_实用于带有 combo 图的力导向布局,举荐有 combo 的图应用该布局。

树图

  • CompactBox Layout:紧凑树布局;
  • Dendrogram Layout:树状布局(叶子节点布局对齐到同一层);
  • Indented Layout:缩进布局;
  • Mindmap Layout:脑图布局。

布局切换

  • updateLayout(params):布局办法或参数的切换;

graph.updateLayout({
          type: 'force', // 布局名称
          preventOverlap: true, // 布局参数,是否容许重叠
          nodeSize: 40, // 布局参数,节点大小,用于判断节点是否重叠
          linkDistance: 100, // 布局参数,边长
        });

*   `changeData()`:数据的切换。graph.changeData(data2);

子图

子图布局独立与全局布局的思路,与 graph 不挂钩,间接应用实例化布局办法的形式,灌入子图数据,通过布局将地位写到相应数据中。这种机制还可供内部的全局布局应用,即便不必 G6 渲染,也能够计算节点布局后的地位

// 实例化布局
const subgraphLayout = new G6.Layout['force']({center: [500, 450],
});

// 初始化布局,灌入子图数据
subgraphLayout.init({
  nodes: subGraphNodes,
  edges: subGraphEdges,
});

// 执行布局
subgraphLayout.execute();

// 图实例依据数据更新节点地位
graph.positionsAnimate();

webworker

在大规模图可视化中,布局算法往往须要较大的计算量。

workerEnabled: true, // 开启 Web-Worker
  • 树图不反对 Web-Worker 机制;
  • 子图布局机制暂不反对 Web-Worker 机制。
  • 应用会造成交互延时须要留神

自定义布局

  getDefaultCfg() {return {};
  },
  /**
   * 初始化
   * @param {object} data 数据
   */
  init(data) {},
  /**
   * 执行布局
   */
  execute() {},
  /**
   * 依据传入的数据进行布局
   * @param {object} data 数据
   */
  layout(data) {},
  /**
   * 更新布局配置,但不执行布局
   * @param {object} cfg 须要更新的配置项
   */
  updateCfg(cfg) {},
  /**
   * 销毁
   */
  destroy() {},
});

布局预测

import {GraphLayoutPredict} from '@antv/vis-predict-engine'

const {predictLayout, confidence} = await GraphLayoutPredict.predict(data);
const graph = new G6.Graph({
  // 省略其余配置
    layout: {type: predictLayout}
})

交互与事件

监听 / 绑定

  • 画布、图形档次的事件,mousedownmouseupclickmouseentermouseleave 等;
  • 节点 / 边 上的事件,node:mousedownedge:click 等,以 type:eventName 为事件名称;
  • 机会事件:

    • 节点 / 边增删改时的事件, 例如:beforeadditemafteradditem  等;
    • 节点 / 边状态扭转时的事件:beforerefreshitemafterrefreshitem
    • 布局机会:beforelayoutafterlayout
graph.on('click', (ev) => {
  const shape = ev.target;
  const item = ev.item;
  if (item) {const type = item.getType();
  }
});

graph.on('node:click', (ev) => {
  const shape = ev.target;
  const node = ev.item;
});

内置 behavior

ehavior 是 G6 提供的定义图上交互事件的机制。

G6 目前共提供了以下 14 个内置的 Behavior。

drag-combo
collapse-expand-combo
drag-canvas
zoom-canvas
drag-node
click-select
tooltip
edge-tooltip
activate-relations
brush-select
lasso-select
collapse-expand
create-edge
shortcuts-call

自定义交互 Behavior

在交互行为上,G6 次要思考了三个场景:

  • 展现关系数据;
  • 可视化建模;
  • 图剖析。

在这些场景中只有用户可能无奈一眼看清楚所有须要的信息,都须要进行交互,例如:

  • 图太大,须要缩放;
  • 单个节点上展现的信息太少,须要通过 tooltip 显示详情;
  • 对节点进行增删改查。
交互模式 Mode
  • default 模式中蕴含点击选中节点行为和拖拽画布行为;
  • edit 模式中蕴含点击节点弹出编辑框行为和拖拽节点行为。
modes: {
    // 反对的 behavior
    default: ['drag-canvas', 'zoom-canvas'],
    edit: ['click-select'],
  },

// 解绑目前图模式的所有事件监听;
// 生成新的 Behavior,进行事件初始化;
// 绑定新的行为对应的事件监听。
graph.setMode(‘edit’);

graph.addBehaviors
graph.removeBehaviors

状态 State

判断是否该应用 state 的准则很简略,从交互和业务两个层面来看:

  • 某个交互动作要扭转节点或边的款式及属性;
  • 出现给用户的内容会依据数据扭转(如 1 代表胜利,0 代表失败)。

满足上述条件其一,则应该应用 state。

在 G6 中,有两种形式配置不同状态的款式:

  • 在实例化 Graph 时,通过 nodeStateStylesedgeStateStyles 对象定义;
  • 在节点 / 边数据中,在 stateStyles 对象中定义状态;
  • 设置状态:setItemState
  • 勾销状态:clearItemStates
  • 更新状态:updateItem
graph.setItemState(item, stateName, stateValue) 

graph.clearItemStates(item, 'selected');
// 实例化
 nodeStateStyles: { },

// 数据
  stateStyles: { },

//updataItem
stateStyles: {
    // 批改 hover 状态下的款式
    hover: {
      opacity: 0.1,
      // 批改 name 为 'node-label' 的子图形 hover 状态下的款式
      'node-text': {stroke: 'blue',},
    },
  },

// 优先级
item.hasState('active');

插件 **

  • Grid
  • Minimap
  • ImageMinimap
  • Edge Bundling
  • Menu
  • ToolBar
  • TimeBar
  • Tooltip
  • Fisheye
  • EdgeFilterLens
// 实例化 Image Minimap 插件
const imageMinimap = new G6.ImageMinimap({
  width: 200,
  graphImg: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eD7nT6tmYgAAAAAAAAAAAABkARQnAQ'
});
const graph = new G6.Graph({
  //... 其余配置项
  plugins: [imageMinimap], // 配置 imageMinimap 插件
});

图算法

计算 nodes,edges x/y

动画

全局

// 全局
 animate: true, // Boolean,切换布局时是否应用动画适度,默认为 false
graph.updateLayout(cfg) 布局的变动
graph.changeData() 数据的变动 

元素

  • 节点上图形的动画
  • 减少带有动画的背景图形
  • 节点上局部图形的旋转动画
  • 圆点在沿着线静止
  • 虚线静止的成果
  • 线从无到有的成果
// 开始
 shape.animate((ratio) => {
          // 每一帧的操作,入参 ratio:这一帧的比例值(Number)。返回值:这一帧须要变动的参数集(Object)。// 先变大、再变小
          const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10;
          let radius = cfg.size;
          if (isNaN(radius)) radius = radius[0];
          // 返回这一帧须要变动的参数集,这里只蕴含了半径
          return {r: radius / 2 + diff,};
        },
        {
          // 动画反复
          repeat: true,
          duration: 3000,
          easing: 'easeCubic',
        },
      ); // 一次动画继续的时长为 3000,动画成果为 'easeCubic'
          
// 完结
shape.stopAnimate();
正文完
 0