Antv/X6
这里的背景是以vue3.2+antv/x6 2.8
为背景的学习,官网的文档是使用react
书写的案例,需要摸索的地方还是有很多,下面开始
前提
假设你已经创建了vue
,如果不清楚怎么创建vue
项目,建议前往官网学习Vue。使用组合式API
开发,为了简便,没有使用路由等东西,就是使用TS + Less
,但是 TS 使用的很烂,有问题拜托指出,谢谢。
快速上手
接下来我们就开始使用
安装 X6
# npm
$ npm install @antv/x6 --save
# yarn
$ yarn add @antv/x6
初始化画布
创建容器
首先我们要创建我们的画布容器,我们使用了id
为container
的div
来当我们的容器
<template>
<div class="graph">
<!-- 1.创建容器 -->
<div id="container" class="container"></div>
</div>
</template>
引入 antv/x6
<script setup lang="ts">
// 1.引入vue和antv/x6
import { ref, onMounted } from "vue";
import { Graph } from "@antv/x6";
// 2.定义一个变量来接受这个
const graph = ref();
// 3. 在 onMounted 生命周期中才能访问到DOM节点,需要注意一下。
onMounted(() => {
// 4.定义画布
graph.value = new Graph({
container: document.getElementById("container") as HTMLElement,
width: 800,
height: 600,
background: {
color: "#F2F7FA", // 设置画布的背景颜色。
},
});
});
</script>
在上面的代码块中,我们定义了一个画布,以下对一些参数做一些解释。
container
,目标容器width
,画布的宽度height
,画布的高度background
,画布的背景,比如这里我们设置了背景的颜色
到这里我们应该在浏览器中就有一个画布了。
渲染节点和边
X6 支持 JSON 格式数据,该对象中 nodes
代表节点数据,edges
代表边数据,可以使用 attrs
属性来定制节点和边的样式(可以类比 CSS)。
定义节点和边的信息
<script setup lang="ts">
// 定义节点和边的信息
const data = {
nodes: [
{
id: "node1",
shape: "rect",
x: 40,
y: 40,
width: 100,
height: 40,
label: "hello",
attrs: {
// body 是选择器名称,选中的是 rect 元素
body: {
stroke: "#8f8f8f",
strokeWidth: 1,
fill: "#fff",
rx: 6,
ry: 6,
},
},
},
{
id: "node2",
shape: "rect",
x: 160,
y: 180,
width: 100,
height: 40,
label: "world",
attrs: {
body: {
stroke: "#8f8f8f",
strokeWidth: 1,
fill: "#fff",
rx: 6,
ry: 6,
},
},
},
],
edges: [
{
shape: "edge",
source: "node1",
target: "node2",
label: "x6",
attrs: {
// line 是选择器名称,选中的边的 path 元素
line: {
stroke: "#8f8f8f",
strokeWidth: 1,
},
},
},
],
};
</script>
下面我们来解释一下上面一坨代码的含义,其实大部分内容是重复的。我们从节点(nodes)开始.
nodes 解释
id
,节点的唯一标识,如果不指定节点,那么 x6 会自动给我们生成 ID。shape
,指定节点的图形,x6 给我们提供了很多的内置节点,比如我们这里使用的就是矩形。x
,x 轴,在画布中水平向右为 x 轴正方向,垂直 x 轴向下为 y 轴正方向。此处指的就是节点在画布中 x 轴的位置。y
,在画布中 y 轴的位置。width
,节点的宽度height
,节点的高度label
,节点中间的描述性文字attrs
,可以理解为css
,是一个对象。比如我们这里body
是选择器的名称,选中的是rect
元素stroke
,节点的矩形框描边颜色strokeWidth
,节点的矩形框描边宽度fill
,节点的矩形框填充颜色rx
,节点的矩形直角的边框圆角水平半径ry
,节点的矩形直角的边框圆角垂直半径
edges 解释
shape
,指定边的类型source
,源节点或者起始节点target
,目标节点label
,标签,或者简单说就是边上的文字attrs
,line
是选择器名称,选中的边的path
元素
渲染
当我们定义好节点之后,我们就要开始渲染了。因为在Vue3
之中,在onMounted
之中才能拿到 Dom 节点,所以我们也需要再onMounted
之中,才能拿到 Dom 赋值。
<script setup lang="ts">
// 1.引入vue和antv/x6
import { ref, onMounted } from "vue";
import { Graph } from "@antv/x6";
// 2.定义一个变量来接受这个
const graph = ref();
// 3. 在 onMounted 生命周期中才能访问到DOM节点,需要注意一下。
onMounted(() => {
// 4.定义画布
graph.value = new Graph({
container: document.getElementById("container") as HTMLElement,
width: 800,
height: 600,
background: {
color: "#F2F7FA", // 设置画布的背景颜色。
},
});
// 5.加载数据
graph.value.fromJSON(data);
});
</script>
然后去看浏览器,应该会有如下的画面:
我们在上面使用的时候,看到graph.value.fromJSON(data);
这种用法,总是先.value
之后再使用对应的方法,其实这个是因为我们创建变量的时候,使用的是ref
创建的变量,使用ref
创建的变量,只要不是在模版中使用,都是需要.value
的。
到这里,快速上手就完毕了,就是这么简单。
画布
画布布是在 X6 中用于展示和编辑图形的区域,类似于绘图板的概念。通过画布,可以创建、移动、编辑和删除图形,包括节点、连接线、文本等。
画布自适应
我们在实例化Graph
对象的时候,可以通过设置 width
和 height
固定画布大小,如果不设置,就会以画布容器大小初始化画布。但是我们有可能会遇到页面的 resize
事件,导致画布容器大小改变,导致画布元素显示异常。
resize
事件是 JavaScript 中一个针对浏览器窗口大小改变的事件。当用户调整浏览器窗口大小时,浏览器会触发 resize
事件,允许开发者在窗口大小改变时执行相关的代码。
window.addEventListener("resize", function () {
// 处理窗口大小改变事件
});
这时候,我们就需要设置autoResize
来解决。
<script setup lang="ts">
// 1.引入vue和antv/x6
import { ref, onMounted } from "vue";
import { Graph } from "@antv/x6";
// 2.定义一个变量来接受这个
const graph = ref();
// 3. 在 onMounted 生命周期中才能访问到DOM节点,需要注意一下。
onMounted(() => {
// 4.定义画布
const graph = new Graph({
container: document.getElementById("container"),
autoResize: true,
});
// 5.加载数据
graph.value.fromJSON(data);
});
</script>
设置好之后,查看效果
当我们拉动浏览器的宽度的时候,我们发现,画布左右侧始终有一定的空间,画布会自适应变化宽度。
设置背景和网格
在antv/x6
之中,可以通过 background
和 grid
两个配置来设置画布的背景以及网格。
背景
首先我们来看背景,他有多种情况。
color
背景颜色,支持所有 CSS background-color 属性的取值,如:
'red'
,颜色关键字'#f5f5f5'
,十六进制符号'rgba(255, 255, 128, 0.5)'
函数符,红绿蓝透明度'hsla(50, 33%, 25%, 0.75)'
HSL
圆柱坐标系统是指一种颜色空间表示方式,其中 HSL 代表色相、饱和度和亮度,圆柱坐标则表示这些参数的变化。
在HSL
圆柱坐标系统中,色相是指颜色的种类或类别,如红色、黄色等,它沿着一个 360 度的色轮上变化。饱和度表示颜色的强度或纯度,取值范围为 0 到 1,0 表示灰度,1 表示完全饱和。亮度则表示颜色的亮暗程度,取值范围同样为 0 到 1,0 表示黑色,1 表示白色。最后一个值也是透明度,取值范围 0 到 1。
'radial-gradient(shape size at position, red, green)'
radial-gradient
是CSS3
中用来创建径向渐变效果的函数,使用 radial-gradient 函数可以创建从一个中心点向周围扩散的渐变效果。
shape可以是circle(圆形)或ellipse(椭圆形),size可以是closest-side(最近的边)、closest-corner(最近的角)、farthest-side(最远的边)或farthest-corner(最远的角),position表示渐变的中心点位置(可以是一个像素值或一个百分比),start-color表示起始颜色,last-color表示终止颜色。
比如:
background: radial-gradient(circle, #ff9d9d, #fe2d2d);
这将创建一个从中心向外扩散的圆形渐变效果,起始颜色为#ff9d9d
,终止颜色为#fe2d2d
。
image
背景图片的 URL 地址,这里需要值得注意的我们需要先导入,然后再使用
<script setup lang="ts">
import bgcImage from "@/antv-x6/bg2.b4f49dec.png";
onMounted(() => {
graph.value = new Graph({
container: document.getElementById("container") as HTMLElement,
width: 800,
height: 600,
background: {
image: bgcImage,
},
autoResize: true,
});
graph.value.fromJSON(data);
});
</script>
position
背景图片位置,支持所有 CSS background-position 属性的取值,默认为 'center'
。
size
背景图片大小,支持所有 CSS background-size 属性的取值,默认为 'auto auto'
。
repeat
背景图片重复方式,支持所有 CSS background-repeat 属性的取值,默认为 'no-repeat' 不平铺
。
另外,还支持以下几个预定义值:
'watermark'
水印效果。'flip-x'
水平翻转背景图片。'flip-y'
垂直翻转背景图片。'flip-xy'
水平和垂直翻转背景图片。
画布拖拽(平移)和缩放
画布的拖拽和缩放通过 panning
和 mousewheel
配置来实现这两个功能
const graph = new Graph({
...,
panning: true,
mousewheel: true
})
节点
X6
是基于 SVG
的渲染引擎,可以使用不同的 SVG
元素渲染节点和边,非常适合节点内容比较简单的场景。如果我们需要复杂的场景,那么我们可以通过vue
节点来实现。
添加节点
我们在最初的时候在setup
中定义了一个graph
属性,这个graph
我们通过new
创建了画布的对象。新增节点可以通过addNode
方法,传入一个对象。
graph.value.addNode({
shape: "rect",
label: "矩形",
x: 100,
y: 40,
width: 100,
height: 40,
});
shape
,节点的图形x
,在画布中 x 轴的的位置y
,在画布中的 y 轴的位置width
,元素的宽度height
,元素的高度label
,矩形中间的文字
内置节点
在Antv/X6
之中,也内置了很多节点,比如圆形,椭圆,矩形等等。
shape 名称 | 描述 |
---|---|
rect | 矩形 |
circle | 圆形 |
ellipse | 椭圆 |
polygon | 多边形 |
polyline | 折线 |
path | 路径 |
image | 图片 |
html | HTML 节点,使用 foreignObject 渲染 HTML 片段。 |
矩形
graph.value.addNode({
shape: "rect",
label: "矩形",
x: 100,
y: 40,
width: 100,
height: 40,
});
圆形
graph.value.addNode({
shape: "circle",
label: "矩形",
x: 100,
y: 40,
width: 100,
height: 40,
});
定制节点
可以通过 markup
和 attrs
来定制节点的形状和样式,markup
可以类比 HTML
,attrs
类比 CSS
。强烈建议仔细阅读 markup 和 attrs 文档。
但是个人认为这个适合做一些简单的节点,如果复杂的节点,推荐使用vue
节点,后面会介绍到。
修改节点
在我们创建完成之后,还能够对节点进行一定的修改,我们还可以通过 API 修改节点的所有属性。我们会常用到下面两个方法:
const node = graph.addNode({
shape: "rect",
width: 100,
height: 40,
x: 100,
y: 100,
label: "edge",
});
console.log(node.prop());
比如:
source.prop("size", { width: 120, height: 50 }); // 修改元素的宽高
source.attr("rect/fill", "#ccc"); // 修改填充色,等价于 source.prop('attrs/rect/fill', '#ccc')
通常情况下,真实场景并不会像上面的示例,还给节点一个单独的名称,在实际过程中,我们一般是配合事件一起来进行使用,比如我们选中某个节点想要设置其边框颜色,他会自动监听画布中的点击事件,然后去进行对应的操作。
graph.value.on("cell:click", ({ e, x, y, cell, view }) => {
// cell 就是我们所需要的节点对象
cell.attr("body/stroke", "red");
});
或者说还有情况就是给画布中的所有对象都设置
const nodes = this.graph.getNodes(); // 获取画布中的所有节点
nodes.forEach((node) => {
const color = Color.random().toHex();
node.attr("body/fill", color);
});
边
如何添加边
graph.value.addEdge({
shape: "edge",
source: "node1",
target: "node2",
});
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
source | TerminalData | - | 源节点或起始点。其与节点的 ID 相同 |
target | TerminalData | - | 目标节点或目标点。其与节点的 ID 相同 |
vertices | Point.PointLike[] | - | 路径点。 |
router | RouterData | - | 路由。 |
connector | ConnectorData | - | 连接器。 |
labels | Label[] | - | 标签。 |
defaultLabel | Label | 默认标签 | 默认标签。 |
上面代码就是添加边的方法,source
和target
的值需要与节点的ID
一致就可以将两个节点进行连接,如果你只是看看能不能创建边,其实还有种写法
graph.value.addEdge({
shape: "edge",
source: [100, 100],
target: [400, 100],
});
数组代表的是x
轴和y
轴。
vertices
路径点。边从起始点开始,按顺序经过路径点,最后到达终止点。
graph.value.addEdge({
source: "rect1",
target: "rect2",
vertices: [
{ x: 100, y: 200 },
{ x: 300, y: 120 },
],
});
router
路由 router
将对 vertices
进一步处理,并在必要时添加额外的点,然后返回处理后的点。
orth
正交路由,该路由在路径上添加额外的一些点,使边的每一条线段都水平或垂直正交。
graph.value.addEdge({
source,
target,
vertices: [
{ x: 100, y: 200 },
{ x: 300, y: 120 },
],
router: {
name: "orth",
args: {
padding: {
left: 50,
},
},
},
});
那两个圆圈的地方就是我们自己设置的vertices
,其他的都是定义orth
路由,自动生成的。
其他的版本可以看官网
manhattan
曼哈顿路由 'manhattan'
路由是正交路由 'orth'
的智能版本,该路由由水平或垂直的正交线段组成,并自动避开路径上的其他节点(障碍)。
同时需要注意的是,manhattan
路由的特性是自动避开路径中的障碍物,如果出现无法避开的情况,就会自动降级到 orth
路由,此时为了让开发者能够发现问题,在控制台增加了 warn:Unable to execute manhattan algorithm, use orth instead
。
这个在最新的官网已经注明了。
如果你看着警告不爽,解决办法就是忽略参与计算的节点,但是这样就相当于没有manhattan
就白用了一样。看自己选择吧。
labels 和 defaultLabel
graph.addEdge({
source,
target,
attrs: {
line: {
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
labels: [
{
attrs: {
label: {
text: '40%', // 字体
stroke: '#aaa', // 颜色
},
},
position: 0.4, // 在线上的位置
},
{
attrs: {
label: {
text: '60%',
stroke: '#aaa',
},
},
position: 0.6,
},
],
})
}
定制边
基类派生
定制箭头有两种方式,一种是使用从基类派生出我们的边,并重写某些样式和方法。详细可以看antv/x6 1.0
版本,在 2.0 版本中没有明确说明这种方式。
import { Shape } from "@antv/x6";
//1. 派生出自己的边样式
const MyEdge = Shape.Edge({
markup: [
{
tagName: "path",
selector: "wrap",
attrs: {
fill: "none",
cursor: "pointer",
stroke: "transparent",
strokeLinecap: "round",
},
},
{
tagName: "path",
selector: "line",
attrs: {
fill: "none",
pointerEvents: "none",
},
},
],
attrs: {
wrap: {
connection: true,
strokeWidth: 10,
strokeLinejoin: "round",
},
line: {
connection: true,
stroke: "#333333",
strokeWidth: 2,
strokeLinejoin: "round",
targetMarker: {
tagName: "path",
d: "M 10 -5 0 0 10 5 z",
},
},
},
});
//2. 将边注册,这里用的就是Graph,不是实例后的画布对象 第一个参数是自定义的,只要在创建边的时候对应就行
Graph.registerEdge("edge1", MyEdge);
//3. 使用
graph.addEdge({
shape: "edge1",
source,
target,
});
箭头
对于边两端的箭头,antv/x6
提供了内置箭头和自定义箭头两种方式
内置箭头
antv/x6
提供了以下的几种箭头。
实心箭头(block)、经典箭头(classic)、菱形箭头(diamond)、交叉箭头(cross)、async、path、圆形箭头(circle)、圆形和加号箭头(circlePlus)、椭圆箭头(elipse)
定制箭头
工厂方法
在Graph
原型上有个registerMarker
方法,可以帮助我们自定义箭头
// 1.注册
Graph.registerMarker("image", (args: ImageMarkerArgs) => {
const { imageUrl, imageWidth, imageHeight, ...attrs } = args;
return {
...attrs, // 原样返回非特殊涵义的参数
tagName: "image", // 使用 <image> 标签渲染箭头,其余键值对都将作为该元素的属性。
width: imageWidth,
height: imageHeight,
"xlink:href": imageUrl,
};
});
//2. 使用
edge.attr({
line: {
sourceMarker: {
name: "image",
imageUrl:
"http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png",
imageWidth: 24,
imageHeight: 24,
y: -12,
},
targetMarker: {
name: "image",
imageUrl:
"http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png",
imageWidth: 24,
imageHeight: 24,
y: -12,
},
},
});
直接生成
我们可以通过实例对象上的暴露的方法直接生成边的同时,指定对应的样式,起始箭头和终止箭头使用了相同的 d
属性,这是因为x6
会自动计算箭头方向,简单来说,在定义箭头时,只需要定义一个向左指向坐标原点的箭头即可。
graph.addEdge({
shape: "edge",
sourece: [100, 100],
target: [500, 500],
attrs: {
line: {
sourceMarker: {
tagName: "path",
d: "M 20 -10 0 0 20 10 Z",
},
targetMarker: {
tagName: "path",
fill: "yellow", // 使用自定义填充色
stroke: "green", // 使用自定义边框色
strokeWidth: 2,
d: "M 20 -10 0 0 20 10 Z",
},
},
},
});