G6的插件系统

news/2025/6/19 17:45:56

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

插件大致分为四种类型:

  1. behaviour 行为, 可以理解为事件处理
  2. node, edge的插件, 就是node和edge的样式, 同样是插件
  3. layout插件, node的布局之类, 这部分涉及的算法比较多
  4. 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 defaultreturn 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 defaultreturn 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 datacreateChainData(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 datacreateCyclicData(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 edgescreateNodesData(num) {const nodes = [];for (let index = 0; index < num * num; index++) {nodes.push({id: index});}return {nodes};}
};
Util.mix(Util, randomData);

https://dhexx.cn/news/show-2612546.html

相关文章

四合一简化 WordPress 个人信息,更符合国人使用习惯

2019独角兽企业重金招聘Python工程师标准>>> 今天缙哥哥想增加个人信息字段&#xff0c;方便管理中医体质档案&#xff0c;可是发现默认情况下&#xff0c;WordPress 后台让用户可以在后台设置&#xff1a;姓&#xff0c;名&#xff0c;昵称&#xff0c;然后选择显示…

关于状态码401与403区别

401 表示用户没有权限(令牌,用户名,密码错误) 403 表示用户有权限 ,只是访问是被禁止的,(可以理解为,用户有权限,但是某些目录禁止访问)

【iOS沉思录】iOS中如何触发定时任务或延时任务?

iOS中如何触发定时任务或延时任务&#xff1f; 定时任务指的是周期性的调用某个方法&#xff0c;实现任务的反复执行&#xff0c;例如倒计时功能的实现&#xff1b;延时任务指的是等待一定时间后再执行某个任务&#xff0c;例如页面的延时跳转等。iOS中控制任务的延时或定时执…

nginx之自动日志切割--请注意这里不是脚本

之前安装 nginx 都是自己编译安装&#xff0c;然后打成 rpm 包。换了一个新公司之后&#xff0c;发现服务器的 nginx 都是 yum 安装的&#xff0c;这也没什么问题&#xff0c;业务量不大。之后我发现在 nginx 的日志存储目录下&#xff0c;日志都被切割了&#xff0c;这很正常&…

Cmake 编辑opencv dll 问题

https://blog.csdn.net/Kena_M/article/details/53978150 可按照上述进行编辑将source文件夹下转换&#xff0c;需要说明&#xff0c;可以自行看看opencv bin下是否有相应的dll 版本不同则不同&#xff0c;有的有很多dll 有的opencv_world340.dll可代替所有&#xff0c;如有相…

亚马逊AWS技术峰会在京召开,落地两年的答卷是否合格?

摘要&#xff1a; 在亚马逊发布的2018年二季度财报中&#xff0c;AWS继续成为财报的亮点&#xff0c;净销售额为61.05亿美元&#xff0c;比上年同期的41亿美元增长49%&#xff0c;增速持续维持在40%以上。尤其是利润率超过 25&#xff05;&#xff0c;远高于其核心零售业务的市…

mac下流程图画图工具Omnigraffle

发现mac下并没有visio画图工具,所以准备使用Omnigraffle工具来画图,

【iOS沉思录】iOS沙盒内存使用深入剖析

背景 沙盒存储是iOS数据持久化的一种方案&#xff0c;操作简单&#xff0c;可以将数据以NSData以及常用的NSDictionary和NSArray的组织方式&#xff08;通过plist文件创建文件对象&#xff09;在沙盒的Documents目录中读写更新以及删除。沙盒存储的缺点是更新比较低效&#xf…

Docker sonar本地搭建

1、数据库操作&#xff1a;进去数据库复制代码psql -U postgres -h 127.0.0.1 复制代码查看所有用户postgres# \du复制代码创建数据库CREATE DATABASE sonar复制代码创建角色CREATE ROLE sonar ALTER ROLE sonar WITH LOGIN;复制代码2、Docker构建sonar镜像&#xff08;SONA…

四周第五次课(4月17日)6.5 zip压缩工具 6.6 tar打包 6.7 打包并压缩

2019独角兽企业重金招聘Python工程师标准>>> 6.5 zip压缩工具 zip 1.txt.zip 1.txt //压缩文件zip -r 123.zip 123/ //压缩目录unzip 1.txt.zip //解压unzip 123.zip -d /root/456/ //解压文件&#xff0c;并指定解压到那个目录下不能查看压缩文件的内容&#…