From 654aa57a6dfbea300bf91b0b1f6819be8691ea7d Mon Sep 17 00:00:00 2001 From: Claudiu Ivan Date: Mon, 26 Aug 2024 23:40:51 +0300 Subject: [PATCH] docs: add english translation --- .../x6-sites/docs/api/graph/background.en.md | 131 + .../x6-sites/docs/api/graph/coordinate.en.md | 96 + sites/x6-sites/docs/api/graph/graph.en.md | 41 + sites/x6-sites/docs/api/graph/grid.en.md | 218 ++ .../x6-sites/docs/api/graph/mousewheel.en.md | 123 + sites/x6-sites/docs/api/graph/panning.en.md | 112 + sites/x6-sites/docs/api/graph/transform.en.md | 350 +++ sites/x6-sites/docs/api/model/attrs.en.md | 199 ++ sites/x6-sites/docs/api/model/cell.en.md | 2202 +++++++++++++++++ sites/x6-sites/docs/api/model/edge.en.md | 742 ++++++ .../x6-sites/docs/api/model/interaction.en.md | 414 ++++ sites/x6-sites/docs/api/model/labels.en.md | 546 ++++ sites/x6-sites/docs/api/model/marker.en.md | 381 +++ sites/x6-sites/docs/api/model/node.en.md | 890 +++++++ sites/x6-sites/docs/api/mvc/model.en.md | 698 ++++++ sites/x6-sites/docs/api/mvc/view.en.md | 201 ++ sites/x6-sites/docs/api/registry/attr.en.md | 881 +++++++ .../docs/api/registry/connection-point.en.md | 161 ++ .../docs/api/registry/connector.en.md | 242 ++ .../docs/api/registry/edge-anchor.en.md | 92 + .../docs/api/registry/edge-tool.en.md | 429 ++++ sites/x6-sites/docs/api/registry/filter.en.md | 214 ++ .../docs/api/registry/highlighter.en.md | 117 + .../docs/api/registry/node-anchor.en.md | 250 ++ .../docs/api/registry/node-tool.en.md | 260 ++ .../docs/api/registry/port-label-layout.en.md | 247 ++ .../docs/api/registry/port-layout.en.md | 393 +++ sites/x6-sites/docs/api/registry/router.en.md | 287 +++ sites/x6-sites/docs/temp/animation.en.md | 346 +++ sites/x6-sites/docs/temp/components.en.md | 116 + sites/x6-sites/docs/temp/layout.en.md | 225 ++ .../docs/temp/ui/auto-scrollbox.en.md | 19 +- .../x6-sites/docs/temp/ui/color-picker.en.md | 12 +- sites/x6-sites/docs/temp/ui/contextmenu.en.md | 20 +- sites/x6-sites/docs/temp/ui/dropdown.en.md | 28 +- sites/x6-sites/docs/temp/ui/menu.en.md | 58 +- sites/x6-sites/docs/temp/ui/menubar.en.md | 18 +- sites/x6-sites/docs/temp/ui/scrollbox.en.md | 46 +- sites/x6-sites/docs/temp/ui/splitbox.en.md | 40 +- sites/x6-sites/docs/temp/ui/toolbar.en.md | 58 +- sites/x6-sites/docs/tutorial/about.en.md | 72 + sites/x6-sites/docs/tutorial/basic/edge.en.md | 338 +++ .../x6-sites/docs/tutorial/basic/events.en.md | 416 ++++ .../x6-sites/docs/tutorial/basic/graph.en.md | 93 + .../docs/tutorial/basic/interacting.en.md | 220 ++ sites/x6-sites/docs/tutorial/basic/node.en.md | 150 ++ sites/x6-sites/docs/tutorial/basic/port.en.md | 122 + .../docs/tutorial/basic/serialization.en.md | 101 + .../docs/tutorial/basic/serialization.zh.md | 2 +- sites/x6-sites/docs/tutorial/devtool.en.md | 38 + .../docs/tutorial/getting-started.en.md | 2 + .../docs/tutorial/intermediate/angular.en.md | 155 ++ .../{angular.md => angular.zh.md} | 0 .../intermediate/connection-point.en.md | 78 + .../docs/tutorial/intermediate/group.en.md | 139 ++ .../docs/tutorial/intermediate/html.en.md | 66 + .../intermediate/{html.md => html.zh.md} | 0 .../docs/tutorial/intermediate/react.en.md | 99 + .../docs/tutorial/intermediate/tools.en.md | 80 + .../docs/tutorial/intermediate/vue.en.md | 200 ++ .../intermediate/{vue.md => vue.zh.md} | 0 .../docs/tutorial/plugins/clipboard.en.md | 180 ++ .../x6-sites/docs/tutorial/plugins/dnd.en.md | 141 ++ .../docs/tutorial/plugins/export.en.md | 99 + .../docs/tutorial/plugins/history.en.md | 224 ++ .../docs/tutorial/plugins/keyboard.en.md | 163 ++ .../docs/tutorial/plugins/minimap.en.md | 63 + .../docs/tutorial/plugins/scroller.en.md | 119 + .../docs/tutorial/plugins/selection.en.md | 405 +++ .../docs/tutorial/plugins/snapline.en.md | 211 ++ .../docs/tutorial/plugins/stencil.en.md | 211 ++ .../plugins/{stencil.md => stencil.zh.md} | 2 +- .../docs/tutorial/plugins/transform.en.md | 138 ++ sites/x6-sites/docs/tutorial/update.en.md | 101 + .../docs/xflow/components/background.en.md | 60 + .../{background.md => background.zh.md} | 0 .../docs/xflow/components/clipboard.en.md | 39 + .../{clipboard.md => clipboard.zh.md} | 0 .../docs/xflow/components/control.en.md | 46 + .../components/{control.md => control.zh.md} | 0 .../docs/xflow/components/graph.en.md | 324 +++ .../components/{graph.md => graph.zh.md} | 0 .../x6-sites/docs/xflow/components/grid.en.md | 78 + .../xflow/components/{grid.md => grid.zh.md} | 0 .../docs/xflow/components/history.en.md | 35 + .../components/{history.md => history.zh.md} | 0 .../docs/xflow/components/minimap.en.md | 47 + .../components/{minimap.md => minimap.zh.md} | 0 .../docs/xflow/components/snapline.en.md | 35 + .../{snapline.md => snapline.zh.md} | 0 .../docs/xflow/components/transform.en.md | 40 + .../{transform.md => transform.zh.md} | 0 .../docs/xflow/guide/introduction.en.md | 48 + .../{introduction.md => introduction.zh.md} | 0 .../docs/xflow/guide/quick-start.en.md | 36 + .../{quick-start.md => quick-start.zh.md} | 2 +- .../docs/xflow/hooks/useClipboard.en.md | 56 + .../{useClipboard.md => useClipboard.zh.md} | 0 sites/x6-sites/docs/xflow/hooks/useDnd.en.md | 60 + .../xflow/hooks/{useDnd.md => useDnd.zh.md} | 0 .../x6-sites/docs/xflow/hooks/useExport.en.md | 40 + .../hooks/{useExport.md => useExport.zh.md} | 0 .../docs/xflow/hooks/useGraphEvent.en.md | 40 + .../{useGraphEvent.md => useGraphEvent.zh.md} | 0 .../docs/xflow/hooks/useGraphInstance.en.md | 32 + ...raphInstance.md => useGraphInstance.zh.md} | 0 .../docs/xflow/hooks/useGraphStore.en.md | 56 + .../{useGraphStore.md => useGraphStore.zh.md} | 0 .../docs/xflow/hooks/useHistory.en.md | 41 + .../hooks/{useHistory.md => useHistory.zh.md} | 4 +- .../docs/xflow/hooks/useKeyboard.en.md | 46 + .../{useKeyboard.md => useKeyboard.zh.md} | 0 sites/x6-sites/docs/xflow/store.en.md | 81 + .../docs/xflow/{store.md => store.zh.md} | 0 114 files changed, 17422 insertions(+), 155 deletions(-) create mode 100644 sites/x6-sites/docs/api/graph/background.en.md create mode 100644 sites/x6-sites/docs/api/graph/coordinate.en.md create mode 100644 sites/x6-sites/docs/api/graph/graph.en.md create mode 100644 sites/x6-sites/docs/api/graph/grid.en.md create mode 100644 sites/x6-sites/docs/api/graph/mousewheel.en.md create mode 100644 sites/x6-sites/docs/api/graph/panning.en.md create mode 100644 sites/x6-sites/docs/api/graph/transform.en.md create mode 100644 sites/x6-sites/docs/api/model/attrs.en.md create mode 100644 sites/x6-sites/docs/api/model/cell.en.md create mode 100644 sites/x6-sites/docs/api/model/edge.en.md create mode 100644 sites/x6-sites/docs/api/model/interaction.en.md create mode 100644 sites/x6-sites/docs/api/model/labels.en.md create mode 100644 sites/x6-sites/docs/api/model/marker.en.md create mode 100644 sites/x6-sites/docs/api/model/node.en.md create mode 100644 sites/x6-sites/docs/api/mvc/model.en.md create mode 100644 sites/x6-sites/docs/api/mvc/view.en.md create mode 100644 sites/x6-sites/docs/api/registry/attr.en.md create mode 100644 sites/x6-sites/docs/api/registry/connection-point.en.md create mode 100644 sites/x6-sites/docs/api/registry/connector.en.md create mode 100644 sites/x6-sites/docs/api/registry/edge-anchor.en.md create mode 100644 sites/x6-sites/docs/api/registry/edge-tool.en.md create mode 100644 sites/x6-sites/docs/api/registry/filter.en.md create mode 100644 sites/x6-sites/docs/api/registry/highlighter.en.md create mode 100644 sites/x6-sites/docs/api/registry/node-anchor.en.md create mode 100644 sites/x6-sites/docs/api/registry/node-tool.en.md create mode 100644 sites/x6-sites/docs/api/registry/port-label-layout.en.md create mode 100644 sites/x6-sites/docs/api/registry/port-layout.en.md create mode 100644 sites/x6-sites/docs/api/registry/router.en.md create mode 100644 sites/x6-sites/docs/temp/animation.en.md create mode 100644 sites/x6-sites/docs/temp/components.en.md create mode 100644 sites/x6-sites/docs/temp/layout.en.md create mode 100644 sites/x6-sites/docs/tutorial/about.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/edge.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/events.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/graph.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/interacting.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/node.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/port.en.md create mode 100644 sites/x6-sites/docs/tutorial/basic/serialization.en.md create mode 100644 sites/x6-sites/docs/tutorial/devtool.en.md create mode 100644 sites/x6-sites/docs/tutorial/intermediate/angular.en.md rename sites/x6-sites/docs/tutorial/intermediate/{angular.md => angular.zh.md} (100%) create mode 100644 sites/x6-sites/docs/tutorial/intermediate/connection-point.en.md create mode 100644 sites/x6-sites/docs/tutorial/intermediate/group.en.md create mode 100644 sites/x6-sites/docs/tutorial/intermediate/html.en.md rename sites/x6-sites/docs/tutorial/intermediate/{html.md => html.zh.md} (100%) create mode 100644 sites/x6-sites/docs/tutorial/intermediate/react.en.md create mode 100644 sites/x6-sites/docs/tutorial/intermediate/tools.en.md create mode 100644 sites/x6-sites/docs/tutorial/intermediate/vue.en.md rename sites/x6-sites/docs/tutorial/intermediate/{vue.md => vue.zh.md} (100%) create mode 100644 sites/x6-sites/docs/tutorial/plugins/clipboard.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/dnd.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/export.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/history.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/keyboard.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/minimap.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/scroller.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/selection.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/snapline.en.md create mode 100644 sites/x6-sites/docs/tutorial/plugins/stencil.en.md rename sites/x6-sites/docs/tutorial/plugins/{stencil.md => stencil.zh.md} (99%) create mode 100644 sites/x6-sites/docs/tutorial/plugins/transform.en.md create mode 100644 sites/x6-sites/docs/tutorial/update.en.md create mode 100644 sites/x6-sites/docs/xflow/components/background.en.md rename sites/x6-sites/docs/xflow/components/{background.md => background.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/clipboard.en.md rename sites/x6-sites/docs/xflow/components/{clipboard.md => clipboard.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/control.en.md rename sites/x6-sites/docs/xflow/components/{control.md => control.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/graph.en.md rename sites/x6-sites/docs/xflow/components/{graph.md => graph.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/grid.en.md rename sites/x6-sites/docs/xflow/components/{grid.md => grid.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/history.en.md rename sites/x6-sites/docs/xflow/components/{history.md => history.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/minimap.en.md rename sites/x6-sites/docs/xflow/components/{minimap.md => minimap.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/snapline.en.md rename sites/x6-sites/docs/xflow/components/{snapline.md => snapline.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/components/transform.en.md rename sites/x6-sites/docs/xflow/components/{transform.md => transform.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/guide/introduction.en.md rename sites/x6-sites/docs/xflow/guide/{introduction.md => introduction.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/guide/quick-start.en.md rename sites/x6-sites/docs/xflow/guide/{quick-start.md => quick-start.zh.md} (99%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useClipboard.en.md rename sites/x6-sites/docs/xflow/hooks/{useClipboard.md => useClipboard.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useDnd.en.md rename sites/x6-sites/docs/xflow/hooks/{useDnd.md => useDnd.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useExport.en.md rename sites/x6-sites/docs/xflow/hooks/{useExport.md => useExport.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useGraphEvent.en.md rename sites/x6-sites/docs/xflow/hooks/{useGraphEvent.md => useGraphEvent.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useGraphInstance.en.md rename sites/x6-sites/docs/xflow/hooks/{useGraphInstance.md => useGraphInstance.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useGraphStore.en.md rename sites/x6-sites/docs/xflow/hooks/{useGraphStore.md => useGraphStore.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useHistory.en.md rename sites/x6-sites/docs/xflow/hooks/{useHistory.md => useHistory.zh.md} (94%) create mode 100644 sites/x6-sites/docs/xflow/hooks/useKeyboard.en.md rename sites/x6-sites/docs/xflow/hooks/{useKeyboard.md => useKeyboard.zh.md} (100%) create mode 100644 sites/x6-sites/docs/xflow/store.en.md rename sites/x6-sites/docs/xflow/{store.md => store.zh.md} (100%) diff --git a/sites/x6-sites/docs/api/graph/background.en.md b/sites/x6-sites/docs/api/graph/background.en.md new file mode 100644 index 00000000000..77ef38efcf6 --- /dev/null +++ b/sites/x6-sites/docs/api/graph/background.en.md @@ -0,0 +1,131 @@ +--- +title: Background +order: 3 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/graph +--- + +The background is used to specify the background color or background image of the canvas, supporting [watermark background](#repeat). The background layer is at the bottom of the DOM layer. + +## Demo + + + +## 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 `` and ``. +- [`refRx`](/en/docs/api/registry/attr#refrx) and [`refRy`](/en/docs/api/registry/attr#refry) set the radius of ``. +- [`refR`](/en/docs/api/registry/attr#refr) sets the radius of ``. + +Let's take a look at how to use these relative attributes. In the following example, we define a red ellipse `e`, a green rectangle `r`, a blue circle `c`, and a rectangle `outline` that represents the node size. + +```ts +graph.addNode({ + shape: 'custom-rect', + x: 160, + y: 100, + width: 280, + height: 120, + attrs: { + e: { + refRx: '50%', // ellipse x-axis radius is half of the width + refRy: '25%', // ellipse y-axis radius is a quarter of the height + refCx: '50%', // ellipse center x-coordinate is half of the width + refCy: 0, // ellipse center y-coordinate is 0 + refX: '-50%', // offset to the left by half of the width + refY: '25%', // offset down by a quarter of the height + }, + r: { + refX: '100%', // rectangle x-coordinate is at the right bottom corner of the node + refY: '100%', // rectangle y-coordinate is at the right bottom corner of the node + refWidth: '50%', // rectangle width is half of the node width + refHeight: '50%', // rectangle height is half of the node height + x: -10, // offset to the left by 10px + y: -10, // offset up by 10px + }, + c: { + refRCircumscribed: '50%', // circle radius is half of the larger value of node width and height + refCx: '50%', // circle center x-coordinate is at the node center + refCy: '50%', // circle center y-coordinate is at the node center + }, + }, +}) +``` + +## Relative Sub-elements + +The above attributes are calculated relative to the node size by default. We can also use the `ref` attribute to provide a sub-element selector, so that all calculations are relative to the element referred to by `ref`, achieving relative size and position to sub-elements. + +::: warning +Note that setting `ref` will make all calculations dependent on the sub-element's bbox measurement in the browser, which may affect performance. +::: + +```ts +graph.addNode({ + shape: 'custom-text', + x: 320, + y: 160, + width: 280, + height: 120, + attrs: { + label: { + text: 'H', + }, + e: { + ref: 'label', + refRx: '50%', + refRy: '25%', + refCx: '50%', + refCy: 0, + refX: '-50%', + refY: '25%', + }, + r: { + ref: 'label', + refX: '100%', + refY: '100%', + x: -10, + y: -10, + refWidth: '50%', + refHeight: '50%', + }, + c: { + ref: 'label', + refRCircumscribed: '50%', + }, + }, +}) +``` + +## Relative Position Along the Edge + +We provide the following attributes to set the position of edges and sub-elements relative to the edge. + +- [`connection`](/en/docs/api/registry/attr#connection) is only applicable to `` elements of edges, indicating that the edge will be rendered on this element when set to `true`. +- [`atConnectionLength`](/en/docs/api/registry/attr#atconnectionlengthkeepgradient) is an abbreviation of `atConnectionLengthKeepGradient`, indicating that the element will be moved to the specified offset position and automatically rotated to match the slope of the edge at that position. +- [`atConnectionRatio`](/en/docs/api/registry/attr#atconnectionratiokeepgradient) is an abbreviation of `atConnectionRatioKeepGradient`, indicating that the element will be moved to the specified ratio `[0, 1]` position and automatically rotated to match the slope of the edge at that position. +- [`atConnectionLengthIgnoreGradient`](/en/docs/api/registry/attr#atconnectionlengthignoregradient) will move the element to the specified offset position, ignoring the edge's slope, without automatic rotation. +- [`atConnectionRatioIgnoreGradient`](/en/docs/api/registry/attr#atconnectionratioignoregradient) will move the element to the specified ratio `[0, 1]` position, ignoring the edge's slope, without automatic rotation. + +```ts +graph.addEdge({ + shape: 'custom-edge', + source: { x: 100, y: 60 }, + target: { x: 500, y: 60 }, + vertices: [{ x: 300, y: 160 }], + attrs: { + symbol: { + atConnectionRatio: 0.75, // along the edge, 75% from the start point + }, + arrowhead: { + atConnectionLength: 100, // along the edge, 100px from the start point + }, + }, +}) +``` + +```ts +graph.addEdge({ + shape: 'custom-edge', + source: { x: 100, y: 60 }, + target: { x: 500, y: 60 }, + vertices: [{ x: 300, y: 160 }], + attrs: { + relativeLabel: { + text: '0.25', + atConnectionRatio: 0.25, + }, + relativeLabelBody: { + atConnectionRatio: 0.25, + }, + + absoluteLabel: { + text: '150', + atConnectionLength: 150, + }, + absoluteLabelBody: { + atConnectionLength: 150, + }, + + absoluteReverseLabel: { + text: '-100', + atConnectionLength: -100, + }, + absoluteReverseLabelBody: { + atConnectionLength: -100, + }, + + offsetLabelPositive: { + y: 40, + text: 'keepGradient: 0,40', + atConnectionRatio: 0.66, + }, + offsetLabelPositiveBody: { + x: -60, // 0 + -60 + y: 30, // 40 + -10 + atConnectionRatio: 0.66, + }, + + offsetLabelNegative: { + y: -40, + text: 'keepGradient: 0,-40', + atConnectionRatio: 0.66, + }, + offsetLabelNegativeBody: { + x: -60, // 0 + -60 + y: -50, // -40 + -10 + atConnectionRatio: 0.66, + }, + + offsetLabelAbsolute: { + x: -40, + y: 80, + text: 'ignoreGradient: -40,80', + atConnectionRatioIgnoreGradient: 0.66, + }, + offsetLabelAbsoluteBody: { + x: -110, // -40 + -70 + y: 70, // 80 + -10 + atConnectionRatioIgnoreGradient: 0.66, + }, + }, +}) +``` + +## Using Arrows + +We can use the `sourceMarker` and `targetMarker` special attributes to specify the start and end arrowheads of edges, respectively. For more information, please refer to [this tutorial](/en/docs/api/model/marker). \ No newline at end of file diff --git a/sites/x6-sites/docs/api/model/cell.en.md b/sites/x6-sites/docs/api/model/cell.en.md new file mode 100644 index 00000000000..6fb324b359f --- /dev/null +++ b/sites/x6-sites/docs/api/model/cell.en.md @@ -0,0 +1,2202 @@ +--- +title: Cell +order: 0 +redirect_from: + - /docs + - /docs/api + - /docs/api/model +--- + +Cell is the base class for [Node](/docs/api/model/node) and [Edge](/docs/api/model/edge), containing common property and method definitions for nodes and edges, such as attribute styles, visibility, business data, etc. It also exhibits the same behavior in terms of instantiation, style customization, default options, and custom options. + +## Properties + +| Option | Type | Default | Required | Description | +|----------|---------------------------------|---------|:--------:|------------------------------------------------------------------------------------------------| +| id | string | | | Unique identifier for the node/edge. It's recommended to use an ID with business meaning. By default, a UUID is automatically generated. | +| markup | Markup | | | SVG/HTML fragment for the node/edge. | +| attrs | Attr.CellAttrs | | | Attribute styles for the node/edge. | +| shape | string | | | Shape used to render the node/edge. Default value for nodes is `rect`, for edges is `edge`. | +| view | string | | | View used to render the node/edge. | +| zIndex | number | | | Layer level of the node/edge in the canvas. By default, it's automatically determined based on the order of node/edge addition. | +| visible | boolean | `true` | | Whether the node/edge is visible. | +| parent | string | | | Parent node. | +| children | string[] | | | Child nodes/edges. | +| tools | ToolItem \| ToolItem[] \| Tools | | | Tool options. | +| data | any | | | Business data associated with the node/edge. | + +### id + +`id` is the unique identifier for the node/edge. It's recommended to use an ID with business meaning. By default, a UUID is automatically generated. + +### markup + +`markup` specifies the SVG/HTML fragment used to render the node/edge, described in JSON format. For example, the `markup` definition for the built-in node `Shape.Rect` is as follows: + +```ts +{ + markup: [ + { + tagName: 'rect', + selector: 'body', + }, + { + tagName: 'text', + selector: 'label', + }, + ], +} +``` + +This indicates that the node internally contains two SVG elements: `` and ``. After rendering to the page, the SVG element corresponding to the node looks like this: + +```html + + + + rect + + +``` + +From the above introduction, we have a general understanding of the `Markup` structure. Now, let's detail the `Markup` definition. + +```ts +interface Markup { + tagName: string + ns?: string + selector?: string + groupSelector?: string | string[] + attrs?: { [key: string]: string | number } + style?: { [key: string]: string | number } + className?: string | string[] + textContent?: string + children?: Markup[] +} +``` + +| Option | Type | Default | Required | Description | +|---------------|------------------|--------------------------------|:--------:|------------------------------------------------------------------------------------------------| +| tagName | string | | ✓ | SVG/HTML element tag name. | +| ns | string | `"http://www.w3.org/2000/svg"` | | SVG/HTML element namespace. | +| selector | string | - | | Unique selector for the element, used to locate the element or specify attribute styles for it. | +| groupSelector | string | - | | Group selector for the element, can be used to specify styles for multiple elements in the group simultaneously. | +| attrs | Attr.SimpleAttrs | - | | Default attribute key-value pairs for the element. | +| style | KeyValue | - | | Inline style key-value pairs for the element. | +| className | string | - | | CSS class name for the element. | +| textContent | string | - | | Text content of the element. | +| children | Markup[] | - | | Nested child elements. | + +#### tagName + +Specifies which type of SVG/HTML element to create through `tagName`. + +#### ns + +The namespace of the element. It should correspond to the element type specified by `tagName`. By default, it uses the SVG element namespace `"http://www.w3.org/2000/svg"`. + +- SVG element namespace is `"http://www.w3.org/2000/svg"` +- HTML element namespace is `"http://www.w3.org/1999/xhtml"` + +#### selector + +The unique selector for the element, used to specify [attribute styles](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Fills_and_Strokes) for the element. For example, to specify attribute styles for `` and `` elements of the built-in node `Shape.Rect`: + +```ts +const rect = new Shape.Rect({ + x: 40, + y: 40, + width: 100, + height: 40, + attrs: { + // Specify styles for the rect element + body: { + stroke: '#000', // Border color + fill: '#fff', // Fill color + }, + // Specify styles for the text element + label: { + text: 'rect', // Text content + fill: '#333', // Text color + }, + }, +}) +``` + +#### groupSelector + +The group selector for the element. Through the group selector, styles can be specified for multiple elements associated with the group. For example, in the following Markup, two `` elements have the same `groupSelector` value `group1`: + +```ts +{ + markup: [ + { + tagName: 'rect', + selector: 'body', + groupSelector: 'group1', + }, + { + tagName: 'rect', + selector: 'wrap', + groupSelector: 'group1', + }, + { + tagName: 'text', + selector: 'label', + }, + ], +} +``` + +When creating a node, we can specify group styles like this: + +```ts +new SomeNode({ + attrs: { + group1: { + fill: '#2ECC71', + }, + }, +}) +``` + +#### attrs + +Default attribute key-value pairs for the element, typically used to define unchanging common attributes. These default attributes can also be overridden when instantiating the node. Note that the `attrs` property in `markup` only supports native SVG attributes, meaning X6's [custom attributes]() are not available here. + +For example, we specified the following default attributes for the `` and `` elements of the built-in node `Shape.Rect`: + +```js +{ + markup: [ + { + tagName: 'rect', + selector: 'body', + attrs: { + fill: '#fff', + stroke: '#000', + strokeWidth: 2, + } + }, + { + tagName: 'text', + selector: 'label', + attrs: { + fill: '#333', + textAnchor: 'middle', + textVerticalAnchor: 'middle', + } + }, + ], +} +``` + +#### style + +Inline style key-value pairs for the element. + +#### className + +CSS class name for the element. + +#### textContent + +Text content of the element. + +#### children + +Nested child elements. + +### attrs + +The attribute option `attrs` is a complex object. The keys of this object are the selectors ([selector](#selector)) of elements defined in the node's Markup, and the corresponding values are [SVG attribute values](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) (such as [fill](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill) and [stroke](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke)) applied to that SVG element. If you're not familiar with SVG attributes yet, you can refer to the beginner's tutorial on [Fills and Strokes](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Fills_and_Strokes) provided by MDN. + +For example, the Markup of the built-in node `Shape.Rect` defines two selectors: `body` (representing the `` element) and `label` (representing the `` element). We can specify attribute styles for elements in this node like this: + +```ts +const rect = new Shape.Rect({ + x: 40, + y: 40, + width: 100, + height: 40, + attrs: { + body: { + fill: '#2ECC71', + stroke: '#000', + }, + label: { + text: 'rect', + fill: '#333', + fontSize: 13, + }, + }, +}) +``` + +After the node is rendered to the canvas, the DOM structure looks like this: + +```html + + + + rect + + +``` + +Additionally, we can use CSS selectors to specify node styles, so we don't have to remember predefined selector names. We can simply define styles based on the rendered DOM structure. When using CSS selectors, it's important to note that the specified CSS selector may match multiple elements, in which case the corresponding attribute styles will be applied to multiple elements simultaneously. + +```ts +const rect = new Shape.Rect({ + x: 40, + y: 40, + width: 100, + height: 40, + attrs: { + rect: { + // Use the 'rect' CSS selector instead of the predefined 'body' selector + fill: '#2ECC71', + stroke: '#000', + }, + text: { + // Use the 'text' CSS selector instead of the predefined 'label' selector + text: 'rect', + fill: '#333', + fontSize: 13, + }, + }, +}) +``` + +It's worth mentioning that camelCase format for property names is supported, such as `fontSize`. This avoids the hassle of having to add quotes to property names like `font-size` when used as object keys. + +In addition to standard SVG attributes, we have defined a series of special attributes in X6. For details, please refer to [Special Attributes](/en/docs/api/model/attrs) and [Custom Attributes](/en/docs/api/model/cell/#custom-attributes). Furthermore, we can use CSS to customize styles. Nodes and edges rendered on the canvas have the class names `x6-node` and `x6-edge` respectively. The default style definitions can be [referenced here](https://github.com/antvis/X6/blob/master/packages/x6/src/style/index.less). For example, we can specify the style of the `` element in nodes like this: + +```css +.x6-node rect { + fill: #2ecc71; + stroke: #000; +} +``` + +After creating nodes/edges, we can call the `attr()` method on the instance to modify node attribute styles. In the code below, the path separated by `/` modifies the style. The `label` selector corresponds to the `` element, `text` is the attribute name of that element, and `hello` is the new attribute value. + +```ts +rect.attr('label/text', 'hello') + +// Equivalent to +rect.attr('label', { + text: 'hello', +}) + +// Equivalent to +rect.attr({ + label: { + text: 'hello', + }, +}) +``` + +When the attribute value passed in is `null`, that attribute can be removed. + +```ts +rect.attr('label/text', null) +``` + +### shape + +The shape of the node/edge, similar to the Model in the MVC pattern, determines the structured data of the node/edge. This option is typically used when adding nodes and edges with the `graph.addNode` and `graph.addEdge` methods. + +```ts +const rect = graph.addNode({ + shape: 'rect', + x: 100, + y: 200, + width: 80, + height: 40, + label: 'rect', +}) + +const circle = graph.addNode({ + shape: 'circle', + x: 280, + y: 200, + width: 60, + height: 60, + label: 'circle', +}) + +const edge = graph.addEdge({ + shape: 'edge', + source: rect, + target: circle, +}) +``` + +In X6's internal implementation, we use the shape specified by `shape` to find the corresponding constructor to initialize the node/edge and add it to the canvas. + +The default values for this option are: + +- The default value of `shape` in the `graph.addNode` method is `rect` +- The default value of `shape` in the `graph.addEdge` method is `edge` + +At the same time, we have built-in a series of nodes and edges in X6. + +| 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, renders HTML fragment using `foreignObject`. | + +### view + +Specifies the view used to render the node/edge. The concept of view is consistent with the View in the MVC pattern. Generally, there's no need to set the view field, as X6's built-in view is used by default. + +### zIndex + +The layer level of the node/edge in the canvas, automatically determined by the order of node/edge addition by default. After the node/edge is rendered to the canvas, you can use `cell.getZIndex()` and `cell.setZIndex(z: number)` to get or set the `zIndex` value, or call `cell.toFront()` and `cell.toBack()` to move it to the top or bottom layer. + +### visible + +Whether the node/edge is visible, visible by default. + +### parent + +Parent node ID. + +### children + +Array of child node/edge IDs. + +### tools + +Tools for nodes/edges. Tools can enhance the interaction capabilities of nodes/edges. We provide the following built-in tools for nodes and edges respectively: + +Nodes + +- [button](/en/docs/api/registry/node-tool#button) Renders a button at the specified position, supports customizing button click interactions. +- [button-remove](/en/docs/api/registry/node-tool#button-remove) Renders a delete button at the specified position, deletes the corresponding node when clicked. +- [boundary](/en/docs/api/registry/node-tool#boundary) Renders a rectangle surrounding the node based on the node's bounding box. Note that this tool only renders a rectangle without any interaction. +- [node-editor](/en/docs/api/registry/node-tool#node-editor) Provides text editing functionality on the node. + +Edges + +- [vertices](/en/docs/api/registry/edge-tool#vertices) Path point tool, renders a small dot at the path point position, drag the dot to modify the path point position, double-click the dot to delete the path point, click on the edge to add a path point. +- [segments](/en/docs/api/registry/edge-tool#segments) Segment tool. Renders a toolbar at the center of each edge segment, which can be dragged 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 the edge's 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 the specified position, supports customizing button click interactions. +- [button-remove](/en/docs/api/registry/edge-tool#button-remove) Renders a delete button at the specified position, 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 (arrow by default) at the start or end point of the edge, drag the shape to modify the start or end point of the edge. +- [edge-editor](/en/docs/api/registry/edge-tool#edge-editor) Provides text editing functionality on the edge. + +You can specify a single tool: + +```ts +graph.addNode({ + x: 40, + y: 40, + width: 100, + height: 40, + tools: 'button-remove', // or { name: 'button-remove' } +}) +``` + +Also, you can specify the parameter options for the tool like this: + +```ts +graph.addNode({ + x: 40, + y: 40, + width: 100, + height: 40, + tools: { + name: 'button-remove', + args: { + x: 10, // x coordinate of the button, relative to the top-left corner of the node + y: 10, // y coordinate of the button, relative to the top-left corner of the node + }, + }, +}) +``` + +You can also specify multiple tools at the same time: + +```ts +graph.addNode({ + x: 40, + y: 40, + width: 100, + height: 40, + tools: [ + 'button-remove', + { + name: 'boundary', + args: { + padding: 5, + }, + }, + ], +}) +``` + +### data + +Business data associated with the node/edge. For example, in actual use, we usually store certain business data on the `data` of the node/edge. + +```ts +const rect = new Shape.Rect({ + x: 40, + y: 40, + width: 100, + height: 40, + data: { + bizID: 125, + date: '20200630', + price: 89.0, + }, +}) +``` + +## Methods + +### General + +#### get shape + +Get the shape of the node/edge, returns the name of the shape registered to X6. + +```ts +if (node.shape === 'rect') { + // do something if the node is a 'rect' node. +} +``` + +#### get view + +Get the view of the node/edge, returns the name of the view registered to X6. + +```ts +if (node.view === 'rect') { + // do something if the node is a 'rect' view. +} +``` + +#### isNode() + +```ts +isNode(): boolean +``` + +Checks if the instance is a [Node](/en/docs/api/model/node) instance. Returns `true` if it's a [Node](/en/docs/api/model/node) instance, otherwise returns `false`. All nodes inheriting from [Node](/en/docs/api/model/node) return `true`. + +```ts +if (cell.isNode()) { + // do something if the cell is a node. +} +``` + +#### isEdge() + +```ts +isEdge(): boolean +``` + +Checks if the instance is an [Edge](/en/docs/api/model/edge) instance. Returns `true` if it's an [Edge](/en/docs/api/model/edge) instance, otherwise returns `false`. All edges inheriting from [Edge](/en/docs/api/model/edge) return `true`. + +```ts +if (cell.isEdge()) { + // do something if the cell is an edge. +} +``` + +#### toJSON(...) + +```ts +toJSON(options?: Cell.ToJSONOptions): Object +``` + +Converts the structured data of the node/edge to JSON data for persistent storage (usually we call `graph.toJSON` to export the data of the entire canvas). + +| Option | Type | Default | Required | Description | +|--------------|---------|---------|:--------:|------------------------------------------------| +| options.diff | boolean | `false` | | Whether to return data that differs from the default values (still exports data for the entire canvas). | + +- When `options.diff` is `false`, returns complete data. +- When `options.diff` is `true`, returns differential data (removes default values of properties). + +#### clone(...) + +```ts +clone(options?: Cell.CloneOptions): Cell | Node | Edge | { [id:string]: Node | Edge } +``` + +Clone the node/edge. + +| Option | Type | Default | Required | Description | +|--------------|---------|---------|:--------:|------------------------------------------------------------| +| options.deep | boolean | `false` | | Whether to clone descendant nodes and edges, default is `false` which means only cloning itself. | + +- When `options.deep` is `false`, returns the newly created node/edge by cloning. +- When `options.deep` is `true`, returns an object where the Key is the ID of the cloned node/edge, and the Value is the cloned node/edge. + +#### on(...) + +```ts +on(name: string, handler: Events.Handler, context?: any): this +``` + +Listen to events. + +| Option | Type | Default | Required | Description | +|---------|----------------|--------|:----:|----------------------------------| +| name | string | | ✓ | Event name. | +| handler | Events.Handler | | ✓ | Callback function. | +| context | any | | | Calling context of the callback. | + +#### once(...) + +```ts +once(name: string, handler: Events.Handler, context?: any): this +``` + +Listen to an event once, automatically remove the listener after the event is triggered. + +| Option | Type | Default | Required | Description | +|---------|----------------|---------|:--------:|---------------------------------------| +| name | string | | ✓ | Event name. | +| handler | Events.Handler | | ✓ | Callback function. | +| context | any | | | Calling context of callback function. | + +#### off(...) + +```ts +/** + * Remove all event listeners. + */ +off(): this + +/** + * Remove all event listeners for the specified name. + */ +off(name: string): this + +/** + * Remove the event listener corresponding to the specified handler. + */ +off(name: null, handler: Events.Handler): this + +/** + * Remove the event listener for the specified name and handler. + */ +off(name: string, handler: Events.Handler, context?: any): this +``` + +Remove event listeners. + +#### trigger(...) + +```ts +trigger(name: string, ...args?: any[]): boolean | Promise +``` + +Trigger an event. + +| Option | Type | Default | Required | Description | +|---------|--------|---------|:--------:|-------------------------------------------| +| name | string | | ✓ | Event name. | +| ...args | any[] | | | Parameters passed to callback functions. | + +- When all callback functions are synchronous, it returns `false` if any callback function returns `false`, otherwise returns `true`. +- When there are asynchronous functions among the callbacks, it returns `Promise` based on the same logic as synchronous callbacks. + +#### dispose() + +```ts +dispose(): void +``` + +Destroy and remove the node/edge from its parent. + +### Element Structure markup + +Specifies the SVG/HTML structure used to render nodes/edges, described in [JSON format](#markup), usually set through the [`config`]() method when defining nodes/edges to be shared by all instances. When modifying `markup`, it will trigger the `change:markup` event and canvas redraw. + +#### get markup + +Get `markup`. + +```ts +const markup = cell.markup +``` + +#### set markup + +Set `markup`, and trigger the `change:markup` event and canvas redraw. + +```ts +cell.markup = markup +``` + +#### getMarkup() + +```ts +getMarkup(): Markup +``` + +Get `markup`. + +```ts +const markup = cell.getMarkup() +``` + +#### setMarkup(...) + +```ts +setMarkup(markup: Markup, options?: Cell.SetOptions): this +``` + +Set `markup`. By default, it triggers the `change:markup` event and canvas redraw. When `options.silent` is `true`, it does not trigger the `change:markup` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|-------------------|:--------:|---------|----------------------------------------------------------------------| +| markup | [Markup](#markup) | ✓ | | | +| options.silent | boolean | | `false` | When `true`, do not trigger `change:markup` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeMarkup(...) + +```ts +removeMarkup(options?: Cell.SetOptions): this +``` + +Remove `markup`. By default, it triggers the `change:markup` event and canvas redraw. When `options.silent` is `true`, it does not trigger the `change:markup` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------|----------------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, do not trigger `change:markup` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Element Attributes attrs + +The `attrs` property is a [complex object](#attrs-1). When modifying `attrs`, it will trigger the `change:attrs` event and canvas redraw. + +#### get attrs + +Get attributes. + +```ts +const atts = cell.attrs +``` + +#### set attrs + +Set attributes, and trigger the `change:attrs` event and canvas redraw. + +```ts +cell.atts = attrs +``` + +#### getAttrs() + +```ts +getAttrs(): Attr.CellAttrs +``` + +Get attributes. + +```ts +const atts = cell.getAttrs() +``` + +#### setAttrs(...) + +```ts +setAttrs(attrs: Attr.CellAttrs, options?: Cell.SetAttrOptions): this +``` + +Set attributes. By default, it triggers the `change:attrs` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|-------------------|-------------------------------------|:--------:|---------|--------------------------------------------------------------------------------------------------------------------------| +| attrs | Attr.CellAttrs \| null \| undefined | ✓ | | | +| options.overwrite | boolean | | `false` | When `true`, replace existing attributes; otherwise, perform deep or shallow merge based on the `options.deep` option. | +| options.deep | boolean | | `true` | Effective when `options.overwrite` is `false`. When `true`, perform deep merge; otherwise, perform shallow merge. | +| options.silent | boolean | | `false` | When `true`, do not trigger `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +By default, the specified attributes will be [deeply merged](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with the old attributes: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } + +cell.setAttrs({ + body: { fill: '#f5f5f5' }, + label: { text: 'My Label' }, +}) + +console.log(cell.getAttrs()) +// { +// body: { fill: '#f5f5f5' }, +// label: { fill: '#333333', text: 'My Label' }, +// } +``` + +When `options.deep` is `false`, perform shallow merge: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } + +cell.setAttrs({ label: { text: 'My Label' } }, { deep: false }) + +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { text: 'My Label' }, +// } +``` + +When `options.overwrite` is `true`, directly replace old attributes: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } + +cell.setAttrs({ label: { text: 'My Label' } }, { overwrite: true }) + +console.log(cell.getAttrs()) +// { +// label: { text: 'My Label' }, +// } +``` + +#### replaceAttrs(...) + +```ts +replaceAttrs(attrs: Attr.CellAttrs, options: Cell.SetOptions = {}): this +``` + +Replace original attributes with given attributes, equivalent to calling `setAttrs(attrs, { ...options, overwrite: true })`. + +| Name | Type | Required | Default | Description | +|------------------|-------------------------------------|:--------:|---------|-------------------------------------------------------------------| +| attrs | Attr.CellAttrs \| null \| undefined | ✓ | | | +| options.silent | boolean | | `false` | When `true`, do not trigger `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### updateAttrs(...) + +```ts +updateAttrs(attrs: Attr.CellAttrs, options: Cell.SetOptions = {}): this +``` + +Update attributes using shallow merge, equivalent to calling `setAttrs(attrs, { ...options, deep: false })`. + +| Name | Type | Required | Default | Description | +|------------------|-------------------------------------|:----:|---------|---------------------------------------------------| +| attrs | Attr.CellAttrs \| null \| undefined | ✓ | | | +| options.silent | boolean | | `false` | When `true`, it doesn't trigger the `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeAttrs(...) + +```ts +removeAttrs(options?: Cell.SetOptions): this +``` + +Remove attributes. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|----------------------------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, it won't trigger the `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getAttrByPath(...) + +```ts +getAttrByPath(path?: string | string[]): T +``` + +Get attribute value by attribute path. + +| Name | Type | Required | Default | Description | +|------|--------------------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| path | string \| string[] | | | Attribute path. When `path` is of type `string`, the path is a string separated by `\`. When `path` is of type `string[]`, the path is an array of keys on the attribute object path. | + +The attribute value of a certain node is as follows: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } +``` + +When the path is empty, it returns all attributes: + +```ts +console.log(cell.getAttrByPath()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } +``` + +Get attribute value through string path: + +```ts +console.log(cell.getAttrByPath('body')) +// { fill: '#ffffff' } + +console.log(cell.getAttrByPath('body/fill')) +// '#ffffff' + +console.log(cell.getAttrByPath('unknown')) +// undefined + +console.log(cell.getAttrByPath('body/unknown')) +// undefined +``` + +Get attribute value through a path composed of an array of keys of the attribute object: + +```ts +console.log(cell.getAttrByPath(['body'])) +// { fill: '#ffffff' } + +console.log(cell.getAttrByPath(['body', 'fill'])) +// '#ffffff' + +console.log(cell.getAttrByPath(['unknown'])) +// undefined + +console.log(cell.getAttrByPath(['body', 'unknown'])) +// undefined +``` + +#### setAttrByPath(...) + +```ts +setAttrByPath(path: string | string[], value: Attr.ComplexAttrValue, options?: Cell.SetOptions): this +``` + +Set attribute value by attribute path. + +| Name | Type | Required | Default | Description | +|------------------|-----------------------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| path | string \| string[] | ✓ | | Attribute path. When `path` is of type `string`, the path is a string separated by `\`. When `path` is of type `string[]`, the path is an array of keys on the attribute object path. | +| value | Attr.ComplexAttrValue | ✓ | | New attribute value. | +| options.silent | boolean | | `false` | When `true`, it won't trigger the `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +The initial attribute value of a certain node is as follows: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } +``` + +Set attribute value through string path: + +```ts +cell.setAttrByPath('body', { stroke: '#000000' }) // Replace body attribute value +console.log(cell.getAttrs()) +// { +// body: { stroke: '#000000' }, +// label: { fill: '#333333' }, +// } + +cell.setAttrByPath('body/fill', '#f5f5f5') // Set body.fill attribute value +console.log(cell.getAttrs()) +// { +// body: { stroke: '#000000', fill: '#f5f5f5' }, +// label: { fill: '#333333' }, +// } +``` + +Or set attribute value through a path composed of an array of keys of the attribute object: + +```ts +cell.setAttrByPath(['body'], { stroke: '#000000' }) // Replace body attribute value +console.log(cell.getAttrs()) +// { +// body: { stroke: '#000000' }, +// label: { fill: '#333333' }, +// } + +cell.setAttrByPath(['body', 'fill'], '#f5f5f5') // Set body.fill attribute value +console.log(cell.getAttrs()) +// { +// body: { stroke: '#000000', fill: '#f5f5f5' }, +// label: { fill: '#333333' }, +// } +``` + +#### removeAttrByPath(...) + +```ts +removeAttrByPath(path: string | string[], options?: Cell.SetOption ): this +``` + +Remove attribute value at the specified path. + +| Name | Type | Required | Default | Description | +|------------------|--------------------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| path | string \| string[] | ✓ | | Attribute path. When `path` is of type `string`, the path is a string separated by `\`. When `path` is of type `string[]`, the path is an array of keys on the attribute object path. | +| options.silent | boolean | | `false` | When `true`, it won't trigger the `change:attrs` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +The initial attribute value of a certain node is as follows: + +```ts +console.log(cell.getAttrs()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } +``` + +Remove attribute value through string path: + +```ts +cell.removeAttrByPath('body/fill') +console.log(cell.getAttrs()) +// { +// body: { }, +// label: { fill: '#333333' }, +// } + +cell.removeAttrByPath('body') +console.log(cell.getAttrs()) +// { +// label: { fill: '#333333' }, +// } +``` + +Or remove attribute value through a path composed of an array of keys of the attribute object: + +```ts +cell.removeAttrByPath(['body', 'fill']) +console.log(cell.getAttrs()) +// { +// body: { }, +// label: { fill: '#333333' }, +// } + +cell.removeAttrByPath(['body']) +console.log(cell.getAttrs()) +// { +// label: { fill: '#333333' }, +// } +``` + +#### attr(...) + +```ts +/** + * Get attributes. + */ +attr(): Cell.CellAttrs + +/** + * Get attribute value at the specified path. + */ +attr(path: string | string[]): T + +/** + * Set attribute value at the specified path. + */ +attr(path: string | string[], value: Attr.ComplexAttrValue | null, options?: Cell.SetOptions): this + +/** + * Set attribute values, the passed attributes are deeply merged with the old attributes. + */ +attr(attrs: Attr.CellAttrs, options?: Cell.SetOptions): this +``` + +This method is an integration of [`getAttrByPath`](#getattrbypath), [`setAttrByPath`](#setattrbypath), and [`setAttrs`](#setattrs) methods, providing the above four function signatures, making it a very practical method. + +Get all attribute values: + +```ts +console.log(cell.attr()) +// { +// body: { fill: '#ffffff' }, +// label: { fill: '#333333' }, +// } +``` + +Get attribute value at the specified path: + +```ts +console.log(cell.attr('body/fill')) +// '#ffffff' +``` + +Set attribute value at the specified path: + +```ts +cell.attr('body/fill', '#f5f5f5') +console.log(cell.attr()) +// { +// body: { fill: '#f5f5f5' }, +// label: { fill: '#333333' }, +// } +``` + +Set attribute values through the attribute object, and perform a [deep merge](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with the existing attribute object. + +```ts +cell.attr({ + body: { stroke: '#000000' }, + label: { fill: 'blue', text: 'my label' }, +}) +console.log(cell.attr()) +// { +// body: { fill: '#f5f5f5', stroke: '#000000' }, +// label: { fill: 'blue', text: 'my label' }, +// } +``` + +### Hierarchy zIndex + +`zIndex` is the layer level of a node/edge in the canvas, which is automatically determined based on the order of node/edge addition by default. When modifying `zIndex`, it will trigger the `change:zIndex` event and canvas redraw. + +#### get zIndex + +Get the `zIndex`. + +```ts +const z = cell.zIndex +``` + +#### set zIndex + +Set the `zIndex`, triggering the `change:zIndex` event and canvas redraw. + +```ts +cell.zIndex = 2 +``` + +#### getZIndex() + +```ts +getZIndex(): number +``` + +Get the `zIndex`. + +```ts +const z = cell.getZIndex() +``` + +#### setZIndex(...) + +```ts +setZIndex(zIndex: number, options?: Cell.SetOptions): this +``` + +Set the `zIndex`. By default, it triggers the `change:zIndex` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger the `change:zIndex` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|----------------------------------------------------------------| +| zIndex | number | ✓ | | | +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:zIndex` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeZIndex(...) + +```ts +removeZIndex(options?: Cell.SetOptions): this +``` + +Remove the `zIndex`. By default, it triggers the `change:zIndex` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger the `change:zIndex` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------|----------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:zIndex` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### toFront(...) + +```ts +toFront(options?: Cell.ToFrontOptions): this +``` + +Move the node/edge to the topmost layer. + +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------|----------------------------------------------------------------| +| options.deep | boolean | | `false` | When `true`, also updates the hierarchy of all child nodes/edges. | +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:zIndex` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### toBack(...) + +```ts +toBack(options?: Cell.ToBackOptions): this +``` + +Move the node/edge to the bottommost layer. + +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------|----------------------------------------------------------------| +| options.deep | boolean | | `false` | When `true`, also updates the hierarchy of all child nodes/edges. | +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:zIndex` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +By default, updating `zIndex` triggers the `change:zIndex` event and canvas redraw: + +```ts +cell.toBack() +``` + +When `options.deep` is `true`, it also updates the hierarchy of all child nodes/edges: + +```ts +cell.toBack({ deep: true }) +``` + +### Visibility Visible + +#### get visible + +Returns whether the node/edge is visible. + +```ts +if (cell.visible) { + // do something +} +``` + +#### set visible + +Sets whether the node/edge is visible and triggers the `change:visible` event and canvas redraw. + +#### show(...) + +```ts +show(options?: Cell.SetOptions): this +``` + +Show the node/edge. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-----------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:visible` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### hide(...) + +```ts +hide(options?: Cell.SetOptions): this +``` + +Hide the node/edge. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-----------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:visible` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +:::info{title="Note"} +X6 2.x implements element hiding by adding `display: none` to the node label. +::: + +#### isVisible() + +```ts +isVisible(): boolean +``` + +Returns whether the node/edge is visible. + +#### setVisible(...) + +```ts +setVisible(visible: boolean, options?: Cell.SetOptions): this +``` + +Set the visibility of the node/edge. By default, it triggers the `change:visible` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger the `change:visible` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-----------------------------------------------------------------| +| visible | boolean | ✓ | | | +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:visible` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### toggleVisible(...) + +```ts +toggleVisible(options?: Cell.SetOptions): this +``` + +Toggle the visibility of the node/edge. By default, it triggers the `change:visible` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger the `change:visible` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-----------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:visible` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Business Data + +Business data associated with nodes/edges. For example, in practical use, we often store certain business data on the data property of nodes/edges. + +```ts +const rect = new Shape.Rect({ + x: 40, + y: 40, + width: 100, + height: 40, + data: { + bizID: 125, + date: '20200630', + price: 89.0, + }, +}) +``` + +#### get data + +Get the associated data. + +#### set data + +Set the associated data and trigger the `change:data` event and canvas redraw. + +#### getData() + +```ts +getData(): any +``` + +Get the associated data. + +#### setData(...) + +```ts +setData(data: any, options?: Cell.SetDataOptions): this +``` + +Set the associated business data. By default, it triggers the `change:data` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger the `change:data` event and canvas redraw. + +| Name | Type | Required | Default | Description | +|-------------------|---------|:--------:|---------|-----------------------------------------------------------------------------------------------| +| data | any | ✓ | | | +| options.overwrite | boolean | | `false` | When `true`, replaces existing values; otherwise, performs deep or shallow merge based on `options.deep`. | +| options.deep | boolean | | `true` | Effective when `options.overwrite` is `false`. When `true`, performs deep merge; otherwise, shallow merge. | +| options.silent | boolean | | `false` | When `true`, doesn't trigger `change:data` event and redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +By default, it performs a [deep merge](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with the original data and triggers the `change:data` event and canvas redraw: + +```ts +cell.setData(data) +``` + +When `options.overwrite` is `true`, it replaces the old data: + +```ts +cell.setData(data, { overwrite: true }) +``` + +When `options.deep` is `false`, it performs a shallow merge with the original data: + +```ts +cell.setData(data, { deep: false }) +``` + +:::info{title="Note"} +The `setData` method uses shallow comparison to determine if the data has been updated, thus deciding whether to trigger node redraw. +::: + +```ts +const obj = { name: 'x6', star: true } +node.setData(obj) // This will trigger a node redraw + +obj.star = false +node.setData(obj) // Note: At this point, no deep comparison is performed. The object is considered unchanged, so it won't trigger a node redraw + +node.setData({ + ...obj, + star: false, +}) // This will trigger a node redraw +``` + +#### replaceData(...) + +```ts +replaceData(data: any, options: Cell.SetOptions = {}): this +``` + +Replace the original data with the specified data, equivalent to calling `setData(data, { ...options, overwrite: true })`. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-------------------------------------------------------------------------------| +| data | any | ✓ | | | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:data` event and canvas redrawing. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### updateData(...) + +```ts +updateData(data: any, options: Cell.SetOptions = {}): this +``` + +Update data using shallow merge, equivalent to calling `setData(data, { ...options, deep: false })`. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-------------------------------------------------------------------------------| +| data | any | ✓ | | | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:data` event and canvas redrawing. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeData(...) + +```ts +removeData(options: Cell.SetOptions): this +``` + +Remove data. By default, it triggers the `change:data` event and canvas redrawing. When `options.silent` is `true`, it does not trigger the `change:data` event and canvas redrawing. + +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------|-------------------------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:data` event and canvas redrawing. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Parent/Children Relationship + +#### get parent + +Get the parent node. + +#### getParent() + +```ts +getParent(): Cell | null +``` + +Get the parent node. Returns the parent node if it exists, otherwise returns `null`. + +#### setParent(...) + +```ts +setParent(parent: Cell | null, options?: Cell.SetOptions): this +``` + +Set the parent node. + +| Name | Type | Required | Default | Description | +|------------------|--------------|:--------:|---------|------------------------------------------------------------------------------------| +| parent | Cell \| null | ✓ | | Parent node or `null`. When `parent` is `null`, it removes the parent node. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:parent` event and canvas redrawing. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getParentId() + +```ts +getParentId(): string | undefined +``` + +Get the ID of the parent node. Returns the parent node's ID if it exists, otherwise returns `undefined`. + +#### hasParent() + +```ts +hasParent(): boolean +``` + +Check if the node/edge has a parent node. + +#### get children + +Get all child nodes/edges. + +#### getChildren() + +```ts +getChildren(): Cell[] | null +``` + +Get all child nodes/edges. + +#### setChildren() + +```ts +setChildren(children: Cell[] | null, options?: Cell.SetOptions) +``` + +Set child nodes/edges. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|----------------------------------------------------------------------------------------| +| children | Cell[] \| null | ✓ | | Array of child nodes/edges or `null`. When `children` is `null`, it clears all children. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:children` event and canvas redrawing. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### isParentOf(...) + +```ts +isParentOf(child: Cell | null): boolean +``` + +Returns whether the current node is the parent of the specified Cell. + +| Name | Type | Required | Default | Description | +|-------|--------------|:--------:|---------|-------------| +| child | Cell \| null | ✓ | | | + +#### isChildOf(...) + +```ts +isChildOf(parent: Cell | null): boolean +``` + +Returns whether the current node/edge is a child of the specified node. + +| Name | Type | Required | Default | Description | +|--------|--------------|:--------:|---------|-------------| +| parent | Cell \| null | ✓ | | | + +#### eachChild(...) + +```ts +eachChild(iterator: (child: Cell, index: number, children: Cell[]) => void, context?: any): this +``` + +Iterate through child nodes. + +| Name | Type | Required | Default | Description | +|----------|--------------------------------------------------------|:--------:|---------|----------------------------------------| +| iterator | (child: Cell, index: number, children: Cell[]) => void | ✓ | | Iterator function. | +| context | any | | | Execution context of iterator function. | + +#### filterChild(...) + +```ts +filterChild(iterator: (child: Cell, index: number, children: Cell[]) => boolean, context?: any): Cell[] +``` + +Filter child nodes. + +| Name | Type | Required | Default | Description | +|----------|-----------------------------------------------------------|:--------:|---------|----------------------------------------| +| iterator | (child: Cell, index: number, children: Cell[]) => boolean | ✓ | | Filter function. | +| context | any | | | Execution context of filter function. | + +#### getChildCount() + +```ts +getChildCount(): number +``` + +Get the number of child nodes/edges. + +#### getChildIndex(...) + +```ts +getChildIndex(child: Cell): number +``` + +Get the index of a child node/edge. + +| Name | Type | Required | Default | Description | +|-------|------|:--------:|---------|-------------| +| child | Cell | ✓ | | | + +#### getChildAt(...) + +```ts +getChildAt(index: number): Cell | null +``` + +Get the child node/edge at the specified index. + +| Name | Type | Required | Default | Description | +|-------|--------|:--------:|---------|-------------| +| index | number | ✓ | | Index position. | + +#### getAncestors(...) + +```ts +getAncestors(options?: { deep?: boolean }): Cell[] +``` + +Get all ancestor nodes. + +| Name | Type | Required | Default | Description | +|--------------|---------|:--------:|---------|-----------------------------------------------------------------------------------------------| +| options.deep | boolean | | `true` | By default, recursively gets all ancestor nodes. Set to `false` to only return the parent node. | + +#### getDescendants(...) + +```ts +getDescendants(options?: Cell.GetDescendantsOptions): Cell[] +``` + +Get all descendant nodes. + +| Name | Type | Required | Default | Description | +|----------------------|---------|:--------:|---------|-------------------------------------------------------------------------------------------------| +| options.deep | boolean | | `true` | By default, recursively gets all descendant nodes. Set to `false` to only return child nodes/edges. | +| options.breadthFirst | boolean | | `false` | By default, uses depth-first algorithm. Set to `true` to use breadth-first search algorithm. | + +Returns an array of descendant nodes/edges. + +#### isDescendantOf(...) + +```ts +isDescendantOf(ancestor: Cell | null, options?: { deep?: boolean }): boolean +``` + +Returns whether the current node/edge is a descendant of the specified node. + +| Name | Type | Required | Default | Description | +|--------------|--------------|:--------:|---------|------------------------------------------------------------------------------------------------------------| +| ancestor | Cell \| null | ✓ | | Specified node. | +| options.deep | boolean | | `true` | By default, recursively checks all descendants of the specified node. Set to `false` to only check children. | + +#### isAncestorOf(...) + +```ts +isAncestorOf(descendant: Cell | null, options?: { deep?: boolean }): boolean +``` + +Returns whether the current node is an ancestor of the specified node/edge. + +| Name | Type | Required | Default | Description | +|--------------|--------------|:--------:|---------|------------------------------------------------------------------------------------------------------------| +| descendant | Cell \| null | ✓ | | Specified node/edge. | +| options.deep | boolean | | `true` | By default, recursively checks all descendants of the specified node. Set to `false` to only check children. | + +#### getCommonAncestor(...) + +```ts +getCommonAncestor(...cells: (Cell | null | undefined)[]): Cell | null +``` + +Get the common ancestor nodes of the given nodes/edges. + +| Name | Type | Required | Default | Description | +|----------|-------------------------------|:--------:|---------|---------------------| +| ...cells | (Cell \| null \| undefined)[] | ✓ | | Specified nodes/edges. | + +#### addChild(...) + +```ts +addChild(child: Cell, options?: Cell.SetOptions): this +``` + +Adds the specified node/edge to the end of the current node's children. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|----------------------------------------------------------------------------| +| child | Cell | ✓ | | The specified node/edge. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:children` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeChild(...) + +```ts +removeChild(child: Cell, options?: Cell.RemoveOptions): Cell | null +``` + +Removes the specified child node/edge. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-----------------------------------------------------------------------------------------------------------| +| child | Cell | ✓ | | The specified node/edge. | +| options.deep | boolean | | `true` | By default, recursively removes all child nodes/edges. Set to `false` to only remove the current node/edge. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:children` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### remove(...) + +```ts +remove(options?: Cell.RemoveOptions): this +``` + +First removes the current node/edge from its parent node, then removes it from the canvas. + +### Node and Edge Properties + +The basic options introduced above such as `markup`, `attrs`, `zIndex`, `data`, as well as node options like `size`, `position`, `angle`, `ports`, and edge options like `source`, `target`, `labels`, along with any additional key-value pairs provided when creating nodes/edges, are all called properties. + +```ts +const rect = new Shape.Rect({ + x: 30, + y: 30, + width: 100, + height: 40, + attrs: {...}, + data: {...}, + zIndex: 10, + sale: {...}, + product: { + id: '1234', + name: 'apple', + price: 3.99, + }, +}) +``` + +For example, in the code above, `attrs`, `data`, `zIndex` are standard properties, while `x` and `y` are a pair of [custom options](#custom-options) that are converted to the `position` property during node initialization. Similarly, `width` and `height` are another pair of [custom options](#custom-options) converted to the `size` property during node initialization. The remaining `sale` and `product` objects are non-standard properties. + +We've introduced some standard properties and methods to operate (get/set) these standard properties above. Now let's introduce a few more general methods that apply to both standard and non-standard properties. + +#### getProp(...) + +Gets the value of the specified property. + +```ts +getProp(key: string, defaultValue?: T): T +``` + +| Name | Type | Required | Default | Description | +|--------------|--------|:--------:|---------|------------------------------------------------------------------| +| key | string | ✓ | | Property name. | +| defaultValue | T | | - | Default value, returned when the specified property doesn't exist. | + +```ts +// Get standard properties +const zIndex = rect.getProp('zIndex') +const position = rect.getProp<{ x: number; y: number }>('position') + +// Get non-standard properties +const product = rect.getProp('product') +``` + +#### setProp(...) + +Sets the specified property. By default, it triggers the corresponding `change:xxx` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger. + +```ts +// Set a specific property +setProp(key: string, value: any, options?: Cell.SetOptions): this +// Batch set properties, deeply merging the provided properties with the original properties. Note that using this method will trigger propHooks calls +setProp(props: Partial, options?: Cell.SetOptions): this +``` + +| Name | Type | Required | Default | Description | +|------------------|-----------------------|:--------:|---------|---------------------------------------------------------------------------------------------------------------| +| key | string | ✓ | | Property name. | +| value | any | ✓ | | Property value. | +| props | `Partial` | ✓ | | Property key-value pairs, which will be [deeply merged](https://lodash.com/docs/4.17.15#merge) with existing properties. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:markup` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +// Set a single property: +rect.setProp('size', { width: 100, height: 30 }) +rect.setProp('zIndex', 10) + +// Set multiple properties simultaneously +rect.setProp({ + size: { + width: 100, + height: 30, + }, + zIndex: 10, +}) +``` + +#### removeProp(...) + +Removes the property at the specified path. By default, it triggers the corresponding `change:xxx` event and canvas redraw. When `options.silent` is `true`, it doesn't trigger. + +```ts +removeProp(path: string | string[], options?: Cell.SetOptions): this +``` + +| Name | Type | Required | Default | Description | +|------------------|--------------------|:--------:|---------|----------------------------------------------------------------------------| +| path | string \| string[] | ✓ | | Property path. | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:markup` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +rect.removeProp('zIndex') +rect.removeProp('product/id') +``` + +#### prop(...) + +This method integrates the above methods and provides four function signatures, making it a very practical method. + +```ts +prop(): Properties // Get all properties. +prop(path: string | string[]): T // Get the property value at the specified path. +prop(path: string | string[], value: any, options?: Cell.SetOptions): this // Set the property value at the specified path, deeply merging with existing properties on the path. +prop(props: Partial, options?: Cell.SetOptions): this // Set properties, deeply merging with existing properties. +``` + +```ts +// Get properties: +rect.prop() +rect.prop('zIndex') +rect.prop('product/price') + +// Set properties: +rect.prop('zIndex', 10) +rect.prop('product/price', 5.99) +rect.prop({ + product: { + id: '234', + name: 'banana', + price: 3.99, + }, +}) +``` + +#### hasChanged(...) + +```ts +hasChanged(key: string | undefined | null): boolean +``` + +Returns whether the specified property or all properties have changed. + +| Name | Type | Required | Default | Description | +|------|-----------------------------|:--------:|---------|----------------------------------------------------------------| +| key | string \| undefined \| null | | | Property name. When omitted, it checks all properties. | + +#### previous(...) + +```ts +previous(name: string): T | undefined +``` + +After a specified property has changed, get the property value before the change. + +| Name | Type | Required | Default | Description | +|------|--------|:--------:|---------|----------------| +| key | string | ✓ | | Property name. | + +### Tools + +#### addTools(...) + +```ts +addTools( + items: Cell.ToolItem | Cell.ToolItem[], + options?: Cell.AddToolOptions, +): this +addTools( + items: Cell.ToolItem | Cell.ToolItem[], + name: string, + options?: Cell.AddToolOptions, +): this +``` + +Add tools. + +| Name | Type | Required | Default | Description | +|------------------|----------------------------------|:--------:|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| items | Cell.ToolItem \| Cell.ToolItem[] | | | Tools defined in [NodeTool](/en/docs/api/registry/node-tool#presets) or [EdgeTool](/en/docs/api/registry/edge-tool#presets). | +| name | string | | `null` | Define an alias for this group of tools, which can be used as a parameter for `hasTools(name)` | +| options.reset | boolean | | `false` | Whether to clear the tool set. By default, tools are appended to the tool set. | +| options.local | boolean | | `false` | Whether the tool is rendered in the node/edge container. By default, it's `false`, and all tools are rendered under `x6-graph-svg-decorator`. Only takes effect when `options.reset` is `true` | +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:tools` event and tool redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getTools() + +```ts +getTools(): Cell.Tools | null +``` + +Get the tool set. + +#### removeTools(...) + +```ts +removeTools(options?: Cell.SetOptions): this +``` + +Remove all tools. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-------------------------------------------------------------------------| +| options.silent | boolean | | `false` | When `true`, does not trigger the `change:tools` event and tool redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### hasTool(...) + +```ts +hasTool(name: string): boolean +``` + +Check if a tool with the specified name exists. + +#### removeTool(...) + +```ts +removeTool(name: string, options?: Cell.SetOptions): this +removeTool(index: number, options?: Cell.SetOptions): this +``` + +Removes a tool with the specified name. + +| Name | Type | Required | Default | Description | +|------------------|------------------|:--------:|---------|----------------------------------------------------------------------------------| +| nameOrIndex | string \| number | ✓ | | The name or index of the tool. | +| options.silent | boolean | | `false` | If `true`, doesn't trigger the `change:tools` event and tool redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Animation Transition + +#### transition(...) + +```ts +transition( + path: string | string[], + target: Animation.TargetValue, + options: Animation.StartOptions = {}, + delim: string = '/', +): () => void +``` + +Smoothly transitions the property value at the specified `path` to the target value specified by `target`, and returns a `stop` method. When called, this method immediately stops the animation. + +| Name | Type | Required | Default | 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` | Animation duration, in milliseconds. | +| options.timing | Timing.Names \| (t: number) => number | | | Timing function. | +| options.interp | \(from: T, to: T) => (time: number) => T | | | Interpolation function. | +| options.start | (args: Animation.CallbackArgs) => void | | | Callback function when the animation starts. | +| options.progress | (args: Animation.ProgressArgs) => void | | | Callback function during the animation execution. | +| options.complete | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes. | +| options.stop | (args: Animation.CallbackArgs) => void | | | Callback function when the animation is stopped. | +| options.finish | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes or is stopped. | +| options.jumpedToEnd | boolean | | `false` | Whether to immediately complete the animation when stopped manually. | +| delim | string | | `/` | String path delimiter. | + +We provide some timing functions in the `Timing` namespace. You can use built-in timing function names or provide a function with the signature `(t: number) => number`. The built-in timing functions are as follows: + +- linear +- quad +- cubic +- inout +- exponential +- bounce +- easeInSine +- easeOutSine +- easeInOutSine +- easeInQuad +- easeOutQuad +- easeInOutQuad +- easeInCubic +- easeOutCubic +- easeInOutCubic +- easeInQuart +- easeOutQuart +- easeInOutQuart +- easeInQuint +- easeOutQuint +- easeInOutQuint +- easeInExpo +- easeOutExpo +- easeInOutExpo +- easeInCirc +- easeOutCirc +- easeInOutCirc +- easeInBack +- easeOutBack +- easeInOutBack +- easeInElastic +- easeOutElastic +- easeInOutElastic +- easeInBounce +- easeOutBounce +- easeInOutBounce + +We have built-in some interpolation functions in the `Interp` namespace. Usually, we can automatically determine which interpolation function to use based on the property value on the path. The built-in interpolation functions are as follows: + +- number - Number interpolation function. +- object - `{ [key: string]: number }` object interpolation function. +- unit - Number + unit string interpolation function, such as `10px`. Supported units are: `px, em, cm, mm, in, pt, pc, %`. +- color - Hexadecimal color interpolation function. + +```ts +import { Timing, Interp } from '@antv/x6' + +rect.transition('attrs/label/font-size', '1em', { + interp: Interp.unit, + timing: 'bounce', // Timing.bounce +}) +``` + +#### stopTransition(...) + +```ts +stopTransition( + path: string | string[], + options?: Animation.StopOptions, + delim: string = '/', +): this +``` + +Stops the animation corresponding to the specified `path`. + +| Name | Type | Required | Default | Description | +|---------------------|----------------------------------------|:--------:|---------|----------------------------------------------------------------| +| path | string \| string[] | ✓ | | Path. | +| options.jumpedToEnd | boolean | | `false` | Whether to immediately complete the animation when stopped manually. | +| options.complete | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes. | +| options.stop | (args: Animation.CallbackArgs) => void | | | Callback function when the animation is stopped. | +| options.finish | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes or is stopped. | +| delim | string | | `/` | String path delimiter. | + +```ts +rect.stopTransition('attrs/label/font-size') +``` + +#### getTransitions() + +```ts +getTransitions(): string[] +``` + +Gets all active animations and returns the paths of active animations. + +```ts +// Stop all animations +rect.getTransitions().forEach((path) => rect.stopTransition(path)) +``` + +## config(...) + +```ts +config(presets: C): void +``` + +Sets the default values for node/edge options. + +| Name | Type | Required | Default | Description | +|-------------------|------------------------|:--------:|---------|-------------------------------------------------------------------------------------------------------| +| options.propHooks | Cell.PropHooks\ | | | Custom options. | +| options.attrHooks | Attr.Definitions | | | Custom attribute key-value pairs. Key is the name of the custom attribute, Value is the custom attribute object (including methods for attribute checking, applying attributes, etc.). | +| options...others | object | | | Other options, properties of nodes/edges. | + +### Default Option Values + +This method is very friendly for custom nodes/edges, making it convenient for us to set some preset options for our nodes/edges. For example, when defining a rectangle node, we specified the default Markup, default size, and default style for it. + +```ts +Shape.Rect.config({ + width: 80, + height: 40, + markup: ..., + attrs: ..., +}) +``` + +Our code for creating rectangles can be very simple: + +```ts +const rect = graph.addNode({ + x: 100, + y: 100, + attrs: { + label: { + text: 'rect', + }, + }, +}) +``` + +Each call to `config(presets)` performs a [deep merge](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with the current preset values. For example, the following code modifies the default border color of the rectangle to red and the default text color to blue, respectively. The final effect is the combination of both: + +```ts +// Only modify the default border color +Shape.Rect.config({ + attrs: { + body: { + stroke: 'red', + }, + }, +}) + +// Only modify the default text color +Shape.Rect.config({ + attrs: { + label: { + fill: 'blue', + // Override the 'red' defined above + stroke: '#000', + }, + }, +}) +``` + +### Custom Options + +When creating a rectangle, we can use `label` to set the label text of the rectangle: + +```ts +const rect = graph.addNode({ + x: 100, + y: 100, + label: 'rect', +}) +``` + +We didn't define the `label` option for the rectangle, so how is this `label` applied to `attrs/label/text`? This is where the `propHooks` hook comes in. We can define `propHooks` hooks to consume these non-standard options. + +Let's look at the implementation details of the `label` option hook: + +```ts +Shape.Rect.config({ + // Apply 'label' to the 'attrs/text/text' property through the hook + propHooks(metadata) { + const { label, ...others } = metadata + if (label) { + ObjectExt.setByPath(others, 'attrs/text/text', label) + } + return others + }, +}) +``` + +Through the `propHooks` hook, we can easily extend some custom options. For example, we can define certain styles as options for the node, which not only reduces nesting but also makes the code for creating nodes more semantic. + +Look at the following code, which defines custom `rx` and `ry` options for rectangles: + +```ts +Shape.Rect.config({ + propHooks: { + rx(metadata) { + const { rx, ...others } = metadata + if (rx != null) { + ObjectExt.setByPath(others, 'attrs/body/rx', rx) + } + return others + }, + ry(metadata) { + const { ry, ...others } = metadata + if (ry != null) { + ObjectExt.setByPath(others, 'attrs/body/ry', ry) + } + return others + }, + }, +}) +``` + +This way, we can easily add rounded rectangles: + +```ts +const rect = graph.addNode({ + x: 100, + y: 100, + rx: 5, + ry: 10, + label: 'rect', +}) +``` + +### Custom Attributes + +Custom attributes refer to non-standard SVG/HTML attributes, such as built-in system attributes like `refWidth`, `refHeight`, `sourceMarker`, `targetMarker`, etc. These attributes are globally shared, and we can use the `attrHooks` hook to define **exclusive** custom attributes for nodes/edges. + +For example: + +```ts +import { Shape, Color } from '@antv/x6' + +Shape.Rect.config({ + attrHooks: { + fill: { + set(val) { + return Color.invert(val) // Automatically invert the fill color + }, + }, + theme: { + set(val) { + // Set both fill color and border color simultaneously + return { + fill: val, + stroke: Color.invert(val), + } + }, + }, + }, +}) +``` + +We can use the `fill` and `theme` attributes defined above like this: + +```ts +const rect = graph.addNode({ + x: 100, + y: 100, + rx: 5, + ry: 10, + label: 'rect', + attrs: { + body: { + theme: '#f5f5f5', + }, + label: { + fill: '#fff', + }, + }, +}) +``` diff --git a/sites/x6-sites/docs/api/model/edge.en.md b/sites/x6-sites/docs/api/model/edge.en.md new file mode 100644 index 00000000000..a1406e78663 --- /dev/null +++ b/sites/x6-sites/docs/api/model/edge.en.md @@ -0,0 +1,742 @@ +--- +title: Edge +order: 2 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/model +--- + +Edge is the base class for edges, inheriting from [Cell](/en/docs/api/model/cell), and defines the common properties and methods for edges. + +## Attributes + +In addition to inheriting from Cell [attributes](/en/docs/api/model/cell#properties), the following attributes are also supported. + +| Option | Type | Default Value | Required | Description | +|-------------|--------------------------|---------------|:--------:|--------------------------------------------------| +| source | TerminalData | | | Starting point or source node, connection point information. | +| target | TerminalData | | | End point or target node, connection point information. | +| vertices | Point.PointLike[] | | | Path points. | +| router | RouterData | | | Routing. | +| connector | ConnectorData | | | Connector. | +| labels | Label[] \| string[] | | | Labels. | +| defaultLabel| Label | | | Default label. | + +### Source and Target + +Setting the starting/ending point or source/target node of an edge can be categorized into the following situations: + +- **Connecting to a point on the canvas** + ```ts + const edge = graph.addEdge({ + source: { x: 40, y: 40 }, + target: { x: 180, y: 80 }, + }) + ``` +- **Connecting to nodes/edges** + ```ts + const edge = graph.addEdge({ + source: { cell: 'source-cell-id' }, + target: { cell: 'target-cell-id' }, + }) + ``` +- **Connecting to connection points on nodes** + ```ts + const edge = graph.addEdge({ + source: { cell: 'source-cell-id', port: 'port-id' }, + target: { cell: 'target-cell-id', port: 'port-id' }, + }) + ``` +- **Connecting to specific elements on nodes** + ```ts + const edge = graph.addEdge({ + source: { cell: 'source-cell-id', selector: 'some-selector' }, + target: { cell: 'target-cell-id', selector: 'some-selector' }, + }) + ``` + +Additionally, the edge's [anchor points](/en/docs/api/registry/node-anchor) and [connection points](/en/docs/api/registry/connection-point) options together determine the starting and ending points of the edge. + +- Starting Point: A reference line is drawn 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. Then, based on the intersection calculation method specified by the connectionPoint, the intersection of the reference line and the shape is calculated, which becomes the starting point of the edge. +- Ending Point: A reference line is drawn 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. Then, based on the intersection calculation method specified by the connectionPoint, the intersection of the reference line and the shape is calculated, which becomes the ending point of the edge. + +When creating an edge, you can specify anchor points and connection points for `source` and `target` separately. + +- **Specifying Anchor Points** + ```ts + const edge = graph.addEdge({ + source: { + cell: 'source-id', + anchor: { + name: 'midSide', + args: { + dx: 10, + }, + }, + }, + target: { + cell: 'target-id', + anchor: 'orth', // Can be simplified when there are no parameters + }, + }) + ``` +- **Specifying Connection Points** + ```ts + const edge = graph.addEdge({ + source: { + cell: 'source-id', + connectionPoint: { + name: 'boundary', + args: { + sticky: true, + }, + }, + }, + target: { + cell: 'target-id', + connectionPoint: 'boundary', // Can be simplified when there are no parameters + }, + }) + ``` + +### Vertices + +The path points `vertices` is an array of points. The edge starts from the starting point, passes through the path points in order, and finally reaches the end point. + +```ts +const edge = graph.addEdge({ + source, + target, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], +}) +``` + +### Router + +The router `router` will further process the `vertices`, adding additional points if necessary, and return the processed points (excluding the starting and ending points of the edge). For example, after processing with the [`orth`](/en/docs/api/registry/router#orth) router, each link segment of the edge is either horizontal or vertical. + +We provide the following default routers. + +| Router Name | Description | +|-------------|--------------------------------------------------| +| normal | [Default router](/en/docs/api/registry/router#normal), returns the path points as is. | +| orth | [Orthogonal router](/en/docs/api/registry/router#orth), consists of horizontal or vertical orthogonal segments. | +| oneSide | [Restricted orthogonal router](/en/docs/api/registry/router#oneside), consists of three restricted horizontal or vertical orthogonal segments. | +| manhattan | [Smart orthogonal router](/en/docs/api/registry/router#manhattan), consists of horizontal or vertical orthogonal segments and automatically avoids other nodes (obstacles) along the path. | +| metro | [Smart subway line router](/en/docs/api/registry/router#metro), consists of horizontal or vertical orthogonal segments and diagonal segments, similar to a subway map, and automatically avoids other nodes (obstacles) along the path. | +| er | [Entity-relationship router](/en/docs/api/registry/router#er), consists of `Z` shaped diagonal segments. | + +You can specify the router name `name` and router parameters `args` like this: + +```ts +const edge = graph.addEdge({ + source, + target, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], + router: { + name: 'orth', + args: { + padding: 10, + }, + }, +}) +``` + +When there are no router parameters `args`, it can also be simplified to: + +```ts +const edge = graph.addEdge({ + source, + target, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], + router: 'orth', +}) +``` + +In addition to the built-in routers mentioned above, we can also create custom routers and register them for use. For more details, please refer to the [Custom Router](/en/docs/api/registry/router#registry) tutorial. + +### Connector + +The connector processes the starting point, the points returned by the router, and the ending point into the `d` attribute of the `` element, which determines the style of the edge rendered on the canvas. + +We provide the following default connectors. + +| Connector Name | Description | +|----------------|--------------------------------------------------| +| normal | [Simple connector](/en/docs/api/registry/connector#normal), connects the starting point, routing points, and ending point with straight lines. | +| smooth | [Smooth connector](/en/docs/api/registry/connector#smooth), connects the starting point, routing points, and ending point with cubic Bezier curves. | +| rounded | [Rounded connector](/en/docs/api/registry/connector#rounded), connects the starting point, routing points, and ending point with straight lines and uses arcs to link at the segment connections (rounded corners). | +| jumpover | [Jump line connector](/en/docs/api/registry/connector#jumpover), connects the starting point, routing points, and ending point with straight lines and uses jump line symbols at the intersections of edges. | + +You can specify the connector name `name` and connector parameters `args` like this: + +```ts +const edge = graph.addEdge({ + source, + target, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], + connector: { + name: 'rounded', + args: { + radius: 20, + }, + }, +}) +``` + +When there are no connector parameters `args`, it can also be simplified to: + +```ts +const edge = graph.addEdge({ + source, + target, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], + connector: 'rounded', +}) +``` + +In addition to the built-in connectors mentioned above, we can also create custom connectors and register them for use. For more details, please refer to the [Custom Connector](/en/docs/api/registry/connector#registry) tutorial. + +### Labels and Default Label + +Due to the flexibility of label configuration, we provide a separate tutorial to explain how to use labels. For details, please refer to the [Using Labels](/en/docs/api/model/labels) tutorial. + +## Methods + +### General + +#### isEdge() + +```ts +isEdge(): true +``` + +Determines if it is an edge; this method always returns `true`. + +#### getBBox() + +```ts +getBBox(): Rectangle +``` + +Returns the bounding box of the edge. + +#### getPolyline() + +```ts +getPolyline(): Polyline +``` + +Returns the line segments composed of endpoints and path points. + +#### hasLoop(...) + +```ts +hasLoop(options: { deep?: boolean }): boolean +``` + +Checks if it contains a loop link. + +| Name | Type | Required | Default Value | Description | +|--------------|---------|:--------:|---------------|---------------------------| +| options.deep | boolean | | `false` | Whether to perform nested checks. | + +- When `options.deep` is `false`, it indicates that it is a loop connection only if the starting node and the ending node are the same node. +- When `options.deep` is `true`, it indicates that it is a loop connection if the starting node and the ending node are the same node or if there is a parent-child nesting relationship between the starting node and the ending node. + +### Link Terminal + +#### getSource() + +```ts +getSource(): Edge.TerminalData +``` + +Gets the starting node/start point information of the edge. + +#### getSourceCell() + +```ts +getSourceCell(): Cell | null +``` + +Gets the starting node/edge of the edge; returns `null` if not connected to a node/edge. + +#### getSourceNode() + +```ts +getSourceNode(): Node | null +``` + +Gets the starting node of the edge; returns `null` if not connected to a node. + +#### getSourceCellId() + +```ts +getSourceCellId(): string | null +``` + +Gets the ID of the starting node/edge of the edge; returns `null` if not connected to a node/edge. + +#### getSourcePortId() + +```ts +getSourcePortId(): string | null +``` + +Gets the ID of the starting connection point; returns `null` if not connected to a connection point. + +#### getSourcePoint() + +```ts +getSourcePoint(): Point.PointLike | null +``` + +Gets the starting point linked to the canvas; returns `null` when the edge is connected to a node/edge. + +#### setSource(...) + +```ts +/** + * Link to a node. + */ +setSource( + node: Node, + args?: Edge.SetCellTerminalArgs, + options?: Edge.SetOptions, +): this + +/** + * Link to an edge. + */ +setSource( + edge: Edge, + args?: Edge.SetEdgeTerminalArgs, + options?: Edge.SetOptions, +): this + +/** + * Link to a point on the canvas. + */ +setSource( + point: Point | Point.PointLike, + args?: Edge.SetTerminalCommonArgs, + options?: Edge.SetOptions, +): this + +/** + * Set the starting point or starting node/edge of the edge. + */ +setSource(args: Edge.TerminalData, options?: Edge.SetOptions): this +``` + +#### getTarget() + +```ts +getTarget(): Edge.TerminalData +``` + +Gets the ending node/end point information of the edge. + +#### getTargetCell() + +```ts +getTargetCell(): Cell | null +``` + +Gets the ending node/edge of the edge; returns `null` if not connected to a node/edge. + +#### getTargetNode() + +```ts +getTargetNode(): Node | null +``` + +Gets the ending node of the edge; returns `null` if not connected to a node. + +#### getTargetCellId() + +```ts +getTargetCellId(): string | null +``` + +Gets the ID of the ending node/edge of the edge; returns `null` if not connected to a node/edge. + +#### getTargetPortId() + +```ts +getTargetPortId(): string | null +``` + +Gets the ID of the ending connection point; returns `null` if not connected to a connection point. + +#### getTargetPoint() + +```ts +getTargetPoint(): Point.PointLike | null +``` + +Gets the ending point linked to the canvas; returns `null` when the edge is connected to a node/edge. + +#### setTarget() + +```ts +/** + * Link to a node. + */ +setTarget( + edge: Node, + args?: Edge.SetCellTerminalArgs, + options?: Edge.SetOptions, +): this + +/** + * Link to an edge. + */ +setTarget( + edge: Edge, + args?: Edge.SetEdgeTerminalArgs, + options?: Edge.SetOptions, +): this + +/** + * Link to a point on the canvas. + */ +setTarget( + point: Point | Point.PointLike, + args?: Edge.SetTerminalCommonArgs, + options?: Edge.SetOptions, +): this + +/** + * Set the ending point or ending node/edge of the edge. + */ +setTarget(args: Edge.TerminalData, options?: Edge.SetOptions): this +``` + +#### disconnect(...) + +```ts +disconnect(options?: Edge.SetOptions) +``` + +Removes the link information of the edge, setting both the starting and ending points to the origin of the canvas `{ x:0, y:0 }`. + +| Name | Type | Required | Default Value | Description | +|------|------|:--------:|---------------|-------------| +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:source'` and `'change:target'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Path Points Vertice + +#### getVertices() + +```ts +getVertices(): Point.PointLike[] +``` + +Gets the path points; returns an empty array if there are no path points. + +#### setVertices(...) + +```ts +setVertices( + vertices: Point.PointLike | Point.PointLike[], + options?: Edge.SetOptions, +): this +``` + +Sets the path points. + +| Name | Type | Required | Default Value | Description | +|------|--------------------------|:--------:|---------------|-------------------| +| vertices | Point.PointLike \| Point.PointLike[] | ✓ | | Path points. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:vertices'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### insertVertex(...) + +```ts +insertVertex( + vertice: Point.PointLike, + index?: number, + options?: Edge.SetOptions, +): this +``` + +Inserts a path point at the specified position. + +| Name | Type | Required | Default Value | Description | +|------|----------------|:--------:|---------------|-------------------| +| vertice | Point.PointLike | ✓ | | Path point. | +| index | number | | | Insertion position, defaults to the end of the path point array. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:vertices'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### appendVertex(...) + +```ts +appendVertex(vertex: Point.PointLike, options?: Edge.SetOptions): this +``` + +Inserts a path point at the end of the path point array. + +| Name | Type | Required | Default Value | Description | +|------|----------------|:--------:|---------------|-------------------| +| vertex | Point.PointLike | ✓ | | Path point. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:vertices'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getVertexAt(...) + +```ts +getVertexAt(index: number): Point.PointLike | null +``` + +Gets the path point at the specified index. + +| Name | Type | Required | Default Value | Description | +|-------|--------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | + +#### setVertexAt(...) + +```ts +setVertexAt( + index: number, + vertice: Point.PointLike, + options?: Edge.SetOptions, +): this +``` + +Sets the path point at the specified index. + +| Name | Type | Required | Default Value | Description | +|------|----------------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | +| vertice | Point.PointLike | ✓ | | Path point. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:vertices'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeVertexAt(...) + +```ts +removeVertexAt(index: number, options?: Edge.SetOptions): this +``` + +Removes the path point at the specified index. + +| Name | Type | Required | Default Value | Description | +|------|--------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:vertices'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Router + +#### getRouter() + +```ts +getRouter(): Edge.RouterData +``` + +Gets the router. + +#### setRouter(...) + +```ts +setRouter(name: string, args?: KeyValue, options?: Edge.SetOptions): this +setRouter(router: Edge.RouterData, options?: Edge.SetOptions): this +``` + +Sets the router. + +| Name | Type | Required | Default Value | Description | +|------|----------------|:--------:|---------------|-------------------| +| name | string | ✓ | | Router name. | +| args | KeyValue | | | Router parameters. | +| router | Edge.RouterData | ✓ | | Router. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:router'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeRouter(...) + +```ts +removeRouter(options?: Edge.SetOptions): this +``` + +Removes the router. + +| Name | Type | Required | Default Value | Description | +|------|--------|:--------:|---------------|-------------------| +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:router'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Connector + +#### getConnector() + +```ts +getConnector(): Edge.ConnectorData +``` + +Gets the connector. + +#### setConnector(...) + +```ts +setConnector(name: string, args?: KeyValue, options?: Edge.SetOptions): this +setConnector(connector: Edge.ConnectorData, options?: Edge.SetOptions): this +``` + +Sets the connector. + +| Name | Type | Required | Default Value | Description | +|------|----------------|:--------:|---------------|-------------------| +| name | string | ✓ | | Connector name. | +| args | KeyValue | | | Connector parameters. | +| connector | Edge.ConnectorData | ✓ | | Connector. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:connector'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeConnector(...) + +```ts +removeConnector(options?: Edge.SetOptions): this +``` + +Removes the connector. + +| Name | Type | Required | Default Value | Description | +|------|--------|:--------:|---------------|-------------------| +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:connector'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### Label + +#### getDefaultLabel() + +```ts +getDefaultLabel(): Edge.Label +``` + +Gets the default label. + +#### getLabels() + +```ts +getLabels(): Edge.Label[] +``` + +Gets all labels. + +#### setLabels(...) + +```ts +setLabels( + labels: Edge.Label | Edge.Label[] | string | string[], + options?: Edge.SetOptions, +): this +``` + +Sets the labels. + +| Name | Type | Required | Default Value | Description | +|------|----------------------------------------|:--------:|---------------|-------------------| +| labels | Edge.Label \| Edge.Label[] \| string \| string[] | ✓ | | Labels or array of labels. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:labels'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### insertLabel(...) + +```ts +insertLabel( + label: Edge.Label | string, + index?: number, + options?: Edge.SetOptions, +): this +``` + +Inserts a label at the specified position. + +| Name | Type | Required | Default Value | Description | +|------|--------------------------|:--------:|---------------|-------------------| +| label | Edge.Label \| string | ✓ | | Label. | +| index | number | | | Insertion position, defaults to the end of the label array. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:labels'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### appendLabel(...) + +```ts +appendLabel(label: Edge.Label | string, options?: Edge.SetOptions): this +``` + +Inserts a label at the end of the label array. + +| Name | Type | Required | Default Value | Description | +|------|--------------------------|:--------:|---------------|-------------------| +| label | Edge.Label \| string | ✓ | | Label. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:labels'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getLabelAt(...) + +```ts +getLabelAt(index: number): Edge.Label | null +``` + +Gets the label at the specified position. + +| Name | Type | Required | Default Value | Description | +|-------|--------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | + +#### setLabelAt(...) + +```ts +setLabelAt( + index: number, + label: Edge.Label | string, + options?: Edge.SetOptions, +): this +``` + +Sets the label at the specified position. + +| Name | Type | Required | Default Value | Description | +|------|--------------------------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | +| label | Edge.Label \| string | ✓ | | Label. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:labels'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removeLabelAt(...) + +```ts +removeLabelAt(index: number, options?: Edge.SetOptions): this +``` + +Removes the label at the specified position. + +| Name | Type | Required | Default Value | Description | +|------|--------|:--------:|---------------|-------------------| +| index | number | ✓ | | Index position. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'change:labels'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | diff --git a/sites/x6-sites/docs/api/model/interaction.en.md b/sites/x6-sites/docs/api/model/interaction.en.md new file mode 100644 index 00000000000..eb55019f51c --- /dev/null +++ b/sites/x6-sites/docs/api/model/interaction.en.md @@ -0,0 +1,414 @@ +--- +title: Interaction +order: 6 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/model +--- + +One of the most appealing aspects of X6 for developers is its comprehensive interaction customization capabilities, which allow us to achieve a wide range of complex effects. Below are some common interactive behaviors. + +## Connecting + +By configuring `connecting`, you can achieve rich connection interactions. The usage is as follows: + +```typescript +const graph = new Graph({ + ..., + connecting: { + snap: true, + } +}) +``` + +Below are the configurations supported by `connecting`. + +### snap + +```typescript +snap: boolean | { radius: number, anchor: 'center' | 'bbox' } +``` + +When `snap` is set to `true` or `false`, it represents enabling or disabling automatic snapping during the connection process. When enabled, a distance of `50px` from the target will trigger the snap. You can customize the snap radius by configuring the `radius` property. + +```ts +const graph = new Graph({ + connecting: { + snap: true, + }, +}) +// Equivalent to +const graph = new Graph({ + connecting: { + snap: { + radius: 50, + }, + }, +}) +``` + +When calculating the distance to determine if it snaps to a node, it defaults to the center of the node. You can change this to calculate the distance based on the bounding box of the node by configuring `anchor` to `bbox`. + +### allowBlank + +```typescript +allowBlank: boolean | ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow connections to blank areas of the canvas. The default is `true`, and it also supports dynamic adjustment through a function. + +```typescript +const graph = new Graph({ + connecting: { + allowBlank() { + // Return true or false based on conditions + return true + }, + }, +}) +``` + +### allowLoop + +```typescript +allowLoop: boolean | ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow the creation of loop connections, where the starting and ending nodes are the same. The default is `true`. + +### allowNode + +```typescript +allowNode: boolean | ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow edges to connect to nodes (not connection ports on nodes). The default is `true`. + +### allowEdge + +```typescript +allowEdge: boolean | ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow edges to connect to other edges. The default is `true`. + +### allowPort + +```typescript +allowPort: boolean | ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow edges to connect to connection ports. The default is `true`. + +### allowMulti + +```typescript +allowMulti: boolean | + 'withPort' | + ((this: Graph, args: ValidateConnectionArgs) => boolean) +``` + +Whether to allow multiple edges to be created between the same starting and ending nodes. The default is `true`. When set to `false`, only one edge is allowed between the starting and ending nodes. When set to `'withPort'`, only one edge is allowed between the same connection ports of the starting and ending nodes (i.e., multiple edges can be created between the starting and ending nodes, but they must connect at different ports). + +### highlight + +```typescript +highlight: boolean +``` + +Whether to highlight all available connection ports or nodes while dragging an edge. The default value is `false`. This is generally used in conjunction with [highlighting](/en/docs/api/interacting/interacting#highlighting)highlighting +### anchor + +```typescript +anchor: NodeAnchorOptions +``` + +When connecting to a node, the anchor point of the connected node is specified through [ `anchor` ](/en/docs/api/registry/node-anchor), with the default value being `center`. + +#### sourceAnchor + +```typescript +sourceAnchor?: NodeAnchorOptions +``` + +When connecting to a node, the anchor point of the source node is specified through `sourceAnchor`. + +### targetAnchor + +```typescript +targetAnchor?: NodeAnchorOptions +``` + +When connecting to a node, the anchor point of the target node is specified through `targetAnchor`. + +### edgeAnchor + +```typescript +edgeAnchor: EdgeAnchorOptions +``` + +When connecting to an edge, the anchor point of the connected edge is specified through [ `edgeAnchor` ](/en/docs/api/registry/edge-anchor), with the default value being `ratio`. + +### sourceEdgeAnchor + +```typescript +sourceEdgeAnchor?: EdgeAnchorOptions +``` + +When connecting to an edge, the anchor point of the source edge is specified through `sourceEdgeAnchor`. + +### targetEdgeAnchor + +```typescript +targetEdgeAnchor?: EdgeAnchorOptions +``` + +When connecting to an edge, the anchor point of the target edge is specified through `targetEdgeAnchor`. + +### connectionPoint + +```typescript +connectionPoint: ConnectionPointOptions +``` + +Specifies the [connection point](/en/docs/api/registry/connector), with the default value being `boundary`. + +### sourceConnectionPoint + +```typescript +sourceConnectionPoint?: ConnectionPointOptions +``` + +The connection point of the source. + +### targetConnectionPoint + +```typescript +targetConnectionPoint?: ConnectionPointOptions +``` + +The connection point of the target. + +### router + +```typescript +router: string | Router.NativeItem | Router.ManaualItem +``` + +The [router](/en/docs/api/registry/router) further processes the edge's path points `vertices`, adding extra points if necessary, and returns the processed points. The default value is `normal`. + +### connector + +```typescript +connector: string | Connector.NativeItem | Connector.ManaualItem +``` + +The [connector](/en/docs/api/registry/connector) processes the starting point, the points returned by the router, and the endpoint into the `d` attribute of the `path` element, determining the style of the edge after rendering on the canvas. The default value is `normal`. + +### createEdge + +```typescript +createEdge?: ( + this: Graph, + args: { + sourceCell: Cell + sourceView: CellView + sourceMagnet: Element + }, +) => Nilable | void +``` + +This method allows you to customize the style of the newly created edge. + +### validateMagnet + +```typescript +validateMagnet?: ( + this: Graph, + args: { + cell: Cell + view: CellView + magnet: Element + e: Dom.MouseDownEvent | Dom.MouseEnterEvent + }, +) => boolean +``` + +When clicking on a `magnet`, the return value of `validateMagnet` determines whether to add a new edge. The trigger occurs when the `magnet` is pressed. If it returns `false`, there is no response; if it returns `true`, a new edge will be created at the current `magnet`. + +### validateConnection + +```typescript +validateConnection: (this: Graph, args: ValidateConnectionArgs) => boolean +``` + +When moving an edge, this checks if the connection is valid. If it returns `false`, the edge will not connect to the current element when the mouse is released; otherwise, it will connect. + +### validateEdge + +```typescript +validateEdge?: ( + this: Graph, + args: { + edge: Edge + type: Edge.TerminalType + previous: Edge.TerminalData + }, +) => boolean +``` + +When stopping the drag of an edge, this checks if the edge is valid based on the return value of `validateEdge`. If it returns `false`, the edge will be removed. + +## Embedding + +By using `embedding`, you can drag a node into another node, making it a child of the other node. This feature is disabled by default. The supported configurations are as follows: + +### enabled + +```typescript +enabled?: boolean +``` + +Whether to allow nesting between nodes. The default value is `false`. + +### findParent + +```typescript +findParent?: + | 'bbox' + | 'center' + | 'topLeft' + | 'topRight' + | 'bottomLeft' + | 'bottomRight' + | ((this: Graph, args: { node: Node; view: NodeView }) => Cell[]) +``` + +When a node is moved, the method specified by `findParent` returns the parent node. The default value is `bbox`. + +### frontOnly + +```typescript +frontOnly?: boolean +``` + +If `frontOnly` is `true`, only nodes displayed in the front can be embedded. The default value is `true`. + +### validate + +```typescript +validate: ( + this: Graph, + args: { + child: Node + parent: Node + childView: CellView + parentView: CellView + }, +) => boolean +``` + +`validate` is a function that determines whether a node can be embedded in a parent node. The default return value is `true`. + +## Restrictions + +Limit the interaction behavior of nodes and edges. The `interacting` configuration supports the following: + +```typescript +export type Interacting = + | boolean + | InteractionMap + | ((this: Graph, cellView: CellView) => InteractionMap | boolean) +``` + +- `boolean`: Whether the node or edge is interactive. +- `InteractionMap`: Interaction details for the node or edge, supporting the following properties: + - `'nodeMovable'`: Whether the node can be moved. + - `'magnetConnectable'`: Whether to trigger connection interactions when dragging starts on elements with the `'magnet'` attribute. + - `'edgeMovable'`: Whether the edge can be moved. + - `'edgeLabelMovable'`: Whether the edge's label can be moved. + - `'arrowheadMovable'`: Whether the starting/ending arrow of the edge can be moved. + - `'vertexMovable'`: Whether the path points of the edge can be moved. + - `'vertexAddable'`: Whether path points can be added to the edge. + - `'vertexDeletable'`: Whether path points can be deleted from the edge. +- `(this: Graph, cellView: CellView) => InteractionMap | boolean` + +```ts +const graph = new Graph({ + container: this.container, + width: 800, + height: 1400, + grid: 10, + interacting: function (cellView: CellView) { + if (cellView.cell.getProp('customLinkInteractions')) { + return { vertexAdd: false } + } + return true + }, +}) +``` + +## Highlighting + +You can specify the highlighting style triggered by certain interactions through the `highlighting` option, such as: + +```ts +new Graph({ + highlighting: { + // When connection ports are available for linking, render a 2px wide red rectangle around the port + magnetAvailable: { + name: 'stroke', + args: { + padding: 4, + attrs: { + 'stroke-width': 2, + stroke: 'red', + }, + }, + }, + }, +}) +``` + +The supported `highlighting` configuration options include: + +- `'default'`: Default highlighting options used when the following highlighting configurations are absent. +- `'embedding'`: Used when a node can be embedded during the drag operation. +- `'nodeAvailable'`: Used when a node can be linked during the connection process. +- `'magnetAvailable'`: Used when connection ports can be linked during the connection process. +- `'magnetAdsorbed'`: Used when automatically snapping to connection ports during the connection process. + +The `magnetAvailable.name` above is actually the name of the highlighter. X6 has built-in highlighters `stroke` and `className`. For more details, refer to [Highlighter](/en/docs/api/registry/highlighter). + +## Movement Range + +You can globally configure `translating` to limit the movement range of nodes. + +```ts +const graph = new Graph({ + translating: { + restrict: true, + }, +}) +``` + +### restrict + +The movable range of nodes. Supports the following two methods: + +- `boolean`: If set to `true`, nodes cannot move outside the canvas area. +- `Rectangle.RectangleLike | (arg: CellView) => Rectangle.RectangleLike`: Specify a node's movement range. + +```ts +const graph = new Graph({ + translating: { + restrict: { + x: 0, + y: 0, + width: 100, + height: 100, + }, + }, +}) +``` diff --git a/sites/x6-sites/docs/api/model/labels.en.md b/sites/x6-sites/docs/api/model/labels.en.md new file mode 100644 index 00000000000..c6093d60f80 --- /dev/null +++ b/sites/x6-sites/docs/api/model/labels.en.md @@ -0,0 +1,546 @@ +--- +title: Labels +order: 3 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/model +--- + +The label configuration for edges in X6 is very flexible, so we dedicate a separate section to detail how to use edge labels. + +Before we begin, let's briefly understand a few methods for manipulating labels on an Edge instance. + +| Method Signature | Description | +|-------------------------------------------------------------------|---------------------| +| [edge.getLabels()](/en/docs/api/model/edge#getlabels) | Get all labels. | +| [edge.setLabels(...)](/en/docs/api/model/edge#setlabels) | Set labels. | +| [edge.insertLabel(...)](/en/docs/api/model/edge#insertlabel) | Insert a label at a specified position. | +| [edge.appendLabel(...)](/en/docs/api/model/edge#appendlabel) | Append a label at the end. | +| [edge.setLabelAt(...)](/en/docs/api/model/edge#setlabelat) | Set a label at a specified position. | +| [edge.getLabelAt(...)](/en/docs/api/model/edge#getlabelat) | Get a label at a specified position. | +| [edge.removeLabelAt(...)](/en/docs/api/model/edge#removelabelat) | Remove a label at a specified position. | + +## Label Definition + +A label includes label markup, label position, label style, etc. The complete definition is as follows. + +```ts +interface Label { + markup?: Markup + attrs?: Attr.CellAttrs + position?: + | number + | { + distance: number + offset?: + | number + | { + x?: number + y?: number + } + angle?: number + options?: { + absoluteDistance?: boolean + reverseDistance?: boolean + absoluteOffset?: boolean + keepGradient?: boolean + ensureLegibility?: boolean + } + } +} +``` + +- `markup`: Label markup. +- `attrs`: Label style. +- `position`: Label position. When its value is a `number`, it is equivalent to setting the value of `position.distance`. + - `distance`: [Label position](#position). + - `offset`: [Label offset](#offset). + - `angle`: [Label rotation](#rotation). + +## Default Label + +When creating an Edge, you can set the default label using the [defaultLabel option](/en/docs/tutorial/basic/edge#defaultlabel), with the default value as follows: + +```ts +{ + markup: [ + { + tagName: 'rect', + selector: 'body', + }, + { + tagName: 'text', + selector: 'label', + }, + ], + attrs: { + text: { + fill: '#000', + fontSize: 14, + textAnchor: 'middle', + textVerticalAnchor: 'middle', + pointerEvents: 'none', + }, + rect: { + ref: 'label', + fill: '#fff', + rx: 3, + ry: 3, + refWidth: 1, + refHeight: 1, + refX: 0, + refY: 0, + }, + }, + position: { + distance: 0.5, + }, +} +``` + +This default label includes a `` element (representing the label text) and a `` element (representing the label background), which is centered by default and has a white rounded background. Since all custom labels will be [merged](https://www.lodashjs.com/docs/latest#_mergeobject-sources) with this default label, we can simply provide a text attribute for a label as shown below. + +```ts +edge.appendLabel({ + attrs: { + text: { + text: 'Hello Label', + }, + }, +}) +``` + + + +## 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 `` element, such as `‘fill’` and `'stroke'`. | + +### classic + +Classic 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. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + +### diamond + +Diamond 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. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + +### cross + +Cross 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. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + +### async + +| Parameter Name | Type | Default Value | Description | +|----------------|---------|---------------|---------------------------------------------------------------------------------------------| +| width | Number | 10 | Width of the arrow. | +| height | Number | 6 | Height of the arrow. | +| offset | Number | 0 | Absolute offset along the edge direction. | +| open | Boolean | false | Non-closed arrow. | +| flip | Boolean | false | Whether to flip the arrow. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + +### path + +Custom arrow with [pathData](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d). + +| Parameter Name | Type | Default Value | Description | +|----------------|--------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| d | string | undefined | The [d attribute value](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) of the `` element, applied to the `` element after being standardized by `Util.normalizeMarker`. | +| offsetX | Number | 0 | x-direction offset. | +| offsetY | Number | 0 | y-direction offset. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + +```ts +graph.addEdge({ + source: { x: 100, y: 40 }, + target: { x: 400, y: 40 }, + attrs: { + line: { + stroke: '#31d0c6', + sourceMarker: { + name: 'path', + d: 'M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z', + }, + targetMarker: { + name: 'path', + offsetX: 10, + 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', + }, + }, + }, +}) +``` + + + +### 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 `` element, such as `‘fill’` and `'stroke'`. | + +### circlePlus + +Circular plus arrow. + +| Parameter Name | Type | Default Value | Description | +|----------------|--------|---------------|----------------------------------------------------------------------------------------------| +| r | Number | 5 | Circle radius. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element (plus), such as `‘fill’` and `'stroke'`. | + +### ellipse + +Elliptical arrow. + +| Parameter Name | Type | Default Value | Description | +|----------------|--------|---------------|----------------------------------------------------------------------------------------------| +| rx | Number | 5 | x-axis radius of the ellipse. | +| ry | Number | 5 | y-axis radius of the ellipse. | +| ...attrs | Object | { } | Other parameters will be treated as attributes of the arrow `` element, such as `‘fill’` and `'stroke'`. | + + +## Custom Arrows + +We can specify which SVG element to use for rendering the arrow through `tagName`. For example, below we specify the use of the `` element to render the arrow. All options except `tagName` will be added as attributes to the created `` element. 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: { + tagName: 'path', + d: 'M 20 -10 0 0 20 10 Z', + }, + targetMarker: { + tagName: 'path', + fill: 'yellow', // Use custom fill color + stroke: 'green', // Use custom stroke color + strokeWidth: 2, + d: 'M 20 -10 0 0 20 10 Z', + }, + }, +}) +``` + +In the code above, it is worth noting that our starting and ending arrows use the same `'d'` attribute value because we automatically calculate the arrow direction. In simple terms, we only need to define an arrow that points **left towards the origin**. + + + +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 ``, we can also use ``, ``, ``, ``, ``, ``, and other elements to define arrows. You just need to specify the tag name through `tagName` and set other necessary attributes for the element. For example, using an image to customize an arrow is also simple. First, we set `tagName` to `image` and specify the image URL through the `xlink:href` attribute, and then adjust the `y` attribute to center the image. + +```ts +edge.attr({ + line: { + sourceMarker: { + tagName: 'image', + 'xlink:href': + 'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png', + width: 24, + height: 24, + y: -12, + }, + targetMarker: { + tagName: 'image', + 'xlink:href': + 'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png', + width: 24, + height: 24, + y: -12, + }, + }, +}) +``` + + + +It is important to note that when using `` and `` to customize arrows, you can set their `cx` attribute to the corresponding axis radius to avoid the arrow overflowing the edge boundary. Other elements can be adjusted using the `y` attribute to center the arrow vertically. + +```ts +edge.attr({ + line: { + sourceMarker: { + tagName: 'ellipse', + rx: 20, + ry: 10, + cx: 20, + fill: 'rgba(255,0,0,0.3)', + }, + targetMarker: { + tagName: 'circle', + r: 12, + cx: 12, + fill: 'rgba(0,255,0,0.3)', + }, + }, +}) +``` + + + +## 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 `` arrow with the parameter name `'imageUrl'` to make it more semantic. +- And more... + +Before continuing, let's take a look at the definition of the arrow factory method. + +```ts +type Factory = (args: T) => Result + +type Result = Attr.SimpleAttrs & { + tagName?: string + children?: Result[] +} +``` + +The arrow factory method has only one parameter `args`, which is passed in when configuring the arrow. For example: + +```ts +edge.attr({ + line: { + sourceMarker: 'block', + targetMarker: { + name: 'ellipse', + rx: 10, + ry: 6, + }, + }, +}) +``` + +The above configuration is parsed to obtain the arrow name and parameters for both the starting and ending arrows. + +| Arrow Type | Arrow Name `name` | Arrow Parameters `args` | +|----------------|-------------------|------------------------------| +| sourceMarker | block | { } | +| targetMarker | ellipse | { rx: 10, ry: 6 } | + +Internally, X6 finds the corresponding factory method by the arrow name and calls that method with the provided parameters `args`, returning the result. The structure of the result `Result` is the same as that of the custom arrow structure introduced above, specifying which SVG element to use for rendering the arrow through `tagName`, while the remaining key-value pairs are attached as attributes to that element, supporting nesting through `children`. + +Once we understand the principle of the factory method, we can register the factory method using the static method `registerMarker` provided by Graph. + +``` +Graph.registerMarker(name: string, factory: Factory, overwrite?: boolean) +``` + +| Parameter Name | Parameter Type | Default Value | Description | +|----------------|----------------|---------------|-------------------------------------------------------------------| +| name | String | | Arrow name. | +| factory | Factory | | Arrow factory method. | +| overwrite | Boolean | false | Whether to overwrite the old factory method when encountering a name conflict; set to `true` to overwrite, otherwise an error will be thrown. | + +Finally, let's register an image arrow. + +```ts +/** + * Parameter Definition + */ +interface ImageMarkerArgs extends Attr.SimpleAttrs { + imageUrl: string + imageWidth?: number + imageHeight?: number +} + +Graph.registerMarker('image', (args: ImageMarkerArgs) => { + const { imageUrl, imageWidth, imageHeight, ...attrs } = args + return { + ...attrs, // Return non-special parameters as is + tagName: 'image', // Use tag to render the arrow; other key-value pairs will be treated as attributes of that element. + width: imageWidth, + height: imageHeight, + 'xlink:href': imageUrl, + } +}) +``` + +After registration, we can use the image arrow like this: + +```ts +edge.attr({ + line: { + sourceMarker: { + name: 'image', + imageUrl: + 'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png', + imageWidth: 24, + imageHeight: 24, + y: -12, + }, + targetMarker: { + name: 'image', + imageUrl: + 'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png', + imageWidth: 24, + imageHeight: 24, + y: -12, + }, + }, +}) +``` diff --git a/sites/x6-sites/docs/api/model/node.en.md b/sites/x6-sites/docs/api/model/node.en.md new file mode 100644 index 00000000000..a5f13b8aa3f --- /dev/null +++ b/sites/x6-sites/docs/api/model/node.en.md @@ -0,0 +1,890 @@ +--- +title: Node +order: 1 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/model +--- + +Node is the base class for all nodes, inheriting from [Cell](/en/docs/api/model/cell), and defines the common properties and methods for nodes. + +## Attributes + +In addition to inheriting from Cell [attributes](/en/docs/api/model/cell#properties), the following attributes are also supported. + +| Option | Type | Default Value | Required | Description | +| --- | --- | --- | :-: | --- | +| size | `{ width: number; height: number }` | `{ width: 1, height: 1 }` | | Node size. | +| position | `{ x: number; y: number }` | - | | Node position. | +| angle | number | - | | Node rotation angle. | +| ports | object | - | | Connection ports. | +| portMarkup | Markup | object | | DOM structure of the connection ports. | +| portLabelMarkup | Markup | object | | DOM structure of the connection port labels. | + +### Size + +The size of the node, which is an object containing `width` and `height` properties, can be retrieved and set using the [`size(...)`](#size-1) method. + +### Position + +The position of the node, which is an object containing `x` and `y` properties, can be retrieved and set using the [`position(...)`](#position-1) method. + +### Angle + +The rotation angle of the node, with the rotation center being the center of the node, can be retrieved and set using the [`rotate(...)`](#rotate) method. + +### Ports + +Connection ports are fixed connection points on the node. Many graph applications have connection ports, and some applications also categorize them into input and output ports. + +The `ports` option is a complex object that can be used as follows: + +```ts +const node = new Node({ + ports: { + group: { ... }, // Connection port group definition + items: [ ... ], // Connection ports + } +}) +``` + +Or + +```ts +const node = new Node({ + ports: [ ... ], // Connection ports +}) +``` + +Typically, we group connection ports with the same behavior and appearance into the same group and set the grouping through the `group` option, which is an object `{ [groupName: string]: PortGroupMetadata }`, where 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 { + /** + * Connection port DOM structure definition. + */ + markup?: Markup + + /** + * Attributes and styles. + */ + attrs?: Attr.CellAttrs + + /** + * DOM hierarchy of the connection ports, the higher the value, the higher the hierarchy. + */ + zIndex?: number | 'auto' + + /** + * Layout of the connection ports in the group. + */ + position?: + | [number, number] // Absolute positioning + | string // Name of the connection port layout method + | { + // Name and parameters of the connection port layout method + name: string + args?: object + } + + /** + * Connection port label. + */ + label?: { + markup?: Markup + position?: { + // Layout of the connection port label + name: string // Layout name + args?: object // Layout parameters + } + } +} +``` + +For example: + +```ts +const node = new Node({ + ports: { + group: { + group1: { + markup: { tagName: 'circle' }, + attrs: { }, + zIndex: 1, + position: { + name: 'top', + args: {}, + }, + }, + group2: { ... }, + group3: { ... }, + }, + items: [ ... ], + } +}) +``` + +Another option, `items`, is an array `PortMetadata[]`, where each item represents a connection port. The supported options for connection ports are as follows: + +```ts +interface PortMetadata { + /** + * Unique ID of the connection port, automatically generated by default. + */ + id?: string + + /** + * Group name, specifying a group will inherit the connection port options from the group. + */ + group?: string + + /** + * Provides parameters for the layout algorithm specified in the group for the designated connection port. + * We cannot specify a layout algorithm for a single connection port, but we can provide different parameters for the layout algorithm specified in the group. + */ + args?: object + + /** + * DOM element and structure definition of the connection port. Specifying this option will override the default options provided by the group. + */ + markup?: Markup + + /** + * Element attribute styles. Specifying this option will override the default options provided by the group. + */ + attrs?: Attr.CellAttrs + + /** + * DOM hierarchy of the connection port, the higher the value, the higher the hierarchy. Specifying this option will override the default options provided by the group. + */ + zIndex?: number | 'auto' + + /** + * Connection port label. Specifying this option will override the default options provided by the group. + */ + label?: { + markup?: Markup + position?: { + // Layout of the connection port label + name: string // Layout name + args?: object // Layout parameters + } + } +} +``` + +For example: + +```ts +const node = new Node({ + ports: { + group: { ... }, + items: [ + { id: 'port1', group: 'group1', ... }, + { id: 'port2', group: 'group1', ... }, + { id: 'port3', group: 'group2', ... }, + ], + } +}) +``` + +For more details, please refer to the [Configure Connection Ports](#connection-ports) documentation. + +### Port Markup + +The DOM structure of the connection ports. When neither `ports.groups` nor `ports.items` specifies `markup` for the corresponding connection port, this default option is used to render the connection port, with the default value being: + +```ts +{ + tagName: 'circle', + selector: 'circle', + attrs: { + r: 10, + fill: '#fff', + stroke: '#000', + }, +} +``` + +This indicates that the connection port is rendered as a circle with a radius of `10px`. + +### Port Label Markup + +The DOM structure of the connection port labels. When neither `ports.groups` nor `ports.items` specifies `markup` for the corresponding connection port label, this default option is used to render the connection port label, with the default value being: + +```ts +{ + tagName: 'text', + selector: 'text', + attrs: { + fill: '#000000', + }, +} +``` + +## Methods + +### General + +#### isNode() + +```ts +isNode(): true +``` + +Determines if it is a node; this method always returns `true`. + +#### getBBox(...) + +```ts +getBBox(options: { deep?: boolean }): Rectangle +``` + +Gets the bounding box of the node. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| options.deep | boolean | | `false` | When `true`, includes the bounding box of all child nodes and edges; defaults to `false`. | + +```ts +const rect1 = node.getBBox() +const rect2 = node.getBBox({ deep: true }) +``` + +### Size + +#### size(...) + +```ts +/** + * Gets the size of the node. + */ +size(): Size + +/** + * Sets the size of the node. + */ +size(size: Size, options?: Node.ResizeOptions): this + +/** + * Sets the size of the node. + */ +size(width: number, height: number, options?: Node.ResizeOptions): this +``` + +Gets the size of the node. + +```ts +const size = node.size() +console.log(size.width, size.height) +``` + +The parameters and usage for setting the node size are the same as the [`resize`](#resize) method. + +#### resize(...) + +Changes the size of the node. Depending on the rotation angle and `options.direction`, both the position and size of the node may change. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| width | number | | | Node width. | +| height | number | | | Node height. | +| options.direction | Direction | | `'bottom-right'` | The direction in which to change the size; defaults to fixing the top-left corner and resizing towards the bottom-right. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:size'` and `'change:position'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +Supports resizing the node in 8 directions, with the default being `'bottom-right'`, which means fixing the top-left corner and resizing towards the bottom-right. + +- top +- right +- bottom +- left +- top-left +- top-right +- bottom-left +- bottom-right + +```ts +node.resize(100, 40) + +// Fixing the bottom-right corner, resizing towards the top-left +node.resize(100, 40, { direction: 'top-left' }) + +// Do not trigger events and redraw +node.resize(100, 40, { silent: true }) +``` + +#### scale(...) + +```ts +scale( + sx: number, + sy: number, + origin?: Point.PointLike, + options?: Node.SetOptions, +): this +``` + +Scales the node. Depending on the scaling center and scaling ratio, both the size and position of the node may change. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| sx | number | ✓ | | Scaling ratio in the X direction. | +| sy | number | ✓ | | Scaling ratio in the Y direction. | +| origin | Point.PointLike \| null | | - | Scaling center, defaults to the center of the node. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:size'` and `'change:position'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +node.scale(1.5, 1.5) + +// Custom scaling center +node.scale(1.5, 1.5, { x: 100, y: 30 }) + +// Do not trigger events and redraw +node.scale(1.5, 1.5, null, { silent: true }) +``` + +#### fit(...) + +```ts +fit(options?: Node.FitEmbedsOptions): this +``` + +Automatically adjusts the size and position of the node based on the size and position of child nodes and edges, ensuring that all child nodes and edges are within the bounding box of the node. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| options.padding | number \| `{ top: number; right: number; bottom: number; left: number }` | | `0` | Padding. | +| options.deep | boolean | | `false` | Whether to include all descendant nodes and edges; defaults to only including direct child nodes and edges. | +| options.silent | boolean | | `false` | When `true`, does not trigger events and redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +node.fit() +node.fit({ padding: 10 }) +node.fit({ padding: { top: 20, bottom: 20, left: 10, right: 10 } }) +``` + +### Position + +#### position(...) + +```ts +/** + * Gets the position of the node. + */ +position(options?: Node.GetPositionOptions): Point.PointLike + +/** + * Sets the position of the node. + */ +position(x: number, y: number, options?: Node.SetPositionOptions): this +``` + +Gets the position of the node. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| options.relative | boolean | | `false` | Whether to return the relative position to the parent node; defaults to `false`, indicating that the absolute position relative to the canvas is returned. | + +```ts +const pos = rect.position() +console.log(pos.x, pos.y) + +const relativePos = child.position({ relative: true }) +console.log(relativePos.x, relativePos.y) +``` + +Sets the position of the node. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| x | number | ✓ | | Absolute or relative X-axis coordinate of the node. | +| y | number | ✓ | | Absolute or relative Y-axis coordinate of the node. | +| options.relative | boolean | | `false` | Whether the provided coordinates are relative coordinates. When `true`, indicates that the provided coordinates are relative to the parent node; defaults to `false`, indicating that the provided coordinates are absolute coordinates relative to the canvas. | +| options.deep | boolean | | `false` | Whether to also change the position of child nodes/edges. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:position'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +By default, absolute coordinates are used. When `options.relative` is `true`, relative coordinates are used. + +```ts +// Move the node to the canvas position [30, 30] +node.position(30, 30) + +// Move the child node to the relative position [30, 30] at the top-left corner of the parent node +child.position(30, 30, { relative: true }) +``` + +When `options.deep` is `true`, child nodes and edges will also be moved simultaneously. + +```ts +parent.position(30, 30, { deep: true }) +``` + +When `options.silent` is `true`, it does not trigger `'change:position'` events and does not redraw the canvas. + +```ts +node.position(30, 30, { silent: true }) +``` + +Other custom key-value pairs can be used in event callbacks. + +```ts +node.position(30, 30, { otherKey: 'otherValue', ... }) +``` + +#### translate(...) + +```ts +translate(tx?: number, ty?: number, options?: Node.TranslateOptions): this +``` + +Translates the node along with its child nodes and edges. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| tx | number | | `0` | The offset of the node in the X direction. | +| ty | number | | `0` | The offset of the node in the Y direction. | +| options.restrict | Rectangle.RectangleLike | | `undefined` | Restricts the movable range of the node to the specified rectangular area. | +| options.transition | boolean \| Animation.Options | | `false` | Whether to use animation or specify an [animation option](/en/docs/api/model/cell#transition). | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:position'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +When the specified `tx` and `ty` are `undefined`, it indicates that the corresponding direction's translation amount is `0`. + +```ts +node.translate(30, 30) +node.translate(30) // Move only in the X direction +node.translate(undefined, 30) // Move only in the Y direction +``` + +We can restrict the movement of the node within a specified rectangle `{x: number; y: number; width: number; height: number}` using the `options.restrict` option. + +For example, we can restrict the movement of child nodes within the bounding box of the parent node: + +```ts +child.translate(30, 30, { + restrict: child.getParent().getBBox(), +}) +``` + +When `options.transition` is `true` or an [animation option](/en/docs/api/model/cell#transition) is specified, it indicates that animation should be used to translate the node. For more details, please refer to the [Using Animation Documentation](/en/docs/api/model/cell#transition). + +```ts +// Translate the node using the default animation +node.translate(30, 30, { + transition: true, +}) + +// Custom animation options +node.translate(30, 30, { + transition: { + duration: 2000, + }, +}) +``` + +When `options.silent` is true, it does not trigger `'change:position'` events and does not redraw the canvas. + +```ts +node.translate(30, 30, { silent: true }) +``` + +Other custom key-value pairs can be used in event callbacks. + +```ts +node.translate(30, 30, { otherKey: 'otherValue', ... }) +``` + +### Rotation Angle + +#### getAngle() + +```ts +getAngle(): number +``` + +Gets the rotation angle of the node. + +```ts +if (node.getAngle() !== 0) { + // do something +} +``` + +#### rotate(...) + +```ts +rotate( + deg: number, + absolute?: boolean, + origin?: Point.PointLike, + options?: Node.RotateOptions, +): this +``` + +Rotates the node. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| deg | number | ✓ | | Rotation degree. | +| options.absolute | boolean | | `false` | When `true`, indicates that the given degree is the absolute degree after rotation; defaults to `false`, indicating that the node rotates the given degree based on the current rotation angle. | +| options.center | Point.PointLike | | `undefined` | Defaults to rotating around the center of the node; when `options.center` is given, it indicates rotating around the specified center. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:angle'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +By default, it is a relative rotation, meaning that the node rotates the given degree based on the current rotation angle. When `options.absolute` is `true`, it indicates absolute rotation, meaning that the given degree is the angle of the node after rotation. + +```ts +// Relative rotation, the node rotates 30 degrees based on the current rotation angle +node.rotate(30) + +// Absolute rotation, the angle of the node after rotation is 30 degrees +node.rotate(30, { absolute: true }) +``` + +By default, it rotates around the center of the node. You can specify a rotation center using the `options.center` option. + +```ts +node.rotate(30, { center: { x: 10, y: 10 } }) +``` + +By default, it triggers `'change:angle'` events and redraws the canvas. When `options.silent` is `true`, it does not trigger `'change:angle'` events and does not redraw the canvas. + +```ts +node.rotate(30, { silent: true }) +``` + +Other custom key-value pairs can be used in event callbacks. + +```ts +node.rotate(30, { otherKey: 'otherValue', ... }) +``` + +### Connection Ports + +Connection ports are fixed connection points on the node. Many graph applications have connection ports, and some applications also categorize them into input and output ports. + +In the above, we introduced the data structure of connection ports. Here, we will continue to introduce some methods for operating connection ports on the node. + +#### addPort(...) + +```ts +addPort(port: PortMetadata, options?: Node.SetOptions): this +``` + +Adds a single connection port. The connection port is added to the end of the connection port array. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| port | [PortMetadata](#ports) | ✓ | | Connection port. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### addPorts(...) + +```ts +addPorts(ports: PortMetadata[], options?: Node.SetOptions) +``` + +Adds multiple connection ports. The connection ports are added to the end of the connection port array. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| port | [PortMetadata](#ports)[] | ✓ | | Array of connection ports. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### insertPort(...) + +```ts +insertPort(index: number, port: PortMetadata, options?: Node.SetOptions): this +``` + +Adds a connection port at the specified position. Note that the `port` parameter needs to include the `id` property. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| index | number | ✓ | | Position of the connection port. | +| port | [PortMetadata](#ports) | ✓ | | Connection port. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### hasPort(...) + +```ts +hasPort(portId: string): boolean +``` + +Checks if the specified connection port exists. + +| Name | Type | Required | Default Value | Description | +| ------ | ------ | :--: | ------ | ----------- | +| portId | string | ✓ | | Connection port ID. | + +```ts +if (node.hasPort('port1')) { + // do something +} +``` + +#### hasPorts() + +```ts +hasPorts(): boolean +``` + +Checks if the node contains connection ports. + +```ts +if (node.hasPorts()) { + // do something +} +``` + +#### getPort(...) + +```ts +getPort(portId: string): PortMetadata +``` + +Gets the connection port by ID. + +| Name | Type | Required | Default Value | Description | +| ------ | ------ | :--: | ------ | ----------- | +| portId | string | ✓ | | Connection port ID. | + +#### getPortAt(...) + +```ts +getPortAt(index: number): PortMetadata | null +``` + +Gets the connection port at the specified index. + +| Name | Type | Required | Default Value | Description | +| ----- | ------ | :--: | ------ | ------------ | +| index | number | ✓ | | Connection port index. | + +#### getPorts() + +```ts +getPorts(): PortMetadata[] +``` + +Gets all connection ports. + +#### getPortsByGroup(...) + +```ts +getPortsByGroup(groupName: string): PortMetadata[] +``` + +Gets all connection ports under the specified group. + +| Name | Type | Required | Default Value | Description | +| --------- | ------ | :--: | ------ | ---------- | +| groupName | string | ✓ | | Group name. | + +#### removePort(...) + +```ts +/** + * Removes the specified connection port. + */ +removePort(port: PortMetadata, options?: Node.SetOptions): this + +/** + * Removes the connection port with the specified ID. + */ +removePort(portId: string, options?: Node.SetOptions): this +``` + +Removes the specified connection port. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| port | PortMetadata | ✓ | | Connection port. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +Removes the connection port with the specified ID. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| portId | string | ✓ | | Connection port ID. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removePortAt(...) + +```ts +removePortAt(index: number, options?: Node.SetOptions): this +``` + +Removes the connection port at the specified index. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| index | number | ✓ | | Connection port index. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### removePorts(...) + +```ts +/** + * Removes all connection ports. + */ +removePorts(options?: Node.SetOptions): this + +/** + * Removes the specified connection ports. + */ +removePorts(ports: (PortMetadata | string)[], options?: Node.SetOptions): this +``` + +Removes the specified multiple connection ports. + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| ports | (PortMetadata \| string)[] | | | Array of connection ports to be removed. | +| options.silent | boolean | | `false` | When `true`, does not trigger `'change:ports'` events and does not redraw the canvas. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### getPortIndex(...) + +```ts +getPortIndex(port: PortMetadata | string): number +``` + +Obtain the index position of the connection port. + +#### getPortProp(...) + +```ts +getPortProp(portId: string, path?: string | string[]): any +``` + +Retrieves the property value at the specified path of the port. When the path is empty, it returns the complete port. + +| Name | Type | Required | Default Value | Description | +|----------|---------------------|:--------:|---------------|---------------------------------| +| portId | string | ✓ | | Port ID. | +| path | string \| string[] | | | Property path. When `path` is of type `string`, the path is a string separated by `'/'`. When `path` is of type `string[]`, the path is an array of keys that make up the port object path. | + +```ts +node.getPortProp('port1') +node.getPortProp('port1', 'attrs/circle') +node.getPortProp('port1', ['attrs', 'circle']) +``` + +#### setPortProp(...) + +```ts +setPortProp( + portId: string, + path: string | string[], + value: any, + options?: Node.SetOptions, +): this +``` + +Sets the property of the port based on the path. + +| Name | Type | Required | Default Value | Description | +|----------|---------------------|:--------:|---------------|---------------------------------| +| portId | string | ✓ | | Port ID. | +| path | string \| string[] | ✓ | | Property path. When `path` is of type `string`, the path is a string separated by `'/'`. When `path` is of type `string[]`, the path is an array of keys that make up the port object path. | +| value | any | ✓ | | Property value. | +| options.silent | boolean | | `false` | If `true`, does not trigger the `'change:ports'` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +node.setPortProp('port1', 'attrs/circle', { + fill: '#ffffff', + stroke: '#000000', +}) +node.setPortProp('port1', ['attrs', 'circle'], { + fill: '#ffffff', + stroke: '#000000', +}) +``` + +```ts +setPortProp( + portId: string, + value: DeepPartial, + options?: Node.SetOptions, +): this +``` + +Sets the properties of the port, merging the provided property options with the current values using [deep merge](https://www.lodashjs.com/docs/latest#_mergeobject-sources). + +| Name | Type | Required | Default Value | Description | +|----------|-------------------------------|:--------:|---------------|---------------------------------| +| portId | string | ✓ | | Port ID. | +| value | DeepPartial\ | ✓ | | Port options. | +| options.silent | boolean | | `false` | If `true`, does not trigger the `'change:ports'` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +node.getPortProp('port1', { + attrs: { + circle: { + fill: '#ffffff', + stroke: '#000000', + }, + }, +}) +``` + +#### removePortProp(...) + +```ts +removePortProp(portId: string, options?: Node.SetOptions): this +``` + +Removes the options of the specified port. + +| Name | Type | Required | Default Value | Description | +|----------|---------------------|:--------:|---------------|---------------------------------| +| portId | string | ✓ | | Port ID. | +| options.silent | boolean | | `false` | If `true`, does not trigger the `'change:ports'` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +```ts +removePortProp(portId: string, path: string | string[], options?: Node.SetOptions): this +``` + +Removes the options of the specified port at the specified path. + +| Name | Type | Required | Default Value | Description | +|----------|---------------------|:--------:|---------------|---------------------------------| +| portId | string | ✓ | | Port ID. | +| path | string \| string[] | ✓ | | Property path. When `path` is of type `string`, the path is a string separated by `'/'`. When `path` is of type `string[]`, the path is an array of keys that make up the port object path. | +| options.silent | boolean | | `false` | If `true`, does not trigger the `'change:ports'` event and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +#### portProp(...) + +```ts +portProp(portId: string): PortMetadata +portProp(portId: string, path: string | string[]): T +portProp( + portId: string, + path: string | string[], + value: any, + options?: Node.SetOptions, +): this +portProp( + portId: string, + value: DeepPartial, + options?: Node.SetOptions, +): this +``` + +This method is a combination of [`getPortProp`](#getportprop) and [`setPortProp`](#setportprop), with parameter options and usage consistent with these two methods. diff --git a/sites/x6-sites/docs/api/mvc/model.en.md b/sites/x6-sites/docs/api/mvc/model.en.md new file mode 100644 index 00000000000..6e518d22661 --- /dev/null +++ b/sites/x6-sites/docs/api/mvc/model.en.md @@ -0,0 +1,698 @@ +--- +title: Model +order: 1 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/mvc +--- + +## Configuration + +### model + +The model corresponding to the canvas, by default creates a new model. + +## Methods + +### isNode(...) + +```ts +isNode(cell: Cell): cell is Node +``` + +Returns whether the specified Cell is a node. + +| Name | Type | Required | Default | Description | +|------|------|:--------:|---------|-------------| +| cell | Cell | ✓ | | The specified Cell. | + +### isEdge(...) + +```ts +isEdge(cell: Cell): cell is Edge +``` + +Returns whether the specified Cell is an edge. + +| Name | Type | Required | Default | Description | +|------|------|:--------:|---------|-------------| +| cell | Cell | ✓ | | The specified Cell. | + +### createNode(...) + +```ts +createNode(metadata: Node.Metadata): Node +``` + +Creates a node. + +| Name | Type | Required | Default | Description | +|----------|---------------|:--------:|---------|-------------| +| metadata | Node.Metadata | ✓ | | Node metadata. | + +### addNode(...) + +```ts +addNode(metadata: Node.Metadata, options?: AddOptions): Node +addNode(node: Node, options?: AddOptions): Node +``` + +Adds a node to the canvas, returns the added node. + +| Name | Type | Required | Default | Description | +|------------------|-----------------------|:--------:|---------|-------------| +| node | Node.Metadata \| Node | ✓ | | Node metadata or node instance. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'node:added'` and `'cell:added'` events and canvas redraw. | +| options.sort | boolean | | `true` | Whether to sort by `zIndex`. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### addNodes(...) + +```ts +addNodes(nodes: (Node.Metadata | Node)[], options?: AddOptions): Graph +``` + +Adds multiple nodes to the canvas, returns the graph. When adding nodes in batch, it's recommended to use this method for better performance compared to multiple addNode calls. + +| Name | Type | Required | Default | Description | +|------------------|---------------------------|:--------:|---------|-------------| +| nodes | (Node.Metadata \| Node)[] | ✓ | | Array of node metadata or node instances. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'node:added'` and `'cell:added'` events and canvas redraw. | +| options.sort | boolean | | `true` | Whether to sort by `zIndex`. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### removeNode(...) + +```ts +removeNode(nodeId: string, options?: RemoveOptions): Node | null +removeNode(node: Node, options?: RemoveOptions): Node | null +``` + +Removes a node, returns the removed node. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| node | string \| Node | ✓ | | Node ID or node instance. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'node:removed'` and `'cell:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### createEdge(...) + +```ts +createEdge(metadata: Edge.Metadata): Edge +``` + +Creates an edge. + +| Name | Type | Required | Default | Description | +|----------|---------------|:--------:|---------|-------------| +| metadata | Edge.Metadata | ✓ | | Edge metadata. | + +### addEdge(...) + +```ts +addEdge(metadata: Edge.Metadata, options?: AddOptions): Edge +addEdge(edge:Edge, options?: AddOptions): Edge +``` + +Adds an edge to the canvas, returns the added edge. + +| Name | Type | Required | Default | Description | +|------------------|-----------------------|:--------:|---------|-------------| +| edge | Edge.Metadata \| Edge | ✓ | | Edge metadata or edge instance. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'edge:added'` and `'cell:added'` events and canvas redraw. | +| options.sort | boolean | | `true` | Whether to sort by `zIndex`. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### addEdges(...) + +```ts +addEdges(edges: (Edge.Metadata | Edge)[], options?: AddOptions): Graph +``` + +Adds multiple edges to the canvas, returns the graph. + +| Name | Type | Required | Default | Description | +|------------------|---------------------------|:--------:|---------|-------------| +| edges | (Edge.Metadata \| Edge)[] | ✓ | | Array of edge metadata or edge instances. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'edge:added'` and `'cell:added'` events and canvas redraw. | +| options.sort | boolean | | `true` | Whether to sort by `zIndex`. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### removeEdge(...) + +```ts +removeEdge(edgeId: string, options?: RemoveOptions): Edge | null +removeEdge(edge: Edge, options?: RemoveOptions): Edge | null +``` + +Removes an edge, returns the removed edge. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| edge | string \| Edge | ✓ | | Edge ID or edge instance. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'edge:removed'` and `'cell:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### addCell(...) + +```ts +addCell(cell: Cell | Cell[], options?: AddOptions): this +``` + +Adds a node or edge to the canvas. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| cell | Cell \| Cell[] | ✓ | | Node instance or edge instance, supports passing an array to add multiple nodes or edges at once. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:added'`, `'node:added'`, and `'edge:added'` events and canvas redraw. | +| options.sort | boolean | | `true` | Whether to sort by `zIndex`. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### removeCell(...) + +```ts +removeCell(cellId: string, options?: RemoveOptions): Cell | null +removeCell(cell: Cell, options?: RemoveOptions): Cell | null +``` + +Removes a node or edge, returns the removed node or edge. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge instance. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:removed'`, `'node:removed'`, and `'edge:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### removeCells(...) + +```ts +removeCells(cells: (Cell | string)[], options?: RemoveOptions): Cell[] +``` + +Removes multiple nodes/edges, returns an array of removed nodes or edges. + +| Name | Type | Required | Default | Description | +|------------------|--------------------|:--------:|---------|-------------| +| cell | (string \| Cell)[] | ✓ | | Array of node/edge IDs or node/edge instances. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:removed'`, `'node:removed'`, and `'edge:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### removeConnectedEdges(...) + +```ts +removeConnectedEdges(cell: Cell | string, options?: RemoveOptions): Edge[] +``` + +Removes edges connected to the node/edge, returns an array of removed edges. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:removed'` and `'edge:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### disconnectConnectedEdges(...) + +```ts +disconnectConnectedEdges(cell: Cell | string, options?: Edge.SetOptions): this +``` + +Sets the source and target of edges connected to the node/edge to the origin `{x: 0, y: 0}`, effectively disconnecting them. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'edge:change:source'` and `'edge:change:target'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### clearCells(...) + +```ts +clearCells(options?: SetOptions): this +``` + +Clears the canvas. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-------------| +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:removed'`, `'node:removed'`, and `'edge:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### resetCells(...) + +```ts +resetCells(cells: Cell[], options?: SetOptions): this +``` + +Clears the canvas and adds the specified nodes/edges. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|-------------| +| cell | Cell[] | ✓ | | Array of nodes/edges. | +| options.silent | boolean | | `false` | If `true`, does not trigger `'cell:added'`, `'node:added'`, `'edge:added'`, `'cell:removed'`, `'node:removed'`, and `'edge:removed'` events and canvas redraw. | +| options...others | object | | | Other custom key-value pairs that can be used in event callbacks. | + +### hasCell(...) + +```ts +hasCell(cellId: string): boolean +hasCell(cell: Cell): boolean +``` + +Returns whether the canvas contains the specified node/edge. + +| Name | Type | Required | Default | Description | +|------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge. | + +### getCellById(...) + +```ts +getCellById(id: string) +``` + +Gets a node/edge by its ID. + +| Name | Type | Required | Default | Description | +|------|--------|:--------:|---------|-------------| +| id | string | ✓ | | ID of the node/edge. | + +### updateCellId(...) + +```ts +updateCellId(cell: Cell, newId: string) +``` + +Updates the ID of a node or edge, returns the newly created node/edge. + +| Name | Type | Required | Default | Description | +|-------|--------|:--------:|---------|-------------| +| cell | Cell | ✓ | | Node/edge. | +| newId | string | ✓ | | New ID. | + +### getCells() + +```ts +getCells(): Cell[] +``` + +Returns all nodes and edges in the canvas. + +### getCellCount() + +```ts +getCellCount(): number +``` + +Returns the count of all nodes and edges in the canvas. + +### getNodes() + +```ts +getNodes(): Node[] +``` + +Returns all nodes in the canvas. + +### getEdges() + +```ts +getEdges(): Edge[] +``` + +Returns all edges in the canvas. + +### getOutgoingEdges(...) + +```ts +getOutgoingEdges(cell: Cell | string): Edge[] | null +``` + +Gets the outgoing edges connected to the node/edge, i.e., edges whose source is the specified node/edge. + +| Name | Type | Required | Default | Description | +|------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge. | + +### getIncomingEdges(...) + +```ts +getIncomingEdges(cell: Cell | string): Edge[] | null +``` + +Gets the incoming edges connected to the node/edge, i.e., edges whose target is the specified node/edge. + +| Name | Type | Required | Default | Description | +|------|----------------|:--------:|---------|-------------| +| cell | string \| Cell | ✓ | | Node/edge ID or node/edge. | + +### getConnectedEdges(...) + +```ts +getConnectedEdges(cell: Cell | string, options?: GetConnectedEdgesOptions): Edge[] +``` + +Get the edges connected to a node/edge. + +| Name | Type | Required | Default | Description | +|------------------|----------------|:--------:|---------|---------------------------------------------------------------------------------------------------------------------------| +| cell | string \| Cell | ✓ | | Node/Edge ID or Node/Edge. | +| options.incoming | boolean | | - | Whether to include incoming edges. By default, returns all incoming and outgoing edges. When `incoming` is `true`, only returns incoming edges. | +| options.outgoing | boolean | | - | Whether to include outgoing edges. By default, returns all incoming and outgoing edges. When `outgoing` is `true`, only returns outgoing edges. | +| options.deep | boolean | | `false` | Whether to recursively get edges for all child nodes/edges. When `true`, it will also return edges connected to all descendant nodes/edges. | +| options.enclosed | boolean | | `false` | Whether to include edges connecting descendant nodes. | +| options.indirect | boolean | | `false` | Whether to include indirectly connected edges, i.e., edges connected to input or output edges. | + +```ts +const edges = graph.getConnectedEdges(node) // Returns incoming and outgoing edges +const edges = graph.getConnectedEdges(node, { incoming: true, outgoing: true }) // Returns incoming and outgoing edges + +const edges = graph.getConnectedEdges(node, { incoming: true }) // Returns incoming edges +const edges = graph.getConnectedEdges(node, { + incoming: true, + outgoing: false, +}) // Returns incoming edges + +const edges = graph.getConnectedEdges(node, { outgoing: true }) // Returns outgoing edges +const edges = graph.getConnectedEdges(node, { + incoming: false, + outgoing: true, +}) // Returns outgoing edges + +const edges = graph.getConnectedEdges(node, { deep: true }) // Returns incoming and outgoing edges, including those connected to all descendant nodes/edges +const edges = graph.getConnectedEdges(node, { deep: true, incoming: true }) // Returns incoming edges, including those connected to all descendant nodes/edges +const edges = graph.getConnectedEdges(node, { deep: true, enclosed: true }) // Returns incoming and outgoing edges, including edges connecting descendant nodes/edges + +const edges = graph.getConnectedEdges(node, { indirect: true }) // Returns incoming and outgoing edges, including indirectly connected edges +``` + +### getRootNodes() + +```ts +getRootNodes(): Node[] +``` + +Get all root nodes, i.e., nodes without incoming edges. + +### isRootNode(...) + +```ts +isRootNode(cell: Cell | string): boolean +``` + +Returns whether the specified node is a root node. + +| Name | Type | Required | Default | Description | +|------|----------------|:--------:|---------|----------------------------| +| cell | string \| Cell | ✓ | | Node/Edge ID or Node/Edge. | + +### getLeafNodes() + +```ts +getLeafNodes(): Node[] +``` + +Returns all leaf nodes, i.e., nodes without outgoing edges. + +### isLeafNode(...) + +```ts +isLeafNode(cell: Cell | string): boolean +``` + +Returns whether the specified node is a leaf node. + +| Name | Type | Required | Default | Description | +|------|----------------|:--------:|---------|----------------------------| +| cell | string \| Cell | ✓ | | Node/Edge ID or Node/Edge. | + +### getNeighbors(...) + +```ts +getNeighbors(cell: Cell, options?: GetNeighborsOptions): Cell[] +``` + +Get neighboring nodes. + +| Name | Type | Required | Default | Description | +|------------------|---------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------| +| cell | Cell | ✓ | | Node/Edge. | +| options.incoming | boolean | | - | Whether to include incoming neighboring nodes. By default, includes both incoming and outgoing nodes. When `incoming` is `true`, only returns incoming nodes. | +| options.outgoing | boolean | | - | Whether to include outgoing neighboring nodes. By default, includes both incoming and outgoing nodes. When `outgoing` is `true`, only returns outgoing nodes. | +| options.deep | boolean | | `false` | Whether to recursively get all child nodes/edges. When `true`, it will also return neighboring nodes of all descendant nodes/edges. | +| options.indirect | boolean | | `false` | Whether to include indirectly connected neighboring nodes, i.e., neighbors connected through multiple edges (edge-to-edge connections). | + +### isNeighbor(...) + +```ts +isNeighbor(cell1: Cell, cell2: Cell, options?: GetNeighborsOptions): boolean +``` + +Returns whether `cell2` is a neighbor of `cell1`. The `options` are the same as those in the [`getNeighbors(...)`](#getneighbors) method. + +### getPredecessors(...) + +```ts +getPredecessors(cell: Cell, options?: GetPredecessorsOptions): Cell[] +``` + +Returns the predecessor nodes of a node, i.e., nodes connected from the root node to the specified node. + +| Name | Type | Required | Default | Description | +|----------------------|-------------------------------------------------------|:--------:|---------|---------------------------------------------------------------------------------------------------------------| +| cell | Cell | ✓ | | Node/Edge. | +| options.breadthFirst | boolean | | `false` | Whether to use breadth-first search algorithm. By default, uses depth-first search algorithm. | +| options.deep | boolean | | `false` | Whether to recursively get all child nodes/edges. When `true`, it will also return predecessors of all descendant nodes/edges. | +| options.distance | number \| number[] \| ((distance: number) => boolean) | | - | Get predecessors at a specified distance. The number of edges between nodes is considered as 1 distance unit. | + +### isPredecessor(...) + +```ts +isPredecessor(cell1: Cell, cell2: Cell, options?: GetPredecessorsOptions): boolean +``` + +Returns whether `cell2` is a predecessor of `cell1`. The `options` are the same as those in the [`getPredecessors(...)`](#getpredecessors) method. + +### getSuccessors(...) + +```ts +getSuccessors(cell: Cell, options?: GetPredecessorsOptions): Cell[] +``` + +Get all successor nodes, i.e., nodes connected from the specified node to leaf nodes. The `options` are the same as those in the [`getPredecessors(...)`](#getpredecessors) method. + +### isSuccessor(...) + +```ts +isSuccessor(cell1: Cell, cell2: Cell, options?: GetPredecessorsOptions): boolean +``` + +Returns whether `cell2` is a successor of `cell1`. The `options` are the same as those in the [`getPredecessors(...)`](#getpredecessors) method. + +### getCommonAncestor(...) + +```ts +getCommonAncestor(...cells: {Cell | Cell[])[]): Cell | null +``` + +Get the common ancestor node of the specified nodes. + +### getSubGraph(...) + +```ts +getSubGraph(cells: Cell[], options?: GetSubgraphOptions): Cell[] +``` + +Returns a subgraph consisting of the specified nodes and edges. It traverses the given `cells` array, including the source and target nodes when encountering an edge; when encountering a node, it includes the edge if both nodes connected by the edge are in the `cells` array. + +| Name | Type | Required | Default | Description | +|--------------|---------|:--------:|---------|------------------------------------------------| +| cells | Cell[] | ✓ | | Array of nodes/edges. | +| options.deep | boolean | | `false` | Whether to recursively get all child nodes/edges. | + +### cloneCells(...) + +```ts +cloneCells(cells: Cell[]): { [oldCellId: string]: Cell } +``` + +Clone cells, returning a key-value pair of old node/edge IDs and cloned nodes/edges. + +### cloneSubGraph(...) + +```ts +cloneSubGraph(cells: Cell[], options?: GetSubgraphOptions): { [oldCellId: string]: Cell } +``` + +Get and clone a subgraph. The `options` are the same as those in the [`getSubGraph(...)`](#getsubgraph) method. + +### getNodesFromPoint(...) + +```ts +getNodesFromPoint(x: number, y: number): Node[] +getNodesFromPoint(p: Point.PointLike): Node[] +``` + +Returns nodes at the specified position, i.e., nodes whose rectangular area contains the specified point. + +### getNodesInArea(...) + +```ts +getNodesInArea( + x: number, + y: number, + w: number, + h: number, + options?: Model.GetCellsInAreaOptions, +): Node[] +getNodesInArea( + rect: Rectangle.RectangleLike, + options?: Model.GetCellsInAreaOptions, +): Node[] +``` + +Returns nodes in the specified rectangular area. When `options.strict` is `true`, it requires the node's rectangular area to be completely contained within the specified rectangle; otherwise, intersection is sufficient. + +### getNodesUnderNode(...) + +```ts +getNodesUnderNode( + node: Node, + options?: { + by?: 'bbox' | Rectangle.KeyPoint + }, +): Node[] +``` + +Returns nodes at the position of the specified node. The `options.by` option specifies the method of retrieval, including: + +- `null` or `bbox`: Returns nodes that intersect with the specified node's rectangular area +- `Rectangle.KeyPoint`: Returns nodes that contain a specific key point of the rectangle, where `Rectangle.KeyPoint` can be one of: + - `"center"` + - `"origin"` + - `"corner"` + - `"topLeft"` + - `"topCenter"` + - `"topRight"` + - `"bottomLeft"` + - `"bottomCenter"` + - `"bottomRight"` + - `"leftMiddle"` + - `"rightMiddle"` + +### searchCell(...) + +```ts +searchCell(cell: Cell, iterator: SearchIterator, options?: SearchOptions): this +``` + +Traverse starting from the specified node/edge. + +| Name | Type | Required | Default | Description | +|----------------------|---------------------------------------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------| +| cell | Cell | ✓ | | Node/Edge. | +| iterator | (cell: Cell, distance: number) => any | ✓ | | Traversal method. | +| options.breadthFirst | boolean | | `false` | Whether to use breadth-first search algorithm. By default, uses depth-first search algorithm. | +| options.incoming | boolean | | - | Whether to traverse incoming neighboring nodes. By default, traverses both incoming and outgoing nodes. When `incoming` is `true`, only traverses incoming nodes. | +| options.outgoing | boolean | | - | Whether to traverse outgoing neighboring nodes. By default, traverses both incoming and outgoing nodes. When `outgoing` is `true`, only traverses outgoing nodes. | +| options.deep | boolean | | `false` | Whether to recursively traverse all child nodes/edges. When `true`, it will also traverse neighboring nodes of all descendant nodes/edges. | +| options.indirect | boolean | | `false` | Whether to traverse indirectly connected neighboring nodes, i.e., neighbors connected through multiple edges (edge-to-edge connections). | + +### getShortestPath(...) + +```ts +getShortestPath( + source: Cell | string, + target: Cell | string, + options?: GetShortestPathOptions, +): string[] +``` + +Get the shortest path between nodes, returning the node IDs on the shortest path. + +| Name | Type | Required | Default | Description | +|------------------|----------------------------------|:--------:|----------------|---------------------------------------------------------------------------------------------------------------| +| source | Cell \| string | ✓ | | Start node/edge. | +| target | Cell \| string | ✓ | | End node/edge. | +| options.directed | boolean | | `false` | Whether to consider directionality. When `true`, the path must follow the direction from start node to end node. | +| options.weight | (u: string, v: string) => number | | `(u, v) => 1` | Distance weight algorithm. `u` and `v` are adjacent nodes, default distance is `1`. | + +### getAllCellsBBox(...) + +```ts +getAllCellsBBox(): Rectangle | null +``` + +Returns the rectangular area of all nodes and edges on the canvas. + +### getCellsBBox(...) + +```ts +getCellsBBox(cells: Cell[], options?: Cell.GetCellsBBoxOptions): Rectangle | null +``` + +Returns the rectangular area formed by the specified nodes and edges. + +| Name | Type | Required | Default | Description | +|--------------|---------|:--------:|---------|----------------------------------------------------| +| cells | Cell[] | ✓ | | Array of nodes and edges. | +| options.deep | boolean | | `false` | Whether to include all descendant nodes and edges. | + +### toJSON(...) + +```ts +toJSON(options?: ToJSONOptions): object +``` + +Export nodes and edges in the graph, returning an object with a `{ cells: [] }` structure, where the `cells` array stores nodes and edges in rendering order. + +| Name | Type | Required | Default | Description | +|--------------|------|:--------:|---------|-------------------------------------------------------------------------------------------------------------------------------| +| options.deep | diff | | `false` | Whether to export differential data of nodes and edges (parts that differ from the [default configuration](/docs/api/model/cell#default-options) of nodes and edges). | + +### parseJSON(...) + +Convert specified data to nodes and edges. + +Supports an array of node/edge metadata, returning created nodes and edges in array order. + +```ts +parseJSON(cells: (Node.Metadata | Edge.Metadata)[]): (Node | Edge)[] +``` + +Or provide an object containing `cells`, `nodes`, `edges`, creating and returning nodes and edges in the order of `[...cells, ...nodes, ...edges]`. + +```ts +parseJSON({ + cells?: (Node.Metadata | Edge.Metadata)[], + nodes?: Node.Metadata[], + edges?: Edge.Metadata[], +}): (Node | Edge)[] +``` + +### fromJSON(...) + +Render nodes and edges according to the specified JSON data. + +Supports an array of node/edge metadata, rendering nodes and edges in array order. + +```ts +fromJSON(data: (Node.Metadata | Edge.Metadata)[], options?: FromJSONOptions): this +``` + +Or provide an object containing `cells`, `nodes`, `edges`, rendering in the order of `[...cells, ...nodes, ...edges]`. + +```ts +fromJSON( + data: { + cells?: (Node.Metadata | Edge.Metadata)[], + nodes?: Node.Metadata[], + edges?: Edge.Metadata[], + }, + options?: FromJSONOptions, +): this +``` + +When `options.silent` is `true`, it does not trigger `cell:added`, `node:added`, and `edge:added` events or canvas redrawing. diff --git a/sites/x6-sites/docs/api/mvc/view.en.md b/sites/x6-sites/docs/api/mvc/view.en.md new file mode 100644 index 00000000000..376ef954639 --- /dev/null +++ b/sites/x6-sites/docs/api/mvc/view.en.md @@ -0,0 +1,201 @@ +--- +title: View +order: 7 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/mvc +--- + +## Configuration + +### async + +Whether the canvas is rendered asynchronously. Asynchronous rendering does not block the UI and significantly improves performance when adding a large number of nodes and edges. However, it's important to note that some synchronous operations may produce unexpected results, such as getting the view of a node or getting the bounding box of nodes/edges, because these synchronous operations may be triggered before the asynchronous rendering is complete. + +### virtual + +Whether to render only the elements in the visible area, default is `false`. If set to `true`, the initial screen load will only render elements in the current visible area. When dragging or zooming the canvas, the remaining elements will be automatically loaded based on the canvas window size. This significantly improves performance in scenarios with a large number of elements. + +### magnetThreshold + +The number of mouse movements required before triggering a connection, or set to 'onleave' to trigger a connection when the mouse leaves the element. Default is `0`. + +### moveThreshold + +The number of mouse movements allowed before triggering the 'mousemove' event, default is `0`. + +### clickThreshold + +When the number of mouse movements exceeds the specified number, the mouse click event will not be triggered. Default is `0`. + +### preventDefaultContextMenu + +Whether to disable the default right-click menu of the canvas, default is `true`. + +### preventDefaultBlankAction + +Whether to disable the default mouse behavior when responding to mouse events in blank areas of the canvas, default is `true`. + +### onPortRendered + +```ts +( + this: Graph, + args: { + node: Node + port: Port + container: Element + selectors?: Markup.Selectors + labelContainer: Element + labelSelectors?: Markup.Selectors + contentContainer: Element + contentSelectors?: Markup.Selectors + }, +) => void +``` + +Callback triggered when a port is rendered, with the following parameters: + +| Name | Type | Required | Description | +|------------------|------------------|:--------:|------------------------------------------------| +| node | Node | ✓ | Node instance. | +| port | Port | ✓ | Port options. | +| container | Element | ✓ | Container element of the port. | +| selectors | Markup.Selectors | | Selector key-value pairs after port Markup rendering. | +| labelContainer | Element | ✓ | Container element of the port label. | +| labelSelectors | Markup.Selectors | | Selector key-value pairs after port label Markup rendering. | +| contentContainer | Element | ✓ | Container element of the port content. | +| contentSelectors | Markup.Selectors | | Selector key-value pairs after port content Markup rendering. | + +For example, we can render a React-type port: + +```tsx +const graph = new Graph({ + container: this.container, + onPortRendered(args) { + const selectors = args.contentSelectors + const container = selectors && selectors.foContent + if (container) { + ReactDOM.render( + +
+ , + container, + ) + } + }, +}) +``` + +### onEdgeLabelRendered + +```ts +( + this: Graph, + args: { + edge: Edge + label: Edge.Label + container: Element + selectors: Markup.Selectors + }, +) => void +``` + +Callback triggered when an edge's text label is rendered, with the following parameters: + +| Name | Type | Required | Description | +|-----------|------------------|:--------:|------------------------------------------------| +| edge | Edge | ✓ | Edge instance. | +| label | Edge.Label | ✓ | Text label options. | +| container | Element | ✓ | Text label container. | +| selectors | Markup.Selectors | ✓ | Selector key-value pairs after text label Markup rendering. | + +We can add a `` element when defining the Label Markup to support HTML and React rendering capabilities. + +```tsx +const graph = new Graph({ + container: this.container, + onEdgeLabelRendered: (args) => { + const { selectors } = args + const content = selectors.foContent as HTMLDivElement + + if (content) { + content.style.display = 'flex' + content.style.alignItems = 'center' + content.style.justifyContent = 'center' + ReactDOM.render(, content) + } + }, +}) +``` + +### createCellView + +```ts +(this: Graph, cell: Cell) => CellView | null | undefined +``` + +Customize the view of an element. It can return a `CellView` to replace the default view. If it returns `null`, the element won't be rendered. If it returns `undefined`, the element will be rendered in the default way. + +## Methods + +### findView(...) + +```ts +findView(ref: Cell | Element): CellView | null +``` + +Find the corresponding view based on the node/edge or element. + +### findViewByCell(...) + +```ts +findViewByCell(cellId: string | number): CellView | null +findViewByCell(cell: Cell | null): CellView | null +``` + +Find the corresponding view based on the node/edge ID or instance. + +### findViewByElem(...) + +```ts +findViewByElem(elem: string | Element | undefined | null): CellView | null +``` + +Find the corresponding view based on the element selector or element object. + +### findViewsFromPoint(...) + +```ts +findViewsFromPoint(x: number, y: number): CellView[] +findViewsFromPoint(p: Point.PointLike): CellView[] +``` + +Return views of nodes/edges whose bounding boxes contain the specified point. + +### findViewsInArea(...) + +```ts +findViewsInArea( + x: number, + y: number, + width: number, + height: number, + options?: FindViewsInAreaOptions, +): CellView[] +findViewsInArea( + rect: Rectangle.RectangleLike, + options?: FindViewsInAreaOptions, +): CellView[] +``` + +Return views of nodes/edges whose bounding boxes intersect with the specified rectangle. When `options.strict` is `true`, the bounding box of the node/edge must completely contain the specified rectangle. + +### findViews(...) + +```ts +findViews(ref: Point.PointLike | Rectangle.RectangleLike): CellView[] +``` + +Return views of nodes/edges whose bounding boxes contain the specified point or intersect with the specified rectangle. diff --git a/sites/x6-sites/docs/api/registry/attr.en.md b/sites/x6-sites/docs/api/registry/attr.en.md new file mode 100644 index 00000000000..9a4846e0e5e --- /dev/null +++ b/sites/x6-sites/docs/api/registry/attr.en.md @@ -0,0 +1,881 @@ +--- +title: Attributes +order: 13 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +X6 provides a wide range of built-in attributes as well as methods for custom attributes. + +## Built-in Attributes + +### ref + +Specifies a selector pointing to an element, which serves as the reference element. + +```typescript +graph.addNode({ + ..., + markup: [ + { + tagName: 'rect', + selector: 'body,' + }, + { + tagName: 'rect', + selector: 'custom,' + } + ], + attrs: { + body: { + width: 100, + height: 50, + }, + // The length and width of the custom element are half of the body + custom: { + ref: 'body', + refWidth: 0.5, + refHeight: 0.5, + } + } +}) +``` + +### refX + +Sets the `x` coordinate of the element. The target `x` coordinate is relative to the `x` coordinate of the top-left corner of the element referenced by [`ref`](#ref). + +- When its value is between `[0, 1]` or a percentage (e.g., `50%`), it represents the relative offset of the target `x` coordinate as a percentage of the reference element's width from the reference `x` coordinate. For example, `refX: 0.5` means the target `x` coordinate is offset to the right by 50% of the reference width from the reference `x` coordinate. +- When its value is `<0` or `>1`, it represents the absolute offset of the target `x` coordinate from the reference `x` coordinate. For example, `refX: 20` means the target `x` coordinate is offset 20px to the right from the reference `x` coordinate. + +### refX2 + +Same as [`refX`](#refx), used when both relative and absolute offsets need to be specified simultaneously. + +```ts +{ + refX: '50%', + refX2: 20, +} +``` + +The above code indicates that the target `x` coordinate is offset 50% of the reference element's width to the right from the reference `x` coordinate, plus an additional 20px. + +### refY + +Sets the `y` coordinate of the element. The target `y` coordinate is relative to the `y` coordinate of the top-left corner of the element referenced by [`ref`](#ref) (reference `y` coordinate). + +- When its value is between `[0, 1]` or a percentage (e.g., `50%`), it represents the relative offset of the target `y` coordinate as a percentage of the reference element's height from the reference `y` coordinate. For example, `refY: 0.5` means the target `y` coordinate is offset downward by 50% of the reference height from the reference `y` coordinate. +- When its value is `<0` or `>1`, it represents the absolute offset of the target `y` coordinate from the reference `y` coordinate. For example, `refY: 20` means the target `y` coordinate is offset 20px downward from the reference `y` coordinate. + +### refY2 + +Same as [`refY`](#refy), used when both relative and absolute offsets need to be specified simultaneously. + +```ts +{ + refY: '50%', + refY2: 20, +} +``` + +The above code indicates that the target `y` coordinate is offset 50% of the reference element's height downward from the reference `y` coordinate, plus an additional 20px. + +### refDx + +Sets the `x` coordinate of the element. The target `x` coordinate is relative to the `x` coordinate of the bottom-right corner of the element referenced by [`ref`](#ref) (reference `x` coordinate). + +- When its value is between `[0, 1]` or a percentage (e.g., `50%`), it represents the relative offset of the target `x` coordinate as a percentage of the reference element's width from the reference `x` coordinate. For example, `refDx: 0.5` means the target `x` coordinate is offset to the right by 50% of the reference width from the reference `x` coordinate. +- When its value is `<0` or `>1`, it represents the absolute offset of the target `x` coordinate from the reference `x` coordinate. For example, `refDx: 20` means the target `x` coordinate is offset 20px to the right from the reference `x` coordinate. + +### refDy + +Sets the `y` coordinate of the element. The target `y` coordinate is relative to the `y` coordinate of the bottom-right corner of the element referenced by [`ref`](#ref) (reference `y` coordinate). + +- When its value is between `[0, 1]` or a percentage (e.g., `50%`), it represents the relative offset of the target `y` coordinate as a percentage of the reference element's height from the reference `y` coordinate. For example, `refDy: 0.5` means the target `y` coordinate is offset downward by 50% of the reference height from the reference `y` coordinate. +- When its value is `<0` or `>1`, it represents the absolute offset of the target `y` coordinate from the reference `y` coordinate. For example, `refDy: 20` means the target `y` coordinate is offset 20px downward from the reference `y` coordinate. + +### refWidth + +Sets the width of the element. The width is calculated relative to the width of the element referenced by [`ref`](#ref) (reference width). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's width as a percentage of the reference width. For example, `refWidth: 0.75` means the element's width is 75% of the reference width. +- When its value is `<0` or `>1`, it represents how much the element's width is decreased or increased based on the reference width. For example, `refWidth: 20` means the element is 20px wider than the reference element. + +:::warning{title=Note} +This attribute only applies to elements that support width and height, such as the `` element. +::: + +### refWidth2 + +Same as [`refWidth`](#refwidth), used when both absolute and relative widths need to be specified simultaneously. + +```ts +{ + refWidth: '75%', + refWidth2: 20, +} +``` + +The above code indicates that the target width is 75% of the reference width plus an additional 20px. + +### refHeight + +Sets the height of the element. The height is calculated relative to the height of the element referenced by [`ref`](#ref) (reference height). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's height as a percentage of the reference height. For example, `refHeight: 0.75` means the element's height is 75% of the reference height. +- When its value is `<0` or `>1`, it represents how much the element's height is decreased or increased based on the reference height. For example, `refHeight: 20` means the element is 20px taller than the reference element. + +:::warning{title=Note} +This attribute only applies to elements that support width and height, such as the `` element. +::: + +### refHeight2 + +Same as [`refHeight`](#refheight), used when both absolute and relative heights need to be specified simultaneously. + +```ts +{ + refHeight: '75%', + refHeight2: 20, +} +``` + +The above code indicates that the target height is 75% of the reference height plus an additional 20px. + +### refCx + +Sets the center `x` coordinate of the element, i.e., the [native `cx` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cx). The target value is calculated relative to the width of the element referenced by [`ref`](#ref) (reference width). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's `cx` as a percentage of the reference width. For example, `refCx: 0.75` means the element's center `x` coordinate is at 75% of the reference width. +- When its value is `<0` or `>1`, it represents how much the element's `cx` is decreased or increased based on the reference width. For example, `refCx: 20` means the element's center `x` coordinate is at the reference width plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support `cx` and `cy` attributes, such as the `` element. +::: + +### refCy + +Sets the center `y` coordinate of the element, i.e., the [native `cy` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cy). The target value is calculated relative to the height of the element referenced by [`ref`](#ref) (reference height). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's `cy` as a percentage of the reference height. For example, `refCy: 0.75` means the element's center `y` coordinate is at 75% of the reference height. +- When its value is `<0` or `>1`, it represents how much the element's `cy` is decreased or increased based on the reference height. For example, `refCy: 20` means the element's center `y` coordinate is at the reference height plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support `cx` and `cy` attributes, such as the `` element. +::: + +### refRx + +Sets the [`rx` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx) of the element. The target value is calculated relative to the width of the element referenced by [`ref`](#ref) (reference width). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's `rx` as a percentage of the reference width. For example, `refRx: 0.75` means the element's `rx` is 75% of the reference width. +- When its value is `<0` or `>1`, it represents how much the element's `rx` is decreased or increased based on the reference width. For example, `refRx: 20` means the element's `rx` is the reference width plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support `rx` and `ry` attributes, such as the `` element. +::: + +### refRy + +Sets the [`ry` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ry) of the element. The target value is calculated relative to the height of the element referenced by [`ref`](#ref) (reference height). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents the element's `ry` as a percentage of the reference height. For example, `refRy: 0.75` means the element's `ry` is 75% of the reference height. +- When its value is `<0` or `>1`, it represents how much the element's `ry` is decreased or increased based on the reference height. For example, `refRy: 20` means the element's `ry` is the reference height plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support `rx` and `ry` attributes, such as the `` element. +::: + +### refRCircumscribed + +Sets the [`r` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r) of the element. The target value is relative to the **diagonal length** of the element referenced by [`ref`](#ref) (reference length). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents `r` as a percentage of the reference length. For example, `refRCircumscribed: 0.75` means `r` is 75% of the reference length. +- When its value is `<0` or `>1`, it represents how much `r` is decreased or increased based on the reference length. For example, `refRCircumscribed: 20` means `r` is the reference length plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support the `r` attribute, such as the `` element. +::: + +### refRInscribed + +_Alias_: **`refR`** + +Sets the [`r` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r) of the element. The target value is relative to the **minimum of the width and height** of the element referenced by [`ref`](#ref) (reference length). + +- When its value is between `[0, 1]` or a percentage (e.g., `75%`), it represents `r` as a percentage of the reference length. For example, `refRInscribed: 0.75` means `r` is 75% of the reference length. +- When its value is `<0` or `>1`, it represents how much `r` is decreased or increased based on the reference length. For example, `refRInscribed: 20` means `r` is the reference length plus 20px. + +:::warning{title=Note} +This attribute only applies to elements that support the `r` attribute, such as the `` element. +::: + +### refDKeepOffset + +Sets the [`d` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) of the `` element. It scales the original pathData to make the target `` element the same size as the element referenced by [`ref`](#ref), and translates the original pathData to align the starting point of the target `` element with the starting point of the element referenced by [`ref`](#ref). + +At the same time, the offset of the provided pathData will be preserved, which means that if the top-left corner of the provided pathData is not at the coordinate origin `0, 0`, this offset will be preserved when the `` element is rendered on the canvas. + +```ts +import { Graph, Node } from '@antv/x6' + +const Path = Node.define({ + markup: [{ tagName: 'path' }], + attrs: { + path: { + refDKeepOffset: 'M 10 10 30 10 30 30 z', // path offset is 10,10 + fill: 'red', + stroke: 'black', + }, + }, +}) + +const container = document.getElementById('container')! +const graph = new Graph({ + container, + width: 800, + height: 80, + grid: true, +}) + +const path = new Path().resize(40, 40).addTo(graph) +const view = graph.findView(path) +console.log(view.findOne('path').getAttribute('d')) +// 'M 10 10 50 10 50 50 z' +``` + +### refDResetOffset + +_Alias_: **`refD`** + +Sets the [`d` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) of the `` element. It scales the original pathData to make the target `` element the same size as the element referenced by [`ref`](#ref), and translates the original pathData to align the starting point of the target `` element with the starting point of the element referenced by [`ref`](#ref). + +At the same time, the offset of the provided pathData will be removed, which means that if the top-left corner of the provided pathData is not at the coordinate origin `0, 0`, it will also be translated to the origin, and when the `` element is rendered on the canvas, it will be strictly aligned with the reference element. + +```ts +import { Graph, Node } from '@antv/x6' + +const Path = Node.define({ + markup: [{ tagName: 'path' }], + attrs: { + path: { + refDResetOffset: 'M 10 10 30 10 30 30 z', // path offset is 10,10 + fill: 'red', + stroke: 'black', + }, + }, +}) + +const container = document.getElementById('container')! +const graph = new Graph({ + container, + width: 800, + height: 80, + grid: true, +}) + +const path = new Path().resize(40, 40).addTo(graph) +const view = graph.findView(path) +console.log(view.findOne('path').getAttribute('d')) +// 'M 0 0 40 0 40 40 z' +``` + +### resetOffset + +When the `resetOffset` property value is `true`, the point matrix will be translated so that the top-left corner of the matrix is at the origin. + +```ts +path.attr({ + path: { + d: 'M 10 10 20 20', + resetOffset: true, // The d attribute value after translation is "M 0 0 10 10" + }, +}) +``` + +### refPointsKeepOffset + +Sets the [points attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/points) of `` or `` elements by scaling the original point matrix to make the target element the same size as the reference element specified by [`ref`](#ref), and translating the original point matrix to align the starting coordinates of the target element with the starting coordinates of the reference element specified by [`ref`](#ref). + +At the same time, the offset of the point matrix will be preserved, which means that if the top-left corner of the point matrix is not at the coordinate origin `0, 0`, this offset will be preserved when the element is rendered on the canvas. + +```ts +import { Graph, Node } from '@antv/x6' + +const Polygon = Node.define({ + markup: [{ tagName: 'polygon' }], + attrs: { + polygon: { + refPointsKeepOffset: '10,10 30,10 30,30', // points offset is 10,10 + fill: 'red', + stroke: 'black', + }, + }, +}) + +const container = document.getElementById('container')! +const graph = new Graph({ + container, + width: 800, + height: 80, + grid: true, +}) + +const polygon = new Polygon().resize(40, 40).addTo(graph) +const view = graph.findView(polygon) +console.log(view.findOne('polygon').getAttribute('points')) +// '10,10 50,10 50,50' +``` + +### refPointsResetOffset + +_Alias_: **`refPoints`** + +Sets the [points attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/points) of `` or `` elements by scaling the original point matrix to make the target element the same size as the reference element specified by [`ref`](#ref), and translating the original point matrix to align the starting coordinates of the target element with the starting coordinates of the reference element specified by [`ref`](#ref). + +At the same time, the offset of the point matrix will be removed, which means that if the top-left corner of the point matrix is not at the coordinate origin `0, 0`, it will be translated to the origin simultaneously. When the `` element is rendered on the canvas, it will be strictly aligned with the reference element. + +```ts +import { Graph, Node } from '@antv/x6' + +const Polygon = Node.define({ + markup: [{ tagName: 'polygon' }], + attrs: { + polygon: { + refPointsResetOffset: '10,10 30,10 30,30', // points offset is 10,10 + fill: 'red', + stroke: 'black', + }, + }, +}) + +const container = document.getElementById('container')! +const graph = new Graph({ + container, + width: 800, + height: 80, + grid: true, +}) + +const polygon = new Polygon().resize(40, 40).addTo(graph) +const view = graph.findView(polygon) +console.log(view.findOne('polygon').getAttribute('points')) +// '100,0 40,0 40,40' +``` + +### xAlign + +The horizontal alignment of the element with its `x` coordinate. + +- `'left'` The left side of the target element aligns with `x`. +- `'middle'` The center of the target element aligns with `x`. +- `'right'` The right side of the target element aligns with `x`. + +### yAlign + +The vertical alignment of the element with its `y` coordinate. + +- `'top'` The top of the target element aligns with `y`. +- `'middle'` The center of the target element aligns with `y`. +- `'bottom'` The bottom of the target element aligns with `y`. + + + +### 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 `` child element to the specified element. The `<title>` element does not affect the rendering result but only adds a descriptive explanation. + +```ts +rect.attr('body/title', 'Description of the rectangle') +``` + +### text + +Only applicable to `<text>` elements, used to set the text content. If the provided text is a single line (does not contain newline characters `'\n'`), the text is directly set as the content of the `<text>` element; otherwise, a `<tspan>` element is created for each line of text and then added to the `<text>` element. + +### textWrap + +Only applicable to `<text>` elements, used to set the text content. Unlike the [`text`](#text) attribute, this attribute automatically adds line breaks to the text, making the provided text completely enclosed within the bounding box of the reference element. + +Its attribute value is a simple object, specifying the text content through `text`. Optional `width` and `height` options can be provided to adjust the size of the element. When negative, it indicates reducing the corresponding width or height (equivalent to setting a padding margin for the text); when positive, it increases the corresponding width or height; when a percentage, it indicates how much percentage of the reference element's width or height. + +When the provided text exceeds the display range, the text will be automatically truncated. If the `ellipsis` option is set to `true`, an ellipsis `...` will be added at the end of the truncated text. + +By default, English words will be truncated. If you don't want a complete word to be truncated, you can set `breakWord: false`. In this case, to display the complete word, the text may exceed the width range. + +```ts +textWrap: { + text: 'lorem ipsum dolor sit amet consectetur adipiscing elit', + width: -10, // Width reduced by 10px + height: '50%', // Height is half of the reference element's height + ellipsis: true, // Automatically add ellipsis when text exceeds display range + breakWord: true, // Whether to truncate words +} +``` + +<code id="attrs-text-wrap" src="@/src/api/attrs/text-wrap/index.tsx"></code> + +### textPath + +Only applicable to `<text>` elements, used to render text along a path. + +When the provided attribute value is a string, it indicates that the text is rendered along the path represented by the string (pathData). + +When the provided attribute value is an object, you can specify the rendering path of the text through the `d` option, or specify an SVGPathElement element in a node/edge through the `selector` option, supporting CSS selectors and selectors defined in [Markup](). You can also specify the position of the text on the path through the `startOffset` option, for example, `50%` indicates that the text is at 50% along the path, and `20` indicates that the text is 20px offset from the start of the path. + +### lineHeight + +Only applicable to `<text>` elements, used to specify the [line height](https://www.w3.org/TR/SVG/text.html#LineHeightProperty) of the text. + +### textVerticalAnchor + +Only applicable to `<text>` elements, the vertical alignment of the element with its `y` coordinate. + +- `'top'` The top of the target element aligns with `y`. +- `'middle'` The center of the target element aligns with `y`. +- `'bottom'` The bottom of the target element aligns with `y`. + +<code id="attrs-text-anchor" src="@/src/api/attrs/text-anchor/index.tsx"></code> + +### connection + +Only applicable to the `<path>` element of edges. When this attribute is `true`, it indicates that the edge will be rendered on this element, i.e., setting the [`d`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) of this element to the pathData of the edge. + +```ts +edge.attr('pathSelector', { + connection: true, + stroke: 'red', + fill: 'none', +}) +``` + +It also supports an object with `stubs` and `reserve` options. + +- When `reverse` is `false`: + + - When `stubs` is positive, it indicates the length of the rendered start and end portions. For example, `connection: { stubs: 20 }` means only the first `20px` and last `20px` of the connection are rendered, and the rest is not rendered. + - When `stubs` is negative, it indicates the length of the middle missing (not rendered) portion. For example, `connection: { stubs: -20 }` means there is a `20px` gap in the middle of the connection that is not rendered. + +- When `reverse` is `true`: + - When `stubs` is positive, it indicates the length of the start and end portions that are not rendered. For example, `connection: { stubs: 20 }` means the first `20px` and last `20px` are not rendered. + - When `stubs` is negative, it indicates the length of the middle portion. For example, `connection: { stubs: -20 }` means only the middle `20px` is rendered. + +```ts +edge.attr('pathSelector', { + connection: { stubs: -20, reverse: true }, +}) +``` + +### atConnectionLengthKeepGradient + +_Alias_: **`atConnectionLength`** + +Moves the specified element in the edge to the position at the specified offset and automatically rotates the element so that its direction is consistent with the slope of the edge at that position. + +- When positive, it indicates the offset from the start point of the edge. +- When negative, it indicates the offset from the end point of the edge. + +```ts +edge.attr('rectSelector', { + atConnectionLengthKeepGradient: 30, + // atConnectionLength: 30, + width: 10, + height: 10, + fill: 'red', +}) +``` + +### atConnectionLengthIgnoreGradient + +Move the specified element in the edge to the position at the specified offset, ignoring the direction of the edge. This means it will not automatically rotate the element like the [`atConnectionLengthKeepGradient`](#atconnectionlengthkeepgradient) property. + +- When positive, it represents the offset from the start point of the edge. +- When negative, it represents the offset from the end point of the edge. + +```ts +edge.attr('rectSelector', { + atConnectionLengthIgnoreGradient: 30, + width: 10, + height: 10, + fill: 'red', +}) +``` + +### atConnectionRatioKeepGradient + +_Alias_: **`atConnectionRatio`** + +Moves the specified element in the edge to the specified ratio position `[0, 1]`, and automatically rotates the element to keep its direction consistent with the slope of the edge at that position. + +```ts +edge.attr('rectSelector', { + atConnectionRatioKeepGradient: 0.5, + // atConnectionRatio: 0.5, + width: 10, + height: 10, + fill: 'red', +}) +``` + +### atConnectionRatioIgnoreGradient + +Moves the specified element in the edge to the specified ratio position `[0, 1]`, ignoring the direction of the edge, i.e., it will not automatically rotate the element like the [`atConnectionRatioKeepGradient`](#atconnectionratiokeepgradient) property. + +```ts +edge.attr('rectSelector', { + atConnectionRatioIgnoreGradient: 0.5, + width: 10, + height: 10, + fill: 'red', +}) +``` + +### sourceMarker + +Applicable to all `<path>` elements, adds an SVG element (such as a start arrow) at the start point of the path and automatically rotates the element to keep it consistent with the path direction. For more details, please refer to [this tutorial](/api/model/marker). + +```ts +edge.attr('connection/sourceMarker', { + tagName: 'circle', + fill: '#666', + stroke: '#333', + r: 5, + cx: 5, +}) +``` + +### targetMarker + +Applicable to all `<path>` elements, adds an SVG element (such as an end arrow) at the end point of the path and automatically rotates the element to keep it consistent with the path direction. For more details, please refer to [this tutorial](/api/model/marker). + +:::warning{title=Note} +This element is initially rotated by `180` degrees, and then the rotation angle is automatically adjusted to be consistent with the direction of the path. For example, for a horizontal straight line, if we specify a left-pointing arrow for its start point, we can also specify the same arrow for its end point, and this arrow will automatically point to the right side (automatically rotated by `180` degrees). +::: + +### vertexMarker + +Applicable to all `<path>` elements, used in the same way as [`sourceMarker`](#sourcemarker), adds additional elements at all vertex positions of the `<path>` element. + +### magnet + +When the `magnet` attribute is `true`, it indicates that the element can be connected, i.e., it can be used as the start or end point of a connection during the connection process, similar to a connection port. + +### port + +Specifies a port ID for elements marked as [`magnet`](#magnet). When an edge connects to this element, this ID will be saved in the `source` or `target` of the edge. + +- If it's a string, the string will be used as the port ID. +- If it's an object, the `id` property value of the object will be used as the port ID. + +### event + +Customizes a click event on the specified element, and then you can add a callback for this event on the Graph. + +```ts +node.attr({ + // Represents a delete button, clicking it will delete the node + image: { + event: 'node:delete', + xlinkHref: 'trash.png', + width: 20, + height: 20, + }, +}) + +// Bind event callback, delete the node when triggered +graph.on('node:delete', ({ view, e }) => { + e.stopPropagation() + view.cell.remove() +}) +``` + +### xlinkHref + +Alias for the [`xlink:href`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href) attribute, for example: + +```ts +node.attr({ + image: { + xlinkHref: 'xxx.png', + }, +}) +``` + +### xlinkShow + +Alias for the [`xlink:show`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:show) attribute. + +### xlinkType + +Alias for the [`xlink:type`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:type) attribute. + +### xlinkTitle + +Alias for the [`xlink:title`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:title) attribute. + +### xlinkArcrole + +Alias for the [`xlink:arcrole`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:arcrole) attribute. + +### xmlSpace + +Alias for the [`xml:space`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xml:space) attribute. + +### xmlBase + +Alias for the [`xml:base`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xml:base) attribute. + +### xmlLang + +Alias for the [`xml:lang`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xml:lang) attribute. + +## registry + +We provide two methods, [`register`](#register) and [`unregister`](#unregister), on the `registry` object to register and delete special attributes. + +### register + +```ts +register(entities: { [name: string]: Definition }, force?: boolean): void +register(name: string, entity: Definition, force?: boolean): Definition +``` + +Registers custom attributes. + +### unregister + +```ts +unregister(name: string): Definition | null +``` + +Deletes registered attributes. + +At the same time, we mount the [`register`](#register) and [`unregister`](#unregister) methods as two static methods of `Graph`: `Graph.registerAttr` and `Graph.unregisterAttr`. It is recommended to use these two static methods to register and delete special attributes. + +### Definition + +In the internal implementation, we convert special attributes into attributes that the browser can recognize, so theoretically, the value of special attributes can be of any type, and the definition of special attributes also supports multiple forms. + +#### String + +Defines aliases for native attributes. For example, the definition of the special attribute `xlinkHref` is actually defining a more easily written alias for the [`xlink:href`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href) attribute. + +```ts +// Definition +Graph.registerAttr('xlinkHref', 'xlink:href') + +// Usage +node.attr({ + image: { + xlinkHref: 'xxx.png', + }, +}) +``` + +Before continuing to introduce attribute definitions, let's understand the attribute qualification `qualify` function. Only attribute values that pass the qualification function's judgment will be processed by special attributes. For example, the [`stroke`](#stroke) attribute is only treated as a special attribute (using gradient color to fill the border) when its value is of `Object` type. Let's look at the definition of the qualification function. + +```ts +type QualifyFucntion = ( + this: CellView, // View of the node/edge + val: ComplexAttrValue, // Current attribute value + options: { + elem: Element // Element to which the current attribute is applied + attrs: ComplexAttrs // Key-value pairs of attributes applied to this element + cell: Cell // Node/edge + view: CellView // View of the node/edge + }, +) => boolean // Returns true if it passes the qualification function's judgment +``` + +For example, the definition of the [`stroke`](#stroke) attribute is as follows: + +```ts +export const stroke: Attr.Definition = { + qualify(val) { + // Only trigger special attribute processing logic when the attribute value is an object. + return ObjectExt.isPlainObject(val) + }, + set(stroke, { view }) { + return `url(#${view.graph.defineGradient(stroke as any)})` + }, +} +``` + +#### set + +Sets the attribute definition, suitable for most scenarios. + +```ts +export interface SetDefinition { + qualify?: QualifyFucntion // Qualification function + set: ( + this: CellView, // View of the node/edge + val: ComplexAttrValue, // Current attribute value + options: { + refBBox: Rectangle // Bounding box of the reference element, or a rectangle representing the position and size of the node when there is no reference element + elem: Element // Element to which the current attribute is applied + attrs: ComplexAttrs // Key-value pairs of attributes applied to this element + cell: Cell // Node/edge + view: CellView // View of the node/edge + }, + ) => SimpleAttrValue | SimpleAttrs | void +} +``` + +When the `set` method returns a `string` or `number`, it means to use the return value as the value of the special attribute. This approach is usually used to extend the definition of native attributes, such as the [`stroke`](#stroke) and [`fill`](#fill) attributes that support gradient color filling. + +```ts +// stroke attribute definition +export const stroke: Attr.SetDefinition = { + qualify: ObjectExt.isPlainObject, + set(stroke, { view }) { + // Returns a string, the return value is used as the attribute value of the stroke attribute. + return `url(#${view.graph.defineGradient(stroke as any)})` + }, +} + +// Using the stroke attribute +node.attr({ + rect: { + stroke: {...}, + }, +}) +``` + +When the `set` method returns a simple object, this object is applied to the corresponding element as attribute key-value pairs, such as the [`sourceMarker`](#sourcemarker) and [`targetMarker`](#targetmarker) attributes. + +```ts +export const sourceMarker: Attr.SetDefinition = { + qualify: ObjectExt.isPlainObject, + set(marker: string | JSONObject, { view, attrs }) { + // Returns a simple object, the return value is applied to the corresponding element as attribute key-value pairs. + return { + 'marker-start': createMarker(marker, view, attrs), + } + }, +} +``` + +When the `set` method doesn't have a return value, it indicates that the property assignment is completed within the method itself, such as the [`html`](#html) attribute. + +```ts +export const html: Attr.Definition = { + set(html, { view, elem }) { + // No return value, property assignment is completed within the method + view.$(elem).html(`${html}`) + }, +} +``` + +#### offset + +Offset property definition. + +```ts +export interface OffsetDefinition { + qualify?: QualifyFucntion // Qualification function + offset: ( + this: CellView, // View of the node/edge + val: ComplexAttrValue, // Current attribute value + options: { + refBBox: Rectangle // Bounding box of the reference element, if no reference element, use the rectangle represented by the node's position and size + elem: Element // Element to which the current attribute is applied + attrs: ComplexAttrs // Key-value pairs of attributes applied to the element + cell: Cell // Node/edge + view: CellView // View of the node/edge + }, + ) => Point.PointLike // Returns absolute offset +} +``` + +Returns a `Point.PointLike` object representing absolute offsets in `x` and `y` directions, like the [`xAlign`](#xalign) attribute. + +```ts +export const xAlign: Attr.OffsetDefinition = { + offset(alignment, { refBBox }) { + ... + // Returns the absolute offset on the x-axis + return { x, y: 0 } + }, +} +``` + +#### position + +Position attribute definition. + +```ts +export interface PositionDefinition { + qualify?: QualifyFucntion // Qualification function + offset: ( + this: CellView, // View of the node/edge + val: ComplexAttrValue, // Current attribute value + options: { + refBBox: Rectangle // Bounding box of the reference element, if no reference element, use the rectangle represented by the node's position and size + elem: Element // Element to which the current attribute is applied + attrs: ComplexAttrs // Key-value pairs of attributes applied to the element + cell: Cell // Node/edge + view: CellView // View of the node/edge + }, + ) => Point.PointLike // Returns absolute positioning coordinates +} +``` + +Returns absolute positioning coordinates relative to the node, like the [`refX`](#refx) and [`refDx`](#refdx) attributes. + +```ts +export const refX: Attr.PositionDefinition = { + position(val, { refBBox }) { + ... + // Returns the absolute positioning on the x-axis + return { x, y: 0 } + }, +} +``` diff --git a/sites/x6-sites/docs/api/registry/connection-point.en.md b/sites/x6-sites/docs/api/registry/connection-point.en.md new file mode 100644 index 00000000000..effe0f95e4b --- /dev/null +++ b/sites/x6-sites/docs/api/registry/connection-point.en.md @@ -0,0 +1,161 @@ +--- +title: Connection Point +order: 10 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +The Connection Point and Anchor jointly determine the starting or ending point of an edge. + +- Starting point: Draw a reference line from the center of the first path point or target node (if there is no path point) to the anchor point of the source node, and calculate the intersection point of the reference line and the shape according to the specified connection point calculation method. This intersection point is the starting point of the edge. +- Ending point: Draw a reference line from the center of the last path point or source node (if there is no path point) to the anchor point of the target node, and calculate the intersection point of the reference line and the shape according to the specified connection point calculation method. This intersection point is the ending point of the edge. + +X6 provides the following built-in connection point calculation methods. + +- [boundary](#boundary) Default value, intersection with the boundary of the linked shape. +- [bbox](#bbox) Intersection with the bounding box of the linked element. +- [rect](#rect) Intersection with the rotated rectangular region of the linked element. +- [anchor](#anchor) Use the anchor point as the connection point. + +<code id="connection-point" src="@/src/api/connection-point/playground/index.tsx"></code> + +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 `<ellipse>` element will be recognized as an ellipse, and the intersection point of the ellipse and the reference line will be calculated. Elements that cannot be recognized (such as `text` or `<path>`) will use the bounding box of the shape as the connection point, which is the same as using `'bbox'`. + +Supported parameters are as follows: + +| Parameter Name | Parameter Type | Required | Default Value | Parameter Description | +|--------------------|---------------------------|:-------:|-------------|--------------------------------------------------------------------------------------------------------------------| +| offset | number \| Point.PointLike | No | `0` | Offset of the connection point. | +| stroked | boolean | No | `true` | Whether to consider the stroke width of the shape. | +| insideout | boolean | No | `true` | When the reference line is inside the shape and there is no intersection point, whether to extend the reference line to calculate the intersection point, default is `true`. | +| extrapolate | boolean | No | `false` | When the reference line is outside the shape and there is no intersection point, whether to extend the reference line to calculate the intersection point, default is `false`. This parameter has higher priority than `sticky`. | +| sticky | boolean | No | `false` | When the reference line is outside the shape and there is no intersection point, whether to use the point on the boundary closest to the reference line as the connection point, default is `false`. | +| precision | number | No | `2` | Precision of intersection point calculation. | +| selector | string | No | `undefined` | Selector, used to identify an element, and use the boundary of the element to calculate the intersection point. Default uses the first child element that is not in the `<g>` element in the node. | + +### anchor + +Use the anchor point as the connection point, supporting the following parameters: + +| Parameter Name | Parameter Type | Required | Default Value | Parameter Description | +|---------------|---------------------------|:-------:|--------|-------------| +| offset | number \| Point.PointLike | No | `0` | Offset of the connection point. | + +### bbox + +Intersection point of the bounding box of the linked element and the reference line, supporting the following parameters: + +| Parameter Name | Parameter Type | Required | Default Value | Parameter Description | +|---------------|---------------------------|:-------:|---------|---------------------| +| offset | number \| Point.PointLike | No | `0` | Offset of the connection point. | +| stroked | boolean | No | `false` | Whether to consider the stroke width of the shape. | + +### rect + +Intersection point of the rotated rectangular region of the linked element and the reference line, supporting the following parameters: + +| Parameter Name | Parameter Type | Required | Default Value | Parameter Description | +|---------------|---------------------------|:-------:|---------|---------------------| +| offset | number \| Point.PointLike | No | `0` | Offset of the connection point. | +| stroked | boolean | No | `false` | Whether to consider the stroke width of the shape. | + +## Custom Connection Points + +A connection point definition is a function with the following signature, returning the connection point. + +```ts +export type Definition<T> = ( + line: Line, + view: NodeView, + magnet: SVGElement, + args: T, +) => Point +``` + +| Parameter Name | Parameter Type | Parameter Description | +|----------------|-----------------|---------------------------------| +| line | Line | Reference line. | +| nodeView | NodeView | View of the connected node. | +| magnet | SVGElement | Element on the connected node. | +| args | T | Parameters. | + +After completing the connection point definition, we register the connection point: + +```ts +Graph.registerConnectionPoint('custom-connection-point', ...) +``` + +After registration, we can use the connection point by name: + +```ts +new Graph({ + connecting: { + connectionPoint: 'custom-connection-point' + }, +}) +``` diff --git a/sites/x6-sites/docs/api/registry/connector.en.md b/sites/x6-sites/docs/api/registry/connector.en.md new file mode 100644 index 00000000000..5d737b8aa11 --- /dev/null +++ b/sites/x6-sites/docs/api/registry/connector.en.md @@ -0,0 +1,242 @@ +--- +title: Connector +order: 6 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +The connector processes the start point, route return point, and end point into a `<path>` element's `d` attribute, determining the style of the edge rendering on the canvas. X6 has several built-in connectors. + +| Connector | Description | +|----------|-------------------------------------------------------------------------------------| +| normal | [Simple Connector](#normal), connects the start point, route point, and end point with a straight line. | +| smooth | [Smooth Connector](#smooth), connects the start point, route point, and end point with a cubic Bezier curve. | +| rounded | [Rounded Connector](#rounded), connects the start point, route point, and end point with a straight line and uses an arc to connect the line segments (fillet). | +| jumpover | [Jumpover Connector](#jumpover), connects the start point, route point, and end point with a straight line and uses a jump symbol to connect the intersecting edges. | + +You can set a route for a specific edge: + +```ts +const edge = graph.addEdge({ + source, + target, + connector: { + name: 'rounded', + args: { + radius: 20, + }, + }, +}) +``` + +When there is no connector parameter, it can be simplified to: + +```ts +const edge = graph.addEdge({ + source, + target, + connector: 'rounded', +}) +``` + +You can also call `edge.setConnector` to set the connector: + +```ts +edge.setConnector('rounded', { radius: 20 }) +``` + +When creating a canvas, you can set the global default connector (default is `'normal'`) through the `connecting` option: + +```ts +new Graph({ + connecting: { + connector: { + name: 'rounded', + args: { + radius: 20, + }, + }, + }, +}) +``` + +When there is no route parameter, it can be simplified to: + +```ts +new Graph({ + connecting: { + connector: 'rounded', + }, +}) +``` + +Let's take a look at how to use built-in connectors and how to customize and register custom connectors. + +## Built-in Connectors + +### normal + +The system's default connector, connects the start point, route point, and end point in sequence with a straight line. + +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. | + +<code id="connector-normal" src="@/src/api/connector/normal/index.tsx"></code> + +### 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', +}) +``` + +<code id="connector-smooth" src="@/src/api/connector/smooth/index.tsx"></code> + +### 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, + }, + }, +}) +``` + +<code id="connector-rounded" src="@/src/api/connector/rounded/index.tsx"></code> + +### 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. | + +<code id="connector-jumpover" src="@/src/api/connector/jumpover/index.tsx"></code> + +## Custom Connectors + +A connector is a function with the following signature, returning a `Path` object or a serialized string. + +```ts +export type Definition<T> = ( + this: EdgeView, // Edge view + sourcePoint: Point.PointLike, // Start point + targetPoint: Point.PointLike, // End point + routePoints: Point.PointLike[], // Route return points + args: T, // Connector parameters + edgeView: EdgeView, // Edge view +) => Path | string +``` + +| Parameter Name | Parameter Type | Parameter Description | +|--------------------|-------------------------|-------------------------| +| this | EdgeView | Edge view. | +| sourcePoint | Point.PointLike | Start point. | +| targetPoint | Point.PointLike | End point. | +| routePoints | Point.PointLike[] | Route return points. | +| args | T | Connector parameters. | +| edgeView | EdgeView | Edge view. | + +I'll define a `wobble` connector: + +```ts +export interface WobbleArgs { + spread?: number + raw?: boolean +} + +function wobble( + sourcePoint: Point.PointLike, + targetPoint: Point.PointLike, + vertices: Point.PointLike[], + args: WobbleArgs, +) { + const spread = args.spread || 20 + const points = [...vertices, targetPoint].map((p) => Point.create(p)) + let prev = Point.create(sourcePoint) + const path = new Path(Path.createSegment('M', prev)) + + for (let i = 0, n = points.length; i < n; i += 1) { + const next = points[i] + const distance = prev.distance(next) + let d = spread + + while (d < distance) { + const current = prev.clone().move(next, -d) + current.translate( + Math.floor(7 * Math.random()) - 3, + Math.floor(7 * Math.random()) - 3, + ) + path.appendSegment(Path.createSegment('L', current)) + d += spread + } + + path.appendSegment(Path.createSegment('L', next)) + prev = next + } + + return args.raw ? path : path.serialize() +} +``` + +Then register the connector: + +```ts +Graph.registerConnector('wobble', wobble) +``` + +After registration, we can use it by connector name: + +```ts +edge.setConnector('wobble', { spread: 16 }) +``` +<code id="connector-wobble" src="@/src/api/connector/wobble/index.tsx"></code> 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. + +<code id="edge-anchor-playground" src="@/src/api/edge-anchor/playground/index.tsx"></code> + +## 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.<br>When `fallbackAt` is a percentage string, it represents the proportion of the edge length from the starting point.<br>When `fallbackAt` is a number, it represents the length from the starting point of the edge. | + +## Custom Anchor Points + +The edge anchor point definition is a function with the following signature, which returns the anchor point. + +```ts +export type Definition<T> = ( + this: EdgeView, + view: EdgeView, + magnet: SVGElement, + ref: Point.PointLike | SVGElement, + args: T, +) => Point +``` + +| Parameter Name | Parameter Type | Parameter Description | +|---------------|---------------------------------------|-----------------------| +| this | EdgeView | The view of the edge. | +| view | EdgeView | The view of the connected edge. | +| magnet | SVGElement | The element of the connected edge. | +| ref | Point.PointLike \| SVGElement | The reference point/element. | +| args | T | The arguments. | + +After completing the anchor point definition, we register the anchor point: + +```ts +Graph.registerEdgeAnchor('custom-anchor', ...) +``` + +After registration, we can use the anchor point by name: + +```ts +new Graph({ + connecting: { + edgeAnchor: { + name: 'custom-anchor', + }, + }, +}) +``` \ No newline at end of file diff --git a/sites/x6-sites/docs/api/registry/edge-tool.en.md b/sites/x6-sites/docs/api/registry/edge-tool.en.md new file mode 100644 index 00000000000..0fb48aee0ae --- /dev/null +++ b/sites/x6-sites/docs/api/registry/edge-tool.en.md @@ -0,0 +1,429 @@ +--- +title: Edge Tools +order: 4 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +Since edges are typically narrow lines or curves, interacting with them can be inconvenient. To address this issue, we render a transparent `<path>` shape that matches the edge's shape but is wider, allowing users to interact with the edge more easily. Additionally, we can add small tools to edges to enhance their interactivity, such as vertex tools that allow path points to be moved, and segment tools that enable the movement of segments within the edge. + +**Scenario 1: Adding specified tools.** + +```ts +// Add tools when creating an edge +graph.addEdge({ + source, + target, + tools: [ + { name: 'vertices' }, + { + name: 'button-remove', + args: { distance: 20 }, + }, + ], +}) + +// Add tools after creating an edge +edge.addTools([ + { name: 'vertices' }, + { + name: 'button-remove', + args: { distance: 20 }, + }, +]) +``` + +**Scenario 2: Dynamically adding/removing tools with the mouse.** + +```ts +graph.on('edge:mouseenter', ({ cell }) => { + cell.addTools([ + { name: 'vertices' }, + { + name: 'button-remove', + args: { distance: 20 }, + }, + ]) +}) + +graph.on('edge:mouseleave', ({ cell }) => { + if (cell.hasTool('button-remove')) { + cell.removeTool('button-remove') + } +}) +``` + +In X6, the following tools for edges are provided by default: + +- [vertices](#vertices) Vertex tool, renders a small dot at the position of the path point. Dragging the dot modifies the position of the path point, double-clicking the dot deletes the path point, and clicking on the edge adds a path point. +- [segments](#segments) Segment tool. Renders a tool bar at the center of each segment of the edge, allowing the tool bar to be dragged to adjust the positions of the path points at both ends of the segment. +- [boundary](#boundary) Renders a rectangle surrounding the edge based on its bounding box. Note that this tool only renders a rectangle without any interactivity. +- [button](#button) Renders a button at a specified position, supporting custom click interactions for the button. +- [button-remove](#button-remove) Renders a delete button at a specified position, which deletes the corresponding edge when clicked. +- [source-arrowhead and target-arrowhead](#source-arrowhead-and-target-arrowhead) Renders a shape (default is an arrow) at the start or end of the edge, allowing the shape to be dragged to modify the start or end of the edge. +- [edge-editor](#edge-editor) Provides text editing functionality on the edge. + +## Built-in Tools + +### vertices + +The path point tool renders a small dot at the position of the path point. You can drag the dot to modify the path point's position, double-click the dot to delete the path point, and click on the edge to add a new path point. The configuration is as follows: + +| Parameter Name | Type | Default Value | Description | +|----------------------|---------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------| +| attrs | KeyValue | `object` | Attributes of the small dot. | +| snapRadius | number | `20` | The snap radius during the movement of the path point. When the path point is within the radius of a neighboring path point, it will snap to that point. | +| addable | boolean | `true` | Whether new path points can be added by clicking the mouse on the edge. | +| removable | boolean | `true` | Whether path points can be removed by double-clicking. | +| 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. | +| modifiers | `string \| ModifierKey[]` | - | Keys that must be pressed to add path points, which can resolve the overlap of interactions for adding path points and clicking on edges. | + +The default value (default style) for `attrs` is: + +```ts +{ + r: 6, + fill: '#333', + stroke: '#fff', + cursor: 'move', + 'stroke-width': 2, +} +``` + +The tool is used as follows: + +```ts +// Add the small tool when creating an edge +const edge1 = graph.addEdge({ + ..., + tools: [ + { + name: 'vertices', + args: { + attrs: { fill: '#666' }, + }, + }, + ] +}) +``` + +<code id="api-edge-tool-vertices" src="@/src/api/edge-tool/vertices/index.tsx"></code> + +### 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', + }, + }, + }] +}) +``` + +<code id="api-edge-tool-segments" src="@/src/api/edge-tool/segments/index.tsx"></code> + +### 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, + }, + }, + }, + ] +}) +``` + +<code id="api-edge-tool-boundary" src="@/src/api/edge-tool/boundary/index.tsx"></code> + +### 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) { + // + }, + }, + }, + ], +}) +``` + +<code id="api-edge-tool-button" src="@/src/api/edge-tool/button/index.tsx"></code> + +### 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 }, + }, + ] +}) +``` + +<code id="api-edge-tool-button-remove" src="@/src/api/edge-tool/button-remove/index.tsx"></code> + +### 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() +}) +``` + +<code id="api-edge-tool-arrowhead" src="@/src/api/edge-tool/arrowhead/index.tsx"></code> + +### 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)` + +<code id="api-edge-tool-editor" src="@/src/api/node-tool/node-editor/index.tsx"></code> + +## 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<Vertices.Options>({ + attrs: { + fill: 'red', + }, +}) + +Graph.registerEdgeTool('red-vertices', RedVertices, true) +``` + +<code id="api-edge-tool-custom-vertices" src="@/src/api/edge-tool/custom-vertices/index.tsx"></code> + +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', + }, +}) +``` + +<code id="api-edge-tool-custom-arrowhead" src="@/src/api/edge-tool/custom-arrowhead/index.tsx"></code> 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. | + +<code id="filter-drop-shadow" src="@/src/api/filter/drop-shadow/index.tsx"></code> + +### 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. | + +<code id="filter-blur" src="@/src/api/filter/blur/index.tsx"></code> + +### 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. | + +<code id="filter-gray-scale" src="@/src/api/filter/gray-scale/index.tsx"></code> + +### 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. | + +<code id="filter-sepia" src="@/src/api/filter/sepia/index.tsx"></code> + +### 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]`. | + +<code id="filter-saturate" src="@/src/api/filter/saturate/index.tsx"></code> + +### 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. | + +<code id="filter-hue-rotate" src="@/src/api/filter/hue-rotate/index.tsx"></code> + +### 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. | + +<code id="filter-invert" src="@/src/api/filter/invert/index.tsx"></code> + +### 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. | + +<code id="filter-brightness" src="@/src/api/filter/brightness/index.tsx"></code> + +### 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. | + +<code id="filter-contrast" src="@/src/api/filter/contrast/index.tsx"></code> + +### 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. | + +<code id="filter-highlight" src="@/src/api/filter/highlight/index.tsx"></code> + +### 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. | + +<code id="filter-outline" src="@/src/api/filter/outline/index.tsx"></code> + +## Custom Filters + +A filter definition is a function with the following signature that returns a `<filter>` tag string. + +```ts +export type Definition<T> = (args: T) => string +``` + +For example, the definition of the Gaussian blur filter is: + +```ts +export interface BlurArgs { + x?: number + y?: number +} + +export function blur(args: BlurArgs = {}) { + const x = getNumber(args.x, 2) + const stdDeviation = args.y != null && isFinite(args.y) ? [x, args.y] : x + + return ` + <filter> + <feGaussianBlur stdDeviation="${stdDeviation}"/> + </filter> + `.trim() +} +``` + +We can register a filter by calling the `Graph.registerFilter(...)` method. + +```ts +Graph.registerFilter('blur', blur) +``` diff --git a/sites/x6-sites/docs/api/registry/highlighter.en.md b/sites/x6-sites/docs/api/registry/highlighter.en.md new file mode 100644 index 00000000000..2335af05a8d --- /dev/null +++ b/sites/x6-sites/docs/api/registry/highlighter.en.md @@ -0,0 +1,117 @@ +--- +title: Highlighter +order: 14 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +Node/edge highlighters used to highlight specified elements. X6 includes the following types of highlighters. + +| Name | Description | +|-----------|----------------------------------------------------------| +| stroke | [Stroke Highlighter](#stroke), renders a highlighted border around the bounding box of the element. | +| className | [Class Name Highlighter](#classname), highlights elements by adding additional class names. | + +When creating a Graph, you can specify the highlighting style triggered by certain interactions through the `highlighting` option, such as: + +```ts +new Graph({ + highlighting: { + // When a magnet is available for linking, render a 2px wide red rectangle around the magnet + magnetAvailable: { + name: 'stroke', + args: { + padding: 4, + attrs: { + 'stroke-width': 2, + stroke: 'red', + }, + }, + }, + }, +}) +``` + +Supported `highlighting` configuration options include: + +- `'default'` Default highlighting option, used when the following highlighting configurations are not specified. +- `'embedding'` Used when dragging a node for embedding and the node can be embedded. +- `'nodeAvailable'` Used during the linking process when a node can be linked. +- `'magnetAvailable'` Used during the linking process when a magnet can be linked. +- `'magnetAdsorbed'` Used during the linking process when automatically snapping to a magnet. +## Built-in Highlighters + +### Stroke + +The border highlighter renders a highlighted border along the bounding box of the element. + +| Parameter Name | Type | Default Value | Description | +|----------------|---------|---------------------------------------------|------------------| +| rx | number | `0` | Border radius. | +| ry | number | `0` | Border radius. | +| padding | number | `3` | Padding. | +| attrs | object | `{ 'stroke-width': 3, stroke: '#FEB663' }` | Border element attributes. | + +### ClassName + +The style name highlighter highlights elements by adding an additional style name. + +| Parameter Name | Type | Default Value | Description | +|----------------|---------|---------------------|--------------| +| className | string | `x6-highlighted` | Style name. | + +## Custom Highlighters + +A highlighter is an object with the following signature, containing two methods: `highlight` and `unhighlight`, which are used to highlight and unhighlight elements, respectively. + +```ts +export interface Definition<T> { + highlight: (cellView: CellView, magnet: Element, options: T) => void + unhighlight: (cellView: CellView, magnet: Element, options: T) => void +} +``` + +| Parameter Name | Type | Default Value | Description | +|----------------|----------|---------------|-----------------------| +| cellView | CellView | | View. | +| magnet | Element | | The highlighted element. | +| options | T | | Highlight options. | + + +Now, let's define a highlighter named `opacity`, which adds a `'highlight-opacity'` style name to the element. + +```ts +export interface OpacityHighlighterOptions {} + +const className = 'highlight-opacity' + +export const opacity: Highlighter.Definition<OpacityHighlighterOptions> = { + highlight(cellView, magnet) { + Dom.addClass(magnet, className) + }, + + unhighlight(cellView, magnetEl) { + Dom.removeClass(magnetEl, className) + }, +} +``` + +After defining it, we can register our highlighter: + +```ts +Graph.registerHighlighter('opacity', opacity, true) +``` + +Then we can use this highlighter with the string `opacity`: + +```ts +new Graph({ + highlighting: { + magnetAvailable: { + name: 'opacity', + }, + }, +}) +``` diff --git a/sites/x6-sites/docs/api/registry/node-anchor.en.md b/sites/x6-sites/docs/api/registry/node-anchor.en.md new file mode 100644 index 00000000000..f477c93c599 --- /dev/null +++ b/sites/x6-sites/docs/api/registry/node-anchor.en.md @@ -0,0 +1,250 @@ +--- +title: Node Anchor +order: 8 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +When connecting to a node, you can specify the anchor point of the connected node using `NodeAnchor`, which, together 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 (when there is no path point) 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), which 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 (when there is no path point) 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), which is the ending point of the edge. + +X6 has built-in the following anchor point definitions. + +- [center](#center) The center point of the element connected to the edge (default value). +- [top](#top) The top center point of the element connected to the edge. +- [bottom](#bottom) The bottom center point of the element connected to the edge. +- [left](#left) The left center point of the element connected to the edge. +- [right](#right) The right center point of the element connected to the edge. +- [midSide](#midside) The center point of the nearest side of the element connected to the edge. +- [topLeft](#topleft) The top-left corner of the element connected to the edge. +- [topRight](#topright) The top-right corner of the element connected to the edge. +- [bottomLeft](#bottomleft) The bottom-left corner of the element connected to the edge. +- [bottomRight](#bottomright) The bottom-right corner of the element connected to the edge. +- [orth](#orth) The orthogonal point. +- [nodeCenter](#nodecenter) The center point of the node. + +<code id="node-anchor-playground" src="@/src/api/node-anchor/playground/index.tsx"></code> + +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<T> = ( + this: EdgeView, + nodeView: NodeView, + magnet: SVGElement, + ref: Point.PointLike | SVGElement, + args: T, + type: Edge.TerminalType, +) => Point +``` + +| Parameter Name | Parameter Type | Parameter Description | +|---------------|-------------------------------|-------------------| +| this | EdgeView | The edge view. | +| nodeView | NodeView | The node view. | +| magnet | SVGElement | The magnet element. | +| ref | Point.PointLike \| SVGElement | The reference point/element. | +| args | T | The arguments. | +| type | Edge.TerminalType | The edge terminal type. | + +After completing the anchor point definition, we register the anchor point: + +```ts +Graph.registerAnchor('custom-anchor', ...) +``` + +After registration, we can use the anchor point by name: + +```ts +new Graph({ + connecting: { + anchor: { + name: 'custom-anchor', + }, + }, +}) +``` \ No newline at end of file diff --git a/sites/x6-sites/docs/api/registry/node-tool.en.md b/sites/x6-sites/docs/api/registry/node-tool.en.md new file mode 100644 index 00000000000..9c09b05b6b6 --- /dev/null +++ b/sites/x6-sites/docs/api/registry/node-tool.en.md @@ -0,0 +1,260 @@ +--- +title: Node Tools +order: 3 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +Node tools are small components rendered on nodes that typically come with some interactive features, such as a delete button that removes the corresponding node when clicked. We can add or remove tools based on the following scenarios. + +```ts +// Add tools when creating a node +graph.addNode({ + ..., + tools: [ + { + name: 'button-remove', + args: { x: 10, y: 10 }, + }, + ], +}) + +// Add tools after creating a node +node.addTools([ + { + name: 'button-remove', + args: { x: 10, y: 10 }, + }, +]) + +// Remove tool +graph.on("node:mouseleave", ({ node }) => { + if (node.hasTool("button-remove")) { + node.removeTool("button-remove"); + } +}); +``` + +X6 provides the following default tools for nodes: + +- [button](#button) Renders a button at a specified position, supporting custom click interactions for the button. +- [button-remove](#button-remove) Renders a delete button at a specified position, which deletes the corresponding node when clicked. +- [boundary](#boundary) Renders a rectangle surrounding the node based on the node's bounding box. Note that this tool only renders a rectangle and does not provide any interaction. +- [node-editor](#node-editor) Provides text editing functionality for the node. +## Built-in Tools + +### button + +Renders a button at a specified position, supporting custom click interactions. The configuration is as follows: + +| Parameter Name | Type | Default Value | Description | +|--------------------|------------------------------------------------------------------------|---------------|---------------------------------------------------------------------------------------------------------| +| x | number \| string | `0` | The X coordinate relative to the top-left corner of the node, with decimals and percentages indicating relative positions. | +| y | number \| string | `0` | The Y coordinate relative to the top-left corner of the node, with decimals and percentages indicating relative positions. | +| offset | number \| `{ x: number, y: number }` | `0` | The offset based on `x` and `y`. | +| rotate | boolean | - | Whether to follow the rotation of the node. | +| 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`. | +| markup | Markup.JSONMarkup | - | The Markup definition for rendering the button. | +| onClick | `(args: {e: Dom.MouseDownEvent, cell: Cell, view: CellView }) => void` | - | Callback function for button clicks. | + +```ts +// Add button on mouse hover +graph.on('node:mouseenter', ({ node }) => { + node.addTools({ + name: 'button', + args: { + markup: ..., + x: 0, + y: 0, + offset: { x: 18, y: 18 }, + onClick({ view }) { ... }, + }, + }) +}) + +// Remove button on mouse leave +graph.on('node:mouseleave', ({ node }) => { + node.removeTools() // Remove all tools +}) +``` + +<code id="api-node-tool-button" src="@/src/api/node-tool/button/index.tsx"></code> + +### 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 }, + }, + }, + ], +}) +``` + +<code id="api-node-tool-button-remove" src="@/src/api/node-tool/button-remove/index.tsx"></code> + +### 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, + }, + }, + }, + ], +}) +``` + +<code id="api-node-tool-boundary" src="@/src/api/node-tool/boundary/index.tsx"></code> + +### 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)` + +<code id="api-node-tool-editor" src="@/src/api/node-tool/node-editor/index.tsx"></code> + +## 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<Button.Options>({ + name: 'my-btn', + markup: ..., + onClick({ view }) { ... }, +}) + +Graph.registerNodeTool('my-btn', MyButton, true) +``` + +Additionally, we provide a quick inheritance implementation for the `Graph.registerNodeTool` method to specify default options: + +```ts +Graph.registerNodeTool('my-btn', { + inherit: 'button', // Base class name, using the name of the already registered tool. + markup: ..., + onClick: ..., +}) +``` + +<code id="api-node-tool-custom-button" src="@/src/api/node-tool/custom-button/index.tsx"></code> 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<T> = ( + portPosition: Point, // port position + elemBBox: Rectangle, // node bounding box + args: T, // label position arguments +) => Result + +interface Result { + position: Point.PointLike // label position relative to port + angle: number // label rotation angle + attrs: Attr.CellAttrs // label attributes +} +``` + +When creating a port, you can specify the label layout in the `groups` or override it in `items`: + +```ts +graph.addNode( + ..., + ports: { + // port group + groups: { + group1: { + label: { + position: { // label layout algorithm + name: 'xxx', // label layout algorithm name + args: { ... }, // label layout algorithm arguments + }, + }, + }, + }, + + // port definition + items: [ + { + groups: 'group1', + label: { + position: { // override label layout algorithm specified in group1 + name: 'xxx', + args: { ... }, + } + }, + } + ], + }, +) +``` + +Let's take a look at how to use built-in label layout algorithms and how to define and register custom layout algorithms. + +## Built-in Port Label Layout + +### Side + +The label is located on one side of the port. + +- `'left'` The label is located on the left side of the port. +- `'right'` The label is located on the right side of the port. +- `'top'` The label is located on the top side of the port. +- `'bottom'` The label is located on the bottom side of the port. + +You can specify the label position and rotation angle through `args`. + +```ts +interface SideArgs { + x?: number + y?: number + angle?: number + attrs?: Attr.CellAttrs +} +``` + +| Name | Type | Required | Default Value | Description | +|-------|----------------|:----:|--------|-----------------------------------------| +| 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 : 'right', + args: { + y: 10, // Force the y-coordinate to be 10, replacing the calculated y-coordinate + attrs: { + text: { + fill: 'red', // Set the label color to red + }, + }, + }, + }, +} +``` + +<code id="port-label-layout-side" src="@/src/api/port-label-layout/side/index.tsx"></code> + +### 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', + }, +} +``` + +<code id="port-label-layout-inside-outside" src="@/src/api/port-label-layout/inside-outside/index.tsx"></code> + +### 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', + }, +} +``` + +<code id="port-label-layout-radial" src="@/src/api/port-label-layout/radial/index.tsx"></code> + +## 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<T> = ( + portPosition: Point, // port position + elemBBox: Rectangle, // node bounding box + args: T, // label position arguments +) => Result + +interface Result { + position: Point.PointLike // label position relative to port + angle: number // label rotation angle + attrs: Attr.CellAttrs // label attributes +} +``` + +So we can create a custom layout algorithm according to the above rules, for example, implementing a layout that is located at the bottom right of the port: + +```ts +function bottomRight(portPosition, elemBBox, args) { + const dx = args.dx || 10 + const dy = args.dy || 10 + + return { + position: { + x: portPosition.x + dx, + y: portPosition.y + dy, + } + } +} +``` + +After implementing the layout algorithm, we need to register it to the system. After registration, we can use it like built-in layout algorithms. + +```ts +Graph.registerPortLabelLayout('bottomRight', bottomRight) +``` + +After registration, we can use it like built-in layout algorithms: + +```ts +const rect = graph.addNode({ + ports: { + groups: { + group1: { + position: { + name: 'top', + }, + label: { + position: { + name: 'bottomRight', + }, + }, + }, + }, + + items: [ + { id: 'port1', group: 'group1' }, + { id: 'port2', label: { position: 'bottomRight' } }, + ], + }, +}) +``` \ No newline at end of file diff --git a/sites/x6-sites/docs/api/registry/port-layout.en.md b/sites/x6-sites/docs/api/registry/port-layout.en.md new file mode 100644 index 00000000000..48e31bc56c2 --- /dev/null +++ b/sites/x6-sites/docs/api/registry/port-layout.en.md @@ -0,0 +1,393 @@ +--- +title: Port Layout Algorithm +order: 11 +redirect_from: + - /en/docs + - /en/docs/api + - /en/docs/api/registry +--- + +The port layout algorithm is a function with the following signature, which returns the relative position of the port 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 port is `{ x: 2, y: 4 }`, then the port will be rendered at `{ x: 32, y: 44 }` on the canvas. + +```ts +type Definition<T> = ( + portsPositionArgs: T[], // layout algorithm parameters specified in the port + elemBBox: Rectangle, // bounding box of the node + groupPositionArgs: T, // default layout algorithm parameters defined in the group +) => Result[] + +interface Result { + position: Point.PointLike // relative position to the node + angle?: number // rotation angle +} +``` + +Note that when configuring the port `ports`, we can only configure the layout algorithm through the `groups` option, and provide optional layout algorithm parameters `args` in `items` to affect the layout result. + +```ts +graph.addNode( + ..., + ports: { + // port group + groups: { + group1: { + position: { + name: 'xxx', // layout algorithm name + args: { }, // default parameters of the layout algorithm + }, + }, + }, + + // port definition + items: [ + { + groups: 'group1', + args: { }, // override the default parameters specified in group1 + }, + ], + }, +) +``` + +Let's take a look at how to use the built-in port layout algorithms and how to customize and register custom layout algorithms. + +## Built-in Layouts + +### absolute + +Absolute positioning, specifying the port position through `args`. + +```ts +interface AbsoluteArgs { + x?: string | number + y?: string | number + angle?: number +} +``` + +| Name | Type | Required | Default Value | Description | +|-------|------------------|:----:|--------|----------------------| +| x | string \| number | | `0` | Relative position on the X-axis. | +| y | string \| number | | `0` | Relative position on the Y-axis. | +| angle | number | | `0` | Rotation angle. | + +When `x` and `y` are percentage strings or between `[0, 1]`, they represent the percentage offset in the width and height directions, otherwise, they represent absolute offsets. + +```ts +graph.addNode({ + ports: { + groups: { + group1: { + position: { + name: 'absolute', + args: { x: 0, y: 0 }, + }, + }, + }, + items: [ + { + group: 'group1', + args: { + x: '60%', + y: 32, + angle: 45, + }, + }, + ], + }, +}) +``` + +<code id="port-layout-absolute" src="@/src/api/port-layout/absolute/index.tsx"></code> + +### 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, + }, + }, + ], + }, +}) +``` + +<code id="port-layout-side" src="@/src/api/port-layout/side/index.tsx"></code> + +### 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, + }, + }, + ], + }, +}) +``` + +<code id="port-layout-line" src="@/src/api/port-layout/line/index.tsx"></code> + +### 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 } }, + }) +}) +``` + +<code id="port-layout-ellipse" src="@/src/api/port-layout/ellipse/index.tsx"></code> + +### 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 } }, + }) +}) +``` + +<code id="port-layout-ellipse-spread" src="@/src/api/port-layout/ellipse-spread/index.tsx"></code> + +## 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<T> = ( + portsPositionArgs: T[], // Layout algorithm parameters specified in the connection points + elemBBox: Rectangle, // Node bounding box + groupPositionArgs: T, // Default layout algorithm parameters defined in the group +) => Result[] + +interface Result { + position: Point.PointLike // Relative position to the node + angle?: number // Rotation angle +} +``` + +We can create a custom layout algorithm according to the above rules, for example, implementing a sine distribution layout algorithm: + +```ts +function sin(portsPositionArgs, elemBBox) { + return portsPositionArgs.map((_, index) => { + const step = -Math.PI / 8 + const y = Math.sin(index * step) * 50 + return { + position: { + x: index * 12, + y: y + elemBBox.height, + }, + angle: 0, + } + }) +} +``` + +After implementing the layout algorithm, we need to register it to the system. After registration, we can use it like the built-in layout algorithms. + +```ts +Graph.registerPortLayout('sin', sin) +``` + +After registration, we can use it like the built-in layout algorithms: + +```ts +const rect = graph.addNode({ + ports: { + groups: { + sin: { + position: { + name: 'sin', + args: { + start: 45, + }, + }, + attrs: { + rect: { + fill: '#fe854f', + width: 11, + }, + text: { + fill: '#fe854f', + }, + circle: { + fill: '#fe854f', + r: 5, + magnet: true, + }, + }, + }, + }, + }, +}) + +Array.from({ length: 24 }).forEach(() => { + rect.addPort({ group: 'sin' }) +}) +``` + +<code id="port-layout-sin" src="@/src/api/port-layout/sin/index.tsx"></code> \ 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, + }, + }, + }, +}) +``` + +<code id="api-orth-router" src="@/src/api/router/orth/index.tsx"></code> + +### 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' }, + }, +}) +``` + +<code id="api-oneside-router" src="@/src/api/router/oneside/index.tsx"></code> + +### 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. +::: + +<code id="api-manhattan-router" src="@/src/api/router/manhattan/index.tsx"></code> + +### 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'], + }, + }, +}) +``` + +<code id="api-metro-router" src="@/src/api/router/metro/index.tsx"></code> + +### 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, + }, + }, +}) +``` + +<code id="api-er-router" src="@/src/api/router/er/index.tsx"></code> + +## 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 }) +``` + +<code id="api-random-router" src="@/src/api/router/random/index.tsx"></code> 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 +``` + +<span class="tag-param">Parameters<span> + +| 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 | \<T\>(from: T, to: T) => (time: number) => T | | | Interpolation function. | +| options.start | (args: Animation.CallbackArgs) => void | | | Callback function when the animation starts. | +| options.progress | (args: Animation.ProgressArgs) => void | | | Callback function during the animation execution. | +| options.complete | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes. | +| options.stop | (args: Animation.CallbackArgs) => void | | | Callback function when the animation is stopped. | +| options.finish | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes or is stopped. | +| options.jumpedToEnd | boolean | | `false` | Whether to immediately complete the animation when manually stopped. | +| delim | string | | `'/'` | String path delimiter. | + +We provide several timing functions in the `Timing` namespace. You can use built-in timing function names or provide a function with the signature `(t: number) => number`. The built-in timing functions are as follows: + +- linear +- quad +- cubic +- inout +- exponential +- bounce +- easeInSine +- easeOutSine +- easeInOutSine +- easeInQuad +- easeOutQuad +- easeInOutQuad +- easeInCubic +- easeOutCubic +- easeInOutCubic +- easeInQuart +- easeOutQuart +- easeInOutQuart +- easeInQuint +- easeOutQuint +- easeInOutQuint +- easeInExpo +- easeOutExpo +- easeInOutExpo +- easeInCirc +- easeOutCirc +- easeInOutCirc +- easeInBack +- easeOutBack +- easeInOutBack +- easeInElastic +- easeOutElastic +- easeInOutElastic +- easeInBounce +- easeOutBounce +- easeInOutBounce + +We have built-in some interpolation functions in the `Interp` namespace, which can usually be automatically determined based on the property values along the path. The built-in interpolation functions are as follows: + +- number - Numeric interpolation function. +- object - `{ [key: string]: number }` Object interpolation function. +- unit - Numeric + unit string interpolation function, such as `10px`. Supported units include: `px, em, cm, mm, in, pt, pc, %`. +- color - Hex color interpolation function. + +> Click the refresh button below to see the animation effect. + +<iframe src="/demos/tutorial/advanced/animation/yellow-ball"></iframe> + +### Stop + +After the animation starts, you can call the [`cell.stopTransition(...)`](/en/docs/api/model/cell#stoptransition) method to stop the animation on the specified path. + +```ts +stopTransition( + path: string | string[], + options?: Animation.StopOptions<T>, + delim: string = '/', +): this +``` + +<span class="tag-param">Parameters<span> + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| path | string \| string[] | ✓ | | Path. | +| options.jumpedToEnd | boolean | | `false` | Whether to immediately complete the animation when manually stopped. | +| options.complete | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes. | +| options.stop | (args: Animation.CallbackArgs) => void | | | Callback function when the animation is stopped. | +| options.finish | (args: Animation.CallbackArgs) => void | | | Callback function when the animation completes or is stopped. | +| delim | string | | `'/'` | String path delimiter. | + +<iframe src="/demos/tutorial/advanced/animation/football"></iframe> + +### Events + +- `'transition:start'` Triggered when the animation starts +- `'transition:progress'` Triggered during the animation +- `'transition:complete'` Triggered when the animation completes +- `'transition:stop'` Triggered when the animation is stopped +- `'transition:finish'` 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) => {}) +``` + +<iframe src="/demos/tutorial/advanced/animation/ufo"></iframe> + +## Element Animation + +You can specify the animation process of a certain property of an element through the `animate()` method on `CellView`. You need to specify the duration of the animation, as well as the initial and final values of the property. It returns a method to stop the animation. + +```ts +view.animate( + elem: SVGElement | string, + options: Dom.AnimationOptions, +): () => void +``` + +<span class="tag-param">Parameters<span> + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| elem | SVGElement \| string | ✓ | | The element or element selector moving along the edge. | +| options.start | (e) => void | | | Callback when the animation starts. | +| options.complete | (e) => void | | | Callback when the animation ends. | +| options.repeat | (e) => void | | | Callback when the animation repeats. | +| options.... | | | | Other key-value pairs representing animation options. | + +The animation options can refer to the properties of the [AnimateElement](https://www.w3.org/TR/SVG11/animate.html#AnimateElement). + +<span class="tag-example">Usage<span> + +```ts +const rect = graph.addNode({ + x: 40, + y: 40, + width: 100, + height: 40, +}) + +const view = graph.findView(rect) +if (view) { + view.animate('rect', { + attributeType: 'XML', + attributeName: 'x', + from: 40, + to: 120, + dur: '1s', + repeatCount: 'indefinite', + }) +} +``` + +<iframe src="/demos/tutorial/advanced/animation/animate"></iframe> + +Through the `animateTransform()` method on `CellView`, you can have more control over the movement and transformation of elements. It can specify transformations, scaling, rotation, and distortion of shapes. It returns a method to stop the animation. + +```ts +view.animateTransform( + elem: SVGElement | string, + options: Dom.AnimationOptions, +): () => void +``` + +<span class="tag-param">Parameters<span> + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| elem | SVGElement \| string | ✓ | | The element or element selector moving along the edge. | +| options.start | (e) => void | | | Callback when the animation starts. | +| options.complete | (e) => void | | | Callback when the animation ends. | +| options.repeat | (e) => void | | | Callback when the animation repeats. | +| options.... | | | | Other key-value pairs representing animation options. | + +The animation options can refer to the properties of the [AnimateTransformElement](https://www.w3.org/TR/SVG11/animate.html#AnimateTransformElement). + +<span class="tag-example">Usage<span> + +```ts +const rect = graph.addNode({ + x: 60, + y: 60, + width: 30, + height: 30, +}) + +const view = graph.findView(rect) +if (view) { + view.animateTransform('rect', { + attributeType: 'XML', + attributeName: 'transform', + type: 'rotate', + from: '0 0 0', + to: '360 0 0', + dur: '3s', + repeatCount: 'indefinite', + }) +} +``` + +<iframe src="/demos/tutorial/advanced/animation/animate-transform"></iframe> + +## Path Animation + +### Animation Along a Path + +We provide a utility method `Dom.animateAlongPath()` in the `Dom` namespace to trigger an animation that moves along an SVGPathElement path element. + +```ts +Dom.animateAlongPath( + elem: SVGElement, + options: { [name: string]: string }, + path: SVGPathElement, +): void +``` + +<span class="tag-param">Parameters<span> + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| elem | SVGElement | ✓ | | The element moving along the path. | +| options | { [name: string]: string } | ✓ | | Animation options, please refer to [Animation Timing Attributes](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute#Animation_timing_attributes). | +| path | SVGPathElement | ✓ | | Path element. | + +You can also create a Vector object using the `Vector.create(...)` method, and then call the `animateAlongPath` method on that object to make the Vector object move along the specified path. + +```ts +Vector.prototype.animateAlongPath( + options: { [name: string]: string }, + path: SVGPathElement +): () => void +``` + +```ts +const view = graph.findViewByCell(cylinder) +if (view) { + const path = view.findOne('path') as SVGPathElement + if (path) { + const token = Vector.create('circle', { r: 8, fill: 'red' }) + token.animateAlongPath( + { + dur: '4s', + repeatCount: 'indefinite', + }, + path, + ) + + token.appendTo(path.parentNode as SVGGElement) + } +} +``` + +<iframe src="/demos/tutorial/advanced/animation/along-path"></iframe> + +### Animation Along an Edge + +We can call the `sendToken(...)` method on EdgeView to trigger an animation that moves along the edge, while returning a method to stop that animation. + +```ts +sendToken( + token: SVGElement | string, + options?: + | number + | { + duration?: number + reversed?: boolean + selector?: string + }, + callback?: () => void, +): () => void +``` + +<span class="tag-param">Parameters<span> + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| token | SVGElement \| string | ✓ | | The element or element selector moving along the edge. | +| options.duration | number | | `1000` | Duration of the animation, in milliseconds. | +| options.reversed | boolean | | `false` | Whether to move in the reverse direction, i.e., from the endpoint of the edge to the starting point. | +| options.selector | string | | `undefined` | The SVGPathElement element referenced for the animation, defaulting to moving along the edge's SVGPathElement. | +| options.start | (e) => void | | | Callback when the animation starts. | +| options.complete | (e) => void | | | Callback when the animation ends. | +| options.repeat | (e) => void | | | Callback when the animation repeats. | +| options.... | | | | Other key-value pairs representing animation options. | +| callback | () => void | | | Callback function after the animation completes. | + +The animation options can refer to the properties of the [AnimateMotionElement](https://www.w3.org/TR/SVG11/animate.html#AnimateMotionElement). + +<span class="tag-example">Usage<span> + +```ts +const view = graph.findViewByCell(edge) as EdgeView +const token = Vector.create('circle', { r: 6, fill: 'green' }) +const stop = view.sendToken(token.node, 1000) + +// Stop the animation after 5 seconds +setTimeout(stop, 5000) +``` + +<iframe src="/demos/tutorial/advanced/animation/signal"></iframe> diff --git a/sites/x6-sites/docs/temp/components.en.md b/sites/x6-sites/docs/temp/components.en.md new file mode 100644 index 00000000000..c3cf9bbad74 --- /dev/null +++ b/sites/x6-sites/docs/temp/components.en.md @@ -0,0 +1,116 @@ +--- +title: Using UI Components +order: 6 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/advanced +--- + +Building a complex diagram editing application also requires UI components such as Menubar, Toolbar, Dropdown, ContextMenu, and Splitbox. We provide some of these React components in [x6-react-components](https://www.npmjs.com/package/@antv/x6-react-components), which can be used in conjunction with [antd](https://ant.design/). + +## Installation + +```shell +# npm +$ npm install @antv/x6-react-components --save + +# yarn +$ yarn add @antv/x6-react-components +``` + +If you are including it directly via a `script` tag, you can use any of the following three CDNs, which will return the latest version of x6-react-components by default: + +- https://unpkg.com/@antv/x6-react-components/dist/x6-react-components.js +- https://cdn.jsdelivr.net/npm/@antv/x6-react-components/dist/x6-react-components.js +- https://cdnjs.cloudflare.com/ajax/libs/antv-x6-react-components/1.8.15/x6-react-components.js (does not support fetching the latest version) + +For production environments, we recommend using a specific version number to avoid unexpected breakages caused by new versions: + +- https://unpkg.com/@antv/x6-react-components@1.8.15/dist/x6-react-components.js +- https://cdn.jsdelivr.net/npm/@antv/x6-react-components@1.8.15/dist/x6-react-components.js +- https://cdnjs.cloudflare.com/ajax/libs/antv-x6-react-components/1.8.15/x6-react-components.js + +## Usage + +Import the required components and their corresponding styles: + +```ts +import { Menu } from '@antv/x6-react-components/es/menu' +// less +import '@antv/x6-react-components/es/menu/style' +// or css +import '@antv/x6-react-components/es/menu/style/index.css' +``` + +We strongly recommend using the [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) plugin to automatically import component styles. Add the following configuration in your `.babelrc` or babel-loader: + +```js +{ + "plugins": [ + [ + "import", + { + "libraryName": "@antv/x6-react-components", + "libraryDirectory": "es", // es or lib + "style": true, + "transformToDefaultImport": true + } + ] + ] +} +``` + +This way, when you import components, the corresponding styles will be automatically imported: + +```ts +import { Menu } from '@antv/x6-react-components' +``` + +If you are using a `script` tag to include it, the usage is as follows: + +```html +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>X6-React-Components + + + +
+ + + + + + + +``` + +## Components + +Click the links below to view the documentation for each component. + +- [Menu](/en/docs/api/ui/menu) Menu +- [Dropdown](/en/docs/api/ui/dropdown) Dropdown Menu +- [ContextMenu](/en/docs/api/ui/contextmenu) Right-click Menu +- [Menubar](/en/docs/api/ui/menubar) Menu Bar +- [Toolbar](/en/docs/api/ui/toolbar) Toolbar +- [SplitBox](/en/docs/api/ui/splitbox) Split Container +- [ScrollBox](/en/docs/api/ui/scrollbox) Container with Custom Scrollbars +- [AutoScrollBox](/en/docs/api/ui/auto-scrollbox) Container that automatically adjusts and updates scrollbars based on content size +- [ColorPicker](/en/docs/api/ui/color-picker) Color Picker diff --git a/sites/x6-sites/docs/temp/layout.en.md b/sites/x6-sites/docs/temp/layout.en.md new file mode 100644 index 00000000000..9111d986d98 --- /dev/null +++ b/sites/x6-sites/docs/temp/layout.en.md @@ -0,0 +1,225 @@ +--- +title: Using Layouts +order: 8 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/advanced +--- + +:::info{title="In this chapter, we mainly introduce knowledge related to layouts. By reading, you can learn about"} + +- How to implement layout of shapes on the canvas +- What layout methods are built into X6 ::: + +If you want the shapes on the canvas to be arranged according to certain rules, layout algorithms are essential. We provide many layout algorithms in [Layout](https://github.com/antvis/layout). Below, we will introduce how to use `X6` in conjunction with `Layout`. + +## Installation + +```shell +# npm +$ npm install @antv/layout --save + +# yarn +$ yarn add @antv/layout +``` + +If you are including it directly via a `script` tag, you can use either of the following CDNs: + +- https://unpkg.com/@antv/layout/dist/layout.min.js +- https://cdn.jsdelivr.net/npm/@antv/layout/dist/layout.min.js + +## Usage + +Here is a simple example of using a grid layout: + +```ts +import { Graph } from '@antv/x6' +import { GridLayout } from '@antv/layout' // In UMD mode, use const { GridLayout } = window.layout + +const graph = new Graph({ + container: document.getElementById('container'), + width: 600, + height: 400, +}) + +const model = { + nodes: [ + { + id: 'node1', + }, + { + id: 'node2', + }, + ], + edges: [ + { + source: 'node1', + target: 'node2', + }, + ], +} + +const gridLayout = new GridLayout({ + type: 'grid', + width: 600, + height: 400, + center: [300, 200], + rows: 4, + cols: 4, +}) + +const newModel = gridLayout.layout(model) + +graph.fromJSON(newModel) +``` + +#### Layout Process + +- Choose a layout type, such as the `grid` above. If you are unsure which layout to use, you can check the examples [here](https://g6.antv.vision/zh/examples/gallery#category-%E5%8A%9B%E5%AF%BC%E5%90%91%E5%9B%BE%E5%B8%83%E5%B1%80) for visual references. You can refer to the corresponding documentation for layout configurations. +- Construct the layout data, which is quite simple: + +```ts +// The following is the data format required for the layout +{ + nodes: [ + { + id: 'node1', + size: { + width: 30, + height: 40, + } + }, + { + id: 'node2', + size: { + width: 30, + height: 40, + } + } + ], + edges: [ + { + source: 'node1', + target: 'node2', + } + ] +} +``` + +- After executing the layout method, the layout algorithm will add `x` and `y` properties to the nodes based on the data you provided. Once you have the positions of the nodes, you can move them to the specified locations. + +```ts +const layoutData = gridLayout.layout(originData) +layoutData.nodes.forEach((node) => { + node.x -= node.size.width / 2 + node.y -= node.size.height / 2 +}) +``` + +:::warning{title=Note:} The `x` and `y` returned by the layout algorithm actually represent the center coordinates of the nodes. In X6, the `x` and `y` of the nodes represent the top-left corner coordinates, so after the layout, we need to perform a coordinate transformation. ::: + +## Common Layouts + +### Grid Layout + +The grid layout arranges nodes in a grid based on the specified sorting method. + + + +```ts +import { GridLayout } from '@antv/layout' + +const gridLayout = new GridLayout({ + type: 'grid', + width: 600, + height: 400, + center: [300, 200], + rows: 4, + cols: 4, +}) +``` + +Supports the following configurations: + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| type | string | `true` | `grid` | Layout type | +| begin | [number, number] | `false` | [0, 0] | Grid starting position (top-left corner) | +| width | number | `false` | - | Width of the layout area | +| height | number | `false` | - | Height of the layout area | +| center | [number, number] | `false` | - | Center point of the layout | +| preventOverlap | boolean | `false` | `false` | Whether to prevent overlap | +| preventOverlapPadding | number | `false` | 10 | Padding between nodes when preventing overlap. Effective when `preventOverlap` is `true` | +| rows | number | `false` | - | Number of rows in the grid; if not set, the algorithm calculates based on the number of nodes, layout space, and `cols` (if specified) | +| cols | number | `false` | - | Number of columns in the grid; if not set, the algorithm calculates based on the number of nodes, layout space, and `rows` (if specified) | +| condense | boolean | `false` | `false` | When `false`, it utilizes all available canvas space; when `true`, it utilizes the minimum canvas space | +| sortBy | string | `false` | - | Specifies the sorting criterion (node attribute name); the higher the value, the more centered the node will be placed. If not set, the algorithm calculates based on node degree; nodes with higher degrees will be placed more centrally | +| nodeSize | number \| number[] | `false` | 30 | Uniformly set the size of the nodes | + +### Circular Layout + +The layout arranges all nodes in a circular ring, allowing you to choose the order of nodes on the ring. You can extend the configuration parameters to create grouped layouts, spiral layouts, etc. + + + +```ts +import { CircularLayout } from '@antv/layout' + +const circularLayout = new CircularLayout({ + type: 'circular', + width: 600, + height: 400, + center: [300, 200], + radius: 50, +}) +``` + +Supports the following configurations: + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| type | string | `true` | `circular` | Layout type | +| width | number | `false` | - | Width of the layout area | +| height | number | `false` | - | Height of the layout area | +| center | [number, number] | `false` | - | Center point of the layout | +| radius | number | `false` | `null` | Radius of the circle. If `radius` is set, `startRadius` and `endRadius` will not take effect | +| startRadius | number | `false` | `null` | Starting radius for spiral layout | +| endRadius | number | `false` | `null` | Ending radius for spiral layout | +| clockwise | boolean | `false` | `true` | Whether to arrange in a clockwise direction | +| divisions | number | `false` | 1 | Number of segments for nodes on the ring (segments will be evenly distributed); effective when `endRadius - startRadius != 0` | +| ordering | string | `false` | `null` | Basis for ordering nodes on the ring. Default `null` means using the order in the data. `topology` sorts by topology. `degree` sorts by degree size | +| angleRatio | number | `false` | 1 | The ratio of the angle between the first and last nodes | + +### Dagre + +Dagre is a hierarchical layout. + + + +```ts +import { DagreLayout } from '@antv/layout' + +const dagreLayout = new DagreLayout({ + type: 'dagre', + rankdir: 'LR', + align: 'UL', + ranksep: 30, + nodesep: 15, + controlPoints: true, +}) +``` + +Supports the following configurations: + +| Name | Type | Required | Default Value | Description | +| --- | --- | :-: | --- | --- | +| type | string | `true` | `dagre` | Layout type | +| begin | [number, number] | `false` | - | Alignment position of the top-left corner of the layout | +| rankdir | 'TB' \| 'BT' \| 'LR' \| 'RL' | `false` | `TB` | Direction of the layout. T: top; B: bottom; L: left; R: right | +| align | 'UL' \| 'UR' \| 'DL' \| 'DR' \| undefined | `false` | - | Node alignment method. U: upper; D: down; L: left; R: right; undefined (centered) | +| nodesep | number | `false` | 50 | Node spacing (px). When `rankdir` is `TB` or `BT`, this is the horizontal spacing between nodes; when `rankdir` is `LR` or `RL`, this represents the vertical spacing between nodes | +| ranksep | number | `false` | 50 | Layer spacing (px). When `rankdir` is `TB` or `BT`, this is the vertical spacing between adjacent layers; when `rankdir` is `LR` or `RL`, this represents the horizontal spacing between adjacent layers | +| nodesepFunc | function | `false` | - | Callback function for node spacing (px), allowing different spacing for different nodes. | +| ranksepFunc | function | `false` | - | Callback function for layer spacing (px), allowing different spacing for different layers. | +| controlPoints | boolean | `false` | `true` | Whether to retain control points for layout connections | diff --git a/sites/x6-sites/docs/temp/ui/auto-scrollbox.en.md b/sites/x6-sites/docs/temp/ui/auto-scrollbox.en.md index 6fb8d8ab852..6bbeac0c53f 100644 --- a/sites/x6-sites/docs/temp/ui/auto-scrollbox.en.md +++ b/sites/x6-sites/docs/temp/ui/auto-scrollbox.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -自动根据内容大小设置和更新容器的滚动条。 +Automatically adjusts and updates the scrollbar of the container based on the content size. @@ -43,14 +43,13 @@ import '@antv/x6-react-components/es/auto-scroll-box/style/index.css'
``` - ## AutoScrollBox -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| scrollBoxProps | 内部的 [ScrollBox](/en/docs/api/ui/scrollbox) 组件选项 | ScrollBox.Props | - | -| refreshRate | 监听内容容器大小改变的频率 | number | `1000` | -| skipOnMount | 首次渲染时是否触发 `onResize` 回调 | boolean | - | -| scrollX | 是否显示水平滚动条 | boolean | `true` | -| scrollY | 是否显示垂直滚动条 | boolean | `true` | -| onResize | 内容容器大小改变时的回调函数 | (width: number, height: number) => void | - | +| Parameter | Description | Type | Default Value | +|-------------------|-----------------------------------------------------|-----------------------|---------------| +| scrollBoxProps | Options for the internal [ScrollBox](/en/docs/api/ui/scrollbox) component | ScrollBox.Props | - | +| refreshRate | Frequency of listening for changes in the content container size | number | `1000` | +| skipOnMount | Whether to trigger the `onResize` callback on the first render | boolean | - | +| scrollX | Whether to show the horizontal scrollbar | boolean | `true` | +| scrollY | Whether to show the vertical scrollbar | boolean | `true` | +| onResize | Callback function when the content container size changes | (width: number, height: number) => void | - | diff --git a/sites/x6-sites/docs/temp/ui/color-picker.en.md b/sites/x6-sites/docs/temp/ui/color-picker.en.md index 007babb524c..19053e29cf2 100644 --- a/sites/x6-sites/docs/temp/ui/color-picker.en.md +++ b/sites/x6-sites/docs/temp/ui/color-picker.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -颜色选择器。 +Color Picker. @@ -21,9 +21,9 @@ import '@antv/x6-react-components/es/color-picker/style/index.css' ## ColorPicker -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| style | 样式 | CSSProperties | - | -| color | 当前颜色 | string \| RGBColor | - | -| disabled | 是否禁用 | boolean | - | -| overlayProps | [弹出层](https://ant.design/components/popover-cn/)选项 | | - | +| style | Style | CSSProperties | - | +| color | Current color | string \| RGBColor | - | +| disabled | Is disabled | boolean | - | +| overlayProps | [Popover](https://ant.design/components/popover/) options | | - | diff --git a/sites/x6-sites/docs/temp/ui/contextmenu.en.md b/sites/x6-sites/docs/temp/ui/contextmenu.en.md index 45ea0cf0178..edea048efd4 100644 --- a/sites/x6-sites/docs/temp/ui/contextmenu.en.md +++ b/sites/x6-sites/docs/temp/ui/contextmenu.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -上下文菜单。 +Context Menu. @@ -44,13 +44,13 @@ const menu = ( ## ContextMenu -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| className | 自定义的样式名 | string | - | -| menu | 菜单 [Menu](/en/docs/api/ui/menu) 组件 | Menu | - | -| overlayClassName | 下拉根元素的类名称 | string | - | -| overlayStyle | 下拉根元素的样式 | CSSProperties | - | -| disabled | 菜单是否禁用 | boolean | `false` | -| visible | 菜单是否显示 | boolean | `false` | -| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | (triggerNode: Element) => HTMLElement | - | -| onVisibleChange | 菜单显示状态改变时调用 | (visible?: boolean) => void | - | +| className | Custom style name | string | - | +| menu | Menu [Menu](/en/docs/api/ui/menu) component | Menu | - | +| overlayClassName | Class name for the dropdown root element | string | - | +| overlayStyle | Style for the dropdown root element | CSSProperties | - | +| disabled | Whether the menu is disabled | boolean | `false` | +| visible | Whether the menu is displayed | boolean | `false` | +| getPopupContainer | The parent node for rendering the menu. By default, it renders to the body. If you encounter positioning issues with scrolling, try changing it to the scrolling area and positioning it relative to that. | (triggerNode: Element) => HTMLElement | - | +| onVisibleChange | Called when the visibility state of the menu changes | (visible?: boolean) => void | - | diff --git a/sites/x6-sites/docs/temp/ui/dropdown.en.md b/sites/x6-sites/docs/temp/ui/dropdown.en.md index 2f19aa31f1d..61d3f287b8b 100644 --- a/sites/x6-sites/docs/temp/ui/dropdown.en.md +++ b/sites/x6-sites/docs/temp/ui/dropdown.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -下拉菜单。 +Dropdown menu @@ -35,17 +35,17 @@ const menu = ( ## Dropdown -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| className | 自定义的样式名 | string | - | -| overlay | 菜单,通常使用 [Menu](/en/docs/api/ui/menu) 组件 | ReactNode | - | -| overlayClassName | 下拉根元素的类名称 | string | - | -| overlayStyle | 下拉根元素的样式 | CSSProperties | - | -| disabled | 菜单是否禁用 | boolean | `false` | -| visible | 菜单是否显示 | boolean | `false` | -| trigger | 触发行为,可选 `hover` \| `click` \| `contextMenu`,可使用数组设置多个触发行为 | string \| string[] | `'hover'` | -| placement | 下拉菜单的位置,可选 `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | `'bottomLeft'` | -| mouseEnterDelay | 当 `trigger` 为 `'hover'`时,鼠标移入后延时多少才显示下拉菜单,单位:秒 | number | `0.15` | -| mouseLeaveDelay | 当 `trigger` 为 `'hover'`时,鼠标移出后延时多少才隐藏下拉菜单,单位:秒 | number | `0.1` | -| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | (triggerNode: Element) => HTMLElement | - | -| onVisibleChange | 菜单显示状态改变时调用 | (visible?: boolean) => void | - | +| className | Custom style name | string | - | +| overlay | Menu, typically using the [Menu](/en/docs/api/ui/menu) component | ReactNode | - | +| overlayClassName | Class name for the dropdown root element | string | - | +| overlayStyle | Style for the dropdown root element | CSSProperties | - | +| disabled | Whether the menu is disabled | boolean | `false` | +| visible | Whether the menu is displayed | boolean | `false` | +| trigger | Trigger behavior, options are `hover` \| `click` \| `contextMenu`, can use an array to set multiple trigger behaviors | string \| string[] | `'hover'` | +| placement | Position of the dropdown menu, options are `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | `'bottomLeft'` | +| mouseEnterDelay | When `trigger` is `'hover'`, the delay in seconds before the dropdown menu is displayed after mouse enters | number | `0.15` | +| mouseLeaveDelay | When `trigger` is `'hover'`, the delay in seconds before the dropdown menu is hidden after mouse leaves | number | `0.1` | +| getPopupContainer | Parent node for rendering the menu. By default, it renders to the body. If you encounter positioning issues with scrolling, try changing it to the scrolling area and positioning it relative to that. | (triggerNode: Element) => HTMLElement | - | +| onVisibleChange | Called when the visibility state of the menu changes | (visible?: boolean) => void | - | diff --git a/sites/x6-sites/docs/temp/ui/menu.en.md b/sites/x6-sites/docs/temp/ui/menu.en.md index 3e5cd311422..f15cc06c5a1 100644 --- a/sites/x6-sites/docs/temp/ui/menu.en.md +++ b/sites/x6-sites/docs/temp/ui/menu.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -菜单组件。一般在 [Menubar](/en/docs/api/ui/menubar)、[ContextMenu](/en/docs/api/ui/contextmenu)、[Dropdown](/en/docs/api/ui/dropdown) 组件中使用。 +Menu component. Generally used in [Menubar](/en/docs/api/ui/menubar), [ContextMenu](/en/docs/api/ui/contextmenu), and [Dropdown](/en/docs/api/ui/dropdown) components. @@ -43,43 +43,43 @@ const Divider = Menu.Divider ## Menu -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| className | 自定义的样式名 | string | - | -| hasIcon | 是否包含 Icon | boolean | `false` | -| onClick | 点击 MenuItem 调用此函数 | (name: string) => void | - | -| registerHotkey | 注册快捷键 | (hotkey: string, handler: () => void) => void | - | -| unregisterHotkey | 取消注册快捷键 | (hotkey: string, handler: () => void) => void | - | +| className | Custom style name | string | - | +| hasIcon | Whether to include an Icon | boolean | `false` | +| onClick | Function called when MenuItem is clicked | (name: string) => void | - | +| registerHotkey | Register a hotkey | (hotkey: string, handler: () => void) => void | - | +| unregisterHotkey | Unregister a hotkey | (hotkey: string, handler: () => void) => void | - | ## Menu.Item -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| className | 自定义的样式名 | string | - | -| name | 菜单名称(唯一标识),在 Menu 的 `onClick` 回调中使用,如果不设置 `name` 属性,`onClick` 将不会被调用。 | string | - | -| icon | 菜单图标 | ReactNode | - | -| text | 菜单文本 | string | - | -| hotkey | 菜单快捷键 | string | - | -| active | 是否被激活(显示鼠标 Hover 的背景) | boolean | `false` | -| hidden | 是否隐藏 | boolean | `false` | -| disabled | 是否被禁用 | boolean | `false` | -| onClick | 点击 MenuItem 调用此函数 | () => void | - | -| children | 额外的子组件 | ReactNode | - | +| className | Custom style name | string | - | +| name | Menu name (unique identifier), used in the Menu's `onClick` callback. If the `name` attribute is not set, `onClick` will not be called. | string | - | +| icon | Menu icon | ReactNode | - | +| text | Menu text | string | - | +| hotkey | Menu hotkey | string | - | +| active | Whether it is active (shows background on mouse hover) | boolean | `false` | +| hidden | Whether it is hidden | boolean | `false` | +| disabled | Whether it is disabled | boolean | `false` | +| onClick | Function called when MenuItem is clicked | () => void | - | +| children | Additional child components | ReactNode | - | ## Menu.SubMenu -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| className | 自定义的样式名 | string | - | -| name | 菜单名称(唯一标识),在 Menu 的 `onClick` 回调用使用 | string | - | -| icon | 菜单图标 | ReactNode | - | -| text | 菜单文本 | string | - | -| hotkey | 菜单快捷键 | string | - | -| active | 是否被激活(显示鼠标 Hover 的背景和子菜单) | boolean | `false` | -| hidden | 是否隐藏 | boolean | `false` | -| disabled | 是否被禁用 | boolean | `false` | -| onClick | 点击 MenuItem 调用此函数 | () => void | - | +| className | Custom style name | string | - | +| name | Menu name (unique identifier), used in the Menu's `onClick` callback | string | - | +| icon | Menu icon | ReactNode | - | +| text | Menu text | string | - | +| hotkey | Menu hotkey | string | - | +| active | Whether it is active (shows background on mouse hover and sub-menu) | boolean | `false` | +| hidden | Whether it is hidden | boolean | `false` | +| disabled | Whether it is disabled | boolean | `false` | +| onClick | Function called when MenuItem is clicked | () => void | - | ## Menu.Divider -菜单项分割线。 +Menu item divider. diff --git a/sites/x6-sites/docs/temp/ui/menubar.en.md b/sites/x6-sites/docs/temp/ui/menubar.en.md index 443a4b4195f..8fac9324335 100644 --- a/sites/x6-sites/docs/temp/ui/menubar.en.md +++ b/sites/x6-sites/docs/temp/ui/menubar.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -菜单栏。 +Menu Bar. @@ -33,14 +33,14 @@ import '@antv/x6-react-components/es/menubar/style/index.css' ## Menubar -| 参数 | 说明 | 类型 | 默认值 | -| --------- | -------------------- | --------- | ------ | -| className | 自定义样式名 | string | - | -| extra | 菜单栏右侧的额外组件 | ReactNode | - | +| Parameter | Description | Type | Default Value | +|------------|---------------------------------|-----------|---------------| +| className | Custom style name | string | - | +| extra | Additional component on the right side of the menu bar | ReactNode | - | ## Menubar.Item -| 参数 | 说明 | 类型 | 默认值 | -| ------ | ---------- | ------- | ------ | -| text | 菜单项文本 | string | - | -| hidden | 是否隐藏 | boolean | - | +| Parameter | Description | Type | Default Value | +|-----------|-------------------|---------|---------------| +| text | Menu item text | string | - | +| hidden | Whether to hide | boolean | - | diff --git a/sites/x6-sites/docs/temp/ui/scrollbox.en.md b/sites/x6-sites/docs/temp/ui/scrollbox.en.md index 36c96e4ecb1..012e85299f7 100644 --- a/sites/x6-sites/docs/temp/ui/scrollbox.en.md +++ b/sites/x6-sites/docs/temp/ui/scrollbox.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -自定义滚动条的容器。 +Custom scroll bar container. @@ -40,27 +40,27 @@ import '@antv/x6-react-components/es/scroll-box/style/index.css' ## ScrollBox -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| containerClassName | 容器样式名 | string | - | -| contentClassName | 内容样式名 | string | - | -| containerStyle | 容器样式 | CSSProperties | - | -| contentStyle | 内容样式 | CSSProperties | - | -| containerWidth | 容器宽度 | number | - | -| containerHeight | 容器高度 | number | - | -| contentWidth | 内容宽度 | number | - | -| contentHeight | 内容高度 | number | - | -| scrollTop | 垂直滚动条的位置 | number | `0` | -| scrollLeft | 水平滚动条的位置 | number | `0` | -| dragable | 是否可以通过拖动内容来改变滚动条的位置 | boolean | `true` | -| touchable | 是否支持 touch 事件 | boolean | `true` | -| scrollbarAutoHide | 是否自动隐藏滚动条 | boolean | `true` | -| scrollbarSize | 滚动条大小(水平滚动条的高度、垂直滚动条的宽度) | number | `4` | -| miniThumbSize | 滚动条最小标识大小 | number | `16` | -| keyboardScrollAmount | 通过键盘方向键滚动时,每次滚动的大小 | number | `40` | +| containerClassName | Container style class name | string | - | +| contentClassName | Content style class name | string | - | +| containerStyle | Container style | CSSProperties | - | +| contentStyle | Content style | CSSProperties | - | +| containerWidth | Container width | number | - | +| containerHeight | Container height | number | - | +| contentWidth | Content width | number | - | +| contentHeight | Content height | number | - | +| scrollTop | Position of the vertical scrollbar | number | `0` | +| scrollLeft | Position of the horizontal scrollbar | number | `0` | +| dragable | Whether the scrollbar position can be changed by dragging the content | boolean | `true` | +| touchable | Whether touch events are supported | boolean | `true` | +| scrollbarAutoHide | Whether to automatically hide the scrollbar | boolean | `true` | +| scrollbarSize | Size of the scrollbar (height of the horizontal scrollbar, width of the vertical scrollbar) | number | `4` | +| miniThumbSize | Minimum size of the scrollbar thumb | number | `16` | +| keyboardScrollAmount | Amount of scroll per key press when using keyboard arrow keys | number | `40` | | zIndex | | number | - | -| onVerticalScroll | 垂直滚动条滚动时的回调函数 | (scrollTop: number) => void | - | -| onHorizontalScroll | 水平滚动条滚动时的回调函数 | (scrollLeft: number) => void | - | -| onScrollStart | 滚动条开始滚动时的回调函数 | (scrollLeft: number, scrollTop: number) => void | - | -| onScroll | 滚动条滚动时的回调函数 | (scrollLeft: number, scrollTop: number) => void | - | -| onScrollEnd | 滚动条结束滚动时的回调函数 | (scrollLeft: number, scrollTop: number) => void | - | +| onVerticalScroll | Callback function when the vertical scrollbar is scrolled | (scrollTop: number) => void | - | +| onHorizontalScroll | Callback function when the horizontal scrollbar is scrolled | (scrollLeft: number) => void | - | +| onScrollStart | Callback function when scrolling starts | (scrollLeft: number, scrollTop: number) => void | - | +| onScroll | Callback function during scrolling | (scrollLeft: number, scrollTop: number) => void | - | +| onScrollEnd | Callback function when scrolling ends | (scrollLeft: number, scrollTop: number) => void | - | diff --git a/sites/x6-sites/docs/temp/ui/splitbox.en.md b/sites/x6-sites/docs/temp/ui/splitbox.en.md index 9691996cb44..c44a86fe10f 100644 --- a/sites/x6-sites/docs/temp/ui/splitbox.en.md +++ b/sites/x6-sites/docs/temp/ui/splitbox.en.md @@ -7,29 +7,29 @@ redirect_from: - /en/docs/api/ui --- -拆分面板。 +Split Panel. ## SplitBox -| 参数 | 说明 | 类型 | 默认值 | +| Parameter | Description | Type | Default Value | | --- | --- | --- | --- | -| split | 拆分方向 | `'vertical'` \| `'horizontal'` | `'vertical'` | -| resizable | 是否可以调整面板大小 | boolean | `true` | -| primary | 主面板 | `'first'` \| `'second'` | `'first'` | -| size | 主面板大小 | number \| string | - | -| defaultSize | 主面板默认大小 | number \| string | `'25%'` | -| minSize | 主面板最小大小 | number | - | -| maxSize | 主面板最大大小 | number | - | -| step | 调整大小的步长 | number | - | -| style | 组件样式 | CSSProperties | - | -| boxStyle | 面板样式 | CSSProperties | - | -| primaryBoxStyle | 主面板样式 | CSSProperties | - | -| secondBoxStyle | 次面板样式 | CSSProperties | - | -| resizerStyle | 分割条样式 | CSSProperties | - | -| onResizeStart | 开始调整大小时的回调函数 | () => void | - | -| onResizeEnd | 调整大小结束时的回调函数 | (newSize: number) => void | - | -| onResizing | 调整大小过程中的回调函数 | (newSize: number) => void | - | -| onResizerClick | 单击分隔条的回调函数 | () => void | - | -| onResizerDoubleClick | 双击分隔条的回调函数 | () => void | - | +| split | Split direction | `'vertical'` \| `'horizontal'` | `'vertical'` | +| resizable | Whether the panel size can be adjusted | boolean | `true` | +| primary | Primary panel | `'first'` \| `'second'` | `'first'` | +| size | Primary panel size | number \| string | - | +| defaultSize | Default size of the primary panel | number \| string | `'25%'` | +| minSize | Minimum size of the primary panel | number | - | +| maxSize | Maximum size of the primary panel | number | - | +| step | Step size for resizing | number | - | +| style | Component style | CSSProperties | - | +| boxStyle | Panel style | CSSProperties | - | +| primaryBoxStyle | Primary panel style | CSSProperties | - | +| secondBoxStyle | Secondary panel style | CSSProperties | - | +| resizerStyle | Splitter style | CSSProperties | - | +| onResizeStart | Callback function when resizing starts | () => void | - | +| onResizeEnd | Callback function when resizing ends | (newSize: number) => void | - | +| onResizing | Callback function during resizing | (newSize: number) => void | - | +| onResizerClick | Callback function when the splitter is clicked | () => void | - | +| onResizerDoubleClick | Callback function when the splitter is double-clicked | () => void | - | diff --git a/sites/x6-sites/docs/temp/ui/toolbar.en.md b/sites/x6-sites/docs/temp/ui/toolbar.en.md index 569bc4bab2a..0810ff050f0 100644 --- a/sites/x6-sites/docs/temp/ui/toolbar.en.md +++ b/sites/x6-sites/docs/temp/ui/toolbar.en.md @@ -7,7 +7,7 @@ redirect_from: - /en/docs/api/ui --- -工具栏。 +Toolbar. @@ -19,7 +19,7 @@ import '@antv/x6-react-components/es/toolbar/style/index.css' const Item = Toolbar.Item const Group = Toolbar.Group -Extra Component}> +>Extra Component}> } /> } /> @@ -42,36 +42,36 @@ const Group = Toolbar.Group ## Toolbar -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| className | 自定义样式名 | string | - | -| extra | 工具栏右侧的额外组件 | ReactNode | - | -| size | 工具栏大小 | `'small'` \| `'big'` | - | -| align | 工具对齐方式 | `'left'` \| `'right'` | - | -| hoverEffect | 鼠标 Hover 时是否显示一个圆角背景 | boolean | `false` | -| onClick | 点击工具栏的回调函数 | (name: string, value?: any) => void | - | +| Parameter | Description | Type | Default Value | +|-------------|--------------------------------------|-------------------------------|---------------| +| className | Custom style name | string | - | +| extra | Additional components on the right side of the toolbar | ReactNode | - | +| size | Size of the toolbar | `'small'` \| `'big'` | - | +| align | Tool alignment method | `'left'` \| `'right'` | - | +| hoverEffect | Whether to show a rounded background on mouse hover | boolean | `false` | +| onClick | Callback function when the toolbar is clicked | (name: string, value?: any) => void | - | ## Toolbar.Group -| 参数 | 说明 | 类型 | 默认值 | -| --------- | ------------ | ------ | ------ | -| className | 自定义样式名 | string | - | +| Parameter | Description | Type | Default Value | +|-------------|--------------------------------------|-------------------------------|---------------| +| className | Custom style name | string | - | ## Toolbar.Item -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| className | 自定义样式名 | string | - | -| name | 工具项名称 | string | - | -| icon | 工具项图标 | ReactNode | - | -| text | 显示的文本 | string \| ReactNode | - | -| hidden | 是否隐藏 | boolean | - | -| disabled | 是否禁用 | boolean | - | -| active | 是否被激活 | boolean | - | -| tooltip | 工具提示文本 | string | - | -| tooltipProps | [Tooltip](https://ant.design/components/tooltip-cn/) 组件的选项 | TooltipProps | - | -| tooltipAsTitle | 是否将提示文本作为工具项的 `title` 属性 | boolean | - | -| dropdown | 下拉菜单 | ReactNode | - | -| dropdownArrow | 是否显示下拉菜单箭头 | boolean | - | -| dropdown | [下拉菜单](/en/docs/api/ui/dropdown)的选项 | Dropdown.Props | - | -| onClick | 点击工具项的回调函数 | (name?: string) => void | - | +| Parameter | Description | Type | Default Value | +|-------------|--------------------------------------|-------------------------------|---------------| +| className | Custom style name | string | - | +| name | Name of the tool item | string | - | +| icon | Icon for the tool item | ReactNode | - | +| text | Displayed text | string \| ReactNode | - | +| hidden | Whether to hide | boolean | - | +| disabled | Whether to disable | boolean | - | +| active | Whether it is activated | boolean | - | +| tooltip | Tooltip text | string | - | +| tooltipProps| Options for the [Tooltip](https://ant.design/components/tooltip-cn/) component | TooltipProps | - | +| tooltipAsTitle | Whether to use the tooltip text as the `title` attribute of the tool item | boolean | - | +| dropdown | Dropdown menu | ReactNode | - | +| dropdownArrow| Whether to show the dropdown menu arrow | boolean | - | +| dropdown | Options for the [Dropdown](/en/docs/api/ui/dropdown) | Dropdown.Props | - | +| onClick | Callback function when the tool item is clicked | (name?: string) => void | - | diff --git a/sites/x6-sites/docs/tutorial/about.en.md b/sites/x6-sites/docs/tutorial/about.en.md new file mode 100644 index 00000000000..0ec3258060b --- /dev/null +++ b/sites/x6-sites/docs/tutorial/about.en.md @@ -0,0 +1,72 @@ +--- +title: Introduction +order: 0 +redirect_from: + - /en/docs + - /en/docs/tutorial +--- + +X6 is a graph editing engine based on HTML and SVG, offering low-cost customization capabilities and out-of-the-box built-in extensions, making it easy for us to quickly build applications such as DAG diagrams, ER diagrams, flowcharts, and lineage graphs. + +If you haven't used X6 yet, we recommend experiencing its charm through the [Getting Started Guide](/en/docs/tutorial/getting-started). + +

+build +NPM Package +NPM Downloads +

+ +

+MIT License +Language +PRs Welcome +website +

+ +## ✨ Features + +- 🌱 Highly Customizable: Supports customizing node styles and interactions using SVG/HTML/React/Vue. +- 🚀 Ready to Use: Comes with 10+ built-in graph editing extensions, such as selection, alignment lines, mini-map, etc. +- 🧲 Data-Driven: Based on MVC architecture, allowing users to focus more on data logic and business logic. +- 💯 Event-Driven: Can listen to any events occurring within the graph. + +## 🍉 Documentation + +- [Getting Started](/en/docs/tutorial/getting-started) +- [Basics](/en/docs/tutorial/basic/graph) +- [Advanced](/en/docs/tutorial/intermediate/connection-point) +- [Plugins](/en/docs/tutorial/plugins/transform) +- [API](/en/docs/api/graph/graph) + +The X6 documentation is divided into two parts: documentation and API. It is recommended to read the documentation carefully, as it will help you get started with development. The API documentation is extensive, so you can refer to it when you encounter issues by searching for the relevant documents. + +## ❤️ 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/X6/issues/new/choose) +- Email: [antv@antfin.com](mailto:antv@antfin.com) +- Yuque Column: [https://www.yuque.com/antv/blog](https://www.yuque.com/antv/blog) + +X6 Graph Editing Community + +## 🤝 Contributing + +### Bugs + +If you encounter any issues while using, please check [issues](https://github.com/antvis/x6/issues) to see if there are similar bugs or suggestions. Before reporting a bug, please ensure you have searched existing issues and read our [FAQ](https://www.yuque.com/antv/x6/tox1ukbz5cw57qfy). + +### Code of Conduct + +We have a [Code of Conduct](https://github.com/antvis/X6/blob/master/CONTRIBUTING.md) that we hope all contributors will adhere to. Please take the time to read it to understand what is acceptable and what is not. + +### Join the Community + +You can also refer to the contribution guidelines below to become a contributor to X6 step by step: + +- [How to Participate in X6 Open Source Development](https://www.yuque.com/antv/x6/gcinvi) +- [How to Contribute Code Elegantly on GitHub](https://segmentfault.com/a/1190000000736629?u_atoken=b71f69b7-7d74-4e6c-a373-76e0a36e2c87&u_asession=01aGvG2P10Vrjamv5BFM7yX0X2_OcJ_XmHlitgQC_BVnNLlRLdwpnHYH8ma1b1UKRaX0KNBwm7Lovlpxjd_P_q4JsKWYrT3W_NKPr8w6oU7K93NVUbout2zcDySUWFprtJUe3R9QHfzEvknA4dzJmVTGBkFo3NEHBv0PZUm6pbxQU&u_asig=05FBplinh079EhmRTHTDgrLXp5aawipV_A-9VAsAs841tY8QeTTaaTvFKcH6odRhI4VX2pBdH5ae6FY2MiL2X_4yTqZp2jK-_nBOl2nesFZDM2RmF5JkBT_JWpU60Z6lY1hzgqVxFxj_uE1HnffLBmwa5Sl9NkdZ4_S8RH_A-AooP9JS7q8ZD7Xtz2Ly-b0kmuyAKRFSVJkkdwVUnyHAIJzZMNY1otqX6vcbPyd-A-Ld3WE-pEMt_G6ZtWjng8eWoZH_8T8uYGNepqxdb-gLe1IO3h9VXwMyh6PgyDIVSG1W-dzbV77H9pFSh5eWBVfcZZYGYDqHeX90h_yD6KfDquy8GWlAwW_v4wTa3IAdocwA0iaDksczFnALAG-4HaicdUmWspDxyAEEo4kbsryBKb9Q&u_aref=SU72jL%2FvYl46xrVouxNG%2FiEj5e0%3D) + + + Contributors + diff --git a/sites/x6-sites/docs/tutorial/basic/edge.en.md b/sites/x6-sites/docs/tutorial/basic/edge.en.md new file mode 100644 index 00000000000..3d0f7b985d1 --- /dev/null +++ b/sites/x6-sites/docs/tutorial/basic/edge.en.md @@ -0,0 +1,338 @@ +--- +title: Edges +order: 2 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/basic/basic +--- + +:::info{title="In this chapter, we mainly introduce knowledge related to edges. By reading, you can learn about"} + +- Methods to add edges +- How to configure the shape of edges +- How to add arrows to edges +- How to customize edges +- How to modify edges through the API + +::: + +## Adding Edges + +Both nodes and edges share a common base class [Cell](/en/docs/api/model/cell). In addition to inheriting properties from `Cell`, edges support the following options. + +| Property Name | Type | Default Value | Description | +|----------------|--------------------|------------------------------------------------|----------------------| +| source | TerminalData | - | Source node or starting point. | +| target | TerminalData | - | Target node or endpoint. | +| vertices | Point.PointLike[] | - | Path points. | +| router | RouterData | - | Router. | +| connector | ConnectorData | - | Connector. | +| labels | Label[] | - | Labels. | +| defaultLabel | Label | [Default Label](/en/docs/api/model/labels#default-label) | Default label. | + +```ts +graph.addEdge({ + shape: 'edge', + source: 'node1', + target: 'node2', +}) +``` + +## Configuring Edges + +Let's take a look at how to use the configurations mentioned above. + +### source/target + +The source and target nodes (points) of the edge. + +```ts +graph.addEdge({ + source: rect1, // Source node + target: rect2, // Target node +}) + +graph.addEdge({ + source: 'rect1', // Source node ID + target: 'rect2', // Target node ID +}) + +graph.addEdge({ + source: { cell: rect1, port: 'out-port-1' }, // Source node and connection port ID + target: { cell: 'rect2', port: 'in-port-1' }, // Target node ID and connection port ID +}) + +graph.addEdge({ + source: 'rect1', // Source node ID + target: { x: 100, y: 120 }, // Target point +}) +``` + +### vertices + +Path points. The edge starts from the starting point, passes through the path points in order, and finally reaches the endpoint. + +```ts +graph.addEdge({ + source: rect1, + target: rect2, + vertices: [ + { x: 100, y: 200 }, + { x: 300, y: 120 }, + ], +}) +``` + + + +### 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 `` element to render the arrow, which inherits the edge's fill color `fill` and border color `stroke` by default. + +```ts +graph.addEdge({ + shape: 'edge', + source: [100, 100], + target: [500, 500], + attrs: { + line: { + sourceMarker: { + tagName: 'path', + d: 'M 20 -10 0 0 20 10 Z', + }, + targetMarker: { + tagName: 'path', + fill: 'yellow', // Use custom fill color + stroke: 'green', // Use custom border color + strokeWidth: 2, + d: 'M 20 -10 0 0 20 10 Z', + }, + }, + }, +}) +``` + +:::info{title="Tip"} +Our starting and ending arrows use the same `d` attribute because we automatically calculate the arrow direction. In simple terms, when defining the arrow, we only need to define an arrow that points **towards the origin**. +::: + + + +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 + +
+
+
+``` + +```ts +const graph = new Graph({ + container: document.getElementById('container'), + autoResize: true, +}) +``` + +In the example below, you can drag the gray area with the mouse to change the container size. You can see through the background color that the sizes of the three graphs are adaptive. + + + +## 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 + +
+ {{ data.value }} +
+
+``` + +```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 { + @ViewChild('template') template: TemplateRef<{}>; + + ngAfterViewInit(): void { + register({ + shape: 'custom-angular-template-node', + width: 120, + height: 20, + content: this.template, + injector: this.injector, + }); + + this.graph.addNode({ + shape: 'custom-angular-template-node', + x: 100, + y: 100, + data: { + ngArguments: { + value: 'Why is the magic failing?', + }, + }, + }); + } +} +``` + +## Updating Nodes + +Whether using Component or TemplateRef, the update method is the same. + +```ts +node.setData({ + ngArguments: { + value: 'A few frames from the past in the evening breeze', + }, +}); +``` + +## Is there a demo? + +Yes, because the rendering of nodes in X6 is decoupled from the framework, the `x6-angular-shape` package is not directly modified in the source code but developed in a separate Angular environment. The demo also provides performance tests for various node types. For more details, please refer to [Eve-Sama/x6-angular-shape](https://github.com/Eve-Sama/x6-angular-shape) and [Performance comparison between X6 and G6, as well as discussions on FPS thresholds for multiple node types in X6](https://github.com/antvis/X6/issues/3266). + +## FAQ + +### Why can't input properties be placed directly in data and must be placed in ngArguments? And why is it not called ngInput? + +Not all properties in `node.data` are input properties, so it is inappropriate to iterate over all properties in `data` for assignment. The reason it is called `ngArguments` is mainly due to two considerations: + +- 1. The 1.x version has already used this, and maintaining this API can reduce the upgrade cost for users. +- The concept of `Input` actually comes from `Component`, while in `TemplateRef` it is `context`. Abstracting a concept of `Arguments` based on the two is more general. + +### Are there any new features in version 2.x of x6-angular-shape compared to version 1.x? + +The implementation approach is quite similar to before, but there are indeed a few points worth mentioning. + +#### More Focused Demo + +The demo in version 1.x included a series of cases such as rendering components, drawing connections, clearing, etc. While it seemed like an extension, it was actually overwhelming. The demo for version 2.x of `x6-angular-shape` is more focused, concentrating on the usage and performance testing of shapes. For unrelated content, please refer to the X6 official website. + +#### More Stable Functionality + +In version 1.x, although functionality was implemented, the consideration of usage scenarios was not comprehensive. For example, changes to `ngArguments` did not affect the `TemplateRef` scenario. While it worked for `Component`, it could not trigger `ngOnChanges`. In the new version, these issues will no longer exist. + +### Version Requirements + +Your Angular version must be at least 14 or above. Below version 14, some features need to be implemented using hacks, which can be cumbersome. This is not currently provided, but if needed, you can raise an issue, and I will explain how to implement it. diff --git a/sites/x6-sites/docs/tutorial/intermediate/angular.md b/sites/x6-sites/docs/tutorial/intermediate/angular.zh.md similarity index 100% rename from sites/x6-sites/docs/tutorial/intermediate/angular.md rename to sites/x6-sites/docs/tutorial/intermediate/angular.zh.md diff --git a/sites/x6-sites/docs/tutorial/intermediate/connection-point.en.md b/sites/x6-sites/docs/tutorial/intermediate/connection-point.en.md new file mode 100644 index 00000000000..c0065eb5146 --- /dev/null +++ b/sites/x6-sites/docs/tutorial/intermediate/connection-point.en.md @@ -0,0 +1,78 @@ +--- +title: Connection Points +order: 0 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/intermediate +--- + +:::info{title="In this chapter, we mainly introduce knowledge related to connection points. By reading, you can learn about"} + +- The concepts of anchor points and connection points +- How to use anchor points and connection points to customize special connections + +::: + +Let's start with an example: + + + +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. + +Connection Point + +## 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 ( +
+ +
+ ) +} + +register({ + shape: 'custom-react-node', + width: 100, + height: 100, + component: NodeComponent, +}) + +graph.addNode({ + shape: 'custom-react-node', + x: 60, + y: 100, +}) +``` + + + +## 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 + + + +``` + +The content of the node component is as follows: + +```html + + + +``` + +The final effect is as follows: + + + +## Updating Nodes + +To update the content of a `Vue` node, there are two methods: + +- Listen for node events within the component and trigger events externally. +- Use state management tools like `Vuex` (not elaborated here, but used in the same way as regular `Vue` components with `Vuex` data). + +Below is an introduction to dynamically updating node content using events: + +```ts +const node = graph.addNode({ + shape: 'custom-vue-node', + x: 100, + y: 60, + data: { + progress: 80, + }, +}) + +setInterval(() => { + const { progress } = node.getData() + node.setData({ + progress: (progress + 10) % 100, + }) +}, 2000) +``` + +Inside the node component, we can listen for changes to the node's `data`: + +```ts +export default defineComponent({ + name: 'ProgressNode', + inject: ['getNode'], + data() { + return { + percentage: 80, + } + }, + mounted() { + const node = (this as any).getNode() as Node + node.on('change:data', ({ current }) => { + const { progress } = current + this.percentage = progress + }) + }, +}) +``` + + + +## Using in Vue2 + +In the above example, we used `teleport`, which is a feature in `Vue3`. How can we use it in `Vue2`? + +```html + + + +``` + +The node component is written in the same way as above. + +:::warning{title=Note} +In Vue2, there are some limitations on the content of node components, such as the inability to use Vuex, i18n, element-ui, etc. +::: diff --git a/sites/x6-sites/docs/tutorial/intermediate/vue.md b/sites/x6-sites/docs/tutorial/intermediate/vue.zh.md similarity index 100% rename from sites/x6-sites/docs/tutorial/intermediate/vue.md rename to sites/x6-sites/docs/tutorial/intermediate/vue.zh.md diff --git a/sites/x6-sites/docs/tutorial/plugins/clipboard.en.md b/sites/x6-sites/docs/tutorial/plugins/clipboard.en.md new file mode 100644 index 00000000000..ac7c60709bd --- /dev/null +++ b/sites/x6-sites/docs/tutorial/plugins/clipboard.en.md @@ -0,0 +1,180 @@ +--- +title: Clipboard +order: 2 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/plugins +--- + +:::info{title="This chapter mainly introduces knowledge related to the clipboard. By reading, you can learn about"} + +- How to use the copy and paste function + +::: + +## Usage + +The clipboard is used for copying/pasting nodes and edges. We provide a standalone plugin package `@antv/x6-plugin-clipboard` to utilize this feature. + +```shell +# npm +$ npm install @antv/x6-plugin-clipboard --save + +# yarn +$ yarn add @antv/x6-plugin-clipboard +``` + +Then we use it in the code like this: + +```ts +import { Clipboard } from '@antv/x6-plugin-clipboard' + +const graph = new Graph({ + background: { + color: '#F2F7FA', + }, +}) +graph.use( + new Clipboard({ + enabled: true, + }), +) +``` + +## Demo + +- After selecting a node, click the copy button to copy the node. +- Set different `offset` values to observe the effect on the node's position when pasting. +- After enabling `localStorage`, copy a node, refresh the page or reopen the browser, then click the paste button. + + + +## 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) => { + // The node is the node being dragged, which is also the node placed on the canvas by default, and can be customized with any properties + const node = graph.createNode({ + shape: 'rect', + width: 100, + height: 40, + }) + dnd.start(node, e.nativeEvent) + } + + return ( +
    +
  • +
+ ) +} +``` + +## Demo + + + +## 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\ | | | Validate whether the node can be placed on the target canvas when dragging ends. | +| dndContainer | HTMLElement | | | 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. | +| draggingContainer | HTMLElement | | `document.body` | Customize the dragging canvas container. | + +## Frequently Asked Questions + +1. Why does the node ID change after dragging and dropping it onto the canvas? + +According to the dragging details above, we can see that the overall dragging process is: source node -> dragging node -> dropped node. By default, we clone the source node to get the dragging node, and clone the dragging node to get the dropped node. During the cloning process, the node ID will be reset. If you want to keep the original node ID, you can do the following: + +```ts +// This way, the ID of the node placed on the canvas will be the same as the ID of the node passed to `dnd.start`. +const dnd = new Dnd({ + getDragNode: (node) => node.clone({ keepId: true }), + getDropNode: (node) => node.clone({ keepId: true }), +}) +``` + +2. How to customize the style of the dragged node? + +```ts +const dnd = new Dnd({ + getDragNode(node) { + // Return a new node as the dragged node + return graph.createNode({ + width: 100, + height: 100, + shape: 'rect', + attrs: { + body: { + fill: '#ccc', + }, + }, + }) + }, +}) +``` + +3. How to customize the style of the node placed on the canvas? + +```ts +const dnd = new Dnd({ + getDropNode(node) { + const { width, height } = node.size() + // Return a new node as the node placed on the canvas + return node.clone().size(width * 3, height * 3) + }, +}) +``` + +4. How to get the position of the node placed on the canvas? + +```ts +graph.on('node:added', ({ node }) => { + const { x, y } = node.position() +}) +``` + +5. How to set the zIndex of the node placed on the canvas? + +```ts +graph.on('node:added', ({ node }) => { + node.setZIndex(5) +}) +``` diff --git a/sites/x6-sites/docs/tutorial/plugins/export.en.md b/sites/x6-sites/docs/tutorial/plugins/export.en.md new file mode 100644 index 00000000000..94e8c8d6df1 --- /dev/null +++ b/sites/x6-sites/docs/tutorial/plugins/export.en.md @@ -0,0 +1,99 @@ +--- +title: Export +order: 9 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/plugins +--- + +:::info{title="By reading this section, you can learn about"} + +- How to export the canvas content in image format + +::: + +## Usage + +We often need to export the content of a canvas as an image. We provide a standalone plugin package `@antv/x6-plugin-export` to use this feature. + +```shell +# npm +$ npm install @antv/x6-plugin-export --save + +# yarn +$ yarn add @antv/x6-plugin-export +``` + +Then we use it in the code like this: + +```ts +import { Export } from '@antv/x6-plugin-export' + +const graph = new Graph({ + background: { + color: '#F2F7FA', + }, +}) + +graph.use(new Export()) +``` + +## API + +### graph.exportSVG(...) + +```ts +exportSVG(fileName?: string, options?: Export.ToSVGOptions): void +``` + +`fileName` is the name of the file, defaulting to `chart`. `Export.ToSVGOptions` is described as follows: + +| Property Name | Type | Default Value | Required | Description | +|--------------------|--------------------------------------------|---------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| preserveDimensions | `boolean \| Size` | - | | `preserveDimensions` controls the size of the exported SVG. If not set, width and height default to 100%; if set to true, width and height will be automatically calculated to the actual size of the graphic area. | +| viewBox | Rectangle.RectangleLike | - | | Sets the viewBox of the exported SVG. | +| copyStyles | boolean | `true` | | Whether to copy styles from external stylesheets, default is true. When `copyStyles` is enabled, all stylesheets will be disabled during the export process, which may cause a brief loss of styles on the page. If the effect is particularly poor, you can set `copyStyles` to false. | +| stylesheet | string | - | | Custom stylesheet. | +| serializeImages | boolean | `true` | | Whether to convert the `xlink:href` links of image elements to dataUri format. | +| beforeSerialize | `(this: Graph, svg: SVGSVGElement) => any` | - | | You can call `beforeSerialize` to modify the SVG string before exporting it. | + +### graph.exportPNG(...) + +```ts +exportPNG(fileName?: string, options?: Export.ToImageOptions): void +``` + +`fileName` is the name of the file, defaulting to `chart`. `Export.ToImageOptions` inherits from the above `Export.ToSVGOptions` and has the following additional configurations: + +| Property Name | Type | Default Value | Required | Description | +|--------------------|-----------------------|---------------|----------|-------------------------------------------------------------------------------------------| +| width | number | - | | Width of the exported image. | +| height | number | - | | Height of the exported image. | +| backgroundColor | string | - | | Background color of the exported image. | +| padding | NumberExt.SideOptions | - | | Padding for the image. | +| quality | number | - | | Image quality, which can be selected from a range of 0 to 1. If out of range, the default value of 0.92 will be used. | + +### graph.exportJPEG(...) + +```ts +exportJPEG(fileName?: string, options?: Export.ToImageOptions): void +``` + +### graph.toSVG(...) + +```ts +toSVG(callback: (dataUri: string) => any, options?: Export.ToSVGOptions): void +``` + +### graph.toPNG(...) + +```ts +toPNG(callback: (dataUri: string) => any, options?: Export.ToImageOptions): void +``` + +### graph.toJPEG(...) + +```ts +toJPEG(callback: (dataUri: string) => any, options?: Export.ToImageOptions): void +``` diff --git a/sites/x6-sites/docs/tutorial/plugins/history.en.md b/sites/x6-sites/docs/tutorial/plugins/history.en.md new file mode 100644 index 00000000000..94f5e806ae8 --- /dev/null +++ b/sites/x6-sites/docs/tutorial/plugins/history.en.md @@ -0,0 +1,224 @@ +--- +title: History +order: 4 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/plugins +--- + +:::info{title="This chapter mainly introduces knowledge related to undo and redo. By reading, you can learn about"} + +- How to implement undo and redo for element operations + +::: + +## Usage + +We provide a standalone plugin package `@antv/x6-plugin-history` to use the undo and redo functionality. + +```shell +# npm +$ npm install @antv/x6-plugin-history --save + +# yarn +$ yarn add @antv/x6-plugin-history +``` + +Then we use it in the code like this: + +```ts +import { History } from '@antv/x6-plugin-history' + +const graph = new Graph({ + background: { + color: '#F2F7FA', + }, +}) +graph.use( + new History({ + enabled: true, + }), +) +``` + +## Demo + +- After moving a node freely, the Undo button becomes available. +- Clicking the Undo button restores the node's position, and then the Redo button becomes available. +- Clicking the Redo button updates the node's position. + + + +## 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 `` component can only be used within the `` component to function properly. + +::: + +After importing the `` component, you can set the canvas background of ``. + +```tsx + + ... + + +``` + +## Background Color + +Specify the background color of the canvas using the `color` property. + + + +## 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 `` component can only be used properly within the `` component. + +::: + +By importing this component under the XFlow component, you can enable the ability to copy and paste nodes and edges on the canvas. + +Combined with [useClipboard](/xflow/hooks/use-clipboard), you can quickly implement copy and paste functionality. + +```tsx + + ... + + +``` + + + +## 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 `` component can only be used properly within the `` component. + +::: + +The Control component provides shortcuts for common operations on the canvas. + +```tsx + + ... + + +``` + + + +## 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 `` component can only be used within the `` component. + +::: + +After importing `` under ``, the internal component will save the canvas instance to the context of `` for use by its children. You can quickly obtain the canvas instance in your component using the [useGraphInstance](#basic-usage) hook. + +```tsx + + ... + + +``` + + + +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 + +``` + +## Canvas Zooming + +- Minimum and maximum zoom levels for the canvas. + +You can set the canvas zoom by configuring `minScale` and `maxScale`. + +```tsx + +``` + +- Zooming the canvas with the mouse wheel. + +For specific `zoomOptions` configuration, refer to [mousewheel configuration](/api/graph/mousewheel#configuration). + +```tsx + +``` + +## Canvas Scrolling + +Enable the canvas scrolling feature. + +```tsx + +``` + +## Canvas Panning + +Enable `pannable` to support dragging and panning the canvas, and configure dragging options through `panOptions`. + +```tsx + +``` + +The configuration parameters for `panOptions` are as follows: + +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| modifiers | Configures modifier keys; dragging the canvas requires pressing the modifier key and clicking the mouse | `string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null` | - | +| eventTypes | Interaction methods that trigger canvas panning | `('leftMouseDown' | 'rightMouseDown' | 'mouseWheel' | 'mouseWheelDown')[]` | - | + +Dragging may conflict with other operations; in this case, you can set the `modifiers` parameter. After setting the modifier keys, you need to press the modifier key and click the mouse to trigger canvas dragging. + +`ModifierKey` 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` or both `ctrl` and `shift` simultaneously. + +`eventTypes` supports three forms or combinations of them: + +- `leftMouseDown`: Dragging by pressing the left mouse button. +- `rightMouseDown`: Dragging by pressing the right mouse button. +- `mouseWheel`: Dragging using the mouse wheel. +- `mouseWheelDown`: Dragging by pressing the mouse wheel. + +## Viewport Transformation + +- When `centerView` is set to true, the center of the canvas content will align with the center of the viewport. You can configure this with `centerViewOptions`. + +```tsx + +``` + +The configuration parameters for `centerViewOptions` are as follows: + +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| padding | Margin, effective only in `scroller` canvas | number | - | +| useCellGeometry | Whether to calculate the content area using the geometric information (Model) of nodes/edges | boolean | `true` | + +- `fitView` scales the canvas content to fill the viewport. You can configure this with `fitView`. + +The configuration parameters for `fitViewOptions` are as follows: + +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| padding | Margin | number | `{ left: number, top: number, right: number, bottom: number }` | - | +| contentArea | Content area, defaults to the canvas content area | `Rectangle.RectangleLike` | - | +| viewportArea | Viewport area, defaults to the canvas viewport | `Rectangle.RectangleLike` | - | +| scaleGrid | Corrects the zoom ratio to be a multiple of `scaleGrid` | number | - | +| minScale | Minimum zoom ratio | number | - | +| maxScale | Maximum zoom ratio | number | - | +| minScaleX | Minimum zoom ratio in the X direction | number | - | +| maxScaleX | Maximum zoom ratio in the X direction | number | - | +| minScaleY | Minimum zoom ratio in the Y direction | number | - | +| maxScaleY | Maximum zoom ratio in the Y direction | number | - | +| preserveAspectRatio | Whether to maintain the aspect ratio | boolean | `false` | +| useCellGeometry | Whether to use the geometric information (Model) of nodes/edges to calculate the bounding box | boolean | `true` | + +## Node Embedding + +Drag one node into another to make it a child of the other node. + +```tsx + true, + }} +/> +``` + +The configuration for `embedOptions` is as follows: + +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| findParent | Method to specify how to find the parent node when a node is moved. Default value is [findParent](/api/model/interaction#findparent) | `bbox` | +| frontOnly | If `frontOnly` is true, nodes can only be embedded if they are displayed in front | boolean | true | +| validate | `validate` is a function that determines whether a node can be embedded in a parent node | [validate](/api/model/interaction#validate) | `() => true` | + +## Node Movement Range + +You can restrict the movement range of nodes by configuring `restrict`, and specify the movement range through `restrictOptions`. + +```tsx + +``` + +The `restrictOptions` can specify the movement range of a node. If not set, nodes cannot move outside the canvas area. + +```tsx +restrictOptions?: { + bound: + | Rectangle.RectangleLike + | ((arg: CellView | null) => Rectangle.RectangleLike | null); +}; +``` + +## Connection Configuration + +Configure `connectionOptions` to enable connection interactions. For specific configurations, refer to [connection configuration](/api/model/interaction#connection). + +```tsx + +``` + +Note: Unlike connection configuration, if you want to customize the style of newly created edges, you need to set the `connectionEdgeOptions` parameter instead of configuring `createEdge` in `connectionOptions`. + +```tsx +connectionEdgeOptions={{ + animated: true, + draggable: false, + selected: false, + attrs: { + line: { + stroke: 'rgb(72, 203, 164)', + strokeWidth: 2, + targetMarker: { + name: 'block', + width: 14, + height: 10, + }, + }, + }, + zIndex: 0, +}} +``` + +The `connectionEdgeOptions` parameter inherits from [Edge](/api/model/edge#attributes) and additionally has the properties `selected`, `draggable`, and `animated`. + +```tsx +export interface EdgeOptions extends Edge.Metadata { + selected?: boolean; // Whether selected + draggable?: boolean; // Whether draggable + animated?: boolean; // Whether to show animation +} +``` + +## Interaction Highlighting + +Specify the highlight style for nodes/edges when a certain interaction is triggered. + +HighlightManager.Options has two parameters, `name` and its corresponding `args`. The `name` has two built-in highlight types: one is [stroke](/api/registry/highlighter#stroke) and the other is [className](/api/registry/highlighter#classname). + +Note: When the following highlight configurations `embedHighlightOptions`, `nodeAvailableHighlightOptions`, `magnetAvailableHighlightOptions`, and `magnetAdsorbedHighlightOptions` are not set, the `defaultHighlightOptions` configuration is used by default. + +```tsx +// stroke + + +// className + +``` + +## API + +### XFlowGraph + +| Parameter Name | Description | Type | Default Value | +|----------------|-------------|------|---------------| +| style | Semantic structure style | CSSProperties | - | +| classNames | Semantic structure class | string | - | +| readonly | Disables canvas interaction | boolean | false | +| virtual | Whether to render only the visible area content | boolean | false | +| minScale | Minimum zoom level for the canvas | number | 0.01 | +| maxScale | Maximum zoom level for the canvas | number | 16 | +| zoomable | Whether mouse wheel zooming is enabled for the canvas | boolean | false | +| zoomOptions | Configuration for enabling mouse wheel zooming | [Omit](/api/graph/mousewheel#configuration) | - | +| pannable | Whether to enable canvas panning interaction | boolean | false | +| panOptions | Configuration for enabling canvas panning interaction | [panOptions](#panOptions-configuration-parameters) | - | +| centerView | Aligns the center of the canvas content with the center of the viewport | boolean | false | +| centerViewOptions | Configuration for aligning the center of the canvas content with the viewport | [centerViewOptions](#centerViewOptions-configuration-parameters) | - | +| fitView | Scales the canvas content to fill the viewport | boolean | false | +| fitViewOptions | Configuration for scaling the canvas content | [fitViewOptions](#fitViewOptions-configuration-parameters) | - | +| scroller | Whether to enable scrolling on the canvas | boolean | false | +| scrollerOptions | Configuration for enabling scrolling on the canvas | [scrollerOptions](/tutorial/plugins/scroller#options) | - | +| connectionOptions | Connection configuration | [Omit](/api/model/interaction#connection) | - | +| connectionEdgeOptions | Custom edge in connection options | [EdgeOptions](#connectionEdgeOptions) | - | +| embedable | Whether to allow node embedding | boolean | false | +| embedOptions | Node embedding configuration | [embedOptions](#embedOptions-parameter-configuration) | - | +| restrict | Whether to restrict node movement range | boolean | false | +| restrictOptions | Configuration for restricting node movement range | [restrict configuration](#restrictOptions-node-movement-range) | - | +| selectOptions | Box selection configuration | [Selection configuration](/tutorial/plugins/selection#configuration) | - | +| keyboardOptions | Shortcut key configuration | [Keyboard configuration](/tutorial/plugins/keyboard#configuration) | - | +| defaultHighlightOptions | Default highlight options used when the following highlight configurations are not set | [HighlightManager.Options](#highlight-HighlightManager.Options) | - | +| embedHighlightOptions | Used when dragging nodes for embedding operations | [HighlightManager.Options](#highlight-HighlightManager.Options) | - | +| nodeAvailableHighlightOptions | Used when nodes can be linked during connection | [HighlightManager.Options](#highlight-HighlightManager.Options) | - | +| magnetAvailableHighlightOptions | Used when connection magnets can be linked | [HighlightManager.Options](#highlight-HighlightManager.Options) | - | +| magnetAdsorbedHighlightOptions | Used when automatically snapping to connection magnets | [HighlightManager.Options](#highlight-HighlightManager.Options) | - | diff --git a/sites/x6-sites/docs/xflow/components/graph.md b/sites/x6-sites/docs/xflow/components/graph.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/components/graph.md rename to sites/x6-sites/docs/xflow/components/graph.zh.md diff --git a/sites/x6-sites/docs/xflow/components/grid.en.md b/sites/x6-sites/docs/xflow/components/grid.en.md new file mode 100644 index 00000000000..9e085fb5907 --- /dev/null +++ b/sites/x6-sites/docs/xflow/components/grid.en.md @@ -0,0 +1,78 @@ +--- +title: Grid +order: 2 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/components +--- + +Canvas Grid + +## Basic Usage + +:::info{title="Note"} + +The `` component can only be used properly within the `` component. + +::: + +After importing the `` component, you can set the canvas grid for ``. + +```tsx + + ... + + +``` + +## Grid Size + +You can control the grid size by setting the `size` property. The default grid size is 10px, which means that when rendering nodes, they will align to the grid with 10 as the minimum unit. For example, a node positioned at { x: 24, y: 38 } will actually render at { x: 20, y: 40 } on the canvas. When moving nodes, the minimum distance moved will be 10px. + +## Hide Grid + +You can hide the grid by adding the `visible` property. + +## Dot Grid + +The dot grid, with the `type` property set to `dot`, allows you to set the grid color and width through the `options` property. + + + +## 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 `` component can only be used within the `` component to function properly. + +::: + +Import the `History` component, and in conjunction with [useHistory](/xflow/hooks/use-history), you can quickly implement undo and redo functionality for element operations. + +```tsx + + ... + + +``` + + + +## 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 `` component can only be used properly within the `` component. + +::: + +To implement a mini-map feature for the canvas quickly, import the `Minimap` component: + +```tsx + + ... + + +``` + + + +## 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 `` component can only be used properly within the `` component. + +::: + +After importing ``, you can enable node alignment guide lines. + +```tsx + + ... + + +``` + + + +## 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 `` component can only be used properly within the `` component. + +::: + +Use the `` component to enable node adjustment capabilities. + +```tsx + + ... + + +``` + +By setting the `resizing` and `rotating` properties of the Transform component to `true`, you can enable the ability to adjust the size and rotation angle of nodes. You can also configure the `resizing` and `rotating` properties. + + + +## 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: +- Yuque Column: + + + XFlow Graph Visualization Communication Group + + +## How to Contribute + +If you encounter any issues while using, please first check the [issues](https://github.com/antvis/x6/issues) to see if there are similar bugs or suggestions. + +Before reporting a bug, please ensure you have searched existing issues and read our [FAQ]("/xflow/faq"). + +To submit code, please follow our [Contribution Guidelines](https://github.com/antvis/X6/blob/master/CONTRIBUTING.md). + + + Contributors + diff --git a/sites/x6-sites/docs/xflow/guide/introduction.md b/sites/x6-sites/docs/xflow/guide/introduction.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/guide/introduction.md rename to sites/x6-sites/docs/xflow/guide/introduction.zh.md diff --git a/sites/x6-sites/docs/xflow/guide/quick-start.en.md b/sites/x6-sites/docs/xflow/guide/quick-start.en.md new file mode 100644 index 00000000000..c5335726837 --- /dev/null +++ b/sites/x6-sites/docs/xflow/guide/quick-start.en.md @@ -0,0 +1,36 @@ +--- +title: Quick Start +order: 1 +redirect_from: + - /en/docs + - /en/docs/tutorial + - /en/docs/tutorial/basic +--- + +# Installation + +:::info{title="Prerequisites"} + +- Familiarity with the command line +- Node.js version 18.0 or higher installed + +::: + +## Using a Package Manager + +```bash [NPM] +# Using npm +$ npm install @antv/xflow --save + +# Using yarn +$ yarn add @antv/xflow + +# Using pnpm +$ pnpm add @antv/xflow +``` + +# Basic Usage + +Next, let's use XFlow to build a simple graphical application and experience the charm of XFlow together. + + 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.MouseEvent) => void | - | + +

NodeOptions, 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` | - | diff --git a/sites/x6-sites/docs/xflow/hooks/useDnd.md b/sites/x6-sites/docs/xflow/hooks/useDnd.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useDnd.md rename to sites/x6-sites/docs/xflow/hooks/useDnd.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useExport.en.md b/sites/x6-sites/docs/xflow/hooks/useExport.en.md new file mode 100644 index 00000000000..206807ecab6 --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useExport.en.md @@ -0,0 +1,40 @@ +--- +title: useExport +order: 5 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +A Hook for exporting canvas content as an image. + +## Basic Usage + +```tsx + const { exportPNG, exportJPEG, exportSVG } = useExport(); +``` + +## API + +```tsx + +const { + exportPNG: (fileName, options) => void, + exportJPEG: (fileName, options) => void, + exportSVG: (fileName, options) => void +} = useExport(); + +``` + +## Return Values + +| Parameter | Description | Type | Default Value | +|------------|-------------|------|---------------| +| exportPNG | Export as PNG | (fileName:string, options: [Export.ToImageOptions]((/tutorial/plugins/export#graphexportsvg)) = {}) => void | `('chart', {}) => void` | +| exportJPEG | Export as JPEG | (fileName:string, options: [Export.ToImageOptions]((/tutorial/plugins/export#graphexportsvg)) = {}) => void | `('chart', {}) => void` | +| exportSVG | Export as SVG | (fileName:string, options: [Export.ToSVGOptions]((/tutorial/plugins/export#graphexportsvg)) = {}) => void | `('chart', {}) => void` | + +## Parameters + +None diff --git a/sites/x6-sites/docs/xflow/hooks/useExport.md b/sites/x6-sites/docs/xflow/hooks/useExport.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useExport.md rename to sites/x6-sites/docs/xflow/hooks/useExport.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphEvent.en.md b/sites/x6-sites/docs/xflow/hooks/useGraphEvent.en.md new file mode 100644 index 00000000000..ec1eba08a38 --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useGraphEvent.en.md @@ -0,0 +1,40 @@ +--- +title: useGraphEvent +order: 2 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +Canvas Event Listener Hook + +## Basic Usage + +```tsx + useGraphEvent('blank:click', () => { ... }); +``` + +Here is a simple example of using `useGraphEvent` to listen for node click events and randomly change the node color. + + +## API + +```tsx + useGraphEvent( + name: T, + callback: (args: EventArgs[T]) => void +); +``` + +## Return Value + +None + +## Parameters + +For specific event types to listen to, please refer to [X6 Events](/tutorial/basic/events). +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| name | The event to listen for | `T` | - | +| callback | The callback for the event listener | `(args: EventArgs[T]) => void` | - | diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphEvent.md b/sites/x6-sites/docs/xflow/hooks/useGraphEvent.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useGraphEvent.md rename to sites/x6-sites/docs/xflow/hooks/useGraphEvent.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphInstance.en.md b/sites/x6-sites/docs/xflow/hooks/useGraphInstance.en.md new file mode 100644 index 00000000000..0f94a104ba4 --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useGraphInstance.en.md @@ -0,0 +1,32 @@ +--- +title: useGraphInstance +order: 0 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +Hook for obtaining the canvas instance + +## Basic Usage + +```tsx + const graph = useGraphInstance(); +``` + +## API + +```tsx + const graph: Graph = useGraphInstance() +``` + +## Return Value + +| Parameter | Description | Type | Default Value | +|-----------|---------------|--------|---------------| +| graph | Canvas instance | `Graph` | `null` | + +## Parameters + +None diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphInstance.md b/sites/x6-sites/docs/xflow/hooks/useGraphInstance.zh.md similarity index 100% rename from sites/x6-sites/docs/xflow/hooks/useGraphInstance.md rename to sites/x6-sites/docs/xflow/hooks/useGraphInstance.zh.md diff --git a/sites/x6-sites/docs/xflow/hooks/useGraphStore.en.md b/sites/x6-sites/docs/xflow/hooks/useGraphStore.en.md new file mode 100644 index 00000000000..520db9a89f6 --- /dev/null +++ b/sites/x6-sites/docs/xflow/hooks/useGraphStore.en.md @@ -0,0 +1,56 @@ +--- +title: useGraphStore +order: 1 +redirect_from: + - /en/docs + - /en/docs/xflow + - /en/docs/xflow/hooks +--- + +Get the current canvas store and a Hook to change the store. + +## Basic Usage + +```tsx + const nodes = useGraphStore((state) => state.nodes); +``` + +Using `useGraphStore` allows for easy CRUD (Create, Read, Update, Delete) operations on the canvas data. +Below is a simple example of adding and removing nodes using `useGraphStore`. + + +## API + +```tsx + + useGraphStore(selector: (state: U) => T): U + +``` + +## Return Value + +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| `U` | Actions of the canvas store | [Options](#Options-parameters-below) | - | + +## Parameters + +| Parameter | Description | Type | Default Value | +|-----------|-------------|------|---------------| +| selector | Function to get the store's actions | (state: [Options](#Options-parameters-below)) => [Options](#Options-parameters-below) | - | + +

Options 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