Compare commits

...

64 Commits

Author SHA1 Message Date
cff8c126de chore(release): 🚀 publish 2022-09-08 15:52:46 +08:00
346c6a268a chore: 🔧 update yarn.lock (#2653) 2022-09-08 15:51:53 +08:00
f53f819043 chore: 🔧 update peerDeps for plugins (#2652) 2022-09-08 15:44:50 +08:00
f351284809 chore(release): 🚀 publish 2022-09-08 11:30:48 +08:00
12c67255ae feat: add onPortRendered options (#2649)
* chore: 🔧 set x6-next and x6-core to private

* feat:  add onPortRendered options
2022-09-08 11:29:15 +08:00
7e179844dc chore: 🔧 update peerdeps for some package (#2597) 2022-08-31 10:48:06 +08:00
bc5284c6fe chore(release): 🚀 publish 2022-08-31 10:37:48 +08:00
ad63046e89 feat: support inherit options for react-shape registry (#2596) 2022-08-31 10:29:44 +08:00
12f0345555 docs: 📚️ add react-shape demos (#2590) 2022-08-29 17:14:13 +08:00
5e0e2acde7 feat: add scroller plugin (#2580)
* feat:  support priority when find anchors

* feat:  add scroller plugin
2022-08-25 21:44:09 +08:00
a10dcdb29f chore: 🔧 change publish script (#2565) 2022-08-24 11:51:19 +08:00
394c945fa2 chore: update x6-next version (#2563)
* feat:  add built-in shapes

* chore: 🔧 change virtualRender option to virtual

* feat:  support mouseenter and mouseleave event

* chore: 🔧 update x6-next version
2022-08-24 10:57:33 +08:00
ecfd4263b1 feat: support mouseenter and mouseleave event (#2559)
* feat:  add built-in shapes

* chore: 🔧 change virtualRender option to virtual

* feat:  support mouseenter and mouseleave event

* chore: 🔧 add lerna publish cmd

* chore(release): 🚀 publish
2022-08-24 10:26:20 +08:00
6ce3980f86 chore: optimize some features (#2530)
* chore: 🔧 release @antv/x6-common@2.0.1-beta.5

* chore: 🔧 release @antv/x6-next@2.0.1-beta.5

* feat:  add built-in shapes

* fix: 🐛 remove transition:begin and transition:end event

* chore: 🔧 change virtualRender option to virtual
2022-08-17 23:14:15 +08:00
a09deaadd0 chore: 🔧 update x6-next version (#2416) 2022-07-25 16:06:11 +08:00
b8576ce96a chore: 🔧 release @antv/x6-next@2.0.1-beta.4 2022-07-24 20:06:09 +08:00
aafdab63ba chore: 🔧 release @antv/x6-geometry@2.0.1-beta.4 (#2414) 2022-07-24 20:00:53 +08:00
41f6b252ac chore: 🔧 update commit msg for release (#2413) 2022-07-24 19:42:09 +08:00
3700fa683b chore: 🔧 release 2.0.1-beta.4 2022-07-24 17:25:02 +08:00
f1c80a8cd7 feat: put animation in x6-common (#2411)
* feat:  put animation in x6-common

* chore: 🔧 adjust package struct
2022-07-24 17:19:29 +08:00
5a3caed2a4 chore: 🔧 update package version (#2304)
Co-authored-by: 文瑀 <wenyu.jqq@antfin.com>
2022-07-03 07:47:15 +08:00
a6a2d12b07 fix: 🐛 add timeout for schedule (#2303)
Co-authored-by: 文瑀 <wenyu.jqq@antfin.com>
2022-07-03 07:32:47 +08:00
ee7ae2fca9 refactor: ♻️ separate the x6-next and x6-core (#2299)
Co-authored-by: 文瑀 <wenyu.jqq@antfin.com>
2022-07-02 11:07:36 +08:00
425a540f23 refactor: ♻️ add teleport for vue shape (#2272) 2022-06-28 16:18:24 +08:00
7617efbe40 refactor: ♻️ refactor x6 react shape (#2262) 2022-06-23 19:16:56 +08:00
55d36e4680 feat: add panning and mousewheel module (#2243) 2022-06-20 10:50:50 +08:00
0aced58056 perf: ️ optimize breakText for a high performance version (#2242) 2022-06-19 09:40:53 +08:00
9496d1a720 feat: add view sorting and display feature (#2206) 2022-06-10 19:20:21 +08:00
fcba5e1480 feat: add virtual render feature (#2198) 2022-06-08 21:20:48 +08:00
1436586f85 perf: ️ repalce getTransformToElement and getBBox to improve performance (#2177) 2022-06-02 16:38:08 +08:00
825190ee82 chore: 🔧 update node versio for workflow (#2179) 2022-06-02 16:36:07 +08:00
c42c1b21f3 refactor: ♻️ remove functions related to string markup (#2118) 2022-05-18 13:04:19 +08:00
7a96008010 reactor: remove unnecessary api or options (#2106)
* refactor: ♻️ remove connection strategy options

* refactor: ♻️ change getClientMatrix to getLocalMatrix

* refactor: ♻️ remove delay attrs mechanism
2022-05-13 14:33:43 +08:00
237869f496 refactor: ♻️ remove toolsMarkup options (#2099) 2022-05-11 09:35:35 +08:00
7a9f0908d7 chore: 🔧 delete browserslist config (#2088) 2022-05-07 10:24:05 +08:00
5ae7271a25 perf: ️ check whether label existed in port (#2063) 2022-04-26 22:16:44 +08:00
d16066a734 chore: 🔧 build x6-vector when bootstrap to fix test error (#2053) 2022-04-25 11:19:43 +08:00
c32fdfd7f8 feat: add priority scheduling for async jobs (#2052)
* refactor: ♻️ expose renderer interface in x6-core

* feat:  add renderview job to sync queue

* feat:  add priority scheduling for async jobs
2022-04-25 09:50:04 +08:00
57a50a9dec feat: add scheduler for render nodes to improve performance (#2044)
* refactor: ♻️ expose renderer interface in x6-core

* feat:  add renderview job to sync queue

* chore: 🔧 include css type in karma config
2022-04-23 08:45:34 +08:00
23fcea2e8a refactor: ♻️ expose renderer interface in x6-core (#2021)
* refactor: ♻️ expose renderer interface in x6-core

* chore: 🔧 amend build-dev script
2022-04-19 10:26:29 +08:00
c68140504b feat: sync code from master (#2004)
* fix(x6-vue-shape): 🐛 error on removing fragment node (#1974)

* fix: 🐛 fix scroller resize size miscalculation when graph resize (#1977)

Co-authored-by: mrmengj <mrmengj@gmail.como>

* fix: 🐛 change copystyle not include number propery when toSvg (#1985)

* docs: 📚️ optimize tooltip tools (#1988)

* docs: 📚️ update doc api (#1991)

Co-authored-by: DanielLeefu <you@2228429150@qq.com>

* fix: 🐛 fix animationOptions type (#1989)

* fix: 🐛 update dnd widget zIndex

* fix: 🐛 fix animateOptions type

* fix: 🐛 sync from master

* fix: 🐛 annotate a error test cases

Co-authored-by: sallen450 <qinghua10199@gmail.com>
Co-authored-by: MrMengJ <2646973632@qq.com>
Co-authored-by: mrmengj <mrmengj@gmail.como>
Co-authored-by: 九思 <2228429150@qq.com>
Co-authored-by: DanielLeefu <you@2228429150@qq.com>
2022-04-12 16:47:08 +08:00
ca48de2d7e refactor: ♻️ split graph and mvc module (#2000) 2022-04-12 15:23:05 +08:00
690718c18e chore: 🔧 adjusting the directory structure (#1992) 2022-04-11 09:39:42 +08:00
aee3666da2 feat: add version.ts (#1981)
* feat:  add version.ts

* fix: 🐛 export tools from x6-core
2022-04-07 15:59:20 +08:00
38c6fd6992 feat: remove jquery deps in x6-core (#1971)
* feat:  remove jquery deps in x6-core

* fix: 🐛 prevents malicious properties
2022-04-04 22:03:02 +08:00
d1eb01c491 feat: add dom data methods (#1969) 2022-04-02 20:04:43 +08:00
023b81301e chore: 🔧 replace import type to import (#1963) 2022-04-01 23:07:52 +08:00
e8fbcd83fd feat: add css method for dom (#1959) 2022-04-01 14:14:13 +08:00
10ab981274 chore: 🔧 add importsNotUsedAsValues tsconfig (#1955)
* chore: 🔧 add importsNotUsedAsValues tsconfig

* chore: 🔧 add utility-types deps
2022-03-31 21:00:51 +08:00
d7cfb6af19 feat: init x6-core repo (#1954) 2022-03-31 09:37:57 +08:00
5ba9b1d2dc chore: 🔧 unnamespace the types (#1950) 2022-03-29 23:11:25 +08:00
075db14981 feat: add config module for x6-next (#1945)
* docs: 📚️ add alt for img in readme

* feat:  add configs module for x6-next
2022-03-27 21:26:19 +08:00
5913369bc5 feat: init x6-next repo (#1943) 2022-03-26 21:30:37 +08:00
445eaf3475 chore: 🔧 migrate registry to common (#1941) 2022-03-26 21:00:14 +08:00
f07a2eb386 chore: 🔧 only include src in tsconfig (#1934) 2022-03-25 14:44:30 +08:00
c1d0fc188e feat: add events module in common (#1932) 2022-03-25 11:44:01 +08:00
68c143babf feat: add dom event to replace jquery event (#1929) 2022-03-24 19:01:45 +08:00
df11dfbce2 refactor: remove the dependence between common and geometry (#1925)
* refactor: ♻️ remove the dependence between common and geometry

* fix: 🐛 export util methods
2022-03-23 19:47:02 +08:00
223cb4330f chore: 🔧 update the directory of test case (#1914) 2022-03-21 23:02:22 +08:00
9e19ab98b6 docs: add security policy (#1911)
* fix: 🐛 change the order of statement (#1910)

* chore: update AUTHORS [skip ci]

* docs: add security policy

add security policy

Co-authored-by: x6-bot[bot] <71382382+x6-bot[bot]@users.noreply.github.com>
2022-03-21 13:55:08 +08:00
d060d3405f chore: 🔧 delete package x6-react (#1908) 2022-03-20 20:54:55 +08:00
299b0f7d3d style: 🎨 fix lint error (#1907)
* style: 🎨 fix lint error

* test: 🚨 delete some test case
2022-03-20 19:40:28 +08:00
4e8ef5f5ff style: 🎨 prettier all files 2022-03-20 15:17:46 +08:00
6415927413 docs: 📚️ update readme and contributing 2022-03-18 18:28:55 +08:00
832 changed files with 167652 additions and 7564 deletions

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [16.x]
steps:
- name:  Checkout
uses: actions/checkout@v2

View File

@ -138,9 +138,6 @@
- name: pkg:x6
color: eeeeee
description: Denotes a PR that changes packages/x6
- name: pkg:x6-react
color: eeeeee
description: Denotes a PR that changes packages/x6-react
- name: pkg:x6-react-shape
color: eeeeee
description: Denotes a PR that changes packages/x6-react-shape

View File

@ -20,7 +20,6 @@ jobs:
group: '(?!^)@.*$'
exclude: |
@antv/x6@**
@antv/x6-react@**
@antv/x6-vue-shape@**
@antv/x6-react-shape@**
@antv/x6-angular-shape@**

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [16.x]
steps:
- name:  Checkout
uses: actions/checkout@v2

View File

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [16.x]
steps:
- uses: actions/checkout@v2

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [16.x]
steps:
- name:  Checkout
uses: actions/checkout@v2

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
node-version: [16.x]
steps:
- name:  Checkout
uses: actions/checkout@v2

2
.gitignore vendored
View File

@ -11,3 +11,5 @@ es
dist
*.pem
!mock-cert.pem
tmp
test

View File

@ -37,6 +37,7 @@ lopn <lopnxrp@126.com>
luchunwei <luchunwei@gmail.com>
luzhuang <364439895@qq.com>
lvhuiyang <ilvhuiyang@gmail.com>
newbyvector <vectorse@126.com>
niexq <1879633916@qq.com>
niexq <niexq@firstgrid.cn>
pengxingjian.pxj <pengxingjian.pxj@alibaba-inc.com>

View File

@ -110,8 +110,8 @@ Look at [these files](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJyg
X6 uses semantic versioning in release process based on [semver](https://semver.org/).
- [Publishing maintenance releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/maintenance-releases.md)
- [Publishing pre-releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/pre-releases.md)
- [Publishing maintenance releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/release-workflow/maintenance-releases.md)
- [Publishing pre-releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/release-workflow/pre-releases.md)
### Branch Strategy

View File

@ -1,6 +1,6 @@
# 代码贡献规范
有任何疑问,欢迎提交 [issue](https://github.com/antvis/x6/issues) 或 [PR](https://github.com/antvis/x6/pulls)!
如果你有任何疑问,欢迎提交 [issue](https://github.com/antvis/x6/issues) 或 [PR](https://github.com/antvis/x6/pulls)!
## 提交 issue
@ -109,8 +109,8 @@ BREAKING CHANGE:
## 发布管理
- [Publishing maintenance releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/maintenance-releases.md)
- [Publishing pre-releases](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/pre-releases.md)
- [发布维护版本](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/release-workflow/maintenance-releases.md)
- [发布预发版本](https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/release-workflow/pre-releases.md)
X6 基于 [semver](http://semver.org/lang/zh-CN/) 语义化版本号进行发布。
@ -121,7 +121,7 @@ X6 基于 [semver](http://semver.org/lang/zh-CN/) 语义化版本号进行发布
### 发布策略
每个大版本都有一个发布经理管理(PM,他/她要做的事情
每个大版本的发布中,都会有一个PM在发布的不同阶段负有以下职责:
#### 准备工作:
@ -135,6 +135,6 @@ X6 基于 [semver](http://semver.org/lang/zh-CN/) 语义化版本号进行发布
#### 发布时:
- 将老的稳定版本master备份到以当前大版本为名字的分支上例如 `1.x`),并设置 tag 为 {v}.x` v 为当前版本,例如 `1.x`)。
- 将老的稳定版本master备份到以当前大版本为名字的分支上例如 `1.x`),并设置 tag 为 {v}.x v 为当前版本,例如 `1.x`)。
- 发布新的稳定版本到 [npm](http://npmjs.com),并通知上层框架进行更新。
- `npm publish` 之前,请先阅读[『我是如何发布一个 npm 包的』](https://fengmk2.com/blog/2016/how-i-publish-a-npm-package)。

View File

@ -2,10 +2,9 @@
<p align="center"><img src="/flow.svg"></p>
<p align="center"><strong>Graph Editing Engine Of AntV</strong></p>
<p align="center"><strong>JavaScript diagramming library that uses SVG and HTML for rendering</strong></p>
<p align="center"><a href="https://x6.antv.vision/en/docs/tutorial/about">Tutorials</a> · <a href="https://x6.antv.vision/en/examples/gallery">Examples</a> · <a href="https://x6.antv.vision/en/docs/api/graph">API</a></p>
<p align="center">
<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>
@ -23,15 +22,22 @@
## Features
- 🌱 easy-to-customize: based on well known SVG/HTML/CSS or React/Vue to custom nodes and edges
- 🚀 out-of-the-box: built-in 10+ plugins, such as selection, dnd, redo/undo, snapline, minimap, etc.
- 🧲 data-driven: base on MVC architecture, you can focus on data logic and business logic
- 💯 highly-event-driven: you can react on any event that happens inside the graph
- 🌱 Easy-to-customize: based on well known SVG/HTML/CSS or React/Vue/Angular to custom nodes and edges
- 🚀 Out-of-the-box: built-in 10+ plugins, such as selection, dnd, redo/undo, snapline, minimap, etc.
- 🧲 Data-driven: base on MVC architecture, you can focus on data logic and business logic
- 💯 Highly-event-driven: you can react on any event that happens inside the graph
## Environment Support
- Modern browsers and Internet Explorer 11 (with polyfills)
- Server-side Rendering
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari |
| --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## Installation
### NPM/Yarn
```shell
# npm
$ npm install @antv/x6 --save
@ -40,51 +46,20 @@ $ npm install @antv/x6 --save
$ yarn add @antv/x6
```
### CDNs
For learning purposes, you can use the latest version with one of the CDN:
- https://unpkg.com/@antv/x6/dist/x6.js
- https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.js
- https://cdnjs.cloudflare.com/ajax/libs/antv-x6/1.3.20/x6.js
```html
<script src="https://unpkg.com/@antv/x6/dist/x6.js"></script>
```
For production, we recommend linking to a specific version number to avoid unexpected breakage from newer versions:
- https://unpkg.com/@antv/x6@1.1.1/dist/x6.js
- https://cdn.jsdelivr.net/npm/@antv/x6@1.1.1/dist/x6.js
- https://cdnjs.cloudflare.com/ajax/libs/antv-x6/1.1.1/x6.js
```html
<script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
```
## Usage
**Step 1**: specify a container the render the diagram.
```html
<div id="container" style="width: 600px; height: 400px"></div>
```
**Step 2**: render nodes and edges.
```ts
// import from node_modules
import { Graph } from '@antv/x6'
// or use the global variable `X6` exported from CDN links
// const { Graph } = X6
// Create an instance of Graph.
const graph = new Graph({
container: document.getElementById('container'),
grid: true
})
// Render source node.
const source = graph.addNode({
x: 300,
y: 40,
@ -93,7 +68,6 @@ const source = graph.addNode({
label: 'Hello',
})
// Render target node.
const target = graph.addNode({
x: 420,
y: 180,
@ -102,94 +76,23 @@ const target = graph.addNode({
label: 'World',
})
// Render edge from source to target.
graph.addEdge({
source,
target,
})
```
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*o4W3RLZicagAAAAAAAAAAAAAARQnAQ" alt="HelloWorld" />
## Links
## Documentation
- [About](https://x6.antv.vision/en/docs/tutorial/about)
- [Getting Started](https://x6.antv.vision/en/docs/tutorial/getting-started)
- [Basic Usage](https://x6.antv.vision/en/docs/tutorial/basic/graph)
- [Advanced Practice](https://x6.antv.vision/en/docs/tutorial/intermediate/serialization)
- [Senior Guidance](https://x6.antv.vision/en/docs/tutorial/advanced/animation)
- [ChangeLog](https://x6.antv.vision/en/docs/tutorial/log)
## App Demos Build with X6
<center>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#flowchart" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*JSr-RbwCgmcAAAAAAAAAAAAAARQnAQ" alt="Flow"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#dag" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*RPiGRaSus3UAAAAAAAAAAAAAARQnAQ" alt="Dag"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#mindmap" target="_blank" rel="noopener noreferrer">
<img width="400" height="200" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*GsEGSaBkc84AAAAAAAAAAAAAARQnAQ" alt="MindMap"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#bpmn" target="_blank" rel="noopener noreferrer">
<img width="400" height="200" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*aPSySa8oz4sAAAAAAAAAAAAAARQnAQ" alt="BPMN"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#class" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*OaCpR7t_mVoAAAAAAAAAAAAAARQnAQ" alt="Class"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#org" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*FWx5SYDzLw4AAAAAAAAAAAAAARQnAQ" alt="ORG"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#er" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*7yVJQoM6-9AAAAAAAAAAAAAAARQnAQ" alt="ER"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#swimlane" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*mUVrSJMkP1UAAAAAAAAAAAAAARQnAQ" alt="SwimLane"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#tree" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*XDnNRqnj4WkAAAAAAAAAAAAAARQnAQ" alt="Tree"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#elk" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Z3ebTKy0w9cAAAAAAAAAAAAAARQnAQ" alt="ELK"/>
</a>
</center>
## Communication
Welcome to join the **X6 Communication Group** (Scan the QR Code to Join us). We also welcome the github [issues](https://github.com/antvis/x6/issues).
<a href="https://qr.dingtalk.com/action/joingroup?code=v1,k1,rOHuvgq5s0EHDktyyQJffDE3ZAmHnbB2e6iwn/w4BKs=&_dt_no_comment=1&origin=11" target="_blank" rel="noopener noreferrer">
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Up-4S4v8H-0AAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群1" width="375" />
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*4Y_5S7i26LAAAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群2" width="375" />
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*KHB4QJAsW4QAAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群3" width="375" />
</a>
- [Documents](https://x6.antv.vision/zh/docs/tutorial/about)
- [Samples](https://x6.antv.vision/zh/examples/gallery)
- [Blog](https://www.yuque.com/antv/x6/gcinvi)
- [Versioning Release Note](https://www.yuque.com/antv/x6/bbfu6r)
- [FAQ](https://www.yuque.com/antv/x6/be9pfx)
- [CodeSanbox Template](https://codesandbox.io/s/qosj0?file=/src/app.tsx)
## Development
This repo is based on [lerna](https://github.com/lerna/lerna) with the following structure:
```
.
├── examples
│ ├── x6-app-dag # example of dag graph
│ ├── x6-app-draw # example of flowchart
│ ├── x6-app-er # example of ER chart
│ └── x6-example-features # example of basic features
├── packages
│ ├── x6 # X6
│ ├── x6-react # wrap X6 with react(reserved)
│ ├── x6-react-components # react componets to build graph apps
│ ├── x6-react-shape # support render node with react
│ └── x6-vue-shape # support render node with vue
└── sites
├── x6-sites # sites and documents
├── x6-sites-demos # demos in documents
└── x6-sites-demos-helper # tools to build demos
```
We need to install some necessary global tools before getting started.
```shell
# install yarn and lerna
$ npm install yarn -g
@ -197,37 +100,19 @@ $ npm install lerna -g
# install deps and build
$ yarn bootstrap
```
Then we can `cd` to dirs to development and debugging.
Such as, we can start `examples/x6-example-features` locally:
```shell
cd examples/x6-example-features
yarn start
```
When need to fix some bugs of X6, we can start with **watch** mode:
```shell
# enter the specified project development and debugging
cd packages/x6
yarn build:watch
// build esm to "em" dir
yarn build:watch:esm
// build commonjs to "lib" dir
yarn build:watch:cjs
# start example to see the effect
cd examples/x6-example-features
yarn start
```
## Contributing
Please let us know how can we help. Do check out [issues](https://github.com/antvis/x6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](/CONTRIBUTING.md).
## Contributors
To become a contributor, please follow our [contributing guide](/CONTRIBUTING.md). If you are an active contributor, you can apply to be a outside collaborator.
<a href="https://github.com/antvis/x6/graphs/contributors">
<img src="/CONTRIBUTORS.svg" alt="Contributors" width="740" />

170
README.md
View File

@ -1,10 +1,9 @@
简体中文 | [English](/README.en-us.md)
<p align="center"><img src="/flow.svg"></p>
<p align="center"><img alt="flow" src="/flow.svg"></p>
<p align="center"><strong>X6 是 AntV 旗下的图编辑引擎</strong></p>
<p align="center"><strong>提供简单易用的节点定制能力和开箱即用的交互组件方便我们快速搭建流程图、DAG 图、ER 图等图应用</strong></p>
<p align="center"><a href="https://x6.antv.vision/zh/docs/tutorial/about">教程</a><a href="https://x6.antv.vision/zh/examples/gallery">示例</a><a href="https://x6.antv.vision/zh/docs/api/graph">API</a></p>
<p align="center">
<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>
@ -21,17 +20,23 @@
<a href="https://x6.antv.vision"><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>
</p>
## 特性
- 🌱 极易定制:支持使用 SVG/HTML/React/Vue 定制节点样式和交互
- 🌱 极易定制:支持使用 SVG/HTML/React/Vue/Angular 定制节点样式和交互
- 🚀 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等
- 🧲 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑
- 💯 事件驱动:完备的事件系统,可以监听图表内发生的任何事件
## 安装
## 兼容环境
### 使用 NPM/Yarn
- 现代浏览器和 IE11需要 polyfills
- 支持服务端渲染。
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari |
| --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## 安装
```shell
# npm
@ -41,51 +46,20 @@ $ npm install @antv/x6 --save
$ yarn add @antv/x6
```
### 使用 CDN
可以使用下面任意一个最新版本的 CDN 地址:
- https://unpkg.com/@antv/x6/dist/x6.js
- https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.js
- https://cdnjs.cloudflare.com/ajax/libs/antv-x6/1.3.20/x6.js
```html
<script src="https://unpkg.com/@antv/x6/dist/x6.js"></script>
```
在生产环境中,建议使用指定版本号的链接,以避免版本更新带来的意外破坏:
- https://unpkg.com/@antv/x6@1.1.1/dist/x6.js
- https://cdn.jsdelivr.net/npm/@antv/x6@1.1.1/dist/x6.js
- https://cdnjs.cloudflare.com/ajax/libs/antv-x6/1.1.1/x6.js
```html
<script src="https://unpkg.com/@antv/x6@1.1.1/dist/x6.js"></script>
```
## 快速使用
**Step 1**: 指定渲染图的容器。
## 示例
```html
<div id="container" style="width: 600px; height: 400px"></div>
```
**Step 2**: 渲染节点和边。
```ts
// 从 node_modules 引入
import { Graph } from '@antv/x6'
// 从 CND 引入时,我们暴露了 X6 这个全局变量
// const { Graph } = X6
// 创建 Graph 的实例
const graph = new Graph({
container: document.getElementById('container'),
grid: true
})
// 渲染源节点
const source = graph.addNode({
x: 300,
y: 40,
@ -94,7 +68,6 @@ const source = graph.addNode({
label: 'Hello',
})
// 渲染目标节点
const target = graph.addNode({
x: 420,
y: 180,
@ -103,97 +76,22 @@ const target = graph.addNode({
label: 'World',
})
// 渲染边
graph.addEdge({
source,
target,
})
```
渲染结果如下。
## 链接
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*o4W3RLZicagAAAAAAAAAAAAAARQnAQ" alt="HelloWorld" />
- [文档](https://x6.antv.vision/zh/docs/tutorial/about)
- [示例](https://x6.antv.vision/zh/examples/gallery)
- [博客](https://www.yuque.com/antv/x6/gcinvi)
- [更新日志](https://www.yuque.com/antv/x6/bbfu6r)
- [常见问题](https://www.yuque.com/antv/x6/be9pfx)
- [CodeSanbox 模板](https://codesandbox.io/s/qosj0?file=/src/app.tsx)
## 使用文档
- [简介](https://x6.antv.vision/zh/docs/tutorial/about)
- [快速上手](https://x6.antv.vision/zh/docs/tutorial/getting-started)
- [基础教程](https://x6.antv.vision/zh/docs/tutorial/basic/graph)
- [进阶实践](https://x6.antv.vision/zh/docs/tutorial/intermediate/serialization)
- [高级指引](https://x6.antv.vision/zh/docs/tutorial/advanced/animation)
- [更新日志](https://x6.antv.vision/zh/docs/tutorial/log)
## 应用案例
<center>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#flowchart" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*JSr-RbwCgmcAAAAAAAAAAAAAARQnAQ" alt="Flow"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#dag" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*RPiGRaSus3UAAAAAAAAAAAAAARQnAQ" alt="Dag"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#mindmap" target="_blank" rel="noopener noreferrer">
<img width="400" height="200" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*GsEGSaBkc84AAAAAAAAAAAAAARQnAQ" alt="MindMap"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#bpmn" target="_blank" rel="noopener noreferrer">
<img width="400" height="200" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*aPSySa8oz4sAAAAAAAAAAAAAARQnAQ" alt="BPMN"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#class" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*OaCpR7t_mVoAAAAAAAAAAAAAARQnAQ" alt="Class"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#org" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*FWx5SYDzLw4AAAAAAAAAAAAAARQnAQ" alt="ORG"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#er" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*7yVJQoM6-9AAAAAAAAAAAAAAARQnAQ" alt="ER"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#swimlane" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*mUVrSJMkP1UAAAAAAAAAAAAAARQnAQ" alt="SwimLane"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#tree" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*XDnNRqnj4WkAAAAAAAAAAAAAARQnAQ" alt="Tree"/>
</a>
<a href="https://x6.antv.vision/zh/examples/showcase/practices#elk" target="_blank" rel="noopener noreferrer">
<img width="400" height="250" style="margin-bottom: 20px" src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Z3ebTKy0w9cAAAAAAAAAAAAAARQnAQ" alt="ELK"/>
</a>
</center>
## 如何交流
如果你在使用的过程中碰到问题,可以先通过 [issues](https://github.com/antvis/x6/issues) 看看有没有类似的 bug 或者建议。欢迎提 [issues](https://github.com/antvis/x6/issues/new) 交流,也可以使用[钉钉](https://m.dingtalk.com/)扫描下面二维码加入**X6 交流群**。
需要注意的是,提问题时请配上 [CodeSandbox](https://codesandbox.io/s/pensive-sound-f4nhc) 的复现代码,方便快速定位和解决问题。
<a href="https://qr.dingtalk.com/action/joingroup?code=v1,k1,rOHuvgq5s0EHDktyyQJffDE3ZAmHnbB2e6iwn/w4BKs=&_dt_no_comment=1&origin=11" target="_blank" rel="noopener noreferrer">
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Up-4S4v8H-0AAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群1" width="375" />
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*4Y_5S7i26LAAAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群2" width="375" />
<img src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*KHB4QJAsW4QAAAAAAAAAAAAAARQnAQ" alt="X6 图可视化交流群3" width="375" />
</a>
## 如何开发
我们使用了 [lerna](https://github.com/lerna/lerna) 来管理项目,目录结构如下:
```
.
├── examples
│ ├── x6-app-dag # dag 图示例
│ ├── x6-app-draw # 流程图示例
│ ├── x6-app-er # ER 图示例
│ └── x6-example-features # 特性演示示例
├── packages
│ ├── x6 # X6
│ ├── x6-react # X6 的 React 封装(预留)
│ ├── x6-react-components # 配套 React 组件库
│ ├── x6-react-shape # 支持使用 React 渲染节点
│ └── x6-vue-shape # 支持使用 Vue 渲染节点
└── sites
├── x6-sites # 官网和文档
├── x6-sites-demos # 文档中嵌入的 DEMO
└── x6-sites-demos-helper # 构建文档 DEMO 的工具
```
开始之前需要安装必要的全局依赖和初始化:
## 本地开发
```shell
# 全局安装 yarn 和 lerna 工具
@ -202,35 +100,19 @@ $ npm install lerna -g
# 安装项目依赖和初始化构建
$ yarn bootstrap
```
然后可以进入到指定项目开发和调试
# 进入到指定项目开发和调试
cd packages/x6
yarn build:watch
如本地启动 `examples/x6-example-features` 示例:
```shell
# 启动 example 查看效果
cd examples/x6-example-features
yarn start
```
修复 X6 的 BUG 时可以开启 watch 模式,配合上面启动的本地 DEMO实时查看修复效果
## 参与共建
```shell
cd packages/x6
// esm 模式,动态构建 es 产物
yarn build:watch:esm
// commonjs 模式,动态构建 lib 产物
yarn build:watch:cjs
```
## 如何贡献
如果你在使用的过程中碰到问题,可以先通过 [issues](https://github.com/antvis/x6/issues) 看看有没有类似的 bug 或者建议。
如需提交代码,请遵从我们的[贡献指南](/CONTRIBUTING.zh-CN.md)。我们会收集贡献者的 Github 头像到下面贡献者清单中。
如果希望参与到 X6 的开发中,请遵从我们的[贡献指南](/CONTRIBUTING.zh-CN.md)。如果你贡献度足够活跃,你可以申请成为社区协作者。
<a href="https://github.com/antvis/x6/graphs/contributors">
<img src="/CONTRIBUTORS.svg" alt="Contributors" width="740" />

21
SECURITY.md Normal file
View File

@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.

View File

@ -8,6 +8,7 @@
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"ts-node": "^10.2.1",
"typescript": "^4.4.3"
"typescript": "^4.4.3",
"release-it": "^14.0.1"
}
}

View File

@ -7,7 +7,6 @@
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"lint": "umi-lint --eslint src/ -p.no-semi --prettier --fix",
"test:coverage": "umi-test --coverage"
},

View File

@ -1,10 +1,10 @@
declare module '*.css';
declare module '*.less';
declare module '*.png';
declare module '*.css'
declare module '*.less'
declare module '*.png'
declare module '*.svg' {
export function ReactComponent(
props: React.SVGProps<SVGSVGElement>,
): React.ReactElement;
const url: string;
export default url;
): React.ReactElement
const url: string
export default url
}

View File

@ -10,9 +10,7 @@
"baseUrl": "./",
"strict": true,
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
},
"allowSyntheticDefaultImports": true
}

View File

@ -7,7 +7,6 @@
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "@antv/x6-example-features",
"version": "1.2.2",
"version": "2.0.2-beta.0",
"scripts": {
"start": "umi dev",
"build": "umi build",
@ -10,22 +10,23 @@
},
"dependencies": {
"@antv/x6": "^1.30.2",
"@antv/x6-react-components": "^1.1.16",
"@antv/x6-react-shape": "^1.6.0",
"@antv/x6-next": "^2.0.3-beta.0",
"@antv/x6-react-components": "^2.0.3-beta.0",
"@antv/x6-react-shape": "^2.0.3-beta.0",
"@antv/x6-vector": "^1.3.0",
"antd": "^4.4.2",
"classnames": "^2.2.6",
"dagre": "^0.8.5",
"elkjs": "^0.7.1",
"react": "^16.12.0",
"react-dom": "^16.8.6",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-helmet": "^6.0.0"
},
"devDependencies": {
"@ant-design/icons": "^4.2.2",
"@types/jest": "^25.2.1",
"@types/react": "^16.7.18",
"@types/react-dom": "^16.0.11",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-helmet": "^6.0.0",
"@types/react-test-renderer": "^16.0.3",
"eslint": "^7.16.0",

View File

@ -5,12 +5,11 @@ import '../index.less'
class BallView extends NodeView {
protected speed: number = 0
protected angle: number = 0
protected timerId: number = 0
protected edge: Edge | null
protected init() {
this.timerId = this.cell.transition('attrs/label/opacity', 1, {
delay: (1 + Math.random()) * 3000,
this.cell.transition('attrs/label/opacity', 1, {
delay: 0,
duration: 3000,
timing: 'inout',
interp: function (a: number, b: number) {
@ -28,7 +27,7 @@ class BallView extends NodeView {
})
this.cell.on('change:position', ({ cell, current }) => {
const node = (cell as any) as Node
const node = cell as any as Node
this.angle = Point.create(node.getPosition()).theta(
node.previous('position'),
)
@ -97,17 +96,13 @@ class BallView extends NodeView {
}
onMouseDown(e: JQuery.MouseDownEvent, x: number, y: number) {
console.log('mousedown1')
// Do not allow drag element while it's still in a transition.
if (this.cell.getTransitions().indexOf('position') > -1) {
console.log('mousedown2')
return
}
// Cancel displaying 'drag me!' if dragging already starts.
if (this.timerId) {
clearTimeout(this.timerId)
delete this.timerId
}
this.edge = this.graph.addEdge({
shape: 'edge',
source: this.cell.getBBox().getCenter(),
@ -128,7 +123,7 @@ class BallView extends NodeView {
// Change the marker arrow color.
this.edge.on('change:target', ({ cell }) => {
const edge = (cell as any) as Edge
const edge = cell as any as Edge
const sourcePoint = edge.getSourcePoint()!
const targetPoint = edge.getTargetPoint()!
const dist = sourcePoint.distance(targetPoint)

View File

@ -1,5 +1,7 @@
import React from 'react'
import { Graph, Cell, Point, Timing, Interp } from '@antv/x6'
import { Graph, Cell } from '@antv/x6-next'
import { Point } from '@antv/x6-geometry'
import { Timing, Interp } from '@antv/x6-common'
import '../index.less'
export default class Example extends React.Component {
@ -11,6 +13,9 @@ export default class Example extends React.Component {
width: 650,
height: 400,
grid: 1,
background: {
color: '#F2F7FA',
},
})
const ball = graph.addNode({
@ -23,9 +28,12 @@ export default class Example extends React.Component {
label: {
text: 'ball',
fontSize: 20,
stroke: '#8f8f8f',
},
body: {
fill: '#FFFFFF',
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})
@ -59,7 +67,6 @@ export default class Example extends React.Component {
{
delay: 5000,
duration: 2000,
easing: 'easeInBounce',
interp: (
start: { text: String; fontSize: number },
end: { text: String; fontSize: number },
@ -84,9 +91,12 @@ export default class Example extends React.Component {
label: {
text: 'u.f.o.',
fontSize: 10,
stroke: '8f8f8f',
},
body: {
fill: '#FFFFFF',
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})

View File

@ -1,5 +1,5 @@
import React from 'react'
import { Graph, Cell } from '@antv/x6'
import { Graph, Cell } from '@antv/x6-next'
import { Bus, Connector, Component, Fader, Aux } from './shapes'
import '../index.less'
import './index.less'
@ -12,9 +12,6 @@ export default class Example extends React.Component {
container: this.container,
width: 1000,
height: 800,
async: true,
frozen: true,
sorting: 'approx',
translating: {
restrict: true,
},
@ -206,8 +203,6 @@ export default class Example extends React.Component {
connector24,
connector25,
] as any)
graph.unfreeze()
}
refContainer = (container: HTMLDivElement) => {

View File

@ -1,4 +1,4 @@
import { Node, Shape } from '@antv/x6'
import { Node, Shape } from '@antv/x6-next'
export class Bus extends Shape.Edge {
static create(x: number, label: string, color: string) {

View File

@ -1,453 +1,453 @@
import React from 'react'
import { Graph, Node, Path, Cell } from '@antv/x6'
import '@antv/x6-react-shape'
import '../index.less'
import './index.less'
interface NodeStatus {
id: string
status: 'default' | 'success' | 'failed' | 'running'
label?: string
}
// import React from 'react'
// import { Graph, Node, Path, Cell } from '@antv/x6'
// import '@antv/x6-react-shape'
// import '../index.less'
// import './index.less'
// interface NodeStatus {
// id: string
// status: 'default' | 'success' | 'failed' | 'running'
// label?: string
// }
const image = {
logo: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*evDjT5vjkX0AAAAAAAAAAAAAARQnAQ',
success:
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ',
failed:
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ',
running:
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*t8fURKfgSOgAAAAAAAAAAAAAARQnAQ',
}
export class AlgoNode extends React.Component<{ node?: Node }> {
shouldComponentUpdate() {
const { node } = this.props
if (node) {
if (node.hasChanged('data')) {
return true
}
}
return false
}
// const image = {
// logo: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*evDjT5vjkX0AAAAAAAAAAAAAARQnAQ',
// success:
// 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ',
// failed:
// 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ',
// running:
// 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*t8fURKfgSOgAAAAAAAAAAAAAARQnAQ',
// }
// export class AlgoNode extends React.Component<{ node?: Node }> {
// shouldComponentUpdate() {
// const { node } = this.props
// if (node) {
// if (node.hasChanged('data')) {
// return true
// }
// }
// return false
// }
render() {
const { node } = this.props
const data = node?.getData() as NodeStatus
const { label, status = 'default' } = data
// render() {
// const { node } = this.props
// const data = node?.getData() as NodeStatus
// const { label, status = 'default' } = data
return (
<div className={`node ${status}`}>
<img src={image.logo} />
<span className="label">{label}</span>
<span className="status">
{status === 'success' && <img src={image.success} />}
{status === 'failed' && <img src={image.failed} />}
{status === 'running' && <img src={image.running} />}
</span>
</div>
)
}
}
// return (
// <div className={`node ${status}`}>
// <img src={image.logo} alt="logo" />
// <span className="label">{label}</span>
// <span className="status">
// {status === 'success' && <img src={image.success} alt="success" />}
// {status === 'failed' && <img src={image.failed} alt="failed" />}
// {status === 'running' && <img src={image.running} alt="running" />}
// </span>
// </div>
// )
// }
// }
Graph.registerNode(
'dag-node',
{
inherit: 'react-shape',
width: 180,
height: 36,
component: <AlgoNode />,
ports: {
groups: {
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#C2C8D5',
strokeWidth: 1,
fill: '#fff',
},
},
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#C2C8D5',
strokeWidth: 1,
fill: '#fff',
},
},
},
},
},
},
true,
)
// Graph.registerNode(
// 'dag-node',
// {
// inherit: 'react-shape',
// width: 180,
// height: 36,
// component: <AlgoNode />,
// ports: {
// groups: {
// top: {
// position: 'top',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: '#C2C8D5',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// bottom: {
// position: 'bottom',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: '#C2C8D5',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// },
// },
// },
// true,
// )
Graph.registerEdge(
'dag-edge',
{
inherit: 'edge',
attrs: {
line: {
stroke: '#C2C8D5',
strokeWidth: 1,
targetMarker: null,
},
},
},
true,
)
// Graph.registerEdge(
// 'dag-edge',
// {
// inherit: 'edge',
// attrs: {
// line: {
// stroke: '#C2C8D5',
// strokeWidth: 1,
// targetMarker: null,
// },
// },
// },
// true,
// )
Graph.registerConnector(
'algo-connector',
(s, e) => {
const offset = 4
const deltaY = Math.abs(e.y - s.y)
const control = Math.floor((deltaY / 3) * 2)
// Graph.registerConnector(
// 'algo-connector',
// (s, e) => {
// const offset = 4
// const deltaY = Math.abs(e.y - s.y)
// const control = Math.floor((deltaY / 3) * 2)
const v1 = { x: s.x, y: s.y + offset + control }
const v2 = { x: e.x, y: e.y - offset - control }
// const v1 = { x: s.x, y: s.y + offset + control }
// const v2 = { x: e.x, y: e.y - offset - control }
return Path.normalize(
`M ${s.x} ${s.y}
L ${s.x} ${s.y + offset}
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
L ${e.x} ${e.y}
`,
)
},
true,
)
// return Path.normalize(
// `M ${s.x} ${s.y}
// L ${s.x} ${s.y + offset}
// C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
// L ${e.x} ${e.y}
// `,
// )
// },
// true,
// )
const data = [
{
id: '1',
shape: 'dag-node',
x: 290,
y: 110,
data: {
label: '读数据',
status: 'success',
},
ports: [
{
id: '1-1',
group: 'bottom',
},
],
},
{
id: '2',
shape: 'dag-node',
x: 290,
y: 225,
data: {
label: '读数据',
status: 'success',
},
ports: [
{
id: '2-1',
group: 'top',
},
{
id: '2-2',
group: 'bottom',
},
{
id: '2-3',
group: 'bottom',
},
],
},
{
id: '3',
shape: 'dag-node',
x: 170,
y: 350,
data: {
label: '读数据',
status: 'success',
},
ports: [
{
id: '3-1',
group: 'top',
},
{
id: '3-2',
group: 'bottom',
},
],
},
{
id: '4',
shape: 'dag-node',
x: 450,
y: 350,
data: {
label: '读数据',
status: 'success',
},
ports: [
{
id: '4-1',
group: 'top',
},
{
id: '4-2',
group: 'bottom',
},
],
},
{
id: '5',
shape: 'dag-edge',
source: {
cell: '1',
port: '1-1',
},
target: {
cell: '2',
port: '2-1',
},
zIndex: 0,
},
{
id: '6',
shape: 'dag-edge',
source: {
cell: '2',
port: '2-2',
},
target: {
cell: '3',
port: '3-1',
},
zIndex: 0,
},
{
id: '7',
shape: 'dag-edge',
source: {
cell: '2',
port: '2-3',
},
target: {
cell: '4',
port: '4-1',
},
zIndex: 0,
},
]
// const data = [
// {
// id: '1',
// shape: 'dag-node',
// x: 290,
// y: 110,
// data: {
// label: '读数据',
// status: 'success',
// },
// ports: [
// {
// id: '1-1',
// group: 'bottom',
// },
// ],
// },
// {
// id: '2',
// shape: 'dag-node',
// x: 290,
// y: 225,
// data: {
// label: '读数据',
// status: 'success',
// },
// ports: [
// {
// id: '2-1',
// group: 'top',
// },
// {
// id: '2-2',
// group: 'bottom',
// },
// {
// id: '2-3',
// group: 'bottom',
// },
// ],
// },
// {
// id: '3',
// shape: 'dag-node',
// x: 170,
// y: 350,
// data: {
// label: '读数据',
// status: 'success',
// },
// ports: [
// {
// id: '3-1',
// group: 'top',
// },
// {
// id: '3-2',
// group: 'bottom',
// },
// ],
// },
// {
// id: '4',
// shape: 'dag-node',
// x: 450,
// y: 350,
// data: {
// label: '读数据',
// status: 'success',
// },
// ports: [
// {
// id: '4-1',
// group: 'top',
// },
// {
// id: '4-2',
// group: 'bottom',
// },
// ],
// },
// {
// id: '5',
// shape: 'dag-edge',
// source: {
// cell: '1',
// port: '1-1',
// },
// target: {
// cell: '2',
// port: '2-1',
// },
// zIndex: 0,
// },
// {
// id: '6',
// shape: 'dag-edge',
// source: {
// cell: '2',
// port: '2-2',
// },
// target: {
// cell: '3',
// port: '3-1',
// },
// zIndex: 0,
// },
// {
// id: '7',
// shape: 'dag-edge',
// source: {
// cell: '2',
// port: '2-3',
// },
// target: {
// cell: '4',
// port: '4-1',
// },
// zIndex: 0,
// },
// ]
const nodeStatusList = [
[
{
id: '1',
status: 'running',
},
{
id: '2',
status: 'default',
},
{
id: '3',
status: 'default',
},
{
id: '4',
status: 'default',
},
],
[
{
id: '1',
status: 'success',
},
{
id: '2',
status: 'running',
},
{
id: '3',
status: 'default',
},
{
id: '4',
status: 'default',
},
],
[
{
id: '1',
status: 'success',
},
{
id: '2',
status: 'success',
},
{
id: '3',
status: 'running',
},
{
id: '4',
status: 'running',
},
],
[
{
id: '1',
status: 'success',
},
{
id: '2',
status: 'success',
},
{
id: '3',
status: 'success',
},
{
id: '4',
status: 'failed',
},
],
]
export default class Example extends React.Component {
private container: HTMLDivElement
// const nodeStatusList = [
// [
// {
// id: '1',
// status: 'running',
// },
// {
// id: '2',
// status: 'default',
// },
// {
// id: '3',
// status: 'default',
// },
// {
// id: '4',
// status: 'default',
// },
// ],
// [
// {
// id: '1',
// status: 'success',
// },
// {
// id: '2',
// status: 'running',
// },
// {
// id: '3',
// status: 'default',
// },
// {
// id: '4',
// status: 'default',
// },
// ],
// [
// {
// id: '1',
// status: 'success',
// },
// {
// id: '2',
// status: 'success',
// },
// {
// id: '3',
// status: 'running',
// },
// {
// id: '4',
// status: 'running',
// },
// ],
// [
// {
// id: '1',
// status: 'success',
// },
// {
// id: '2',
// status: 'success',
// },
// {
// id: '3',
// status: 'success',
// },
// {
// id: '4',
// status: 'failed',
// },
// ],
// ]
// export default class Example extends React.Component {
// private container: HTMLDivElement
componentDidMount() {
const graph: Graph = new Graph({
container: this.container,
width: 800,
height: 600,
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,
connector: 'algo-connector',
connectionPoint: 'anchor',
anchor: 'center',
validateMagnet({ magnet }) {
return magnet.getAttribute('port-group') !== 'top'
},
createEdge() {
return graph.createEdge({
shape: 'dag-edge',
attrs: {
line: {
strokeDasharray: '5 5',
},
},
zIndex: -1,
})
},
},
selecting: {
enabled: true,
multiple: true,
rubberEdge: true,
rubberNode: true,
modifiers: 'shift',
rubberband: true,
},
})
// componentDidMount() {
// const graph: Graph = new Graph({
// container: this.container,
// width: 800,
// height: 600,
// 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,
// connector: 'algo-connector',
// connectionPoint: 'anchor',
// anchor: 'center',
// validateMagnet({ magnet }) {
// return magnet.getAttribute('port-group') !== 'top'
// },
// createEdge() {
// return graph.createEdge({
// shape: 'dag-edge',
// attrs: {
// line: {
// strokeDasharray: '5 5',
// },
// },
// zIndex: -1,
// })
// },
// },
// selecting: {
// enabled: true,
// multiple: true,
// rubberEdge: true,
// rubberNode: true,
// modifiers: 'shift',
// rubberband: true,
// },
// })
graph.on('edge:connected', ({ edge }) => {
edge.attr({
line: {
strokeDasharray: '',
},
})
})
// graph.on('edge:connected', ({ edge }) => {
// edge.attr({
// line: {
// strokeDasharray: '',
// },
// })
// })
graph.on('node:change:data', ({ node }) => {
const edges = graph.getIncomingEdges(node)
const { status } = node.getData() as NodeStatus
edges?.forEach((edge) => {
if (status === 'running') {
edge.attr('line/strokeDasharray', 5)
edge.attr('line/style/animation', 'running-line 30s infinite linear')
} else {
edge.attr('line/strokeDasharray', '')
edge.attr('line/style/animation', '')
}
})
})
// graph.on('node:change:data', ({ node }) => {
// const edges = graph.getIncomingEdges(node)
// const { status } = node.getData() as NodeStatus
// edges?.forEach((edge) => {
// if (status === 'running') {
// edge.attr('line/strokeDasharray', 5)
// edge.attr('line/style/animation', 'running-line 30s infinite linear')
// } else {
// edge.attr('line/strokeDasharray', '')
// edge.attr('line/style/animation', '')
// }
// })
// })
// 初始化节点/边
const init = (data: Cell.Metadata[]) => {
const cells: Cell[] = []
data.forEach((item) => {
if (item.shape === 'dag-node') {
cells.push(graph.createNode(item))
} else {
cells.push(graph.createEdge(item))
}
})
graph.resetCells(cells)
}
// // 初始化节点/边
// const init = (data: Cell.Metadata[]) => {
// const cells: Cell[] = []
// data.forEach((item) => {
// if (item.shape === 'dag-node') {
// cells.push(graph.createNode(item))
// } else {
// cells.push(graph.createEdge(item))
// }
// })
// graph.resetCells(cells)
// }
// 显示节点状态
const showNodeStatus = async (statusList: NodeStatus[][]) => {
const status = statusList.shift()
status?.forEach((item) => {
const { id, status } = item
const node = graph.getCellById(id)
const data = node.getData() as NodeStatus
node.setData({
...data,
status: status,
})
})
setTimeout(() => {
showNodeStatus(statusList)
}, 3000)
}
// // 显示节点状态
// const showNodeStatus = async (statusList: NodeStatus[][]) => {
// const status = statusList.shift()
// status?.forEach((item) => {
// const { id, status } = item
// const node = graph.getCellById(id)
// const data = node.getData() as NodeStatus
// node.setData({
// ...data,
// status: status,
// })
// })
// setTimeout(() => {
// showNodeStatus(statusList)
// }, 3000)
// }
init(data)
showNodeStatus(nodeStatusList)
}
// init(data)
// showNodeStatus(nodeStatusList)
// }
refContainer = (container: HTMLDivElement) => {
this.container = container
}
// refContainer = (container: HTMLDivElement) => {
// this.container = container
// }
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}
// render() {
// return (
// <div className="x6-graph-wrap">
// <div ref={this.refContainer} className="dag" />
// </div>
// )
// }
// }

View File

@ -155,7 +155,7 @@ export default class Example extends React.Component {
const { bendPoints = [] } = edge.sections[0]
if (pos) {
bendPoints.map((bendPoint: Position) => {
bendPoints.forEach((bendPoint: Position) => {
bendPoint.x += pos.x
bendPoint.y += pos.y
})

View File

@ -1,70 +1,72 @@
.node {
display: flex;
align-items: center;
width: 100%;
height: 100%;
background-color: #fff;
border: 1px solid #c2c8d5;
border-left: 4px solid #1890ff;
border-radius: 4px;
box-shadow: 0 2px 5px 1px rgba(0, 0, 0, 0.06);
img {
width: 20px;
height: 20px;
flex-shrink: 0;
margin-left: 8px;
}
.label {
display: inline-block;
flex-shrink: 0;
width: 104px;
margin-left: 8px;
color: #666;
font-size: 12px;
}
.status {
flex-shrink: 0;
}
&.success {
border-left: 4px solid #52c41a;
}
&.failed {
border-left: 4px solid #ff4d4f;
}
&.running .status img {
animation: spin 1s linear infinite;
}
}
.x6-node-selected {
.dag {
.node {
border-color: #1890ff;
border-radius: 2px;
box-shadow: 0 0 0 4px #d4e8fe;
display: flex;
align-items: center;
width: 100%;
height: 100%;
background-color: #fff;
border: 1px solid #c2c8d5;
border-left: 4px solid #1890ff;
border-radius: 4px;
box-shadow: 0 2px 5px 1px rgba(0, 0, 0, 0.06);
img {
width: 20px;
height: 20px;
flex-shrink: 0;
margin-left: 8px;
}
.label {
display: inline-block;
flex-shrink: 0;
width: 104px;
margin-left: 8px;
color: #666;
font-size: 12px;
}
.status {
flex-shrink: 0;
}
&.success {
border-left: 4px solid #52c41a;
}
&.failed {
border-left: 4px solid #ff4d4f;
}
&.running .status img {
animation: spin 1s linear infinite;
}
}
.node.success {
border-color: #52c41a;
border-radius: 2px;
box-shadow: 0 0 0 4px #ccecc0;
}
.node.failed {
border-color: #ff4d4f;
border-radius: 2px;
box-shadow: 0 0 0 4px #fedcdc;
}
}
.x6-edge:hover {
path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1px;
.x6-node-selected {
.node {
border-color: #1890ff;
border-radius: 2px;
box-shadow: 0 0 0 4px #d4e8fe;
}
.node.success {
border-color: #52c41a;
border-radius: 2px;
box-shadow: 0 0 0 4px #ccecc0;
}
.node.failed {
border-color: #ff4d4f;
border-radius: 2px;
box-shadow: 0 0 0 4px #fedcdc;
}
}
}
.x6-edge-selected {
path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1.5px !important;
.x6-edge:hover {
path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1px;
}
}
.x6-edge-selected {
path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1.5px !important;
}
}
}

View File

@ -189,8 +189,7 @@ export default class Example extends React.Component {
stroke: '#31d0c6',
fill: '#31d0c6',
name: 'path',
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',
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',
offsetX: 10,
},
},

View File

@ -98,14 +98,12 @@ export default class Example extends React.Component {
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',
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',
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',
},
},
},

View File

@ -48,7 +48,7 @@ class TooltipTool extends ToolsView.ToolItem<EdgeView, TooltipTool.Options> {
() => this.toggleTooltip(true),
this.delay,
)
if (this.options.follow != false) {
if (this.options.follow !== false) {
document.addEventListener('mousemove', this.onMouseMove)
}
}
@ -60,7 +60,7 @@ class TooltipTool extends ToolsView.ToolItem<EdgeView, TooltipTool.Options> {
() => this.toggleTooltip(false),
this.delay,
)
if (this.options.follow != false) {
if (this.options.follow !== false) {
document.removeEventListener('mousemove', this.onMouseMove)
}
}
@ -89,6 +89,7 @@ class TooltipTool extends ToolsView.ToolItem<EdgeView, TooltipTool.Options> {
}
}
// eslint-disable-next-line
namespace TooltipTool {
TooltipTool.config({
markup: Markup.getForeignObjectMarkup(),

View File

@ -14,7 +14,9 @@ export default class Example extends React.Component {
validateMagnet({ cell, magnet }) {
let count = 0
const connectionCount = magnet.getAttribute('connection-count')
const max = connectionCount ? parseInt(connectionCount, 10) : Number.MAX_SAFE_INTEGER
const max = connectionCount
? parseInt(connectionCount, 10)
: Number.MAX_SAFE_INTEGER
const outgoingEdges = graph.getOutgoingEdges(cell)
if (outgoingEdges) {
outgoingEdges.forEach((edge: Edge) => {

View File

@ -94,6 +94,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
namespace Example {
export interface Props {}
export interface State {

View File

@ -163,7 +163,7 @@ export default class Example extends React.Component {
if (!magnet) {
return true
}
var cell = (cellView.cell as any) as TogglableRect
var cell = cellView.cell as any as TogglableRect
var portId = magnet.getAttribute('port')
return portId ? !cell.isPortCollapsed(portId) : true
},
@ -180,7 +180,7 @@ export default class Example extends React.Component {
e.stopPropagation()
var portId = magnet.getAttribute('port')
if (portId) {
const rect = (view.cell as any) as TogglableRect
const rect = view.cell as any as TogglableRect
rect.expandPort(portId)
}
})
@ -191,13 +191,13 @@ export default class Example extends React.Component {
const visible = current !== false
const sourceCell = cell.getSourceCell()
if (sourceCell) {
const rect = (sourceCell as any) as TogglableRect
const rect = sourceCell as any as TogglableRect
rect.onConnectedEdgeVisibleChange(cell, 'source', visible)
}
const targetCell = cell.getTargetCell()
if (targetCell) {
const rect = (targetCell as any) as TogglableRect
const rect = targetCell as any as TogglableRect
rect.onConnectedEdgeVisibleChange(cell, 'target', visible)
}
}

View File

@ -87,7 +87,7 @@ export default class Example extends React.Component {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
<div id="minimap"/>
<div id="minimap" />
</div>
)
}

View File

@ -53,10 +53,8 @@ export class IntermediateEvent extends Event {
})
}
gateTypes = {
or:
'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0',
xor:
'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0 M -20 0 0 -30 M 0 -30 20 0',
or: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0',
xor: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0 M -20 0 0 -30 M 0 -30 20 0',
and: 'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z',
priority_and:
'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z M -20 0 0 -30 20 0',

View File

@ -154,6 +154,7 @@ export class AttributeCard extends React.Component<
}
}
// eslint-disable-next-line
export namespace AttributeCard {
export interface Props {
attrs: {

View File

@ -212,6 +212,7 @@ export class BackgroundCard extends React.Component<
}
}
// eslint-disable-next-line
export namespace BackgroundCard {
export interface Props {
onChange: (res: Graph.BackgroundOptions) => void

View File

@ -33,6 +33,7 @@ export class BBoxCard extends React.Component<GridCard.Props> {
}
}
// eslint-disable-next-line
export namespace GridCard {
export interface Props {
x: number

View File

@ -105,6 +105,7 @@ export class FitToContentCard extends React.Component<
}
}
// eslint-disable-next-line
export namespace FitToContentCard {
export interface Props {
onChange: (options: State) => void

View File

@ -228,6 +228,7 @@ export class GridCard extends React.Component<GridCard.Props, GridCard.State> {
}
}
// eslint-disable-next-line
export namespace GridCard {
export interface Props {
onGridSizeChange: (size: number) => void

View File

@ -77,7 +77,7 @@ export default class Example extends React.Component<
}),
})
})
.on('translate', ({origin: {x, y}}) => {
.on('translate', ({ origin: { x, y } }) => {
this.effect.hideAll()
this.setState({
attrs: getAttrs({
@ -195,6 +195,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
namespace Example {
export interface Props {}
export interface State {

View File

@ -122,6 +122,7 @@ export class ScaleContentToFitCard extends React.Component<
}
}
// eslint-disable-next-line
export namespace ScaleContentToFitCard {
export interface Props {
onChange: (options: State) => void

View File

@ -42,7 +42,7 @@ export default class Example extends React.Component {
stroke: '#9254de',
},
},
},
},
{
id: '2',
shape: 'rect',
@ -57,7 +57,7 @@ export default class Example extends React.Component {
stroke: '#9254de',
},
},
},
},
{
id: '3',
shape: 'rect',
@ -72,7 +72,7 @@ export default class Example extends React.Component {
stroke: '#9254de',
},
},
},
},
{
id: '4',
shape: 'rect',
@ -87,7 +87,7 @@ export default class Example extends React.Component {
stroke: '#9254de',
},
},
},
},
{
id: '5',
shape: 'rect',
@ -185,8 +185,8 @@ export default class Example extends React.Component {
}
onPositionPoint = () => {
this.graph1.positionPoint({x: 50, y: 60}, 100, 100)
this.graph2.positionPoint({x: 50, y: 60}, 100, 100)
this.graph1.positionPoint({ x: 50, y: 60 }, 100, 100)
this.graph2.positionPoint({ x: 50, y: 60 }, 100, 100)
}
onPositionRect = () => {
@ -214,23 +214,37 @@ export default class Example extends React.Component {
render() {
return (
<div>
<div>
<div className="x6-graph-wrap" style={{ display: 'flex' }}>
<div ref={this.refContainer1} className="x6-graph" />
<div ref={this.refContainer2} className="x6-graph" />
</div>
<div style={{
display: 'flex',
flexFlow: 'wrap',
flexShrink: 0,
padding: '24px 48px',
}}>
<div
style={{
display: 'flex',
flexFlow: 'wrap',
flexShrink: 0,
padding: '24px 48px',
}}
>
<Button onClick={() => this.onZoom(0.1)}>ZoomIn</Button>
<Button onClick={() => this.onZoom(-0.1)}>ZoomOut</Button>
<Button onClick={() => this.onZoom(0.1, { center: {x: 300, y: 200} })}>ZoomIn At [300, 200]</Button>
<Button onClick={() => this.onZoom(-0.1, { center: {x: 300, y: 200} })}>ZoomOut At [300, 200]</Button>
<Button
onClick={() => this.onZoom(0.1, { center: { x: 300, y: 200 } })}
>
ZoomIn At [300, 200]
</Button>
<Button
onClick={() => this.onZoom(-0.1, { center: { x: 300, y: 200 } })}
>
ZoomOut At [300, 200]
</Button>
<Button onClick={() => this.onZoomTo(1.5)}>ZoomTo</Button>
<Button onClick={() => this.onZoomTo(1.5, { center: {x: 200, y: 100} })}>ZoomTo At [200, 100]</Button>
<Button
onClick={() => this.onZoomTo(1.5, { center: { x: 200, y: 100 } })}
>
ZoomTo At [200, 100]
</Button>
<Button onClick={() => this.onZoomToRect()}>ZoomToRect</Button>
<Button onClick={() => this.onZoomToFit()}>ZoomToFit</Button>
<Button onClick={() => this.onCenterPoint()}>CenterPoint</Button>
@ -239,7 +253,9 @@ export default class Example extends React.Component {
<Button onClick={() => this.onCenterCell()}>CenterCell</Button>
<Button onClick={() => this.onPositionPoint()}>PositionPoint</Button>
<Button onClick={() => this.onPositionRect()}>PositionRect</Button>
<Button onClick={() => this.onPositionContent()}>PositionContent</Button>
<Button onClick={() => this.onPositionContent()}>
PositionContent
</Button>
<Button onClick={() => this.onPositionCell()}>PositionCell</Button>
</div>
</div>

View File

@ -1,310 +1,310 @@
import React from 'react'
import { Graph, Node } from '@antv/x6'
import '@antv/x6-react-shape'
import data from './data.json'
import '../index.less'
import './index.less'
// import React from 'react'
// import { Graph, Node } from '@antv/x6'
// import '@antv/x6-react-shape'
// import data from './data.json'
// import '../index.less'
// import './index.less'
//#region react component
interface IProps {
node?: Node
}
interface IState {
collapsed: boolean
}
class GroupComponent extends React.Component<IProps, IState> {
state = {
collapsed: false,
}
// //#region react component
// interface IProps {
// node?: Node
// }
// interface IState {
// collapsed: boolean
// }
// class GroupComponent extends React.Component<IProps, IState> {
// state = {
// collapsed: false,
// }
shouldComponentUpdate(nextProps: IProps, nextState: IState) {
return nextState.collapsed !== this.state.collapsed
}
// shouldComponentUpdate(nextProps: IProps, nextState: IState) {
// return nextState.collapsed !== this.state.collapsed
// }
onCollapse = () => {
const node = this.props.node
const target = !this.state.collapsed
// onCollapse = () => {
// const node = this.props.node
// const target = !this.state.collapsed
if (node) {
const cells = node.getChildren()
if (cells) {
cells.forEach((cell: Node) => {
if (target) {
cell.hide()
} else {
cell.show()
}
})
}
if (target) {
node.prop('previousSize', node.size())
node.size(160, 32)
} else {
const previousSize = node.prop('previousSize')
node.size(previousSize.width, previousSize.height)
}
}
// if (node) {
// const cells = node.getChildren()
// if (cells) {
// cells.forEach((cell: Node) => {
// if (target) {
// cell.hide()
// } else {
// cell.show()
// }
// })
// }
// if (target) {
// node.prop('previousSize', node.size())
// node.size(160, 32)
// } else {
// const previousSize = node.prop('previousSize')
// node.size(previousSize.width, previousSize.height)
// }
// }
this.setState({
collapsed: target,
})
}
// this.setState({
// collapsed: target,
// })
// }
render() {
return (
<div className="group">
<div className="header">
<span>
<img
src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*rYacTYE0PR0AAAAAAAAAAAAAARQnAQ"
alt="group"
/>
<span>Group</span>
</span>
<span className="btn" onClick={this.onCollapse}>
{this.state.collapsed ? '+' : '-'}
</span>
</div>
</div>
)
}
}
Graph.registerReactComponent('group', <GroupComponent />, true)
//#endregion
// render() {
// return (
// <div className="group">
// <div className="header">
// <span>
// <img
// src="https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*rYacTYE0PR0AAAAAAAAAAAAAARQnAQ"
// alt="group"
// />
// <span>Group</span>
// </span>
// <span className="btn" onClick={this.onCollapse}>
// {this.state.collapsed ? '+' : '-'}
// </span>
// </div>
// </div>
// )
// }
// }
// Graph.registerReactComponent('group', <GroupComponent />, true)
// //#endregion
export default class Example extends React.Component {
private graph: Graph
private container: HTMLDivElement
// export default class Example extends React.Component {
// private graph: Graph
// private container: HTMLDivElement
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
grid: true,
connecting: {
connector: 'smooth',
},
})
// componentDidMount() {
// const graph = new Graph({
// container: this.container,
// width: 800,
// height: 600,
// grid: true,
// connecting: {
// connector: 'smooth',
// },
// })
this.graph = graph
this.initShape()
this.initEvent()
}
// this.graph = graph
// this.initShape()
// this.initEvent()
// }
initShape = () => {
const nodes = data.nodes
const edges = data.edges
const groups = data.groups
const newEdges: typeof edges = []
// initShape = () => {
// const nodes = data.nodes
// const edges = data.edges
// const groups = data.groups
// const newEdges: typeof edges = []
const getNode = (nodeId: string) => {
if (nodeId) {
return nodes.find((node) => node.id === nodeId)
}
return null
}
// const getNode = (nodeId: string) => {
// if (nodeId) {
// return nodes.find((node) => node.id === nodeId)
// }
// return null
// }
const getGroup = (groupId: string | undefined) => {
if (groupId) {
return groups.find((group) => group.id === groupId)
}
return null
}
// const getGroup = (groupId: string | undefined) => {
// if (groupId) {
// return groups.find((group) => group.id === groupId)
// }
// return null
// }
// 将连接到群组内部节点的连线进行拆分
// source target op
// √ X source->群组->target
// X √ source->群组->target
// √ √ source->群组1->群组2->target
edges.forEach((edge) => {
const sourceNodeId =
typeof edge.source === 'string' ? edge.source : edge.source.cell
const targetNodeId =
typeof edge.target === 'string' ? edge.target : edge.target.cell
const sourceNode = getNode(sourceNodeId)
const targetNode = getNode(targetNodeId)
const sourceGroup = getGroup(sourceNode?.group)
const targetGroup = getGroup(targetNode?.group)
// // 将连接到群组内部节点的连线进行拆分
// // source target op
// // √ X source->群组->target
// // X √ source->群组->target
// // √ √ source->群组1->群组2->target
// edges.forEach((edge) => {
// const sourceNodeId =
// typeof edge.source === 'string' ? edge.source : edge.source.cell
// const targetNodeId =
// typeof edge.target === 'string' ? edge.target : edge.target.cell
// const sourceNode = getNode(sourceNodeId)
// const targetNode = getNode(targetNodeId)
// const sourceGroup = getGroup(sourceNode?.group)
// const targetGroup = getGroup(targetNode?.group)
if (sourceGroup !== targetGroup) {
if (sourceGroup && targetGroup) {
const sourceGroupPort = {
cell: sourceGroup.id,
port: sourceGroup.ports.items[0].id,
}
const targetGroupPort = {
cell: targetGroup.id,
port: targetGroup.ports.items[0].id,
}
newEdges.push(
...[
{
...edge,
source: edge.source,
target: sourceGroupPort,
id: `${edge.id}_1`,
for: edge.id,
},
{
...edge,
source: targetGroupPort,
target: edge.target,
id: `${edge.id}_2`,
for: edge.id,
},
],
)
edge.source = sourceGroupPort
edge.target = targetGroupPort
// if (sourceGroup !== targetGroup) {
// if (sourceGroup && targetGroup) {
// const sourceGroupPort = {
// cell: sourceGroup.id,
// port: sourceGroup.ports.items[0].id,
// }
// const targetGroupPort = {
// cell: targetGroup.id,
// port: targetGroup.ports.items[0].id,
// }
// newEdges.push(
// ...[
// {
// ...edge,
// source: edge.source,
// target: sourceGroupPort,
// id: `${edge.id}_1`,
// for: edge.id,
// },
// {
// ...edge,
// source: targetGroupPort,
// target: edge.target,
// id: `${edge.id}_2`,
// for: edge.id,
// },
// ],
// )
// edge.source = sourceGroupPort
// edge.target = targetGroupPort
const sourceChildren = sourceGroup.children as string[]
const targetChildren = targetGroup.children as string[]
sourceChildren.push(sourceNode!.id)
targetChildren.push(targetNode!.id)
} else if (sourceGroup) {
const sourceGroupPort = {
cell: sourceGroup.id,
port: sourceGroup.ports.items[0].id,
}
newEdges.push(
...[
{
...edge,
source: edge.source,
target: sourceGroupPort,
id: `${edge.id}_1`,
for: edge.id,
},
],
)
edge.source = sourceGroupPort
// const sourceChildren = sourceGroup.children as string[]
// const targetChildren = targetGroup.children as string[]
// sourceChildren.push(sourceNode!.id)
// targetChildren.push(targetNode!.id)
// } else if (sourceGroup) {
// const sourceGroupPort = {
// cell: sourceGroup.id,
// port: sourceGroup.ports.items[0].id,
// }
// newEdges.push(
// ...[
// {
// ...edge,
// source: edge.source,
// target: sourceGroupPort,
// id: `${edge.id}_1`,
// for: edge.id,
// },
// ],
// )
// edge.source = sourceGroupPort
const children = sourceGroup.children as string[]
children.push(sourceNode!.id)
} else if (targetGroup) {
const targetGroupPort = {
cell: targetGroup.id,
port: targetGroup.ports.items[0].id,
}
newEdges.push(
...[
{
...edge,
source: targetGroupPort,
target: edge.target,
id: `${edge.id}_1`,
for: edge.id,
},
],
)
edge.target = targetGroupPort
// const children = sourceGroup.children as string[]
// children.push(sourceNode!.id)
// } else if (targetGroup) {
// const targetGroupPort = {
// cell: targetGroup.id,
// port: targetGroup.ports.items[0].id,
// }
// newEdges.push(
// ...[
// {
// ...edge,
// source: targetGroupPort,
// target: edge.target,
// id: `${edge.id}_1`,
// for: edge.id,
// },
// ],
// )
// edge.target = targetGroupPort
const children = targetGroup.children as string[]
children.push(targetNode!.id)
}
}
})
// const children = targetGroup.children as string[]
// children.push(targetNode!.id)
// }
// }
// })
this.graph.addNodes([...nodes, ...groups])
this.graph.addEdges([...edges, ...newEdges])
}
// this.graph.addNodes([...nodes, ...groups])
// this.graph.addEdges([...edges, ...newEdges])
// }
initEvent = () => {
const graph = this.graph
graph.on('node:moving', ({ node }) => {
const isGroup = node.prop('isGroup')
if (isGroup) {
node.prop('originPosition', node.getPosition())
return
}
// initEvent = () => {
// const graph = this.graph
// graph.on('node:moving', ({ node }) => {
// const isGroup = node.prop('isGroup')
// if (isGroup) {
// node.prop('originPosition', node.getPosition())
// return
// }
const groupId = node.prop('group')
const group = graph.getNodes().find((node) => node.id === groupId)
if (!group) {
return
}
// const groupId = node.prop('group')
// const group = graph.getNodes().find((node) => node.id === groupId)
// if (!group) {
// return
// }
let hasChange = false
let originSize = group.prop('originSize')
if (originSize == null) {
originSize = group.size()
group.prop('originSize', originSize)
}
let originPosition = group.prop('originPosition')
if (originPosition == null) {
originPosition = group.position()
group.prop('originPosition', originPosition)
}
// let hasChange = false
// let originSize = group.prop('originSize')
// if (originSize == null) {
// originSize = group.size()
// group.prop('originSize', originSize)
// }
// let originPosition = group.prop('originPosition')
// if (originPosition == null) {
// originPosition = group.position()
// group.prop('originPosition', originPosition)
// }
let x = originPosition.x
let y = originPosition.y
let cornerX = originPosition.x + originSize.width
let cornerY = originPosition.y + originSize.height
const childs = group.getChildren()
if (childs) {
childs.forEach((child) => {
const bbox = child.getBBox().inflate(32)
const corner = bbox.getCorner()
// let x = originPosition.x
// let y = originPosition.y
// let cornerX = originPosition.x + originSize.width
// let cornerY = originPosition.y + originSize.height
// const childs = group.getChildren()
// if (childs) {
// childs.forEach((child) => {
// const bbox = child.getBBox().inflate(32)
// const corner = bbox.getCorner()
if (bbox.x < x) {
x = bbox.x
hasChange = true
}
// if (bbox.x < x) {
// x = bbox.x
// hasChange = true
// }
if (bbox.y < y) {
y = bbox.y
hasChange = true
}
// if (bbox.y < y) {
// y = bbox.y
// hasChange = true
// }
if (corner.x > cornerX) {
cornerX = corner.x
hasChange = true
}
// if (corner.x > cornerX) {
// cornerX = corner.x
// hasChange = true
// }
if (corner.y > cornerY) {
cornerY = corner.y
hasChange = true
}
})
}
// if (corner.y > cornerY) {
// cornerY = corner.y
// hasChange = true
// }
// })
// }
if (hasChange) {
group.prop({
position: { x, y },
size: { width: cornerX - x, height: cornerY - y },
})
}
})
}
// if (hasChange) {
// group.prop({
// position: { x, y },
// size: { width: cornerX - x, height: cornerY - y },
// })
// }
// })
// }
toJson = () => {
const res = this.graph.toJSON()
const cells = res.cells
res.cells = cells
.filter((cell) => !cell.for)
.map((cell) => {
if (cell.shape === 'edge') {
return {
...cell,
source: cell.originSource || cell.source,
target: cell.originTarget || cell.target,
}
}
return cell
})
return res
}
// toJson = () => {
// const res = this.graph.toJSON()
// const cells = res.cells
// res.cells = cells
// .filter((cell) => !cell.for)
// .map((cell) => {
// if (cell.shape === 'edge') {
// return {
// ...cell,
// source: cell.originSource || cell.source,
// target: cell.originTarget || cell.target,
// }
// }
// return cell
// })
// return res
// }
refContainer = (container: HTMLDivElement) => {
this.container = container
}
// refContainer = (container: HTMLDivElement) => {
// this.container = container
// }
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}
// render() {
// return (
// <div className="x6-graph-wrap">
// <div ref={this.refContainer} className="x6-graph" />
// </div>
// )
// }
// }

View File

@ -23,3 +23,9 @@
box-shadow: 0 0 10px 1px #e9e9e9;
margin: 0 auto;
}
.home {
width: 800px;
height: 100%;
margin: 0 auto;
}

View File

@ -1,9 +1,42 @@
import React from 'react'
import { Table } from 'antd'
import './index.less'
export default function() {
const dataSource = [
{
key: '1',
example: 'animation/transition',
description: 'transition 动画',
},
]
const columns = [
{
title: 'example',
dataIndex: 'example',
render(text: string) {
return (
<a href={`./${text}`} target="_blank">
{text}
</a>
)
},
},
{
title: 'description',
dataIndex: 'description',
},
]
export default function () {
return (
<div>
<h1>Feature List</h1>
<div className="home">
<Table
dataSource={dataSource}
columns={columns}
pagination={false}
size="small"
/>
</div>
)
}

View File

@ -245,6 +245,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -174,6 +174,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -32,7 +32,7 @@ class ContextMenuTool extends ToolsView.ToolItem<
trigger={['click']}
overlay={this.options.menu}
>
<a />
<a href="#" />
</Dropdown>,
this.knob,
() => {

View File

@ -43,8 +43,7 @@ const data = {
y: 40,
attrs: {
label: {
text:
'testing测试测试测试thisisaveryveryveryveryveryverylongword jsvascriptjsvascriptjsvascript',
text: 'testing测试测试测试thisisaveryveryveryveryveryverylongword jsvascriptjsvascriptjsvascript',
},
},
},

View File

@ -84,6 +84,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -56,14 +56,10 @@ export default class Example extends React.Component {
graph.on('edge:connected', ({ edge }) => {
graph.batchUpdate(() => {
const {
port: sourcePort,
...source
} = edge.getSource() as Edge.TerminalCellData
const {
port: targetPort,
...target
} = edge.getTarget() as Edge.TerminalCellData
const { port: sourcePort, ...source } =
edge.getSource() as Edge.TerminalCellData
const { port: targetPort, ...target } =
edge.getTarget() as Edge.TerminalCellData
edge.removeProp('source')
edge.removeProp('target')

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
Graph,
Node,
@ -138,7 +139,7 @@ Graph.registerEdge(
return defaults
}
const attr = (val as {}) as AngleEdge.AngleOptions
const attr = val as {} as AngleEdge.AngleOptions
var angleRadius = attr.radius || 40
var angleStart = attr.start || 'self'
var anglePie = attr.pie || false
@ -181,7 +182,7 @@ Graph.registerEdge(
set(val, options) {
let text = ''
const view = options.view as EdgeView
const attr = (val as {}) as AngleEdge.AngleTextOptions
const attr = val as {} as AngleEdge.AngleTextOptions
let meta = AngleEdge.getArcMeta(view, attr.type, { radius: 40 })
if (meta) {
@ -213,8 +214,8 @@ Graph.registerEdge(
line = new Line(connectionPoint, p).setLength(distance)
} else {
const c = new Line(arcPoint1, arcPoint2).getCenter()
;(line = new Line(connectionPoint, c).setLength(distance)),
largeArcFlag && line.scale(-1, -1, line.start)
line = new Line(connectionPoint, c).setLength(distance)
largeArcFlag && line.scale(-1, -1, line.start)
}
const pos = line.end
@ -230,6 +231,7 @@ Graph.registerEdge(
true,
)
// eslint-disable-next-line
namespace Cache {
function ensure(view: EdgeView) {
const cacheKey = 'angleData'
@ -237,7 +239,7 @@ namespace Cache {
if (!(cacheKey in cache)) {
cache[cacheKey] = {}
}
return (cache[cacheKey] as Object) as {
return cache[cacheKey] as Object as {
[key: string]: AngleEdge.Metadata | null
}
}
@ -261,6 +263,7 @@ namespace Cache {
}
}
// eslint-disable-next-line
namespace AngleEdge {
export type AngleStart = 'self' | 'source' | 'target'
export type AngleDirection = 'clockwise' | 'anticlockwise' | 'small' | 'large'

View File

@ -202,8 +202,7 @@ export default class Example extends React.Component {
{
tagName: 'path',
attrs: {
d:
'M -4 -0.8 L -7.2 2.4 L -4 5.6 L -4 3.2 L 1.6 3.2 L 1.6 1.6 L -4 1.6 L -4 -0.8 Z M 7.2 -2.4 L 4 -5.6 L 4 -3.2 L -1.6 -3.2 L -1.6 -1.6 L 4 -1.6 L 4 0.8 L 7.2 -2.4 Z',
d: 'M -4 -0.8 L -7.2 2.4 L -4 5.6 L -4 3.2 L 1.6 3.2 L 1.6 1.6 L -4 1.6 L -4 -0.8 Z M 7.2 -2.4 L 4 -5.6 L 4 -3.2 L -1.6 -3.2 L -1.6 -1.6 L 4 -1.6 L 4 0.8 L 7.2 -2.4 Z',
cursor: 'pointer',
strokeWidth: 2,
fill: '#fff',
@ -241,8 +240,7 @@ export default class Example extends React.Component {
{
tagName: 'path',
attrs: {
d:
'M -4 -0.8 L -7.2 2.4 L -4 5.6 L -4 3.2 L 1.6 3.2 L 1.6 1.6 L -4 1.6 L -4 -0.8 Z M 7.2 -2.4 L 4 -5.6 L 4 -3.2 L -1.6 -3.2 L -1.6 -1.6 L 4 -1.6 L 4 0.8 L 7.2 -2.4 Z',
d: 'M -4 -0.8 L -7.2 2.4 L -4 5.6 L -4 3.2 L 1.6 3.2 L 1.6 1.6 L -4 1.6 L -4 -0.8 Z M 7.2 -2.4 L 4 -5.6 L 4 -3.2 L -1.6 -3.2 L -1.6 -1.6 L 4 -1.6 L 4 0.8 L 7.2 -2.4 Z',
cursor: 'pointer',
strokeWidth: 2,
fill: '#fff',

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-namespace */
import { Graph, Shape, EdgeView, Edge, Registry, Point, Angle } from '@antv/x6'
Graph.registerNode(
@ -138,7 +139,7 @@ export const DistanceEdgeBase = Graph.registerEdge(
distanceAnchor: {
set(val, { view }) {
if (typeof val === 'object') {
const attr = (val as {}) as DistanceEdge.DistanceAnchorOptions
const attr = val as {} as DistanceEdge.DistanceAnchorOptions
const edgeView = view as EdgeView
const anchor = edgeView.getTerminalAnchor(attr.type)
const kont = edgeView.getTerminalConnectionPoint(attr.type)
@ -151,7 +152,7 @@ export const DistanceEdgeBase = Graph.registerEdge(
distanceText: {
set(val, options) {
const view = options.view as EdgeView
const attr = (val as {}) as DistanceEdge.DistanceTextOptions
const attr = val as {} as DistanceEdge.DistanceTextOptions
const text = DistanceEdge.getDistanceText(view, attr)
const raw = Registry.Attr.presets.text as Registry.Attr.SetDefinition
raw.set.call(this, text, options)

View File

@ -247,6 +247,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -31,6 +31,7 @@ class Coords {
}
}
// eslint-disable-next-line
namespace RandomDir {
let radian = 4

View File

@ -181,7 +181,7 @@ export default class Example extends React.Component<
edges.shift()
this.viewport = (viewportTemplate.clone() as any) as Node
this.viewport = viewportTemplate.clone() as any as Node
console.time('perf-reset')
@ -305,6 +305,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -1,81 +1,102 @@
[{
"num": 200,
"time": 0.379,
"type": "async"
}, {
"num": 400,
"time": 0.481,
"type": "async"
}, {
"num": 600,
"time": 0.569,
"type": "async"
}, {
"num": 800,
"time": 0.681,
"type": "async"
}, {
"num": 1000,
"time": 0.79,
"type": "async"
}, {
"num": 1200,
"time": 0.915,
"type": "async"
}, {
"num": 1400,
"time": 1.056,
"type": "async"
}, {
"num": 1600,
"time": 1.24,
"type": "async"
}, {
"num": 1800,
"time": 1.388,
"type": "async"
}, {
"num": 2000,
"time": 1.497,
"type": "async"
},{
"num": 200,
"time": 0.224,
"type": "sync"
}, {
"num": 400,
"time": 0.355,
"type": "sync"
}, {
"num": 600,
"time": 0.489,
"type": "sync"
}, {
"num": 800,
"time": 0.579,
"type": "sync"
}, {
"num": 1000,
"time": 0.764,
"type": "sync"
}, {
"num": 1200,
"time": 0.858,
"type": "sync"
}, {
"num": 1400,
"time": 0.992,
"type": "sync"
}, {
"num": 1600,
"time": 1.126,
"type": "sync"
}, {
"num": 1800,
"time": 1.282,
"type": "sync"
}, {
"num": 2000,
"time": 1.763,
"type": "sync"
}]
[
{
"num": 200,
"time": 0.379,
"type": "async"
},
{
"num": 400,
"time": 0.481,
"type": "async"
},
{
"num": 600,
"time": 0.569,
"type": "async"
},
{
"num": 800,
"time": 0.681,
"type": "async"
},
{
"num": 1000,
"time": 0.79,
"type": "async"
},
{
"num": 1200,
"time": 0.915,
"type": "async"
},
{
"num": 1400,
"time": 1.056,
"type": "async"
},
{
"num": 1600,
"time": 1.24,
"type": "async"
},
{
"num": 1800,
"time": 1.388,
"type": "async"
},
{
"num": 2000,
"time": 1.497,
"type": "async"
},
{
"num": 200,
"time": 0.224,
"type": "sync"
},
{
"num": 400,
"time": 0.355,
"type": "sync"
},
{
"num": 600,
"time": 0.489,
"type": "sync"
},
{
"num": 800,
"time": 0.579,
"type": "sync"
},
{
"num": 1000,
"time": 0.764,
"type": "sync"
},
{
"num": 1200,
"time": 0.858,
"type": "sync"
},
{
"num": 1400,
"time": 0.992,
"type": "sync"
},
{
"num": 1600,
"time": 1.126,
"type": "sync"
},
{
"num": 1800,
"time": 1.282,
"type": "sync"
},
{
"num": 2000,
"time": 1.763,
"type": "sync"
}
]

View File

@ -73,7 +73,7 @@ export default class Example extends React.Component {
})
nodes.push(a)
})
Array.from({ length: num }).forEach(() => {
const a = graph.createEdge({
shape: 'performance_normal_edge',
@ -92,7 +92,7 @@ export default class Example extends React.Component {
function test(num: number, iterations: number) {
const { nodes, edges } = mockCells(num)
graph.model.resetCells(nodes)
const startTime = new Date().getTime()
graph.model.addCells(edges)
if (ASYNC) {
@ -121,7 +121,11 @@ export default class Example extends React.Component {
function output() {
const res = Object.keys(result).map((key: string) => ({
num: parseInt(key, 10),
time: parseFloat((result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(3)),
time: parseFloat(
(result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(
3,
),
),
type: ASYNC ? 'async' : 'sync',
}))
document.getElementById('result')!.innerText = JSON.stringify(res)
@ -137,7 +141,7 @@ export default class Example extends React.Component {
render() {
return (
<div className="x6-graph-wrap">
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }}/>
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }} />
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -1,81 +1,102 @@
[{
"num": 500,
"time": 0.285,
"type": "sync"
}, {
"num": 1000,
"time": 0.477,
"type": "sync"
}, {
"num": 1500,
"time": 0.744,
"type": "sync"
}, {
"num": 2000,
"time": 0.964,
"type": "sync"
}, {
"num": 2500,
"time": 1.347,
"type": "sync"
}, {
"num": 3000,
"time": 1.561,
"type": "sync"
}, {
"num": 3500,
"time": 1.831,
"type": "sync"
}, {
"num": 4000,
"time": 2.14,
"type": "sync"
}, {
"num": 4500,
"time": 2.715,
"type": "sync"
}, {
"num": 5000,
"time": 2.848,
"type": "sync"
},{
"num": 500,
"time": 0.276,
"type": "async"
}, {
"num": 1000,
"time": 0.429,
"type": "async"
}, {
"num": 1500,
"time": 0.677,
"type": "async"
}, {
"num": 2000,
"time": 0.897,
"type": "async"
}, {
"num": 2500,
"time": 1.356,
"type": "async"
}, {
"num": 3000,
"time": 1.584,
"type": "async"
}, {
"num": 3500,
"time": 2.045,
"type": "async"
}, {
"num": 4000,
"time": 2.347,
"type": "async"
}, {
"num": 4500,
"time": 2.705,
"type": "async"
}, {
"num": 5000,
"time": 3.072,
"type": "async"
}]
[
{
"num": 500,
"time": 0.285,
"type": "sync"
},
{
"num": 1000,
"time": 0.477,
"type": "sync"
},
{
"num": 1500,
"time": 0.744,
"type": "sync"
},
{
"num": 2000,
"time": 0.964,
"type": "sync"
},
{
"num": 2500,
"time": 1.347,
"type": "sync"
},
{
"num": 3000,
"time": 1.561,
"type": "sync"
},
{
"num": 3500,
"time": 1.831,
"type": "sync"
},
{
"num": 4000,
"time": 2.14,
"type": "sync"
},
{
"num": 4500,
"time": 2.715,
"type": "sync"
},
{
"num": 5000,
"time": 2.848,
"type": "sync"
},
{
"num": 500,
"time": 0.276,
"type": "async"
},
{
"num": 1000,
"time": 0.429,
"type": "async"
},
{
"num": 1500,
"time": 0.677,
"type": "async"
},
{
"num": 2000,
"time": 0.897,
"type": "async"
},
{
"num": 2500,
"time": 1.356,
"type": "async"
},
{
"num": 3000,
"time": 1.584,
"type": "async"
},
{
"num": 3500,
"time": 2.045,
"type": "async"
},
{
"num": 4000,
"time": 2.347,
"type": "async"
},
{
"num": 4500,
"time": 2.705,
"type": "async"
},
{
"num": 5000,
"time": 3.072,
"type": "async"
}
]

View File

@ -90,7 +90,11 @@ export default class Example extends React.Component {
function output() {
const res = Object.keys(result).map((key: string) => ({
num: parseInt(key, 10),
time: parseFloat((result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(3)),
time: parseFloat(
(result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(
3,
),
),
type: ASYNC ? 'async' : 'sync',
}))
document.getElementById('result')!.innerText = JSON.stringify(res)
@ -106,7 +110,7 @@ export default class Example extends React.Component {
render() {
return (
<div className="x6-graph-wrap">
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }}/>
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }} />
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -1,81 +1,102 @@
[{
"num": 500,
"time": 0.594,
"type": "sync"
}, {
"num": 1000,
"time": 1.005,
"type": "sync"
}, {
"num": 1500,
"time": 1.514,
"type": "sync"
}, {
"num": 2000,
"time": 2.014,
"type": "sync"
}, {
"num": 2500,
"time": 2.775,
"type": "sync"
}, {
"num": 3000,
"time": 3.103,
"type": "sync"
}, {
"num": 3500,
"time": 3.689,
"type": "sync"
}, {
"num": 4000,
"time": 4.844,
"type": "sync"
}, {
"num": 4500,
"time": 4.972,
"type": "sync"
}, {
"num": 5000,
"time": 6.49,
"type": "sync"
}, {
"num": 500,
"time": 0.546,
"type": "async"
}, {
"num": 1000,
"time": 0.934,
"type": "async"
}, {
"num": 1500,
"time": 1.37,
"type": "async"
}, {
"num": 2000,
"time": 1.867,
"type": "async"
}, {
"num": 2500,
"time": 2.976,
"type": "async"
}, {
"num": 3000,
"time": 3.687,
"type": "async"
}, {
"num": 3500,
"time": 4.809,
"type": "async"
}, {
"num": 4000,
"time": 5.251,
"type": "async"
}, {
"num": 4500,
"time": 6.628,
"type": "async"
}, {
"num": 5000,
"time": 7.04,
"type": "async"
}]
[
{
"num": 500,
"time": 0.594,
"type": "sync"
},
{
"num": 1000,
"time": 1.005,
"type": "sync"
},
{
"num": 1500,
"time": 1.514,
"type": "sync"
},
{
"num": 2000,
"time": 2.014,
"type": "sync"
},
{
"num": 2500,
"time": 2.775,
"type": "sync"
},
{
"num": 3000,
"time": 3.103,
"type": "sync"
},
{
"num": 3500,
"time": 3.689,
"type": "sync"
},
{
"num": 4000,
"time": 4.844,
"type": "sync"
},
{
"num": 4500,
"time": 4.972,
"type": "sync"
},
{
"num": 5000,
"time": 6.49,
"type": "sync"
},
{
"num": 500,
"time": 0.546,
"type": "async"
},
{
"num": 1000,
"time": 0.934,
"type": "async"
},
{
"num": 1500,
"time": 1.37,
"type": "async"
},
{
"num": 2000,
"time": 1.867,
"type": "async"
},
{
"num": 2500,
"time": 2.976,
"type": "async"
},
{
"num": 3000,
"time": 3.687,
"type": "async"
},
{
"num": 3500,
"time": 4.809,
"type": "async"
},
{
"num": 4000,
"time": 5.251,
"type": "async"
},
{
"num": 4500,
"time": 6.628,
"type": "async"
},
{
"num": 5000,
"time": 7.04,
"type": "async"
}
]

View File

@ -156,7 +156,11 @@ export default class Example extends React.Component {
function output() {
const res = Object.keys(result).map((key: string) => ({
num: parseInt(key, 10),
time: parseFloat((result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(3)),
time: parseFloat(
(result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(
3,
),
),
type: ASYNC ? 'async' : 'sync',
}))
document.getElementById('result')!.innerText = JSON.stringify(res)
@ -172,7 +176,7 @@ export default class Example extends React.Component {
render() {
return (
<div className="x6-graph-wrap">
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }}/>
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }} />
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -1,81 +1,102 @@
[{
"num": 500,
"time": 0.232,
"type": "sync"
}, {
"num": 1000,
"time": 0.344,
"type": "sync"
}, {
"num": 1500,
"time": 0.565,
"type": "sync"
}, {
"num": 2000,
"time": 0.707,
"type": "sync"
}, {
"num": 2500,
"time": 0.903,
"type": "sync"
}, {
"num": 3000,
"time": 1.147,
"type": "sync"
}, {
"num": 3500,
"time": 1.36,
"type": "sync"
}, {
"num": 4000,
"time": 1.589,
"type": "sync"
}, {
"num": 4500,
"time": 1.848,
"type": "sync"
}, {
"num": 5000,
"time": 2.332,
"type": "sync"
}, {
"num": 500,
"time": 0.39,
"type": "async"
}, {
"num": 1000,
"time": 0.633,
"type": "async"
}, {
"num": 1500,
"time": 0.903,
"type": "async"
}, {
"num": 2000,
"time": 1.163,
"type": "async"
}, {
"num": 2500,
"time": 1.831,
"type": "async"
}, {
"num": 3000,
"time": 2.172,
"type": "async"
}, {
"num": 3500,
"time": 2.739,
"type": "async"
}, {
"num": 4000,
"time": 3.073,
"type": "async"
}, {
"num": 4500,
"time": 3.7,
"type": "async"
}, {
"num": 5000,
"time": 4.065,
"type": "async"
}]
[
{
"num": 500,
"time": 0.232,
"type": "sync"
},
{
"num": 1000,
"time": 0.344,
"type": "sync"
},
{
"num": 1500,
"time": 0.565,
"type": "sync"
},
{
"num": 2000,
"time": 0.707,
"type": "sync"
},
{
"num": 2500,
"time": 0.903,
"type": "sync"
},
{
"num": 3000,
"time": 1.147,
"type": "sync"
},
{
"num": 3500,
"time": 1.36,
"type": "sync"
},
{
"num": 4000,
"time": 1.589,
"type": "sync"
},
{
"num": 4500,
"time": 1.848,
"type": "sync"
},
{
"num": 5000,
"time": 2.332,
"type": "sync"
},
{
"num": 500,
"time": 0.39,
"type": "async"
},
{
"num": 1000,
"time": 0.633,
"type": "async"
},
{
"num": 1500,
"time": 0.903,
"type": "async"
},
{
"num": 2000,
"time": 1.163,
"type": "async"
},
{
"num": 2500,
"time": 1.831,
"type": "async"
},
{
"num": 3000,
"time": 2.172,
"type": "async"
},
{
"num": 3500,
"time": 2.739,
"type": "async"
},
{
"num": 4000,
"time": 3.073,
"type": "async"
},
{
"num": 4500,
"time": 3.7,
"type": "async"
},
{
"num": 5000,
"time": 4.065,
"type": "async"
}
]

View File

@ -102,7 +102,11 @@ export default class Example extends React.Component {
function output() {
const res = Object.keys(result).map((key: string) => ({
num: parseInt(key, 10),
time: parseFloat((result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(3)),
time: parseFloat(
(result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(
3,
),
),
type: ASYNC ? 'async' : 'sync',
}))
document.getElementById('result')!.innerText = JSON.stringify(res)
@ -118,7 +122,7 @@ export default class Example extends React.Component {
render() {
return (
<div className="x6-graph-wrap">
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }}/>
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }} />
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -1,81 +1,102 @@
[{
"num": 500,
"time": 1.167,
"type": "async"
}, {
"num": 1000,
"time": 1.969,
"type": "async"
}, {
"num": 1500,
"time": 2.944,
"type": "async"
}, {
"num": 2000,
"time": 3.886,
"type": "async"
}, {
"num": 2500,
"time": 6.275,
"type": "async"
}, {
"num": 3000,
"time": 7.236,
"type": "async"
}, {
"num": 3500,
"time": 9.368,
"type": "async"
}, {
"num": 4000,
"time": 10.251,
"type": "async"
}, {
"num": 4500,
"time": 12.526,
"type": "async"
}, {
"num": 5000,
"time": 13.472,
"type": "async"
}, {
"num": 500,
"time": 0.768,
"type": "sync"
}, {
"num": 1000,
"time": 1.353,
"type": "sync"
}, {
"num": 1500,
"time": 1.951,
"type": "sync"
}, {
"num": 2000,
"time": 2.604,
"type": "sync"
}, {
"num": 2500,
"time": 3.522,
"type": "sync"
}, {
"num": 3000,
"time": 4.03,
"type": "sync"
}, {
"num": 3500,
"time": 4.803,
"type": "sync"
}, {
"num": 4000,
"time": 6.168,
"type": "sync"
}, {
"num": 4500,
"time": 7.369,
"type": "sync"
}, {
"num": 5000,
"time": 8.581,
"type": "sync"
}]
[
{
"num": 500,
"time": 1.167,
"type": "async"
},
{
"num": 1000,
"time": 1.969,
"type": "async"
},
{
"num": 1500,
"time": 2.944,
"type": "async"
},
{
"num": 2000,
"time": 3.886,
"type": "async"
},
{
"num": 2500,
"time": 6.275,
"type": "async"
},
{
"num": 3000,
"time": 7.236,
"type": "async"
},
{
"num": 3500,
"time": 9.368,
"type": "async"
},
{
"num": 4000,
"time": 10.251,
"type": "async"
},
{
"num": 4500,
"time": 12.526,
"type": "async"
},
{
"num": 5000,
"time": 13.472,
"type": "async"
},
{
"num": 500,
"time": 0.768,
"type": "sync"
},
{
"num": 1000,
"time": 1.353,
"type": "sync"
},
{
"num": 1500,
"time": 1.951,
"type": "sync"
},
{
"num": 2000,
"time": 2.604,
"type": "sync"
},
{
"num": 2500,
"time": 3.522,
"type": "sync"
},
{
"num": 3000,
"time": 4.03,
"type": "sync"
},
{
"num": 3500,
"time": 4.803,
"type": "sync"
},
{
"num": 4000,
"time": 6.168,
"type": "sync"
},
{
"num": 4500,
"time": 7.369,
"type": "sync"
},
{
"num": 5000,
"time": 8.581,
"type": "sync"
}
]

View File

@ -35,48 +35,48 @@ const Node = N.registry.register(
position: 'top',
attrs: {
fo: {
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
},
},
right: {
position: 'right',
attrs: {
fo: {
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
},
},
bottom: {
position: 'bottom',
attrs: {
fo: {
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
},
},
left: {
position: 'left',
attrs: {
fo: {
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
width: 10,
height: 10,
x: -5,
y: -5,
magnet: 'true',
},
},
},
},
@ -114,15 +114,15 @@ export default class Example extends React.Component {
const container = selectors && selectors.foContent
if (container) {
ReactDOM.render(
(
<div style={{
<div
style={{
width: '100%',
height: '100%',
border: '1px solid #808080',
borderRadius: '100%',
background: '#eee',
}} />
),
}}
/>,
container as HTMLElement,
)
}
@ -176,7 +176,11 @@ export default class Example extends React.Component {
function output() {
const res = Object.keys(result).map((key: string) => ({
num: parseInt(key, 10),
time: parseFloat((result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(3)),
time: parseFloat(
(result[key].reduce((pre, cur) => pre + cur, 0) / ITERATIONS).toFixed(
3,
),
),
type: ASYNC ? 'async' : 'sync',
}))
document.getElementById('result')!.innerText = JSON.stringify(res)
@ -192,7 +196,7 @@ export default class Example extends React.Component {
render() {
return (
<div className="x6-graph-wrap">
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }}/>
<div id="result" style={{ paddingLeft: 8, paddingBottom: 8 }} />
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -1,383 +1,383 @@
import React from 'react'
import { Graph, Color } from '@antv/x6'
import '@antv/x6-react-shape'
import { Button } from 'antd'
import '../index.less'
// import React from 'react'
// import { Graph, Color } from '@antv/x6'
// import '@antv/x6-react-shape'
// import { Button } from 'antd'
// import '../index.less'
Graph.registerNode(
'org-node',
{
width: 260,
height: 88,
markup: [
{
tagName: 'rect',
attrs: {
class: 'card',
},
},
{
tagName: 'image',
attrs: {
class: 'image',
},
},
{
tagName: 'text',
attrs: {
class: 'rank',
},
},
{
tagName: 'text',
attrs: {
class: 'name',
},
},
{
tagName: 'g',
attrs: {
class: 'btn add',
},
children: [
{
tagName: 'circle',
attrs: {
class: 'add',
},
},
{
tagName: 'text',
attrs: {
class: 'add',
},
},
],
},
{
tagName: 'g',
attrs: {
class: 'btn del',
},
children: [
{
tagName: 'circle',
attrs: {
class: 'del',
},
},
{
tagName: 'text',
attrs: {
class: 'del',
},
},
],
},
],
attrs: {
'.card': {
rx: 10,
ry: 10,
refWidth: '100%',
refHeight: '100%',
fill: '#FFF',
stroke: '#000',
strokeWidth: 0,
pointerEvents: 'visiblePainted',
},
'.image': {
x: 16,
y: 16,
width: 56,
height: 56,
opacity: 0.7,
},
'.rank': {
refX: 0.95,
refY: 0.5,
fontFamily: 'Courier New',
fontSize: 13,
textAnchor: 'end',
textVerticalAnchor: 'middle',
},
'.name': {
refX: 0.95,
refY: 0.7,
fontFamily: 'Arial',
fontSize: 14,
fontWeight: '600',
textAnchor: 'end',
},
'.btn.add': {
refDx: -16,
refY: 16,
event: 'node:add',
},
'.btn.del': {
refDx: -44,
refY: 16,
event: 'node:delete',
},
'.btn > circle': {
r: 10,
fill: 'transparent',
stroke: '#333',
strokeWidth: 1,
},
'.btn.add > text': {
fontSize: 20,
fontWeight: 800,
stroke: '#000',
x: -5.5,
y: 7,
fontFamily: 'Times New Roman',
text: '+',
},
'.btn.del > text': {
fontSize: 28,
fontWeight: 500,
stroke: '#000',
x: -4.5,
y: 6,
fontFamily: 'Times New Roman',
text: '-',
},
},
},
true,
)
// Graph.registerNode(
// 'org-node',
// {
// width: 260,
// height: 88,
// markup: [
// {
// tagName: 'rect',
// attrs: {
// class: 'card',
// },
// },
// {
// tagName: 'image',
// attrs: {
// class: 'image',
// },
// },
// {
// tagName: 'text',
// attrs: {
// class: 'rank',
// },
// },
// {
// tagName: 'text',
// attrs: {
// class: 'name',
// },
// },
// {
// tagName: 'g',
// attrs: {
// class: 'btn add',
// },
// children: [
// {
// tagName: 'circle',
// attrs: {
// class: 'add',
// },
// },
// {
// tagName: 'text',
// attrs: {
// class: 'add',
// },
// },
// ],
// },
// {
// tagName: 'g',
// attrs: {
// class: 'btn del',
// },
// children: [
// {
// tagName: 'circle',
// attrs: {
// class: 'del',
// },
// },
// {
// tagName: 'text',
// attrs: {
// class: 'del',
// },
// },
// ],
// },
// ],
// attrs: {
// '.card': {
// rx: 10,
// ry: 10,
// refWidth: '100%',
// refHeight: '100%',
// fill: '#FFF',
// stroke: '#000',
// strokeWidth: 0,
// pointerEvents: 'visiblePainted',
// },
// '.image': {
// x: 16,
// y: 16,
// width: 56,
// height: 56,
// opacity: 0.7,
// },
// '.rank': {
// refX: 0.95,
// refY: 0.5,
// fontFamily: 'Courier New',
// fontSize: 13,
// textAnchor: 'end',
// textVerticalAnchor: 'middle',
// },
// '.name': {
// refX: 0.95,
// refY: 0.7,
// fontFamily: 'Arial',
// fontSize: 14,
// fontWeight: '600',
// textAnchor: 'end',
// },
// '.btn.add': {
// refDx: -16,
// refY: 16,
// event: 'node:add',
// },
// '.btn.del': {
// refDx: -44,
// refY: 16,
// event: 'node:delete',
// },
// '.btn > circle': {
// r: 10,
// fill: 'transparent',
// stroke: '#333',
// strokeWidth: 1,
// },
// '.btn.add > text': {
// fontSize: 20,
// fontWeight: 800,
// stroke: '#000',
// x: -5.5,
// y: 7,
// fontFamily: 'Times New Roman',
// text: '+',
// },
// '.btn.del > text': {
// fontSize: 28,
// fontWeight: 500,
// stroke: '#000',
// x: -4.5,
// y: 6,
// fontFamily: 'Times New Roman',
// text: '-',
// },
// },
// },
// true,
// )
Graph.registerReactComponent(
'custom',
<div
style={{
display: 'flex',
alignItems: 'center',
border: '1px solid #1890ff',
backgroundColor: 'rgba(227,244,255,.9)',
boxShadow: '0 0 3px 3px rgb(64 169 255 / 20%)',
borderRadius: '16px',
}}
>
<div>
<svg
width="1em"
height="1em"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.636 1c.133 0 .26.053.355.147l3.362 3.364a.5.5 0 01.147.353V14.5a.5.5 0 01-.5.5H3a.5.5 0 01-.5-.5v-13A.5.5 0 013 1h6.636zM8.42 9.2c-1.032.048-1.572.593-1.621 1.637.039.93.583 1.465 1.48 1.61l.554.753.902-.273-.613-.61.138-.057c.572-.274.752-.869.738-1.423-.026-1.036-.594-1.58-1.578-1.637zm-3.546-.4c-.786.043-1.211.56-1.274 1.125-.021.524.32 1.02.959 1.155.236.04.495.105.692.184.252.101.34.215.33.4-.02.267-.2.416-.534.431-.357.017-.582-.204-.645-.677l-.802.108c.168.76.467 1.259 1.43 1.274.88.013 1.335-.51 1.366-1.166-.01-.37-.114-.642-.471-.862a3.35 3.35 0 00-.818-.324c-.425-.11-.634-.263-.613-.447.02-.205.15-.393.455-.4.303-.007.476.093.644.415l.806-.214C6.264 9.145 5.703 8.78 4.875 8.8zm6.351.4H10.4v3.2h2.4v-.76h-1.574V9.2zm-2.834.705c.448 0 .821.254.842.934-.02.69-.37.901-.842.901-.452 0-.836-.231-.856-.9.03-.67.42-.935.856-.935zm1.014-7.752v2.94h2.94l-2.94-2.94z"
fill="#1890FF"
fillRule="nonzero"
></path>
</svg>
</div>
<div>SCQL脚本-1</div>
</div>,
true,
)
// Graph.registerReactComponent(
// 'custom',
// <div
// style={{
// display: 'flex',
// alignItems: 'center',
// border: '1px solid #1890ff',
// backgroundColor: 'rgba(227,244,255,.9)',
// boxShadow: '0 0 3px 3px rgb(64 169 255 / 20%)',
// borderRadius: '16px',
// }}
// >
// <div>
// <svg
// width="1em"
// height="1em"
// viewBox="0 0 16 16"
// xmlns="http://www.w3.org/2000/svg"
// >
// <path
// d="M9.636 1c.133 0 .26.053.355.147l3.362 3.364a.5.5 0 01.147.353V14.5a.5.5 0 01-.5.5H3a.5.5 0 01-.5-.5v-13A.5.5 0 013 1h6.636zM8.42 9.2c-1.032.048-1.572.593-1.621 1.637.039.93.583 1.465 1.48 1.61l.554.753.902-.273-.613-.61.138-.057c.572-.274.752-.869.738-1.423-.026-1.036-.594-1.58-1.578-1.637zm-3.546-.4c-.786.043-1.211.56-1.274 1.125-.021.524.32 1.02.959 1.155.236.04.495.105.692.184.252.101.34.215.33.4-.02.267-.2.416-.534.431-.357.017-.582-.204-.645-.677l-.802.108c.168.76.467 1.259 1.43 1.274.88.013 1.335-.51 1.366-1.166-.01-.37-.114-.642-.471-.862a3.35 3.35 0 00-.818-.324c-.425-.11-.634-.263-.613-.447.02-.205.15-.393.455-.4.303-.007.476.093.644.415l.806-.214C6.264 9.145 5.703 8.78 4.875 8.8zm6.351.4H10.4v3.2h2.4v-.76h-1.574V9.2zm-2.834.705c.448 0 .821.254.842.934-.02.69-.37.901-.842.901-.452 0-.836-.231-.856-.9.03-.67.42-.935.856-.935zm1.014-7.752v2.94h2.94l-2.94-2.94z"
// fill="#1890FF"
// fillRule="nonzero"
// ></path>
// </svg>
// </div>
// <div>SCQL脚本-1</div>
// </div>,
// true,
// )
export default class Example extends React.Component {
private container: HTMLDivElement
private graph: Graph
// export default class Example extends React.Component {
// private container: HTMLDivElement
// private graph: Graph
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 1600,
height: 1000,
grid: true,
async: false,
})
this.graph = graph
}
// componentDidMount() {
// const graph = new Graph({
// container: this.container,
// width: 1600,
// height: 1000,
// grid: true,
// async: false,
// })
// this.graph = graph
// }
addNodes = () => {
const nodes = []
for (let i = 0; i < 500; i++) {
nodes.push({
id: i + '',
x: Math.floor(Math.random() * 1600),
y: Math.floor(Math.random() * 1000),
shape: 'org-node',
attrs: {
'.card': { fill: Color.randomHex() },
'.image': {
xlinkHref:
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ',
},
'.rank': {
fill: '#31d0c6',
text: `${i}`,
},
'.name': {
fill: '#000',
text: `${i}`,
},
'.btn > circle': { stroke: '#000' },
'.btn > text': { fill: '#000', stroke: '#000' },
},
})
}
const start = performance.now()
this.graph.addNodes(nodes)
console.log('addNodes', performance.now() - start)
}
// addNodes = () => {
// const nodes = []
// for (let i = 0; i < 500; i++) {
// nodes.push({
// id: i + '',
// x: Math.floor(Math.random() * 1600),
// y: Math.floor(Math.random() * 1000),
// shape: 'org-node',
// attrs: {
// '.card': { fill: Color.randomHex() },
// '.image': {
// xlinkHref:
// 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ',
// },
// '.rank': {
// fill: '#31d0c6',
// text: `${i}`,
// },
// '.name': {
// fill: '#000',
// text: `${i}`,
// },
// '.btn > circle': { stroke: '#000' },
// '.btn > text': { fill: '#000', stroke: '#000' },
// },
// })
// }
// const start = performance.now()
// this.graph.addNodes(nodes)
// console.log('addNodes', performance.now() - start)
// }
addEdges = () => {
const edges = []
for (let i = 0; i < 500; i++) {
edges.push({
source: Math.floor(Math.random() * 500) + '',
target: Math.floor(Math.random() * 500) + '',
})
}
const start = performance.now()
this.graph.addEdges(edges)
console.log('addEdges', performance.now() - start)
}
// addEdges = () => {
// const edges = []
// for (let i = 0; i < 500; i++) {
// edges.push({
// source: Math.floor(Math.random() * 500) + '',
// target: Math.floor(Math.random() * 500) + '',
// })
// }
// const start = performance.now()
// this.graph.addEdges(edges)
// console.log('addEdges', performance.now() - start)
// }
addNodesAndEdges = () => {
this.addNodes()
this.addEdges()
}
// addNodesAndEdges = () => {
// this.addNodes()
// this.addEdges()
// }
addNodesWithPorts = () => {
const nodes = []
for (let i = 0; i < 500; i++) {
nodes.push({
id: i + '',
x: Math.floor(Math.random() * 1600),
y: Math.floor(Math.random() * 1000),
shape: 'org-node',
attrs: {
'.card': { fill: '#31d0c6' },
'.image': {
xlinkHref:
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ',
},
'.rank': {
fill: '#31d0c6',
text: '123',
},
'.name': {
fill: '#000',
text: 'abc',
},
'.btn > circle': { stroke: '#000' },
'.btn > text': { fill: '#000', stroke: '#000' },
},
ports: {
groups: {
top: {
position: 'top',
attrs: {
circle: {
r: 6,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
},
},
},
right: {
position: 'right',
attrs: {
circle: {
r: 6,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
},
},
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 6,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
},
},
},
left: {
position: 'left',
attrs: {
circle: {
r: 6,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
},
},
},
},
items: [
{
group: 'top',
id: i + `_port_top`,
},
{
group: 'right',
id: i + `_port_right`,
},
{
group: 'bottom',
id: i + `_port_bottom`,
},
{
group: 'left',
id: i + `_port_left`,
},
],
},
})
}
const start = performance.now()
this.graph.addNodes(nodes)
console.log('addNodesWithPorts', performance.now() - start)
}
// addNodesWithPorts = () => {
// const nodes = []
// for (let i = 0; i < 500; i++) {
// nodes.push({
// id: i + '',
// x: Math.floor(Math.random() * 1600),
// y: Math.floor(Math.random() * 1000),
// shape: 'org-node',
// attrs: {
// '.card': { fill: '#31d0c6' },
// '.image': {
// xlinkHref:
// 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ',
// },
// '.rank': {
// fill: '#31d0c6',
// text: '123',
// },
// '.name': {
// fill: '#000',
// text: 'abc',
// },
// '.btn > circle': { stroke: '#000' },
// '.btn > text': { fill: '#000', stroke: '#000' },
// },
// ports: {
// groups: {
// top: {
// position: 'top',
// attrs: {
// circle: {
// r: 6,
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff',
// },
// },
// },
// right: {
// position: 'right',
// attrs: {
// circle: {
// r: 6,
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff',
// },
// },
// },
// bottom: {
// position: 'bottom',
// attrs: {
// circle: {
// r: 6,
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff',
// },
// },
// },
// left: {
// position: 'left',
// attrs: {
// circle: {
// r: 6,
// magnet: true,
// stroke: '#31d0c6',
// strokeWidth: 2,
// fill: '#fff',
// },
// },
// },
// },
// items: [
// {
// group: 'top',
// id: i + `_port_top`,
// },
// {
// group: 'right',
// id: i + `_port_right`,
// },
// {
// group: 'bottom',
// id: i + `_port_bottom`,
// },
// {
// group: 'left',
// id: i + `_port_left`,
// },
// ],
// },
// })
// }
// const start = performance.now()
// this.graph.addNodes(nodes)
// console.log('addNodesWithPorts', performance.now() - start)
// }
addReactNodes = () => {
const nodes = []
for (let i = 0; i < 500; i++) {
nodes.push({
id: i + '',
x: Math.floor(Math.random() * 1600),
y: Math.floor(Math.random() * 1000),
shape: 'react-shape',
component: 'custom',
width: 160,
height: 30,
})
}
const start = performance.now()
this.graph.addNodes(nodes)
console.log('addReactNodes', performance.now() - start)
}
// addReactNodes = () => {
// const nodes = []
// for (let i = 0; i < 500; i++) {
// nodes.push({
// id: i + '',
// x: Math.floor(Math.random() * 1600),
// y: Math.floor(Math.random() * 1000),
// shape: 'react-shape',
// component: 'custom',
// width: 160,
// height: 30,
// })
// }
// const start = performance.now()
// this.graph.addNodes(nodes)
// console.log('addReactNodes', performance.now() - start)
// }
refContainer = (container: HTMLDivElement) => {
this.container = container
}
// refContainer = (container: HTMLDivElement) => {
// this.container = container
// }
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
<Button onClick={this.addNodes}>addNodes</Button>
<Button onClick={this.addEdges}>addEdges</Button>
<Button onClick={this.addNodesAndEdges}>addNodesAndEdges</Button>
<Button onClick={this.addNodesWithPorts}>addNodesWithPorts</Button>
<Button onClick={this.addReactNodes}>addReactNodes</Button>
</div>
)
}
}
// render() {
// return (
// <div className="x6-graph-wrap">
// <div ref={this.refContainer} className="x6-graph" />
// <Button onClick={this.addNodes}>addNodes</Button>
// <Button onClick={this.addEdges}>addEdges</Button>
// <Button onClick={this.addNodesAndEdges}>addNodesAndEdges</Button>
// <Button onClick={this.addNodesWithPorts}>addNodesWithPorts</Button>
// <Button onClick={this.addReactNodes}>addReactNodes</Button>
// </div>
// )
// }
// }

View File

@ -0,0 +1,77 @@
import React from 'react'
import { Graph, Node } from '@antv/x6-next'
import { ReactShape, register } from '@antv/x6-react-shape'
import '../index.less'
import './index.less'
class GroupNode extends ReactShape {
isGroup() {
return true
}
}
Graph.registerNode('group-node', GroupNode, true)
const NodeComponent = ({ node }: { node: Node }) => {
const data = node.getData()
return (
<div className="react-algo-node">
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span>{data.name}</span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-3',
width: 144,
height: 28,
effect: ['data'],
inherit: 'group-node',
})
export default class Example extends React.Component {
private container: HTMLDivElement
private count = 0
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
})
const node = graph.createNode({
shape: 'algo-node-3',
x: 80,
y: 80,
data: {
name: '逻辑回归',
},
})
console.log(node.isGroup())
const update = () => {
node.setData({ name: `逻辑回归 ${(this.count += 1)}` })
setTimeout(update, 1000)
}
update()
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -0,0 +1,27 @@
.react-algo-node {
width: 100%;
height: 100%;
border: 1px solid #5f95ff;
border-radius: 14px;
display: flex;
align-items: center;
img {
width: 24px;
height: 24px;
}
span {
margin-left: 4px;
font-size: 12px;
color: #000000a6;
}
&.dark {
background-color: #141414;
span {
color: #fff;
}
}
}

View File

@ -1,42 +1,33 @@
import React from 'react'
import { Graph, Node, Color } from '@antv/x6'
import '@antv/x6-react-shape'
import { Graph, Node } from '@antv/x6-next'
import { register } from '@antv/x6-react-shape'
import '../index.less'
import './index.less'
class MyComponent extends React.Component<{ node?: Node; text: string }> {
shouldComponentUpdate() {
const node = this.props.node
if (node) {
if (node.hasChanged('data')) {
return true
}
}
const NodeComponent = ({ node }: { node: Node }) => {
const data = node.getData()
return false
}
render() {
const color = Color.randomHex()
return (
<div
style={{
color: Color.invert(color, true),
width: '100%',
height: '100%',
textAlign: 'center',
lineHeight: '60px',
borderRadius: 30,
background: color,
}}
>
{this.props.text}
</div>
)
}
return (
<div className="react-algo-node">
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span>{data.name}</span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-1',
width: 144,
height: 28,
effect: ['data'],
})
export default class Example extends React.Component {
private container: HTMLDivElement
private count = 0
componentDidMount() {
const graph = new Graph({
@ -45,60 +36,21 @@ export default class Example extends React.Component {
height: 600,
})
const source = graph.addNode({
shape: 'react-shape',
primer: 'circle',
const node = graph.addNode({
shape: 'algo-node-1',
x: 80,
y: 80,
width: 60,
height: 60,
data: {},
xxx: {},
component: <MyComponent text="Source" />,
})
const target = graph.addNode({
shape: 'react-shape',
x: 320,
y: 320,
width: 120,
height: 48,
component: (node) => {
return (
<div style={{ lineHeight: '48px', textAlign: 'center' }}>
{node.attr('body/fill')}
</div>
)
data: {
name: '逻辑回归',
},
// component: () => <Test text="target" />,
})
graph.addNode({
shape: 'react-shape',
primer: 'circle',
x: 80,
y: 320,
width: 60,
height: 60,
useForeignObject: false,
component: () => {
return <circle stroke="red" cx="30" cy="30" r="30"/>
},
})
graph.addEdge({
source,
target,
})
const update = () => {
target.prop('attrs/body/fill', Color.randomHex())
node.setData({ name: `逻辑回归 ${(this.count += 1)}` })
setTimeout(update, 1000)
}
update()
console.log(graph.toJSON())
}
refContainer = (container: HTMLDivElement) => {

View File

@ -1,42 +1,41 @@
import React from 'react'
import { Graph, Node, Color } from '@antv/x6'
import { Portal } from '@antv/x6-react-shape'
import React, { useContext } from 'react'
import { Graph } from '@antv/x6-next'
import { register, Portal } from '@antv/x6-react-shape'
import { Button } from 'antd'
import '../index.less'
import './index.less'
class MyComponent extends React.Component<{ node?: Node; text: string }> {
shouldComponentUpdate() {
const node = this.props.node
if (node) {
if (node.hasChanged('data')) {
return true
}
}
const X6ReactPortalProvider = Portal.getProvider() // 注意,一个 graph 只能申明一个 portal provider
const ThemeContext = React.createContext('light')
return false
}
const NodeComponent = () => {
const theme = useContext(ThemeContext)
render() {
const color = Color.randomHex()
return (
<div
style={{
color: Color.invert(color, true),
width: '100%',
height: '100%',
textAlign: 'center',
lineHeight: '60px',
background: color,
}}
>
{this.props.text}
</div>
)
}
return (
<div className={`react-algo-node ${theme === 'light' ? 'light' : 'dark'}`}>
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span></span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-2',
width: 144,
height: 28,
effect: [],
})
export default class Example extends React.Component {
private container: HTMLDivElement
state = {
theme: 'light',
}
componentDidMount() {
const graph = new Graph({
container: this.container,
@ -44,42 +43,20 @@ export default class Example extends React.Component {
height: 600,
})
const source = graph.addNode({
shape: 'react-shape',
graph.addNode({
shape: 'algo-node-2',
x: 80,
y: 80,
width: 160,
height: 60,
data: {},
xxx: {},
component: <MyComponent text="Source" />,
})
const target = graph.addNode({
shape: 'react-shape',
x: 320,
y: 320,
width: 160,
height: 60,
component: (node) => {
return <div>{node.attr('body/fill')}</div>
data: {
name: '逻辑回归',
},
// component: () => <Test text="target" />,
})
}
graph.addEdge({
source,
target,
changeTheme = () => {
this.setState({
theme: this.state.theme === 'light' ? 'dark' : 'light',
})
const update = () => {
target.prop('attrs/body/fill', Color.randomHex())
setTimeout(update, 1000)
}
update()
console.log(graph.toJSON())
}
refContainer = (container: HTMLDivElement) => {
@ -87,10 +64,16 @@ export default class Example extends React.Component {
}
render() {
const X6ReactPortalProvider = Portal.getProvider()
return (
<div className="x6-graph-wrap">
<X6ReactPortalProvider />
<ThemeContext.Provider value={this.state.theme}>
<X6ReactPortalProvider />
</ThemeContext.Provider>
<div className="x6-graph-tools">
<Button onClick={this.changeTheme}>
{this.state.theme === 'light' ? 'Light' : 'Dark'}
</Button>
</div>
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -191,6 +191,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -0,0 +1,71 @@
import React from 'react'
import { Graph } from '@antv/x6-next'
import { Scroller } from '@antv/x6-plugin-scroller'
import '../index.less'
import './index.less'
export default class Example extends React.Component {
private graph: Graph
private graphContainer: HTMLDivElement
componentDidMount() {
const graph = new Graph({
container: this.graphContainer,
width: 800,
height: 500,
background: {
color: '#f5f5f5',
},
grid: {
visible: true,
},
mousewheel: {
enabled: true,
// fixed: false,
modifiers: ['ctrl', 'meta'],
minScale: 0.5,
maxScale: 2,
},
})
graph.use(
new Scroller({
enabled: true,
// width: 600,
// height: 400,
pageVisible: true,
pageBreak: true,
pannable: {
enabled: true,
eventTypes: ['leftMouseDown', 'rightMouseDown'],
},
}),
)
graph.addNode({
shape: 'rect',
x: 300,
y: 300,
width: 90,
height: 60,
attrs: {
rect: { fill: '#31D0C6', stroke: '#4B4A67', 'stroke-width': 2 },
text: { text: 'rect', fill: 'white' },
},
ports: [{}],
})
}
refContainer = (container: HTMLDivElement) => {
this.graphContainer = container
}
render() {
return (
<div className="x6-graph-wrap">
<h1>Scroller</h1>
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -27,7 +27,7 @@ export default class Example extends React.Component {
},
},
})
const target = graph.addNode({
shape: 'rect',
x: 320,
@ -41,7 +41,7 @@ export default class Example extends React.Component {
},
},
})
graph.addEdge({
source,
target,
@ -51,33 +51,32 @@ export default class Example extends React.Component {
},
},
})
graph.on('selection:changed', (args: {
added: Cell[],
removed: Cell[],
selected: Cell[],
}) => {
args.added.forEach((cell: Cell) => {
if (cell.isNode()) {
cell.attr('body', {
fill: '#ffd591',
stroke: '#ffa940',
})
} else {
cell.attr('line/stroke', '#ffa940')
}
})
args.removed.forEach((cell: Cell) => {
if (cell.isNode()) {
cell.attr('body', {
fill: '#f5f5f5',
stroke: '#d9d9d9',
})
} else {
cell.attr('line/stroke', '#d9d9d9')
}
})
})
graph.on(
'selection:changed',
(args: { added: Cell[]; removed: Cell[]; selected: Cell[] }) => {
args.added.forEach((cell: Cell) => {
if (cell.isNode()) {
cell.attr('body', {
fill: '#ffd591',
stroke: '#ffa940',
})
} else {
cell.attr('line/stroke', '#ffa940')
}
})
args.removed.forEach((cell: Cell) => {
if (cell.isNode()) {
cell.attr('body', {
fill: '#f5f5f5',
stroke: '#d9d9d9',
})
} else {
cell.attr('line/stroke', '#d9d9d9')
}
})
},
)
}
refContainer = (container: HTMLDivElement) => {

View File

@ -86,8 +86,7 @@ export default class Example extends React.Component {
width: 40,
height: 40,
label: 'path',
d:
'M25.979,12.896 19.312,12.896 19.312,6.229 12.647,6.229 12.647,12.896 5.979,12.896 5.979,19.562 12.647,19.562 12.647,26.229 19.312,26.229 19.312,19.562 25.979,19.562z',
d: 'M25.979,12.896 19.312,12.896 19.312,6.229 12.647,6.229 12.647,12.896 5.979,12.896 5.979,19.562 12.647,19.562 12.647,26.229 19.312,26.229 19.312,19.562 25.979,19.562z',
})
console.log(path)

View File

@ -1,139 +0,0 @@
import React from 'react'
import { Graph } from '@antv/x6'
import { Graph as GraphES } from '@antv/x6/lib'
import '../index.less'
export default class Example extends React.Component {
private container: HTMLDivElement
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
grid: {
visible: true,
type: 'doubleMesh',
args: [
{
color: '#eee', // 主网格线颜色
thickness: 1, // 主网格线宽度
},
{
color: '#ddd', // 次网格线颜色
thickness: 1, // 次网格线宽度
factor: 4, // 主次网格线间隔
},
],
},
// background: {
// color: '#fcfcfc',
// image:
// 'https://gw.alipayobjects.com/os/s/prod/antv/assets/image/logo-with-text-73b8a.svg',
// opacity: 0.2,
// repeat: 'watermark',
// angle: 30,
// },
panning: true,
})
console.log(graph)
console.log(Object.prototype.toString.call(graph))
console.log(GraphES.isGraph(graph))
// const data = [
// {
// id: 'node1',
// shape: 'rect',
// x: 100,
// y: 100,
// width: 80,
// height: 40,
// label: 'hello',
// },
// {
// id: 'node2',
// shape: 'rect',
// x: 240,
// y: 300,
// width: 80,
// height: 40,
// label: 'world',
// },
// {
// shape: 'edge',
// source: 'node1',
// target: 'node2',
// },
// ]
const data = {
// 节点
nodes: [
{
id: 'node1',
shape: 'rect',
x: 120,
y: 100,
width: 80,
height: 40,
label: 'Hello',
attrs: {
body: {
strokeWidth: 1,
},
},
},
{
id: 'node2',
x: 120,
y: 240,
width: 80,
height: 40,
label: 'World',
attrs: {
body: {
strokeWidth: 1,
},
},
},
],
// 边
edges: [
{
source: 'node1',
target: 'node2',
attrs: {
line: {
sourceMarker: 'classic',
targetMarker: 'classic',
strokeWidth: 2,
},
},
},
],
}
graph.fromJSON(data)
// console.log(graph.toJSON())
// graph.scaleContentToFit()
const node = graph.getCellById('node2')
node.transition('attrs/body/strokeWidth', 10, {
duration: 3000,
complete() {},
})
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -1,15 +1,6 @@
import React from 'react'
import { Graph, Markup, ObjectExt, Dom } from '@antv/x6'
import '../index.less'
`
<foreignObject width="160" height="60">
<body style="width: 100%; height: 100%; background: transparent;">
<div style="width: 100%; height: 100%;">
<div>#C969F1</div>
</div>
</body>
</foreignObject>
`
Graph.registerNode('xml-node', {}, true)

View File

@ -135,6 +135,7 @@ export class Component extends React.Component<Component.Props> {
}
}
// eslint-disable-next-line
export namespace Component {
export interface Props {
node?: Node

View File

@ -6,7 +6,7 @@ import { generateData, parsePorts } from './data'
import { getPortsDefinition } from './port'
import { Component } from './component'
import './view'
import '../../index.less'
import '../index.less'
export default class Example extends React.Component {
private container: HTMLDivElement

View File

@ -31,7 +31,7 @@ class ContextMenuTool extends ToolsView.ToolItem<
trigger={['contextMenu']}
overlay={this.options.menu}
>
<a />
<a href="#" />
</Dropdown>,
this.knob,
)

View File

@ -17,18 +17,20 @@ class TooltipTool extends ToolsView.ToolItem<EdgeView, TooltipToolOptions> {
}
private toggleTooltip(visible: boolean) {
ReactDom.unmountComponentAtNode(this.knob)
if (visible) {
ReactDom.render(
<Tooltip
title={this.options.tooltip}
visible={true}
destroyTooltipOnHide
>
<div />
</Tooltip>,
this.knob,
)
if (this.knob) {
ReactDom.unmountComponentAtNode(this.knob)
if (visible) {
ReactDom.render(
<Tooltip
title={this.options.tooltip}
visible={true}
destroyTooltipOnHide
>
<div />
</Tooltip>,
this.knob,
)
}
}
}
@ -69,6 +71,7 @@ class TooltipTool extends ToolsView.ToolItem<EdgeView, TooltipToolOptions> {
}
protected onRemove() {
this.toggleTooltip(false)
this.cellView.off('cell:mouseenter', this.onMosueEnter, this)
this.cellView.off('cell:mouseleave', this.onMouseLeave, this)
this.cellView.off('cell:mousemove', this.onMouseMove, this)

View File

@ -56,7 +56,7 @@ export class Universe extends Model {
for (var i = 0, n = subgraph.length; i < n; i++) {
var cell = subgraph[i]
if (cell.isEdge()) {
(cell as Connection).highlight()
;(cell as Connection).highlight()
}
}
}
@ -67,7 +67,7 @@ export class Universe extends Model {
for (var i = 0, n = subgraph.length; i < n; i++) {
var cell = subgraph[i]
if (cell.isEdge()) {
(cell as Connection).unhighlight()
;(cell as Connection).unhighlight()
}
}
}

View File

@ -97,6 +97,7 @@ export default class Example extends React.Component<
}
}
// eslint-disable-next-line
export namespace Example {
export interface Props {}

View File

@ -0,0 +1,84 @@
import React, { createRef, PureComponent } from 'react'
import './index.less'
const SPEED = 0.003 / Math.PI
const FRAMES = 10
export default class Clock extends PureComponent {
faceRef = createRef<SVGCircleElement>()
arcGroupRef = createRef<SVGGElement>()
clockHandRef = createRef<SVGPathElement>()
frame: number = 0
rotation = 0
t0 = Date.now()
arcs: { rotation: number; td: number }[] = []
animate = () => {
const now = Date.now()
const td = now - this.t0
this.rotation = (this.rotation + SPEED * td) % (2 * Math.PI)
this.t0 = now
this.arcs.push({ rotation: this.rotation, td })
let lx = 0
let ly = 0
let tx = 0
let ty = 0
if (this.arcs.length > FRAMES) {
this.arcs.forEach(({ rotation, td }, i) => {
lx = tx
ly = ty
const r = 145
tx = 155 + r * Math.cos(rotation)
ty = 155 + r * Math.sin(rotation)
const bigArc = SPEED * td < Math.PI ? '0' : '1'
const path = `M${tx} ${ty}A${r} ${r} 0 ${bigArc} 0 ${lx} ${ly}L155 155`
const hue = 120 - Math.min(120, td / 4)
const colour = `hsl(${hue}, 100%, ${60 - i * (30 / FRAMES)}%)`
if (i !== 0) {
const arcEl = this.arcGroupRef.current!.children[i - 1]
arcEl.setAttribute('d', path)
arcEl.setAttribute('fill', colour)
}
})
this.clockHandRef.current!.setAttribute('d', `M155 155L${tx} ${ty}`)
this.arcs.shift()
}
this.frame = requestAnimationFrame(this.animate)
}
componentDidMount() {
this.frame = requestAnimationFrame(this.animate)
}
componentWillUnmount() {
if (this.frame) {
cancelAnimationFrame(this.frame)
}
}
render() {
const paths = new Array(FRAMES)
for (let i = 0; i < FRAMES; i++) {
paths.push(<path className="arcHand" key={i} />)
}
return (
<div className="stutterer">
<svg height="310" width="310">
<circle
className="clockFace"
cx={155}
cy={155}
r={150}
ref={this.faceRef}
fill="hsla(0, 0%, 5%, 0.95)"
/>
<g ref={this.arcGroupRef}>{paths}</g>
<path className="clockHand" ref={this.clockHandRef} />
</svg>
</div>
)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,153 @@
import React from 'react'
import { Graph, Path } from '@antv/x6'
import data from './data'
Graph.registerConnector(
'algo-connector',
(s, e) => {
const offset = 4
const deltaY = Math.abs(e.y - s.y)
const control = Math.floor((deltaY / 3) * 2)
const v1 = { x: s.x, y: s.y + offset + control }
const v2 = { x: e.x, y: e.y - offset - control }
return Path.normalize(
`M ${s.x} ${s.y}
L ${s.x} ${s.y + offset}
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
L ${e.x} ${e.y}
`,
)
},
true,
)
Graph.registerNode(
'perf-node',
{
width: 144,
height: 28,
markup: [
{
tagName: 'rect',
},
{
tagName: 'image',
},
{
tagName: 'text',
},
],
attrs: {
rect: {
rx: 14,
ry: 14,
refWidth: '100%',
refHeight: '100%',
fill: '#FFF',
stroke: '#5f95ff',
strokeWidth: 1,
},
image: {
x: 2,
y: 2,
width: 24,
height: 24,
xlinkHref:
'https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg',
},
// text: {
// textWrap: {
// text: 'abcdefghijklmnopqrstnvwxyzhadfsadfsda23333333333dasdasda',
// width: 30, // 宽度减少 10px
// height: 60,
// ellipsis: true, // 文本超出显示范围时,自动添加省略号
// breakWord: false
// }
// }
text: {
x: 28,
y: 18,
text: '深度学习',
fontSize: 12,
fill: '#000000a6',
},
},
},
true,
)
interface Props {
enableTextWrap: boolean
length: number
}
export default class Canvas extends React.Component<Props> {
private container: HTMLDivElement
private graph: Graph
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
grid: false,
connecting: {
connector: 'algo-connector',
connectionPoint: 'anchor',
anchor: 'center',
},
mousewheel: true,
panning: true,
})
this.graph = graph
}
componentDidUpdate(prevProps: Props) {
if (prevProps.length !== this.props.length) {
this.draw(this.props.length)
}
}
draw(length: number) {
const cells: any[] = []
if (this.props.enableTextWrap) {
data.nodes.forEach((node: any) => {
node.attrs = {
text: {
x: 28,
y: 18,
fontSize: 12,
fill: '#000000a6',
textWrap: {
text: '深度学习',
width: 40,
height: 20,
ellipsis: true,
},
},
}
})
}
if (length > 10) {
cells.push(...data.nodes)
cells.push(...data.edges.slice(0, 100 * (length - 10)))
} else {
cells.push(...data.nodes.slice(0, 100 * length))
}
this.graph.fromJSON(cells)
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -0,0 +1,161 @@
import React from 'react'
import { Graph } from '@antv/x6-next'
import { Path } from '@antv/x6-geometry'
import data from './data'
Graph.registerConnector(
'algo-connector',
(s, e) => {
const offset = 4
const deltaY = Math.abs(e.y - s.y)
const control = Math.floor((deltaY / 3) * 2)
const v1 = { x: s.x, y: s.y + offset + control }
const v2 = { x: e.x, y: e.y - offset - control }
return Path.normalize(
`M ${s.x} ${s.y}
L ${s.x} ${s.y + offset}
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
L ${e.x} ${e.y}
`,
)
},
true,
)
Graph.registerNode(
'perf-node',
{
width: 144,
height: 28,
markup: [
{
tagName: 'rect',
},
{
tagName: 'image',
},
{
tagName: 'text',
},
],
attrs: {
rect: {
rx: 14,
ry: 14,
refWidth: '100%',
refHeight: '100%',
fill: '#FFF',
stroke: '#5f95ff',
strokeWidth: 1,
},
image: {
x: 2,
y: 2,
width: 24,
height: 24,
xlinkHref:
'https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg',
},
// text: {
// textWrap: {
// text: 'abcdefghijklmnopqrstnvwxyzhadfsadfsda23333333333dasdasda',
// width: 30, // 宽度减少 10px
// height: 60,
// ellipsis: true, // 文本超出显示范围时,自动添加省略号
// breakWord: false
// }
// }
text: {
x: 28,
y: 18,
text: '深度学习',
fontSize: 12,
fill: '#000000a6',
},
},
},
true,
)
interface Props {
enableTextWrap: boolean
enableVirtualRender: boolean
length: number
}
export default class Canvas extends React.Component<Props> {
private container: HTMLDivElement
private graph: Graph
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
grid: false,
connecting: {
connector: 'algo-connector',
connectionPoint: 'anchor',
anchor: 'center',
},
mousewheel: true,
panning: true,
})
this.graph = graph
}
componentDidUpdate(prevProps: Props) {
if (this.props.enableVirtualRender) {
this.graph.enableVirtualRender()
} else {
this.graph.disableVirtualRender()
}
if (prevProps.length !== this.props.length) {
this.draw(this.props.length)
}
}
draw(length: number) {
const cells: any[] = []
if (this.props.enableTextWrap) {
data.nodes.forEach((node: any) => {
node.attrs = {
text: {
x: 28,
y: 18,
fontSize: 12,
fill: '#000000a6',
textWrap: {
text: '深度学习',
width: 40,
height: 20,
ellipsis: true,
},
},
}
})
}
if (length > 10) {
cells.push(...data.nodes)
cells.push(...data.edges.slice(0, 100 * (length - 10)))
} else {
cells.push(...data.nodes.slice(0, 100 * length))
}
this.graph.fromJSON(cells)
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -0,0 +1,61 @@
.tools {
width: 800px;
margin: 32px auto;
.ant-input {
margin-bottom: 16px;
}
}
.react-node {
width: 100%;
height: 100%;
border: 1px solid #5f95ff;
border-radius: 14px;
display: flex;
align-items: center;
img {
width: 24px;
height: 24px;
}
span {
margin-left: 4px;
font-size: 12px;
color: #000000a6;
}
}
.stutterer {
transform: scale(1.5);
height: 310px;
width: 310px;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.2);
border-radius: 200px;
}
.clockHand {
stroke: white;
stroke-width: 10px;
stroke-linecap: round;
}
.clockFace {
stroke: white;
stroke-width: 10px;
}
.innerLine {
border-radius: 6px;
position: absolute;
height: 149px;
left: 47.5%;
top: 0%;
width: 5%;
background-color: red;
transform-origin: bottom center;
}

View File

@ -0,0 +1,58 @@
import React, { useState } from 'react'
import GraphV1 from './graph-v1'
import GraphV2 from './graph-v2'
import Clock from './clock'
import { Input, Radio, Checkbox } from 'antd'
import './index.less'
export default () => {
const [value, setValue] = useState('')
const [version, setVersion] = useState('v1')
const [enableTextWrap, setEnableTextWrap] = useState(false)
const [enableVirtualRender, setEnableVirtualRender] = useState(false)
const onChangeVersion = (val: string) => {
setValue('')
setVersion(val)
}
return (
<div>
<div className={'tools'}>
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
maxLength={20}
/>
<p>
{value.length > 10
? `1000 节点 ${(value.length - 10) * 100}`
: `${value.length * 100} 节点`}
</p>
<Radio.Group
onChange={(e) => onChangeVersion(e.target.value)}
value={version}
>
<Radio value={'v1'}>V1</Radio>
<Radio value={'v2'}>V2</Radio>
</Radio.Group>
<Checkbox onChange={(e) => setEnableTextWrap(e.target.checked)}>
</Checkbox>
<Checkbox onChange={(e) => setEnableVirtualRender(e.target.checked)}>
</Checkbox>
</div>
{version === 'v1' ? (
<GraphV1 enableTextWrap={enableTextWrap} length={value.length} />
) : (
<GraphV2
enableTextWrap={enableTextWrap}
enableVirtualRender={enableVirtualRender}
length={value.length}
/>
)}
<Clock />
</div>
)
}

View File

@ -0,0 +1,166 @@
// import React from 'react'
// import { Graph } from '@antv/x6-next'
// import { Path } from '@antv/x6-geometry'
// import data from './data'
// import './index.less'
// import { register } from '@antv/x6-react-shape'
// Graph.registerConnector(
// 'algo-connector',
// (s, e) => {
// const offset = 4
// const deltaY = Math.abs(e.y - s.y)
// const control = Math.floor((deltaY / 3) * 2)
// const v1 = { x: s.x, y: s.y + offset + control }
// const v2 = { x: e.x, y: e.y - offset - control }
// return Path.normalize(
// `M ${s.x} ${s.y}
// L ${s.x} ${s.y + offset}
// C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
// L ${e.x} ${e.y}
// `,
// )
// },
// true,
// )
// const NodeComponent = () => {
// return (
// <div className="react-node">
// <img
// src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
// alt=""
// />
// <span>深度学习</span>
// </div>
// )
// }
// register(NodeComponent, {
// shape: 'perf-node',
// width: 144,
// height: 28,
// effect: ['width'],
// })
// export default class Canvas extends React.Component {
// private container: HTMLDivElement
// private graph: Graph
// componentDidMount() {
// const graph = new Graph({
// container: this.container,
// width: 800,
// height: 600,
// grid: false,
// connecting: {
// connector: 'algo-connector',
// connectionPoint: 'anchor',
// anchor: 'center',
// },
// })
// this.graph = graph
// document.getElementById('add-btn')?.addEventListener('click', () => {
// this.add()
// })
// }
// add = () => {
// data.nodes.forEach((node: any, i) => {
// node.ports = {
// groups: {
// top: {
// position: 'top',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: 'gray',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// right: {
// position: 'right',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: 'gray',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// bottom: {
// position: 'bottom',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: 'gray',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// left: {
// position: 'left',
// attrs: {
// circle: {
// r: 4,
// magnet: true,
// stroke: 'gray',
// strokeWidth: 1,
// fill: '#fff',
// },
// },
// },
// },
// items: [
// {
// group: 'top',
// id: i + `_port_top`,
// },
// {
// group: 'right',
// id: i + `_port_right`,
// },
// {
// group: 'bottom',
// id: i + `_port_bottom`,
// },
// {
// group: 'left',
// id: i + `_port_left`,
// },
// ],
// }
// })
// data.edges.forEach((edge: any) => {
// edge.attrs = {
// line: {
// stroke: '#c5c5c5',
// strokeWidth: 1,
// },
// }
// })
// this.graph.fromJSON(data)
// }
// refContainer = (container: HTMLDivElement) => {
// this.container = container
// }
// render() {
// return (
// <div className="x6-graph-wrap">
// <div ref={this.refContainer} className="x6-graph" />
// <button id="add-btn">add</button>
// </div>
// )
// }
// }

View File

@ -1,33 +0,0 @@
import React from 'react'
import { SVG } from '@antv/x6-vector'
import '../index.less'
export default class Example extends React.Component {
private container: HTMLDivElement
componentDidMount() {
const svg = new SVG()
const rect = svg.rect(100, 100).node
svg.appendTo(this.container)
rect.animate(
[{ fill: '#000000' }, { fill: '#0000FF' }, { fill: '#00FFFF' }],
{
duration: 3000,
iterations: Infinity,
},
)
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<h1>Default Settings</h1>
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -1,3 +0,0 @@
import { version } from '@antv/x6-vector'
console.log(version)

View File

@ -17,9 +17,7 @@
"strictPropertyInitialization": false,
"allowSyntheticDefaultImports": true,
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
}
}
}

View File

@ -1,5 +1,5 @@
{
"version": "independent",
"version": "2.0.6-beta.0",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
@ -24,5 +24,12 @@
"pr(refactor)": ":100: Refactoring",
"pr(test)": ":white_check_mark: Test Case"
}
}
},
"packages": [
"packages/x6-common",
"packages/x6-geometry",
"packages/x6-next",
"packages/x6-react-shape",
"packages/x6-vue-shape"
]
}

Some files were not shown because too many files have changed in this diff Show More