1 Star 0 Fork 3

daning / antv-x6-learn

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

AntV X6 技术分享

[TOC]

一、本文目的

对 AntV x6 知识点的一个总结,也为其他开发同学提供一个说明文档。

二、知识要点

1、简介

X6 是 AntV 旗下的图编辑引擎,提供了一系列开箱即用的交互组件和简单易用的节点定制能力,方便我们快速搭建流程图、DAG 图、ER 图等图应用。

2、安装

npm i @antv/x6 -S

yarn add @antv/6

3、实例代码

import { Graph } from '@antv/x6';

const graph = new Graph({
  container: document.getElementById('container'),
  width: 800,
  height: 600,
});

4、画布 Graph

在 X6 中,Graph 是图的载体,它包含了图上的所有元素(节点、边等),同时挂载了图的相关操作(如交互监听、元素操作、渲染等)。

a. 常用的方法:
graph.dispose() // 销毁画布
graph.centerContent() //内容居中,画布内容中心与视口中心对齐
graph.zoom() // 获取缩放级别
graph.zoom(0.2) // 在原来缩放级别上增加 0.2
graph.zoom(-0.2) // 在原来缩放级别上减少 0.2
graph.getCells() // 返回画布中所有节点和边
graph.getNodes() // 返回画布中所有节点
graph.getEdges() // 返回画布中所有边
graph.toJSON() // 导出图中的节点和边
graph.fromJSON() // 反序列化 按照指定的 JSON 数据渲染节点和边。
graph.clearCells() // 清空画布
graph.resetCells() // 清空画布并添加用指定的节点/边
graph.getCellById() 根据节点/边的 ID 获取节点/边。
b. 画布反序列化
const data = {
  // 节点
  nodes: [
    {
      id: 'node1',
      x: 40,
      y: 40,
      width: 80,
      height: 40,
      label: 'Hello'
    },
    {
      id: 'node2',
      x: 160,
      y: 180,
      width: 80,
      height: 40,
      label: 'World'
    }
  ],
  // 边
  edges: [
    {
      source: 'node1',
      target: 'node2'
    }
  ]
  }

  graph.fromJSON(data)

5、节点 Node

Node 是所有节点的基类,继承自 Cell,并定义了节点的通用属性和方法。

a. 常用方法:
node.isNode() // 判断是不是节点
node.getBBox() // 获取节点的包围盒
node.size() // 获取节点大小
node.resize() // 改变节点大小
node.scale() // 缩放节点
node.position() // 获取节点位置
node.position(30, 30) // 设置节点位置
b. 创建内置节点
// 方式一:构造函数
import { Shape } from '@antv/x6'

// 创建节点
const rect = new Shape.Rect({
  x: 100,
  y: 200,
  width: 80,
  height: 40,
  angle: 30,
  attrs: {
    body: {
      fill: 'blue',
    },
    label: {
      text: 'Hello',
      fill: 'white',
    },
  },
})
graph.addNode(rect)


// 方式二:graph.addNode
const rect = graph.addNode({
  shape: 'rect', // 指定使用何种图形,默认值为 'rect'
  x: 100,
  y: 200,
  width: 80,
  height: 40,
  angle: 30,
  attrs: {
    body: {
      fill: 'blue',
    },
    label: {
      text: 'Hello',
      fill: 'white',
    },
  },
})

// 方式三:graph.createNode
const node = graph.createNode({
  width: 75,
  height: 38,
  shape: 'html',
  attrs: {
    label: {
      text: '开始', // 文本
      style: {
        visibility: 'hidden'
      }
    }
  },
  ports: {
    groups,
    items: startGroupItems
  },
  type: 'start',
  nodeDescription: '开始节点描述',
  html: 'start-html',
  ...startNodeSetting
});
this.dnd.start(node, e);
c. 注册自定义 HTML 节点
  registerHTMLComponent() {
    const startHtml = `
        <div class="custom-node-wrap">
          <div class="custom-node start-node">
            <svg class="icon" aria-hidden="true" class="custom-node-body-img">
              <use xlink:href="#iconkaishi"></use>
            </svg>
            <div class="text">开始</div>
          </div>
        </div>
        `;
    const approvalHtml = `
        <div class="custom-node-wrap">
          <div class="custom-node approval-node">
            <div class="custom-node-header approval-node-header">
              <div class="custom-node-header-name approval-node-name">审批节点</div>
              <i class="custom-node-header-icon iconfont iconshenpi"></i>
            </div>
            <div class="custom-node-body">
              <img class="custom-node-body-img" src="/static/images/avatar.png"/>
            </div>
        </div>
        `;
    const aggregationHtml = `
        <div class="custom-node-wrap">
          <div class="custom-node aggregation-node">
            <div class="custom-node-body aggregation-node-body">
            <div class="custom-node-body-user aggregation-node-name">聚合节点</div>
            <svg class="icon" aria-hidden="true" class="custom-node-body-img">
              <use xlink:href="#iconjuhejiedian"></use>
            </svg>
            </div>
          </div>
        </div>
        `;
    const endHtml = `
        <div class="custom-node-wrap">
          <div class="custom-node end-node">
            <svg class="icon" aria-hidden="true" class="custom-node-body-img">
              <use xlink:href="#iconjieshu"></use>
            </svg>
            <div class="text">结束</div>
          </div>
        </div>
        `;
    const branchHtml = `
            <div class="branch-node-wrap">
             <div class="branch-node">
               <svg fill="#fff" width="110" height="54" version="1.1" xmlns="http://www.w3.org/2000/svg">
                 <polygon points="0,27 55,0 110,27 55,54"/>
                 <g>
                   <path d="M110,27 L55,54 Z" stroke="rgba(0, 0, 0, 0.1)" stroke-width="2" transform="translate(0, -1)"></path>
                   <path d="M55,54 L0,27 Z" stroke="rgba(0, 0, 0, 0.1)" stroke-width="2" transform="translate(0, -1)"></path>
                 </g>
                 <use width="18px" height="18px" x="30" y="18" xlink:href="#iconfenzhijiedian-yuanxing"></use>
               </svg>
             </div>
            </div>
        `;
    Graph.registerHTMLComponent('start-html', startHtml, true);
    Graph.registerHTMLComponent('approval-html', approvalHtml, true);
    Graph.registerHTMLComponent('aggregation-html', aggregationHtml, true);
    Graph.registerHTMLComponent('end-html', endHtml, true);
    Graph.registerHTMLComponent('branch-html', branchHtml, true);
  }
d. 渲染 Vue 节点
npm install @antv/x6-vue-shape
在 vue2 下还需要安装 @vue/composition-api

import { Graph } from '@antv/x6'
import '@antv/x6-vue-shape'
import ServiceNode from './service-node.vue'

Graph.registerVueComponent(
  'service-node',
  {
    template: '<service-node></service-node>',
    components: {
      ServiceNode
    }
  },
  true
)

const graph = new Graph({
  container: document.getElementById('graph')
})

const node1 = graph.addNode({
  shape: "vue-shape",
  x: 300,
  y: 250,
  component: "service-node"
});

const node2 = graph.addNode({
  shape: "vue-shape",
  x: 300,
  y: 550,
  component: "service-node"
});

graph.addEdge({
  source: node1,
  target: node2,
  vertices: [
    { x: 300, y: 250 },
    { x: 300, y: 550 }
  ]
});

6、边 Edge

Edge 是边的基类,继承自 Cell,并定义了边的通用属性和方法。

a. 连接到画布上的点
const edge = new Shape.Edge({
  source: { x: 40, y: 40 },
  target: { x: 180, y: 80 },
})
b. 连接到节点/边
const edge = new Shape.Edge({
  source: { cell: 'source-cell-id' },
  target: { cell: 'target-cell-id' },
})
c. 连接到节点上的链接桩
const edge = new Shape.Edge({
  source: { cell: 'source-cell-id', port: 'port-id' },
  target: { cell: 'target-cell-id', port: 'port-id' },
})
d. 连接到节点上的某个元素
const edge = new Shape.Edge({
  source: { cell: 'source-cell-id', selector: 'some-selector' },
  target: { cell: 'target-cell-id', selector: 'some-selector' },
})
e. 自定义边:
import { Shape } from '@antv/x6';

export class TreeEdge extends Shape.Edge {
// ...
}
TreeEdge.config({
  zIndex: 1
});

Edge.registry.register('tree-edge', TreeEdge, true);
f. 常用的方法有
edge.isEdge() // 判断是不是边
edge.getBBox() // 返回边的包围盒
edge.getSource() // 获取边的起始节点/起始点信息
edge.getTarget() // 获取边的终止节点/终止点信息
g. 箭头
// 内置箭头:https://x6.antv.vision/zh/docs/tutorial/intermediate/marker#%E5%86%85%E7%BD%AE%E7%AE%AD%E5%A4%B4

const markers = [
  ['block', { size: 6 }],
  ['classic', { size: 6 }],
  ['diamond', { size: 8 }],
  ['circle', { size: 6 }],
  ['circlePlus', { size: 6 }],
  ['ellipse', { rx: 6, ry: 4 }],
  ['cross', { size: 8, offset: 1 }],
  ['async', { size: 8, offset: 1 }],
]

markers.forEach(([marker, args], i) => {
  graph.addEdge({
    sourcePoint: [220, 30 + i * 40],
    targetPoint: [500, 30 + i * 40],
    label: marker,
    attrs: {
      line: {
        sourceMarker: {
          args,
          name: marker,
        },
        targetMarker: {
          args,
          name: marker,
        },
        strokeWidth: 1,
      },
    },
  })
})

7、基类 cell

Cell 是 NodeEdge 的基类,包含节点和边的通用属性和方法定义,如属性样式、可见性、业务数据等,并且在实例化、样式定制、默认选项、自定义选项等方面具有相同的行为。

a. 常用的方法有:
cell.isNode() // 监测是否是Node实例
cell.isEdge() // 监测是否是Edge实例
cell.attr() // 获取全部属性值
cell.attr('body/fill')  // 获取某一属性值
cell.attr('body/fill', '#f5f5f5') // 设置某一属性值
cell.getProp().type // 获取指定的属性值。
cell.setProp('name', val); // 设置属性
cell.removeProp('zIndex'); // 删除单个属性

8、辅助工具

a. 自定义 tooltip 弹框
import { ToolsView, Graph } from '@antv/x6';
import insertCss from 'insert-css';

insertCss(`
  .inner-box {
    box-sizing: border-box;
    width: 590px;
    z-index: 2;
    max-height: 175px;
    padding: 20px;
    color: rgba(255, 255, 255, 65);
    background-color: rgba(36, 40, 52, 1);
    box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.5);
    border: 1px solid rgba(255, 255, 255, 0.2);
    position: absolute;
    display: none;
  }
  .inner-box::before {
    width: 0;
    height: 0;
    content: '';
    border-left: 7px solid transparent;
    border-right: 7px solid transparent;
    border-bottom: 10px solid rgba(255, 255, 255, 0.2);
    position: absolute;
    top: -10px;
    left: 49px;
  }
  .inner-box::after {
    width: 0;
    height: 0;
    content: '';
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-bottom: 8px solid rgba(36, 40, 52, 1);
    position: absolute;
    top: -8px;
    left: 50px;
  }
  .inner-box-main-title {
    font-size: 18px;
    font-weight: 600;
    color: rgba(65, 133, 255, 100);
  }
  .inner-box-main-text {
    font-size: 12px;
    line-height: 20px;
  }
`);

export class TooltipTool extends ToolsView.ToolItem {
  render() {
    const dom = `
    <div class="inner-box-main">
      <div class="inner-box-main-title"></div>
      <p class="inner-box-main-text"></p>
    </div>
    `;

    this.knob = ToolsView.createElement('div', false);
    this.knob.setAttribute('class', 'inner-box');
    this.knob.innerHTML = dom;
    this.container.appendChild(this.knob);
    this.updatePosition();

    return this;
  }

  updatePosition() {
    const cell = this.cell;
    const { position, name, description } = cell.getProp();

    if (description && name) {
      const style = this.knob.style;
      style.display = 'block';
      style.left = `${position.x}px`;
      style.top = `${position.y + 70}px`;

      this.knob.querySelector('.inner-box-main-title').innerHTML = name;
      this.knob.querySelector('.inner-box-main-text').innerHTML = description;
    }
  }
}

TooltipTool.config({
  tagName: 'div',
  isSVGElement: false
});

Graph.registerNodeTool('tooltip', TooltipTool, true);


// 页面实例化
new TooltipTool()
cell.addTools([{ name: 'tooltip' }]); // 添加tooltip
cell.removeTools(); // 删除tooltip

三、参考阅读

官网
github
国内镜像
布局

空文件

简介

antv-x6学习总结 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/nyhxiaoning/antv-x6-learn.git
git@gitee.com:nyhxiaoning/antv-x6-learn.git
nyhxiaoning
antv-x6-learn
antv-x6-learn
master

搜索帮助