跳到主要内容

自定义布局

概述

G6 中布局分为迭代布局和非迭代布局两种,迭代布局是指布局算法会迭代多次直到收敛,非迭代布局是指布局算法只执行一次。

实现布局

非迭代布局

实现一个非迭代布局相对简单,只需要实现 BaseLayout 中的 execute 方法即可,下面是一个简单的自定义布局实现:

import { BaseLayout } from '@antv/g6';
import type { GraphData } from '@antv/g6';

class DiagonalLayout extends BaseLayout {
  id = 'diagonal-layout';

  async execute(data: GraphData): Promise<GraphData> {
    const { nodes = [] } = data;
    return {
      nodes: nodes.map((node, index) => ({
        id: node.id,
        style: {
          x: 50 * index + 25,
          y: 50 * index + 25,
        },
      })),
    };
  }
}

在上面的代码中,我们实现了一个简单的布局算法,将节点从左上角沿对角线排列。

import { BaseLayout, ExtensionCategory, Graph, register } from '@antv/g6';

class DiagonalLayout extends BaseLayout {
  id = 'diagonal-layout';

  async execute(data) {
    const { nodes = [] } = data;
    return {
      nodes: nodes.map((node, index) => ({
        id: node.id,
        style: {
          x: 50 * index + 25,
          y: 50 * index + 25,
        },
      })),
    };
  }
}

register(ExtensionCategory.LAYOUT, 'diagonal', DiagonalLayout);

const graph = new Graph({
  container: 'container',
  width: 200,
  height: 200,
  data: {
    nodes: [{ id: 'node-1' }, { id: 'node-2' }, { id: 'node-3' }, { id: 'node-4' }],
  },
  layout: {
    type: 'diagonal',
  },
});

graph.render();

:::info{title=提示} execute 方法返回的是一个 GraphData 对象,里面仅需要包含元素的基本信息(如 id、source、target)以及布局新增的属性(如 x、y、边的控制点等),不需要包含其他无用的信息。 如果仅需要对节点进行布局,可以只返回节点信息,不需要返回边的信息。 :::

迭代布局

迭代布局的实现同样需要继承 BaseLayout,但是除 execute 外还需要实现 tick 和 stop 方法,tick 方法用于将布局迭代到指定轮次,stop 方法用于停止布局迭代。

此外,迭代布局中需要在每次迭代调用 options.onTick 以触发图的更新。

type onTick = (data: GraphData) => void;

下面是一个简单的迭代布局实现:

import { BaseLayout } from '@antv/g6';
import type { GraphData, BaseLayoutOptions } from '@antv/g6';

interface TickTockLayoutOptions extends BaseLayoutOptions {
  onTick: (data: GraphData) => void;
}

class TickTockLayout extends BaseLayout<TickTockLayoutOptions> {
  public id = 'custom-layout';

  private tickCount = 0;

  private data?: GraphData;

  private timer?: number;

  private resolve?: () => void;

  private promise?: Promise<void>;

  async execute(data: GraphData, options: TickTockLayoutOptions): Promise<GraphData> {
    const { onTick } = { ...this.options, ...options };

    this.tickCount = 0;
    this.data = data;

    this.promise = new Promise((resolve) => {
      this.resolve = resolve;
    });

    this.timer = window.setInterval(() => {
      onTick(this.simulateTick());
      if (this.tickCount === 10) this.stop();
    }, 200);

    await this.promise;

    return this.simulateTick();
  }

  simulateTick = () => {
    const x = this.tickCount++ % 2 === 0 ? 50 : 150;

    return {
      nodes: (this?.data?.nodes || []).map((node, index) => ({
        id: node.id,
        style: { x, y: (index + 1) * 30 },
      })),
    };
  };

  tick = () => {
    return this.simulateTick();
  };

  stop = () => {
    clearInterval(this.timer);
    this.resolve?.();
  };
}

在这个例子中,我们实现了一个简单的迭代布局算法,每 200ms 将节点的 x 坐标在 50 和 150 之间切换,并按照节点顺序在 y 方向上排列。

import { BaseLayout, ExtensionCategory, Graph, register } from '@antv/g6';

class TickTockLayout extends BaseLayout {
  id = 'tick-tock-layout';

  async execute(data, options) {
    const { onTick } = { ...this.options, ...options };

    this.tickCount = 0;
    this.data = data;

    this.promise = new Promise((resolve) => {
      this.resolve = resolve;
    });

    this.timer = window.setInterval(() => {
      onTick(this.simulateTick());
      if (this.tickCount === 10) this.stop();
    }, 200);

    await this.promise;

    return this.simulateTick();
  }

  simulateTick = () => {
    const x = this.tickCount++ % 2 === 0 ? 50 : 150;

    return {
      nodes: (this?.data?.nodes || []).map((node, index) => ({
        id: node.id,
        style: { x, y: (index + 1) * 30 },
      })),
    };
  };

  tick = () => {
    return this.simulateTick();
  };

  stop = () => {
    clearInterval(this.timer);
    this.resolve?.();
  };
}

register(ExtensionCategory.LAYOUT, 'tick-tock', TickTockLayout);

const graph = new Graph({
  container: 'container',
  width: 200,
  height: 200,
  animation: true,
  data: {
    nodes: [{ id: 'node-1' }, { id: 'node-2' }, { id: 'node-3' }, { id: 'node-4' }, { id: 'node-5' }],
  },
  layout: {
    type: 'tick-tock',
  },
});

graph.render();

注册布局

通过 G6 提供的 register 方法注册即可,详见注册布局

配置布局

可在 options.layout 中配置布局的类型和参数,详见配置布局

© Copyright 2026 Ant Group Co., Ltd..备案号:京ICP备15032932号-38
全站搜索
文档与示例输入关键词开始搜索

输入关键词,查找文档、API 与示例

↑↓选择↵打开Esc关闭