+
+## Configuration
+
+### color
+
+The background color, supporting all [CSS background-color](https://developer.mozilla.org/en-US/docs/Web/CSS/background-color) property values, such as:
+
+- `red`
+- `#f5f5f5`
+- `rgba(255, 255, 128, 0.5)`
+- `hsla(50, 33%, 25%, 0.75)`
+- `radial-gradient(ellipse at center, red, green)`
+
+### image
+
+The URL address of the background image. The default value is `undefined`, indicating no background image.
+
+### position
+
+The position of the background image, supporting all [CSS background-position](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) property values, with a default value of `'center'`.
+
+### size
+
+The size of the background image, supporting all [CSS background-size](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) property values, with a default value of `'auto auto'`.
+
+### repeat
+
+The repeat mode of the background image, supporting all [CSS background-repeat](https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat) property values, with a default value of `'no-repeat'`.
+
+Additionally, the following predefined values are supported:
+
+- `watermark`: Watermark effect.
+- `flip-x`: Flip the background image horizontally.
+- `flip-y`: Flip the background image vertically.
+- `flip-xy`: Flip the background image both horizontally and vertically.
+
+### opacity
+
+The opacity of the background, with a value range of `[0, 1]`, and a default value of `1`.
+
+### quality
+
+The quality of the background image, with a value range of `[0, 1]`, and a default value of `1`.
+
+### angle
+
+The rotation angle of the watermark, only valid when [repeat](#repeat) is `'watermark'`, with a default value of `20`.
+
+## Methods
+
+### drawBackground(...)
+
+```ts
+drawBackground(options?: Options): this
+```
+
+Redraw the background.
+
+| Name | Type | Required | Default Value | Description |
+| ---------------- | ------ | :------: | ------------- | ------------------ |
+| options.color | string | | - | Background color. |
+| options.image | string | | - | Background image address. |
+| options.position | string | | - | Background image position. |
+| options.size | string | | - | Background image size. |
+| options.repeat | string | | - | Background image repeat mode. |
+| options.opacity | string | | - | Background image opacity. |
+
+### updateBackground()
+
+```ts
+updateBackground(): this
+```
+
+Update the background.
+
+### clearBackground()
+
+```ts
+clearBackground(): this
+```
+
+Clear the background.
+
+## Custom Image Repeat Mode
+
+In addition to the predefined values supported by [repeat](#repeat), you can also customize the image repeat mode.
+
+```ts
+function watermark(img, options) {
+ const width = img.width
+ const height = img.height
+ const canvas = document.createElement('canvas')
+
+ canvas.width = width * 3
+ canvas.height = height * 3
+
+ const ctx = canvas.getContext('2d')!
+ const angle = options.angle != null ? -options.angle : -20
+ const radians = Angle.toRad(angle)
+ const stepX = canvas.width / 4
+ const stepY = canvas.height / 4
+
+ for (let i = 0; i < 4; i += 1) {
+ for (let j = 0; j < 4; j += 1) {
+ if ((i + j) % 2 > 0) {
+ ctx.setTransform(1, 0, 0, 1, (2 * i - 1) * stepX, (2 * j - 1) * stepY)
+ ctx.rotate(radians)
+ ctx.drawImage(img, -width / 2, -height / 2, width, height)
+ }
+ }
+ }
+
+ return canvas
+}
+
+Graph.registerBackground('watermark', watermark)
+```
\ No newline at end of file
diff --git a/sites/x6-sites/docs/api/graph/coordinate.en.md b/sites/x6-sites/docs/api/graph/coordinate.en.md
new file mode 100644
index 00000000000..b4e7993276b
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/coordinate.en.md
@@ -0,0 +1,96 @@
+---
+title: Coordinate Systems
+order: 7
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/graph
+---
+
+## Demo
+
+
+
+In position calculations, we often need to perform coordinate conversions. In X6, there are two coordinate systems: the local canvas coordinate system `local` and the graph coordinate system `graph`. Sometimes, we also need to involve the browser coordinate system. Here's a unified explanation:
+
+- `local`: The local canvas coordinate system, which defaults to being consistent with the `graph` coordinate system but will change with canvas scaling and translation. All node coordinates in the canvas are based on the `local` coordinate system.
+- `graph`: The graph coordinate system, which is the canvas viewport we see and will not change with canvas scaling and translation.
+- `client`: The browser coordinate system, where `e.clientX` and `e.clientY` in mouse events are relative to the browser coordinate system.
+- `page`: The page coordinate system, which considers page horizontal and vertical scrolling compared to `client`. `e.pageX` and `e.pageY` in mouse events are relative to the page coordinate system.
+
+## Methods
+
+### pageToLocal(...)
+
+```ts
+pageToLocal(rect: Rectangle.RectangleLike): Rectangle
+pageToLocal(x: number, y: number, width: number, height: number): Rectangle
+pageToLocal(p: Point.PointLike): Point
+pageToLocal(x: number, y: number): Point
+```
+
+Converts page coordinates to local canvas coordinates.
+
+### localToPage(...)
+
+```ts
+localToPage(rect: Rectangle.RectangleLike): Rectangle
+localToPage(x: number, y: number, width: number, height: number): Rectangle
+localToPage(p: Point.PointLike): Point
+localToPage(x: number, y: number): Point
+```
+
+Converts local canvas coordinates to page coordinates.
+
+### clientToLocal(...)
+
+```ts
+clientToLocal(rect: Rectangle.RectangleLike): Rectangle
+clientToLocal(x: number, y: number, width: number, height: number): Rectangle
+clientToLocal(p: Point.PointLike): Point
+clientToLocal(x: number, y: number): Point
+```
+
+Converts browser coordinates to local canvas coordinates.
+
+### localToClient(...)
+
+```ts
+localToClient(rect: Rectangle.RectangleLike): Rectangle
+localToClient(x: number, y: number, width: number, height: number): Rectangle
+localToClient(p: Point.PointLike): Point
+localToClient(x: number, y: number): Point
+```
+
+Converts local canvas coordinates to browser coordinates.
+
+### localToGraph(...)
+
+```ts
+localToGraph(rect: Rectangle.RectangleLike): Rectangle
+localToGraph(x: number, y: number, width: number, height: number): Rectangle
+localToGraphPoint(p: Point.PointLike): Point
+localToGraphPoint(x: number, y: number): Point
+```
+
+Converts local canvas coordinates to graph coordinates.
+
+### graphToLocal(...)
+
+```ts
+graphToLocal(rect: Rectangle.RectangleLike): Rectangle
+graphToLocal(x: number, y: number, width: number, height: number): Rectangle
+graphToLocal(p: Point.PointLike): Point
+graphToLocal(x: number, y: number): Point
+```
+
+Converts graph coordinates to local canvas coordinates.
+
+### snapToGrid(...)
+
+```ts
+snapToGrid(p: Point.PointLike): Point
+snapToGrid(x: number, y: number): Point
+```
+
+Convert browser coordinates to canvas [local coordinates](#clienttolocal) and align to the canvas grid.
diff --git a/sites/x6-sites/docs/api/graph/graph.en.md b/sites/x6-sites/docs/api/graph/graph.en.md
new file mode 100644
index 00000000000..60694d310f0
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/graph.en.md
@@ -0,0 +1,41 @@
+---
+title: Graph
+order: 0
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/graph
+---
+
+## Configuration
+
+```ts
+new Graph(options: Options)
+```
+
+| Option | Type | Required | Description | Default Value |
+| --- | --- | :-: | --- | --- |
+| container | `HTMLElement` | ✓ | The container of the canvas. | |
+| width | `number` | | The width of the canvas, defaults to the container width. | - |
+| height | `number` | | The height of the canvas, defaults to the container height. | - |
+| scaling | `{ min?: number, max?: number }` | | The minimum and maximum zoom levels of the canvas. | `{ min: 0.01, max: 16 }` |
+| [autoResize](/en/docs/tutorial/basic/graph#canvas-size) | `boolean \| Element \| Document` | | Whether to listen to container size changes and automatically update the canvas size. | `false` |
+| [panning](/en/docs/api/graph/panning) | `boolean \| PanningManager.Options` | | Whether the canvas can be panned, defaults to disabled. | `false` |
+| [mousewheel](/en/docs/api/graph/mousewheel) | `boolean \| MouseWheel.Options` | | Whether the mouse wheel can zoom, defaults to disabled. | `false` |
+| [grid](/en/docs/api/graph/grid) | `boolean \| number \| GridManager.Options` | | The grid, defaults to a 10px grid but does not draw the grid background. | `false` |
+| [background](/en/docs/api/graph/background) | `false \| BackgroundManager.Options` | | The background, defaults to not drawing the background. | `false` |
+| [translating](/en/docs/api/interacting/interaction#moving-range) | `Translating.Options` | | Restricts node movement. | `{ restrict: false }` |
+| [embedding](/en/docs/api/interacting/interaction#embedding) | `boolean \| Embedding.Options` | | Whether to enable nested nodes, defaults to disabled. | `false` |
+| [connecting](/en/docs/api/interacting/interaction#connecting) | `Connecting.Options` | | The connection options. | `{ snap: false, ... }` |
+| [highlighting](/en/docs/api/interacting/interaction#highlighting) | `Highlighting.Options` | | The highlighting options. | `{...}` |
+| [interacting](/en/docs/api/interacting/interaction#restrictions) | `Interacting.Options` | | Customizes the interaction behavior of nodes and edges. | `{ edgeLabelMovable: false }` |
+| [magnetThreshold](/en/docs/api/graph/view#magnetthreshold) | `number \| onleave` | | The number of times the mouse can move before triggering a connection, or set to `onleave` to trigger a connection when the mouse leaves an element. | `0` |
+| [moveThreshold](/en/docs/api/graph/view#movethreshold) | `number` | | The number of times the mouse can move before triggering a `mousemove` event. | `0` |
+| [clickThreshold](/en/docs/api/graph/view#clickthreshold) | `number` | | When the mouse moves more than the specified number of times, the mouse click event will not be triggered. | `0` |
+| [preventDefaultContextMenu](/en/docs/api/graph/view#preventdefaultcontextmenu) | `boolean` | | Whether to disable the browser's default right-click menu. | `true` |
+| [preventDefaultBlankAction](/en/docs/api/graph/view#preventdefaultblankaction) | `boolean` | | Whether to disable the default mouse behavior when clicking on a blank area of the canvas. | `true` |
+| [async](/en/docs/api/graph/view#async) | `boolean` | | Whether to render asynchronously. | `true` |
+| [virtual](/en/docs/api/graph/view#virtual) | `boolean` | | Whether to only render the visible area of the canvas. | `false` |
+| [onPortRendered](/en/docs/api/graph/view#onportrendered) | `(args: OnPortRenderedArgs) => void` | | The callback triggered when a port is rendered. | - |
+| [onEdgeLabelRendered](/en/docs/api/graph/view#onedgelabelrendered) | `(args: OnEdgeLabelRenderedArgs) => void` | | The callback triggered when an edge label is rendered. | - |
+| [createCellView](/en/docs/api/graph/view#createcellview) | `(cell: Cell) => CellView \| null \| undefined` | | Customizes the view of a cell. | - |
\ No newline at end of file
diff --git a/sites/x6-sites/docs/api/graph/grid.en.md b/sites/x6-sites/docs/api/graph/grid.en.md
new file mode 100644
index 00000000000..38ec4a43061
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/grid.en.md
@@ -0,0 +1,218 @@
+---
+title: Grid
+order: 2
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+---
+
+The grid is the smallest unit of rendering/moving nodes. The default grid size is `10px`. When rendering nodes, it means aligning to the grid with `10` as the minimum unit, such as a node with a position of `{ x: 24, y: 38 }` will be rendered at `{ x: 20, y: 40 }` on the canvas. When moving nodes, it means the minimum distance of each move is `10px`.
+
+## Demo
+
+
+
+## Configuration
+
+### size
+
+You can set the grid size when creating the canvas through the following configuration.
+
+```ts
+const graph = new Graph({
+ grid: 10,
+})
+
+// Equivalent to
+const graph = new Graph({
+ grid: {
+ size: 10,
+ },
+})
+```
+
+### type
+
+The grid is invisible by default. You can enable grid drawing when creating the canvas through the following configuration.
+
+```ts
+const graph = new Graph({
+ grid: true, // Grid size is 10px and draw the grid
+})
+
+// Equivalent to
+const graph = new Graph({
+ grid: {
+ size: 10, // Grid size is 10px
+ visible: true, // Draw the grid, default is dot type
+ },
+})
+```
+
+We have four built-in grid types, which can be specified through the `type` option, with a default value of `dot`. You can also configure the grid style through the `args` option.
+
+#### dot (default)
+
+Dot grid.
+
+```ts
+new Graph({
+ container: this.container,
+ grid: {
+ visible: true,
+ type: 'dot',
+ args: {
+ color: '#a0a0a0', // Grid point color
+ thickness: 1, // Grid point size
+ },
+ },
+})
+```
+
+#### fixedDot
+
+Fixed dot grid with a fixed point size. When the canvas zoom ratio is less than `1`, the grid point size scales with the canvas zoom ratio. When the canvas zoom ratio is greater than `1`, the grid point size is the given `thickness` value.
+
+```ts
+new Graph({
+ container: this.container,
+ grid: {
+ visible: true,
+ size: 10,
+ type: 'fixedDot',
+ args: {
+ color: '#a0a0a0', // Grid point color
+ thickness: 2, // Grid point size
+ },
+ },
+})
+
+graph.scale(10, 10)
+```
+
+#### mesh
+
+Mesh grid.
+
+```ts
+new Graph({
+ container: this.container,
+ grid: {
+ visible: true,
+ type: 'mesh',
+ args: {
+ color: '#ddd', // Grid line color
+ thickness: 1, // Grid line width
+ },
+ },
+})
+```
+
+#### doubleMesh
+
+Double mesh grid.
+
+```ts
+const graph = new Graph({
+ grid: {
+ size: 10,
+ visible: true,
+ type: 'doubleMesh',
+ args: [
+ {
+ color: '#eee', // Main grid line color
+ thickness: 1, // Main grid line width
+ },
+ {
+ color: '#ddd', // Secondary grid line color
+ thickness: 1, // Secondary grid line width
+ factor: 4, // Main and secondary grid line interval
+ },
+ ],
+ },
+})
+```
+
+## Methods
+
+### getGridSize()
+
+```ts
+getGridSize(): number
+```
+
+Get the grid size.
+
+### setGridSize()
+
+```ts
+setGridSize(gridSize: number): this
+```
+
+Set the grid size.
+
+### showGrid()
+
+```ts
+showGrid(): this
+```
+
+Show the grid.
+
+### hideGrid()
+
+```ts
+hideGrid(): this
+```
+
+Hide the grid.
+
+### clearGrid()
+
+```ts
+clearGrid(): this
+```
+
+Clear the grid.
+
+### drawGrid(...)
+
+```ts
+drawGrid(options?: DrawGridOptions): this
+```
+
+Redraw the grid.
+
+| Name | Type | Required | Default | Description |
+| --- | --- | :-: | --- | --- |
+| type | string | | `dot` | Grid type. For details, please refer to [here](/en/docs/api/registry/grid). |
+| args | object | | - | Grid parameters corresponding to the grid type. |
+
+## Custom Grid
+
+Here's an example of registering a red dot grid:
+
+```ts
+Graph.registerGrid('red-dot', {
+ color: 'red',
+ thickness: 1,
+ markup: 'rect',
+ update(elem, options) {
+ const width = options.thickness * options.sx
+ const height = options.thickness * options.sy
+ Dom.attr(elem, {
+ width,
+ height,
+ rx: width,
+ ry: height,
+ fill: options.color,
+ })
+ },
+})
+
+const graph = new Graph({
+ grid: {
+ type: 'red-dot',
+ },
+})
+```
diff --git a/sites/x6-sites/docs/api/graph/mousewheel.en.md b/sites/x6-sites/docs/api/graph/mousewheel.en.md
new file mode 100644
index 00000000000..0a241bf864e
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/mousewheel.en.md
@@ -0,0 +1,123 @@
+---
+title: Mousewheel
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/graph
+---
+
+## Demonstration
+
+> Hold down the `Command` key and use the mouse wheel to zoom in/out of the canvas.
+
+
+
+## Configuration
+
+You can use the `mousewheel` configuration to zoom in/out of the canvas, often used in combination with modifier keys. The usage is as follows:
+
+```ts
+const graph = new Graph({
+ mousewheel: {
+ enabled: true,
+ modifiers: ['ctrl', 'meta'],
+ },
+})
+```
+
+Supported options are as follows:
+
+```ts
+interface MouseWheelOptions {
+ enabled?: boolean
+ global?: boolean
+ factor?: number
+ zoomAtMousePosition?: boolean
+ modifiers?: string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null
+ guard?: (this: Graph, e: WheelEvent) => boolean
+}
+```
+
+### enabled
+
+Whether to enable mouse wheel zooming interaction.
+
+### factor
+
+The zoom factor. Defaults to `1.2`.
+
+### zoomAtMousePosition
+
+Whether to zoom in/out at the mouse position. Defaults to `true`.
+
+### global
+
+Whether to bind the wheel event globally. If set to `true`, the wheel event is bound to the `Document`, otherwise it is bound to the canvas container. Defaults to `false`.
+
+### modifiers
+
+Modifier keys (`alt`, `ctrl`, `meta`, `shift`), which can be set to resolve conflicts between default wheel behavior and canvas zooming. Modifier keys support the following formats:
+
+- `alt` represents pressing the `alt` key.
+- `[alt, ctrl]` represents pressing either `alt` or `ctrl`.
+- `alt|ctrl` represents pressing either `alt` or `ctrl`.
+- `alt&ctrl` represents pressing both `alt` and `ctrl` simultaneously.
+- `alt|ctrl&shift` represents pressing both `alt` and `shift` simultaneously or both `ctrl` and `shift` simultaneously.
+
+### guard
+
+Determines whether a wheel event should be handled, returning `false` to ignore the event.
+
+```ts
+new Graph({
+ mousewheel: {
+ enabled: true,
+ guard(e: WheelEvent) {
+ if (e.altKey) {
+ // Ignore all wheel events when the alt key is pressed
+ return false
+ }
+ return true
+ },
+ },
+})
+```
+
+## Methods
+
+### isMouseWheelEnabled()
+
+```ts
+isMouseWheelEnabled(): boolean
+```
+
+Returns whether mouse wheel zooming is enabled.
+
+### enableMouseWheel()
+
+```ts
+enableMouseWheel(): this
+```
+
+Enables mouse wheel zooming.
+
+### disableMouseWheel()
+
+```ts
+disableMouseWheel(): this
+```
+
+Disables mouse wheel zooming.
+
+### toggleMouseWheel(...)
+
+```ts
+toggleMouseWheel(enabled?: boolean): this
+```
+
+Toggles the enabled state of mouse wheel zooming.
+
+| Name | Type | Required | Default | Description |
+| --- | --- | :-: | --- | --- |
+| enabled | boolean | | - | Whether to enable mouse wheel zooming, toggles the state if not provided. |
diff --git a/sites/x6-sites/docs/api/graph/panning.en.md b/sites/x6-sites/docs/api/graph/panning.en.md
new file mode 100644
index 00000000000..9b1a67736fa
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/panning.en.md
@@ -0,0 +1,112 @@
+---
+title: Panning
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/graph
+---
+
+## Demo
+
+
+
+## Configuration
+
+A regular canvas (without the `scroller` plugin) can support panning by enabling the `panning` option.
+
+:::warning{title=Note}
+Do not use `scroller` and `panning` simultaneously, as they conflict with each other in terms of interaction.
+:::
+
+```ts
+const graph = new Graph({
+ panning: true,
+})
+
+// Equivalent to
+const graph = new Graph({
+ panning: {
+ enabled: true,
+ },
+})
+```
+
+The supported options are as follows:
+
+```ts
+interface Options {
+ enabled?: boolean
+ modifiers?: ModifierKey
+ eventTypes?: ('leftMouseDown' | 'rightMouseDown' | 'mouseWheel', 'mouseWheelDown')[]
+}
+```
+
+### enabled
+
+Whether to enable canvas panning interaction.
+
+### modifiers
+
+Dragging may conflict with other operations, so you can set the `modifiers` parameter to specify a modifier key that needs to be pressed along with the mouse click to trigger canvas panning.
+
+The type definition of `ModifierKey` is as follows:
+
+```ts
+type ModifierKey = string | ('alt' | 'ctrl' | 'meta' | 'shift' | 'space')[] | null
+```
+
+It supports the following forms:
+
+- `alt` represents pressing the `alt` key.
+- `[alt, ctrl]` represents pressing either the `alt` or `ctrl` key.
+- `alt|ctrl` represents pressing either the `alt` or `ctrl` key.
+- `alt&ctrl` represents pressing both the `alt` and `ctrl` keys simultaneously.
+- `alt|ctrl&shift` represents pressing both the `alt` and `shift` keys simultaneously or pressing both the `ctrl` and `shift` keys simultaneously.
+
+### eventTypes
+
+The interaction types that trigger canvas panning. It supports three forms or their combinations:
+
+- `leftMouseDown`: Dragging by pressing the left mouse button
+- `rightMouseDown`: Dragging by pressing the right mouse button
+- `mouseWheel`: Dragging by scrolling the mouse wheel
+- `mouseWheelDown`: Dragging by pressing the mouse wheel
+
+## Methods
+
+### isPannable()
+
+```ts
+isPannable(): boolean
+```
+
+Returns whether canvas panning interaction is enabled.
+
+### enablePanning()
+
+```ts
+enablePanning(): this
+```
+
+Enables canvas panning.
+
+### disablePanning()
+
+```ts
+disablePanning(): this
+```
+
+Disables canvas panning.
+
+### togglePanning(...)
+
+```ts
+togglePanning(enabled?: boolean): this
+```
+
+Toggles the enabled state of canvas panning. The parameter is as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|--------------|--------------------------------------------------|
+| enabled | boolean | | - | Whether to enable canvas panning, defaults to toggling the enabled state. |
diff --git a/sites/x6-sites/docs/api/graph/transform.en.md b/sites/x6-sites/docs/api/graph/transform.en.md
new file mode 100644
index 00000000000..27da4e089da
--- /dev/null
+++ b/sites/x6-sites/docs/api/graph/transform.en.md
@@ -0,0 +1,350 @@
+---
+title: Viewport Transformation
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/graph
+---
+
+## Configuration
+
+### scaling
+
+Configure the minimum or maximum zoom level of the canvas through the scaling configuration.
+
+```ts
+new Graph({
+ scaling: {
+ min: 0.05, // default value is 0.01
+ max: 12, // default value is 16
+ },
+})
+```
+
+## Methods
+
+### resize(...)
+
+```ts
+resize(width?: number, height?: number): this
+```
+
+Set the canvas size.
+
+| Name | Type | Required | Default Value | Description |
+| ------ | ------ | :--: | ------ | ------------------------------ |
+| width | number | | | Canvas width, remains unchanged if not provided. |
+| height | number | | | Canvas height, remains unchanged if not provided. |
+
+### zoom(...)
+
+```ts
+zoom(): number
+```
+
+Get the canvas zoom ratio.
+
+```ts
+zoom(factor: number, options?: ZoomOptions): this
+```
+
+Zoom the canvas.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| factor | number | ✓ | | Zoom ratio. |
+| options.absolute | boolean | | `false` | Whether to zoom absolutely. |
+| options.minScale | number | | - | Minimum zoom ratio. |
+| options.maxScale | number | | - | Maximum zoom ratio. |
+| options.scaleGrid | number | | - | Correct the zoom ratio to be an integer multiple of `scaleGrid`. |
+| options.center | Point.PointLike | | - | Zoom center. |
+
+When `options.absolute` is `true`, it means zooming the canvas to the value represented by `factor`. Otherwise, `factor` represents the zoom-in or zoom-out factor. When `factor` is a positive number, it means zooming in, and when it's a negative number, it means zooming out.
+
+### zoomTo(...)
+
+```ts
+zoomTo(factor: number, options?: ZoomOptions): this
+```
+
+Zoom the canvas to a specified ratio.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| factor | number | ✓ | | Zoom ratio. |
+| options.minScale | number | | - | Minimum zoom ratio. |
+| options.maxScale | number | | - | Maximum zoom ratio. |
+| options.scaleGrid | number | | - | Correct the zoom ratio to be an integer multiple of `scaleGrid`. |
+| options.center | Point.PointLike | | - | Zoom center. |
+
+### zoomToFit(...)
+
+```ts
+zoomToFit(options?: Options): this
+```
+
+Zoom the canvas content to fit the viewport.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| rect | Rectangle.RectangleLike | ✓ | | Rectangle area. |
+| options.padding | number \| `{ left: number, top: number, right: number, bottom: number }` | | - | Margin. |
+| options.contentArea | Rectangle.RectangleLike | | - | Content area, defaults to getting the canvas content area. |
+| options.viewportArea | Rectangle.RectangleLike | | - | Viewport area, defaults to getting the canvas viewport. |
+| options.scaleGrid | number | | - | Correct the zoom ratio to be an integer multiple of `scaleGrid`. |
+| options.minScale | number | | - | Minimum zoom ratio. |
+| options.maxScale | number | | - | Maximum zoom ratio. |
+| options.minScaleX | number | | - | Minimum zoom ratio in the X-axis direction. |
+| options.maxScaleX | number | | - | Maximum zoom ratio in the X-axis direction. |
+| options.minScaleY | number | | - | Minimum zoom ratio in the Y-axis direction. |
+| options.maxScaleY | number | | - | Maximum zoom ratio in the Y-axis direction. |
+| options.preserveAspectRatio | boolean | | `false` | Whether to preserve the aspect ratio. |
+| options.useCellGeometry | boolean | | `true` | Whether to use node/edge geometry information (Model) to calculate the bounding box. |
+
+### rotate(...)
+
+```ts
+rotate(): {
+ angle: number
+ cx?: number
+ cy?: number
+}
+```
+
+Get the canvas rotation angle and center.
+
+```ts
+rotate(angle: number, cx?: number, cy?: number): this
+```
+
+Rotate the canvas.
+
+| Name | Type | Required | Default Value | Description |
+| ----- | ------ | :--: | ------ | ----------------------------------- |
+| angle | number | ✓ | | Rotation angle. |
+| cx | number | | - | Rotation center x-coordinate, defaults to the canvas center. |
+| cy | number | | - | Rotation center y-coordinate, defaults to the canvas center. |
+
+### translate(...)
+
+```ts
+translate(): {
+ tx: number
+ ty: number
+}
+```
+
+Get the canvas translation.
+
+```ts
+translate(tx: number, ty: number): this
+```
+
+Translate the canvas.
+
+| Name | Type | Required | Default Value | Description |
+| ---- | ------ | :--: | ------ | ------------ |
+| tx | number | ✓ | | X-axis translation. |
+| ty | number | ✓ | | Y-axis translation. |
+
+### getContentArea(...)
+
+```ts
+getContentArea(options?: Transform.GetContentAreaOptions): Rectangle
+```
+
+Get the bounding box of the canvas content, represented in local coordinates.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| options.useCellGeometry | boolean | | `true` | Whether to use node/edge geometry information (Model) to calculate the content size. |
+
+### getContentBBox(...)
+
+```ts
+getContentBBox(options?: Transform.GetContentAreaOptions): Rectangle
+```
+
+Get the bounding box of the canvas content, represented in graph coordinates.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| options.useCellGeometry | boolean | | `true` | Whether to use node/edge geometry information (Model) to calculate the content size. |
+
+### center(...)
+
+```ts
+center(options?: CenterOptions): this
+```
+
+Align the canvas center with the viewport center.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+### centerPoint(...)
+
+```ts
+centerPoint(x?: number | null, y?: number | null, options?: CenterOptions): this
+```
+
+Align the point `(x, y)` (relative to the canvas) with the viewport center.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| x | number | | - | X-coordinate relative to the canvas. |
+| y | number | | - | Y-coordinate relative to the canvas. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+```ts
+graph.centerPoint(100, 200)
+graph.centerPoint(100, null, { padding: { left: 100 } })
+graph.centerPoint(null, 200, { padding: { left: 100 } })
+```
+
+### centerContent(...)
+
+```ts
+centerContent(options?: PositionContentOptions): this
+```
+
+Align the canvas content center with the viewport center.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+| options.useCellGeometry | boolean | | `true` | Whether to use node/edge geometry information (Model) to calculate the content area. |
+
+```ts
+graph.centerContent()
+graph.centerContent({ padding: { left: 100 } })
+```
+
+### centerCell(...)
+
+```ts
+centerCell(options?: CenterOptions): this
+```
+
+Align the node/edge center with the viewport center.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| cell | Cell | ✓ | | Node/edge. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+```ts
+graph.centerCell(cell)
+graph.centerCell(cell, { padding: { left: 100 } })
+```
+
+### positionContent(...)
+
+```ts
+positionContent(pos: Position, options?: PositionContentOptions): this
+```
+
+Align the canvas content bounding box position with the corresponding viewport position. For example, if `pos` is `'bottom-left'`, it means aligning the bottom-left corner of the content bounding box with the bottom-left corner of the viewport.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| pos | Position | ✓ | | Alignment position. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+| options.useCellGeometry | boolean | | `true` | Whether to use node/edge geometry information (Model) to calculate the content area. |
+
+Supported alignment positions:
+
+```ts
+type Position =
+ | 'center'
+ | 'top'
+ | 'top-right'
+ | 'top-left'
+ | 'right'
+ | 'bottom-right'
+ | 'bottom'
+ | 'bottom-left'
+ | 'left'
+```
+
+### positionCell(...)
+
+```ts
+positionCell(cell: Cell, pos: Direction, options?: CenterOptions): this
+```
+
+Align the node/edge bounding box position with the corresponding viewport position. For example, if `pos` is `'bottom-left'`, it means aligning the bottom-left corner of the node/edge bounding box with the bottom-left corner of the viewport.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| cell | Cell | ✓ | | Node/edge. |
+| pos | Position | ✓ | | Alignment position. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+```ts
+type Position =
+ | 'center'
+ | 'top'
+ | 'top-right'
+ | 'top-left'
+ | 'right'
+ | 'bottom-right'
+ | 'bottom'
+ | 'bottom-left'
+ | 'left'
+```
+
+### positionRect(...)
+
+```ts
+positionRect(rect: Rectangle.RectangleLike, pos: Direction, options?: CenterOptions): this
+```
+
+Align the rectangle position with the corresponding viewport position. For example, if `pos` is `'bottom-left'`, it means aligning the bottom-left corner of the rectangle with the bottom-left corner of the viewport.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| rect | Rectangle.RectangleLike | ✓ | | Rectangle area. |
+| pos | Position | ✓ | | Alignment position. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+```ts
+type Position =
+ | 'center'
+ | 'top'
+ | 'top-right'
+ | 'top-left'
+ | 'right'
+ | 'bottom-right'
+ | 'bottom'
+ | 'bottom-left'
+ | 'left'
+```
+
+### positionPoint(...)
+
+```ts
+positionPoint(point: Point.PointLike, x: number | string, y: number | string, options?: CenterOptions): this
+```
+
+Align the point `(x, y)` (relative to the canvas) with the corresponding viewport position.
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| point | Point.PointLike | ✓ | | Point to be aligned. |
+| x | number \| string | ✓ | | Viewport x-coordinate, supports percentage and negative values. |
+| y | number \| string | ✓ | | Viewport y-coordinate, supports percentage and negative values. |
+| options.padding | number \| Padding | | - | Margin, only effective in scroller canvas. |
+
+```ts
+// Align the top-left corner of the canvas with the point [100, 50] in the viewport
+graph.positionPoint({ x: 0, y: 0 }, 100, 50)
+
+// Align the point { x: 30, y: 80 } on the canvas with the point 25% from the left and 40px from the bottom of the viewport
+graph.positionPoint({ x: 30, y: 80 }, '25%', -40)
+
+// Align the point { x: 30, y: 80 } on the canvas with the point 25% from the right and 40px from the top of the viewport
+graph.positionPoint({ x: 30, y: 80 }, '-25%', 40)
+```
diff --git a/sites/x6-sites/docs/api/model/attrs.en.md b/sites/x6-sites/docs/api/model/attrs.en.md
new file mode 100644
index 00000000000..1b5e1381888
--- /dev/null
+++ b/sites/x6-sites/docs/api/model/attrs.en.md
@@ -0,0 +1,199 @@
+---
+title: Element Attributes
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/model
+---
+
+For native SVG attributes, there are many tutorials available online, such as the [SVG Attribute Reference](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) provided by MDN. Here, we will focus more on how to define and use special attributes. Special attributes provide more flexible and powerful functionality than native SVG attributes. When applying attributes, native attributes are directly passed to the corresponding element, while special attributes are further processed and converted into native attributes recognized by the browser before being passed to the corresponding element.
+
+## Relative Size and Position
+
+When customizing nodes or edges, setting the relative size of elements is a very common requirement. We provide a series of special attributes prefixed with `ref` in X6, which can be used to set the relative size of elements. These attributes are calculated based on the data size of nodes/edges, which means that all calculations do not rely on the browser's bbox calculation, so there are no performance issues.
+
+- [`refWidth`](/en/docs/api/registry/attr#refwidth) and [`refHeight`](/en/docs/api/registry/attr#refheight) set the element size.
+- [`refX`](/en/docs/api/registry/attr#refx) and [`refY`](/en/docs/api/registry/attr#refy) set the element position.
+- [`refCx`](/en/docs/api/registry/attr#refcx) and [`refCy`](/en/docs/api/registry/attr#refcy) set the center position of `
+
+## Label Position
+
+### Position
+
+We can specify the label's position using the `position.distance` option of the Label, with a default value of `0.5`, indicating that the label is positioned at the center of the edge's length. Depending on the value, the calculation of the label's position can be categorized into three cases.
+
+- When it is between `[0, 1]`, it indicates that the label is positioned at a relative length (proportion) from the starting point along the length direction.
+- A positive number indicates that the label is positioned at a distance from the starting point along the edge's length.
+- A negative number indicates that the label is positioned at a distance from the endpoint along the length direction.
+
+```ts
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '0.25',
+ },
+ },
+ position: {
+ distance: 0.25,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '150',
+ },
+ },
+ position: {
+ distance: 150,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '-100',
+ },
+ },
+ position: {
+ distance: -100,
+ },
+})
+```
+
+
+
+### Offset
+
+We can set the label's offset using the `position.offset` option of the Label, with a default value of `0`, indicating no offset. Depending on the value, the calculation of the label's offset can be categorized into three cases.
+
+- A positive number indicates an **absolute offset downwards perpendicular to the edge**.
+- A negative number indicates an **absolute offset upwards perpendicular to the edge**.
+- A coordinate object `{x: number; y: number }` indicates an **absolute offset in both `x` and `y` directions**.
+
+```ts
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: 'offset: 40',
+ },
+ },
+ position: {
+ distance: 0.66,
+ offset: 40,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: 'offset: -40',
+ },
+ },
+ position: {
+ distance: 0.66,
+ offset: -40,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: 'offset: { x: -40, y: 80 }',
+ },
+ },
+ position: {
+ distance: 0.66,
+ offset: {
+ x: -40,
+ y: 80,
+ },
+ },
+})
+```
+
+
+
+### Rotation
+
+We can set the label's rotation angle in the **clockwise direction** using the `position.angle` option of the Label, with a default value of `0`, indicating no rotation.
+
+**Options**
+
+- When `position.options.keepGradient` is `true`, the initial rotation angle of the label is the angle of the edge at the label's position, and subsequent `position.angle` settings are relative to that initial angle.
+- When `position.options.ensureLegibility` is `true`, an additional 180° rotation will be applied to the label if necessary to ensure the label text is more readable.
+
+```ts
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '70°\nkeepGradient',
+ },
+ },
+ position: {
+ distance: 0.05,
+ angle: 70,
+ options: {
+ keepGradient: true,
+ },
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '0°\nkeepGradient',
+ },
+ },
+ position: {
+ distance: 0.3,
+ options: {
+ keepGradient: true,
+ },
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '45°',
+ },
+ },
+ position: {
+ distance: 0.8,
+ angle: 45,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '135°',
+ },
+ },
+ position: {
+ distance: 0.9,
+ angle: 135,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '270°\nkeepGradient',
+ },
+ },
+ position: {
+ distance: 0.66,
+ offset: 80,
+ angle: 270,
+ options: {
+ keepGradient: true,
+ },
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ text: {
+ text: '270°\nkeepGradient\nensureLegibility',
+ },
+ },
+ position: {
+ distance: 0.66,
+ offset: -80,
+ angle: 270,
+ options: {
+ keepGradient: true,
+ ensureLegibility: true,
+ },
+ },
+})
+```
+
+
+
+## Label Style
+
+We can customize the label style using the `markup` and `attrs` options, supporting customization in two dimensions.
+
+**Method 1**: Globally override the default label definition when creating an Edge, affecting all labels.
+
+```ts
+const edge = graph.addEdge({
+ source: { x: 100, y: 40 },
+ target: { x: 400, y: 40 },
+ defaultLabel: {
+ markup: [
+ {
+ tagName: 'ellipse',
+ selector: 'bg',
+ },
+ {
+ tagName: 'text',
+ selector: 'txt',
+ },
+ ],
+ attrs: {
+ txt: {
+ fill: '#7c68fc',
+ textAnchor: 'middle',
+ textVerticalAnchor: 'middle',
+ },
+ bg: {
+ ref: 'txt',
+ refRx: '70%',
+ refRy: '80%',
+ stroke: '#7c68fc',
+ fill: 'white',
+ strokeWidth: 2,
+ },
+ },
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ txt: {
+ text: 'First',
+ },
+ },
+ position: {
+ distance: 0.3,
+ },
+})
+
+edge.appendLabel({
+ attrs: {
+ txt: {
+ text: 'Second',
+ },
+ },
+ position: {
+ distance: 0.7,
+ },
+})
+```
+
+
+
+**Method 2**: Override the default label definition when creating a single label, affecting only that label.
+
+```ts
+edge.appendLabel({
+ markup: [
+ {
+ tagName: 'circle',
+ selector: 'body',
+ },
+ {
+ tagName: 'text',
+ selector: 'label',
+ },
+ {
+ tagName: 'circle',
+ selector: 'asteriskBody',
+ },
+ {
+ tagName: 'text',
+ selector: 'asterisk',
+ },
+ ],
+ attrs: {
+ label: {
+ text: '½',
+ fill: '#000',
+ fontSize: 12,
+ textAnchor: 'middle',
+ textVerticalAnchor: 'middle',
+ pointerEvents: 'none',
+ },
+ body: {
+ ref: 'label',
+ fill: '#fff',
+ stroke: '#000',
+ strokeWidth: 1,
+ refR: 1,
+ refCx: 0,
+ refCy: 0,
+ },
+ asterisk: {
+ ref: 'label',
+ text: '*',
+ fill: '#ff0000',
+ fontSize: 8,
+ textAnchor: 'middle',
+ textVerticalAnchor: 'middle',
+ pointerEvents: 'none',
+ refX: 16.5,
+ refY: -2,
+ },
+ asteriskBody: {
+ ref: 'asterisk',
+ fill: '#fff',
+ stroke: '#000',
+ strokeWidth: 1,
+ refR: 1,
+ refCx: '50%',
+ refCy: '50%',
+ refX: 0,
+ refY: 0,
+ },
+ },
+})
+```
+
+
+
+## String Labels
+
+When setting the [default label](#default-label) using the [`updateLabels`](#default-label) option, adding labels becomes very simple, as shown in the following code.
+
+```ts
+// Specify label when creating a node
+const edge = graph.addEdge({
+ source,
+ target,
+ labels: [
+ {
+ attrs: { label: { text: 'edge label' } },
+ },
+ ],
+})
+
+// Reset labels
+edge.setLabels([
+ {
+ attrs: { label: { text: 'edge label' } },
+ },
+])
+
+// Append label
+edge.appendLabel({
+ attrs: { label: { text: 'edge label' } },
+})
+```
+
+The above code only sets the label text, but it looks complicated as we have to provide a deeply nested object `{ attrs: { label: { text: 'edge' } } }`. To simplify this, we provide a syntax sugar that allows direct input of string labels, making the above code even simpler.
+
+```ts
+const edge = graph.addEdge({
+ source,
+ target,
+ labels: ['edge label'],
+})
+
+edge.setLabels(['edge label'])
+
+edge.appendLabel('edge label')
+```
+
+This syntax sugar defines a static method `parseStringLabel` on `Edge`, which converts string labels into Label objects. The default implementation is as follows.
+
+```ts
+function parseStringLabel(label: string): Label {
+ return {
+ attrs: { label: { text: label } },
+ }
+}
+```
+
+It is important to note that this syntax sugar only applies to the system's default labels. This means that if you redefine the default label's `markup` using the `defaultLabel` option, you will also need to rewrite the `parseStringLabel` method to ensure the usability of string labels.
+
+```ts
+Edge.config({
+ defaultLabel: {
+ markup: [
+ {
+ tagName: 'rect',
+ selector: 'body',
+ },
+ {
+ tagName: 'text',
+ selector: 'my-label', // Here the default selector is modified.
+ },
+ ],
+ },
+})
+
+// You also need to redefine parseStringLabel to ensure the usability of string labels.
+Edge.parseStringLabel = (label: string) => {
+ return {
+ attrs: { 'my-label': { text: label } },
+ }
+}
+```
+
+## Single Label
+
+Most edges only have at most one label, so we define a [custom option](/en/docs/tutorial/basic/cell#custom-options) `label` for `Edge` to support passing a single label.
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ label: {
+ attrs: { label: { text: 'edge label' } },
+ },
+})
+```
+
+When only setting the label text, you can also use the string form of a single label.
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ label: 'edge label',
+})
+```
diff --git a/sites/x6-sites/docs/api/model/marker.en.md b/sites/x6-sites/docs/api/model/marker.en.md
new file mode 100644
index 00000000000..ed53c14e17d
--- /dev/null
+++ b/sites/x6-sites/docs/api/model/marker.en.md
@@ -0,0 +1,381 @@
+---
+title: Arrow
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/model
+---
+
+In the previous [tutorial](/en/docs/tutorial/basic/edge#using-arrows), we briefly introduced how to use the two special attributes [`sourceMarker`](/en/docs/api/registry/attr#sourcemarker) and [`targetMarker`](/en/docs/api/registry/attr#targetmarker) to specify the starting and ending arrows for edges. We demonstrated how to use built-in arrows and custom arrows. Next, we will first list the parameters for each built-in arrow, then provide a detailed explanation of how to use various SVG elements to customize arrows, and finally explain how to register custom arrows as built-in arrows.
+
+## Built-in Arrows
+
+Built-in arrows allow for the parameterization of commonly used arrow types. When using built-in arrows, you only need to specify the arrow name `name` and the corresponding parameters. The fill color `fill` and stroke color `stroke` default to inheriting from the edge, but can be overridden by specifying the `fill` and `stroke` properties.
+
+```ts
+edge.attr({
+ line: {
+ sourceMarker: 'block',
+ targetMarker: {
+ name: 'ellipse',
+ rx: 10, // x radius of the ellipse arrow
+ ry: 6, // y radius of the ellipse arrow
+ },
+ },
+})
+```
+
+
+
+Each built-in arrow has corresponding parameters, which will be introduced below.
+
+### block
+
+Solid arrow.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|---------|---------------|---------------------------------------------------------------------------------------------|
+| size | Number | 10 | Size of the arrow. |
+| width | Number | size | Width of the arrow; can use `size` directly when width and height are the same. |
+| height | Number | size | Height of the arrow; can use `size` directly when width and height are the same. |
+| offset | Number | 0 | Absolute offset along the edge direction. |
+| open | Boolean | false | Non-closed arrow. |
+| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `
+
+### circle
+
+Circular arrow.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|----------------------------------------------------------------------------------------------|
+| r | Number | 5 | Circle radius. |
+| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `
+
+Sometimes, the coordinates of the `d` attribute of the path element we obtain may not be standardized. If used directly as an arrow, it may result in positional deviation. Therefore, we provide the `normalizeMarker` utility method in the `Util` namespace to standardize the coordinates of `d`.
+
+**Method Signature**
+
+```ts
+Registry.Marker.normalize(d: string, offset: { x?: number; y?: number }): string
+Registry.Marker.normalize(d: string, offsetX?: number, offsetY?: number): string
+```
+
+| Parameter Name | Type | Description |
+|----------------|----------------------------|------------------------------------|
+| d | string | |
+| offset | { x?: number; y?: number } | Offset relative to the origin |
+| offsetX | number | x-axis offset relative to the origin |
+| offsetY | number | y-axis offset relative to the origin |
+
+Comparing the starting and ending arrows below, it is clear that the starting arrow has a certain offset. After processing with `normalizeMarker`, the position of the ending arrow is corrected.
+
+```ts
+const d =
+ 'M4.834,4.834L4.833,4.833c-5.889,5.892-5.89,15.443,0.001,21.334s15.44,5.888,21.33-0.002c5.891-5.891,5.893-15.44,0.002-21.33C20.275-1.056,10.725-1.056,4.834,4.834zM25.459,5.542c0.833,0.836,1.523,1.757,2.104,2.726l-4.08,4.08c-0.418-1.062-1.053-2.06-1.912-2.918c-0.859-0.859-1.857-1.494-2.92-1.913l4.08-4.08C23.7,4.018,24.622,4.709,25.459,5.542zM10.139,20.862c-2.958-2.968-2.959-7.758-0.001-10.725c2.966-2.957,7.756-2.957,10.725,0c2.954,2.965,2.955,7.757-0.001,10.724C17.896,23.819,13.104,23.817,10.139,20.862zM5.542,25.459c-0.833-0.837-1.524-1.759-2.105-2.728l4.081-4.081c0.418,1.063,1.055,2.06,1.914,2.919c0.858,0.859,1.855,1.494,2.917,1.913l-4.081,4.081C7.299,26.982,6.379,26.292,5.542,25.459zM8.268,3.435l4.082,4.082C11.288,7.935,10.29,8.571,9.43,9.43c-0.858,0.859-1.494,1.855-1.912,2.918L3.436,8.267c0.58-0.969,1.271-1.89,2.105-2.727C6.377,4.707,7.299,4.016,8.268,3.435zM22.732,27.563l-4.082-4.082c1.062-0.418,2.061-1.053,2.919-1.912c0.859-0.859,1.495-1.857,1.913-2.92l4.082,4.082c-0.58,0.969-1.271,1.891-2.105,2.728C24.623,26.292,23.701,26.983,22.732,27.563z'
+
+graph.addEdge({
+ source: { x: 160, y: 40 },
+ target: { x: 420, y: 40 },
+ attrs: {
+ line: {
+ stroke: '#31d0c6',
+ sourceMarker: {
+ d,
+ tagName: 'path',
+ },
+ targetMarker: {
+ tagName: 'path',
+ d: Util.normalizeMarker(d),
+ },
+ },
+ },
+})
+```
+
+
+
+In addition to `
+
+It is important to note that when using `
+
+## Registering Arrows
+
+Registration refers to the process of registering a method for generating arrows within the X6 system, which we call an arrow factory method. Once registered, the arrow can be used just like built-in arrows.
+
+When do we need to register arrows?
+
+- To unify the abstraction of classic arrows and extract key parameters, allowing parameters to influence the rendering of arrows for multi-scenario reuse, as described in the [Built-in Arrows](#built-in-arrows) section.
+- To provide a unified definition for complex arrows, allowing for a single definition to be reused in multiple places, such as arrows with complex properties and style configurations.
+- To enhance code readability through semantic arrow names and parameter names. For example, we can replace the `xlink:href` attribute of the `
+
+### fill
+
+When the provided `fill` attribute value is an object, it indicates using a gradient fill; otherwise, it uses a string color fill.
+
+```ts
+rect.attr('body/fill', {
+ type: 'linearGradient',
+ stops: [
+ { offset: '0%', color: '#E67E22' },
+ { offset: '20%', color: '#D35400' },
+ { offset: '40%', color: '#E74C3C' },
+ { offset: '60%', color: '#C0392B' },
+ { offset: '80%', color: '#F39C12' },
+ ],
+})
+```
+
+### filter
+
+When the provided `filter` attribute value is an object, it indicates using a custom filter; otherwise, it uses the native string form (e.g., `"url(#myfilter)"`).
+
+```ts
+rect.attr('body/filter', {
+ name: 'dropShadow',
+ args: {
+ dx: 2,
+ dy: 2,
+ blur: 3,
+ },
+})
+```
+
+### stroke
+
+When the provided `stroke` attribute value is an object, it indicates using a gradient fill; otherwise, it uses a string color fill. The usage is the same as the [fill](#fill) attribute.
+
+### style
+
+Applies inline CSS styles to the specified element using jQuery's [`css()`](https://api.jquery.com/css) method.
+
+### html
+
+Sets the innerHTML of the specified element using jQuery's [`html()`](https://api.jquery.com/html) method.
+
+### title
+
+Adds a `
+
+### textPath
+
+Only applicable to `
+
+### connection
+
+Only applicable to the `
+
+You can specify the connection point when creating an edge:
+
+```ts
+const edge = graph.addEdge({
+ source: {
+ cell: 'source-id',
+ connectionPoint: {
+ name: 'boundary',
+ args: {
+ sticky: true,
+ },
+ },
+ },
+ target: {
+ cell: 'target-id',
+ connectionPoint: 'boundary', // Simplified writing when there are no parameters
+ },
+})
+```
+
+After creation, you can modify the connection point by calling the `edge.setSource` and `edge.setTarget` methods:
+
+```ts
+edge.setSource({
+ cell: 'source-id',
+ connectionPoint: {
+ name: 'boundary',
+ args: {
+ sticky: true,
+ },
+ },
+})
+```
+
+When creating a canvas, you can set the global default connection point through the `connecting` option:
+
+```ts
+new Graph({
+ connecting: {
+ connectionPoint: {
+ name: 'boundary',
+ args: {
+ sticky: true,
+ },
+ },
+ },
+})
+```
+
+Simplified writing when there are no parameters:
+
+```ts
+new Graph({
+ connecting: {
+ connectionPoint: 'boundary',
+ },
+})
+```
+
+## Built-in Connection Points
+
+### boundary
+
+Automatically recognize the boundary of the linked shape and calculate the intersection point of the reference line and the anchor point (Anchor). For example, an `
+
+### smooth
+
+A smooth connector, connects the start point, route point, and end point with a cubic Bezier curve.
+
+Supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|-----------------|-----------------|----------|---------|--------------------------------------------------------------|
+| raw | boolean | No | `false` | Whether to return a `Path` object, default value is `false` returns a serialized string. |
+| direction | `H` \| `V` | No | - | Keep horizontal connection or keep vertical connection, not set will dynamically calculate based on the start and end points. |
+
+For example:
+
+```ts
+graph.addEdge({
+ source: rect1,
+ target: rect2,
+ vertices: [
+ { x: 100, y: 200 },
+ { x: 300, y: 120 },
+ ],
+ connector: 'smooth',
+})
+```
+
+
+
+### rounded
+
+A rounded connector, connects the start point, route point, and end point with a straight line and uses an arc to connect the line segments (fillet).
+
+Supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|---------------|:-------:|---------|-------------------------------------------------------------|
+| radius | number | No | `10` | Fillet radius. |
+| raw | boolean | No | `false` | Whether to return a `Path` object, default value is `false` returns a serialized string. |
+
+For example:
+
+```ts
+graph.addEdge({
+ source: rect1,
+ target: rect2,
+ vertices: [
+ { x: 100, y: 200 },
+ { x: 300, y: 120 },
+ ],
+ connector: {
+ name: 'rounded',
+ args: {
+ radius: 10,
+ },
+ },
+})
+```
+
+
+
+### jumpover
+
+A jumpover connector, connects the start point, route point, and end point with a straight line and uses a jump symbol to connect the intersecting edges.
+
+Supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|-------------------------------|:-------:|---------|-------------------------------------------------------------|
+| type | 'arc' \| 'gap' \| 'cubic' | No | `'arc'` | Jump type. |
+| size | number | No | `5` | Jump size. |
+| radius | number | No | `0` | Fillet radius. |
+| raw | boolean | No | `false` | Whether to return a `Path` object, default value is `false` returns a serialized string. |
+
+
+
+## Custom Connectors
+
+A connector is a function with the following signature, returning a `Path` object or a serialized string.
+
+```ts
+export type Definition
diff --git a/sites/x6-sites/docs/api/registry/edge-anchor.en.md b/sites/x6-sites/docs/api/registry/edge-anchor.en.md
new file mode 100644
index 00000000000..971e4658940
--- /dev/null
+++ b/sites/x6-sites/docs/api/registry/edge-anchor.en.md
@@ -0,0 +1,92 @@
+---
+title: Edge Anchor
+order: 9
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/registry
+---
+
+When an edge connects to another edge, you can use EdgeAnchor to specify the anchor point on the connected edge. The anchor point, along with the connection point [ConnectionPoint](/en/docs/api/registry/connection-point), determines the starting and ending points of the edge.
+
+- Starting point: Draw a reference line from the first path point or the center of the target node (if there are no path points) to the anchor point of the source node, and then calculate the intersection point of the reference line and the graph according to the intersection calculation method specified by [connectionPoint](/en/docs/api/registry/connection-point). This intersection point is the starting point of the edge.
+- Ending point: Draw a reference line from the last path point or the center of the source node (if there are no path points) to the anchor point of the target node, and then calculate the intersection point of the reference line and the graph according to the intersection calculation method specified by [connectionPoint](/en/docs/api/registry/connection-point). This intersection point is the ending point of the edge.
+
+X6 provides the following built-in anchor point definitions:
+
+- [ratio](#ratio) The default value, where the anchor point is located at a specified proportion of the connected edge.
+- [length](#length) The anchor point is located at a specified length from the connected edge.
+- [closest](#closest) Uses the point closest to the reference point as the anchor point.
+- [orth](#orth) Orthogonal anchor point.
+
+
+
+## Built-in Anchor Points
+
+### ratio
+
+The anchor point is located at a specified proportion of the connected edge. Supports the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|----------------|---------|--------------|-----------------------|
+| ratio | number | No | `0.5` | The proportion of the edge length from the starting point, defaulting to the center of the edge length. |
+
+### length
+
+The anchor point is located at a specified length from the connected edge. Supports the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|----------------|---------|--------------|-----------------------|
+| length | number | No | `20` | The length from the starting point of the edge, defaulting to 20px from the starting point. |
+
+### closest
+
+Uses the point closest to the reference point as the anchor point.
+
+### orth
+
+Orthogonal anchor point. Supports the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|----------------|---------|--------------|-----------------------|
+| fallbackAt | number \| string | No | `undefined` | When there is no orthogonal point, use the point specified by `fallbackAt` as the anchor point.
+
+### segments
+
+The line segment tool renders a tool bar at the center of each line segment of the edge, allowing you to drag the tool bar to adjust the positions of the path points at both ends of the segment. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|----------------------|---------|---------------|-----------------------------------------------------------------------------------------------------------------------|
+| attrs | object | `object` | Attributes of the element. |
+| precision | number | `0.5` | The tool is rendered only when the coordinate difference of the X or Y axis of the two endpoints of the segment is less than `precision`. The default `0.5` means the tool is rendered only for vertical and horizontal segments. |
+| threshold | number | `40` | The tool is rendered only when the segment length exceeds `threshold`. |
+| snapRadius | number | `10` | The snap radius during the adjustment of the segment. |
+| removeRedundancies | boolean | `true` | Whether to automatically remove redundant path points. |
+| stopPropagation | boolean | `true` | Whether to prevent mouse events on the tool from bubbling up to the edge view. If prevented, mouse interactions with the tool will not trigger the edge's `mousedown`, `mousemove`, and `mouseup` events. |
+
+The default value (default style) for `attrs` is:
+
+```ts
+{
+ width: 20,
+ height: 8,
+ x: -10,
+ y: -4,
+ rx: 4,
+ ry: 4,
+ fill: '#333',
+ stroke: '#fff',
+ 'stroke-width': 2,
+}
+```
+
+The tool is used as follows:
+
+```ts
+graph.addEdge({
+ ...,
+ tools: [{
+ name: 'segments',
+ args: {
+ snapRadius: 20,
+ attrs: {
+ fill: '#444',
+ },
+ },
+ }]
+})
+```
+
+
+
+### boundary
+
+Renders a rectangle surrounding the edge based on its bounding box. Note that this tool only renders a rectangle and does not provide any interaction. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|---------------------|----------|---------------|-----------------------------------------------------------------------------------------------------------------------|
+| tagName | string | `rect` | The type of shape to render. |
+| padding | number | `10` | Margin. |
+| attrs | KeyValue | `object` | Shape attributes. |
+| useCellGeometry | boolean | `true` | Whether to use geometric calculations to compute the element's bounding box. Enabling this will improve performance, but if there are accuracy issues, set it to `false`. |
+
+The default value (default style) for `attrs` is:
+
+```js
+{
+ fill: 'none',
+ stroke: '#333',
+ 'stroke-width': 0.5,
+ 'stroke-dasharray': '5, 5',
+ 'pointer-events': 'none',
+}
+```
+
+The tool is used as follows:
+
+```ts
+graph.addEdge({
+ ...,
+ tools: [
+ {
+ name: 'boundary',
+ args: {
+ padding: 5,
+ attrs: {
+ fill: '#7c68fc',
+ stroke: '#333',
+ 'stroke-width': 0.5,
+ 'fill-opacity': 0.2,
+ },
+ },
+ },
+ ]
+})
+```
+
+
+
+### button
+
+Renders a button at a specified position, supporting custom click interactions. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|------------------------------------------------------------------------|---------------|--------------------------------------|
+| distance | number \| string | `undefined` | Distance or ratio from the start point. |
+| offset | number \| Point.PointLike | `0` | Offset based on `distance`. |
+| rotate | boolean | `undefined` | Whether to rotate with the edge. |
+| markup | Markup.JSONMarkup | `undefined` | Markup definition for rendering the button. |
+| onClick | `(args: {e: Dom.MouseDownEvent, cell: Cell, view: CellView }) => void` | `undefined` | Callback function for button click. |
+
+The usage is as follows:
+
+```ts
+graph.addEdge({
+ ...,
+ tools: [
+ {
+ name: 'button',
+ args: {
+ distance: -40,
+ onClick({ view }: any) {
+ //
+ },
+ },
+ },
+ ],
+})
+```
+
+
+
+### button-remove
+
+Renders a delete button at a specified position, which deletes the corresponding edge when clicked. It is a special case of the `button` tool above, so it supports all configurations of `button`. The usage is as follows:
+
+```ts
+graph.addEdge({
+ ...,
+ tools: [
+ {
+ name: 'button-remove',
+ args: { distance: -40 },
+ },
+ ]
+})
+```
+
+
+
+### source-arrowhead and target-arrowhead
+
+Renders a shape (default is an arrow) at the start or end of the edge, allowing you to drag the shape to modify the start or end of the edge. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|------------------|---------------|----------------------------|
+| tagName | string | `path` | The type of shape to render. |
+| attrs | Attr.SimpleAttrs | `object` | Attributes of the shape. |
+
+The default value for `source-arrowhead` attributes is:
+
+```ts
+{
+ d: 'M 10 -8 -10 0 10 8 Z',
+ fill: '#333',
+ stroke: '#fff',
+ 'stroke-width': 2,
+ cursor: 'move',
+}
+```
+
+The default value for `target-arrowhead` attributes is:
+
+```ts
+{
+ d: 'M -10 -8 10 0 -10 8 Z',
+ fill: '#333',
+ stroke: '#fff',
+ 'stroke-width': 2,
+ cursor: 'move',
+}
+```
+
+The tool is used as follows:
+
+```ts
+graph.on('edge:mouseenter', ({ cell }) => {
+ cell.addTools([
+ 'source-arrowhead',
+ {
+ name: 'target-arrowhead',
+ args: {
+ attrs: {
+ fill: 'red',
+ },
+ },
+ },
+ ])
+})
+
+graph.on('edge:mouseleave', ({ cell }) => {
+ cell.removeTools()
+})
+```
+
+
+
+### edge-editor
+
+Provides text editing functionality on the edge. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|-------------------------------|-------------------------------------------------------------------------|----------------------------------|------------------------------------------------------------------|
+| labelAddable | boolean | true | Whether to create a new label by clicking on a non-text position. |
+| attrs/fontSize | string | `14` | Font size for editing text. |
+| attrs/color | string | `#000` | Font color for editing text. |
+| attrs/fontFamily | string | `Arial, helvetica, sans-serif` | Font for editing text. |
+| attrs/backgroundColor | string | `#fff` | Background color for the editing area. |
+| getText | string \| `(this: CellView, args: {cell: Cell}) => string` | - | Method to get the original text; needs to be customized in custom `markup` scenarios. |
+| setText | string \| `(this: CellView, args: {cell: Cell, value: string}) => void` | - | Method to set new text; needs to be customized in custom `markup` scenarios. |
+
+:::warning{title=Note}
+Note that after version 2.8.0, there is no need to dynamically add tools in the double-click event, so event parameters do not need to be passed.
+:::
+
+```ts
+// Usage before version 2.8.0
+graph.on('node:dblclick', ({ node, e }) => {
+ edge.addTools({
+ name: 'edge-editor',
+ args: {
+ event: e,
+ },
+ })
+})
+
+// Usage after version 2.8.0
+edge.addTools({
+ name: 'edge-editor',
+})
+```
+
+It is also important to note that if a custom `markup` is defined in the edge, it is often necessary to customize the `getText` and `setText` methods to correctly get and set the edited text. Both configurations support function and string forms; the function is straightforward, while the string is the property path of the text to get or set. Generally, it is recommended to use the string form so that the graph data can be fully serialized (since functions cannot be serialized), otherwise, issues may arise with the text editing functionality after rendering the canvas. For example:
+
+```typescript
+edge.addTools({
+ name: 'edge-editor',
+ args: {
+ getText: 'a/b',
+ setText: 'c/d',
+ },
+})
+```
+
+The above configuration indicates:
+
+- Get edited text: `edge.attr('a/b')`
+- Set edited text: `edge.attr('c/d', value)`
+
+
+
+## Custom Tools
+
+### Method One
+
+Inherit from `ToolItem` to implement a tool class, which is more complex and requires understanding of the [ToolItem](https://github.com/antvis/X6/blob/master/packages/x6/src/view/tool.ts) class. You can refer to the source code of the built-in tools above; this will not be elaborated here.
+
+```ts
+Graph.registerEdgeTool('button', Button)
+```
+
+### Method Two
+
+Inherit from an already registered tool and modify the configuration based on that. We provide a static method `define` on the `ToolItem` base class to quickly implement inheritance and modify configurations.
+
+```ts
+import { Vertices } from '@antv/x6/es/registry/tool/vertices'
+
+const RedVertices = Vertices.define
+
+Additionally, we provide a quick way to inherit and specify default options for the `Graph.registerEdgeTool` method:
+
+```ts
+Graph.registerEdgeTool('red-vertices', {
+ inherit: 'vertices', // Base class name, using the name of the already registered tool.
+ attrs: {
+ // Other options, as default options for the inherited class.
+ fill: 'red',
+ },
+})
+```
+
+Using this method, we can quickly define and register a circular endpoint `circle-target-arrowhead`:
+
+```ts
+Graph.registerEdgeTool('circle-target-arrowhead', {
+ inherit: 'target-arrowhead',
+ tagName: 'circle',
+ attrs: {
+ r: 18,
+ fill: '#31d0c6',
+ 'fill-opacity': 0.3,
+ stroke: '#fe854f',
+ 'stroke-width': 4,
+ cursor: 'move',
+ },
+})
+```
+
+
diff --git a/sites/x6-sites/docs/api/registry/filter.en.md b/sites/x6-sites/docs/api/registry/filter.en.md
new file mode 100644
index 00000000000..dd2e73ffac3
--- /dev/null
+++ b/sites/x6-sites/docs/api/registry/filter.en.md
@@ -0,0 +1,214 @@
+---
+title: Filter
+order: 15
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/registry
+---
+
+We can use the special attribute [filter](/en/docs/api/registry/attr#filter) to specify [SVG filters](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Filter_effects) for elements. For example, we can define a predefined object for the `filter` attribute of the element, where `name` and `args` specify the filter name and filter parameters, respectively.
+
+```ts
+// Create a node by specifying the filter through the attrs option
+const rect = graph.addNode({
+ x: 40,
+ y: 40,
+ width: 80,
+ height: 30,
+ attrs: {
+ body: {
+ filter: {
+ name: 'dropShadow',
+ args: {
+ dx: 2,
+ dy: 2,
+ blur: 3,
+ },
+ },
+ },
+ },
+})
+
+// After creating the node, we can modify or specify the element's filter using the `attr()` method
+rect.attr('body/filter', {
+ name: 'dropShadow',
+ args: {
+ dx: 2,
+ dy: 2,
+ blur: 3,
+ },
+})
+```
+
+Additionally, we can call the `graph.defineFilter(...)` method to obtain a filter ID, and then set the `filter` attribute to this filter ID.
+
+```ts
+const filterId = graph.defineFilter({
+ name: 'dropShadow',
+ args: {
+ dx: 2,
+ dy: 2,
+ blur: 3,
+ },
+})
+
+rect.attr('body/filter', `#${filterId}`)
+```
+
+Through this brief introduction, we have learned how to use filters. Next, let's take a look at the predefined filters available in X6.
+## Built-in Filters
+
+### dropShadow
+
+Shadow filter. Refer to [CSS drop-shadow()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|---------------------------------|
+| dx | number | `0` | Shadow offset on the X-axis. |
+| dy | number | `0` | Shadow offset on the Y-axis. |
+| blur | number | `0` | Shadow blur radius. |
+| opacity | number | `1` | Shadow opacity. |
+
+
+
+### blur
+
+Gaussian blur filter. Refer to [CSS blur()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|-----------------------------------------------|
+| x | number | `2` | Blur amount in the X direction. |
+| y | number | - | Blur amount in the Y direction; defaults to X. |
+
+
+
+### grayScale
+
+Grayscale filter. Refer to [CSS grayscale()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/grayscale) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|--------------------------------------------------|
+| amount | number | `1` | Grayscale amount. Ranges from `[0-1]`, where `0` means no grayscale and `1` means full grayscale. |
+
+
+
+### sepia
+
+Sepia filter. Refer to [CSS sepia()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/sepia) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|-----------------------------------------------------|
+| amount | number | `1` | Sepia amount. Ranges from `[0-1]`, where `0` means no sepia and `1` means full sepia. |
+
+
+
+### saturate
+
+Saturation filter. Refer to [CSS saturate()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/saturate) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|-------------------------------|
+| amount | number | `1` | Saturation. Ranges from `[0-1]`. |
+
+
+
+### hueRotate
+
+Hue rotation filter. Refer to [CSS hue-rotate()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/hue-rotate) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|------------------------|
+| angle | number | `0` | Hue rotation angle. |
+
+
+
+### invert
+
+Invert filter. Refer to [CSS invert()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|-----------------------------------------------------|
+| amount | number | `1` | Inversion amount. Ranges from `[0-1]`, where `0` means no inversion and `1` means full inversion. |
+
+
+
+### brightness
+
+Brightness filter. Refer to [CSS brightness()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/brightness) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|--------------------------------------------------|
+| amount | number | `1` | Brightness. Ranges from `[0-1]`, where `0` means completely dark and `1` means completely bright. |
+
+
+
+### contrast
+
+Contrast filter. Refer to [CSS contrast()](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/contrast) filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|--------------------------------------------------|
+| amount | number | `1` | Contrast. Ranges from `[0-1]`, where `0` means completely dark and `1` means completely bright. |
+
+
+
+### highlight
+
+Highlight filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|------------------------|
+| color | string | `red` | Highlight color. |
+| width | number | `1` | Width of the highlight border. |
+| blur | number | `0` | Blur radius. |
+| opacity | number | `1` | Opacity. |
+
+
+
+### outline
+
+Outline filter.
+
+| Parameter Name | Type | Default Value | Description |
+|----------------|--------|---------------|------------------|
+| color | string | `blue` | Outline color. |
+| width | number | `1` | Outline width. |
+| margin | number | `2` | Margin. |
+| opacity | number | `1` | Opacity. |
+
+
+
+## Custom Filters
+
+A filter definition is a function with the following signature that returns a `
+
+You can specify the anchor point when creating an edge:
+
+```ts
+const edge = graph.addEdge({
+ source: {
+ cell: 'source-id',
+ anchor: {
+ name: 'midSide',
+ args: {
+ dx: 10,
+ },
+ },
+ },
+ target: {
+ cell: 'target-id',
+ anchor: 'orth', // Simplified writing when there are no parameters
+ },
+})
+```
+
+After creation, you can modify the anchor point by calling the `edge.setSource` and `edge.setTarget` methods:
+
+```ts
+edge.setSource({
+ cell: 'source-id',
+ anchor: {
+ name: 'midSide',
+ args: {
+ dx: 10,
+ },
+ },
+})
+```
+
+When creating a canvas, you can set the global default anchor point through the `connecting` option:
+
+```ts
+new Graph({
+ connecting: {
+ anchor: {
+ name: 'midSide',
+ args: {
+ dx: 10,
+ },
+ },
+ },
+})
+```
+
+Simplified writing when there are no parameters:
+
+```ts
+new Graph({
+ connecting: {
+ anchor: 'midSide',
+ },
+})
+```
+
+## Built-in Anchors
+
+### center
+
+The center point of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### top
+
+The top center point of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### bottom
+
+The bottom center point of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### left
+
+The left center point of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### right
+
+The right center point of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### midSide
+
+The center point of the nearest side of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------|:-------:|---------|--------------------------------------------------------------------------------------|
+| padding | number | No | `0` | Offset the center point by `padding` pixels, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+| direction | 'H' \| 'V' | No | - | The direction of the connection point, such as setting to `H` to only connect to the left or right center point of the node, automatically judging based on the position. |
+
+### topLeft
+
+The top-left corner of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### topRight
+
+The top-right corner of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### bottomLeft
+
+The bottom-left corner of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### bottomRight
+
+The bottom-right corner of the element, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|------------------------|:-------:|---------|----------------------------------------------------|
+| dx | number \| string | No | `0` | X-axis offset, supporting absolute offset and percentage relative offset. |
+| dy | number \| string | No | `0` | Y-axis offset, supporting absolute offset and percentage relative offset. |
+| rotate | boolean | No | `false` | Whether to use the element's bounding box rotated with the node, defaulting to not considering the rotation angle. |
+
+### orth
+
+The orthogonal point, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|----------------|:-------:|--------|---------|
+| padding | number | No | `0` | X-axis offset. |
+
+### nodeCenter
+
+The center point of the node, supporting the following parameters:
+
+| Parameter Name | Parameter Type | Required | Default Value | Parameter Description |
+|---------------|----------------|:-------:|--------|---------|
+| dx | number | No | `0` | X-axis offset. |
+| dy | number | No | `0` | Y-axis offset. |
+
+## Custom Anchors
+
+An anchor point definition is a function with the following signature, returning an anchor point.
+
+```ts
+export type Definition
+
+### button-remove
+
+Renders a delete button at a specified position, which deletes the corresponding node when clicked. It is a special case of the `button` tool, so it supports all configurations of `button`.
+
+```ts
+const source = graph.addNode({
+ ...,
+ // Add a delete button that is always visible
+ tools: [
+ {
+ name: 'button-remove',
+ args: {
+ x: '100%',
+ y: 0,
+ offset: { x: -10, y: 10 },
+ },
+ },
+ ],
+})
+```
+
+
+
+### boundary
+
+Renders a rectangle surrounding the node based on its bounding box. Note that this tool only renders a rectangle without any interaction. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|--------------------|-------------|---------------|---------------------------------------------------------------------------------------------------------|
+| tagName | string | `rect` | The shape used for rendering. |
+| rotate | boolean | - | Whether the shape follows the rotation of the node. |
+| padding | SideOptions | `10` | Margin. |
+| attrs | KeyValue | `object` | Shape attributes. |
+| useCellGeometry | boolean | `true` | Whether to use geometric calculations to compute the element's bounding box. Enabling this improves performance; if accuracy issues arise, set it to `false`. |
+
+The default values (default styles) for `attrs` are:
+
+```ts
+{
+ fill: 'none',
+ stroke: '#333',
+ 'stroke-width': 0.5,
+ 'stroke-dasharray': '5, 5',
+ 'pointer-events': 'none',
+}
+```
+
+The type definition for `SideOptions` is as follows:
+
+```typescript
+type SideOptions =
+ | number
+ | {
+ vertical?: number
+ horizontal?: number
+ left?: number
+ top?: number
+ right?: number
+ bottom?: number
+ }
+```
+
+The tool usage is as follows:
+
+```ts
+const source = graph.addNode({
+ ...,
+ tools: [
+ {
+ name: 'boundary',
+ args: {
+ padding: 5,
+ attrs: {
+ fill: '#7c68fc',
+ stroke: '#333',
+ 'stroke-width': 1,
+ 'fill-opacity': 0.2,
+ },
+ },
+ },
+ ],
+})
+```
+
+
+
+### node-editor
+
+Provides text editing functionality on the node. The configuration is as follows:
+
+| Parameter Name | Type | Default Value | Description |
+|-------------------------------|-------------------------------------------------------------------------|----------------------------------|---------------------------------------------------------------|
+| x | number \| string | - | The X coordinate relative to the top-left corner of the node, with decimals and percentages indicating relative positions. |
+| y | number \| string | - | The Y coordinate relative to the top-left corner of the node, with decimals and percentages indicating relative positions. |
+| attrs/fontSize | string | `14` | Font size of the edited text. |
+| attrs/color | string | `#000` | Font color of the edited text. |
+| attrs/fontFamily | string | `Arial, helvetica, sans-serif` | Font of the edited text. |
+| attrs/backgroundColor | string | `#fff` | Background color of the editing area. |
+| getText | string \| `(this: CellView, args: {cell: Cell}) => string` | - | Method to get the original text; needs to customize `getText` method in custom `markup` scenarios. |
+| setText | string \| `(this: CellView, args: {cell: Cell, value: string}) => void` | - | Method to set new text; needs to customize `setText` method in custom `markup` scenarios. |
+
+:::warning{title=Note}
+It is important to note that after version 2.8.0, there is no need to dynamically add tools in the double-click event, and event parameters do not need to be passed.
+:::
+
+```ts
+// Usage before version 2.8.0
+graph.on('node:dblclick', ({ node, e }) => {
+ node.addTools({
+ name: 'node-editor',
+ args: {
+ event: e,
+ },
+ })
+})
+
+// Usage after version 2.8.0
+node.addTools({
+ name: 'node-editor',
+})
+```
+
+It is also important to note that if a custom `markup` is defined in the node, it is often necessary to customize the `getText` and `setText` methods to correctly get and set the edited text. Both configurations support both function and string forms; the function form is easier to understand, while the string form is essentially the property path of the text to be retrieved or set. Generally, it is recommended to use the string form so that the graph data can be fully serialized (since functions cannot be serialized), otherwise, issues may arise with the text editing functionality after rendering the canvas, for example:
+
+```typescript
+node.addTools({
+ name: 'node-editor',
+ args: {
+ getText: 'a/b',
+ setText: 'c/d',
+ },
+})
+```
+
+The above configuration indicates:
+
+- Get edited text: `node.attr('a/b')`
+- Set edited text: `node.attr('c/d', value)`
+
+
+
+## Custom Tools
+
+### Method One
+
+Inherit from `ToolItem` to implement a tool class, which is more challenging and requires understanding of the [ToolItem](https://github.com/antvis/X6/blob/master/packages/x6/src/view/tool.ts) class. You can refer to the source code of the built-in tools above; this will not be elaborated here.
+
+```ts
+Graph.registerNodeTool('button', Button)
+```
+
+### Method Two
+
+Inherit from an already registered tool and modify the configuration based on the inheritance. We provide a static method `define` on the `ToolItem` base class to quickly implement inheritance and modify configurations.
+
+```ts
+const MyButton = Button.define
diff --git a/sites/x6-sites/docs/api/registry/port-label-layout.en.md b/sites/x6-sites/docs/api/registry/port-label-layout.en.md
new file mode 100644
index 00000000000..7d311a05a99
--- /dev/null
+++ b/sites/x6-sites/docs/api/registry/port-label-layout.en.md
@@ -0,0 +1,247 @@
+---
+title: Port Label Layout
+order: 12
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/registry
+---
+
+The port label layout algorithm is a function with the following signature, returning the position and rotation angle of the label relative to the port.
+
+```ts
+type Definition
+
+### Inside/Outside
+
+The label is located inside or outside the node, supporting the following four layouts:
+
+- `'inside'` The label is located inside the node, close to the edge.
+- `'outside'` The label is located outside the node, close to the edge.
+- `'insideOriented'` The label is located inside the node and automatically adjusts the text direction based on the position.
+- `'outsideOriented'` The label is located outside the node and automatically adjusts the text direction based on the position.
+
+You can set the offset from the node center to the label position through `args.offset`.
+
+```ts
+interface InOutArgs {
+ offset?: number
+ x?: number
+ y?: number
+ angle?: number
+ attrs?: Attr.CellAttrs
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|--------|----------------|:----:|--------|-----------------------------------------|
+| offset | number | | `15` | Offset from the node center to the label position. |
+| x | number | | - | Replace the calculated X coordinate with the specified value. |
+| y | number | | - | Replace the calculated Y coordinate with the specified value. |
+| angle | number | | - | Replace the calculated rotation angle with the specified value. |
+| attrs | Attr.CellAttrs | | - | Label attributes. |
+
+```ts
+label: {
+ position: {
+ name : 'outside',
+ },
+}
+```
+
+
+
+### Radial
+
+Place the label on the outer circle or ellipse of the node. Supports the following two layouts:
+
+- `'radial'` The label is located on the outer circle or ellipse of the node.
+- `'radialOriented'` The label is located on the outer circle or ellipse of the node and automatically adjusts the text direction based on the position.
+
+```ts
+interface RadialArgs {
+ offset?: number
+ x?: number
+ y?: number
+ angle?: number
+ attrs?: Attr.CellAttrs
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|--------|----------------|:----:|--------|-----------------------------------------|
+| offset | number | | `20` | Offset from the node center to the label position. |
+| x | number | | - | Replace the calculated X coordinate with the specified value. |
+| y | number | | - | Replace the calculated Y coordinate with the specified value. |
+| angle | number | | - | Replace the calculated rotation angle with the specified value. |
+| attrs | Attr.CellAttrs | | - | Label attributes. |
+
+```ts
+label: {
+ position: {
+ name : 'radial',
+ },
+}
+```
+
+
+
+## Custom Port Label Layout
+
+The port label layout algorithm is a function with the following signature, returning the position and rotation angle of the label relative to the port.
+
+```ts
+type Definition
+
+### left, right, top, bottom
+
+Ports are evenly distributed along the specified edge of the rectangle, and `left`, `right`, `top`, and `bottom` are four layout algorithms that are very friendly to rectangular nodes. You can set the offset and rotation angle through `args`.
+
+```ts
+interface SideArgs {
+ dx?: number
+ dy?: number
+ angle?: number
+ x?: number
+ y?: number
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|--------|---------|:----:|---------|---------------------------------------|
+| strict | boolean | | `false` | Whether to strictly distribute evenly. |
+| dx | number | | `0` | Offset in the X-axis direction. |
+| dy | number | | `0` | Offset in the Y-axis direction. |
+| angle | number | | `0` | Rotation angle. |
+| x | number | | - | Override the calculated X-coordinate with the specified value. |
+| y | number | | - | Override the calculated Y-coordinate with the specified value. |
+
+```ts
+graph.addNode({
+ ports: {
+ groups: {
+ group1: {
+ position: 'left',
+ },
+ },
+ items: [
+ {
+ group: 'group1',
+ args: {
+ dx: 2,
+ },
+ },
+ ],
+ },
+})
+```
+
+
+
+### line
+
+Ports are evenly distributed along the line segment.
+
+```ts
+interface LineArgs {
+ start?: Point.PointLike
+ end?: Point.PointLike
+ dx?: number
+ dy?: number
+ angle?: number
+ x?: number
+ y?: number
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|--------|-----------------|:----:|---------|---------------------------------------|
+| start | Point.PointLike | | | Start point of the line segment. |
+| end | Point.PointLike | | | End point of the line segment. |
+| strict | boolean | | `false` | Whether to strictly distribute evenly. |
+| dx | number | | `0` | Offset in the X-axis direction. |
+| dy | number | | `0` | Offset in the Y-axis direction. |
+| angle | number | | `0` | Rotation angle. |
+| x | number | | - | Override the calculated X-coordinate with the specified value. |
+| y | number | | - | Override the calculated Y-coordinate with the specified value. |
+
+```ts
+graph.addNode({
+ ports: {
+ groups: {
+ group1: {
+ position: {
+ name: 'line',
+ args: {
+ start: { x: 10, y: 10 },
+ end: { x: 210, y: 10 },
+ },
+ },
+ },
+ },
+ items: [
+ {
+ group: 'group1',
+ args: {
+ dx: 2,
+ },
+ },
+ ],
+ },
+})
+```
+
+
+
+### ellipse
+
+Ports are distributed along the ellipse, starting from the `start` angle, with a step size of `step`.
+
+```ts
+interface EllipseArgs {
+ start?: number
+ step?: number
+ compensateRotate?: boolean
+ dr?: number
+ dx?: number
+ dy?: number
+ angle?: number
+ x?: number
+ y?: number
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|------------------|--------|:----:|---------|---------------------------------------|
+| start | number | | | Start angle. |
+| step | number | | `20` | Step size. |
+| compensateRotate | number | | `false` | Whether to compensate for the rotation angle of the ellipse. |
+| dr | number | | `0` | Offset in the radial direction. |
+| dx | number | | `0` | Offset in the X-axis direction. |
+| dy | number | | `0` | Offset in the Y-axis direction. |
+| angle | number | | `0` | Rotation angle. |
+| x | number | | - | Override the calculated X-coordinate with the specified value. |
+| y | number | | - | Override the calculated Y-coordinate with the specified value. |
+
+```ts
+const node = graph.addNode({
+ ports: {
+ groups: {
+ group1: {
+ position: {
+ name: 'ellipse',
+ args: {
+ start: 45,
+ },
+ },
+ },
+ },
+ },
+})
+
+Array.from({ length: 10 }).forEach((_, index) => {
+ node.addPort({
+ id: `${index}`,
+ group: 'group1',
+ attrs: { text: { text: index } },
+ })
+})
+```
+
+
+
+### ellipseSpread
+
+Uniformly distributes connection points along an ellipse, starting from the specified angle `start`.
+
+```ts
+interface EllipseSpreadArgs {
+ start?: number
+ compensateRotate?: boolean
+ dr?: number
+ dx?: number
+ dy?: number
+ angle?: number
+ x?: number
+ y?: number
+}
+```
+
+| Name | Type | Required | Default Value | Description |
+|------------------|--------|:----:|---------|---------------------------------------|
+| start | number | | | Starting angle. |
+| compensateRotate | number | | `false` | Whether to adjust the rotation angle of the connection points along the arc. |
+| dr | number | | `0` | Offset along the radial direction. |
+| dx | number | | `0` | Offset along the X-axis direction. |
+| dy | number | | `0` | Offset along the Y-axis direction. |
+| angle | number | | `0` | Rotation angle of the connection points. |
+| x | number | | - | Override the X-coordinate of the calculated result with a specified X-coordinate. |
+| y | number | | - | Override the Y-coordinate of the calculated result with a specified Y-coordinate. |
+
+```ts
+const node = graph.addNode({
+ ports: {
+ groups: {
+ group1: {
+ position: {
+ name: 'ellipseSpread',
+ args: {
+ start: 45,
+ },
+ },
+ },
+ },
+ },
+})
+
+Array.from({ length: 36 }).forEach(function (_, index) {
+ ellipse.addPort({
+ group: 'group1',
+ id: `${index}`,
+ attrs: { text: { text: index } },
+ })
+})
+```
+
+
+
+## Custom Connection Point Layout
+
+A connection point layout algorithm is a function with the following signature, which returns the relative position of each connection point relative to the node. For example, if a node is located at `{ x: 30, y: 40 }` on the canvas, and the returned position of a connection point is `{ x: 2, y: 4 }`, then the rendered position of the connection point on the canvas would be `{ x: 32, y: 44 }`.
+
+```ts
+type Definition
\ No newline at end of file
diff --git a/sites/x6-sites/docs/api/registry/router.en.md b/sites/x6-sites/docs/api/registry/router.en.md
new file mode 100644
index 00000000000..f9ed790f3d2
--- /dev/null
+++ b/sites/x6-sites/docs/api/registry/router.en.md
@@ -0,0 +1,287 @@
+---
+title: Routing
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/api
+ - /en/docs/api/registry
+---
+
+Routing further processes the edge's waypoints [vertices](/en/docs/tutorial/basic/edge#vertices), adding additional points when necessary, and then returns the processed points (excluding the start and end points of the edge). For example, after [`orth`](#orth) routing, each segment of the edge is a horizontal or vertical orthogonal segment.
+
+X6 has the following built-in routing options.
+
+| Routing Name | Description |
+|--------------|---------------------------------------------------------------------------------------------------------------|
+| normal | [Default routing](#normal), returns the waypoints as they are. |
+| orth | [Orthogonal routing](#orth), composed of horizontal or vertical orthogonal segments. |
+| oneSide | [Restricted orthogonal routing](#oneside), composed of three restricted horizontal or vertical orthogonal segments. |
+| manhattan | [Smart orthogonal routing](#manhattan), composed of horizontal or vertical orthogonal segments that automatically avoid other nodes (obstacles) on the path. |
+| metro | [Smart subway line routing](#metro), composed of horizontal or vertical orthogonal segments and diagonal segments, similar to a subway map, and automatically avoids other nodes (obstacles) on the path. |
+| er | [Entity-relationship routing](#er), composed of zigzag diagonal segments. |
+
+When using, you can set the routing for an edge:
+
+```ts
+const edge = graph.addEdge({
+ source,
+ target,
+ router: {
+ name: 'oneSide',
+ args: {
+ side: 'right',
+ },
+ },
+})
+```
+
+When the router has no parameters, it can also be simplified to:
+
+```ts
+const edge = graph.addEdge({
+ source,
+ target,
+ router: 'oneSide',
+})
+```
+
+You can also call the [`edge.setRouter`]() method to set the routing:
+
+```ts
+edge.setRouter('oneSide', { side: 'right' })
+```
+
+When creating a canvas, you can set a global default routing through the `connecting` option (the default routing for the canvas is `'normal'`):
+
+```ts
+new Graph({
+ connecting: {
+ router: {
+ name: 'oneSide',
+ args: {
+ side: 'right',
+ },
+ },
+ },
+})
+```
+
+When the router has no parameters, it can also be simplified to:
+
+```ts
+new Graph({
+ connecting: {
+ router: 'orth',
+ },
+})
+```
+
+Now let's take a look at how to use the built-in routing and how to define and register custom routing.
+## Built-in Routing
+
+### normal
+
+The system's default routing, which returns the input `vertices` path points as is.
+
+### orth
+
+Orthogonal routing, which adds extra points along the path to ensure that each line segment of the edge is horizontally or vertically orthogonal.
+
+The supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Description |
+|----------------|----------------|:--------:|---------------|-----------------------------------------------|
+| padding | SideOptions | No | 20 | Sets the minimum distance from the anchor point to the corner. |
+
+`SideOptions` is defined as follows:
+
+```ts
+export type SideOptions =
+ | number
+ | {
+ vertical?: number
+ horizontal?: number
+ left?: number
+ top?: number
+ right?: number
+ bottom?: number
+ }
+```
+
+For example:
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ vertices: [
+ { x: 100, y: 200 },
+ { x: 300, y: 120 },
+ ],
+ router: {
+ name: 'orth',
+ args: {
+ padding: {
+ left: 50,
+ },
+ },
+ },
+})
+```
+
+
+
+### oneSide
+
+The `oneSide` routing is a restricted version of the orthogonal routing `orth`, which generates a strict three-segment route: starting from the `side` side of the starting node, passing through the middle segment, and ending at the `side` side of the target node. It is important to note that when using this routing, do not specify `vertices` at the same time, as it will result in poor routing performance.
+
+The supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Description |
+|----------------|------------------------------------------------------|:--------:|---------------|-----------------------------------------------|
+| side | `'left'` \| `'right'` \| `'top'` \| `'bottom'` | No | `'bottom'` | The starting/ending direction of the route, default is `'bottom'`. |
+| padding | SideOptions | No | 20 | Sets the minimum distance from the anchor point to the corner. |
+
+For example:
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ router: {
+ name: 'oneSide',
+ args: { side: 'right' },
+ },
+})
+```
+
+
+
+### manhattan
+
+The Manhattan routing `'manhattan'` is an intelligent version of the orthogonal routing `'orth'`, consisting of horizontal or vertical orthogonal line segments that automatically avoid other nodes (obstacles) along the path.
+
+We provide a rich set of options for this routing algorithm:
+
+| Parameter Name | Parameter Type | Required | Default Value | Description |
+|---------------------|-------------------------------|:--------:|---------------------------------------------|---------------------------------------------------------------|
+| step | number | No | `10` | The step length of the routing algorithm; smaller values increase computation. It is recommended to use the canvas grid size. |
+| excludeTerminals | ('source' \| 'target')[] | No | `[]` | Ignore starting or ending nodes; ignored nodes will not be considered as obstacles. |
+| excludeShapes | string[] | No | `[]` | Ignore specified shape nodes; ignored nodes will not be considered as obstacles. |
+| excludeNodes | (Node \| string)[] | No | `[]` | Nodes to ignore; ignored nodes will not be considered as obstacles. |
+| startDirections | string[] | No | `['top', 'right', 'bottom', 'left']` | Supported directions to start routing. |
+| endDirections | string[] | No | `['top', 'right', 'bottom', 'left']` | Supported directions to end routing. |
+| padding | SideOptions | No | - | Sets the minimum distance from the anchor point to the corner. |
+| fallbackRouter | Router | No | `Registry.Router.presets.orth` | In scenarios where obstacles cannot be avoided, downgrade to the specified routing. |
+
+For example:
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ router: {
+ name: 'manhattan',
+ args: {
+ startDirections: ['top'],
+ endDirections: ['bottom'],
+ },
+ },
+})
+```
+
+:::warning{title=Note}
+The characteristic of the manhattan routing is to automatically avoid obstacles in the path. If an unavoidable situation arises, it will automatically downgrade to the orth routing. In this case, to help developers identify the issue, a warning will be logged in the console: Unable to execute manhattan algorithm, use orth instead.
+:::
+
+
+
+### metro
+
+The metro routing `metro` is a variant of the Manhattan routing `manhattan`, consisting of horizontal or vertical orthogonal line segments and diagonal segments, similar to a subway map, and automatically avoids other nodes (obstacles) along the path. Its options are the same as [manhattan](#manhattan), but the default value of `maxDirectionChange` is `45`, indicating that the maximum slope angle of the routing line segment is `45` degrees.
+
+For example:
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ router: {
+ name: 'metro',
+ args: {
+ startDirections: ['top'],
+ endDirections: ['bottom'],
+ },
+ },
+})
+```
+
+
+
+### er
+
+The entity-relationship routing `er` consists of zigzag diagonal segments, commonly used to represent connections between entities in an ER diagram.
+
+The supported parameters are as follows:
+
+| Parameter Name | Parameter Type | Required | Default Value | Description |
+|----------------|-----------------------------------------------|:--------:|---------------|----------------------------------------------------------------------------------------------------|
+| offset | number \| 'center' | No | `32` | The distance between the first and last points of the route and the nodes. When set to `'center'`, the center of the node is used as the route point coordinate. |
+| min | number | No | `16` | The minimum distance between the first and last points of the route and the nodes. |
+| direction | `'T'` \| `'B'` \| `'L'` \| `'R'` \| `'H'` \| `'V'` | No | - | The routing direction; if omitted, the optimal direction will be automatically selected. |
+
+For example:
+
+```ts
+graph.addEdge({
+ source,
+ target,
+ router: {
+ name: 'er',
+ args: {
+ offset: 24,
+ },
+ },
+})
+```
+
+
+
+## Custom Routing
+
+In addition to built-in routing, we can also create custom routing according to certain rules, for example, implementing random routing:
+
+```ts
+// Routing parameters
+interface RandomRouterArgs {
+ bounces?: number
+}
+
+function randomRouter(
+ vertices: Point.PointLike[],
+ args: RandomRouterArgs,
+ view: EdgeView,
+) {
+ const bounces = args.bounces || 20
+ const points = vertices.map((p) => Point.create(p))
+
+ for (var i = 0; i < bounces; i++) {
+ const sourceCorner = view.sourceBBox.getCenter()
+ const targetCorner = view.targetBBox.getCenter()
+ const randomPoint = Point.random(
+ sourceCorner.x,
+ targetCorner.x,
+ sourceCorner.y,
+ targetCorner.y,
+ )
+ points.push(randomPoint)
+ }
+
+ return points
+}
+
+Graph.registerRouter('random', randomRouter)
+edge.setRouter('random', { bounces: 3 })
+```
+
+
diff --git a/sites/x6-sites/docs/temp/animation.en.md b/sites/x6-sites/docs/temp/animation.en.md
new file mode 100644
index 00000000000..46487ea6d0e
--- /dev/null
+++ b/sites/x6-sites/docs/temp/animation.en.md
@@ -0,0 +1,346 @@
+---
+title: Using Animation
+order: 2
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/advanced
+---
+
+## Transition
+
+### Start
+
+We can call the [`cell.transition(...)`](/en/docs/api/model/cell#transition) method to smoothly transition the property value corresponding to the specified path `path` to the target value specified by `target`, and it returns a `stop` method that can be called to immediately stop the animation.
+
+```ts
+transition(
+ path: string | string[],
+ target: Animation.TargetValue,
+ options: Animation.StartOptions = {},
+ delim: string = '/',
+): () => void
+```
+
+Parameters
+
+| Name | Type | Required | Default Value | Description |
+| --- | --- | :-: | --- | --- |
+| path | string \| string[] | ✓ | | Path. |
+| target | any | ✓ | | Target property value. |
+| options.delay | number | | `10` | Delay before the animation starts, in milliseconds. |
+| options.duration | number | | `100` | Duration of the animation, in milliseconds. |
+| options.timing | Timing.Names \| (t: number) => number | | | Timing function. |
+| options.interp | \
+
+### router
+
+The `router` will further process the `vertices`, adding additional points if necessary, and then return the processed points. For example, after processing with [orth routing](/en/docs/api/registry/router#orth), each link segment of the edge will be horizontal or vertical.
+
+```ts
+graph.addEdge({
+ source: rect1,
+ target: rect2,
+ vertices: [
+ { x: 100, y: 200 },
+ { x: 300, y: 120 },
+ ],
+ // If there are no args parameters, it can be simplified to router: 'orth'
+ router: {
+ name: 'orth',
+ args: {},
+ },
+})
+```
+
+
+
+X6 provides the following routing options by default. Click the links below to see how each routing option is used.
+
+- [normal](/en/docs/api/registry/router#normal)
+- [orth](/en/docs/api/registry/router#orth)
+- [oneSide](/en/docs/api/registry/router#oneside)
+- [manhattan](/en/docs/api/registry/router#manhattan)
+- [metro](/en/docs/api/registry/router#metro)
+- [er](/en/docs/api/registry/router#er)
+
+Additionally, we can register custom routers. For more details, please refer to the [Custom Router](/en/docs/api/registry/router#registry) tutorial.
+
+### connector
+
+The `connector` processes the points returned by the `router` into the [pathData](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) needed for rendering the edge. For example, the `rounded` connector will round the corners between the lines.
+
+```ts
+graph.addEdge({
+ source: rect1,
+ target: rect2,
+ vertices: [
+ { x: 100, y: 200 },
+ { x: 300, y: 120 },
+ ],
+ router: 'orth',
+ // If there are no args parameters, it can be simplified to connector: 'rounded'
+ connector: {
+ name: 'rounded',
+ args: {},
+ },
+})
+```
+
+
+
+X6 provides the following connector options by default. Click the links below to see how each connector is used.
+
+- [normal](/en/docs/api/registry/connector#normal)
+- [rounded](/en/docs/api/registry/connector#rounded)
+- [smooth](/en/docs/api/registry/connector#smooth)
+- [jumpover](/en/docs/api/registry/connector#jumpover)
+
+Additionally, we can register custom connectors. For more details, please refer to the [Custom Connector](/en/docs/api/registry/connector#register) tutorial.
+
+### labels
+
+Used to set label text, position, style, etc. Supports multiple labels in array form, and each item specified in `labels` will be used after being [merged](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with the [defaultLabel](/en/docs/api/model/labels#default-label).
+
+```ts
+const edge = graph.addEdge({
+ source: rect1,
+ target: rect2,
+ labels: [
+ {
+ attrs: {
+ label: {
+ text: 'edge',
+ },
+ },
+ },
+ ],
+})
+// Or
+const edge = graph.addEdge({
+ source: rect1,
+ target: rect2,
+ labels: ['edge'], // Multiple labels can be set through labels, and when only setting label text, this syntax can be simplified
+})
+// Or
+const edge = graph.addEdge({
+ source: rect1,
+ target: rect2,
+ label: 'edge', // A single label can be set through label, and when only setting label text, this syntax can be simplified
+})
+```
+
+
+
+In addition to setting text, you can also create complex shapes on the edge using Label, which we will detail in the [API](/en/docs/api/model/labels).
+
+### defaultLabel
+
+Default label. The default label can simplify the label configuration items, and each item specified in `labels` will be used after being merged with `defaultLabel`.
+
+## Using Arrows
+
+We define two special properties, `sourceMarker` and `targetMarker`, to customize the starting and ending arrows of the edge. For example, for `Shape.Edge`, we can specify the starting and ending arrows using the `line` selector.
+
+### Built-in Arrows
+
+X6 provides the following built-in arrows. When using them, you only need to specify the arrow name and parameters (optional).
+
+- [block](/en/docs/api/model/marker#block)
+- [classic](/en/docs/api/model/marker#classic)
+- [diamond](/en/docs/api/model/marker#diamond)
+- [cross](/en/docs/api/model/marker#cross)
+- [async](/en/docs/api/model/marker#async)
+- [path](/en/docs/api/model/marker#path)
+- [circle](/en/docs/api/model/marker#circle)
+- [circlePlus](/en/docs/api/model/marker#circleplus)
+- [ellipse](/en/docs/api/model/marker#ellipse)
+
+```ts
+graph.addEdge({
+ shape: 'edge',
+ source: [100, 100],
+ target: [500, 500],
+ attrs: {
+ line: {
+ sourceMarker: 'block', // Solid arrow
+ targetMarker: {
+ name: 'ellipse', // Ellipse
+ rx: 10, // X radius of the ellipse arrow
+ ry: 6, // Y radius of the ellipse arrow
+ },
+ },
+ },
+})
+```
+
+
+
+:::info{title="Tip"}
+ By default, X6 edges come with a `classic` arrow. If you want to remove it, you can set `targetMarker` to `null`.
+:::
+
+### Custom Arrows
+
+We can also render arrows using SVG elements specified by `tagName`. For example, below we use the `
+
+For more examples and customization tips for arrows, please refer to the [API](/en/docs/api/model/marker).
+
+## Customizing Edges
+
+Like nodes, we can customize the shape and style of edges using `markup` and `attrs`, and we can also register custom edges for reuse. The default edge `Shape.Edge` in X6 defines two selectors: `line` (representing the path element) and `wrap` (representing a transparent path element for interaction). We can define the style of the edge as shown below.
+
+
+
+## Modifying Edges
+
+Similar to nodes, after rendering is complete, we can modify all properties of edges through the API. We commonly use the following two methods:
+
+- edge.prop(path, value), for detailed usage see [prop](/en/docs/api/model/cell#node-and-edge-properties-properties).
+- edge.attr(path, value), for detailed usage see [attr](/en/docs/api/model/cell#element-attributes-attrs).
+
+Let's take a look at the `prop` of the default edge provided by X6.
+
+```ts
+const edge = graph.addEdge({
+ source: [200, 140],
+ target: [500, 140],
+ label: 'edge',
+})
+console.log(edge.prop())
+
+// Output
+{
+ "shape": "edge",
+ "attrs": {
+ "lines": {
+ "connection": true,
+ "strokeLinejoin": "round"
+ },
+ "wrap": {
+ "strokeWidth": 10
+ },
+ "line": {
+ "stroke": "#333",
+ "strokeWidth": 2,
+ "targetMarker": "classic"
+ }
+ },
+ "id": "9d5e4f54-1ed3-429e-8d8c-a1526cff2cd8",
+ "source": {
+ "x": 200,
+ "y": 140
+ },
+ "target": {
+ "x": 500,
+ "y": 140
+ },
+ "labels": [{
+ "attrs": {
+ "label": {
+ "text": "edge"
+ }
+ }
+ }],
+ "zIndex": 1
+}
+```
+
+From the output above, we can see that `prop` is a new configuration after processing, and its values can be updated through methods. After updating, the edge will immediately refresh to the latest state. To modify the edge's `attrs` more conveniently, X6 provides the `attr` method.
+
+```ts
+edge.prop('target', { x: 300, y: 300 }) // Modify the endpoint
+edge.attr('line/stroke', '#ccc') // Modify the edge color, equivalent to edge.prop('attrs/line/stroke', '#ccc')
+```
+
+
diff --git a/sites/x6-sites/docs/tutorial/basic/events.en.md b/sites/x6-sites/docs/tutorial/basic/events.en.md
new file mode 100644
index 00000000000..243574a1249
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/events.en.md
@@ -0,0 +1,416 @@
+---
+title: Events
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This chapter mainly introduces knowledge related to events. By reading, you can learn about"}
+
+- What categories of events can be listened to
+- How to listen to events
+
+:::
+
+## View Interaction Events
+
+Events triggered when interacting with the application through mouse, keyboard, or various interactive components.
+
+### Mouse Events
+
+| Event | Cell Node/Edge | Node Node | Port Connection Point | Edge Edge | Blank Canvas Area |
+|------------|----------------------|---------------------|----------------------------|--------------------|---------------------|
+| Click | `cell:click` | `node:click` | `node:port:click` | `edge:click` | `blank:click` |
+| Double Click | `cell:dblclick` | `node:dblclick` | `node:port:dblclick` | `edge:dblclick` | `blank:dblclick` |
+| Right Click | `cell:contextmenu` | `node:contextmenu` | `node:port:contextmenu` | `edge:contextmenu` | `blank:contextmenu` |
+| Mouse Down | `cell:mousedown` | `node:mousedown` | `node:port:mousedown` | `edge:mousedown` | `blank:mousedown` |
+| Mouse Move | `cell:mousemove` | `node:mousemove` | `node:port:mousemove` | `edge:mousemove` | `blank:mousemove` |
+| Mouse Up | `cell:mouseup` | `node:mouseup` | `node:port:mouseup` | `edge:mouseup` | `blank:mouseup` |
+| Mouse Wheel| `cell:mousewheel` | `node:mousewheel` | - | `edge:mousewheel` | `blank:mousewheel` |
+| Mouse Enter| `cell:mouseenter` | `node:mouseenter` | `node:port:mouseenter` | `edge:mouseenter` | `graph:mouseenter` |
+| Mouse Leave| `cell:mouseleave` | `node:mouseleave` | `node:port:mouseleave` | `edge:mouseleave` | `graph:mouseleave` |
+
+:::warning{title=Note}
+It is important to note that the `mousemove` event here differs from the usual mouse move event; it requires the mouse to be moved after being pressed down to trigger.
+:::
+
+Except for `mouseenter` and `mouseleave`, the parameters of the event callback functions include the mouse position relative to the canvas `x`, `y`, and the mouse event object `e`, among other parameters.
+
+```ts
+graph.on('cell:click', ({ e, x, y, cell, view }) => {})
+graph.on('node:click', ({ e, x, y, node, view }) => {})
+graph.on('edge:click', ({ e, x, y, edge, view }) => {})
+graph.on('blank:click', ({ e, x, y }) => {})
+
+graph.on('cell:mouseenter', ({ e, cell, view }) => {})
+graph.on('node:mouseenter', ({ e, node, view }) => {})
+graph.on('edge:mouseenter', ({ e, edge, view }) => {})
+graph.on('graph:mouseenter', ({ e }) => {})
+```
+
+### Custom Click Events
+
+We can add custom attributes `event` or `data-event` to the DOM elements of nodes/edges to listen for click events on that element, for example:
+
+```ts
+node.attr({
+ // Represents a delete button, which deletes the node when clicked
+ image: {
+ event: 'node:delete',
+ xlinkHref: 'trash.png',
+ width: 20,
+ height: 20,
+ },
+})
+```
+
+You can listen for the bound event name `node:delete` or the generic `cell:customevent`, `node:customevent`, `edge:customevent` event names.
+
+```ts
+graph.on('node:delete', ({ view, e }) => {
+ e.stopPropagation()
+ view.cell.remove()
+})
+
+graph.on('node:customevent', ({ name, view, e }) => {
+ if (name === 'node:delete') {
+ e.stopPropagation()
+ view.cell.remove()
+ }
+})
+```
+
+
+
+### Canvas Zoom/Pan
+
+| Event Name | Callback Parameters | Description |
+|-------------|----------------------------------------------------------|---------------------------------------------------------------|
+| `scale` | `{ sx: number; sy: number; ox: number; oy: number }` | Triggered when zooming the canvas; `sx` and `sy` are the scale factors, `ox` and `oy` are the zoom center. |
+| `resize` | `{ width: number; height: number }` | Triggered when changing the canvas size; `width` and `height` are the canvas dimensions. |
+| `translate` | `{ tx: number; ty: number }` | Triggered when panning the canvas; `tx` and `ty` are the offsets on the X and Y axes. |
+
+```ts
+graph.on('scale', ({ sx, sy, ox, oy }) => {})
+graph.on('resize', ({ width, height }) => {})
+graph.on('translate', ({ tx, ty }) => {})
+```
+
+### Node or Edge Movement
+
+| Event Name | Callback Parameters | Description |
+|---------------|-------------------------------------------------------------------------------------|----------------------------|
+| `node:move` | `{ e: Dom.MouseDownEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered when starting to move a node. |
+| `node:moving` | `{ e: Dom.MouseMoveEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered while moving a node. |
+| `node:moved` | `{ e: Dom.MouseUpEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered after moving a node. |
+| `edge:move` | `{ e: Dom.MouseDownEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered when starting to move an edge. |
+| `edge:moving` | `{ e: Dom.MouseMoveEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered while moving an edge. |
+| `edge:moved` | `{ e: Dom.MouseUpEvent; x: number; y: number; node: Node; view: NodeView }` | Triggered after moving an edge. |
+
+The `x` and `y` parameters are the coordinates of the mouse relative to the canvas.
+
+```ts
+graph.on('node:moved', ({ e, x, y, node, view }) => {})
+```
+
+### Node Embedding
+
+| Event Name | Callback Parameters | Description |
+|------------------|---------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
+| `node:embed` | `{ e: Dom.MouseDownEvent; x: number; y: number; node: Node; view: NodeView, currentParent: Node }` | Triggered when starting to embed a node. |
+| `node:embedding` | `{ e: Dom.MouseMoveEvent; x: number; y: number; node: Node; view: NodeView, currentParent: Node, candidateParent: Node }` | Triggered while searching for the target node. |
+| `node:embedded` | `{ e: Dom.MouseUpEvent; x: number; y: number; node: Node; view: NodeView, previousParent: Node, currentParent: Node }` | Triggered after completing node embedding. |
+
+### Edge Connection/Disconnection
+
+The `edge:connected` event is triggered when dragging the start/end arrow of an edge to connect it to a node/edge or disconnecting it from a node/edge. The callback function parameters are as follows.
+
+```ts
+interface Args {
+ e: Dom.MouseUpEvent // Mouse event object
+ edge: Edge // Edge
+ view: EdgeView // Edge view
+ isNew: boolean // Whether it is a newly created edge
+ type: Edge.TerminalType // Whether the operation is on the start or end arrow ('source' | 'target')
+
+ previousCell?: Cell | null // The node/edge connected before the interaction
+ previousView?: CellView | null // The view of the node/edge connected before the interaction
+ previousPort?: string | null // The ID of the connection point connected before the interaction
+ previousPoint?: Point.PointLike | null // The point connected before the interaction (records the position of the start terminal when dragging the edge terminal from blank to node/edge)
+ previousMagnet?: Element | null // The element connected before the interaction
+
+ currentCell?: Cell | null // The node/edge connected after the interaction
+ currentView?: CellView | null // The view of the node/edge connected after the interaction
+ currentPort?: string | null // The ID of the connection point connected after the interaction
+ currentPoint?: Point.PointLike | null // The point connected after the interaction (records the position of the terminal after dragging from node/edge to blank)
+ currentMagnet?: Element | null // The element connected after the interaction
+}
+```
+
+We can use `isNew` to determine whether the corresponding edge is newly created after the connection is completed. For example, if an edge is created starting from a connection point and connected to another node/connection point, `isNew` will be `true`.
+
+```ts
+graph.on('edge:connected', ({ isNew, edge }) => {
+ if (isNew) {
+ // Perform database insertion or other persistence operations for the newly created edge
+ }
+})
+```
+
+It is particularly important to note that the `previous...` parameters record the state of the terminal before the connection/disconnection operation, and do not refer to `sourceCell`. When obtaining `sourceCell` after creating a new edge, do not use `previousCell`; the correct usage is:
+
+```ts
+graph.on('edge:connected', ({ isNew, edge }) => {
+ if (isNew) {
+ const source = edge.getSourceCell()
+ }
+})
+```
+
+## Node/Edge
+
+### Add/Delete/Modify
+
+When a node/edge is added to the canvas, the following events are triggered:
+
+- `added`
+- `cell:added`
+- `node:added` (only triggered when the cell is a node)
+- `edge:added` (only triggered when the cell is an edge)
+
+When a node/edge is removed, the following events are triggered:
+
+- `removed`
+- `cell:removed`
+- `node:removed` (only triggered when the cell is a node)
+- `edge:removed` (only triggered when the cell is an edge)
+
+When a node/edge undergoes any changes, the following events are triggered:
+
+- `changed`
+- `cell:changed`
+- `node:changed` (only triggered when the cell is a node)
+- `edge:changed` (only triggered when the cell is an edge)
+
+You can listen on the node/edge:
+
+```ts
+cell.on('added', ({ cell, index, options }) => {})
+cell.on('removed', ({ cell, index, options }) => {})
+cell.on('changed', ({ cell, options }) => {})
+```
+
+Or listen on the Graph:
+
+```ts
+graph.on('cell:added', ({ cell, index, options }) => {})
+graph.on('cell:removed', ({ cell, index, options }) => {})
+graph.on('cell:changed', ({ cell, options }) => {})
+
+graph.on('node:added', ({ node, index, options }) => {})
+graph.on('node:removed', ({ node, index, options }) => {})
+graph.on('node:changed', ({ node, options }) => {})
+
+graph.on('edge:added', ({ edge, index, options }) => {})
+graph.on('edge:removed', ({ edge, index, options }) => {})
+graph.on('edge:changed', ({ edge, options }) => {})
+```
+
+### change:xxx
+
+When calling `setXxx(val, options)` and `removeXxx(options)` methods to change the data of a node/edge, and `options.silent` is not `true`, the corresponding `change` event will be triggered, and the node/edge will be redrawn. For example:
+
+```ts
+cell.setZIndex(2)
+cell.setZIndex(2, { silent: false })
+cell.setZIndex(2, { anyKey: 'anyValue' })
+```
+
+This will trigger the following events on the Cell:
+
+- `change:*`
+- `change:zIndex`
+
+And the following events on the Graph:
+
+- `cell:change:*`
+- `node:change:*` (only triggered when the cell is a node)
+- `edge:change:*` (only triggered when the cell is an edge)
+- `cell:change:zIndex`
+- `node:change:zIndex` (only triggered when the cell is a node)
+- `edge:change:zIndex` (only triggered when the cell is an edge)
+
+You can listen on the node/edge:
+
+```ts
+// Triggered when any change occurs on the cell, can determine the changed item through key
+cell.on(
+ 'change:*',
+ (args: {
+ cell: Cell
+ key: string // Determine the changed item through key
+ current: any // Current value
+ previous: any // Value before change
+ options: any // Pass-through options
+ }) => {
+ if (key === 'zIndex') {
+ //
+ }
+ },
+)
+
+cell.on(
+ 'change:zIndex',
+ (args: {
+ cell: Cell
+ current?: number // Current value
+ previous?: number // Value before change
+ options: any // Pass-through options
+ }) => {},
+)
+```
+
+Or listen on the Graph:
+
+```ts
+graph.on(
+ 'cell:change:zIndex',
+ (args: {
+ cell: Cell
+ current?: number // Current value
+ previous?: number // Value before change
+ options: any // Pass-through options
+ }) => {},
+)
+
+// Triggered when the cell is a node
+graph.on(
+ 'node:change:zIndex',
+ (args: {
+ cell: Cell
+ node: Node
+ current?: number // Current value
+ previous?: number // Value before change
+ options: any // Pass-through options
+ }) => {},
+)
+
+// Triggered when the cell is an edge
+graph.on(
+ 'edge:change:zIndex',
+ (args: {
+ cell: Cell
+ edge: Edge
+ current?: number // Current value
+ previous?: number // Value before change
+ options: any // Pass-through options
+ }) => {},
+)
+```
+
+Other `change` events are listed below, and the callback function parameters have the same structure as the parameters mentioned for `change:zIndex`.
+
+- Cell
+ - `change:*`
+ - `change:attrs`
+ - `change:zIndex`
+ - `change:markup`
+ - `change:visible`
+ - `change:parent`
+ - `change:children`
+ - `change:tools`
+ - `change:view`
+ - `change:data`
+- Node
+ - `change:size`
+ - `change:angle`
+ - `change:position`
+ - `change:ports`
+ - `change:portMarkup`
+ - `change:portLabelMarkup`
+ - `change:portContainerMarkup`
+ - `ports:added`
+ - `ports:removed`
+- Edge
+ - `change:source`
+ - `change:target`
+ - `change:terminal`
+ - `change:router`
+ - `change:connector`
+ - `change:vertices`
+ - `change:labels`
+ - `change:defaultLabel`
+ - `vertexs:added`
+ - `vertexs:removed`
+ - `labels:added`
+ - `labels:removed`
+
+In addition to the built-in keys mentioned above, we also support listening to custom keys, for example:
+
+```ts
+cell.on('change:custom', ({ cell, current, previous, options }) => {
+ console.log(current)
+})
+```
+
+When modifying the value of the `custom` property using the `cell.prop('custom', 'any data')` method, the `change:custom` event will be triggered.
+
+### Animation
+
+- `transition:start` is triggered when the animation starts
+- `transition:progress` is triggered during the animation
+- `transition:complete` is triggered when the animation completes
+- `transition:stop` is triggered when the animation is stopped
+- `transition:finish` is triggered when the animation completes or is stopped
+
+```ts
+cell.on('transition:start', (args: Animation.CallbackArgs) => {})
+cell.on('transition:progress', (args: Animation.ProgressArgs) => {})
+cell.on('transition:complete', (args: Animation.CallbackArgs) => {})
+cell.on('transition:stop', (args: Animation.StopArgs) => {})
+cell.on('transition:finish', (args: Animation.CallbackArgs) => {})
+
+graph.on('cell:transition:start', (args: Animation.CallbackArgs) => {})
+graph.on('cell:transition:progress', (args: Animation.ProgressArgs) => {})
+graph.on('cell:transition:complete', (args: Animation.CallbackArgs) => {})
+graph.on('cell:transition:stop', (args: Animation.StopArgs) => {})
+graph.on('cell:transition:finish', (args: Animation.CallbackArgs) => {})
+
+graph.on('node:transition:start', (args: Animation.CallbackArgs) => {})
+graph.on('node:transition:progress', (args: Animation.ProgressArgs) => {})
+graph.on('node:transition:complete', (args: Animation.CallbackArgs) => {})
+graph.on('node:transition:stop', (args: Animation.StopArgs) => {})
+graph.on('node:transition:finish', (args: Animation.CallbackArgs) => {})
+
+graph.on('edge:transition:start', (args: Animation.CallbackArgs) => {})
+graph.on('edge:transition:progress', (args: Animation.ProgressArgs) => {})
+graph.on('edge:transition:complete', (args: Animation.CallbackArgs) => {})
+graph.on('edge:transition:stop', (args: Animation.StopArgs) => {})
+graph.on('edge:transition:finish', (args: Animation.CallbackArgs) => {})
+```
+
+## View
+
+Since X6 implements an asynchronous rendering scheduling algorithm, adding a node does not necessarily mean it is mounted on the canvas. Separate events are triggered when a node is mounted to or unmounted from the canvas.
+
+| Event Name | Callback Parameters | Description |
+|------------------|-----------------------------|----------------------------------|
+| `view:mounted` | `{ view: CellView }` | Triggered when a node is mounted to the canvas. |
+| `view:unmounted` | `{ view: CellView }` | Triggered when a node is unmounted from the canvas. |
+
+```ts
+graph.on('view:mounted', ({ view }) => {})
+graph.on('view:unmounted', ({ view }) => {})
+```
+
+You may also often need to listen for the completion of rendering events after calling `fromJSON` or `resetCells`. In this case, you can use the `render:done` event to listen (added in version 2.15.1).
+
+```typescript
+graph.on('render:done', () => {
+ // pass
+})
+
+graph.fromJSON([...])
+```
diff --git a/sites/x6-sites/docs/tutorial/basic/graph.en.md b/sites/x6-sites/docs/tutorial/basic/graph.en.md
new file mode 100644
index 00000000000..0a4dfa36d3f
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/graph.en.md
@@ -0,0 +1,93 @@
+---
+title: Graph
+order: 0
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This section mainly introduces knowledge related to the graph. By reading, you can learn about"}
+
+- How to make the graph size responsive
+- Optimizing graph style by setting background and grid
+- How to make the graph draggable and resizable
+- Common graph size and position manipulation APIs
+
+:::
+
+## Graph Size
+
+When instantiating a `Graph` object, you can set the `width` and `height` to fix the graph size. If not set, the graph will initialize based on the size of the graph container.
+
+In practical projects, you often encounter the following two scenarios:
+
+- The graph container has not finished rendering (at this point, its size is 0), leading to abnormal display of the graph elements when the graph object is instantiated.
+- The page's `resize` causes the graph container size to change, resulting in abnormal display of the graph elements.
+
+We can use the `autoResize` configuration to solve the above problems.
+
+```html
+
+
+
+## Background and Grid
+
+You can set the graph background and grid using the `background` and `grid` configurations.
+
+
+
+:::info{title="Tip"}
+In X6, the grid is the minimum unit for rendering/moving nodes, with a default size of 10px. This means that a node positioned at `{ x: 24, y: 38 }` will actually render at `{ x: 20, y: 40 }` on the graph.
+:::
+
+The background supports not only colors but also background images. For detailed configurations and methods, refer to the [API](/en/docs/api/graph/background). Additionally, the grid supports four different types and allows configuration of grid line colors and widths. For detailed configurations and methods, refer to the [API](/en/docs/api/graph/grid).
+
+## Zooming and Panning
+
+Dragging and zooming the graph are also common operations. In Graph, these two functionalities are implemented through the `panning` and `mousewheel` configurations. When you press down on the graph and move the mouse, it will drag the graph, and scrolling the mouse wheel will zoom the graph.
+
+```ts
+const graph = new Graph({
+ ...,
+ panning: true,
+ mousewheel: true
+})
+```
+
+Let's experience this through an example:
+
+
+
+Of course, `panning` and `mousewheel` also support many other configurations, such as modifier keys (which must be pressed to trigger the corresponding behavior), zoom factors (rates), etc. We can learn more through the [API](/en/docs/api/graph/mousewheel).
+
+## Common APIs
+
+In addition to the configurations mentioned above, X6 also provides a rich set of APIs for manipulating graph size and position. Here are some commonly used APIs; for more detailed content, see the [API](/en/docs/api/graph/transform).
+
+```ts
+graph.resize(800, 600) // Resize the graph size
+graph.translate(20, 20) // Translate the graph in the x and y directions
+graph.zoom(0.2) // Increase the graph zoom level by 0.2 (default is 1)
+graph.zoom(-0.2) // Decrease the graph zoom level by 0.2
+graph.zoomTo(1.2) // Set the graph zoom level to 1.2
+// Scale the elements in the graph to fit all elements, with maxScale configuration for the maximum zoom level
+graph.zoomToFit({ maxScale: 1 })
+graph.centerContent() // Center the elements in the graph for display
+```
+
+
diff --git a/sites/x6-sites/docs/tutorial/basic/interacting.en.md b/sites/x6-sites/docs/tutorial/basic/interacting.en.md
new file mode 100644
index 00000000000..f448920e7b9
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/interacting.en.md
@@ -0,0 +1,220 @@
+---
+title: Interaction
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="In this chapter, we will mainly introduce the knowledge related to element interaction. After reading, you can understand"}
+
+- How to set connection interaction rules
+- How to embed nodes
+- How to configure highlight styles
+- How to disable or enable some interaction actions
+
+:::
+
+## Connection
+
+Connection interaction rules are all completed through the `connecting` configuration. For a complete configuration, refer to [API](/en/docs/api/interacting/interacting#connection). Below, we introduce some commonly used functions.
+
+### allowXXX
+
+You can use the `allowXXX` configuration to define whether a connection can be connected to a corresponding position. The default supports the following items:
+
+- `allowBlank`: Whether to allow connection to a blank position on the canvas, default is `true`.
+- `allowLoop`: Whether to allow creating a loop connection, i.e., the starting node and ending node are the same node, default is `true`.
+- `allowNode`: Whether to allow connection to a node (non-node connection point), default is `true`.
+- `allowEdge`: Whether to allow connection to another edge, default is `true`.
+- `allowPort`: Whether to allow connection to a connection point, default is `true`.
+- `allowMulti`: Whether to allow creating multiple edges between the same starting node and ending node, default is `true`.
+
+Their values all support the following two types:
+
+```ts
+new Graph({
+ connecting: {
+ allowNode: true, // boolean
+ },
+})
+
+// Function form, often used for dynamic control of connection restrictions
+new Graph({
+ connecting: {
+ allowNode(args) {
+ return true
+ },
+ },
+})
+```
+
+:::info{title="Tip"}
+`allowMulti` supports being set to the string `withPort`, representing that only one edge can be created between the same connection points of the starting and ending nodes (i.e., multiple edges can be created between the starting and ending nodes, but they must be connected to different connection points).
+:::
+
+
+
+### router/connector
+
+In the [edge tutorial](/en/docs/tutorial/basic/edge#router), we know that we can specify `router` and `connector` when adding an edge. If most edges in the entire canvas have the same `router` or `connector`, we can configure them directly in `connecting`, which can avoid repeated configuration in the edge.
+
+```ts
+new Graph({
+ connecting: {
+ router: 'orth',
+ connector: 'rounded',
+ },
+})
+```
+
+### createEdge
+
+In the above demo, we can drag out a connection from a node or connection point. Then you may ask, what kind of elements can drag out a connection? This is a clever design of X6, where any element with the `magnet=true` property can drag out a connection. Moreover, in `connecting`, we can configure the style of the dragged-out connection through the `createEdge` method.
+
+```ts
+new Graph({
+ connecting: {
+ createEdge() {
+ return this.createEdge({
+ shape: 'edge',
+ attrs: {
+ line: {
+ stroke: '#8f8f8f',
+ strokeWidth: 1,
+ },
+ },
+ })
+ },
+ },
+})
+```
+
+### validateXXX
+
+We can also define whether to create a connection or whether the connection is valid through the `validateXXX` method. Compared to `allowXXX`, `validateXXX` is more flexible. The default supports the following items:
+
+- `validateMagnet`: When clicking on an element with `magnet=true`, judge whether to create a new edge according to the return value of `validateMagnet`. If it returns `false`, there will be no reaction; if it returns `true`, a new edge will be created at the current element.
+- `validateConnection`: When moving an edge, judge whether the connection is valid according to the return value of `validateConnection`. If it returns `false`, the connection will not be connected to the current element when the mouse is released.
+- `validateEdge`: When stopping the edge drag, judge whether the edge is valid according to the return value of `validateEdge`. If it returns `false`, the edge will be cleared.
+
+
+
+## Embedding
+
+Sometimes we need to drag a node into another node, making it a child node of the other node. At this time, we can enable embedding through the `embedding` option, and specify the parent node through the `findParent` method when the node is moved. For more detailed configuration, refer to [API](/en/docs/api/interacting/interacting#embedding).
+
+```ts
+const graph = new Graph({
+ embedding: {
+ enabled: true,
+ findParent({ node }) {
+ // Get the bounding box of the moved node
+ const bbox = node.getBBox()
+ // Find the node with `parent: true` in the data and intersect with the moved node's bounding box
+ return this.getNodes().filter((node) => {
+ const data = node.getData<{ parent: boolean }>()
+ if (data && data.parent) {
+ const targetBBox = node.getBBox()
+ return bbox.isIntersectWithRect(targetBBox)
+ }
+ return false
+ })
+ },
+ },
+})
+```
+
+
+
+## Highlighting
+
+We can specify the highlighting style when triggering certain interactions through the `highlighting` option, such as:
+
+```ts
+new Graph({
+ highlighting: {
+ // When the connection point can be connected, render a surrounding box around the connection point
+ magnetAvailable: {
+ name: 'stroke',
+ args: {
+ attrs: {
+ fill: '#fff',
+ stroke: '#A4DEB1',
+ strokeWidth: 4,
+ },
+ },
+ },
+ // When the connection point is adsorbed to the edge, render a surrounding box around the connection point
+ magnetAdsorbed: {
+ name: 'stroke',
+ args: {
+ attrs: {
+ fill: '#fff',
+ stroke: '#31d0c6',
+ strokeWidth: 4,
+ },
+ },
+ },
+ },
+})
+```
+
+Supported `highlighting` configuration items include:
+
+- `default` Default highlighting option, used when the following highlighting configurations are missing.
+- `embedding` Highlighting option used when dragging a node to embed it into another node.
+- `nodeAvailable` Highlighting option used when a node can be connected during the connection process.
+- `magnetAvailable` Highlighting option used when a connection point can be connected during the connection process.
+- `magnetAdsorbed` Highlighting option used when the connection point is automatically adsorbed to the edge during the connection process.
+
+The `magnetAvailable.name` above is actually the name of the highlighter, and X6 has built-in `stroke` and `className` highlighters. For more information, refer to [Highlighter](/en/docs/api/registry/highlighter).
+
+
+
+## Interaction Limitation
+
+We can enable or disable some interaction behaviors of elements through the `interacting` configuration. If the elements on the canvas are purely for preview and cannot be interacted with, we can set it to `false` directly.
+
+```ts
+new Graph({
+ interacting: false,
+})
+```
+
+If we need to define more detailed interaction limitations, we can configure them according to different property values. Supported properties include:
+
+- `nodeMovable` Whether nodes can be moved.
+- `magnetConnectable` Whether to trigger connection interaction when clicking on an element with the `magnet` property.
+- `edgeMovable` Whether edges can be moved.
+- `edgeLabelMovable` Whether edge labels can be moved.
+- `arrowheadMovable` Whether edge arrowheads (after using the arrowhead tool) can be moved.
+- `vertexMovable` Whether edge vertices can be moved.
+- `vertexAddable` Whether edge vertices can be added.
+- `vertexDeletable` Whether edge vertices can be deleted.
+
+Their values all support the following two types:
+
+```ts
+// Directly set to a boolean value
+new Graph({
+ interacting: {
+ nodeMovable: false,
+ edgeMovable: true,
+ },
+})
+
+// Function form, often used for dynamic control of interaction behaviors
+new Graph({
+ interacting: {
+ nodeMovable(view) {
+ const node = view.cell
+ const { enableMove } = node.getData()
+ return enableMove
+ },
+ },
+})
+```
+
+
diff --git a/sites/x6-sites/docs/tutorial/basic/node.en.md b/sites/x6-sites/docs/tutorial/basic/node.en.md
new file mode 100644
index 00000000000..8875a704e64
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/node.en.md
@@ -0,0 +1,150 @@
+---
+title: Nodes
+order: 1
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial/basic
+ - /en/docs/tutorial/basic/basic
+---
+
+:::info{title="In this chapter, we mainly introduce knowledge related to nodes. By reading, you can learn about"}
+
+- Node rendering methods supported by X6
+- Methods for adding nodes
+- Built-in node types in X6
+- How to customize nodes
+- How to modify nodes through the API
+
+:::
+
+## Node Rendering Method
+
+X6 is based on an `SVG` rendering engine, which allows for rendering nodes and edges using different SVG elements, making it particularly suitable for scenarios where node content is relatively simple. For more complex nodes, there is a special `foreignObject` element in `SVG` that can embed any XHTML elements. This element can be used to render HTML, React/Vue/Angular components at the desired location, greatly facilitating project development.
+
+When choosing a rendering method, we recommend:
+
+- If the node content is relatively simple and the requirements are fixed, use `SVG` nodes.
+- For other scenarios, it is recommended to use the framework currently employed in the project to render nodes.
+
+:::warning{title=Note}
+The React/Vue/HTML rendering methods also have some limitations. Due to browser compatibility issues, there may occasionally be some abnormal rendering behaviors, primarily manifested as incomplete node content display or flickering of node content. This can be mitigated by avoiding the use of `position:absolute`, `position:relative`, `transform`, and `opacity` in the CSS styles of internal elements of the node.
+:::
+
+The following introduction is based on `SVG` nodes, but the usage of other rendering forms is very similar, and we will revisit this in the advanced tutorial.
+
+## Adding Nodes
+
+Both nodes and edges share a common base class [Cell](/en/docs/api/model/cell). In addition to inheriting properties from `Cell`, they also support the following options.
+
+| Property Name | Type | Default Value | Description |
+|---------------|--------|---------------|-----------------------------------|
+| x | number | 0 | Node position x coordinate, in px. |
+| y | number | 0 | Node position y coordinate, in px. |
+| width | number | 1 | Node width, in px. |
+| height | number | 1 | Node height, in px. |
+| angle | number | 0 | Node rotation angle. |
+
+```ts
+graph.addNode({
+ shape: 'rect',
+ x: 100,
+ y: 40,
+ width: 100,
+ height: 40,
+})
+```
+
+## Built-in Nodes
+
+The above example uses `shape` to specify the node's graphic, with the default value of `shape` being `rect`. The correspondence between X6 built-in nodes and `shape` names is as follows:
+
+| Constructor | Shape Name | Description |
+|-------------------|------------|-----------------------------------------------------|
+| Shape.Rect | rect | Rectangle. |
+| Shape.Circle | circle | Circle. |
+| Shape.Ellipse | ellipse | Ellipse. |
+| Shape.Polygon | polygon | Polygon. |
+| Shape.Polyline | polyline | Polyline. |
+| Shape.Path | path | Path. |
+| Shape.Image | image | Image. |
+| Shape.HTML | html | HTML node, uses `foreignObject` to render HTML fragments. |
+
+
+
+## Customizing Nodes
+
+We can customize the shape and style of nodes using `markup` and `attrs`, where `markup` is analogous to `HTML` and `attrs` is analogous to `CSS`. It is strongly recommended to read the documentation on [markup](/en/docs/api/model/cell#markup) and [attrs](/en/docs/api/model/cell#attrs) carefully.
+
+Next, we may encounter a problem: if the customized content needs to be used by multiple nodes, do we need to redefine it for each node? The answer is no. X6 provides a convenient way to allow different nodes to reuse configurations.
+
+
+
+## Modifying Nodes
+
+After rendering is complete, we can also modify all properties of a node through the API. The two methods we commonly use are:
+
+- node.prop(path, value), for detailed usage see [prop](/en/docs/api/model/cell#node-and-edge-properties-properties).
+- node.attr(path, value), for detailed usage see [attr](/en/docs/api/model/cell#element-attributes-attrs).
+
+First, let's look at `prop`. We will directly print the `prop` values of the default rect node in X6.
+
+```ts
+const node = graph.addNode({
+ shape: 'rect',
+ width: 100,
+ height: 40,
+ x: 100,
+ y: 100,
+ label: 'edge',
+})
+console.log(node.prop())
+
+// Result
+{
+ "angle": 0,
+ "position": {
+ "x": 100,
+ "y": 100
+ },
+ "size": {
+ "width": 100,
+ "height": 40
+ },
+ "attrs": {
+ "text": {
+ "fontSize": 14,
+ "fill": "#000000",
+ "refX": 0.5,
+ "refY": 0.5,
+ "textAnchor": "middle",
+ "textVerticalAnchor": "middle",
+ "fontFamily": "Arial, helvetica, sans-serif",
+ "text": "node"
+ },
+ "rect": {
+ "fill": "#ffffff",
+ "stroke": "#333333",
+ "strokeWidth": 2
+ },
+ "body": {
+ "refWidth": "100%",
+ "refHeight": "100%"
+ }
+ },
+ "visible": true,
+ "shape": "rect",
+ "id": "ab47cadc-4104-457c-971f-50fbb077508a",
+ "zIndex": 1
+}
+```
+
+From the above result, we can see that `prop` is a new configuration after processing, and its values can be updated through methods. After updating, the node will immediately refresh to the latest state. To modify the node's `attrs` more conveniently, X6 provides the `attr` method.
+
+```ts
+source.prop('size', { width: 120, height: 50 }) // Modify x coordinate
+source.attr('rect/fill', '#ccc') // Modify fill color, equivalent to source.prop('attrs/rect/fill', '#ccc')
+```
+
+
+
+In the above JSON output, we can see that some properties like `refWidth` and `refHeight` are not native SVG properties. They are actually special properties built into X6, such as `refWidth`, which represents relative width. For more detailed special properties, refer to [attrs](/en/docs/api/model/attrs).
diff --git a/sites/x6-sites/docs/tutorial/basic/port.en.md b/sites/x6-sites/docs/tutorial/basic/port.en.md
new file mode 100644
index 00000000000..7edf1f1191e
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/port.en.md
@@ -0,0 +1,122 @@
+---
+title: Connection Pile
+order: 3
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This chapter mainly introduces knowledge related to connection piles. By reading, you can learn about"}
+
+- How to configure connection piles in nodes
+- Adding, deleting, and modifying connection piles
+- How to configure the position of connection piles
+- How to configure the position of labels on connection piles
+
+:::
+
+## Configuring Connection Ports
+
+First, we group connection ports that have the same behavior and appearance into the same group, and set the grouping using the `groups` option, which is an object `{ [groupName: string]: PortGroupMetadata }`. The group name is the key, and the value is the default options for each group of connection ports. The supported options are as follows:
+
+```ts
+interface PortGroupMetadata {
+ markup?: Markup // Definition of the connection port DOM structure.
+ attrs?: Attr.CellAttrs // Attributes and styles.
+ zIndex?: number | 'auto' // The DOM layer level of the connection port; the higher the value, the higher the level.
+ // Layout of connection ports in the group.
+ position?: [number, number] | string | { name: string; args?: object }
+ label?: {
+ // Connection port label
+ markup?: Markup
+ position?: {
+ // Layout of the connection port label
+ name: string // Layout name
+ args?: object // Layout parameters
+ }
+ }
+}
+```
+
+Next, we configure `items`, which is an array `PortMetadata[]`. Each item in the array represents a connection port, and the supported options for connection ports are as follows:
+
+```ts
+interface PortMetadata {
+ id?: string // Unique ID for the connection port, automatically generated by default.
+ group?: string // Group name; specifying a group will inherit the options of the connection ports in that group.
+ args?: object // Parameters for the layout algorithm specified for the connection ports in the group. We cannot specify a layout algorithm for a single connection port, but we can provide different parameters for the layout algorithm specified for the group.
+ markup?: Markup // Definition of the connection port's DOM structure. Specifying this option will override the default options provided by the group referred to by `group`.
+ attrs?: Attr.CellAttrs // Element's attribute styles. Specifying this option will override the default options provided by the group referred to by `group`.
+ zIndex?: number | 'auto' // The DOM layer level of the connection port; the higher the value, the higher the level. Specifying this option will override the default options provided by the group referred to by `group`.
+ label?: {
+ // Label for the connection port. Specifying this option will override the default options provided by the group referred to by `group`.
+ markup?: Markup // Label DOM structure
+ position?: {
+ // Label position
+ name: string // Name of the label position calculation method
+ args?: object // Parameters for the label position calculation method
+ }
+ }
+}
+```
+
+The following example code clearly shows how to define connection ports.
+
+
+
+## Modifying Connection Ports
+
+There is a rich [API](/en/docs/api/model/node#connection-ports) for adding, deleting, and modifying connection ports on nodes.
+
+```ts
+// Add a connection port
+node.addPort({
+ group: 'top',
+ attrs: {
+ text: {
+ text: 'xx',
+ },
+ },
+})
+
+// Remove a connection port
+node.removePort(portId)
+
+// Update a connection port
+node.portProp(portId, 'attrs/circle/stroke', color)
+```
+
+
+
+## Connection Port Position
+
+The layout algorithm for connection ports can only be specified through the `position` option in `groups`, as the layout algorithm needs to consider all connection ports in the group when calculating their positions. We can influence the layout result of a single connection port through the `args` option.
+
+We provide the following layout algorithms for connection ports by default, and also support [custom connection port layout algorithms and registration](/en/docs/api/registry/port-layout#registry). Click the links below to learn how to use each layout algorithm.
+
+- [`absolute`](/en/docs/api/registry/port-layout#absolute) Absolute positioning.
+- [`left`](/en/docs/api/registry/port-layout#left-right-top-bottom) Evenly distributed on the left side of rectangular nodes.
+- [`right`](/en/docs/api/registry/port-layout#left-right-top-bottom) Evenly distributed on the right side of rectangular nodes.
+- [`top`](/en/docs/api/registry/port-layout#left-right-top-bottom) Evenly distributed on the top of rectangular nodes.
+- [`bottom`](/en/docs/api/registry/port-layout#left-right-top-bottom) Evenly distributed on the bottom of rectangular nodes.
+- [`line`](/en/docs/api/registry/port-layout#line) Evenly distributed along a specified line.
+- [`ellipse`](/en/docs/api/registry/port-layout#ellipse) Distributed along an elliptical arc.
+- [`ellipseSpread`](/en/docs/api/registry/port-layout#ellipsespread) Evenly distributed along an ellipse.
+
+## Connection Port Label Position
+
+The position of the label can be specified in both the `label.position` option of `groups` and the `items.label.position` option of the node.
+
+We provide the following label positions by default, and also support [custom label positions and registration](/en/docs/api/registry/port-label-layout#registry). Click the links below to learn how to use each label position.
+
+- [`left`](/en/docs/api/registry/port-label-layout#side) The label is located on the left side of the connection port.
+- [`right`](/en/docs/api/registry/port-label-layout#side) The label is located on the right side of the connection port.
+- [`top`](/en/docs/api/registry/port-label-layout#side) The label is located above the connection port.
+- [`bottom`](/en/docs/api/registry/port-label-layout#side) The label is located below the connection port.
+- [`inside`](/en/docs/api/registry/port-label-layout#insideoutside) The label is located inside the node (close to the edge).
+- [`outside`](/en/docs/api/registry/port-label-layout#insideoutside) The label is located outside the node (close to the edge).
+- [`insideOriented`](/en/docs/api/registry/port-label-layout#insideoutside) The label is located inside the node and automatically adjusts the text direction based on its position.
+- [`outsideOriented`](/en/docs/api/registry/port-label-layout#insideoutside) The label is located outside the node and automatically adjusts the text direction based on its position.
+- [`radial`](/en/docs/api/registry/port-label-layout#radial) The label is located outside circular or elliptical nodes.
+- [`radialOriented`](/en/docs/api/registry/port-label-layout#radial) The label is located outside circular or elliptical nodes and the label text automatically rotates along the arc direction.
diff --git a/sites/x6-sites/docs/tutorial/basic/serialization.en.md b/sites/x6-sites/docs/tutorial/basic/serialization.en.md
new file mode 100644
index 00000000000..1def3fcc069
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/basic/serialization.en.md
@@ -0,0 +1,101 @@
+---
+title: Data Serialization
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This section mainly introduces knowledge related to canvas data serialization. By reading, you can learn about"}
+
+- How to import data
+- How to export data
+
+:::
+
+## Export
+
+We can call the `graph.toJSON()` method to export the nodes and edges in the graph, returning an object with the structure `{ cells: [] }`, where the `cells` array stores nodes and edges **in rendering order**.
+
+The structure of the exported nodes is as follows:
+
+```ts
+{
+ id: string,
+ shape: string,
+ position: {
+ x: number,
+ y: number
+ },
+ size: {
+ width: number,
+ height: number
+ },
+ attrs: object,
+ zIndex: number,
+}
+```
+
+The structure of the edges is as follows:
+
+```ts
+{
+ id: string,
+ shape: string,
+ source: object,
+ target: object,
+ attrs: object,
+ zIndex: number,
+}
+```
+
+
+
+## Import
+
+Support for an array of node/edge metadata `graph.fromJSON(cells: (Node.Metadata | Edge.Metadata)[])`.
+
+```ts
+graph.fromJSON([
+ {
+ id: 'node1',
+ x: 40,
+ y: 40,
+ width: 100,
+ height: 40,
+ label: 'Hello',
+ shape: 'rect',
+ },
+ {
+ id: 'node2',
+ x: 40,
+ y: 40,
+ width: 100,
+ height: 40,
+ label: 'Hello',
+ shape: 'ellipse',
+ },
+ {
+ id: 'edge1',
+ source: 'node1',
+ target: 'node2',
+ shape: 'edge',
+ },
+])
+```
+
+Alternatively, provide an object containing `cells`, `nodes`, and `edges`, rendered in the order of `[...cells, ...nodes, ...edges]`.
+
+```ts
+graph.fromJSON({
+ nodes: [],
+ edges: [],
+})
+```
+
+Typically, we render the data exported by `graph.toJSON()` using `graph.fromJSON(...)`.
+
+:::info{title="Tip"}
+When the data does not provide a `zIndex`, the rendering is done according to the order of nodes/edges in the array, meaning that nodes/edges that appear earlier have a smaller `zIndex`, resulting in a lower layer in the canvas.
+:::
diff --git a/sites/x6-sites/docs/tutorial/basic/serialization.zh.md b/sites/x6-sites/docs/tutorial/basic/serialization.zh.md
index 40d22308a5e..d610f55b6b6 100644
--- a/sites/x6-sites/docs/tutorial/basic/serialization.zh.md
+++ b/sites/x6-sites/docs/tutorial/basic/serialization.zh.md
@@ -1,6 +1,6 @@
---
title: 数据
-order: 5
+order: 6
redirect_from:
- /zh/docs
- /zh/docs/tutorial
diff --git a/sites/x6-sites/docs/tutorial/devtool.en.md b/sites/x6-sites/docs/tutorial/devtool.en.md
new file mode 100644
index 00000000000..bb8390ddcc2
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/devtool.en.md
@@ -0,0 +1,38 @@
+---
+title: Developer Tools
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+---
+
+We provide a plugin for inspecting page elements to help developers more easily develop applications.
+
+### Installation
+
+![image](https://user-images.githubusercontent.com/1826685/238003455-d341f598-1b35-4d8c-bb7c-0320cad6a4cb.png)
+
+### Usage
+
+First, initialize in your project code:
+
+```javascript
+// init window hook
+window.__x6_instances__ = []
+
+const graph = new Graph({ ...blablabla })
+
+window.__x6_instances__.push(graph)
+```
+
+Then you can see the AntV X6 section in the developer panel.
+
+![image](https://user-images.githubusercontent.com/1826685/238013980-2d6018f8-7d85-473c-a043-98b1f03b6674.png)
+
+Here, we can inspect the graph object and the elements within the graph:
+
+![image](https://user-images.githubusercontent.com/1826685/238014156-e65ec2b0-f719-410e-9a10-89cdb836acde.png)
+
+It also supports modifying element properties:
+
+![image](https://user-images.githubusercontent.com/1826685/238014353-124feb8e-2049-499d-a13d-3d26f485bab6.png)
diff --git a/sites/x6-sites/docs/tutorial/getting-started.en.md b/sites/x6-sites/docs/tutorial/getting-started.en.md
index 1cbe4b07f9b..689e1db8f95 100644
--- a/sites/x6-sites/docs/tutorial/getting-started.en.md
+++ b/sites/x6-sites/docs/tutorial/getting-started.en.md
@@ -86,3 +86,5 @@ In addition to using `fromJSON` to render JSON data to the graph, of course, the
```ts
graph.toJSON()
```
+
+That's the end of our demo. If you want to continue learning about some capabilities of X6, you can start reading from the [Basic Tutorial](/en/docs/tutorial/basic/graph).
diff --git a/sites/x6-sites/docs/tutorial/intermediate/angular.en.md b/sites/x6-sites/docs/tutorial/intermediate/angular.en.md
new file mode 100644
index 00000000000..48d69b9a2e5
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/angular.en.md
@@ -0,0 +1,155 @@
+---
+title: Angular Nodes
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/intermediate
+---
+
+:::info{title="In this chapter, you will learn about"}
+
+- How to use Angular to render node content
+- How to update node content
+- FAQ
+
+:::
+
+## Rendering Nodes
+
+We provide a standalone package `@antv/x6-angular-shape` to support rendering Angular components/templates as nodes.
+
+:::warning{title=Note}
+It is important to ensure that the version of x6 matches the version of x6-angular-shape, meaning both packages should use the same major version.
+:::
+
+### Component Rendering
+
+```ts
+@Component({
+ selector: 'app-node',
+ templateUrl: './node.component.html',
+ styleUrls: ['./node.component.scss'],
+})
+export class NodeComponent implements AfterViewInit, OnChanges {
+ @Input() value: string;
+}
+```
+
+```ts
+import { register } from '@antv/x6-angular-shape';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.scss'],
+})
+export class AppComponent implements AfterViewInit {
+ ngAfterViewInit(): void {
+ register({
+ shape: 'custom-angular-component-node',
+ width: 120,
+ height: 20,
+ content: NodeComponent,
+ injector: this.injector,
+ });
+
+ this.graph.addNode({
+ shape: 'custom-angular-component-node',
+ x: 100,
+ y: 100,
+ data: {
+ // Input parameters must be placed here
+ ngArguments: {
+ value: 'Oh my god, what a mess',
+ },
+ },
+ });
+ }
+}
+```
+
+### TemplateRef Rendering
+
+```html
+
+
+When we move the node above, we will notice that the connection points of the edges and the node remain unchanged, and there is a gap between multiple edges. This is completely different from the phenomenon in the previous example. How is this achieved? Let's understand `anchor points` and `connection points` through the following diagram.
+
+## Introduction
+
+By default, the anchor point is set to `center`, which means it is located at the center of the element. The connection point is a method for calculating intersection points, with the default set to `boundary`, meaning it calculates the intersection with the element's border. Therefore, the edge is drawn as a reference line from the anchor point of the starting element to the anchor point of the target element. The intersection point between the reference line and the element is determined by the calculation method specified by the `connectionPoint`, and this intersection point serves as the starting and ending point of the edge.
+
+
+
+## Usage
+
+Both the anchor point `anchor` and the connection point `connectionPoint` have two usage methods. The first method is to configure them in `connecting`, which applies globally. The second method is to specify them when creating an edge in `source` and `target`.
+
+```ts
+// Configuring in connecting
+const graph = new Graph({
+ connecting: {
+ sourceAnchor: {
+ name: 'right', // The anchor point will be offset 10px upwards from the center of the right side of the node
+ args: {
+ dy: -10,
+ },
+ },
+ targetAnchor: {
+ name: 'right', // The anchor point will be offset 10px upwards from the center of the right side of the node
+ args: {
+ dy: -10,
+ },
+ },
+ connectionPoint: 'anchor',
+ },
+})
+
+// You can also configure it when creating the edge, which takes higher priority
+graph.addEdge({
+ source: {
+ cell: source,
+ anchor: {
+ name: 'right',
+ args: {
+ dy: -10,
+ },
+ },
+ connectionPoint: 'anchor',
+ },
+ target: {
+ cell: target,
+ anchor: {
+ name: 'left',
+ args: {
+ dy: -10,
+ },
+ },
+ connectionPoint: 'anchor',
+ },
+})
+```
+
+Of course, X6 also supports a wide variety of anchor and connection point types. If you want to customize special connection edges, you can refer to [NodeAnchor](/en/docs/api/registry/node-anchor) and [ConnectionPoint](/en/docs/api/registry/connection-point).
diff --git a/sites/x6-sites/docs/tutorial/intermediate/group.en.md b/sites/x6-sites/docs/tutorial/intermediate/group.en.md
new file mode 100644
index 00000000000..37ee31fab44
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/group.en.md
@@ -0,0 +1,139 @@
+---
+title: Group
+order: 3
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This chapter mainly introduces knowledge related to grouping. By reading, you can learn about"}
+
+- How to group nodes
+- How to group nodes through interactive methods
+- How to restrict the movement of child nodes within a group
+- How to achieve the effect of automatically expanding parent nodes
+- How to implement the effect of expanding and collapsing parent nodes
+:::
+
+## Group Nodes
+
+We can implement groups through parent-child combinations and provide a series of [methods](/en/docs/api/model/cell#parentchildren-relationship) to get and set these relationships.
+
+
+
+From the example above, we can see that:
+
+- When the parent node is moved, the child nodes will also move along with it, even if the child nodes are outside the parent node.
+- By default, the common parent of the starting and ending nodes of an edge is considered the parent of the edge. When the parent node is moved, the path points of the edge will follow.
+
+## Combining Nodes through Interaction
+
+Sometimes we need to drag one node into another node to make it a child of the other node. In this case, we can enable the `embedding` option, which allows us to specify a method through `findParent` to return the parent node when the node is moved. For more detailed configuration, refer to the [API](/en/docs/api/interacting/interacting#embedding).
+
+
+
+## Restricting the Movement of Child Nodes
+
+At times, we need to limit the movement range of child nodes within the parent node. This can be achieved by using the `translating.restrict` option when creating the `Graph` instance.
+
+
+
+## Automatically Expanding the Parent Node
+
+By listening to the `node:change:position` event, we can automatically expand or shrink the size of the parent node when the child node moves, ensuring that the parent node completely encompasses the child nodes. The code here is a bit complex; you can click the `CodeSandbox` link below the demo to view the detailed code.
+
+
+
+## Expanding and Collapsing the Parent Node
+
+First, we define a custom `Group` node, which renders an expand/collapse button in the top-left corner and sets a custom event `node:collapse` on that button:
+
+```ts
+import { Node } from '@antv/x6'
+
+export class Group extends Node {
+ private collapsed: boolean = false
+ private expandSize: { width: number; height: number }
+
+ protected postprocess() {
+ this.toggleCollapse(false)
+ }
+
+ isCollapsed() {
+ return this.collapsed
+ }
+
+ toggleCollapse(collapsed?: boolean) {
+ const target = collapsed == null ? !this.collapsed : collapsed
+ if (target) {
+ this.attr('buttonSign', { d: 'M 1 5 9 5 M 5 1 5 9' })
+ this.expandSize = this.getSize()
+ this.resize(100, 32)
+ } else {
+ this.attr('buttonSign', { d: 'M 2 5 8 5' })
+ if (this.expandSize) {
+ this.resize(this.expandSize.width, this.expandSize.height)
+ }
+ }
+ this.collapsed = target
+ }
+}
+
+Group.config({
+ markup: [
+ {
+ tagName: 'rect',
+ selector: 'body',
+ },
+ {
+ tagName: 'text',
+ selector: 'label',
+ },
+ {
+ tagName: 'g',
+ selector: 'buttonGroup',
+ children: [
+ {
+ tagName: 'rect',
+ selector: 'button',
+ },
+ {
+ tagName: 'path',
+ selector: 'buttonSign',
+ },
+ ],
+ },
+ ],
+ attrs: {
+ body: { ... },
+ label: { ... },
+ buttonGroup: { ... },
+ button: {
+ ...
+ // Custom event
+ event: 'node:collapse',
+ },
+ buttonSign: { ... },
+ },
+})
+```
+
+Then, we listen for the `node:collapse` event on the `graph`, showing or hiding the corresponding child nodes when the parent node is expanded or collapsed:
+
+```ts
+graph.on('node:collapse', ({ node }: { node: Group }) => {
+ node.toggleCollapse()
+ const collapsed = node.isCollapsed()
+ const cells = node.getDescendants()
+ cells.forEach((node) => {
+ if (collapsed) {
+ node.hide()
+ } else {
+ node.show()
+ }
+ })
+})
+```
+
+
diff --git a/sites/x6-sites/docs/tutorial/intermediate/html.en.md b/sites/x6-sites/docs/tutorial/intermediate/html.en.md
new file mode 100644
index 00000000000..0f24172890b
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/html.en.md
@@ -0,0 +1,66 @@
+---
+title: HTML Nodes
+order: 7
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/intermediate
+---
+
+:::info{title="In this chapter, you will learn"}
+
+- How to use HTML to render node content
+- How to update node content
+
+:::
+
+## Rendering Nodes
+
+X6 comes with built-in `HTML` rendering capabilities, and it's very easy to use:
+
+```ts
+import { Shape } from '@antv/x6'
+
+Shape.HTML.register({
+ shape: 'custom-html',
+ width: 160,
+ height: 80,
+ html() {
+ const div = document.createElement('div')
+ div.className = 'custom-html'
+ return div
+ },
+})
+
+graph.addNode({
+ shape: 'custom-html',
+ x: 60,
+ y: 100,
+})
+```
+
+In the example below, we add a hover animation effect to the `HTML` element, which would be quite complex to implement using `SVG`.
+
+
+
+## Node Updates
+
+You might be curious about how to dynamically update the content of a node if it is rendered dynamically. It's actually quite simple. When registering the node, you provide an `effect` field, which is an array of the current node's `prop`. When any of the `prop` included in the `effect` changes, the `html` method will be re-executed, returning a new DOM element to update the node's content.
+
+```ts
+Shape.HTML.register({
+ shape: 'custom-html',
+ width: 160,
+ height: 80,
+ effect: ['data'],
+ html(cell) {
+ const { color } = cell.getData()
+ const div = document.createElement('div')
+ div.className = 'custom-html'
+ div.style.background = color
+ return div
+ },
+})
+```
+
+
diff --git a/sites/x6-sites/docs/tutorial/intermediate/html.md b/sites/x6-sites/docs/tutorial/intermediate/html.zh.md
similarity index 100%
rename from sites/x6-sites/docs/tutorial/intermediate/html.md
rename to sites/x6-sites/docs/tutorial/intermediate/html.zh.md
diff --git a/sites/x6-sites/docs/tutorial/intermediate/react.en.md b/sites/x6-sites/docs/tutorial/intermediate/react.en.md
new file mode 100644
index 00000000000..cefc310a812
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/react.en.md
@@ -0,0 +1,99 @@
+---
+title: React Nodes
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/intermediate
+---
+
+:::info{title="In this chapter, you will learn"}
+- How to use React components to render node content
+- How to update node content
+:::
+
+## Rendering Nodes
+
+We provide a standalone package `@antv/x6-react-shape` for rendering nodes using React.
+
+:::warning{title=Note}
+It is important to ensure that the version of x6 matches the version of x6-react-shape, meaning both packages need to use the same major version. For example, if X6 is using version 2.x, then x6-react-shape must also use version 2.x.
+:::
+
+:::warning{title=Note}
+x6-react-shape only supports React 18 and above starting from version 2.0.8. If your project is using a version lower than React 18, please lock the version of x6-react-shape to 2.0.8.
+:::
+
+```ts
+import { register } from '@antv/x6-react-shape'
+
+const NodeComponent = () => {
+ return (
+
+
+## Updating Nodes
+
+Similar to `HTML`, when registering a node, you provide an `effect` field, which is an array of the current node's `props`. When any of the `props` included in the `effect` change, the current React component will be re-rendered.
+
+```ts
+register({
+ shape: 'custom-react-node',
+ width: 100,
+ height: 100,
+ effect: ['data'],
+ component: NodeComponent,
+})
+
+const node = graph.addNode({
+ shape: 'custom-react-node',
+ x: 60,
+ y: 100,
+ data: {
+ progress: 30,
+ },
+})
+
+setInterval(() => {
+ const { progress } = node.getData<{ progress: number }>()
+ node.setData({
+ progress: (progress + 10) % 100,
+ })
+}, 1000)
+```
+
+
+
+## Portal Mode
+
+The rendering method of the above React component has a drawback, as it renders the component into the node's DOM using the following approach.
+
+```ts
+import { createRoot, Root } from 'react-dom/client'
+
+const root = createRoot(container) // container is the node container
+root.render(component)
+```
+
+As you can see, the React component is no longer part of the normal rendering document tree. Therefore, it cannot access external `Context` content. If you have such application scenarios, you can use the `Portal` mode to render React components.
+
+
diff --git a/sites/x6-sites/docs/tutorial/intermediate/tools.en.md b/sites/x6-sites/docs/tutorial/intermediate/tools.en.md
new file mode 100644
index 00000000000..c417bd2fe7c
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/tools.en.md
@@ -0,0 +1,80 @@
+---
+title: Tools
+order: 2
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/intermediate
+---
+
+:::info{title="This chapter mainly introduces knowledge related to tools. By reading, you can learn about"}
+
+- How to add tools for nodes or edges
+- What common tools are built into X6 by default
+
+:::
+
+## Using Tools
+
+When creating nodes/edges, you can add tools through the [`tools`](/en/docs/api/model/cell#tools) option:
+
+```ts
+graph.addNode({
+ tools: [
+ {
+ name: 'button-remove', // Tool name
+ args: {
+ // Parameters corresponding to the tool
+ x: 10,
+ y: 10,
+ },
+ },
+ ],
+})
+
+// If the parameters are empty, it can be abbreviated as:
+graph.addNode({
+ tools: ['button-remove'],
+})
+
+graph.addEdge({
+ source,
+ target,
+ vertices: [
+ {
+ x: 90,
+ y: 160,
+ },
+ {
+ x: 210,
+ y: 160,
+ },
+ ],
+ tools: ['vertices', 'segments'],
+})
+```
+
+
+
+After nodes/edges are created, you can call methods like [hasTool(name)](/en/docs/api/model/cell#hastool), [addTools(...)](/en/docs/api/model/cell#addtools), and [removeTools()](/en/docs/api/model/cell#removetools) to add or remove tools.
+
+
+
+## Built-in Tools
+
+Tools are widgets rendered on nodes/edges to enhance their interactivity. We provide the following built-in tools for nodes and edges:
+
+### Nodes:
+
+- [button](/en/docs/api/registry/node-tool#button) Renders a button at a specified position, supporting custom click interactions for the button.
+- [button-remove](/en/docs/api/registry/node-tool#button-remove) Renders a delete button at a specified position, which deletes the corresponding node when clicked.
+- [boundary](/en/docs/api/registry/node-tool#boundary) Renders a rectangle surrounding the node based on its bounding box. Note that this tool only renders a rectangle without any interaction.
+
+### Edges:
+
+- [vertices](/en/docs/api/registry/edge-tool#vertices) Path point tool that renders a small dot at the path point position. You can drag the dot to modify the path point position, double-click the dot to delete the path point, and click on the edge to add a path point.
+- [segments](/en/docs/api/registry/edge-tool#segments) Segment tool that renders a toolbar at the center of each line segment of the edge. You can drag the toolbar to adjust the positions of the path points at both ends of the segment.
+- [boundary](/en/docs/api/registry/edge-tool#boundary) Renders a rectangle surrounding the edge based on its bounding box. Note that this tool only renders a rectangle without any interaction.
+- [button](/en/docs/api/registry/edge-tool#button) Renders a button at a specified position, supporting custom click interactions for the button.
+- [button-remove](/en/docs/api/registry/edge-tool#button-remove) Renders a delete button at a specified position, which deletes the corresponding edge when clicked.
+- [source-arrowhead and target-arrowhead](/en/docs/api/registry/edge-tool#source-arrowhead-and-target-arrowhead) Renders a shape (default is an arrow) at the start or end of the edge, allowing you to drag the shape to modify the start or end of the edge.
diff --git a/sites/x6-sites/docs/tutorial/intermediate/vue.en.md b/sites/x6-sites/docs/tutorial/intermediate/vue.en.md
new file mode 100644
index 00000000000..76be5b1cf65
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/intermediate/vue.en.md
@@ -0,0 +1,200 @@
+---
+title: Vue Nodes
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/intermediate
+---
+
+:::info{title="In this chapter, you will learn about"}
+
+- How to use Vue components to render node content
+- How to update node content
+
+:::
+
+## Rendering Nodes
+
+We provide a standalone package `@antv/x6-vue-shape` to render nodes using Vue components.
+
+:::warning{title=Note}
+It is important to ensure that the versions of x6 and x6-vue-shape match, meaning both packages should use the same major version.
+:::
+
+```html
+
+
+
+## Configuration
+
+| Property Name | Type | Default Value | Required | Description |
+|---------------------|---------|---------------|----------|---------------------------------------------------------------------------------------------------|
+| useLocalStorage | boolean | `false` | | When enabled, the copied nodes/edges are also saved to `localStorage`, allowing copy/paste to work after refreshing or reopening the browser. |
+
+## API
+
+### graph.copy(...)
+
+```ts
+copy(cells: Cell[], options: CopyOptions = {}): this
+```
+
+Copy nodes/edges. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|-------------------------|---------|:--------:|---------------|-----------------------------------------------|
+| cells | Cell[] | ✓ | | The nodes/edges to be copied. |
+| options.deep | boolean | | - | Whether to recursively copy all child nodes/edges. |
+| options.useLocalStorage | boolean | | - | Whether to save the copied nodes/edges in `localStorage`. |
+
+### graph.cut(...)
+
+```ts
+cut(cells: Cell[], options: CopyOptions = {}): this
+```
+
+Cut nodes/edges. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|-------------------------|---------|:--------:|---------------|-----------------------------------------------|
+| cells | Cell[] | ✓ | | The nodes/edges to be cut. |
+| options.deep | boolean | | - | Whether to recursively copy all child nodes/edges. |
+| options.useLocalStorage | boolean | | - | Whether to save the copied nodes/edges in `localStorage`. |
+
+### graph.paste(...)
+
+```ts
+paste(options?: PasteOptions, graph?: Graph): Cell[]
+```
+
+Paste and return the nodes/edges pasted onto the canvas. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|-------------------------|----------------------------------------|:--------:|---------------|---------------------------------------------|
+| options.useLocalStorage | boolean | | - | Whether to use nodes/edges from `localStorage`. |
+| options.offset | number \| `{ dx: number; dy: number }` | | `20` | The offset for the nodes/edges pasted onto the canvas. |
+| options.nodeProps | Node.Properties | | - | Additional properties for the nodes pasted onto the canvas. |
+| options.edgeProps | Edge.Properties | | - | Additional properties for the edges pasted onto the canvas. |
+| graph | Graph | | `this` | The target canvas for pasting, defaults to the current canvas. |
+
+### graph.getCellsInClipboard()
+
+```ts
+getCellsInClipboard: Cell[]
+```
+
+Get the nodes/edges in the clipboard.
+
+### graph.cleanClipboard()
+
+```ts
+cleanClipboard(): this
+```
+
+Clear the clipboard.
+
+### graph.isClipboardEmpty()
+
+```ts
+isClipboardEmpty(): boolean
+```
+
+Return whether the clipboard is empty.
+
+### graph.isClipboardEnabled()
+
+```ts
+isClipboardEnabled(): boolean
+```
+
+Return whether the clipboard is enabled.
+
+### graph.enableClipboard()
+
+```ts
+enableClipboard(): this
+```
+
+Enable the clipboard.
+
+### graph.disableClipboard()
+
+```ts
+disableClipboard(): this
+```
+
+Disable the clipboard.
+
+### graph.toggleClipboard(...)
+
+```ts
+toggleClipboard(enabled?: boolean): this
+```
+
+Toggle the clipboard's enabled state. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable the clipboard; defaults to toggling the clipboard's enabled state. |
+
+## Events
+
+| Event Name | Parameter Type | Description |
+|-----------------------|---------------------------|----------------------------------|
+| `clipboard:changed` | `{ cells: Cell[] }` | Triggered when copying, cutting, or clearing the clipboard. |
+
+```ts
+graph.on('clipboard:changed', ({ cells }) => {
+ console.log(cells)
+})
+
+// We can also listen to events on the plugin instance
+clipboard.on('clipboard:changed', ({ cells }) => {
+ console.log(cells)
+})
+```
diff --git a/sites/x6-sites/docs/tutorial/plugins/dnd.en.md b/sites/x6-sites/docs/tutorial/plugins/dnd.en.md
new file mode 100644
index 00000000000..e6cb9d95eff
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/dnd.en.md
@@ -0,0 +1,141 @@
+---
+title: Dnd
+order: 7
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="By reading this chapter, you can learn about"}
+
+- How to add nodes to the canvas through drag-and-drop interactions
+
+:::
+
+## Usage
+
+We often need to add nodes to the canvas through drag-and-drop interactions, such as in process graph editing scenarios, where we drag and drop components from the process graph component library onto the canvas. We provide a separate plugin package `@antv/x6-plugin-dnd` to use this feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-dnd --save
+
+# yarn
+$ yarn add @antv/x6-plugin-dnd
+```
+
+Then we use it in our code like this:
+
+```ts
+import { Dnd } from '@antv/x6-plugin-dnd'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+
+const dnd = new Dnd({
+ target: graph,
+})
+```
+
+When starting to drag, we need to call the `dnd.start(node, e)` method. In React, we use it like this:
+
+```tsx
+export default () => {
+ const startDrag = (e: React.MouseEvent
+
+## Configuration
+
+| Option | Type | Required | Default Value | Description |
+|-------------------|-------------------------------------------------------------------------------------|:----:|-----------------|-----------------------------------------------------------------------------------------------------|
+| target | Graph | ✓️ | | The target canvas. |
+| getDragNode | (sourceNode: Node, options: GetDragNodeOptions) => Node | | | Get the node being dragged when dragging starts, default to cloning the node passed to `dnd.start`. |
+| getDropNode | (draggingNode: Node, options: GetDropNodeOptions) => Node | | | Get the node to be placed on the target canvas when dragging ends, default to cloning the dragged node. |
+| validateNode | (droppingNode: Node, options: ValidateNodeOptions) => boolean \| Promins\
+
+## Configuration
+
+| Property Name | Type | Default Value | Required | Description |
+|--------------------|---------------------------------|---------------|----------|------------------------------------------------------------------------------------------------------|
+| stackSize | number | `0` | | A `stackSize` of 0 means there is no limit on the length of the history stack; setting it to another number means it will only record that many history entries. |
+| ignoreAdd | boolean | `false` | | If `ignoreAdd` is `true`, adding elements will not be recorded in the history. |
+| ignoreRemove | boolean | `false` | | If `ignoreRemove` is `true`, removing elements will not be recorded in the history. |
+| ignoreChange | boolean | `false` | | If `ignoreChange` is `true`, changes to element properties will not be recorded in the history. |
+| beforeAddCommand | `(event, args) => any` | - | | Called before a command is added to the Undo queue; if this method returns `false`, the command will not be added to the Undo queue. |
+| afterAddCommand | `(event, args, cmd) => any` | - | | Called after a command is added to the Undo queue. |
+| executeCommand | `(cmd, revert, options) => any` | - | | Called when a command is undone or redone; `revert` is `true` if the command is undone, otherwise it indicates the command is redone. |
+
+:::info{title="Tip"}
+In actual projects, we often need to undo or redo multiple changes at once. X6 provides the concept of `batch`, which allows multiple changes to be merged into a single history entry. Here’s how to use it:
+:::
+
+```ts
+// Method 1
+graph.startBatch('custom-batch-name')
+// Changing the border color of the node and modifying its position will be merged into a single record, allowing for a single undo.
+node.attr('body/stroke', 'red')
+node.position(30, 30)
+graph.stopBatch('custom-batch-name')
+
+// Method 2
+graph.batchUpdate(() => {
+ node.prop('zIndex', 10)
+ node.attr('label/text', 'hello')
+ node.attr('label/fill', '#ff0000')
+})
+```
+
+## API
+
+### graph.undo(...)
+
+```ts
+undo(options?: KeyValue): this
+```
+
+Undo. `options` will be passed to the event callback.
+
+### graph.undoAndCancel(...)
+
+```ts
+undoAndCancel(options?: KeyValue): this
+```
+
+Undo and do not add to the redo queue, so this undone command cannot be redone. `options` will be passed to the event callback.
+
+### graph.redo(...)
+
+```ts
+redo(options?: KeyValue): this
+```
+
+Redo. `options` will be passed to the event callback.
+
+### graph.canUndo()
+
+```ts
+canUndo(): boolean
+```
+
+Check if it can be undone.
+
+### graph.canRedo()
+
+```ts
+canRedo(): boolean
+```
+
+Check if it can be redone.
+
+### graph.cleanHistory(...)
+
+```ts
+cleanHistory(options?: KeyValue): this
+```
+
+Clear the history queue. `options` will be passed to the event callback.
+
+### graph.getHistoryStackSize(...)
+
+```ts
+getHistoryStackSize(): number
+```
+
+Get the size of the history stack.
+
+### graph.getUndoRemainSize(...)
+
+```ts
+getUndoRemainSize(): number
+```
+
+Get the remaining size of the history undo stack.
+
+### graph.getUndoStackSize(...)
+
+```ts
+getUndoStackSize(): number
+```
+
+Get the size of the history undo stack.
+
+### graph.getRedoStackSize(...)
+
+```ts
+getRedoStackSize(): number
+```
+
+Get the size of the history redo stack.
+
+### graph.isHistoryEnabled()
+
+```ts
+isHistoryEnabled(): boolean
+```
+
+Check if history state is enabled.
+
+### graph.enableHistory()
+
+```ts
+enableHistory(): this
+```
+
+Enable history state.
+
+### graph.disableHistory()
+
+```ts
+disableHistory(): this
+```
+
+Disable history state.
+
+### graph.toggleHistory(...)
+
+```ts
+toggleHistory(enabled?: boolean): this
+```
+
+Toggle the enabled state of history. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable history state; defaults to toggling the enabled state of history. |
+
+## Events
+
+| Event Name | Parameter Type | Description |
+|-------------------|----------------------------------------------------|------------------------------|
+| `history:undo` | `{ cmds: Command[], options: KeyValue }` | Triggered when a command is undone. |
+| `history:redo` | `{ cmds: Command[], options: KeyValue }` | Triggered when a command is redone. |
+| `history:cancel` | `{ cmds: Command[], options: KeyValue }` | Triggered when a command is canceled. |
+| `history:add` | `{ cmds: Command[], options: KeyValue }` | Triggered when a command is added to the queue. |
+| `history:clean` | `{ cmds: Command[] \| null, options: KeyValue }` | Triggered when the history queue is cleared. |
+| `history:change` | `{ cmds: Command[] \| null, options: KeyValue }` | Triggered when the history queue changes. |
+| `history:batch` | `{ cmds: Command, options: KeyValue }` | Triggered when a batch command is received. |
+
+```ts
+graph.on('history:undo', ({ cmds }) => {
+ console.log(cmds)
+})
+
+// We can also listen to events on the plugin instance
+history.on('undo', ({ cmds }) => {
+ console.log(cmds)
+})
+```
diff --git a/sites/x6-sites/docs/tutorial/plugins/keyboard.en.md b/sites/x6-sites/docs/tutorial/plugins/keyboard.en.md
new file mode 100644
index 00000000000..7f899b6e9b9
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/keyboard.en.md
@@ -0,0 +1,163 @@
+---
+title: Keyboard
+order: 3
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="This section mainly introduces knowledge related to keyboard shortcuts. By reading, you can learn about"}
+
+- How to bind keyboard shortcuts to the canvas
+
+:::
+
+## Usage
+
+We provide a standalone plugin package `@antv/x6-plugin-keyboard` to use keyboard shortcut functionality.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-keyboard --save
+
+# yarn
+$ yarn add @antv/x6-plugin-keyboard
+```
+
+Then we use it in the code like this:
+
+```ts
+import { Keyboard } from '@antv/x6-plugin-keyboard'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+graph.use(
+ new Keyboard({
+ enabled: true,
+ }),
+)
+```
+
+## Demo
+
+
+
+## Configuration
+
+| Property Name | Type | Default Value | Required | Description |
+|---------------|-------------------------------------------|---------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------|
+| global | boolean | `false` | | Whether to use global keyboard events. When set to `true`, keyboard events are bound to `document`; otherwise, they are bound to the canvas container. When bound to the canvas container, the container must gain focus to trigger keyboard events. |
+| format | `(this:Graph, key: string) => string` | - | | Format the key string when binding or unbinding keyboard events. |
+| guard | `(this:Graph,e:KeyboardEvent) => boolean` | - | | Determine whether a keyboard event should be processed. If it returns `false`, the corresponding keyboard event is ignored. |
+
+The `format` and `guard` configurations are used as follows:
+
+```ts
+graph.use(
+ new Keyboard({
+ enabled: true,
+ format(key) {
+ return key.replace(/\s/g, '').replace('cmd', 'command')
+ },
+ }),
+)
+// The statement below is equivalent to graph.bindKey('command', (e) => { })
+graph.bindKey('cmd', (e) => {})
+
+graph.use(
+ new Keyboard({
+ enabled: true,
+ guard(this: Graph, e: KeyboardEvent) {
+ if (e.altKey) {
+ // Ignore all keyboard events when the alt key is pressed
+ return false
+ }
+ return true
+ },
+ }),
+)
+```
+
+## API
+
+### graph.bindKey(...)
+
+```ts
+bindKey(
+ keys: string | string[],
+ callback: (e: KeyboardEvent) => void,
+ action?: 'keypress' | 'keydown' | 'keyup',
+): this
+```
+
+Bind keyboard shortcuts.
+
+### graph.unbindKey(...)
+
+```ts
+unbindKey(
+ keys: string | string[],
+ action?: 'keypress' | 'keydown' | 'keyup',
+): this
+```
+
+Unbind keyboard shortcuts.
+
+### graph.clearKeys()
+
+```ts
+clearKeys(): this
+```
+
+Clear all keyboard shortcuts.
+
+### graph.triggerKey()
+
+```ts
+triggerKey(
+ keys: string,
+ action?: 'keypress' | 'keydown' | 'keyup',
+): this
+```
+
+Manually trigger keyboard shortcuts.
+
+### graph.isKeyboardEnabled()
+
+```ts
+isKeyboardEnabled(): boolean
+```
+
+Get whether keyboard events are enabled.
+
+### graph.enableKeyboard()
+
+```ts
+enableKeyboard(): this
+```
+
+Enable keyboard events.
+
+### graph.disableKeyboard()
+
+```ts
+disableKeyboard(): this
+```
+
+Disable keyboard events.
+
+### graph.toggleKeyboard(...)
+
+```ts
+toggleKeyboard(enabled?: boolean): this
+```
+
+Toggle the enabled state of keyboard events. The parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|----------|---------|:--------:|---------------|------------------------------------------------------|
+| enabled | boolean | | - | Whether to enable keyboard events. If omitted, it toggles the enabled state of keyboard events. |
diff --git a/sites/x6-sites/docs/tutorial/plugins/minimap.en.md b/sites/x6-sites/docs/tutorial/plugins/minimap.en.md
new file mode 100644
index 00000000000..155ef19d0a3
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/minimap.en.md
@@ -0,0 +1,63 @@
+---
+title: Mini Map
+order: 7
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="This chapter mainly introduces knowledge related to the Mini Map plugin. By reading, you can learn about"}
+
+- How to use the Mini Map feature
+
+:::
+
+## Usage
+
+We provide a standalone plugin package `@antv/x6-plugin-minimap` to use the mini-map feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-minimap --save
+
+# yarn
+$ yarn add @antv/x6-plugin-minimap
+```
+
+Then we use it in the code like this:
+
+```ts
+import { MiniMap } from '@antv/x6-plugin-minimap'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+graph.use(
+ new MiniMap({
+ container: document.getElementById('minimap'),
+ }),
+)
+```
+
+## Demo
+
+- Move the mini-map viewport to move the canvas.
+- Zoom the mini-map viewport to zoom the canvas.
+
+
+
+## Options
+
+| Property Name | Type | Default Value | Required | Description |
+|---------------|---------------|---------------|----------|----------------------------------|
+| container | HTMLElement | - | √ | The container to mount the mini-map |
+| width | number | `300` | | The width of the mini-map |
+| height | number | `200` | | The height of the mini-map |
+| padding | number | `10` | | The padding margin of the mini-map container |
+| scalable | boolean | `true` | | Whether it is scalable |
+| minScale | number | `0.01` | | The minimum scale ratio |
+| maxScale | number | `16` | | The maximum scale ratio |
+| graphOptions | Graph.Options | `null` | | Options for creating the mini-map Graph |
diff --git a/sites/x6-sites/docs/tutorial/plugins/scroller.en.md b/sites/x6-sites/docs/tutorial/plugins/scroller.en.md
new file mode 100644
index 00000000000..1193690a581
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/scroller.en.md
@@ -0,0 +1,119 @@
+---
+title: Scroller
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="In this chapter, we mainly introduce knowledge related to the scroller plugin. By reading, you can learn about"}
+
+- How to enable scrolling capabilities for the canvas
+
+:::
+
+:::warning{title=Note}
+When using the `Scroller` plugin, please do not enable the canvas's `panning` configuration at the same time, as the two forms conflict in interaction.
+:::
+
+## Usage
+
+We provide a standalone plugin package `@antv/x6-plugin-scroller` to use the scroller feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-scroller --save
+
+# yarn
+$ yarn add @antv/x6-plugin-scroller
+```
+
+Then we use it in the code like this:
+
+```ts
+import { Scroller } from '@antv/x6-plugin-scroller'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+graph.use(
+ new Scroller({
+ enabled: true,
+ }),
+)
+```
+
+## Demo
+
+
+
+## Options
+
+| Property Name | Type | Default | Required | Description |
+|-------------------|---------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| pannable | boolean | `false` | | Whether to enable canvas panning capability (dragging the canvas after pressing the mouse on a blank area) |
+| className | string | - | | Additional class name for custom styling |
+| width | number | - | | Width of the `Scroller`, defaults to the width of the canvas container |
+| height | number | - | | Height of the `Scroller`, defaults to the height of the canvas container |
+| modifiers | ModifierKey | - | | Set modifier keys that need to be pressed along with the mouse click to trigger canvas dragging |
+| pageWidth | number | - | | Width of each page, defaults to the width of the canvas container |
+| pageHeight | number | - | | Height of each page, defaults to the height of the canvas container |
+| pageVisible | boolean | `false` | | Whether to enable pagination |
+| pageBreak | boolean | `false` | | Whether to show page breaks |
+| autoResize | boolean | `true` | | Whether to automatically expand/shrink the canvas. When enabled, moving nodes/edges will automatically calculate the required canvas size, expanding it according to `pageWidth` and `pageHeight` when exceeding the current size, and shrinking it otherwise. |
+| minVisibleWidth | number | - | | Effective when `padding` is empty, sets the minimum visible width of the canvas during scrolling |
+| minVisibleHeight | number | - | | Effective when `padding` is empty, sets the minimum visible height of the canvas during scrolling |
+| padding | `number \| Padding` | - | | Sets the padding around the canvas. Defaults to being automatically calculated based on `minVisibleWidth` and `minVisibleHeight`, ensuring that at least `minVisibleWidth` and `minVisibleHeight` of the canvas is visible during scrolling. |
+
+The `Padding` type is defined as follows:
+
+```ts
+type Padding = { top: number; right: number; bottom: number; left: number }
+```
+
+The `ModifierKey` type is defined as follows:
+
+```ts
+type ModifierKey = string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null
+```
+
+Supports the following forms:
+
+- `alt` means pressing `alt`.
+- `[alt, ctrl]` means pressing either `alt` or `ctrl`.
+- `alt|ctrl` means pressing either `alt` or `ctrl`.
+- `alt&ctrl` means pressing both `alt` and `ctrl` simultaneously.
+- `alt|ctrl&shift` means pressing both `alt` and `shift` simultaneously or both `ctrl` and `shift` simultaneously.
+
+## API
+
+### graph.lockScroller()
+
+Disables scrolling.
+
+### graph.unlockScroller()
+
+Enables scrolling.
+
+### graph.getScrollbarPosition()
+
+Gets the scrollbar position.
+
+### graph.setScrollbarPosition(left?: number, top?: number)
+
+Sets the scrollbar position.
+
+- `left?: number` The position of the horizontal scrollbar; defaults to no horizontal scrolling.
+- `top?: number` The position of the vertical scrollbar; defaults to no vertical scrolling.
+
+For example:
+
+```ts
+graph.setScrollbarPosition(100)
+graph.setScrollbarPosition(100, null)
+graph.setScrollbarPosition(null, 200)
+graph.setScrollbarPosition(100, 200)
+```
diff --git a/sites/x6-sites/docs/tutorial/plugins/selection.en.md b/sites/x6-sites/docs/tutorial/plugins/selection.en.md
new file mode 100644
index 00000000000..f66f0aee6da
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/selection.en.md
@@ -0,0 +1,405 @@
+---
+title: Selection Box
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="This chapter mainly introduces knowledge related to the selection box plugin. By reading, you can learn about"}
+
+- How to enable selection interaction
+
+:::
+
+## Usage
+
+We provide a standalone plugin package `@antv/x6-plugin-selection` to use the selection feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-selection --save
+
+# yarn
+$ yarn add @antv/x6-plugin-selection
+```
+
+Then we use it in the code like this:
+
+```ts
+import { Selection } from '@antv/x6-plugin-selection'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+graph.use(
+ new Selection({
+ enabled: true,
+ }),
+)
+```
+
+## Demo
+
+- Click to select nodes.
+- Enable multi-selection by holding down Ctrl/Command and clicking on nodes.
+- Enable moving by dragging the selection box to move nodes.
+- Enable rubberband selection by pressing the left mouse button on a blank area of the canvas and dragging the selection box to select nodes.
+- Enable strict rubberband mode and observe its effect on selection.
+- Use modifier keys in conjunction with selection, such as the `alt` key. Hold down the `alt` key and press the left mouse button on a blank area of the canvas to drag the selection box to select nodes.
+- Apply a custom filter (exclude circle nodes), so that circular nodes cannot be selected.
+- Apply custom additional content (display the number of selected nodes). Select two or more nodes to trigger the display of custom content.
+
+
+
+## Configuration
+
+| Property Name | Type | Default Value | Required | Description |
+|-------------------------|----------------------|---------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------|
+| className | string | - | | Additional style name for customizing styles |
+| multiple | boolean | `true` | | Whether to enable multi-selection; when enabled, hold down the `ctrl` or `command` key to click nodes for multi-selection |
+| multipleSelectionModifiers | ModifierKey | `['ctrl', 'meta']` | | Used to set the modifier keys for multi-selection |
+| rubberband | boolean | `false` | | Whether to enable the rubberband selection feature |
+| modifiers | ModifierKey | - | | Used to set the modifier keys for rubberband selection |
+| strict | boolean | `false` | | Whether the selection box needs to completely enclose nodes to select them |
+| movable | boolean | `true` | | Whether the selected nodes move together when dragging the selection box |
+| content | string | - | | Set additional display content |
+| filter | Filter | - | | Node filter |
+| showNodeSelectionBox | boolean | `false` | | Whether to show the selection box for nodes |
+| showEdgeSelectionBox | boolean | `false` | | Whether to show the selection box for edges |
+| pointerEvents | `node \| auto` | `auto` | | When `showNodeSelectionBox` is enabled, an element will overlay on top of the node, causing the node's events to be unresponsive; you can set `pointerEvents: none` to resolve this, default is `auto` |
+| eventTypes | SelectionEventType[] | `['leftMouseDown', 'mouseWheelDown']` | | Used to set the trigger event types for rubberband selection |
+
+The type definition for `Filter` is as follows:
+
+```ts
+type Filter = string[] | { id: string }[] | (this: Graph, cell: Cell) => boolean
+```
+
+- `string[]`: An array of node shapes; only specified node/edge shapes can be selected.
+- `({ id: string })[]`: An array of node IDs; only specified nodes/edges can be selected.
+- `(this: Graph, cell: Cell) => boolean`: Only nodes/edges that return true can be selected.
+
+The type definition for `ModifierKey` is as follows:
+
+```ts
+type ModifierKey = string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null
+```
+
+The modifier keys in X6 include `alt`, `ctrl`, `meta`, and `shift`. After setting the modifier keys, you need to click the mouse and press the modifier keys to trigger the corresponding behavior. Modifier keys are very useful in certain scenarios, such as starting rubberband selection and dragging the canvas simultaneously, where both actions are triggered by pressing the left mouse button on a blank area of the canvas. You can set different modifier keys for rubberband selection and dragging the canvas to achieve simultaneous activation without conflict. You can configure a single (e.g., `alt`) or multiple (e.g., `['alt', 'ctrl']`) modifier keys. Multiple modifier keys configured in array form are treated as an OR relationship. For example, the configured modifier keys indicate pressing `alt` or `ctrl`. If you need more flexible configurations, you can use the following forms:
+
+- `alt` indicates pressing `alt`.
+- `[alt, ctrl]` indicates pressing `alt` or `ctrl`.
+- `alt|ctrl` indicates pressing `alt` or `ctrl`.
+- `alt&ctrl` indicates pressing `alt` and `ctrl` simultaneously.
+- `alt|ctrl&shift` indicates pressing `alt` and `shift` simultaneously or pressing `ctrl` and `shift` simultaneously.
+
+The type definition for `SelectionEventType` is as follows:
+
+```ts
+type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown';
+```
+Interaction methods that trigger rubberband selection. Supports two forms or combinations of them:
+
+- `leftMouseDown`: Pressing the left mouse button to drag.
+- `mouseWheelDown`: Pressing the mouse wheel to drag.
+
+
+## API
+
+### graph.select(...)
+
+```ts
+select(cells: Cell | string | (Cell | string)[]): this
+```
+
+Selects the specified nodes/edges. Note that this method does not unselect currently selected nodes/edges; it appends the specified nodes/edges to the selection. If you also need to unselect currently selected nodes/edges, please use the [resetSelection(...)](#graphresetselection) method.
+
+### graph.unselect(...)
+
+```ts
+unselect(cells: Cell | string | (Cell | string)[]): this
+```
+
+Unselects the specified nodes/edges.
+
+### graph.isSelected(...)
+
+```ts
+isSelected(cell: Cell | string): boolean
+```
+
+Returns whether the specified node/edge is selected.
+
+### graph.resetSelection(...)
+
+```ts
+resetSelection(cells?: Cell | string | (Cell | string)[]): this
+```
+
+Clears the selection first, then selects the provided nodes/edges.
+
+### graph.getSelectedCells()
+
+```ts
+getSelectedCells(): Cell[]
+```
+
+Gets the selected nodes/edges.
+
+### graph.cleanSelection()
+
+```ts
+cleanSelection(): this
+```
+
+Clears the selection.
+
+### graph.isSelectionEmpty()
+
+```ts
+cleanSelection(): boolean
+```
+
+Returns whether the selection is empty.
+
+### graph.isSelectionEnabled()
+
+```ts
+isSelectionEnabled(): boolean
+```
+
+Whether selection capability is enabled.
+
+### graph.enableSelection()
+
+```ts
+enableSelection(): this
+```
+
+Enables selection capability.
+
+### graph.disableSelection()
+
+```ts
+disableSelection(): this
+```
+
+Disables selection capability.
+
+### graph.toggleSelection(...)
+
+```ts
+toggleSelection(enabled?: boolean): this
+```
+
+Toggles the enabled state of selection. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable selection capability; defaults to toggling the enabled state. |
+
+### graph.isMultipleSelection()
+
+```ts
+isMultipleSelection(): boolean
+```
+
+Whether multi-selection is enabled.
+
+### graph.enableMultipleSelection()
+
+```ts
+enableMultipleSelection(): this
+```
+
+Enables multi-selection.
+
+### graph.disableMultipleSelection()
+
+```ts
+disableMultipleSelection(): this
+```
+
+Disables multi-selection.
+
+### graph.toggleMultipleSelection(...)
+
+```ts
+toggleMultipleSelection(multiple?: boolean): this
+```
+
+Toggles the enabled state of multi-selection. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|----------|---------|:--------:|---------------|-----------------------------------------------|
+| multiple | boolean | | - | Whether to enable multi-selection; defaults to toggling the enabled state. |
+
+### graph.isSelectionMovable()
+
+```ts
+isSelectionMovable(): boolean
+```
+
+Returns whether the selected nodes/edges can be moved.
+
+### graph.enableSelectionMovable()
+
+```ts
+enableSelectionMovable(): this
+```
+
+Enables moving of selected nodes/edges.
+
+### graph.disableSelectionMovable()
+
+```ts
+disableSelectionMovable(): this
+```
+
+Disables moving of selected nodes/edges.
+
+### graph.toggleSelectionMovable(...)
+
+```ts
+toggleSelectionMovable(enabled?: boolean): this
+```
+
+Toggles whether selected nodes/edges can be moved. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-------------------------------------------------------|
+| enabled | boolean | | - | Whether to enable moving of selected nodes/edges; defaults to toggling the enabled state. |
+
+### graph.isRubberbandEnabled()
+
+```ts
+isRubberbandEnabled(): boolean
+```
+
+Returns whether rubberband selection is enabled.
+
+### graph.enableRubberband()
+
+```ts
+enableRubberband(): this
+```
+
+Enables rubberband selection.
+
+### graph.disableRubberband()
+
+```ts
+disableRubberband(): this
+```
+
+Disables rubberband selection.
+
+### graph.toggleRubberband(...)
+
+```ts
+toggleRubberband(enabled?: boolean): this
+```
+
+Toggles the enabled state of rubberband selection. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|----------------------------------------|
+| enabled | boolean | | - | Whether to enable rubberband selection; defaults to toggling the enabled state. |
+
+### graph.isStrictRubberband()
+
+```ts
+isStrictRubberband(): boolean
+```
+
+Returns whether strict rubberband selection is enabled. When strict rubberband selection is enabled, only nodes/edges that are completely enclosed by the selection box will be selected.
+
+### graph.enableStrictRubberband()
+
+```ts
+enableStrictRubberband(): this
+```
+
+Enables strict rubberband selection. When strict rubberband selection is enabled, only nodes/edges that are completely enclosed by the selection box will be selected.
+
+### graph.disableStrictRubberband()
+
+```ts
+disableStrictRubberband(): this
+```
+
+Disables strict rubberband selection. When strict rubberband selection is disabled, nodes/edges can be selected as long as the selection box intersects with their bounding box.
+
+### graph.toggleStrictRubberband(...)
+
+```ts
+toggleStrictRubberband(enabled?: boolean): this
+```
+
+Toggles the enabled state of strict rubberband selection. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|---------------------------------------------|
+| enabled | boolean | | - | Whether to enable strict rubberband selection; defaults to toggling the enabled state. |
+
+### graph.setSelectionFilter(...)
+
+```ts
+setSelectionFilter(
+ filter?:
+ | null
+ | (string | { id: string })[]
+ | ((this: Graph, cell: Cell) => boolean)
+): this
+```
+
+Sets the filtering criteria for selection; only nodes/edges that meet the filtering criteria can be selected.
+
+### graph.setRubberbandModifiers(...)
+
+```ts
+setRubberbandModifiers(modifiers?: string | ModifierKey[] | null): this
+```
+
+Sets the modifier keys for rubberband selection; rubberband selection can only be triggered when the modifier keys are pressed simultaneously.
+
+### graph.setSelectionDisplayContent(...)
+
+```ts
+setSelectionDisplayContent(
+ content?:
+ | null
+ | false
+ | string
+ | ((this: Graph, selection: Selection, contentElement: HTMLElement) => string)
+): this
+```
+
+Sets additional display content for selected nodes/edges.
+
+## Events
+
+| Event Name | Parameter Type | Description |
+|-----------------------|---------------------------------------------------------------------------------------|------------------------------------------|
+| `cell:selected` | `{ cell: Cell; options: Model.SetOptions }` | Triggered when a node/edge is selected |
+| `node:selected` | `{ node: Node; options: Model.SetOptions }` | Triggered when a node is selected |
+| `edge:selected` | `{ edge: Edge; options: Model.SetOptions }` | Triggered when an edge is selected |
+| `cell:unselected` | `{ cell: Cell; options: Model.SetOptions }` | Triggered when a node/edge is unselected |
+| `node:unselected` | `{ node: Node; options: Model.SetOptions }` | Triggered when a node is unselected |
+| `edge:unselected` | `{ edge: Edge; options: Model.SetOptions }` | Triggered when an edge is unselected |
+| `selection:changed` | `{added: Cell[]; removed: Cell[]; selected: Cell[]; options: Model.SetOptions}` | Triggered when the selected nodes/edges change (add/remove) |
+
+```ts
+graph.on('node:selected', ({ node }) => {
+ console.log(node)
+})
+
+// We can also listen to events on the plugin instance
+selection.on('node:selected', ({ node }) => {
+ console.log(node)
+})
+```
diff --git a/sites/x6-sites/docs/tutorial/plugins/snapline.en.md b/sites/x6-sites/docs/tutorial/plugins/snapline.en.md
new file mode 100644
index 00000000000..ddbf9d182a6
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/snapline.en.md
@@ -0,0 +1,211 @@
+---
+title: Snapline
+order: 1
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/basic
+---
+
+:::info{title="This section mainly introduces knowledge related to the snapline plugin. By reading, you can learn about"}
+
+- How to use snapline in the canvas
+
+:::
+
+## Usage
+
+The alignment line is an auxiliary tool for the layout of movable nodes. We provide a standalone plugin package `@antv/x6-plugin-snapline` to use this feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-snapline --save
+
+# yarn
+$ yarn add @antv/x6-plugin-snapline
+```
+
+Then we use it in the code like this:
+
+```ts
+import { Snapline } from '@antv/x6-plugin-snapline'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+graph.use(
+ new Snapline({
+ enabled: true,
+ }),
+)
+```
+
+## Demo
+
+
+
+## Configuration
+
+| Property Name | Type | Default Value | Required | Description |
+|---------------|---------|---------------|----------|-------------------------------------------------------------------------------------------------|
+| className | string | - | | Additional style name for customizing the alignment line style |
+| tolerance | number | 10 | | Alignment precision; the alignment line is triggered when the distance to the target position is less than `tolerance` |
+| sharp | boolean | `false` | | Whether to display truncated snapline |
+| resizing | boolean | `false` | | Whether to trigger snapline when resizing nodes |
+| clean | boolean | `true` | | If `true`, the alignment line will be cleared after 3 seconds; if `false`, it will not be cleared; if a number (ms), it will be cleared after the specified time |
+| filter | Filter | - | | Node filter |
+
+The above Filter type is relatively complex and supports the following three types:
+
+- `string[]`: An array of node `shape`; only the specified node `shape` will participate in alignment calculations
+- `({ id: string })[]`: An array of node IDs; only the specified nodes will participate in alignment calculations
+- `(this: Graph, node: Node) => boolean`: Only nodes that return `true` will participate in alignment calculations
+
+## API
+
+### graph.isSnaplineEnabled()
+
+```ts
+isSnaplineEnabled(): boolean
+```
+
+Returns whether the alignment line is enabled.
+
+### graph.enableSnapline()
+
+```ts
+enableSnapline(): this
+```
+
+Enables the alignment line.
+
+### graph.disableSnapline()
+
+```ts
+disableSnapline(): this
+```
+
+Disables the alignment line.
+
+### graph.toggleSnapline(...)
+
+```ts
+toggleSnapline(enabled?: boolean): this
+```
+
+Toggles the enabled state of the alignment line. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable the alignment line; defaults to toggling the enabled state of the alignment line. |
+
+### graph.hideSnapline()
+
+```ts
+hideSnapline(): this
+```
+
+Hides the alignment line.
+
+### graph.isSnaplineOnResizingEnabled()
+
+```ts
+isSnaplineOnResizingEnabled(): boolean
+```
+
+Whether to trigger the alignment line when resizing nodes.
+
+### graph.enableSnaplineOnResizing()
+
+```ts
+enableSnaplineOnResizing(): this
+```
+
+Enables triggering the alignment line during node resizing.
+
+### graph.disableSnaplineOnResizing()
+
+```ts
+disableSnaplineOnResizing(): this
+```
+
+Disables triggering the alignment line during node resizing.
+
+### graph.toggleSnaplineOnResizing(...)
+
+```ts
+toggleSnaplineOnResizing(enabled?: boolean): this
+```
+
+Toggles whether to trigger the alignment line during node resizing. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable the alignment line; defaults to toggling the enabled state of the alignment line. |
+
+### graph.isSharpSnapline()
+
+```ts
+isSharpSnapline(): boolean
+```
+
+Whether to use short snapline.
+
+### graph.enableSharpSnapline()
+
+```ts
+enableSharpSnapline(): this
+```
+
+Enables short snapline; when enabled, the snapline only show up to the relevant node positions, otherwise they span across the canvas.
+
+### graph.disableSharpSnapline()
+
+```ts
+disableSharpSnapline(): this
+```
+
+Disables short snapline; snapline will span the entire canvas.
+
+### graph.toggleSharpSnapline()
+
+```ts
+toggleSharpSnapline(enabled?: boolean): this
+```
+
+Toggles the enabled state of short snapline. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|---------|---------|:--------:|---------------|-----------------------------------------------|
+| enabled | boolean | | - | Whether to enable short snapline; defaults to toggling the enabled state of short snapline. |
+
+### graph.getSnaplineTolerance()
+
+```ts
+getSnaplineTolerance(): number
+```
+
+Gets the alignment line precision.
+
+### graph.setSnaplineTolerance(...)
+
+```ts
+setSnaplineTolerance(tolerance: number): this
+```
+
+Sets the alignment line precision.
+
+### graph.setSnaplineFilter(...)
+
+```ts
+setSnaplineFilter(
+ filter?:
+ | null
+ | (string | { id: string })[]
+ | ((this: Graph, node: Node) => boolean)
+): this
+```
+
+Sets the filter condition; only nodes that meet the filter condition will participate in alignment line calculations.
diff --git a/sites/x6-sites/docs/tutorial/plugins/stencil.en.md b/sites/x6-sites/docs/tutorial/plugins/stencil.en.md
new file mode 100644
index 00000000000..4f40361efd8
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/stencil.en.md
@@ -0,0 +1,211 @@
+---
+title: Stencil
+order: 8
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="By reading this chapter, you will learn"}
+
+- How to further enhance DND capabilities through the Stencil plugin
+
+:::
+
+## Usage
+
+Stencil is a further encapsulation based on Dnd, providing a sidebar-like UI component that supports grouping, collapsing, searching, and other capabilities. We offer a standalone plugin package `@antv/x6-plugin-stencil` to use this feature.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-stencil --save
+
+# yarn
+$ yarn add @antv/x6-plugin-stencil
+```
+
+Then we can use it in the code like this:
+
+```ts
+import { Stencil } from '@antv/x6-plugin-stencil'
+
+const graph = new Graph({
+ background: {
+ color: '#F2F7FA',
+ },
+})
+
+const stencil = new Stencil({
+ target: graph,
+ groups: [
+ {
+ name: 'group1',
+ },
+ {
+ name: 'group2',
+ },
+ ],
+})
+
+const rect1 = graph.createNode({
+ shape: 'rect',
+ width: 100,
+ height: 40,
+})
+const rect2 = rect1.clone()
+
+// A DOM container to hold the stencil, stencilContainer
+stencilContainer.appendChild(stencil.container)
+stencil.load([rect1, rect2], 'group1')
+```
+
+## Demo
+
+
+
+## Configuration
+
+| Option | Type | Required | Default Value | Description |
+|---------------------|-------------------------------------------------------------|:--------:|----------------------|----------------------------------------------|
+| title | string | | `'Stencil'` | Title. |
+| groups | Group[] | ✓️ | - | Group information. |
+| search | Filter | | `false` | Search option. |
+| placeholder | string | | `'Search'` | Placeholder text for the search input. |
+| notFoundText | string | | `'No matches found'` | Text displayed when no search results are found. |
+| collapsable | boolean | | `false` | Whether to show a global collapse/expand button. |
+| layout | (this: Stencil, model: Model, group?: Group \| null) => any | | Grid layout | Layout method for nodes in the stencil canvas. |
+| layoutOptions | any | | - | Layout options. |
+| stencilGraphWidth | number | | `200` | Width of the stencil canvas. |
+| stencilGraphHeight | number | | `800` | Height of the stencil canvas. Set to 0 for auto-adjustment. |
+| stencilGraphPadding | number | | `10` | Padding for the stencil canvas. |
+| stencilGraphOptions | Graph.Options | | - | Options for the stencil canvas. |
+
+:::info{title="Tip"}
+In addition to the configurations above, Stencil also inherits all configurations from Dnd.
+:::
+
+### Grouping
+
+When initializing, a template canvas will be rendered in each group according to the `groups` provided. The type definition for groups is as follows:
+
+```ts
+export interface Group {
+ name: string // Group name
+ title?: string // Group title, defaults to `name`
+ collapsable?: boolean // Whether the group is collapsible, defaults to true
+ collapsed?: boolean // Initial state whether it is collapsed
+ nodeMovable?: boolean // Whether nodes in the stencil canvas can be dragged
+ graphWidth?: number // Width of the stencil canvas
+ graphHeight?: number // Height of the stencil canvas
+ graphPadding?: number // Padding for the stencil canvas
+ graphOptions?: Graph.Options // Options for the stencil canvas
+ layout?: (this: Stencil, model: Model, group?: Group | null) => any
+ layoutOptions?: any // Layout options
+}
+```
+
+As you can see, some configurations within the group overlap with the outer configurations, such as `graphWidth` and `stencilGraphHeight`, with the group configurations taking higher priority.
+
+### Layout
+
+When adding nodes, use the group or global `layout` and `layoutOptions` to automatically layout the nodes. By default, the grid layout method is used to layout the template nodes, and the supported layout options are:
+
+| Option | Type | Default Value | Description |
+|---------------|-------------------------------|---------------|-------------------------------------------------------------------------------------------|
+| columns | number | `2` | Number of columns in the grid layout, defaults to `2`. The number of rows is calculated automatically based on the number of nodes. |
+| columnWidth | number \| 'auto' \| 'compact' | `'auto'` | Column width. `auto`: width of the widest node among all nodes, `compact`: width of the widest node in that column. |
+| rowHeight | number \| 'auto' \| 'compact' | `'auto'` | Row height. `auto`: height of the tallest node among all nodes, `compact`: height of the tallest node in that row. |
+| dx | number | `10` | Offset of the cell on the X-axis, defaults to `10`. |
+| dy | number | `10` | Offset of the cell on the Y-axis, defaults to `10`. |
+| marginX | number | `0` | Margin of the cell on the X-axis, defaults to `0`. |
+| marginY | number | `0` | Margin of the cell on the Y-axis, defaults to `0`. |
+| center | boolean | `true` | Whether the nodes are center-aligned with the grid, defaults to `true`. |
+| resizeToFit | boolean | `false` | Whether to automatically adjust the size of the nodes to fit the grid size, defaults to `false`. |
+
+You can also implement a custom layout according to the signature `(this: Stencil, model: Model, group?: Group | null) => any`.
+
+### Search
+
+Stencil also provides search capabilities.
+
+```ts
+// Only search for rect nodes
+const stencil = new Stencil({
+ search: (cell, keyword, groupName, stencil) => {
+ if (keyword) {
+ return cell.shape === 'rect'
+ }
+ return true
+ },
+})
+
+// Search for rect nodes whose text contains the keyword
+const stencil = new Stencil({
+ search: (cell, keyword, groupName, stencil) => {
+ if (keyword) {
+ return cell.shape === 'rect' && cell.attr('text/text').includes(keyword)
+ }
+ return true
+ },
+})
+```
+
+## API
+
+### stencil.load(...)
+
+```ts
+load(nodes: (Node | Node.Metadata)[], groupName?: string): this
+```
+
+Load nodes. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|-----------|-----------------------------|:--------:|---------------|----------------------------|
+| nodes | `(Node \| Node.Metadata)[]` | √ | - | Nodes to load. |
+| groupName | string | | - | Name of the group to load nodes into. |
+
+### stencil.unload(...)
+
+```ts
+unload(nodes: (Node | Node.Metadata)[], groupName?: string): this
+```
+
+Unload nodes. Parameters are as follows:
+
+| Name | Type | Required | Default Value | Description |
+|-----------|-----------------------------|:--------:|---------------|----------------------------|
+| nodes | `(Node \| Node.Metadata)[]` | √ | - | Nodes to unload. |
+| groupName | string | | - | Name of the group to unload nodes from. |
+
+### stencil.addGroup(...)
+
+```ts
+addGroup(group: Stencil.Group | Stencil.Group[])
+```
+
+Add a new group.
+
+```ts
+stencil.addGroup({
+ name: 'group1',
+ graphHeight: 100,
+})
+```
+
+### stencil.removeGroup(...)
+
+```ts
+removeGroup(groupName: string | string[])
+```
+
+Remove a group.
+
+### stencil.resizeGroup(...)
+
+```typescript
+resizeGroup(groupName: string, size: { width: number; height: number })
+```
+
+Modify the size of a group.
diff --git a/sites/x6-sites/docs/tutorial/plugins/stencil.md b/sites/x6-sites/docs/tutorial/plugins/stencil.zh.md
similarity index 99%
rename from sites/x6-sites/docs/tutorial/plugins/stencil.md
rename to sites/x6-sites/docs/tutorial/plugins/stencil.zh.md
index 3700e06a97f..10eb3356fc5 100644
--- a/sites/x6-sites/docs/tutorial/plugins/stencil.md
+++ b/sites/x6-sites/docs/tutorial/plugins/stencil.zh.md
@@ -208,4 +208,4 @@ removeGroup(groupName: string | string[])
resizeGroup(groupName: string, size: { width: number; height: number })
```
-修改分组的尺寸。
\ No newline at end of file
+修改分组的尺寸。
diff --git a/sites/x6-sites/docs/tutorial/plugins/transform.en.md b/sites/x6-sites/docs/tutorial/plugins/transform.en.md
new file mode 100644
index 00000000000..86ebc76cbc4
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/plugins/transform.en.md
@@ -0,0 +1,138 @@
+---
+title: Graphic Transformations
+order: 0
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+ - /en/docs/tutorial/plugins
+---
+
+:::info{title="In this chapter, we mainly introduce the graphic transformation plugin. By reading, you can learn about"}
+
+- How to adjust node size using the interactive plugin
+- How to adjust node rotation angle using the interactive plugin
+
+:::
+
+## Usage
+
+Using `UI` components to adjust node size and angle is a common requirement. We provide a standalone plugin package `@antv/x6-plugin-transform` to utilize this functionality.
+
+```shell
+# npm
+$ npm install @antv/x6-plugin-transform --save
+
+# yarn
+$ yarn add @antv/x6-plugin-transform
+```
+
+Then we can use it in our code like this:
+
+```ts
+import { Transform } from '@antv/x6-plugin-transform'
+
+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):
+
+
+
+Next, let's experience interactive rotation of nodes (clicking on a node brings up the operation component):
+
+
+
+## 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:
+
+```ts
+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:
+
+```ts
+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 |
+
+```ts
+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())
+})
+```
diff --git a/sites/x6-sites/docs/tutorial/update.en.md b/sites/x6-sites/docs/tutorial/update.en.md
new file mode 100644
index 00000000000..6be9612595a
--- /dev/null
+++ b/sites/x6-sites/docs/tutorial/update.en.md
@@ -0,0 +1,101 @@
+---
+title: Upgrade to Version 2.x
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+---
+
+Compared to version 1.x, the changes to the external API and configuration are minimal, allowing for an upgrade to version 2.0 at a low cost.
+
+## Upgrade Reference
+
+### package.json
+
+```json
+{
+ "@antv/x6": "^2.0.0",
+ "@antv/x6-plugin-clipboard": "^2.0.0", // Install this package if using clipboard functionality
+ "@antv/x6-plugin-history": "^2.0.0", // Install this package if using undo/redo functionality
+ "@antv/x6-plugin-keyboard": "^2.0.0", // Install this package if using keyboard shortcut functionality
+ "@antv/x6-plugin-minimap": "^2.0.0", // Install this package if using minimap functionality
+ "@antv/x6-plugin-scroller": "^2.0.0", // Install this package if using scrollable canvas functionality
+ "@antv/x6-plugin-selection": "^2.0.0", // Install this package if using selection box functionality
+ "@antv/x6-plugin-snapline": "^2.0.0", // Install this package if using alignment line functionality
+ "@antv/x6-plugin-dnd": "^2.0.0", // Install this package if using drag-and-drop functionality
+ "@antv/x6-plugin-stencil": "^2.0.0", // Install this package if using stencil functionality
+ "@antv/x6-plugin-transform": "^2.0.0", // Install this package if using shape transformation functionality
+ "@antv/x6-plugin-export": "^2.0.0", // Install this package if using image export functionality
+ "@antv/x6-react-components": "^2.0.0", // Install this package if using accompanying UI components
+ "@antv/x6-react-shape": "^2.0.0", // Install this package if using React rendering functionality
+ "@antv/x6-vue-shape": "^2.0.0" // Install this package if using Vue rendering functionality
+}
+```
+
+### Configuration Changes
+
+| Property Name | Change | Description |
+|----------------|-----------------------|----------------------------------------------------------------------------|
+| virtual | Added | Whether to enable visual area rendering capability, default value is `false`. |
+| async | Default value changed to `true` | Default asynchronous rendering for improved performance. |
+| sorting | Removed | Sorting is done in the most performance-optimized way; if special sorting is needed, the order of input data must be controlled externally. |
+| frozen | Removed | The new asynchronous rendering mode does not require `frozen`. |
+| checkView | Removed | Built-in visual area rendering capability, enabling `virtual` configuration. |
+| transforming | Removed | Default uses optimal configuration, no external configuration needed. |
+| knob | Removed | Not widely used, removed in version 2.0. |
+| resizing | Removed | Use the transform plugin. |
+| rotating | Removed | Use the transform plugin. |
+| selecting | Removed | Use the selection plugin. |
+| clipboard | Removed | Use the clipboard plugin. |
+| snapline | Removed | Use the snapline plugin. |
+| history | Removed | Use the history plugin. |
+| scroller | Removed | Use the scroller plugin. |
+| keyboard | Removed | Use the keyboard plugin. |
+
+### API Changes
+
+| Method Name | Change | Description |
+|----------------------------|--------|--------------------------------------------|
+| graph.getCell | Removed | Replaced with `getCellById`. |
+| graph.resizeGraph | Removed | Replaced with `resize`. |
+| graph.resizeScroller | Removed | Replaced with `resize`. |
+| graph.getArea | Removed | Replaced with `getGraphArea`. |
+| graph.resizePage | Removed | Provided by the `scroller` plugin. |
+| graph.scrollToPoint | Removed | Provided by the `scroller` plugin. |
+| graph.scrollToContent | Removed | Provided by the `scroller` plugin. |
+| graph.scrollToCell | Removed | Provided by the `scroller` plugin. |
+| graph.transitionToPoint | Removed | Provided by the `scroller` plugin. |
+| graph.transitionToRect | Removed | Provided by the `scroller` plugin. |
+| graph.isFrozen | Removed | In the new rendering mode, `frozen` related methods are not needed. |
+| graph.freeze | Removed | In the new rendering mode, `frozen` related methods are not needed. |
+| graph.unfreeze | Removed | In the new rendering mode, `frozen` related methods are not needed. |
+| graph.isAsync | Removed | Removed `async` related methods. |
+| graph.setAsync | Removed | Removed `async` related methods. |
+| graph.isViewMounted | Removed | Infrequently used method, removed in version 2.0. |
+| graph.getMountedViews | Removed | Infrequently used method, removed in version 2.0. |
+| graph.getUnmountedViews | Removed | Infrequently used method, removed in version 2.0. |
+| graph.getClientMatrix | Removed | Infrequently used method, removed in version 2.0. |
+| graph.getPageOffset | Removed | Infrequently used method, removed in version 2.0. |
+| graph.removeTools | Removed | Infrequently used method, removed in version 2.0. |
+| graph.hideTools | Removed | Infrequently used method, removed in version 2.0. |
+| graph.showTools | Removed | Infrequently used method, removed in version 2.0. |
+| graph.printPreview | Removed | Infrequently used method, removed in version 2.0. |
+| cell.animate | Removed | Will be provided by the `animation` plugin in the future. |
+| cell.animateTransform | Removed | Will be provided by the `animation` plugin in the future. |
+| edge.sendToken | Removed | Will be provided by the `animation` plugin in the future. |
+
+### Using x6-react-shape
+
+For details on using `x6-react-shape`, please refer to the [documentation](/en/docs/tutorial/intermediate/react).
+
+### Using x6-vue-shape
+
+For details on using `x6-vue-shape`, please refer to the [documentation](/en/docs/tutorial/intermediate/vue).
+
+### Using x6-angular-shape
+
+For details on using `x6-angular-shape`, please refer to the [documentation](/en/docs/tutorial/intermediate/angular).
+
+### Plugin Usage
+
+For details on using plugins, please refer to the [documentation](/en/docs/tutorial/plugins/transform).
diff --git a/sites/x6-sites/docs/xflow/components/background.en.md b/sites/x6-sites/docs/xflow/components/background.en.md
new file mode 100644
index 00000000000..44228974412
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/background.en.md
@@ -0,0 +1,60 @@
+---
+title: Background
+order: 1
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Canvas Background
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## Background Image
+
+Add the `image` property to specify a background image for the canvas.
+
+
+
+## Background Watermark
+
+Set the `repeat` property to `watermark` to apply the background image as a watermark effect. You can use the `angle` property to control the rotation angle of the watermark.
+
+
+
+## API
+
+### Background
+
+| Parameter Name | Description | Type | Default Value |
+|----------------|-------------|------|---------------|
+| image | Background image URL | string | - |
+| color | Background color, supports all [CSS background-color](https://developer.mozilla.org/en-US/docs/Web/CSS/background-color) properties | string | - |
+| size | Background image size, supports all [CSS background-size](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) properties | string | - |
+| position | Background image position, supports all [CSS background-position](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) properties | string | `center` |
+| repeat | Background image repeat method, supports all [CSS background-repeat](https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat) properties as well as built-in properties `watermark`, `flip-x`, `flip-y`, `flip-xy` | string | `no-repeat` |
+| angle | Watermark rotation angle, effective only when the `repeat` property is set to `watermark` | number | 20 |
+| opacity | Background image opacity | number | 1 |
+| quality | Background image quality | number | 1 |
diff --git a/sites/x6-sites/docs/xflow/components/background.md b/sites/x6-sites/docs/xflow/components/background.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/background.md
rename to sites/x6-sites/docs/xflow/components/background.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/clipboard.en.md b/sites/x6-sites/docs/xflow/components/clipboard.en.md
new file mode 100644
index 00000000000..9ece9d7e7a2
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/clipboard.en.md
@@ -0,0 +1,39 @@
+---
+title: Clipboard Copy and Paste
+order: 3
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Copy and paste nodes and edges
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## API
+
+### Clipboard
+
+| Parameter Name | Description | Type | Default Value |
+|---------------------|-----------------------------------------------------------------------------|---------|---------------|
+| useLocalStorage | When enabled, the copied nodes/edges are also saved to `localStorage`, allowing copy/paste to work even after the browser is refreshed or reopened. | boolean | `false` |
diff --git a/sites/x6-sites/docs/xflow/components/clipboard.md b/sites/x6-sites/docs/xflow/components/clipboard.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/clipboard.md
rename to sites/x6-sites/docs/xflow/components/clipboard.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/control.en.md b/sites/x6-sites/docs/xflow/components/control.en.md
new file mode 100644
index 00000000000..447200286f5
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/control.en.md
@@ -0,0 +1,46 @@
+---
+title: Control Controller
+order: 8
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Canvas Common Operations Controller
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## API
+
+### Control
+
+| Parameter Name | Description | Type | Default Value |
+| -------------- | ----------- | ---- | ------------- |
+| items | Items displayed by the controller | ControlAction[] | - |
+| direction | Type of display for the controller | `horizontal` | `vertical` | `horizontal` |
+| placement | Direction of the controller's Tooltip display | `top` | `right` | `bottom` | `left` | `top` |
+
+Type of ControlAction
+| Parameter Name | Type | Default Value |
+| -------------- | ---- | ------------- |
+| ControlAction | ("zoomTo" | "zoomToFit" | "zoomIn" | "zoomOut" | "zoomToOrigin")[] | - |
diff --git a/sites/x6-sites/docs/xflow/components/control.md b/sites/x6-sites/docs/xflow/components/control.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/control.md
rename to sites/x6-sites/docs/xflow/components/control.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/graph.en.md b/sites/x6-sites/docs/xflow/components/graph.en.md
new file mode 100644
index 00000000000..4247302e823
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/graph.en.md
@@ -0,0 +1,324 @@
+---
+title: XFlowGraph Canvas
+order: 0
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+XFlow Canvas Component
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+The canvas has default shortcut keys and box selection functionality.
+
+## Read-Only Canvas
+
+Disables interaction with nodes and edges.
+
+When `readonly` is set to `false`, if the `draggable` property of a node/edge is set to `true`, the node/edge can be moved.
+
+```tsx
+
+
+## Fixed Dot Size Grid
+
+The fixed dot size grid, with the `type` property set to `fixedDot`, allows you to set the grid color and width through the `options` property. Note: When the canvas zoom level is less than 1, the dot size scales with the canvas zoom level. When the canvas zoom level is greater than 1, the dot size is fixed to the given thickness value.
+
+
+
+## Mesh Grid
+
+The mesh grid, with the `type` property set to `mesh`, allows you to set the grid color and width through the `options` property.
+
+
+
+## Double Mesh Grid
+
+The double mesh grid, with the `type` property set to `doubleMesh`, allows you to set the color and width of the primary and secondary grid lines through the `options` property.
+
+
+
+## API
+
+### Grid
+
+| Parameter Name | Description | Type | Default Value |
+|----------------|-------------|------|---------------|
+| visible | Whether the grid is displayed | boolean | `true` |
+| size | Grid size | number | 10 |
+| type | Grid type | `dot` \| `fixedDot` \| `mesh` \| `doubleMesh` | - |
+| options | Grid parameters corresponding to the grid type | [args](#options-args-parameters) \| [args](#options-args-parameters)[] | - |
+
+The options corresponding to the args parameters are as follows:
+ +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| color | Grid line color | string | - | +| thickness | Grid line width or dot size | string | - | +| factor | Interval between primary and secondary grid lines, only effective when `type` is `doubleMesh` | number | - | diff --git a/sites/x6-sites/docs/xflow/components/grid.md b/sites/x6-sites/docs/xflow/components/grid.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/components/grid.md rename to sites/x6-sites/docs/xflow/components/grid.zh.md diff --git a/sites/x6-sites/docs/xflow/components/history.en.md b/sites/x6-sites/docs/xflow/components/history.en.md new file mode 100644 index 00000000000..1dc97ec2b5b --- /dev/null +++ b/sites/x6-sites/docs/xflow/components/history.en.md @@ -0,0 +1,35 @@ +--- +title: History Undo Redo +order: 4 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/components +--- + +Element operations' undo and redo + +## Basic Usage + +:::info{title="Note"} + +The `
+
+## API
+
+### History
+
+For detailed configuration, please refer to [X6 Configuration](/tutorial/plugins/history#configuration).
diff --git a/sites/x6-sites/docs/xflow/components/history.md b/sites/x6-sites/docs/xflow/components/history.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/history.md
rename to sites/x6-sites/docs/xflow/components/history.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/minimap.en.md b/sites/x6-sites/docs/xflow/components/minimap.en.md
new file mode 100644
index 00000000000..51628466b20
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/minimap.en.md
@@ -0,0 +1,47 @@
+---
+title: Minimap
+order: 5
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Canvas Minimap
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## API
+
+### Minimap
+
+| Parameter Name | Description | Type | Default Value |
+|----------------|-------------|------|---------------|
+| style | Semantic structure style | CSSProperties | - |
+| classNames | Semantic structure class | string | - |
+| simple | Whether to display a simple view | boolean | `false` |
+| simpleNodeBackground | Background color of nodes in simple view | string | - |
+| minScale | Minimum scale ratio | number | `0.01` |
+| maxScale | Maximum scale ratio | number | `16` |
+| width | Width of the mini-map | number | `300` |
+| height | Height of the mini-map | number | `200` |
+| padding | Padding margin of the mini-map container | number | `10` |
+| scalable | Whether it is scalable | boolean | `true` |
+| graphOptions | Options for creating the mini-map Graph | Graph.Options | `null` |
diff --git a/sites/x6-sites/docs/xflow/components/minimap.md b/sites/x6-sites/docs/xflow/components/minimap.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/minimap.md
rename to sites/x6-sites/docs/xflow/components/minimap.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/snapline.en.md b/sites/x6-sites/docs/xflow/components/snapline.en.md
new file mode 100644
index 00000000000..65b659c5234
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/snapline.en.md
@@ -0,0 +1,35 @@
+---
+title: Snapline Alignment Lines
+order: 6
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Canvas alignment lines, a tool to assist in the layout of moving nodes.
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## API
+
+### Snapline
+
+For detailed configuration, please refer to [Snapline Configuration](/tutorial/plugins/snapline#configuration).
diff --git a/sites/x6-sites/docs/xflow/components/snapline.md b/sites/x6-sites/docs/xflow/components/snapline.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/snapline.md
rename to sites/x6-sites/docs/xflow/components/snapline.zh.md
diff --git a/sites/x6-sites/docs/xflow/components/transform.en.md b/sites/x6-sites/docs/xflow/components/transform.en.md
new file mode 100644
index 00000000000..f708c741f46
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/components/transform.en.md
@@ -0,0 +1,40 @@
+---
+title: Transform
+order: 7
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/components
+---
+
+Adjusting Node Size and Node Rotation Angle
+
+## Basic Usage
+
+:::info{title="Note"}
+
+The `
+
+## API
+
+### Transform
+
+| Parameter Name | Description | Type | Default Value |
+|----------------|-------------|------|---------------|
+| resizing | Configuration for adjusting node size | [Transform.Resizing](/tutorial/plugins/transform#adjust-size) \| `boolean` | - |
+| rotating | Configuration for adjusting node angle | [Transform.Rotating](/tutorial/plugins/transform#adjust-angle) \| `boolean` | - |
diff --git a/sites/x6-sites/docs/xflow/components/transform.md b/sites/x6-sites/docs/xflow/components/transform.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/components/transform.md
rename to sites/x6-sites/docs/xflow/components/transform.zh.md
diff --git a/sites/x6-sites/docs/xflow/guide/introduction.en.md b/sites/x6-sites/docs/xflow/guide/introduction.en.md
new file mode 100644
index 00000000000..a8936bb7700
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/guide/introduction.en.md
@@ -0,0 +1,48 @@
+---
+title: Introduction
+order: 0
+redirect_from:
+ - /en/docs
+ - /en/docs/tutorial
+
+---
+
+:::info{title="You are reading the documentation for XFlow 2.0"}
+
+- XFlow 1.x will stop maintenance on December 31, 2023. For more details, see the [XFlow 1.x Tutorial](https://xflow.antv.vision/en/docs/tutorial/intro/about)
+
+:::
+
+## What is XFlow
+
+XFlow is an application-level solution based on the X6 graph editing engine, designed for users of the React technology stack. It allows you to develop graph editing applications as easily as using React components, helping you efficiently create user interfaces. Whether for simple or complex interfaces, XFlow can handle it all.
+
+## XFlow Features
+
+🚀 Extremely Easy to Use: No complex concepts, just use it like React components.
+🛠️ Comprehensive Support: Built-in commonly used graph editing components.
+📦 Ready to Use: Provides mature solutions for DAG graphs, ER diagrams, flowcharts, and more.
+
+## How to Communicate
+
+If you have any questions, suggestions, feedback, or wish to communicate, you can contact us through the following methods:
+
+- Official Recommendation: [GitHub issues](https://github.com/antvis/XFlow/issues/new/choose)
+- Email:
diff --git a/sites/x6-sites/docs/xflow/guide/quick-start.md b/sites/x6-sites/docs/xflow/guide/quick-start.zh.md
similarity index 99%
rename from sites/x6-sites/docs/xflow/guide/quick-start.md
rename to sites/x6-sites/docs/xflow/guide/quick-start.zh.md
index e7f6a8c599d..9c47714daf2 100644
--- a/sites/x6-sites/docs/xflow/guide/quick-start.md
+++ b/sites/x6-sites/docs/xflow/guide/quick-start.zh.md
@@ -33,4 +33,4 @@ $ pnpm add @antv/xflow
接下来我们就一起使用 XFlow 来构建一个简单的图形应用,来体验一下 XFlow 的魅力吧。
-
\ No newline at end of file
+
diff --git a/sites/x6-sites/docs/xflow/hooks/useClipboard.en.md b/sites/x6-sites/docs/xflow/hooks/useClipboard.en.md
new file mode 100644
index 00000000000..e7bd7320aec
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/hooks/useClipboard.en.md
@@ -0,0 +1,56 @@
+---
+title: useClipboard
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+ - /en/docs/xflow/hooks
+---
+
+A Hook for copying and pasting nodes and edges.
+
+## Basic Usage
+
+```tsx
+ const { copy, paste, cut } = useClipboard();
+```
+
+## API
+
+```tsx
+
+const {
+ copy: (ids, copyOptions) => void,
+ paste: (ids, cutOptions) => void,
+ cut: (pasteOptions) => void
+} = useClipboard();
+
+```
+
+## Return Values
+
+| Parameter | Description | Type |
+|-----------|-------------|------|
+| copy | Copy elements | (ids: string[], copyOptions?: [CopyOptions](#CopyOptions-parameters-below)) => void |
+| paste | Render elements | (ids: string[], cutOptions?: [CopyOptions](#CopyOptions-parameters-below)) => void |
+| cut | Render elements | (pasteOptions?: [PasteOptions](#PasteOptions-parameters-below)) => [Cell](/en/docs/api/model/cell#properties)[] |
+
+CopyOptions parameters are as follows
+ +| Parameter | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| deep | Whether to recursively copy all child nodes/edges. | `boolean` | - | +| useLocalStorage| Whether to save the copied nodes/edges in `localStorage` | `boolean` | - | + +PasteOptions parameters are as follows
+ +| Parameter | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| offset | Offset for pasting nodes/edges onto the canvas | `number` \| `{ dx: number; dy: number }` | 20 | +| useLocalStorage| Whether to use nodes/edges from `localStorage` | `boolean` | - | +| nodeProps | Additional properties for nodes pasted onto the canvas | `Node.Properties` | - | +| edgeProps | Additional properties for edges pasted onto the canvas | `Edge.Properties` | - | + +## Parameters + +None diff --git a/sites/x6-sites/docs/xflow/hooks/useClipboard.md b/sites/x6-sites/docs/xflow/hooks/useClipboard.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useClipboard.md rename to sites/x6-sites/docs/xflow/hooks/useClipboard.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useDnd.en.md b/sites/x6-sites/docs/xflow/hooks/useDnd.en.md new file mode 100644 index 00000000000..147fcdb7f3f --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useDnd.en.md @@ -0,0 +1,60 @@ +--- +title: useDnd +order: 3 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +Quickly implement a hook for node dragging and dropping. + +## Basic Usage + +```tsx + const { startDrag } = useDnd(); +``` + +
+
+## API
+
+```tsx
+ const {
+ startDrag: (n, e) => void
+ } = useDnd(options: Options);
+```
+
+## Return Value
+
+| Parameter | Description | Type | Default Value |
+|-----------|-------------|------|---------------|
+| startDrag | Function to drag nodes | (n: [NodeOptions](#use-dnd-startDrag-options), e: React.MouseEventNodeOptions, in addition to inheriting from Node type, has two additional properties.
+ +For Node-related documentation, please refer to [Node](/api/model/node). + +```tsx +interface NodeOptions extends Node { + selected?: boolean; // Whether the node is selected + draggable?: boolean; // Whether the node is draggable +} +``` + +## Parameters + +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| options | Drag configuration | [Options](#use-dnd-options) | - | + +When using `useDnd` for dragging, you can configure it. + +The Options type is as follows:
+ +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| scaled | Whether the dragged node should be scaled | `boolean` | `false` | +| dndContainer | If `dndContainer` is set, releasing the mouse on `dndContainer` will not place the node, commonly used in scenarios where the `dnd` container is above the canvas | `HTMLElement` | - | +| draggingContainer | Custom dragging canvas container | `HTMLElement` | `document.body` | +| validateNode | Whether the dragged node should be validated | `(droppingNode: Node, options: ValidateNodeOptions) => boolean | Promise
+
+## API
+
+```tsx
+ useGraphEvent
+
+## API
+
+```tsx
+
+ useGraphStoreOptions parameters are as follows
+ +| Parameter | Description | Type | Default Value | +|-------------|---------------------------|----------------------------------------------------------------------|---------------| +| nodes | All nodes in the canvas | [NodeOptions](/api/model/node)[] | - | +| edges | All edges in the canvas | [EdgeOptions](/api/model/edge)[] | - | +| changeList | Store operation records | (`init` \| `addNodes` \| `removeNodes` \| `updateNode` \| `addEdges` \| `removeEdges` \| `updateEdge` )[] | - | +| initData | Initialize data | `(data: {nodes: NodeOptions[], edges: EdgeOptions[] }, options?: {silent?: boolean}) => void` | - | +| addNodes | Add nodes | `(ns: NodeOptions[], options?: {silent?: boolean}) => void` | - | +| removeNodes | Remove nodes | `(ids: string[], options?: {silent?: boolean}) => void` | - | +| updateNode | Update node | `(id: string, data: UpdateNodeDataOrFn, options?: {silent?: boolean}) => void` | - | +| addEdges | Add edges | `(es: EdgeOptions[], options?: {silent?: boolean}) => void` | - | +| removeEdges | Remove edges | `(ids: string[], options?: {silent?: boolean}) => void` | - | +| updateEdge | Update edge | `(id: string, data: UpdateEdgeDataOrFn, options?: {silent?: boolean}) => void` | - | +| clearChangeList | Clear operation records | `() => void` | - | diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphStore.md b/sites/x6-sites/docs/xflow/hooks/useGraphStore.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useGraphStore.md rename to sites/x6-sites/docs/xflow/hooks/useGraphStore.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useHistory.en.md b/sites/x6-sites/docs/xflow/hooks/useHistory.en.md new file mode 100644 index 00000000000..677de2ce32d --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useHistory.en.md @@ -0,0 +1,41 @@ +--- +title: useHistory +order: 6 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +A Hook for implementing canvas history tracking. +## Basic Usage + +```tsx + const { undo, redo, canUndo, canRedo } = useHistory(); +``` + +## API + +```tsx + +const { + undo: (options) => Graph | null, + redo: (options) => Graph | null, + canUndo: boolean, + canRedo: boolean +} = useHistory(); + +``` + +## Return Values + +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| undo | Undo action; `options` will be passed to the event callback | `(options?: KeyValue) => Graph` \| `null` | - | +| redo | Redo action; `options` will be passed to the event callback | `(options?: KeyValue) => Graph` \| `null` | - | +| canUndo | Indicates if undo is possible | `boolean` | `false` | +| canRedo | Indicates if redo is possible | `boolean` | `false` | + +## Parameters + +None diff --git a/sites/x6-sites/docs/xflow/hooks/useHistory.md b/sites/x6-sites/docs/xflow/hooks/useHistory.zh.md similarity index 94% rename from sites/x6-sites/docs/xflow/hooks/useHistory.md rename to sites/x6-sites/docs/xflow/hooks/useHistory.zh.md index e559820714d..2ac3a64e54e 100644 --- a/sites/x6-sites/docs/xflow/hooks/useHistory.md +++ b/sites/x6-sites/docs/xflow/hooks/useHistory.zh.md @@ -3,8 +3,8 @@ title: useHistory order: 6 redirect_from: - /zh/docs - - /zh/docs/xflow - - /zh/docs/xflow/hooks + - /zh/docs/xflow + - /zh/docs/xflow/hooks --- 用于实现画布历史记录的 Hook diff --git a/sites/x6-sites/docs/xflow/hooks/useKeyboard.en.md b/sites/x6-sites/docs/xflow/hooks/useKeyboard.en.md new file mode 100644 index 00000000000..1c83266b0e8 --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useKeyboard.en.md @@ -0,0 +1,46 @@ +--- +title: useKeyboard +order: 7 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +Implementing a Hook for Canvas Keyboard Shortcuts + +## Basic Usage + +```tsx + useKeyboard('ctrl+c', () => { ... }); +``` + +Here is a simple example of using `useKeyboard`: +`Ctrl + C` to copy a node +`Ctrl + V` to paste a node + +
+
+## API
+
+```tsx
+
+useKeyboard(
+ key: string | string[],
+ callback: (e) => void,
+ action?: 'keypress' | 'keydown' | 'keyup'
+)
+
+```
+
+## Return Value
+
+None
+
+## Parameters
+
+| Parameter | Description | Type | Default Value |
+|-----------|-------------|------|---------------|
+| key | The shortcut key to bind | `string` \| `string[]` | - |
+| callback | The callback to execute on the shortcut key | `(e: KeyboardEvent) => void` | - |
+| action | The trigger type | `keypress` \| `keydown` \| `keyup` | - |
diff --git a/sites/x6-sites/docs/xflow/hooks/useKeyboard.md b/sites/x6-sites/docs/xflow/hooks/useKeyboard.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/hooks/useKeyboard.md
rename to sites/x6-sites/docs/xflow/hooks/useKeyboard.zh.md
diff --git a/sites/x6-sites/docs/xflow/store.en.md b/sites/x6-sites/docs/xflow/store.en.md
new file mode 100644
index 00000000000..da71d6990d2
--- /dev/null
+++ b/sites/x6-sites/docs/xflow/store.en.md
@@ -0,0 +1,81 @@
+---
+title: Store
+order: 4
+redirect_from:
+ - /en/docs
+ - /en/docs/xflow
+---
+
+Xflow provides unified management of data on the canvas, with all canvas data stored in a single `store`, making development very easy.
+
+You can conveniently manipulate the `store` using [useGraphStore]((/xflow/hooks/use-graph-store)), allowing you to update the canvas data and achieve canvas updates.
+## Initialization State
+
+### `initData(data, options)`
+
+This function is used to initialize the state manager, setting the initial nodes and edges.
+
+Parameters:
+
+- `data`: An object containing two arrays, `nodes` and `edges`, which store the data for nodes and edges, respectively.
+- `options`: An optional object. When set to `{ silent: true }`, the initialization operation will not be recorded in the change list `changeList`.
+
+## Node Operations
+
+### `addNodes(ns, options)`
+
+Adds new nodes to the state manager.
+
+Parameters:
+
+- `ns`: An array of node objects.
+- `options`: An optional object. When `{ silent: true }`, the add operation will not be recorded in the change list.
+
+### `removeNodes(ids, options)`
+
+Removes nodes by an array of IDs.
+
+Parameters:
+
+- `ids`: An array containing node IDs.
+- `options`: An optional object. When `{ silent: true }`, the remove operation will not be recorded in the change list.
+
+### `updateNode(id, data, options)`
+
+Updates a node by its ID. Modifying the node's `id` or `shape` properties is not allowed.
+
+Parameters:
+
+- `id`: The ID of the node to be updated.
+- `data`: An object or a function containing the data to be updated.
+- `options`: An optional object. When `{ silent: true }`, the update operation will not be recorded in the change list.
+
+## Edge Operations
+
+### `addEdges(es, options)`
+
+Adds new edges to the state manager.
+
+Parameters:
+
+- `es`: An array of edge objects.
+- `options`: An optional object. When `{ silent: true }`, the add operation will not be recorded in the change list.
+
+### `removeEdges(ids, options)`
+
+Removes edges by an array of IDs.
+
+Parameters:
+
+- `ids`: An array containing edge IDs.
+- `options`: An optional object. When `{ silent: true }`, the remove operation will not be recorded in the change list.
+
+### `updateEdge(id, data, options)`
+
+Updates an edge by its ID. Modifying the edge's `id` or `shape` properties is not allowed.
+
+Parameters:
+
+- `id`: The ID of the edge to be updated.
+- `data`: An object or a function containing the data to be updated.
+- `options`: An optional object. When `{ silent: true }`, the update operation will not be recorded in the change list.
diff --git a/sites/x6-sites/docs/xflow/store.md b/sites/x6-sites/docs/xflow/store.zh.md
similarity index 100%
rename from sites/x6-sites/docs/xflow/store.md
rename to sites/x6-sites/docs/xflow/store.zh.md