准备写关于x6的一个系列文章,大致有以下内容:
- X6 极速入门:手把手教你绘制第一个拓扑图
- 揭秘 X6 核心概念:Graph、Node、Edge 与 View
- 自定义节点与边
- X6 交互魔法:拖拽、连线、缩放、对齐线
- X6 布局之道:内置布局算法与自定义布局
- 基于 React + X6 构建可视化流程图编辑器
- X6 性能优化秘籍:应对大规模节点渲染的挑战
- X6源码分析
- 手写最小 X6(X6-mini)
什么是 X6,我为什么要用它?
在现代 Web 开发中,我们经常会遇到需要绘制流程图、脑图、ER 图、架构图等图编辑场景。无论是低代码平台、数据可视化还是内部运维系统,一个强大的图编辑引擎都至关重要。
AntV X6 正是蚂蚁集团 AntV 数据可视化团队推出的一款专业、高效、易用的图编辑引擎。它提供了丰富的内置节点、边和交互功能,同时具备极高的可定制性和扩展性,是国内该领域的佼佼者。
它的核心优势在于:
- 功能强大:支持海量图形、流畅的交互、丰富的插件。
- 生态友好:完美支持 React、Vue、Angular 等主流框架。
- 文档详尽:中文文档非常友好,社区活跃。
暂时抛开复杂的理论,直接动手,在 10 分钟内创建一个包含节点和连线的简单拓扑图。让我们领略一下x6的魅力吧!
一、 环境准备:引入 X6
首先,我们需要一个 HTML 页面。X6 的引入方式非常简单,既可以通过 CDN,也可以通过 npm 安装。为了极速入门,我们使用 CDN 方式。(此处评论:是个前端都知道,废话)
创建一个 index.html 文件,并输入以下代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>X6 极速入门 - 第一个拓扑图</title>
<!-- 1. 引入 X6 样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.css">
<style>
/* 为画布容器定义一个大小和边框 */
#container {
width: 800px;
height: 600px;
margin: 30px auto;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
</head>
<body>
<!-- 2. 定义一个用于绘制拓扑图的容器 -->
<div id="container"></div>
<!-- 3. 引入 X6 库 -->
<script src="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.js"></script>
<script>
// 接下来的所有代码都将写在这里
</script>
</body>
</html>
二、 四步核心代码,绘制你的第一个图
现在,我们在 <script> 标签内开始编写核心逻辑。
步骤 1:创建 Graph 画布实例
画布(Graph)是所有操作的基石。它就像一张绘图纸,所有节点和边都将添加到它上面。
// 在 script 标签内
const graph = new window.X6.Graph({
container: document.getElementById('container'),
width: 800,
height: 600,
// 开启画布网格,方便对齐,默认为点状网格
grid: true,
// 配置背景
background: {
color: '#F5F5F5',
},
// 启用鼠标滚轮缩放
mousewheel: {
enabled: true,
zoomAtMousePosition: true, // 在鼠标位置缩放,体验更好
modifiers: 'ctrl',
minScale: 0.5,
maxScale: 2,
},
});
container: 指定画布渲染的 DOM 容器。grid: true: 显示网格,让作图更规整。mousewheel: 配置用Ctrl+ 鼠标滚轮进行画布缩放,这是非常常见的交互。
步骤 2:创建并添加节点(Node)
节点是拓扑图中的基本元素,可以是服务器、路由器、用户等任何实体。
我们创建两个不同形状的节点:一个矩形和一个圆形。
// 创建矩形节点,代表一台服务器
const rectNode = graph.addNode({
x: 100, // 节点左上角 x 坐标
y: 100, // 节点左上角 y 坐标
width: 80,
height: 40,
label: 'Web Server', // 节点的文本标签
shape: 'rect', // 指定形状为矩形,默认为 rect,可省略
attrs: {
body: {
stroke: '#1890ff', // 边框颜色
fill: '#e6f7ff', // 填充颜色
},
label: {
fontSize: 12,
fill: '#333', // 文本颜色
},
},
});
// 创建圆形节点,代表一台数据库
const circleNode = graph.addNode({
x: 400,
y: 300,
width: 60, // 对于椭圆/圆,width 是直径
height: 60,
label: 'DB',
shape: 'ellipse', // 指定形状为椭圆(圆形是椭圆的一种)
attrs: {
body: {
stroke: '#52c41a',
fill: '#f6ffed',
},
label: {
fontSize: 12,
fill: '#333',
},
},
});
x, y: 决定了节点在画布上的位置。shape: 定义了节点的形状,rect(矩形)和ellipse(椭圆)是内置的基本形状。attrs: 用于深度定制节点的样式,非常强大。body指代节点主体,label指代文本。
步骤 3:创建并添加边(Edge)
边是连接节点的线,代表节点之间的关系,如网络流量、数据流等。
我们创建一条边,将上述两个节点连接起来。
// 创建一条边,连接两个节点
const edge = graph.addEdge({
source: rectNode, // 源节点,可以是节点对象或节点ID
target: circleNode, // 目标节点
// 可以在线上添加文本
labels: [
{
attrs: { label: { text: 'MySQL Protocol' } },
position: 0.5, // 文本位置,0.5 表示中间
},
],
// 配置边的样式
attrs: {
line: {
stroke: '#999', // 线条颜色
strokeWidth: 1, // 线条宽度
// 箭头和虚线等更多样式可以在这里配置
},
},
// 使用默认的平滑连线,更美观
vertices: [
{ x: 240, y: 120 }, // 添加一个路径点,让连线弯曲
{ x: 240, y: 300 },
],
connector: { name: 'rounded' }, // 连接处圆角
router: { name: 'manhattan' }, // 使用曼哈顿路由(正交线)
});
source&target: 指定边的起点和终点节点。vertices: 用于定义路径点,可以强制边按特定路径弯曲。router: 路由算法,manhattan(曼哈顿)表示生成正交的折线(只能横平竖直)。connector: 连接器,定义连接处的样式,rounded表示圆角。
步骤 4:让画面更完美 - 缩放至合适大小
当添加完元素后,我们可能希望画布自动调整到能看清全部内容的位置。
// 缩放画布内容至视口中心,让内容全部可见
graph.zoomToFit({ padding: 10 });
三、 最终效果与完整代码
现在,直接在浏览器中打开这个 index.html 文件,你将看到一个优雅的拓扑图!
完整的 index.html 代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>X6 极速入门 - 第一个拓扑图</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.css">
<style>
#container {
width: 800px;
height: 600px;
margin: 30px auto;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.js"></script>
<script>
// 1. 创建画布
const graph = new window.X6.Graph({
container: document.getElementById('container'),
width: 800,
height: 600,
grid: true,
background: { color: '#F5F5F5' },
mousewheel: {
enabled: true,
zoomAtMousePosition: true,
modifiers: 'ctrl',
minScale: 0.5,
maxScale: 2,
},
});
// 2. 创建节点
const rectNode = graph.addNode({
x: 100,
y: 100,
width: 80,
height: 40,
label: 'Web Server',
attrs: {
body: { stroke: '#1890ff', fill: '#e6f7ff' },
label: { fontSize: 12, fill: '#333' },
},
});
const circleNode = graph.addNode({
x: 400,
y: 300,
width: 60,
height: 60,
label: 'DB',
shape: 'ellipse',
attrs: {
body: { stroke: '#52c41a', fill: '#f6ffed' },
label: { fontSize: 12, fill: '#333' },
},
});
// 3. 创建边(连接线)
const edge = graph.addEdge({
source: rectNode,
target: circleNode,
labels: [{ attrs: { label: { text: 'MySQL Protocol' } }, position: 0.5 }],
attrs: { line: { stroke: '#999', strokeWidth: 1 } },
vertices: [
{ x: 240, y: 120 },
{ x: 240, y: 300 },
],
connector: { name: 'rounded' },
router: { name: 'manhattan' },
});
// 4. 自动调整视野
graph.zoomToFit({ padding: 10 });
</script>
</body>
</html>