X6 学习

1,004 阅读11分钟

选择X6还是G6

在技术选型的时候遇到X6和G6都可以做流程图。 大家可以看下www.zhihu.com/question/43… 大佬们的回答

总结下来就是,偏交互和编辑就X6 偏展示,图大就G6

什么是X6

X6官网

X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和开箱即用的内置扩展,方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。

思维导图

image.png

SVG基本知识

svg 掘金

SVG 是 Scalable Vector Graphics 的缩写,意为可缩放矢量图形,改变大小不会有png图片模糊的问题。

底层用的svg所以很多自定义的图形之类的可以直接使用svg来进行绘制。

  1. 语法
<svg>
    <circle cx="100" cy="100" r="50"/>
</svg>
  1. 基本图形
    • 圆形 (circle)
    • 矩形(rect)
    • 椭圆 (ellipse)
    • 线条(line)
    • 折线 (polyline)
    • 多边形(polygon)
    • 路径 (path)
    • 文本(text)

应用场景

image.png

优点和缺点

优点

  • 🌱 极易定制:支持使用 SVG/HTML/React/Vue 定制节点样式和交互;
  • 🚀 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等;
  • 🧲 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑;
  • 💯 事件驱动:可以监听图表内发生的任何事件。

缺点

  • 学习曲线较陡:如果你对 JavaScript 或图表绘制库没有经验,学习和使用 antv X6 可能需要一些时间和精力。它使用了一些复杂的概念和术语,并有自己的一套 API,需要花些时间来理解和适应。
  • 文档和示例不够丰富:尽管 antv X6 有一份官方文档和示例,但在某些方面可能仍然缺乏详细和全面的解释。这可能会给新用户带来困惑和挫败感。
  • 社区支持相对较小:与一些其他知名的图表库相比,antv X6 的社区规模相对较小。这意味着你可能会在使用过程中遇到问题时,获得的帮助和支持相对有限。

快速入门

安装

# npm
$ npm install @antv/x6 --save

# yarn
$ yarn add @antv/x6

画布

  1. 在 X6 中,Graph 是图的载体,它包含了图上的所有元素(节点、边等)。 就是将所有元素绘制在上面

配置

new Graph(options: Options)

// 等同于
const graph = new Graph({
	container: document.getElementById('container'), // 画布容器 类型vue的挂载的元素
  width:"100px",
	height:"200px"
	mousewheel:true, // 鼠标滚轮缩放,默认禁用
  grid:true, // 网格是不显示
  panning: {
    enabled: true,
  },
})

画布 2.0 文档

画布1.0文档

元素

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

选项名类型默认值描述
idStringundefined节点/边的唯一标识,默认使用自动生成的 UUID。
markupMarkupundefined节点/边的 SVG/HTML 片段。
attrsObject{ }节点/边属性样式。
shapeStringundefined渲染节点/边的图形。
viewStringundefined渲染节点/边的视图。
zIndexNumberundefined节点/边在画布中的层级,默认根据节点/边添加顺序自动确定。
visibleBooleantrue节点/边是否可见。
parentStringundefined父节点。
childrenString[]undefined子节点/边。
dataanyundefined节点/边关联的业务数据。

元素文档

节点

节点类型

  1. 内置节点 创建方式
graph.addNode({
  x: 360, // 相对于画布的X轴
  y: 340, // 相对于画布的Y轴
  width: 120,
  height: 60, 
  label: "rect", // 节点标签文字节点元素
  attrs: { // 属性
    body: {
      stroke: "#237804", // 线条颜色
      fill: "#73d13d", // 填充色
      rx: 10, // 圆角
      ry: 10
    },
    // 文本元素的属性
    label: {
      refX: "100%", // 相对于节点X轴的宽度的100%
      refX2: -8,  
      refY: "100%", // 相对于节点Y轴的宽度的100%
      refY2: -8,
      textAnchor: "end", // 文本在画布x轴的位置 start  middle  end 
      textVerticalAnchor: "bottom" // 文本在画布x轴的位置 top  middle   bottom 
    }
  }
});

image.png

  1. 自定义节点

我们可以通过 markup 和 attrs 来定制节点的形状和样式markup 可以类比 HTMLattrs 类比 CSS makup

interface Markup {
  tagName: string  // SVG/HTML 元素标签名。
  ns?: string // SVG/HTML 元素命名空间。 nameSpace
  selector?: string // 该元素的选择器(唯一),通过选择器来定位该元素或为该元素指定属性样式。
  groupSelector?: string | string[] //该元素的群组选择器,可以同时为该群组对应的多个元素指定样式
  // 该元素的默认属性键值对,通常用于定义那些不变的通用属性,这些默认属性也可以在实例化节点时被覆盖。需要注意的是 markup 中的 attrs 属性只支持原生的 SVG 属性,也就是说 X6 的在这里不可用。
  attrs?: { [key: string]: string | number }
  style?: { [key: string]: string | number } 
  className?: string | string[]
  textContent?: string // 该元素的文本内容。
  children?: Markup[]
}
  1. svg

image.png

import { Graph } from '@antv/x6'
// 自定义节点需要注册,注册后可以直接使用上面的 grap.addNode('custom-node')来进行添加
Graph.registerNode(
  'custom-node',
  {
    width: 200,
    height: 60,
    attrs: {
      body: {
        stroke: '#5F95FF',
        strokeWidth: 1,
        fill: 'rgba(95,149,255,0.05)',
        refWidth: 1,
        refHeight: 1,
      },
      image: {
        'xlink:href':
          'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
        width: 16,
        height: 16,
        x: 12,
        y: 12,
      },
      title: {
        text: 'Node',
        refX: 40,
        refY: 14,
        fill: 'rgba(0,0,0,0.85)',
        fontSize: 12,
        'text-anchor': 'start',
      },
      text: {
        text: 'this is content text',
        refX: 40,
        refY: 38,
        fontSize: 12,
        fill: 'rgba(0,0,0,0.6)',
        'text-anchor': 'start',
      },
    },
    markup: [
      {
        tagName: 'rect',  // 对应svg的名字,还有一些是X6 自带的
        selector: 'body', // 和上面的body 对应
      },
      {
        tagName: 'image',
        selector: 'image',
      },
      {
        tagName: 'text',
        selector: 'title',
      },
      {
        tagName: 'text',
        selector: 'text',
      },
    ],
  },
  true,
)

const graph = new Graph({
  container: document.getElementById('container')!,
  grid: true,
})

graph.addNode({
  x: 200,
  y: 160,
  shape: 'custom-node',
})
  1. react
  2. vue

image.png

// 子组件
<template>
  <div class="app-content">
    <div id="container"></div>
    <TeleportContainer />
  </div>
</template>

<script lang="ts">
  import { defineComponent } from 'vue'
  import ProgressNode from './components/ProgressNode.vue'
  import { Graph } from '@antv/x6'
  import { register, getTeleport } from '@antv/x6-vue-shape'

  register({
    shape: 'custom-vue-node',
    width: 100,
    height: 100,
    component: ProgressNode,
  })
  const TeleportContainer = getTeleport()

  export default defineComponent({
    name: 'App',
    components: {
      TeleportContainer,
    },
    mounted() {
      const graph = new Graph({
        container: document.getElementById('container')!,
        background: {
          color: '#F2F7FA',
        },
        autoResize: true,
      })

      graph.addNode({
        shape: 'custom-vue-node',
        x: 100,
        y: 60,
      })
    },
  })
</script>

连接桩

连接桩是节点上的固定连接点,很多图应用都有连接桩,并且有些应用还将连接桩分为输入连接桩和输出连接桩

连接桩分组:同行为和外观的连接桩归为同一组,并通过 groups 选项来设置分组

image.png

interface PortGroupMetadata {
  markup?: Markup // 连接桩 DOM 结构定义。
  attrs?: Attr.CellAttrs // 属性和样式。
  zIndex?: number | 'auto' // 连接桩的 DOM 层级,值越大层级越高。
  // 群组中连接桩的布局。
  position?: [number, number] | string | { name: string; args?: object }
  label?: {
    // 连接桩标签
    markup?: Markup
    position?: {
      // 连接桩标签布局
      name: string // 布局名称
      args?: object // 布局参数
    }
  }
}

  1. 连接到画布上的点

    const edge = graph.addEdge({
      source: { x: 40, y: 40 }, // 起点的坐标
      target: { x: 180, y: 80 }, // 终点的坐标
    })
    
  2. 连接到节点/边

    const edge = graph.addEdge({
      source: { cell: 'source-cell-id' }, // 元素的ID
      target: { cell: 'target-cell-id' }, // 元素的id
    })
    
  3. 连接到节点上的连接桩

    const edge = graph.addEdge({
      source: { cell: 'source-cell-id', port: 'port-id' }, // 元素的ID 和连接点的ID
      target: { cell: 'target-cell-id', port: 'port-id' }, 
    })
    
  4. 连接到节点上的某个元素

    const edge = graph.addEdge({
      source: { cell: 'source-cell-id', selector: 'some-selector' },
      target: { cell: 'target-cell-id', selector: 'some-selector' },
    })
    

属性

选项类型默认值必选描述
sourceTerminalData起点或起始节点、连接桩信息。
targetTerminalData终点或终止节点、连接桩信息。
verticesPoint.PointLike[]路径点。
routerRouterData路由。
connectorConnectorData连接器。
labelsLabel[]string[]标签。
defaultLabelLabel默认标签。

箭头

箭头样式

内置箭头样式

image.png

 this.graph.addEdge({
      source: [80, 160], // 开始的坐标
      target: [480, 160], // 结束点的坐标
      attrs: {
        line: {
          sourceMarker: 'block', //开始箭头
          targetMarker: 'block', // 结束
          stroke: '#8f8f8f',
          strokeWidth: 1,
        },
      },
    })

自定义箭头

image.png

  // svg  path  自定义箭头
  graph.addEdge({
    source: { x: 100, y: 40 }, // 开始的坐标
    target: { x: 400, y: 40 }, // 结束的坐标
    attrs: {
      line: {
        stroke: '#31d0c6',
        sourceMarker: {
          name: 'path',
          d: 'M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z',
        },
        targetMarker: {
          name: 'path',
          offsetX: 10,
          d: 'M4.834,4.834L4.833,4.833c-5.889,5.892-5.89,15.443,0.001,21.334s15.44,5.888,21.33-0.002c5.891-5.891,5.893-15.44,0.002-21.33C20.275-1.056,10.725-1.056,4.834,4.834zM25.459,5.542c0.833,0.836,1.523,1.757,2.104,2.726l-4.08,4.08c-0.418-1.062-1.053-2.06-1.912-2.918c-0.859-0.859-1.857-1.494-2.92-1.913l4.08-4.08C23.7,4.018,24.622,4.709,25.459,5.542zM10.139,20.862c-2.958-2.968-2.959-7.758-0.001-10.725c2.966-2.957,7.756-2.957,10.725,0c2.954,2.965,2.955,7.757-0.001,10.724C17.896,23.819,13.104,23.817,10.139,20.862zM5.542,25.459c-0.833-0.837-1.524-1.759-2.105-2.728l4.081-4.081c0.418,1.063,1.055,2.06,1.914,2.919c0.858,0.859,1.855,1.494,2.917,1.913l-4.081,4.081C7.299,26.982,6.379,26.292,5.542,25.459zM8.268,3.435l4.082,4.082C11.288,7.935,10.29,8.571,9.43,9.43c-0.858,0.859-1.494,1.855-1.912,2.918L3.436,8.267c0.58-0.969,1.271-1.89,2.105-2.727C6.377,4.707,7.299,4.016,8.268,3.435zM22.732,27.563l-4.082-4.082c1.062-0.418,2.061-1.053,2.919-1.912c0.859-0.859,1.495-1.857,1.913-2.92l4.082,4.082c-0.58,0.969-1.271,1.891-2.105,2.728C24.623,26.292,23.701,26.983,22.732,27.563z',
        },
      },
    },
  })

自定义箭头注册

image.png


// 注册 
// image2 是注册的name
Graph.registerMarker('image2', (args) => {
  
  const { imageUrl, imageWidth, imageHeight, ...attrs } = args
  return {
    ...attrs, // 原样返回非特殊涵义的参数
    tagName: 'image', // 使用 svg <image> 标签渲染箭头,其余键值对都将作为该元素的属性。
    width: imageWidth, // 宽
    height: imageHeight,  // 高
    'xlink:href': imageUrl, // url地址
  }
})

// 使用注册的箭头
  graph.addEdge({
    source: { x: 140, y: 400 },
    target: { x: 420, y: 400 },
    attrs: {
      line: {
        sourceMarker: {
          name: 'image2',
          imageUrl:
            'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png',
          imageWidth: 24,
          imageHeight: 24,
          y: -12,
        },
        targetMarker: {
          name: 'image2', // name和注册name 要一致
          imageUrl:
            'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png',
          imageWidth: 24,
          imageHeight: 24,
          y: -12,
        },
      },
    },
  })

交互

交互文档

X6 最吸引开发者的地方是具备非常完整的交互定制能力

  1. 连接的时候是否吸附
  2. 是不是可以建循环连线
  3. 是否允许边连接到节点(非节点上的连接桩)
  4. 是不是允许连接到边
  5. 拖动是不是课可以高亮

AntV X6 的交互功能使得用户可以与图形进行直接的互动操作和控制,以实现更丰富的用户体验。以下是 AntV X6 交互的一些常见功能:

  1. 节点拖拽和调整:用户可以通过鼠标拖拽节点来调整它们的位置,改变节点间的连接关系和布局。这对于网络拓扑图、流程图等应用非常有用。
  2. 缩放和平移:用户可以使用鼠标滚轮来缩放图形,或者通过拖动画布来平移图形的显示区域。这使得用户能够对大规模的图形进行浏览和导航。
  3. 高亮和选中:用户可以通过悬停鼠标或单击节点来高亮相关的图形元素,以突出显示它们或触发其他操作,例如显示详细信息或执行特定的操作。
  4. 节点大小和样式调整:用户可以调整节点的大小、形状和样式,以满足特定的需求。这对于定制化图形的外观和美观性非常重要。
  5. 数据筛选和筛选器:用户可以根据特定的条件和参数来筛选数据,并动态更新图形的显示。这有助于用户通过交互性的方式探索和分析数据。
  6. 事件交互:AntV X6 提供了各种事件处理机制,允许开发者定义和处理不同的用户交互事件,例如点击、拖拽、放大缩小等,以及自定义的交互行为。

AntV X6 的交互功能使得开发者能够根据不同的场景和需求,为图形应用添加交互性和用户操作的能力,从而提升应用的可用性和用户体验。

事件

视图交互事件

用来监听视图的事件

事件cell 节点/边node 节点port 连接桩edge 边blank 画布空白区域
单击cell:clicknode:clicknode:port:clickedge:clickblank:click
双击cell:dblclicknode:dblclicknode:port:dblclickedge:dblclickblank:dblclick
右键cell:contextmenunode:contextmenunode:port:contextmenuedge:contextmenublank:contextmenu
鼠标按下cell:mousedownnode:mousedownnode:port:mousedownedge:mousedownblank:mousedown
移动鼠标cell:mousemovenode:mousemovenode:port:mousemoveedge:mousemoveblank:mousemove
鼠标抬起cell:mouseupnode:mouseupnode:port:mouseupedge:mouseupblank:mouseup
鼠标滚轮cell:mousewheelnode:mousewheel-edge:mousewheelblank:mousewheel
鼠标进入cell:mouseenternode:mouseenternode:port:mouseenteredge:mouseentergraph:mouseenter
鼠标离开cell:mouseleavenode:mouseleavenode:port:mouseleaveedge:mouseleavegraph:mouseleave
graph.on('cell:click', ({ e, x, y, cell, view }) => {})
graph.on('node:click', ({ e, x, y, node, view }) => {})
graph.on('edge:click', ({ e, x, y, edge, view }) => {})
graph.on('blank:click', ({ e, x, y }) => {})

graph.on('cell:mouseenter', ({ e, cell, view }) => {})
graph.on('node:mouseenter', ({ e, node, view }) => {})
graph.on('edge:mouseenter', ({ e, edge, view }) => {})
graph.on('graph:mouseenter', ({ e }) => {})

数据

导出

{
  id: string,
  shape: string,
  position: {
    x: number
    y: number
  },
  size: {
    width: number
    height: number
  },
  attrs: object,
  zIndex: number,
}

导入

graph.fromJSON([
  {
    id: 'node1',
    x: 40,
    y: 40,
    width: 100,
    height: 40,
    label: 'Hello',
    shape: 'rect',
  },
  {
    id: 'node2',
    x: 40,
    y: 40,
    width: 100,
    height: 40,
    label: 'Hello',
    shape: 'ellipse',
  },
  {
    id: 'edge1',
    source: 'node1',
    target: 'node2',
    shape: 'edge',
  },
])

丰富的扩展能力

工具

节点的工具

node-edite

编辑节点

节点编辑工具

// 2.8.0 版本之前使用方式
graph.on('node:dblclick', ({ node, e }) => {
  node.addTools({
    name: 'node-editor',
    args: {
      event: e,
    },
  })
})

// 2.8.0 版本之后使用方式
node.addTools({
  name: 'node-editor',
})

边的工具

edge-edtie

边编辑例子

// 2.8.0 版本之前使用方式
graph.on('node:dblclick', ({ node, e }) => {
  edge.addTools({
    name: 'edge-editor',
    args: {
      event: e,
    },
  })
})

// 2.8.0 版本之后使用方式
edge.addTools({
  name: 'edge-editor',
})

插件

插件

  1. 图形变换
  2. 对齐线
  3. 复制粘贴
  4. 快捷键
  5. 撤销重做
  6. 框选
  7. 滚动画布
  8. 小地图
  9. Dnd
  10. Stencil
  11. 导出 demo

结语与资源链接

学习资料

  1. X6官网
  2. svg掘金
  3. 流程图github
  4. b站 X6视频
  5. vue3 学习demo
  6. 大佬的demo