Compare commits

...

35 Commits

Author SHA1 Message Date
7b091f35de fix: change dragging container options () 2023-01-13 22:09:21 +08:00
95c72c3033 chore: update CONTRIBUTORS [skip ci] 2023-01-13 13:13:12 +00:00
0c91218b64 chore: update contributors [skip ci] 2023-01-13 13:06:09 +00:00
61c030a162 docs: fix document formatting ()
docs: fix document formatting
2023-01-13 21:05:46 +08:00
5c5f3e5319 chore: update contributors [skip ci] 2023-01-11 02:13:33 +00:00
06a8f28c2d chore: update contributors [skip ci] 2023-01-10 02:17:09 +00:00
ece198265b chore: update contributors [skip ci] 2023-01-05 14:48:42 +00:00
6abd0683ea fix: update group even group is empty () 2023-01-05 22:48:20 +08:00
fff95806c8 docs: add LEGAL for sites () 2023-01-04 20:41:06 +08:00
a069449782 chore: update badge style 2023-01-04 12:18:58 +08:00
3b25683529 chore(release): release 2 packages [skip ci]
[@antv/x6@2.1.4](https://www.npmjs.com/package/@antv/x6/v/2.1.4)
[@antv/x6@2.1.4](https://github.com/antvis/X6/releases/tag/%40antv/x6%402.1.4)

[@antv/x6-sites@1.3.1](https://github.com/antvis/X6/releases/tag/%40antv/x6-sites%401.3.1)
2023-01-03 14:07:28 +00:00
45337e4a62 fix: optimize rendering logic to prevent loops () 2023-01-03 21:56:57 +08:00
91fc97791b chore(release): release 1 package [skip ci]
[@antv/x6-sites@1.3.0](https://github.com/antvis/X6/releases/tag/%40antv/x6-sites%401.3.0)
2023-01-01 11:58:39 +00:00
cdd0913eee Update license copyright year(s) ()
docs(license): update copyright year(s)

Co-authored-by: github-actions <github-actions@github.com>
2023-01-01 19:48:23 +08:00
a696009ede chore: update contributors [skip ci] 2022-12-27 01:29:01 +00:00
c808ca6d2b chore: update CONTRIBUTORS [skip ci] 2022-12-26 03:30:48 +00:00
d3301d33d5 feat: add data processing dag example ()
chore: stash code

feat: add dataProcessingDagre demo

feat: dataProcessingDagre demo add animate and cell status style

chore: perf code

chore: perf code

chore: perf code

chore: perf code
2022-12-26 03:23:31 +00:00
0029555458 chore: force use pnpm package manager in this project 2022-12-25 16:13:18 +08:00
cc18463c53 chore(release): release 3 packages [skip ci]
[@antv/x6@2.1.3](https://www.npmjs.com/package/@antv/x6/v/2.1.3)
[@antv/x6@2.1.3](https://github.com/antvis/X6/releases/tag/%40antv/x6%402.1.3)

[@antv/x6-plugin-transform@2.1.5](https://www.npmjs.com/package/@antv/x6-plugin-transform/v/2.1.5)
[@antv/x6-plugin-transform@2.1.5](https://github.com/antvis/X6/releases/tag/%40antv/x6-plugin-transform%402.1.5)

[@antv/x6-sites@1.2.2](https://github.com/antvis/X6/releases/tag/%40antv/x6-sites%401.2.2)
2022-12-24 14:05:12 +00:00
fb8098c1c0 fix: add defense for view in transform plugin () 2022-12-24 21:54:09 +08:00
c250caba6a chore: update CONTRIBUTORS [skip ci] 2022-12-23 12:08:08 +00:00
019333d79d fix: schedule edge when source and target is not ready () 2022-12-23 20:00:15 +08:00
33c2e59207 chore(release): release 1 package [skip ci]
[@antv/x6-vue-shape@2.0.9](https://www.npmjs.com/package/@antv/x6-vue-shape/v/2.0.9)
[@antv/x6-vue-shape@2.0.9](https://github.com/antvis/X6/releases/tag/%40antv/x6-vue-shape%402.0.9)
2022-12-21 04:03:39 +00:00
844ee5fa04 fix: get graph from right place () 2022-12-21 11:52:57 +08:00
96010e3b52 fix: add createView options () 2022-12-20 20:18:59 +08:00
a98e97db11 fix: add getGraph provide () 2022-12-20 20:16:07 +08:00
30c2ed2655 fix: optimize snapToGrid options for manhattan () 2022-12-20 20:15:55 +08:00
3a020d17c3 chore(release): release 1 package [skip ci]
[@antv/x6-common@2.0.4](https://www.npmjs.com/package/@antv/x6-common/v/2.0.4)
[@antv/x6-common@2.0.4](https://github.com/antvis/X6/releases/tag/%40antv/x6-common%402.0.4)
2022-12-20 03:52:49 +00:00
d8e1e637d8 fix: fix window incompatibility problem () 2022-12-20 11:39:53 +08:00
2d04848d52 chore(release): release 1 package [skip ci]
[@antv/x6@2.1.1](https://www.npmjs.com/package/@antv/x6/v/2.1.1)
[@antv/x6@2.1.1](https://github.com/antvis/X6/releases/tag/%40antv/x6%402.1.1)
2022-12-19 14:40:16 +00:00
e2bb71d954 fix: set snapToGrid to false by default () 2022-12-19 22:29:40 +08:00
8b145941ec chore: update contributors [skip ci] 2022-12-19 14:28:26 +00:00
2c7a04a6f4 chore: move file 2022-12-19 22:27:23 +08:00
dfa8c492da chore: update CONTRIBUTORS [skip ci] 2022-12-19 12:57:10 +00:00
3b668feb4e fix: arrowhead not get options bug () 2022-12-19 20:49:55 +08:00
40 changed files with 8007 additions and 17697 deletions

@ -13,6 +13,7 @@ Indomi <indomi126@gmail.com>
James <san>
Jógvan <lse>
Ken <ei>
Kent <oo>
Limbo <49612796+JUST-Limbo@users.noreply.github.com>
Lixu <37231473+wflixu@users.noreply.github.com>
Lloyd <ho>
@ -36,6 +37,7 @@ Utopia <greatauk11@gmail.com>
XLZY <1017866168@qq.com>
Xingjian <han>
Zhenyu <o>
_XiaoTian <istianlei@qq.com>
arthur657834 <kingkom7834@126.com>
boyu.zlj <boyu.zlj@antgroup.com>
breezefaith <nyzhangzc@qq.com>
@ -79,6 +81,7 @@ zdc1111 <39116292+zdc1111@users.noreply.github.com>
€alix <qq287649920@gmail.com>
九思⚡⚡⚡ <2228429150@qq.com>
何腾飞 <avrin.live.cn@outlook.com>
依枫 <deng25st@163.com>
偏右 <afc163@gmail.com>
小耀 <jinyue.gjy@antfin.com>
崖 <bubkoo.wy@gmail.com>

File diff suppressed because one or more lines are too long

Before

(image error) Size: 12 MiB

After

(image error) Size: 12 MiB

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Copyright (c) 2021-2023 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

@ -6,18 +6,17 @@
<p align="center"><strong>提供简单易用的节点定制能力和开箱即用的交互组件方便我们快速搭建流程图、DAG 图、ER 图等图应用</strong></p>
<p align="center">
<a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/actions/workflow/status/antvis/x6/ci.yml?branch=master&logo=github&style=flat-square"></a>
<!-- <a href="https://app.codecov.io/gh/antvis/X6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&style=flat-square&token=15CO54WYUV"></a> -->
<a href="https://lgtm.com/projects/g/antvis/x6/context:javascript"><img alt="Language grade: JavaScript" src="https://img.shields.io/lgtm/grade/javascript/g/antvis/x6.svg?logo=lgtm&style=flat-square"></a>
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Package" src="https://img.shields.io/npm/v/@antv/x6.svg?style=flat-square"></a>
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@antv/x6?logo=npm&style=flat-square"></a>
<a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/actions/workflow/status/antvis/x6/ci.yml?branch=master&style=for-the-badge&logo=github"></a>
<!-- <a href="https://app.codecov.io/gh/antvis/X6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&style=for-the-badge&token=15CO54WYUV"></a> -->
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Package" src="https://img.shields.io/npm/v/@antv/x6.svg?logo=npm&style=for-the-badge"></a>
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@antv/x6?logo=npm&style=for-the-badge"></a>
</p>
<p align="center">
<a href="/LICENSE"><img src="https://img.shields.io/github/license/antvis/x6?style=flat-square" alt="MIT License"></a>
<a href="https://www.typescriptlang.org"><img alt="Language" src="https://img.shields.io/badge/language-TypeScript-blue.svg?style=flat-square"></a>
<a href="https://github.com/antvis/x6/pulls"><img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=flat-square"></a>
<a href="https://x6.antv.antgroup.com"><img alt="website" src="https://img.shields.io/static/v1?label=&labelColor=505050&message=website&color=0076D6&style=flat-square&logo=google-chrome&logoColor=0076D6"></a>
<a href="/LICENSE"><img src="https://img.shields.io/github/license/antvis/x6?style=for-the-badge" alt="MIT License"></a>
<a href="https://www.typescriptlang.org"><img alt="Language" src="https://img.shields.io/badge/language-TypeScript-blue.svg?style=for-the-badge"></a>
<a href="https://github.com/antvis/x6/pulls"><img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=for-the-badge"></a>
<a href="https://x6.antv.antgroup.com"><img alt="website" src="https://img.shields.io/static/v1?label=&labelColor=505050&message=website&color=0076D6&style=for-the-badge&logo=google-chrome&logoColor=f5f5f5"></a>
</p>
## 特性

@ -2,7 +2,7 @@
"name": "x6",
"private": true,
"scripts": {
"preinstall": "node ./scripts/preinstall",
"preinstall": "npx only-allow pnpm",
"lint:ts": "eslint '**/src/**/*.{js,ts}?(x)' --cache --fix",
"lint:style": "stylelint '**/src/**/*.less' --customSyntax postcss-less --cache --fix",
"lint": "run-s lint:ts lint:style",

@ -1,3 +1,10 @@
## @antv/x6-common [2.0.4](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.3...@antv/x6-common@2.0.4) (2022-12-20)
### Bug Fixes
* fix window incompatibility problem ([#3070](https://github.com/antvis/x6/issues/3070)) ([d8e1e63](https://github.com/antvis/x6/commit/d8e1e637d8027b9494cd26efc87815d74bd51366))
## @antv/x6-common [2.0.1](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.0...@antv/x6-common@2.0.1) (2022-11-25)

@ -1,6 +1,6 @@
{
"name": "@antv/x6-common",
"version": "2.0.3",
"version": "2.0.4",
"description": "Basic toolkit for X6",
"main": "lib/index.js",
"module": "es/index.js",

@ -1,6 +1,10 @@
// compatible with NodeList.prototype.forEach() before chrome 51
// https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
if (window.NodeList && !NodeList.prototype.forEach) {
if (
typeof window === 'object' &&
window.NodeList &&
!NodeList.prototype.forEach
) {
NodeList.prototype.forEach = Array.prototype.forEach as any
}

@ -81,7 +81,10 @@ export class Dnd extends View {
this.targetModel.startBatch('dnd')
Dom.addClass(this.container, 'dragging')
Dom.appendTo(this.container, this.options.containerParent || document.body)
Dom.appendTo(
this.container,
this.options.draggingContainer || document.body,
)
this.sourceNode = node
this.prepareDragging(node, e.clientX, e.clientY)
@ -481,7 +484,7 @@ export namespace Dnd {
// duration?: number
// easing?: string
// }
containerParent?: HTMLElement
draggingContainer?: HTMLElement
/**
* dnd tool box container.
*/

@ -1,3 +1,10 @@
## @antv/x6-plugin-transform [2.1.5](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.4...@antv/x6-plugin-transform@2.1.5) (2022-12-24)
### Bug Fixes
* add defense for view in transform plugin ([#3092](https://github.com/antvis/x6/issues/3092)) ([fb8098c](https://github.com/antvis/x6/commit/fb8098c1c06440dd69f4e93881fd36f7e6de2a56))
## @antv/x6-plugin-transform [2.1.4](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.3...@antv/x6-plugin-transform@2.1.4) (2022-12-07)

@ -1,6 +1,6 @@
{
"name": "@antv/x6-plugin-transform",
"version": "2.1.4",
"version": "2.1.5",
"description": "transform plugin for X6",
"main": "lib/index.js",
"module": "es/index.js",

@ -107,7 +107,11 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
render() {
this.renderHandles()
this.view.addClass(Private.NODE_CLS)
if (this.view) {
this.view.addClass(Private.NODE_CLS)
}
Dom.addClass(this.container, this.containerClassName)
Dom.toggleClass(
this.container,
@ -153,7 +157,9 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
}
remove() {
this.view.removeClass(Private.NODE_CLS)
if (this.view) {
this.view.removeClass(Private.NODE_CLS)
}
return super.remove()
}

@ -26,10 +26,7 @@ export class ReactShapeView extends NodeView<ReactShape> {
const node = this.cell
if (container) {
const graph = node.model ? node.model.graph : null
// Actually in the dnd plugin, this graph is empty,
// in order to make the external perception type of graph is a graph, rather than graph | null, so hack this.
const elem = React.createElement(Wrap, { node, graph: graph! })
const elem = React.createElement(Wrap, { node, graph: this.graph })
if (Portal.isActive()) {
const portal = createPortal(elem, container) as ReactPortal
Portal.connect(this.cell.id, portal)

@ -1,3 +1,10 @@
## @antv/x6-vue-shape [2.0.9](https://github.com/antvis/x6/compare/@antv/x6-vue-shape@2.0.8...@antv/x6-vue-shape@2.0.9) (2022-12-21)
### Bug Fixes
* get graph from right place ([#3078](https://github.com/antvis/x6/issues/3078)) ([844ee5f](https://github.com/antvis/x6/commit/844ee5fa043cbcd788ec1693f88576e797426228))
## @antv/x6-vue-shape [2.0.7](https://github.com/antvis/x6/compare/@antv/x6-vue-shape@2.0.6...@antv/x6-vue-shape@2.0.7) (2022-12-09)

@ -1,6 +1,6 @@
{
"name": "@antv/x6-vue-shape",
"version": "2.0.7",
"version": "2.0.9",
"description": "X6 shape for rendering vue components.",
"main": "lib/index.js",
"module": "es/index.js",

@ -1,4 +1,5 @@
import { defineComponent, h, reactive, isVue3, Vue } from 'vue-demi'
import { Graph } from '@antv/x6'
import { VueShape } from './node'
let active = false
@ -9,6 +10,7 @@ export function connect(
component: any,
container: HTMLDivElement,
node: VueShape,
graph: Graph,
) {
if (active) {
const { Teleport, markRaw } = Vue as any
@ -17,6 +19,7 @@ export function connect(
render: () => h(Teleport, { to: container } as any, [h(component)]),
provide: () => ({
getNode: () => node,
getGraph: () => graph,
}),
}),
)

@ -26,6 +26,7 @@ export class VueShapeView extends NodeView<VueShape> {
this.unmountVueComponent()
const root = this.getComponentContainer()
const node = this.cell
const graph = this.graph
if (root) {
const { component } = shapeMaps[node.shape]
@ -40,12 +41,13 @@ export class VueShapeView extends NodeView<VueShape> {
provide() {
return {
getNode: () => node,
getGraph: () => graph,
}
},
})
} else if (isVue3) {
if (isActive()) {
connect(this.targetId(), component, root, node)
connect(this.targetId(), component, root, node, graph)
} else {
this.vm = createApp({
render() {
@ -54,6 +56,7 @@ export class VueShapeView extends NodeView<VueShape> {
provide() {
return {
getNode: () => node,
getGraph: () => graph,
}
},
})

@ -1,3 +1,25 @@
## @antv/x6 [2.1.4](https://github.com/antvis/x6/compare/@antv/x6@2.1.3...@antv/x6@2.1.4) (2023-01-03)
### Bug Fixes
* optimize rendering logic to prevent loops ([#3108](https://github.com/antvis/x6/issues/3108)) ([45337e4](https://github.com/antvis/x6/commit/45337e4a62224aaffd60fc8b2670a071c5560796))
## @antv/x6 [2.1.3](https://github.com/antvis/x6/compare/@antv/x6@2.1.2...@antv/x6@2.1.3) (2022-12-24)
### Bug Fixes
* schedule edge when source and target is not ready ([#3090](https://github.com/antvis/x6/issues/3090)) ([019333d](https://github.com/antvis/x6/commit/019333d79d7f22c44c400f29d501497f4323af1a))
## @antv/x6 [2.1.1](https://github.com/antvis/x6/compare/@antv/x6@2.1.0...@antv/x6@2.1.1) (2022-12-19)
### Bug Fixes
* arrowhead not get options bug ([#3065](https://github.com/antvis/x6/issues/3065)) ([3b668fe](https://github.com/antvis/x6/commit/3b668feb4eac47994f52d0cc977d22a8a2c06acd))
* set snapToGrid to false by default ([#3066](https://github.com/antvis/x6/issues/3066)) ([e2bb71d](https://github.com/antvis/x6/commit/e2bb71d95484b29187fafca97f1a386e9b984095))
# @antv/x6 [2.1.0](https://github.com/antvis/x6/compare/@antv/x6@2.0.9...@antv/x6@2.1.0) (2022-12-19)

@ -1,6 +1,6 @@
{
"name": "@antv/x6",
"version": "2.1.0",
"version": "2.1.4",
"description": "JavaScript diagramming library that uses SVG and HTML for rendering",
"main": "lib/index.js",
"module": "es/index.js",

@ -55,6 +55,8 @@ export namespace Options {
onPortRendered?: (args: OnPortRenderedArgs) => void
onEdgeLabelRendered?: (args: OnEdgeLabelRenderedArgs) => void
createCellView?: (this: Graph, cell: Cell) => CellView | null | undefined
}
export interface ManualBooleans {

@ -265,6 +265,32 @@ function findRoute(
return null
}
function snap(vertices: Point[], gridSize = 10) {
if (vertices.length <= 1) {
return vertices
}
for (let i = 0, len = vertices.length; i < len - 1; i += 1) {
const first = vertices[i]
const second = vertices[i + 1]
if (first.x === second.x) {
const x = gridSize * Math.round(first.x / gridSize)
if (first.x !== x) {
first.x = x
second.x = x
}
} else if (first.y === second.y) {
const y = gridSize * Math.round(first.y / gridSize)
if (first.y !== y) {
first.y = y
second.y = y
}
}
}
return vertices
}
export const router: Router.Definition<ManhattanRouterOptions> = function (
vertices,
optionsRaw,
@ -282,7 +308,7 @@ export const router: Router.Definition<ManhattanRouterOptions> = function (
)
const oldVertices = vertices.map((p) => Point.create(p))
let newVertices: Point[] = []
const newVertices: Point[] = []
// The origin of first route's grid, does not need snapping
let tailPoint = sourceEndpoint
@ -351,10 +377,7 @@ export const router: Router.Definition<ManhattanRouterOptions> = function (
}
if (options.snapToGrid) {
newVertices = newVertices.map((vertice) => {
const gridSize = edgeView.graph.grid.getGridSize()
return vertice.snapToGrid(gridSize)
})
return snap(newVertices, edgeView.graph.grid.getGridSize())
}
return newVertices

@ -74,6 +74,7 @@ class Arrowhead extends ToolsView.ToolItem<EdgeView, Arrowhead.Options> {
x: coords.x,
y: coords.y,
options: {
...this.options,
toolId: this.cid,
},
})

@ -1,4 +1,4 @@
import { KeyValue, Dom, Disposable } from '@antv/x6-common'
import { KeyValue, Dom, Disposable, FunctionExt } from '@antv/x6-common'
import { Rectangle } from '@antv/x6-geometry'
import { Model, Cell } from '../model'
import { View, CellView, NodeView, EdgeView } from '../view'
@ -181,13 +181,15 @@ export class Scheduler extends Disposable {
}
}
this.requestViewUpdate(
viewItem.view,
flag,
options,
cell.isNode() ? JOB_PRIORITY.RenderNode : JOB_PRIORITY.RenderEdge,
false,
)
if (viewItem) {
this.requestViewUpdate(
viewItem.view,
flag,
options,
cell.isNode() ? JOB_PRIORITY.RenderNode : JOB_PRIORITY.RenderEdge,
false,
)
}
})
this.flush()
@ -217,6 +219,18 @@ export class Scheduler extends Disposable {
if (result) {
console.log('left flag', result) // eslint-disable-line
if (
cell.isEdge() &&
(result & view.getFlag(['source', 'target'])) === 0
) {
this.queue.queueJob({
id,
priority: JOB_PRIORITY.RenderEdge,
cb: () => {
this.updateView(view, flag, options)
},
})
}
}
}
@ -375,15 +389,22 @@ export class Scheduler extends Disposable {
}
protected createCellView(cell: Cell) {
const options = { graph: this.graph }
const createViewHook = this.graph.options.createCellView
if (createViewHook) {
const ret = FunctionExt.call(createViewHook, this.graph, cell)
if (ret || ret === null) {
return ret
}
}
const view = cell.view
const options = { graph: this.graph }
if (view != null && typeof view === 'string') {
const def = CellView.registry.get(view)
if (def) {
return new def(cell, options) // eslint-disable-line new-cap
}
return CellView.registry.onNotFound(view)
}

@ -357,7 +357,12 @@ export class NodeView<
protected updatePorts() {
const groups = this.cell.getParsedGroups()
Object.keys(groups).forEach((groupName) => this.updatePortGroup(groupName))
const groupList = Object.keys(groups)
if (groupList.length === 0) {
this.updatePortGroup()
} else {
groupList.forEach((groupName) => this.updatePortGroup(groupName))
}
}
protected updatePortGroup(groupName?: string) {
@ -847,7 +852,6 @@ export class NodeView<
) {
this.graph.model.startBatch('add-edge')
const edgeView = this.createEdgeFromMagnet(magnet, x, y)
edgeView.notifyMouseDown(e, x, y) // backwards compatibility events
edgeView.setEventData(
e,
edgeView.prepareArrowheadDragging('target', {
@ -858,6 +862,7 @@ export class NodeView<
}),
)
this.setEventData<Partial<EventData.Magnet>>(e, { edgeView })
edgeView.notifyMouseDown(e, x, y)
}
protected getDefaultEdge(sourceView: CellView, sourceMagnet: Element) {

24058
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

@ -1,8 +0,0 @@
#!/usr/bin/env node
if (!/pnpm/.test(process.env.npm_execpath || '')) {
console.warn(
`This repository requires using pnpm as the package manager for scripts to work properly.`,
)
process.exit(1)
}

@ -1,18 +1,19 @@
if (window) {
(window as any).react = require('react');
(window as any).reactDom = require('react-dom');
(window as any).antd = require('antd');
(window as any).dagre = require('dagre');
(window as any).x6 = require('@antv/x6');
(window as any).x6PluginSnapline = require('@antv/x6-plugin-snapline');
(window as any).x6PluginClipboard = require('@antv/x6-plugin-clipboard');
(window as any).x6PluginKeyboard = require('@antv/x6-plugin-keyboard');
(window as any).x6PluginSelection = require('@antv/x6-plugin-selection');
(window as any).x6PluginTransform = require('@antv/x6-plugin-transform');
(window as any).x6PluginStencil = require('@antv/x6-plugin-stencil');
(window as any).x6PluginHistory = require('@antv/x6-plugin-history');
(window as any).x6ReactShape = require('@antv/x6-react-shape');
(window as any).layout = require('@antv/layout');
(window as any).hierarchy = require('@antv/hierarchy');
(window as any).elkjs = require('elkjs/lib/elk.bundled.js');
}
;(window as any).react = require('react')
;(window as any).reactDom = require('react-dom')
;(window as any).antd = require('antd')
;(window as any).dagre = require('dagre')
;(window as any).x6 = require('@antv/x6')
;(window as any).x6PluginSnapline = require('@antv/x6-plugin-snapline')
;(window as any).x6PluginClipboard = require('@antv/x6-plugin-clipboard')
;(window as any).x6PluginKeyboard = require('@antv/x6-plugin-keyboard')
;(window as any).x6PluginSelection = require('@antv/x6-plugin-selection')
;(window as any).x6PluginTransform = require('@antv/x6-plugin-transform')
;(window as any).x6PluginStencil = require('@antv/x6-plugin-stencil')
;(window as any).x6PluginHistory = require('@antv/x6-plugin-history')
;(window as any).x6ReactShape = require('@antv/x6-react-shape')
;(window as any).layout = require('@antv/layout')
;(window as any).classnames = require('classnames')
;(window as any).hierarchy = require('@antv/hierarchy')
;(window as any).elkjs = require('elkjs/lib/elk.bundled.js')
}

@ -1,3 +1,24 @@
## @antv/x6-sites [1.3.1](https://github.com/antvis/x6/compare/@antv/x6-sites@1.3.0...@antv/x6-sites@1.3.1) (2023-01-03)
### Bug Fixes
* optimize rendering logic to prevent loops ([#3108](https://github.com/antvis/x6/issues/3108)) ([45337e4](https://github.com/antvis/x6/commit/45337e4a62224aaffd60fc8b2670a071c5560796))
# @antv/x6-sites [1.3.0](https://github.com/antvis/X6/compare/@antv/x6-sites@1.2.2...@antv/x6-sites@1.3.0) (2023-01-01)
### Features
* add data processing dag example ([#3091](https://github.com/antvis/X6/issues/3091)) ([d3301d3](https://github.com/antvis/X6/commit/d3301d33d575269d9219ab1337a2ec1785d61494))
## @antv/x6-sites [1.2.2](https://github.com/antvis/X6/compare/@antv/x6-sites@1.2.1...@antv/x6-sites@1.2.2) (2022-12-24)
### Bug Fixes
* schedule edge when source and target is not ready ([#3090](https://github.com/antvis/X6/issues/3090)) ([019333d](https://github.com/antvis/X6/commit/019333d79d7f22c44c400f29d501497f4323af1a))
# @antv/x6-sites [1.2.0](https://github.com/antvis/X6/compare/@antv/x6-sites@1.1.2...@antv/x6-sites@1.2.0) (2022-12-16)

7
sites/x6-sites/LEGAL.md Normal file

@ -0,0 +1,7 @@
Legal Disclaimer
Within this source code, the comments in Chinese shall be the original, governing version. Any comment in other languages are for reference only. In the event of any conflict between the Chinese language version comments and other language version comments, the Chinese language version shall prevail.
法律免责声明
关于代码注释部分,中文注释为官方版本,其它语言注释仅做参考。中文注释可能与其它语言注释存在不一致,当中文注释与其它语言注释存在不一致时,请以中文注释为准。

@ -13,26 +13,29 @@ redirect_from:
new Graph(options: Options)
```
| 选项 | 类型 | 必选 | 默认值 | 描述 |
| ------------------------------------------------------------------------------ | ------------------------------ | :--: | ------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [container](#container) | HTMLElement | ✓ | | 画布的容器。 |
| [width](#width) | number | | `undefined` | 画布宽度,默认使用容器宽度。 |
| [height](#height) | number | | `undefined` | 画布高度,默认使用容器高度。 |
| [autoResize](#autoresize) | boolean \| Element \| Document | | `false` | 是否监听容器大小改变,并自动更新画布大小。默认监听画布容器,也可以指定监听的元素,如 `Document` |
| [panning](/zh/docs/api/graph/panning) | object | | { enabled: false, eventTypes: ['leftMouseDown'],} | 画布是否可以拖动 |
| [grid](/zh/docs/api/graph/grid) | boolean \| number \| object | | `false` | 网格,默认使用 `10px` 的网格,但不绘制网格背景。 |
| [background](/zh/docs/api/graph/background) | false \| object | | `false` | 背景,默认不绘制背景 |
| [mousewheel](/zh/docs/api/graph/mousewheel) | boolean \| object | | `false` | 鼠标滚轮缩放,默认禁用。 |
| [translating](/zh/docs/api/graph/transform#translating) | object | | object | 平移节点 |
| [embedding](/zh/docs/api/graph/interaction#embedding) | boolean \| object | | `false` | 嵌套节点,默认禁用。 |
| [connecting](/zh/docs/api/graph/interaction#connecting) | object | | object | 连线选项 |
| [highlighting](/zh/docs/api/graph/interaction#highlighting) | object | | object | 高亮选项。 |
| [interacting](/zh/docs/api/graph/interaction#interacting) | object \| function | | `{ edgeLabelMovable: false }` | 定制节点和边的交互行为。 |
| [magnetThreshold](/zh/docs/api/graph/view#magnetThreshold) | number \| 'onleave' | | `0` | 鼠标移动多少次后才触发连线,或者设置为 `'onleave'` 时表示鼠标移出元素时才触发连线。 |
| [moveThreshold](/zh/docs/api/graph/view#moveThreshold) | number | | `0` | 触发 `'mousemove'` 事件之前,允许鼠标移动的次数。 |
| [clickThreshold](/zh/docs/api/graph/view#clickThreshold) | number | | `0` | 当鼠标移动次数超过指定的数字时,将不触发鼠标点击事件。 |
| [preventDefaultContextMenu](/zh/docs/api/graph/view#preventDefaultContextMenu) | boolean | | `true` | 是否禁用浏览器默认右键菜单 |
| [preventDefaultBlankAction](/zh/docs/api/graph/view#preventDefaultBlankAction) | boolean | | `true` | 在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为。 |
| [guard](/zh/docs/api/graph/view#guard) | function | | `() => false` | 返回是否应该忽略某个鼠标事件,返回 `true` 时忽略指定的鼠标事件。 |
| [async](/zh/docs/api/graph/view#async) | boolean | | `true` | 是否异步渲染 |
| [virtual](/zh/docs/api/graph/view#virtual) | boolean | | `false` | 是否只渲染可视区域内容 |
| 选项 | 类型 | 必选 | 描述 | 默认值 |
| ------------------------------------------------------------------------------ | ------------------------------ | :--: | ------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| containers | HTMLElement | ✓ | 画布的容器。 | |
| width | number | | 画布宽度,默认使用容器宽度。 | - |
| height | number | | 画布高度,默认使用容器高度。 | - |
| scaling | { min?: number, max?: number } | | 画布的最小最大缩放级别。 | { min: 0.01, max: 16 } |
| [autoResize](/zh/docs/tutorial/basic/graph#画布大小) | boolean \| Element \| Document | | 是否监听容器大小改变,并自动更新画布大小。 | `false` |
| [panning](/zh/docs/api/graph/panning) | boolean \| `PanningManager.Options` | | 画布是否可以拖拽平移,默认禁用。 | `false` |
| [mousewheel](/zh/docs/api/graph/mousewheel) | boolean \| `MouseWheel.Options` | | 鼠标滚轮缩放,默认禁用| `false` |
| [grid](/zh/docs/api/graph/grid) | boolean \| number \| `GridManager.Options` | | 网格,默认使用 `10px` 的网格,但不绘制网格背景。 | `false` |
| [background](/zh/docs/api/graph/background) | false \| `BackgroundManager.Options` | | 背景,默认不绘制背景| `false` |
| [translating](/zh/docs/api/interacting/interaction#trasnlating) | `Translating.Options` | | 限制节点移动。 | { restrict: false } |
| [embedding](/zh/docs/api/interacting/interaction#embedding) | boolean \| `Embedding.Options` | | 嵌套节点,默认禁用| `false` |
| [connecting](/zh/docs/api/interacting/interaction#connecting) | `Connecting.Options` | | 连线选项。 | { snap: false, ... } |
| [highlighting](/zh/docs/api/interacting/interaction#highlighting) | `Highlighting.Options` | | 高亮选项。 | {...} |
| [interacting](/zh/docs/api/interacting/interaction#interacting) | `Interacting.Options` | | 定制节点和边的交互行为。 | { edgeLabelMovable: false } |
| [magnetThreshold](/zh/docs/api/graph/view#magnetthreshold) | number \| 'onleave' | | 鼠标移动多少次后才触发连线,或者设置为 `'onleave'` 时表示鼠标移出元素时才触发连线。 | `0` |
| [moveThreshold](/zh/docs/api/graph/view#movethreshold) | number | | 触发 `'mousemove'` 事件之前,允许鼠标移动的次数。 | `0` |
| [clickThreshold](/zh/docs/api/graph/view#clickthreshold) | number | | 当鼠标移动次数超过指定的数字时,将不触发鼠标点击事件| `0` |
| [preventDefaultContextMenu](/zh/docs/api/graph/view#preventdefaultcontextmenu) | boolean | | 是否禁用浏览器默认右键菜单。 | `true` |
| [preventDefaultBlankAction](/zh/docs/api/graph/view#preventdefaultblankaction) | boolean | | 在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为。 | `true` |
| [async](/zh/docs/api/graph/view#async) | boolean | | 是否异步渲染 | `true` |
| [virtual](/zh/docs/api/graph/view#virtual) | boolean | | 是否只渲染可视区域内容 | `false` |
| [onPortRendered](/zh/docs/api/graph/view#onportrendered) | (args: OnPortRenderedArgs) => void | | 当某个连接桩渲染完成时触发的回调。 | - |
| [onEdgeLabelRendered](/zh/docs/api/graph/view#onedgelabelrendered) | (args: OnEdgeLabelRenderedArgs) => void | | 当边的文本标签渲染完成时触发的回调。 | - |
| [createCellView](/zh/docs/api/graph/view#createcellview) | (this: Graph, cell: Cell) => CellView \| null \| undefined | | 是自定义元素的视图。 | - |

@ -10,10 +10,14 @@ redirect_from:
### async
是否是异步渲染的画布。异步渲染不会阻塞 UI对需要添加大量节点和边时的性能提升非常明显。但需要注意的是一些同步操作可能会出现意外结果比如获取某个节点的视图、获取节点/边的包围盒等,因为这些同步操作触发时异步渲染可能并没有完成,此时只能通过监听 `render:done` 事件来确保所有变更都已经生效,然后在事件回调中进行这些操作
是否是异步渲染的画布。异步渲染不会阻塞 UI对需要添加大量节点和边时的性能提升非常明显。但需要注意的是一些同步操作可能会出现意外结果比如获取某个节点的视图、获取节点/边的包围盒等,因为这些同步操作触发时异步渲染可能并没有完成。
<!-- <iframe src="/demos/api/graph/async"></iframe> -->
### virtual
是否只渲染可视区域内的元素,默认为 `false`,如果设置为 `true`,首屏加载只会渲染当前可视区域内的元素,当拖动画布或者缩放画布时,会根据画布窗口大小自动加载剩余元素。在元素数量很大的场景,性能提升非常明显。
### magnetThreshold
鼠标移动多少次后才触发连线,或者设置为 'onleave' 时表示鼠标移出元素时才触发连线,默认为 `0`
@ -34,14 +38,6 @@ redirect_from:
在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为,默认为 `true`
### guard
```sign
(e: Dom.EventObject, view?: CellView | null) => boolean
```
是否应该忽略某个鼠标事件,返回 `true` 时忽略指定的鼠标事件,否则不忽略。
### onPortRendered
```sign
@ -60,9 +56,7 @@ redirect_from:
) => void
```
当某个连接桩渲染完成时触发的回调
<span class="tag-param">args 参数<span>
当某个连接桩渲染完成时触发的回调,参数如下:
| 名称 | 类型 | 非空 | 描述 |
| ---------------- | ---------------- | :--: | ---------------------------------------- |
@ -75,7 +69,6 @@ redirect_from:
| contentContainer | Element | ✓ | 连接桩内容的容器元素。 |
| contentSelectors | Markup.Selectors | | 连接桩内容 Markup 渲染后的选择器键值对。 |
<span class="tag-example">使用<span>
例如,我们可以渲染一个 React 类型的连接桩。
@ -97,7 +90,7 @@ const graph = new Graph({
});
```
<iframe src="/demos/tutorial/advanced/react/react-port"></iframe>
<!-- <iframe src="/demos/tutorial/advanced/react/react-port"></iframe> -->
### onEdgeLabelRendered
@ -113,9 +106,8 @@ const graph = new Graph({
) => void
```
当边的文本标签渲染完成时触发的回调
当边的文本标签渲染完成时触发的回调,参数如下:
<span class="tag-param">args 参数<span>
| 名称 | 类型 | 非空 | 描述 |
| --------- | ---------------- | :--: | -------------------------------------- |
@ -124,7 +116,6 @@ const graph = new Graph({
| container | Element | ✓ | 文本标签容器。 |
| selectors | Markup.Selectors | ✓ | 文本标签 Markup 渲染后的选择器键值对。 |
<span class="tag-example">使用<span>
例如,我们可以在标签上渲染任何想要的元素。
@ -164,7 +155,7 @@ const graph = new Graph({
});
```
<iframe src="/demos/tutorial/advanced/react/react-label-base"></iframe>
<!-- <iframe src="/demos/tutorial/advanced/react/react-label-base"></iframe> -->
我们也可以在定义 Label 的 Markup 时添加 `<foreignObject>` 元素来支持 HTML 和 React 的渲染能力。
@ -185,72 +176,21 @@ const graph = new Graph({
});
```
<iframe src="/demos/tutorial/advanced/react/react-label-markup"></iframe>
<!-- <iframe src="/demos/tutorial/advanced/react/react-label-markup"></iframe> -->
### onToolItemCreated
### createCellView
```sign
(
this: Graph,
args: {
name: string
cell: Cell
view: CellView
tool: View
},
) => void
cell: Cell,
) => CellView | null | undefined
```
当工具项渲染完成时触发的回调。
<span class="tag-param">args 参数<span>
| 名称 | 类型 | 非空 | 描述 |
| ---- | -------- | :--: | ------------- |
| cell | Cell | ✓ | 节点/边实例。 |
| view | CellView | ✓ | 节点/边视图。 |
| name | string | ✓ | 工具项名称。 |
| tool | View | ✓ | 工具视图。 |
<span class="tag-example">使用<span>
例如,我们为 `vertices` 工具设置间隔填充效果。
```ts
const graph = new Graph({
container: this.container,
grid: true,
onToolItemCreated({ name, cell, tool }) {
if (name === "vertices" && cell === edge2) {
const options = (tool as any).options;
if (options && options.index % 2 === 1) {
tool.setAttrs({ fill: "red" });
}
}
},
});
```
<iframe src="/demos/api/registry/edge-tool/vertices"></iframe>
自定义元素的视图,可以返回一个 `CellView`,会替换默认的视图,如果返回 `null`,则不会渲染,如果返回 `undefined`,会按照默认方式渲染。
## 方法
### isAsync()
```sign
isAsync(): boolean
```
返回画布是否是异步渲染模式。异步渲染不会阻塞 UI对需要添加大量节点和边时的性能提升非常明显异步画布的使用细节请参考 [`async`](#async) 选项。
### isFrozen()
```sign
isFrozen(): boolean
```
返回[异步画布](#async)是否处于冻结状态。处于冻结状态的画布不会立即响应画布中节点和边的变更,直到调用 [`unfreeze(...)`](#unfreeze) 方法来解除冻结并重新渲染画布。
### findView(...)
```sign

@ -72,7 +72,7 @@ export interface Connecting {
### snap
`snap` 设置为 `true` 时连线的过程中距离节点或者连接桩 `50px` 时会触发自动吸附,可以通过配置 `radius` 属性自定义触发吸附的距离。当 `snap` 设置为 `false` 时不会触发自动吸附。默认值为 `false`
`snap` 设置为 `true` 时连线的过程中距离节点或者连接桩 `50px` 时会触发自动吸附,可以通过配置 `radius` 属性自定义触发吸附的距离。当 `snap` 设置为 `false` 时不会触发自动吸附。默认值为 `false`
```ts
const graph = new Graph({
@ -92,35 +92,35 @@ const graph = new Graph({
### allowBlank
是否允许连接到画布空白位置的点,默认为 `true`
是否允许连接到画布空白位置的点,默认为 `true`
### allowMulti
是否允许在相同的起始节点和终止之间创建多条边,默认为 `true`。当设置为 `false` 时,在起始和终止节点之间只允许创建一条边,当设置为 `'withPort'` 时,在起始和终止节点的相同连接桩之间只允许创建一条边(即,起始和终止节点之间可以创建多条边,但必须要要链接在不同的连接桩上)。
是否允许在相同的起始节点和终止之间创建多条边,默认为 `true` 。当设置为 `false` 时,在起始和终止节点之间只允许创建一条边,当设置为 `'withPort'` 时,在起始和终止节点的相同连接桩之间只允许创建一条边(即,起始和终止节点之间可以创建多条边,但必须要要链接在不同的连接桩上)。
### allowLoop
是否允许创建循环连线,即边的起始节点和终止节点为同一节点,默认为 `true`
是否允许创建循环连线,即边的起始节点和终止节点为同一节点,默认为 `true`
### allowNode
是否允许边链接到节点(非节点上的连接桩),默认为 `true`
是否允许边链接到节点(非节点上的连接桩),默认为 `true`
### allowEdge
是否允许边链接到另一个边,默认为 `true`
是否允许边链接到另一个边,默认为 `true`
### allowPort
是否允许边链接到连接桩,默认为 `true`
是否允许边链接到连接桩,默认为 `true`
### highlight
拖动边时,是否高亮显示所有可用的连接桩或节点,默认值为 `false`
拖动边时,是否高亮显示所有可用的连接桩或节点,默认值为 `false`
### anchor
当连接到节点时,通过 [`anchor`](/zh/docs/api/registry/node-anchor) 来指定被连接的节点的锚点,默认值为 `center`
当连接到节点时,通过 [ `anchor` ](/zh/docs/api/registry/node-anchor) 来指定被连接的节点的锚点,默认值为 `center`
#### sourceAnchor
@ -132,7 +132,7 @@ const graph = new Graph({
### edgeAnchor
当连接到边时,通过 [`edgeAnchor`](/zh/docs/api/registry/edge-anchor) 来指定被连接的边的锚点,默认值为 `ratio`
当连接到边时,通过 [ `edgeAnchor` ](/zh/docs/api/registry/edge-anchor) 来指定被连接的边的锚点,默认值为 `ratio`
### sourceEdgeAnchor
@ -144,7 +144,7 @@ const graph = new Graph({
### connectionPoint
指定[连接点](/zh/docs/api/registry/connector),默认值为 `boundary`
指定[连接点](/zh/docs/api/registry/connector),默认值为 `boundary`
### sourceConnectionPoint
@ -156,11 +156,11 @@ const graph = new Graph({
#### router
[路由](/zh/docs/api/registry/router)将边的路径点 `vertices` 做进一步转换处理,并在必要时添加额外的点,然后返回处理后的点,默认值为 `normal`
[路由](/zh/docs/api/registry/router)将边的路径点 `vertices` 做进一步转换处理,并在必要时添加额外的点,然后返回处理后的点,默认值为 `normal`
### connector
[连接器](/zh/docs/api/registry/connector)将起点、路由返回的点、终点加工为 <path> 元素的 d 属性,决定了边渲染到画布后的样式,默认值为 `normal`
[连接器](/zh/docs/api/registry/connector)将起点、路由返回的点、终点加工为 <path> 元素的 d 属性,决定了边渲染到画布后的样式,默认值为 `normal`
### createEdge
@ -168,7 +168,7 @@ const graph = new Graph({
### validateMagnet
点击 `magnet` 时 根据 `validateMagnet` 返回值来判断是否新增边,触发时机是 `magnet` 被按下,如果返回 `false`,则没有任何反应,如果返回 `true`,会在当前 `magnet` 创建一条新的边。
点击 `magnet` 时 根据 `validateMagnet` 返回值来判断是否新增边,触发时机是 `magnet` 被按下,如果返回 `false` ,则没有任何反应,如果返回 `true` ,会在当前 `magnet` 创建一条新的边。
```ts
validateMagnet({ e, magnet, view, cell }) {
@ -178,7 +178,7 @@ validateMagnet({ e, magnet, view, cell }) {
### validateConnection
在移动边的时候判断连接是否有效,如果返回 `false`,当鼠标放开的时候,不会连接到当前元素,否则会连接到当前元素。
在移动边的时候判断连接是否有效,如果返回 `false` ,当鼠标放开的时候,不会连接到当前元素,否则会连接到当前元素。
```ts
validateConnection({
@ -200,7 +200,7 @@ validateConnection({
### validateEdge
当停止拖动边的时候根据 `validateEdge` 返回值来判断边是否生效,如果返回 `false`, 该边会被清除。
当停止拖动边的时候根据 `validateEdge` 返回值来判断边是否生效,如果返回 `false` , 该边会被清除。
```ts
validateEdge({ edge, type, previous }) {
@ -240,19 +240,19 @@ export interface Embedding {
### enabled
是否允许节点之间嵌套,默认值为 `false`
是否允许节点之间嵌套,默认值为 `false`
### findParent
在节点被移动时通过 `findParent` 指定的方法返回父节点。默认值为 `bbox`
在节点被移动时通过 `findParent` 指定的方法返回父节点。默认值为 `bbox`
### frontOnly
如果 `frontOnly``true`,则只能嵌入显示在最前面的节点,默认值为 `true`
如果 `frontOnly``true` ,则只能嵌入显示在最前面的节点,默认值为 `true`
### validate
`validate` 为判断节点能否被嵌入父节点的函数,默认返回 `true`
`validate` 为判断节点能否被嵌入父节点的函数,默认返回 `true`
## interacting
@ -283,17 +283,17 @@ export type Interacting =
| ((this: Graph, cellView: CellView) => InteractionMap | boolean);
```
- `boolean` 节点或边是否可交互
- `InteractionMap` 节点或边的交互细节,支持以下属性:
- `'nodeMovable'` 节点是否可以被移动。
- `'magnetConnectable'` 当在具有 `'magnet'` 属性的元素上按下鼠标开始拖动时,是否触发连线交互。
- `'edgeMovable'` 边是否可以被移动。
- `'edgeLabelMovable'` 边的标签是否可以被移动。
- `'arrowheadMovable'` 边的起始/终止箭头是否可以被移动。
- `'vertexMovable'` 边的路径点是否可以被移动。
- `'vertexAddable'` 是否可以添加边的路径点。
- `'vertexDeletable'` 边的路径点是否可以被删除。
- `(this: Graph, cellView: CellView) => InteractionMap | boolean`
* `boolean` 节点或边是否可交互
* `InteractionMap` 节点或边的交互细节,支持以下属性:
+ `'nodeMovable'` 节点是否可以被移动。
+ `'magnetConnectable'` 当在具有 `'magnet'` 属性的元素上按下鼠标开始拖动时,是否触发连线交互。
+ `'edgeMovable'` 边是否可以被移动。
+ `'edgeLabelMovable'` 边的标签是否可以被移动。
+ `'arrowheadMovable'` 边的起始/终止箭头是否可以被移动。
+ `'vertexMovable'` 边的路径点是否可以被移动。
+ `'vertexAddable'` 是否可以添加边的路径点。
+ `'vertexDeletable'` 边的路径点是否可以被删除。
* `(this: Graph, cellView: CellView) => InteractionMap | boolean`
```ts
const graph = new Graph({
@ -334,10 +334,41 @@ new Graph({
支持的 `highlighting` 配置项有:
- `'default'` 默认高亮选项,当以下几种高亮配置缺省时被使用。
- `'embedding'` 拖动节点进行嵌入操作过程中,节点可以被嵌入时被使用。
- `'nodeAvailable'` 连线过程中,节点可以被链接时被使用。
- `'magnetAvailable'` 连线过程中,连接桩可以被链接时被使用。
- `'magnetAdsorbed'` 连线过程中,自动吸附到连接桩时被使用。
* `'default'` 默认高亮选项,当以下几种高亮配置缺省时被使用。
* `'embedding'` 拖动节点进行嵌入操作过程中,节点可以被嵌入时被使用。
* `'nodeAvailable'` 连线过程中,节点可以被链接时被使用。
* `'magnetAvailable'` 连线过程中,连接桩可以被链接时被使用。
* `'magnetAdsorbed'` 连线过程中,自动吸附到连接桩时被使用。
上面 `magnetAvailable.name` 其实是高亮器的名称X6 内置了 `stroke``className` 两种高亮器,详细信息参考 [Highlighter](/zh/docs/api/registry/highlighter)
## trasnlating
可以在全局配置 `translating` 来限制节点的移动范围。
```ts
const graph = new Graph({
translating: {
restrict: true,
},
})
```
### restrict
节点的可移动范围。支持以下两种方式:
* `boolean` 如果设置为 `true`, 节点不能移动超出画布区域
* `Rectangle.RectangleLike | (arg: CellView) => Rectangle.RectangleLike` 指定一个节点的移动范围
```ts
const graph = new Graph({
translating: {
restrict: {
x: 0,
y: 0,
width: 100,
height: 100,
}
}
})

@ -221,11 +221,11 @@ graph.addEdge({
支持的参数如下表:
| 参数名 | 参数类型 | 是否必选 | 默认值 | 参数说明 |
| --------- | ------------------ | :------: | ------ | -------------------------------------------------------------------------------------------------- | --- | ---- | --- | --------- | ------------------------------------ |
| offset | number \| 'center' | 否 | `32` | 路由的第一个点和最后一个点与节点之间的距离。当取值为 `'center'` 时,节点距离的中心作为路由点坐标。 |
| min | number | 否 | `16` | 路由的第一个点和最后一个点与节点之间的最小距离。 |
| direction | `'T' | 'B' | 'L' | 'R' | 'H' | 'V'` | 否 | undefined | 路由方向,缺省时将自动选择最优方向。 |
| 参数名 | 参数类型 | 是否必选 | 默认值 | 参数说明 |
| --------- | ---------------------------------------- | -------- | --------- | ------------------------------------------------------------ |
| offset | number \|'center' | 否 | `32` | 路由的第一个点和最后一个点与节点之间的距离。当取值为 `'center'` 时,节点距离的中心作为路由点坐标。 |
| min | number | 否 | `16` | 路由的第一个点和最后一个点与节点之间的最小距离。 |
| direction | `'T'`\|`'B'`\|`'L'`\|`'R'`\|`'H'`\|`'V'` | 否 | undefined | 路由方向,缺省时将自动选择最优方向。 |
例如:

@ -11,9 +11,9 @@ X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和
如果你还没有使用过 X6 建议通过 [快速上手](/zh/docs/tutorial/getting-started) 抢先体验 X6 的魅力。
<p align="left">
<a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/workflow/status/antvis/x6/%F0%9F%91%B7%E3%80%80CI/master?logo=github&style=flat-square"></a>
<a href="https://app.codecov.io/gh/antvis/X6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&style=flat-square&token=15CO54WYUV"></a>
<a href="https://lgtm.com/projects/g/antvis/x6/context:javascript"><img alt="Language grade: JavaScript" src="https://img.shields.io/lgtm/grade/javascript/g/antvis/x6.svg?logo=lgtm&style=flat-square"></a>
<a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/actions/workflow/status/antvis/x6/ci.yml?branch=master&logo=github&style=flat-square"></a>
<!-- <a href="https://app.codecov.io/gh/antvis/X6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&style=flat-square&token=15CO54WYUV"></a>
<a href="https://lgtm.com/projects/g/antvis/x6/context:javascript"><img alt="Language grade: JavaScript" src="https://img.shields.io/lgtm/grade/javascript/g/antvis/x6.svg?logo=lgtm&style=flat-square"></a> -->
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Package" src="https://img.shields.io/npm/v/@antv/x6.svg?style=flat-square"></a>
<a href="https://www.npmjs.com/package/@antv/x6"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@antv/x6?logo=npm&style=flat-square"></a>
</p>

@ -70,11 +70,12 @@ export default () => {
| 选项 | 类型 | 必选 | 默认值 | 说明 |
| -------------------- | ----------------------------------------------------------------------------------- | :--: | ------ | -------------------------------------------------------------------------------------------------------- |
| options.target | Graph | ✓️ | | 目标画布。 |
| options.getDragNode | (sourceNode: Node, options: GetDragNodeOptions) => Node | | | 拖拽开始时,获取被拖拽的节点,默认克隆 `dnd.start` 传入的节点。 |
| options.getDropNode | (draggingNode: Node, options: GetDropNodeOptions) => Node | | | 拖拽结束时,获取放置到目标画布的节点,默认克隆被拖拽的节点。 |
| options.validateNode | (droppingNode: Node, options: ValidateNodeOptions) => boolean \| Promins\<boolean\> | | | 拖拽结束时,验证节点是否可以放置到目标画布中。 |
| options.dndContainer | HTMLElement | | | 如果设置 `dndContainer`,在 `dndContainer` 上放开鼠标不会放置节点,常用于 `dnd` 容器处于画布上面的场景。 |
| target | Graph | ✓️ | | 目标画布。 |
| getDragNode | (sourceNode: Node, options: GetDragNodeOptions) => Node | | | 拖拽开始时,获取被拖拽的节点,默认克隆 `dnd.start` 传入的节点。 |
| getDropNode | (draggingNode: Node, options: GetDropNodeOptions) => Node | | | 拖拽结束时,获取放置到目标画布的节点,默认克隆被拖拽的节点。 |
| validateNode | (droppingNode: Node, options: ValidateNodeOptions) => boolean \| Promins\<boolean\> | | | 拖拽结束时,验证节点是否可以放置到目标画布中。 |
| dndContainer | HTMLElement | | | 如果设置 `dndContainer`,在 `dndContainer` 上放开鼠标不会放置节点,常用于 `dnd` 容器处于画布上面的场景。 |
| draggingContainer | HTMLElement | | `document.body` | 自定义拖拽画布容器。 |
## 常见问题

@ -0,0 +1,869 @@
import React from 'react'
import { Graph, Node, Path, Edge, Platform, StringExt } from '@antv/x6'
import { Selection } from '@antv/x6-plugin-selection'
import classnames from 'classnames'
import insertCss from 'insert-css'
import { register } from '@antv/x6-react-shape'
import { Tooltip, Dropdown } from 'antd'
// 节点类型
enum NodeType {
INPUT = 'INPUT', // 数据输入
FILTER = 'FILTER', // 数据过滤
JOIN = 'JOIN', // 数据连接
UNION = 'UNION', // 数据合并
AGG = 'AGG', // 数据聚合
OUTPUT = 'OUTPUT', // 数据输出
}
// 元素校验状态
enum CellStatus {
DEFAULT = 'default',
SUCCESS = 'success',
ERROR = 'error',
}
// 节点位置信息
interface Position {
x: number
y: number
}
// 加工类型列表
const PROCESSING_TYPE_LIST = [
{
type: 'FILTER',
name: '数据筛选',
},
{
type: 'JOIN',
name: '数据连接',
},
{
type: 'UNION',
name: '数据合并',
},
{
type: 'AGG',
name: '数据聚合',
},
{
type: 'OUTPUT',
name: '数据输出',
},
]
// 不同节点类型的icon
const NODE_TYPE_LOGO = {
INPUT:
'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*RXnuTpQ22xkAAAAAAAAAAAAADtOHAQ/original', // 数据输入
FILTER:
'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*ZJ6qToit8P4AAAAAAAAAAAAADtOHAQ/original', // 数据筛选
JOIN: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*EHqyQoDeBvIAAAAAAAAAAAAADtOHAQ/original', // 数据连接
UNION:
'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*k4eyRaXv8gsAAAAAAAAAAAAADtOHAQ/original', // 数据合并
AGG: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*TKG8R6nfYiAAAAAAAAAAAAAADtOHAQ/original', // 数据聚合
OUTPUT:
'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*zUgORbGg1HIAAAAAAAAAAAAADtOHAQ/original', // 数据输出
}
/**
* 根据起点初始下游节点的位置信息
* @param node 起始节点
* @param graph
* @returns
*/
const getDownstreamNodePosition = (
node: Node,
graph: Graph,
dx = 250,
dy = 100,
) => {
// 找出画布中以该起始节点为起点的相关边的终点id集合
const downstreamNodeIdList: string[] = []
graph.getEdges().forEach((edge) => {
const originEdge = edge.toJSON()?.data
if (originEdge.source === node.id) {
downstreamNodeIdList.push(originEdge.target)
}
})
// 获取起点的位置信息
const position = node.getPosition()
let minX = Infinity
let maxY = -Infinity
graph.getNodes().forEach((graphNode) => {
if (downstreamNodeIdList.indexOf(graphNode.id) > -1) {
const nodePosition = graphNode.getPosition()
// 找到所有节点中最左侧的节点的x坐标
if (nodePosition.x < minX) {
minX = nodePosition.x
}
// 找到所有节点中最x下方的节点的y坐标
if (nodePosition.y > maxY) {
maxY = nodePosition.y
}
}
})
return {
x: minX !== Infinity ? minX : position.x + dx,
y: maxY !== -Infinity ? maxY + dy : position.y,
}
}
// 根据节点的类型获取ports
const getPortsByType = (type: NodeType, nodeId: string) => {
let ports = []
switch (type) {
case NodeType.INPUT:
ports = [
{
id: `${nodeId}-out`,
group: 'out',
},
]
break
case NodeType.OUTPUT:
ports = [
{
id: `${nodeId}-in`,
group: 'in',
},
]
break
default:
ports = [
{
id: `${nodeId}-in`,
group: 'in',
},
{
id: `${nodeId}-out`,
group: 'out',
},
]
break
}
return ports
}
/**
* 创建节点并添加到画布
* @param type 节点类型
* @param graph
* @param position 节点位置
* @returns
*/
export const createNode = (
type: NodeType,
graph: Graph,
position?: Position,
) => {
if (!graph) {
return {}
}
let newNode = {}
const sameTypeNodes = graph
.getNodes()
.filter((item) => item.getData()?.type === type)
const typeName = PROCESSING_TYPE_LIST?.find(
(item) => item.type === type,
)?.name
const id = StringExt.uuid()
const node = {
id,
shape: 'data-processing-dag-node',
x: position?.x,
y: position?.y,
ports: getPortsByType(type, id),
data: {
name: `${typeName}_${sameTypeNodes.length + 1}`,
type,
},
}
newNode = graph.addNode(node)
return newNode
}
/**
* 创建边并添加到画布
* @param source
* @param target
* @param graph
*/
const createEdge = (source: string, target: string, graph: Graph) => {
const edge = {
id: StringExt.uuid(),
shape: 'data-processing-curve',
source: {
cell: source,
port: `${source}-out`,
},
target: {
cell: target,
port: `${target}-in`,
},
zIndex: -1,
data: {
source,
target,
},
}
if (graph) {
graph.addEdge(edge)
}
}
class DataProcessingDagNode extends React.Component<{
node: Node
}> {
state = {
plusActionSelected: false,
}
// 创建下游的节点和边
createDownstream = (type: NodeType) => {
const { node } = this.props
const { graph } = node.model || {}
if (graph) {
// 获取下游节点的初始位置信息
const position = getDownstreamNodePosition(node, graph)
// 创建下游节点
const newNode = createNode(type, graph, position)
const source = node.id
const target = newNode.id
// 创建该节点出发到下游节点的边
createEdge(source, target, graph)
}
}
// 点击添加下游+号
clickPlusDragMenu = (type: NodeType) => {
this.createDownstream(type)
this.setState({
plusActionSelected: false,
})
}
// 获取+号下拉菜单
getPlusDagMenu = () => {
return (
<ul>
{PROCESSING_TYPE_LIST.map((item) => {
const content = (
// eslint-disable-next-line
<a onClick={() => this.clickPlusDragMenu(item.type)}>
<i
className="node-mini-logo"
style={{ backgroundImage: `url(${NODE_TYPE_LOGO[item.type]})` }}
/>
<span>{item.name}</span>
</a>
)
return (
<li className="each-sub-menu" key={item.type}>
{content}
</li>
)
})}
</ul>
)
}
// 添加下游菜单的打开状态变化
onPlusDropdownOpenChange = (value: boolean) => {
this.setState({
plusActionSelected: value,
})
}
// 鼠标进入矩形主区域的时候显示连接桩
onMainMouseEnter = () => {
const { node } = this.props
// 获取该节点下的所有连接桩
const ports = node.getPorts() || []
ports.forEach((port) => {
node.setPortProp(port.id, 'attrs/circle', {
fill: '#fff',
stroke: '#85A5FF',
})
})
}
// 鼠标离开矩形主区域的时候隐藏连接桩
onMainMouseLeave = () => {
const { node } = this.props
// 获取该节点下的所有连接桩
const ports = node.getPorts() || []
ports.forEach((port) => {
node.setPortProp(port.id, 'attrs/circle', {
fill: 'transparent',
stroke: 'transparent',
})
})
}
render() {
const { plusActionSelected } = this.state
const { node } = this.props
const data = node?.getData()
const { name, type, status, statusMsg } = data
return (
<div className="data-processing-dag-node">
<div
className="main-area"
onMouseEnter={this.onMainMouseEnter}
onMouseLeave={this.onMainMouseLeave}
>
<div className="main-info">
{/* 节点类型icon */}
<i
className="node-logo"
style={{ backgroundImage: `url(${NODE_TYPE_LOGO[type]})` }}
/>
<Tooltip title={name} mouseEnterDelay={0.8}>
<div className="ellipsis-row node-name">{name}</div>
</Tooltip>
</div>
{/* 节点状态信息 */}
<div className="status-action">
{status === CellStatus.ERROR && (
<Tooltip title={statusMsg}>
<i className="status-icon status-icon-error" />
</Tooltip>
)}
{status === CellStatus.SUCCESS && (
<i className="status-icon status-icon-success" />
)}
{/* 节点操作菜单 */}
<div className="more-action-container">
<i className="more-action" />
</div>
</div>
</div>
{/* 添加下游节点 */}
{type !== NodeType.OUTPUT && (
<div className="plus-dag">
<Dropdown
dropdownRender={this.getPlusDagMenu}
overlayClassName="processing-node-menu"
trigger={['click']}
placement="bottom"
open={plusActionSelected}
onOpenChange={this.onPlusDropdownOpenChange}
>
<i
className={classnames('plus-action', {
'plus-action-selected': plusActionSelected,
})}
/>
</Dropdown>
</div>
)}
</div>
)
}
}
register({
shape: 'data-processing-dag-node',
width: 212,
height: 48,
component: DataProcessingDagNode,
// port默认不可见
ports: {
groups: {
in: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: 'transparent',
strokeWidth: 1,
fill: 'transparent',
},
},
},
out: {
position: {
name: 'right',
args: {
dx: -32,
},
},
attrs: {
circle: {
r: 4,
magnet: true,
stroke: 'transparent',
strokeWidth: 1,
fill: 'transparent',
},
},
},
},
},
})
// 注册连线
Graph.registerConnector(
'curveConnector',
(sourcePoint, targetPoint) => {
const hgap = Math.abs(targetPoint.x - sourcePoint.x)
const path = new Path()
path.appendSegment(
Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y),
)
path.appendSegment(
Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y),
)
// 水平三阶贝塞尔曲线
path.appendSegment(
Path.createSegment(
'C',
sourcePoint.x < targetPoint.x
? sourcePoint.x + hgap / 2
: sourcePoint.x - hgap / 2,
sourcePoint.y,
sourcePoint.x < targetPoint.x
? targetPoint.x - hgap / 2
: targetPoint.x + hgap / 2,
targetPoint.y,
targetPoint.x - 6,
targetPoint.y,
),
)
path.appendSegment(
Path.createSegment('L', targetPoint.x + 2, targetPoint.y),
)
return path.serialize()
},
true,
)
Edge.config({
markup: [
{
tagName: 'path',
selector: 'wrap',
attrs: {
fill: 'none',
cursor: 'pointer',
stroke: 'transparent',
strokeLinecap: 'round',
},
},
{
tagName: 'path',
selector: 'line',
attrs: {
fill: 'none',
pointerEvents: 'none',
},
},
],
connector: { name: 'curveConnector' },
attrs: {
wrap: {
connection: true,
strokeWidth: 10,
strokeLinejoin: 'round',
},
line: {
connection: true,
stroke: '#A2B1C3',
strokeWidth: 1,
targetMarker: {
name: 'classic',
size: 6,
},
},
},
})
Graph.registerEdge('data-processing-curve', Edge, true)
const graph: Graph = new Graph({
container: document.getElementById('container')!,
panning: {
enabled: true,
eventTypes: ['leftMouseDown', 'mouseWheel'],
},
mousewheel: {
enabled: true,
modifiers: 'ctrl',
factor: 1.1,
maxScale: 1.5,
minScale: 0.5,
},
highlighting: {
magnetAdsorbed: {
name: 'stroke',
args: {
attrs: {
fill: '#fff',
stroke: '#31d0c6',
strokeWidth: 4,
},
},
},
},
connecting: {
snap: true,
allowBlank: false,
allowLoop: false,
highlight: true,
sourceAnchor: {
name: 'left',
args: {
dx: Platform.IS_SAFARI ? 4 : 8,
},
},
targetAnchor: {
name: 'right',
args: {
dx: Platform.IS_SAFARI ? 4 : -8,
},
},
createEdge() {
return graph.createEdge({
shape: 'data-processing-curve',
attrs: {
line: {
strokeDasharray: '5 5',
},
},
zIndex: -1,
})
},
// 连接桩校验
validateConnection({ sourceMagnet, targetMagnet }) {
// 只能从输出链接桩创建连接
if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
return false
}
// 只能连接到输入链接桩
if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
return false
}
return true
},
},
})
graph.use(
new Selection({
enabled: true,
multiple: true,
rubberEdge: true,
rubberNode: true,
modifiers: 'shift',
rubberband: true,
}),
)
// 节点状态列表
const nodeStatusList = [
{
id: 'node-0',
status: 'success',
},
{
id: 'node-1',
status: 'success',
},
{
id: 'node-2',
status: 'success',
},
{
id: 'node-3',
status: 'success',
},
{
id: 'node-4',
status: 'error',
statusMsg: '错误信息示例',
},
]
// 边状态列表
const edgeStatusList = [
{
id: 'edge-0',
status: 'success',
},
{
id: 'edge-1',
status: 'success',
},
{
id: 'edge-2',
status: 'success',
},
{
id: 'edge-3',
status: 'success',
},
]
// 显示节点状态
const showNodeStatus = () => {
nodeStatusList.forEach((item) => {
const { id, status, statusMsg } = item
const node = graph.getCellById(id)
const data = node.getData() as CellStatus
node.setData({
...data,
status,
statusMsg,
})
})
}
// 开启边的运行动画
const excuteAnimate = () => {
graph.getEdges().forEach((edge) => {
edge.attr({
line: {
stroke: '#3471F9',
},
})
edge.attr('line/strokeDasharray', 5)
edge.attr('line/style/animation', 'running-line 30s infinite linear')
})
}
// 关闭边的动画
const stopAnimate = () => {
graph.getEdges().forEach((edge) => {
edge.attr('line/strokeDasharray', 0)
edge.attr('line/style/animation', '')
})
edgeStatusList.forEach((item) => {
const { id, status } = item
const edge = graph.getCellById(id)
if (status === 'success') {
edge.attr('line/stroke', '#52c41a')
}
if (status === 'error') {
edge.attr('line/stroke', '#ff4d4f')
}
})
// 默认选中一个节点
graph.select('node-2')
}
fetch('/data/data-processing-dag.json')
.then((response) => response.json())
.then((data) => {
graph.fromJSON(data)
const zoomOptions = {
padding: {
left: 10,
right: 10,
},
}
graph.zoomToFit(zoomOptions)
setTimeout(() => {
excuteAnimate()
}, 2000)
setTimeout(() => {
showNodeStatus()
stopAnimate()
}, 3000)
})
insertCss(`
.data-processing-dag-node {
display: flex;
flex-direction: row;
align-items: center;
}
.main-area {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 12px;
width: 180px;
height: 48px;
color: rgba(0, 0, 0, 65%);
font-size: 12px;
font-family: PingFangSC;
line-height: 24px;
background-color: #fff;
box-shadow: 0 -1px 4px 0 rgba(209, 209, 209, 50%), 1px 1px 4px 0 rgba(217, 217, 217, 50%);
border-radius: 2px;
border: 1px solid transparent;
}
.main-area:hover {
border: 1px solid rgba(0, 0, 0, 10%);
box-shadow: 0 -2px 4px 0 rgba(209, 209, 209, 50%), 2px 2px 4px 0 rgba(217, 217, 217, 50%);
}
.node-logo {
display: inline-block;
width: 24px;
height: 24px;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
.node-name {
overflow: hidden;
display: inline-block;
width: 70px;
margin-left: 6px;
color: rgba(0, 0, 0, 65%);
font-size: 12px;
font-family: PingFangSC;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: top;
}
.status-action {
display: flex;
flex-direction: row;
align-items: center;
}
.status-icon {
display: inline-block;
width: 24px;
height: 24px;
}
.status-icon-error {
background: url('https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ')
no-repeat center center / 100% 100%;
}
.status-icon-success {
background: url('https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ')
no-repeat center center / 100% 100%;
}
.more-action-container {
margin-left: 12px;
width: 15px;
height: 15px;
text-align: center;
cursor: pointer;
}
.more-action {
display: inline-block;
width: 3px;
height: 15px;
background: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*tFw7SIy-ttQAAAAAAAAAAAAADtOHAQ/original')
no-repeat center center / 100% 100%;
}
.plus-dag {
visibility: hidden;
position: relative;
margin-left: 12px;
height: 48px;
}
.plus-action {
position: absolute;
top: calc(50% - 8px);
left: 0;
width: 16px;
height: 16px;
background: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*ScX2R4ODfokAAAAAAAAAAAAADtOHAQ/original')
no-repeat center center / 100% 100%;
cursor: pointer;
}
.plus-action:hover {
background-image: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*tRaoS5XhsuQAAAAAAAAAAAAADtOHAQ/original');
}
.plus-action:active,
.plus-action-selected {
background-image: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*k9cnSaSmlw4AAAAAAAAAAAAADtOHAQ/original');
}
.x6-node-selected .main-area {
border-color: #3471f9;
}
.x6-node-selected .plus-dag {
visibility: visible;
}
.processing-node-menu {
padding: 2px 0;
width: 105px;
background-color: #fff;
box-shadow: 0 9px 28px 8px rgba(0, 0, 0, 5%), 0 6px 16px 0 rgba(0, 0, 0, 8%),
0 3px 6px -4px rgba(0, 0, 0, 12%);
border-radius: 2px;
}
.processing-node-menu ul {
margin: 0;
padding: 0;
}
.processing-node-menu li {
list-style:none;
}
.each-sub-menu {
padding: 6px 12px;
width: 100%;
}
.each-sub-menu:hover {
background-color: rgba(0, 0, 0, 4%);
}
.each-sub-menu a {
display: inline-block;
width: 100%;
height: 16px;
font-family: PingFangSC;
font-weight: 400;
font-size: 12px;
color: rgba(0, 0, 0, 65%);
}
.each-sub-menu span {
margin-left: 8px;
vertical-align: top;
}
.each-disabled-sub-menu a {
cursor: not-allowed;
color: rgba(0, 0, 0, 35%);
}
.node-mini-logo {
display: inline-block;
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
vertical-align: top;
}
@keyframes running-line {
to {
stroke-dashoffset: -1000;
}
}
`)

@ -16,6 +16,14 @@
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*RPiGRaSus3UAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "dataProcessingDag.tsx",
"title": {
"zh": "数据加工 DAG 图",
"en": "DAG for Data Processing"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*yRLDQ5KgSO4AAAAAAAAAAAAADtOHAQ/original"
},
{
"filename": "er.ts",
"title": {

@ -1,7 +1,7 @@
{
"private": true,
"name": "@antv/x6-sites",
"version": "1.2.0",
"version": "2.0.0",
"description": "X6 sites deployed on gh-pages",
"scripts": {
"dev": "dumi dev",
@ -33,11 +33,13 @@
"@antv/x6-react-shape": "^2.x",
"antd": "^4.4.2",
"dagre": "^0.8.5",
"dumi": "^2.x",
"dumi": "2.0.16",
"elkjs": "^0.8.2",
"highlight.js": "^10.1.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-i18next": "^11.5.0"
}
"react-i18next": "^11.5.0",
"classnames": "^2.2.6"
},
"repository": "https://github.com/antvis/x6"
}

@ -0,0 +1,163 @@
{
"nodes": [
{
"id": "node-0",
"shape": "data-processing-dag-node",
"x": 0,
"y": 100,
"ports": [
{
"id": "node-0-out",
"group": "out"
}
],
"data": {
"name": "数据输入_1",
"type": "INPUT",
"checkStatus": "sucess"
}
},
{
"id": "node-1",
"shape": "data-processing-dag-node",
"x": 250,
"y": 100,
"ports": [
{
"id": "node-1-in",
"group": "in"
},
{
"id": "node-1-out",
"group": "out"
}
],
"data": {
"name": "数据筛选_1",
"type": "FILTER"
}
},
{
"id": "node-2",
"shape": "data-processing-dag-node",
"x": 250,
"y": 200,
"ports": [
{
"id": "node-2-out",
"group": "out"
}
],
"data": {
"name": "数据输入_2",
"type": "INPUT"
}
},
{
"id": "node-3",
"shape": "data-processing-dag-node",
"x": 500,
"y": 100,
"ports": [
{
"id": "node-3-in",
"group": "in"
},
{
"id": "node-3-out",
"group": "out"
}
],
"data": {
"name": "数据连接_1",
"type": "JOIN"
}
},
{
"id": "node-4",
"shape": "data-processing-dag-node",
"x": 750,
"y": 100,
"ports": [
{
"id": "node-4-in",
"group": "in"
}
],
"data": {
"name": "数据输出_1",
"type": "OUTPUT"
}
}
],
"edges": [
{
"id": "edge-0",
"source": {
"cell": "node-0",
"port": "node-0-out"
},
"target": {
"cell": "node-1",
"port": "node-1-in"
},
"shape": "data-processing-curve",
"zIndex": -1,
"data": {
"source": "node-0",
"target": "node-1"
}
},
{
"id": "edge-1",
"source": {
"cell": "node-2",
"port": "node-2-out"
},
"target": {
"cell": "node-3",
"port": "node-3-in"
},
"shape": "data-processing-curve",
"zIndex": -1,
"data": {
"source": "node-2",
"target": "node-3"
}
},
{
"id": "edge-2",
"source": {
"cell": "node-1",
"port": "node-1-out"
},
"target": {
"cell": "node-3",
"port": "node-3-in"
},
"shape": "data-processing-curve",
"zIndex": -1,
"data": {
"source": "node-1",
"target": "node-3"
}
},
{
"id": "edge-3",
"source": {
"cell": "node-3",
"port": "node-3-out"
},
"target": {
"cell": "node-4",
"port": "node-4-in"
},
"shape": "data-processing-curve",
"zIndex": -1,
"data": {
"source": "node-3",
"target": "node-4"
}
}
]
}