Skip to content

Graphic Transformations

This chapter mainly introduces knowledge related to the graphic transformation plugin. By reading, you can learn about

  • How to adjust node size using the interactive plugin
  • How to adjust a node’s rotation angle using the interactive plugin

Usage

Using interactive UI components to adjust node size and angle is a common requirement. We provide the transform plugin to implement this. Use it like this:

import { Graph, Transform } from '@antv/x6'

const graph = new Graph({
  background: {
    color: '#F2F7FA',
  },
})
graph.use(
  new Transform({
    resizing: resizingOptions,
    rotating: rotatingOptions,
  }),
)

Demo

First, let’s experience interactive resizing of nodes (clicking on a node brings up the operation component):

import './index.less'
import { createRoot } from 'react-dom/client'
import React from 'react'
import { Graph, Transform } from '@antv/x6'
import { Settings, State } from './settings.tsx'

export default class Example extends React.Component {
  private container: HTMLDivElement
  private graph: Graph

  componentDidMount() {
    this.initGraph({
      enabled: true,
      minWidth: 1,
      maxWidth: 200,
      minHeight: 1,
      maxHeight: 150,
      orthogonal: false,
      restrict: false,
      preserveAspectRatio: false,
    })
  }

  initGraph = (options: State) => {
    if (this.graph) {
      this.graph.dispose()
    }
    this.graph = new Graph({
      container: this.container,
      background: {
        color: '#F2F7FA',
      },
    })

    this.graph.use(
      new Transform({
        resizing: options,
      }),
    )

    const source = this.graph.addNode({
      shape: 'rect',
      x: 32,
      y: 32,
      width: 100,
      height: 40,
      label: 'Hello',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    const target = this.graph.addNode({
      shape: 'circle',
      x: 160,
      y: 180,
      width: 60,
      height: 60,
      label: 'World',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
        },
      },
    })

    this.graph.addEdge({
      source,
      target,
      attrs: {
        line: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
        },
      },
    })

    this.graph.centerContent()
  }

  onSettingChanged = (options: State) => {
    this.initGraph(options)
  }

  refContainer = (container: HTMLDivElement) => {
    this.container = container
  }

  render() {
    return (
      <div className="resizing-app">
        <div className="app-side">
          <Settings onChange={this.onSettingChanged} />
        </div>
        <div className="app-content" ref={this.refContainer} />
      </div>
    )
  }
}

const root = createRoot(document.getElementById('container')!)
root.render(<Example />)
window.addEventListener('pagehide', () => root.unmount(), { once: true })

Next, let’s experience interactive rotation of nodes (clicking on a node brings up the operation component):

import './index.less'
import { createRoot } from 'react-dom/client'
import React from 'react'
import { Graph, Transform } from '@antv/x6'
import { Settings, State } from './settings.tsx'

export default class Example extends React.Component {
  private container: HTMLDivElement
  private graph: Graph

  componentDidMount() {
    this.initGraph({
      enabled: true,
      grid: 15,
    })
  }

  initGraph = (options: State) => {
    if (this.graph) {
      this.graph.dispose()
    }
    this.graph = new Graph({
      container: this.container,
      background: {
        color: '#F2F7FA',
      },
    })

    this.graph.use(
      new Transform({
        rotating: options,
      }),
    )

    const source = this.graph.addNode({
      x: 60,
      y: 130,
      width: 100,
      height: 40,
      label: 'Hello',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    const target = this.graph.addNode({
      shape: 'circle',
      x: 260,
      y: 120,
      width: 60,
      height: 60,
      label: 'World',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    this.graph.addEdge({
      source,
      target,
      attrs: {
        line: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
        },
      },
    })

    this.graph.centerContent()
  }

  onSettingChanged = (options: State) => {
    this.initGraph(options)
  }

  refContainer = (container: HTMLDivElement) => {
    this.container = container
  }

  render() {
    return (
      <div className="rotating-app">
        <div className="app-side">
          <Settings onChange={this.onSettingChanged} />
        </div>
        <div className="app-content" ref={this.refContainer} />
      </div>
    )
  }
}

const root = createRoot(document.getElementById('container')!)
root.render(<Example />)
window.addEventListener('pagehide', () => root.unmount(), { once: true })

Configuration

Resizing

Property Name Type Default Value Required Description
enabled boolean false Whether resizing of nodes is supported
minWidth number 0 Minimum resizing width
minHeight number 0 Minimum resizing height
maxWidth number Infinity Maximum resizing width
maxHeight number Infinity Maximum resizing height
orthogonal boolean true Whether to show intermediate resizing points
restrict boolean false Whether resizing boundaries can exceed canvas edges
autoScroll boolean true Whether to automatically scroll the canvas when dragging exceeds its bounds
preserveAspectRatio boolean false Whether to maintain the aspect ratio during resizing
allowReverse boolean true Whether to allow control points to drag in reverse when reaching minimum width or height

The above configuration supports dynamic modification using functions as well:

new Transform({
  resizing: {
    enabled: true,
    orthogonal(node: Node) {
      const { enableOrthogonal } = node.getData()
      return enableOrthogonal
    },
  },
})

Rotating

Property Name Type Default Value Required Description
enabled boolean false Whether rotating of nodes is supported
grid number 15 Angle of rotation per step

The above configuration also supports dynamic modification using functions:

new Transform({
  rotating: {
    enabled: true,
    grid() {
      return 30
    },
  },
})

API

graph.createTransformWidget(node: Node)

Creates a transform control for the node.

graph.clearTransformWidgets()

Clears all transform controls.

Events

Event Name Parameter Type Description
node:resize { e: Dom.MouseDownEvent; x: number; y: number; node: Node; view: NodeView } Triggered when resizing starts
node:resizing { e: Dom.MouseMoveEvent; x: number; y: number; node: Node; view: NodeView } Triggered during resizing
node:resized { e: Dom.MouseUpEvent; x: number; y: number; node: Node; view: NodeView } Triggered after resizing
node:rotate { e: Dom.MouseDownEvent; x: number; y: number; node: Node; view: NodeView } Triggered when rotation starts
node:rotating { e: Dom.MouseMoveEvent; x: number; y: number; node: Node; view: NodeView } Triggered during rotation
node:rotated { e: Dom.MouseUpEvent; x: number; y: number; node: Node; view: NodeView } Triggered after rotation
graph.on('node:rotated', ({ node }) => {
  console.log(node.angle())
})

// We can also listen to events on the plugin instance
transform.on('node:rotated', ({ node }) => {
  console.log(node.angle())
})
© Copyright 2026 Ant Group Co., Ltd..备案号:京ICP备15032932号-38
Site search
Documentation and examplesType to start searching

Search documentation, APIs, and examples

↑↓Select↵OpenEscClose