资讯专栏INFORMATION COLUMN

G6的插件系统

Ilikewhite / 336人阅读

摘要:的插件系统做的相当完善可惜文档没有具体说到这里整理一下的插件插件大致分为四种类型行为可以理解为事件处理的插件就是和的样式同样是插件插件的布局之类这部分涉及的算法比较多插件就是自定义工具函数将其内置中这四种插件都有各自的写法以及但是文档中没有

G6的插件系统做的相当完善, 可惜文档没有具体说到. 这里整理一下g6的插件.

插件大致分为四种类型:

behaviour 行为, 可以理解为事件处理

node, edge的插件, 就是node和edge的样式, 同样是插件

layout插件, node的布局之类, 这部分涉及的算法比较多

Util插件, 就是自定义工具函数, 将其内置G6.Util中

这四种插件都有各自的写法以及api, 但是文档中没有提到, 这里简单介绍一下. 一下都以官方插件为例.

behaviour 行为
写完发现其实官方有这部分的文档: https://www.yuque.com/antv/g6/custom-interaction

请看下面代码, 这部分是注册一个右键拖动的行为:

// g6/plugins/behaviour.analysis/index.js
function panCanvas(graph, button = "left", panBlank = false) {
  let lastPoint;
  if (button === "right") {
    graph.behaviourOn("contextmenu", ev => {
      ev.domEvent.preventDefault();
    });
  }
  graph.behaviourOn("mousedown", ev => {
    if (button === "left" && ev.domEvent.button === 0 ||
    button === "right" && ev.domEvent.button === 2) {
      if (panBlank) {
        if (!ev.shape) {
          lastPoint = {
            x: ev.domX,
            y: ev.domY
          };
        }
      } else {
        lastPoint = {
          x: ev.domX,
          y: ev.domY
        };
      }
    }
  });


// 鼠标右键拖拽画布空白处平移画布交互
G6.registerBehaviour("rightPanBlank", graph => {
  panCanvas(graph, "right", true);
})

然后在实例化graph的时候在modes中引入:

new Graph({
  modes: {
    default: ["panCanvas"]
  }
})

其实到这里我们已经知道了, 只要是在一些内置事件中注册一下自定义事件再引入我们就可以称之为一个行为插件. 但是我们还需要再深入一点, 看到底是不是这样的.

// g6/src/mixin/mode.js
behaviourOn(type, fn) {
    const eventCache = this._eventCache;
    if (!eventCache[type]) {
      eventCache[type] = [];
    }
    eventCache[type].push(fn);
    this.on(type, fn);
},

照老虎画猫我们最终可以实现一个自己的行为插件:

// 未经过验证
function test(graph) {
 graph.behaviourOn("mousedown" () => alert(1) ) 
}


// 鼠标右键拖拽画布空白处平移画布交互
G6.registerBehaviour("test", graph => {
  test(graph);
})

new Graph({
  modes: {
    default: ["test"]
  }
})
node, edge的插件

关于node, edge的插件的插件其实官方文档上面的自定义形状和自定义边.

// g6/plugins/edge.polyline/index.js
G6.registerEdge("polyline", {
  offset: 10,
  getPath(item) {
    const points = item.getPoints();
    const source = item.getSource();
    const target = item.getTarget();
    return this.getPathByPoints(points, source, target);
  },
  getPathByPoints(points, source, target) {
    const polylinePoints = getPolylinePoints(points[0], points[points.length - 1], source, target, this.offset);
    // FIXME default
    return Util.pointsToPolygon(polylinePoints);
  }
});

G6.registerEdge("polyline-round", {
  borderRadius: 9,
  getPathByPoints(points, source, target) {
    const polylinePoints = simplifyPolyline(
      getPolylinePoints(points[0], points[points.length - 1], source, target, this.offset)
    );
    // FIXME default
    return getPathWithBorderRadiusByPolyline(polylinePoints, this.borderRadius);
  }
}, "polyline");

这部分那么多代码其实最重要的还是上面的部分, 注册一个自定义边, 直接引入就可以在shape中使用了, 具体就不展开了.
自定义边
自定义节点

layout插件

layout在初始化的时候即可以在 layout 字段中初始化也可以在plugins中.

const graph = new G6.Graph({
  container: "mountNode",
  layout: dagre
})

/* ---- */

const graph = new G6.Graph({
  container: "mountNode",
  plugins: [ dagre ]
})

原因在于写插件的时候同时也把布局注册为一个插件了:

// g6/plugins/layout.dagre/index.js
class Plugin {
  constructor(options) {
    this.options = options;
  }
  init() {
    const graph = this.graph;
    graph.on("beforeinit", () => {
      const layout = new Layout(this.options);
      graph.set("layout", layout);
    });
  }
}

G6.Plugins["layout.dagre"] = Plugin;

通过查看源码我们可以知道自定义布局的核心方法就是execute, 再具体一点就是我们需要在每个布局插件中都有execute方法:

// g6/plugins/layout.dagre/layout.js
// 执行布局
  execute() {
    const nodes = this.nodes;
    const edges = this.edges;
    const nodeMap = {};
    const g = new dagre.graphlib.Graph();
    const useEdgeControlPoint = this.useEdgeControlPoint;
    g.setGraph({
      rankdir: this.getValue("rankdir"),
      align: this.getValue("align"),
      nodesep: this.getValue("nodesep"),
      edgesep: this.getValue("edgesep"),
      ranksep: this.getValue("ranksep"),
      marginx: this.getValue("marginx"),
      marginy: this.getValue("marginy"),
      acyclicer: this.getValue("acyclicer"),
      ranker: this.getValue("ranker")
    });
    g.setDefaultEdgeLabel(function() { return {}; });
    nodes.forEach(node => {
      g.setNode(node.id, { width: node.width, height: node.height });
      nodeMap[node.id] = node;
    });
    edges.forEach(edge => {
      g.setEdge(edge.source, edge.target);
    });
    dagre.layout(g);
    g.nodes().forEach(v => {
      const node = g.node(v);
      nodeMap[v].x = node.x;
      nodeMap[v].y = node.y;
    });
    g.edges().forEach((e, i) => {
      const edge = g.edge(e);
      if (useEdgeControlPoint) {
        edges[i].controlPoints = edge.points.slice(1, edge.points.length - 1);
      }
    });
  }

上面是官方插件有向图的核心代码, 用到了dagre算法, 再简化一点其实可以理解为就是利用某种算法确定节点和边的位置.

最终执行布局的地方:

// g6/src/controller/layout.js
graph._executeLayout(processor, nodes, edges, groups)
Util插件

这类插件相对简单许多, 就是将函数内置到Util中. 最后直接在G6.Util中使用即可

比如一个生成模拟数据的:

// g6/plugins/util.randomData/index.js
const G6 = require("@antv/g6");
const Util = G6.Util;
const randomData = {
  // generate chain graph data
  createChainData(num) {
    const nodes = [];
    const edges = [];
    for (let index = 0; index < num; index++) {
      nodes.push({
        id: index
      });
    }
    nodes.forEach((node, index) => {
      const next = nodes[index + 1];
      if (next) {
        edges.push({
          source: node.id,
          target: next.id
        });
      }
    });
    return {
      nodes,
      edges
    };
  },
  // generate cyclic graph data
  createCyclicData(num) {
    const data = randomData.createChainData(num);
    const { nodes, edges } = data;
    const l = nodes.length;
    edges.push({
      source: data.nodes[l - 1].id,
      target: nodes[0].id
    });
    return data;
  },
  // generate num * num nodes without edges
  createNodesData(num) {
    const nodes = [];
    for (let index = 0; index < num * num; index++) {
      nodes.push({
        id: index
      });
    }
    return {
      nodes
    };
  }
};
Util.mix(Util, randomData);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99451.html

相关文章

  • G6 2.0 开源发布 -- 裂变·聚变

    摘要:从年月,立项至今,已经过去了年半的时间。期间获得过赞誉,也有吐槽,取得一定成就,也暴露过不少问题。这次,我们很高兴的告诉大家,今天除了开源,还会开放取得了阶段性成果的详见链接。与产品深度融合为了避免和成为工程师闭门造车的产物。 showImg(https://segmentfault.com/img/remote/1460000015199265?w=1500&h=756); G6 是...

    ThinkSNS 评论0 收藏0
  • 初见 g6 图表库

    摘要:准备好数据节点节点节点坐标节点坐标边节点,从哪里出发节点,到哪里结束初始化对象容器渲染位置,表示渲染到图表的中间位置画布高渲染数据这是渲染出来的效果。链接线会以元素为基准。绘制元素时,需要在初始化对象的时候,指定。 hello world // 1. 准备好数据 // node(节点) let nodes = [ { id: 1, // 节点 id ...

    LittleLiByte 评论0 收藏0
  • 腾讯云:轻量应用服务器免费升级配置活动,1核2G6M免费升配2核4G6M

    摘要:腾讯云轻量应用服务器免费升级配置活动开始中腾讯云的活动真的越来越良心了,前几天刚刚出了一个免费领取一年的核轻量应用服务器活动。腾讯云轻量应用服务器免费升级配置活动开始中!腾讯云的活动真的越来越良心了,前几天刚刚出了一个免费领取一年的2核4G轻量应用服务器活动。今天,腾讯云又出了一个轻量应用云服务器升级配置的活动,通过邀请五个好友进行助力,可以将1核2G6M免费升配2核4G6M,好友只需要点击...

    Shonim 评论0 收藏0
  • 腾讯云,免费升配活动,可将180元/3年1核2G6M云服务器免费升配至2核4G6M

    摘要:内存硬盘带宽月流量价格购买核元年链接核元年链接核元年链接核元年链接活动内容活动时间年月日年月日活动对象腾讯云官网已注册且完成实名认证的国内站用户均可参与协作者与子用户账号除外发起助力购买后,别忘记来这里发起你的助力活动。腾讯云轻量应用服务器周年庆免费升配活动开始,也就是周年感恩回馈活动,加量不加价再返场!1核2G6M免费升配2核4G6M,如何玩呢? 只要你购买了秒杀活动中的1核2G6M...

    joywek 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<