AntV X6 极速入门:手把手教你绘制第一个拓扑图

716 阅读6分钟

准备写关于x6的一个系列文章,大致有以下内容:

  1. X6 极速入门:手把手教你绘制第一个拓扑图
  2. 揭秘 X6 核心概念:Graph、Node、Edge 与 View
  3. 自定义节点与边
  4. X6 交互魔法:拖拽、连线、缩放、对齐线
  5. X6 布局之道:内置布局算法与自定义布局
  6. 基于 React + X6 构建可视化流程图编辑器
  7. X6 性能优化秘籍:应对大规模节点渲染的挑战
  8. X6源码分析
  9. 手写最小 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 文件,你将看到一个优雅的拓扑图!

image.png

完整的 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>