Compare commits
23 Commits
@antv/x6@2
...
@antv/x6@2
Author | SHA1 | Date | |
---|---|---|---|
7161d1432d | |||
423ddeda73 | |||
2efa843e07 | |||
5d4c5991cc | |||
2083c74bd5 | |||
44a5cfdbc3 | |||
cbae927138 | |||
adc06ada96 | |||
96ed42b5eb | |||
4b1a0f8b31 | |||
ac71e239cf | |||
f4afde62d1 | |||
a277a8995d | |||
e93021bfb7 | |||
c1dedfa515 | |||
baabd328b6 | |||
37515c45c8 | |||
efc45f6f01 | |||
be8f734aa6 | |||
68e3ef1535 | |||
6cb7a60e5d | |||
943c06b272 | |||
8b1f661585 |
19
.github/workflows/backup/auto-assign.yml
vendored
19
.github/workflows/backup/auto-assign.yml
vendored
@ -1,19 +0,0 @@
|
||||
name: 🧑 Auto Assign
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: wow-actions/auto-assign@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
||||
CONFIG_FILE: .github/workflows/config/auto-assign.yml
|
@ -1,48 +0,0 @@
|
||||
name: 🚫 Delete Stale Releases
|
||||
# on:
|
||||
# repository_dispatch:
|
||||
# types: [released]
|
||||
# jobs:
|
||||
# clean:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: wow-actions/use-app-token@v2
|
||||
# with:
|
||||
# app_id: ${{ secrets.APP_ID }}
|
||||
# private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
#
|
||||
# - uses: wow-actions/delete-stale-releases@v1
|
||||
# with:
|
||||
# GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
||||
# delete_tags: true
|
||||
# keep_latest_count: 3
|
||||
# group: '(?!^)@.*$'
|
||||
# exclude: |
|
||||
# @antv/x6@**
|
||||
# @antv/x6-common@**
|
||||
# @antv/x6-geometry@**
|
||||
# @antv/x6-plugin-**@**
|
||||
# @antv/x6-vue-shape@**
|
||||
# @antv/x6-react-shape@**
|
||||
# @antv/x6-angular-shape@**
|
||||
# @antv/x6-react-components@**
|
||||
|
||||
# delete all releases and tag
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
clean:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: wow-actions/delete-stale-releases@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
||||
delete_tags: true
|
||||
keep_latest_count: -1
|
21
.github/workflows/backup/gitleaks.yml
vendored
21
.github/workflows/backup/gitleaks.yml
vendored
@ -1,21 +0,0 @@
|
||||
name: 🥤 GitLeaks
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- alpha
|
||||
- beta
|
||||
jobs:
|
||||
gitleaks:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: '1'
|
||||
- name: wget
|
||||
uses: wei/wget@v1
|
||||
with:
|
||||
args: -O .gitleaks.toml https://raw.githubusercontent.com/ycjcl868/gitleaks/master/.gitleaks.toml
|
||||
- name: gitleaks-action
|
||||
uses: zricethezav/gitleaks-action@master
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -10,16 +10,12 @@ on:
|
||||
- beta
|
||||
jobs:
|
||||
ci:
|
||||
strategy:
|
||||
matrix:
|
||||
codecov: [x6, x6-common, x6-geometry]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
steps:
|
||||
- name: ⤵️ Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 🎉 Setup nodejs
|
||||
uses: actions/setup-node@v3
|
||||
@ -63,11 +59,11 @@ jobs:
|
||||
|
||||
|
||||
- name: 💡 Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: ./packages/${{ matrix.codecov }}/test/coverage/lcov.info
|
||||
flags: ${{ matrix.codecov }}
|
||||
files: ./packages/x6/test/coverage/lcov.info
|
||||
flags: x6
|
||||
|
||||
- name: 🔀 Dispatch(ci_passed)
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
|
42
.github/workflows/codeql.yml
vendored
42
.github/workflows/codeql.yml
vendored
@ -1,42 +0,0 @@
|
||||
name: ⛵️ CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "bot", "gh-pages", "v1" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: "41 2 * * 1"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ javascript ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/workflows/config/codeql.yml
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
7
.github/workflows/config/auto-assign.yml
vendored
7
.github/workflows/config/auto-assign.yml
vendored
@ -1,7 +0,0 @@
|
||||
assignees:
|
||||
- NewByVector
|
||||
reviewers:
|
||||
- bubkoo
|
||||
- NewByVector
|
||||
skipKeywords:
|
||||
- wip
|
7
.github/workflows/config/codeql.yml
vendored
7
.github/workflows/config/codeql.yml
vendored
@ -1,7 +0,0 @@
|
||||
paths-ignore:
|
||||
- sites/public
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: js/use-before-declaration
|
||||
- exclude:
|
||||
id: js/polynomial-redos
|
16
.github/workflows/create-issue-branch.yml
vendored
16
.github/workflows/create-issue-branch.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: 🚧 Create Issue Branch
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
jobs:
|
||||
cib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: robvanderleek/create-issue-branch@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
78
.github/workflows/deploy-sites.yml
vendored
78
.github/workflows/deploy-sites.yml
vendored
@ -1,78 +0,0 @@
|
||||
name: 🚀 Deploy Sites
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [released]
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: ⤵️ Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: 🎉 Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: 🌱 Get Yarn Cache Directory
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: 🚸 Setup Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
## cache webpack(babel-loader, eslint-loader)
|
||||
- name: 💩 Setup Webpack Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
sites/x6-sites-demos/packages/**/node_modules
|
||||
key: ${{ runner.os }}-webpack-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-webpack-
|
||||
|
||||
## cache sites
|
||||
- name: 💩 Setup Sites Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: sites/x6-sites/static/demos
|
||||
key: ${{ runner.os }}-sites-${{ hashFiles('./packages/x6/package.json', './sites/x6-sites-demos/**/src') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-sites-
|
||||
|
||||
- name: 🚧 Prepare
|
||||
run: yarn global add lerna
|
||||
|
||||
- name: 🚀 Bootstrap
|
||||
run: yarn bootstrap
|
||||
|
||||
- name: 🧲 Build Apps
|
||||
run: yarn build:apps
|
||||
|
||||
- name: 📦 Build Demos
|
||||
run: yarn build:demos
|
||||
|
||||
- name: ✨ Build Sites
|
||||
run: yarn build:sites
|
||||
|
||||
- name: 🔑 Generate Token
|
||||
uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
|
||||
- name: ✅ Deploy sites
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ env.BOT_TOKEN }}
|
||||
publish_dir: ./sites/x6-sites/public
|
||||
publish_branch: gh-pages
|
2
.github/workflows/pr-label-status.yml
vendored
2
.github/workflows/pr-label-status.yml
vendored
@ -17,4 +17,4 @@ jobs:
|
||||
- uses: wow-actions/pr-triage@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
||||
WORKFLOW-ID: ${{ github.event.workflow_run.id }}
|
||||
WORKFLOW_ID: ${{ github.event.workflow_run.id }}
|
||||
|
85
.github/workflows/preview.yml
vendored
85
.github/workflows/preview.yml
vendored
@ -1,85 +0,0 @@
|
||||
name: 🔂 Surge PR Preview
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- sites/x6-sites/**
|
||||
- sites/x6-sites-demos/**
|
||||
- sites/x6-sites-demos-helper/**
|
||||
- examples/x6-app-**
|
||||
jobs:
|
||||
surge:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: 🌱 Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: 🚸 Setup yarn cacha
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
## cache webpack(babel-loader, eslint-loader)
|
||||
- name: 💩 Setup webpack cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
sites/x6-sites-demos/packages/**/node_modules
|
||||
key: ${{ runner.os }}-webpack-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-webpack-
|
||||
|
||||
## cache sites
|
||||
- name: 💩 Setup sites cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: sites/x6-sites/static/demos
|
||||
key: ${{ runner.os }}-sites-${{ hashFiles('./packages/x6/package.json', './sites/x6-sites-demos/**/src') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-sites-
|
||||
|
||||
- name: 🎉 Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: 🚧 Prepare Environment
|
||||
run: |
|
||||
yarn global add lerna
|
||||
|
||||
- name: 🚀 Bootstrap
|
||||
run: yarn bootstrap
|
||||
|
||||
- name: 📦 Build Demos
|
||||
run: yarn build:demos
|
||||
|
||||
- name: 🧲 Build Apps
|
||||
run: yarn build:apps
|
||||
|
||||
- name: ✨ Build Sites
|
||||
run: yarn build:sites
|
||||
|
||||
- name: 🔑 Generate Token
|
||||
uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
|
||||
- name: ✅ Deploy Sites
|
||||
uses: afc163/surge-preview@v1
|
||||
with:
|
||||
surge_token: ${{ secrets.SURGE_TOKEN }}
|
||||
github_token: ${{ env.BOT_TOKEN }}
|
||||
build: |
|
||||
echo Create sites preview
|
||||
dist: sites/x6-sites/public
|
16
.github/workflows/report-monthly.yml
vendored
16
.github/workflows/report-monthly.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: 📆 Monthly Report
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 1 * *'
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: wow-actions/activity-report@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
16
.github/workflows/report-weekly.yml
vendored
16
.github/workflows/report-weekly.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: 📆 Weekly Report
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 17 * * 5'
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: wow-actions/activity-report@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
58
.github/workflows/stale.yml
vendored
58
.github/workflows/stale.yml
vendored
@ -1,58 +0,0 @@
|
||||
name: 👻 Stale
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ env.BOT_TOKEN }}
|
||||
stale-issue-message: |
|
||||
Hiya!
|
||||
|
||||
This issue has gone quiet. Spooky quiet. 👻
|
||||
|
||||
We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this issue open!
|
||||
|
||||
As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out [contribute](https://github.com/antvis/X6/blob/master/CONTRIBUTING.md) for more information about opening PRs, triaging issues, and contributing!
|
||||
|
||||
Thanks for being a part of the AntV community! 💪💯
|
||||
|
||||
close-issue-message: |
|
||||
Hey again!
|
||||
|
||||
It’s been 60 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it. Please keep in mind that I’m only a robot 🤖, so if I’ve closed this issue in error, I’m `HUMAN_EMOTION_SORRY`. Please feel free to comment on this issue or create a new one if you need anything else.
|
||||
|
||||
As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out [contribute](https://github.com/antvis/X6/blob/master/CONTRIBUTING.md) for more information about opening PRs, triaging issues, and contributing!
|
||||
|
||||
Thanks again for being part of the AntV community! 💪💯
|
||||
|
||||
stale-pr-message: |
|
||||
Hiya!
|
||||
|
||||
This PR has gone quiet. Spooky quiet. 👻
|
||||
|
||||
We get a lot of PRs, so we currently close PRs after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this PR or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this PR open!
|
||||
|
||||
Thanks for being a part of the AntV community! 💪💯
|
||||
|
||||
close-pr-message: |
|
||||
Hey again!
|
||||
|
||||
It’s been 60 days since anything happened on this PR, so our friendly neighborhood robot (that’s me!) is going to close it. Please keep in mind that I’m only a robot 🤖, so if I’ve closed this PR in error, I’m `HUMAN_EMOTION_SORRY`. Please feel free to comment on this PR or create a new one if you need anything else.
|
||||
|
||||
Thanks again for being part of the AntV community! 💪💯
|
||||
|
||||
days-before-stale: 20
|
||||
days-before-close: 40
|
||||
stale-issue-label: 'stale'
|
||||
exempt-issue-label: 'not-stale,awaiting-approval,work-in-progress'
|
||||
stale-pr-label: 'stale'
|
||||
exempt-pr-label: 'not-stale,awaiting-approval,work-in-progress'
|
21
.github/workflows/sync-labels.yml
vendored
21
.github/workflows/sync-labels.yml
vendored
@ -1,21 +0,0 @@
|
||||
name: 🔄 Sync Labels
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/config/labels.yml
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/use-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
|
||||
- uses: micnncim/action-label-syncer@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ env.BOT_TOKEN }}
|
||||
with:
|
||||
manifest: .github/workflows/config/labels.yml
|
34
.github/workflows/sync-to-gitee.yml
vendored
34
.github/workflows/sync-to-gitee.yml
vendored
@ -1,34 +0,0 @@
|
||||
# https://github.com/marketplace/actions/gitee-pages-action
|
||||
# 配置步骤如下
|
||||
# 1. 在命令行终端或 Git Bash 使用命令 ssh-keygen -t rsa -C "youremail@example.com" 生成 SSH Key,注意替换为自己的邮箱。生成的 id_rsa 是私钥,id_rsa.pub 是公钥。(⚠️注意此处不要设置密码)
|
||||
# 2. 在 GitHub 项目的「Settings -> Secrets」路径下配置好命名为 GITEE_RSA_PRIVATE_KEY 和 GITEE_PASSWORD 的两个密钥。其中:GITEE_RSA_PRIVATE_KEY 存放 id_rsa 私钥;GITEE_PASSWORD 存放 Gitee 帐号的密码。
|
||||
# 3. 在 GitHub 的个人设置页面「Settings -> SSH and GPG keys」 配置 SSH 公钥(即:id_rsa.pub),命名随意。或者在仓库设置页面添加一个部署公钥。
|
||||
# 4. 在 Gitee 的个人设置页面「安全设置 -> SSH 公钥」 配置 SSH 公钥(即:id_rsa.pub),命名随意。
|
||||
|
||||
name: 🔁 Sync to Gitee
|
||||
on: [push]
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🔁 Sync to Gitee
|
||||
uses: wearerequired/git-mirror-action@master
|
||||
env:
|
||||
# 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY
|
||||
SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
|
||||
with:
|
||||
# 注意替换为你的 GitHub 源仓库地址
|
||||
source-repo: 'git@github.com:antvis/X6.git'
|
||||
# 注意替换为你的 Gitee 目标仓库地址
|
||||
destination-repo: 'git@gitee.com:antv-x6/antv-x6.git'
|
||||
- name: 📦 Build Gitee Pages
|
||||
uses: yanglbme/gitee-pages-action@master
|
||||
with:
|
||||
# 注意替换为你的 Gitee 用户名
|
||||
gitee-username: afc163
|
||||
# 注意在 Settings->Secrets 配置 GITEE_PASSWORD
|
||||
gitee-password: ${{ secrets.GITEE_PASSWORD }}
|
||||
# 注意替换为你的 Gitee 仓库
|
||||
gitee-repo: antv-x6/antv-x6
|
||||
# 要部署的分支
|
||||
branch: gh-pages
|
2
.npmrc
Normal file
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
||||
registry=https://registry.npm.taobao.org
|
||||
strict-peer-dependencies=false
|
@ -14,3 +14,4 @@ dist/
|
||||
coverage/
|
||||
sites/public
|
||||
csstype.ts
|
||||
ui.js
|
||||
|
@ -12,6 +12,8 @@ HQidea <HQidea@users.noreply.github.com>
|
||||
ImgBotApp <ImgBotHelp@gmail.com>
|
||||
Indomi <indomi126@gmail.com>
|
||||
James Tsang <wtzeng1@gmail.com>
|
||||
JasonSun <42314340+LolipopJ@users.noreply.github.com>
|
||||
Jinxing Lin <172601673@qq.com>
|
||||
Jógvan Olsen <jogvanolsen@hotmail.com>
|
||||
Ken Geis <geis.ken@gmail.com>
|
||||
Kent Wood <minzojian@hotmail.com>
|
||||
|
111
CONTRIBUTORS.svg
111
CONTRIBUTORS.svg
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 14 MiB After Width: | Height: | Size: 14 MiB |
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Graph, Cell, Point, Timing, Interp } from '@antv/x6'
|
||||
import { Graph, Cell, Point, Timing, Interp } from '@antv/x6'
|
||||
import '../index.less'
|
||||
|
||||
export default class Example extends React.Component {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Graph, Cell, Node } from '@antv/x6'
|
||||
import { Graph, Node } from '@antv/x6'
|
||||
import { connectors } from '../connector/xmind-definitions'
|
||||
import Hierarchy from '@antv/hierarchy'
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
@ -220,7 +220,7 @@ export default class Example extends React.Component {
|
||||
const node = graph.getCellById(data.id)
|
||||
node.prop('position', { x: hierarchyItem.x, y: hierarchyItem.y })
|
||||
} else {
|
||||
const node = graph.addNode({
|
||||
graph.addNode({
|
||||
id: data.id,
|
||||
shape: data.type === 'topic-child' ? 'topic-child' : 'topic',
|
||||
x: hierarchyItem.x,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Shape, Path, Point, NumberExt, JSONObject } from '@antv/x6'
|
||||
import { Shape, Path, Point, NumberExt, JSONObject } from '@antv/x6'
|
||||
|
||||
interface KnobsAttrValue extends JSONObject {
|
||||
round: boolean | string | number
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
||||
/* eslint-disable jsx-a11y/anchor-has-content */
|
||||
import React from 'react'
|
||||
import ReactDom from 'react-dom'
|
||||
import { Menu, Dropdown } from 'antd'
|
||||
|
@ -14,14 +14,14 @@
|
||||
"build:esm": "turbo run build:esm --filter=./packages/*",
|
||||
"build:dev": "turbo run build:dev --filter=./packages/*",
|
||||
"build:umd": "turbo run build:umd --filter=./packages/*",
|
||||
"build:demos": "sh ./scripts/build-demos",
|
||||
"clean:turbo": "pnpm -r --if-present --parallel --filter=./packages/* run clean:turbo",
|
||||
"clean:build": "pnpm -r --if-present --parallel --filter=./packages/* run clean",
|
||||
"clean:modules": "pnpm -r --parallel exec rimraf node_modules && rimraf node_modules",
|
||||
"clean": "run-s clean:build clean:turbo clean:modules",
|
||||
"update:deps": "pnpm update --interactive --latest --recursive",
|
||||
"setup:husky": "husky install .husky",
|
||||
"prepare": "is-ci || run-p setup:husky build:dev"
|
||||
"prepare": "is-ci || run-p setup:husky build:dev",
|
||||
"start": "cd ./examples/x6-example-features && pnpm start"
|
||||
},
|
||||
"rss": {
|
||||
"clean:turbo": "rimraf .turbo",
|
||||
@ -159,7 +159,8 @@
|
||||
"ts-node": "^10.2.1",
|
||||
"tslib": "^2.4.1",
|
||||
"turbo": "^1.6.3",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"cross-spawn": "^7.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-terser": "^0.2.0"
|
||||
|
7
packages/x6-devtool/.gitignore
vendored
Normal file
7
packages/x6-devtool/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
yarn.lock
|
||||
.vscode
|
||||
devtools.crx
|
||||
devtools.pem
|
||||
.DS_Store
|
||||
.vscode
|
49
packages/x6-devtool/README.md
Normal file
49
packages/x6-devtool/README.md
Normal file
@ -0,0 +1,49 @@
|
||||
# X6 Devtool
|
||||
> A devtool for @antv/x6 in chrome, it's still WIP, you can load it in unpack way;
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Import unpacked plugin
|
||||

|
||||
|
||||
1. Open the Extension Management page by navigating to chrome://extensions.
|
||||
2. Enable Developer Mode by clicking the toggle switch next to Developer mode.
|
||||
3. Click the Load unpacked button and select the 'devtool' directory.
|
||||
|
||||
### Connect with X6 Graph;
|
||||
|
||||
#### In X6
|
||||
|
||||
```javascript
|
||||
// init window hook
|
||||
window.__x6_instances__ = [];
|
||||
|
||||
var graph = new Graph({...blablabla});
|
||||
|
||||
window.__x6_instances__.push(graph);
|
||||
|
||||
```
|
||||
|
||||
### Using devtool
|
||||
|
||||
After these steps, the tab 'AntV X6' should show in devtools' tab, select it and choose a canvas
|
||||
|
||||

|
||||
|
||||
|
||||
## Features
|
||||
|
||||
### Inspect Element in Graph
|
||||
|
||||

|
||||
|
||||
### View and Modify Attributes of Element
|
||||
|
||||

|
||||
|
||||
### Using select element directly in graph
|
||||
|
||||

|
||||
|
||||
|
||||
|
BIN
packages/x6-devtool/devtools/icons/128.png
Normal file
BIN
packages/x6-devtool/devtools/icons/128.png
Normal file
Binary file not shown.
BIN
packages/x6-devtool/devtools/icons/16.png
Normal file
BIN
packages/x6-devtool/devtools/icons/16.png
Normal file
Binary file not shown.
BIN
packages/x6-devtool/devtools/icons/32.png
Normal file
BIN
packages/x6-devtool/devtools/icons/32.png
Normal file
Binary file not shown.
BIN
packages/x6-devtool/devtools/icons/48-disabled.png
Normal file
BIN
packages/x6-devtool/devtools/icons/48-disabled.png
Normal file
Binary file not shown.
BIN
packages/x6-devtool/devtools/icons/48.png
Normal file
BIN
packages/x6-devtool/devtools/icons/48.png
Normal file
Binary file not shown.
19
packages/x6-devtool/devtools/manifest.json
Normal file
19
packages/x6-devtool/devtools/manifest.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "AntV X6 Dev Tool",
|
||||
"description": "devtool for x6 graph",
|
||||
"version": "0.0.1",
|
||||
"devtools_page": "x6_devtools.html",
|
||||
"minimum_chrome_version": "49",
|
||||
"manifest_version": 2,
|
||||
"permissions": ["file:///*", "http://*/*", "https://*/*"],
|
||||
"icons": {
|
||||
"16": "icons/16.png",
|
||||
"32": "icons/32.png",
|
||||
"48": "icons/48.png",
|
||||
"128": "icons/128.png"
|
||||
},
|
||||
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"web_accessible_resources": ["main.html", "panel.html", "script/backend.js"],
|
||||
"browser_action": {}
|
||||
}
|
59
packages/x6-devtool/devtools/panel.html
Normal file
59
packages/x6-devtool/devtools/panel.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="display: flex">
|
||||
<head>
|
||||
<meta charset="utf8" />
|
||||
<style>
|
||||
html {
|
||||
display: flex;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
#container {
|
||||
display: block;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
#desc {
|
||||
width: 240px;
|
||||
padding-left: 12px;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
overflow: auto;
|
||||
background: white;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
.tag.selected {
|
||||
background: rgba(135, 59, 244, 0.5);
|
||||
}
|
||||
.tag {
|
||||
background: rgba(128, 128, 128, 0.5);
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.tag.selected::after {
|
||||
display: inline-block;
|
||||
opacity: 0.4;
|
||||
font-size: 12px;
|
||||
content: '$gElement';
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="./ui/ui.js"></script>
|
||||
<script src="./script/panel.js"></script>
|
||||
</body>
|
||||
</html>
|
20
packages/x6-devtool/devtools/script/background.js
Normal file
20
packages/x6-devtool/devtools/script/background.js
Normal file
@ -0,0 +1,20 @@
|
||||
chrome.runtime.onMessage.addListener((req, sender) => {
|
||||
if (req.isAntVX6 && sender && sender.tab) {
|
||||
if (req.disabled) {
|
||||
chrome.browserAction.setIcon({
|
||||
tabId: sender.tab.id,
|
||||
path: 'icons/48-disabled.png',
|
||||
})
|
||||
} else {
|
||||
chrome.browserAction.setIcon({
|
||||
tabId: sender.tab.id,
|
||||
path: {
|
||||
16: 'icons/16.png',
|
||||
32: 'icons/32.png',
|
||||
48: 'icons/48.png',
|
||||
128: 'icons/128.png',
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
52
packages/x6-devtool/devtools/script/main.js
Normal file
52
packages/x6-devtool/devtools/script/main.js
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* global instance and flag
|
||||
*/
|
||||
|
||||
var panelInstance
|
||||
var itv
|
||||
|
||||
function createPanelInstance() {
|
||||
if (panelInstance) {
|
||||
return
|
||||
}
|
||||
|
||||
chrome.devtools.inspectedWindow.eval(
|
||||
`!!(window.__x6_instances__ && window.__x6_instances__.length)`,
|
||||
function (connected, err) {
|
||||
if (!connected) {
|
||||
return
|
||||
}
|
||||
|
||||
clearInterval(itv)
|
||||
|
||||
panelInstance = chrome.devtools.panels.create(
|
||||
'AntV X6',
|
||||
'icons/32.png',
|
||||
'panel.html',
|
||||
function (panel) {
|
||||
panel.onHidden.addListener(function () {
|
||||
chrome.devtools.inspectedWindow.eval(`(function() {
|
||||
var elements = document.getElementsByClassName('g_devtool_rect');
|
||||
[].forEach.apply(elements, [function (e) {
|
||||
e.remove();
|
||||
}])
|
||||
})()`)
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
isAntVX6: true,
|
||||
disabled: false,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
chrome.devtools.network.onNavigated.addListener(function () {
|
||||
// createPanelIfReactLoaded();
|
||||
})
|
||||
|
||||
createPanelInstance()
|
||||
|
||||
itv = setInterval(createPanelInstance, 1000)
|
281
packages/x6-devtool/devtools/script/panel.js
Normal file
281
packages/x6-devtool/devtools/script/panel.js
Normal file
@ -0,0 +1,281 @@
|
||||
//
|
||||
// script execute function
|
||||
//
|
||||
|
||||
// execute raw script in inspect window
|
||||
var executeScriptInInspectWindow = function (script) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
chrome.devtools.inspectedWindow.eval(script, function (result, exception) {
|
||||
if (exception) {
|
||||
console.error('eval error', script)
|
||||
reject(exception)
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// execute function in anynomous code block
|
||||
var executeFuntionInInspectWindow = function (func, args) {
|
||||
return executeScriptInInspectWindow(
|
||||
`(${func.toString()}).apply(window, ${JSON.stringify(args)})`,
|
||||
)
|
||||
}
|
||||
|
||||
//
|
||||
// these are the function that execute in inspect window
|
||||
//
|
||||
|
||||
function doFPSThings() {
|
||||
if (window.__x6_fps) {
|
||||
cancelAnimationFrame(window.__x6_fps)
|
||||
}
|
||||
let lastCalledTime
|
||||
let fps
|
||||
let delta
|
||||
|
||||
function requestAnimFrame() {
|
||||
if (!lastCalledTime) {
|
||||
lastCalledTime = performance.now()
|
||||
fps = 0
|
||||
} else {
|
||||
delta = (performance.now() - lastCalledTime) / 1000
|
||||
lastCalledTime = performance.now()
|
||||
fps = 1 / delta
|
||||
}
|
||||
window.__x6_fps_value = Math.round(fps)
|
||||
window.__x6_fps = requestAnimationFrame(requestAnimFrame)
|
||||
}
|
||||
|
||||
requestAnimFrame()
|
||||
}
|
||||
|
||||
// get global X6 Graph structure
|
||||
function getGlobalInstances() {
|
||||
var instances = window.__x6_instances__
|
||||
var gmap = {}
|
||||
var getGraphCells = function (graph) {
|
||||
// 使用model中的引用直接获取元素
|
||||
return graph.model.collection.cells
|
||||
}
|
||||
window.__x6_instances__.globalMap = gmap
|
||||
var gInfo = []
|
||||
function getX6Instance(instance) {
|
||||
const ga = {}
|
||||
// antv/g 实现了getChildren可以递归获取,x6不行
|
||||
// if (instance.getChildren && instance.getChildren()) {
|
||||
// ga.children = instance.getChildren().map(function (p) {
|
||||
// return getX6Instance(p);
|
||||
// });
|
||||
// }
|
||||
|
||||
if (!instance.__dev_hash) {
|
||||
ga.hash = Math.random().toString(16).slice(-8)
|
||||
instance.__dev_hash = ga.hash
|
||||
} else {
|
||||
ga.hash = instance.__dev_hash
|
||||
}
|
||||
|
||||
gmap[ga.hash] = instance
|
||||
ga.id = instance.id
|
||||
ga.name = instance.name || instance.prop('shape') || instance.prop('label')
|
||||
ga.type = instance.isEdge() ? 'edge' : 'node'
|
||||
return ga
|
||||
}
|
||||
|
||||
if (instances && instances.length) {
|
||||
gInfo = instances.map(function (instance) {
|
||||
const hash = instance.hash || Math.random().toString(16).slice(-8)
|
||||
const cells = getGraphCells(instance).map((e) => getX6Instance(e))
|
||||
const plugins = Array.from(instance.installedPlugins).map((plugin) => {
|
||||
const hash = plugin.hash || Math.random().toString(16).slice(-8)
|
||||
const ga = {
|
||||
name: plugin.name,
|
||||
hash,
|
||||
type: 'plugin',
|
||||
}
|
||||
plugin.hash = ga.hash
|
||||
gmap[ga.hash] = plugin
|
||||
return ga
|
||||
})
|
||||
var ga = {
|
||||
type: 'svg',
|
||||
name: 'Graph',
|
||||
nodeName: 'graph',
|
||||
hash,
|
||||
children: cells.concat(plugins),
|
||||
memory: window.performance.memory.usedJSHeapSize,
|
||||
fps: window.__x6_fps_value,
|
||||
}
|
||||
instance.hash = ga.hash
|
||||
gmap[ga.hash] = instance
|
||||
return ga
|
||||
})
|
||||
} else {
|
||||
gInfo.length = 0
|
||||
}
|
||||
|
||||
return gInfo
|
||||
}
|
||||
|
||||
function checkGraphByHash(hash) {
|
||||
return !!window.__x6_instances__.map((e) => e.hash).includes(hash)
|
||||
}
|
||||
|
||||
function createBoxUsingId(bbox, id, color) {
|
||||
var el = document.createElement('div')
|
||||
window[id] = el
|
||||
el.classList.add('x6_devtool_rect')
|
||||
document.body.appendChild(el)
|
||||
el.style.position = 'absolute'
|
||||
el.style.width = `${bbox.width}px`
|
||||
el.style.height = `${bbox.height}px`
|
||||
el.style.top = `${bbox.top}px`
|
||||
el.style.left = `${bbox.left}px`
|
||||
el.style.background = color || 'rgba(135, 59, 244, 0.5)'
|
||||
el.style.border = '2px dashed rgb(135, 59, 244)'
|
||||
el.style.boxSizing = 'border-box'
|
||||
}
|
||||
|
||||
function removeBoxUsingId(id) {
|
||||
if (window[id]) {
|
||||
window[id].remove()
|
||||
}
|
||||
}
|
||||
|
||||
function removeAllBox() {
|
||||
var elements = document.getElementsByClassName('x6_devtool_rect')
|
||||
;[].forEach.apply(elements, [
|
||||
function (e) {
|
||||
e.remove()
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
function getElemetBBoxByHash(hash) {
|
||||
try {
|
||||
var targetEl = window.__x6_instances__.globalMap[hash]
|
||||
if (targetEl) {
|
||||
const bbox = targetEl.getGraphArea
|
||||
? targetEl.getGraphArea()
|
||||
: targetEl.getBBox()
|
||||
const pageBBox = targetEl.model.graph.localToPage(bbox)
|
||||
const { width, height, x, y, left, top } = pageBBox
|
||||
return { width, height, x, y, left, top }
|
||||
}
|
||||
} catch (e) {}
|
||||
return {}
|
||||
}
|
||||
|
||||
function getElementAttrByHash(hash) {
|
||||
const instance = window.__x6_instances__.globalMap[hash]
|
||||
if (instance) {
|
||||
return instance.prop
|
||||
? instance.prop()
|
||||
: instance.options
|
||||
? {
|
||||
...instance.options,
|
||||
container: undefined,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
function setElementAttrByHash(hash, name, value) {
|
||||
const instance = window.__x6_instances__.globalMap[hash]
|
||||
// graph can not set prop
|
||||
if (instance && instance.prop) {
|
||||
instance.prop(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
function setGElementByHash(hash) {
|
||||
window.$gElemet = hash ? window.__x6_instances__.globalMap[hash] : undefined
|
||||
}
|
||||
|
||||
function consoleElementByHash(hash, desc) {
|
||||
window.console.log(
|
||||
desc || '<Click To Expand>',
|
||||
window.__x6_instances__.globalMap[hash],
|
||||
)
|
||||
}
|
||||
|
||||
//
|
||||
// these are the functions that run in devtools panel
|
||||
//
|
||||
|
||||
function setRect(bbox, id, color) {
|
||||
executeFuntionInInspectWindow(removeBoxUsingId, [id]).finally(() => {
|
||||
executeFuntionInInspectWindow(createBoxUsingId, [bbox, id, color])
|
||||
})
|
||||
}
|
||||
|
||||
function cleanRect(id) {
|
||||
executeFuntionInInspectWindow(removeBoxUsingId, [id])
|
||||
}
|
||||
|
||||
function showRect(hash, id, color) {
|
||||
executeFuntionInInspectWindow(getElemetBBoxByHash, [hash]).then((bbox) => {
|
||||
setRect(bbox, id, color)
|
||||
})
|
||||
}
|
||||
|
||||
function cleanAllRect() {
|
||||
executeFuntionInInspectWindow(removeAllBox)
|
||||
}
|
||||
|
||||
function getAttrs(hash) {
|
||||
if (hash) {
|
||||
executeFuntionInInspectWindow(setGElementByHash, [hash])
|
||||
return executeFuntionInInspectWindow(getElementAttrByHash, [hash])
|
||||
}
|
||||
return executeFuntionInInspectWindow(setGElementByHash, [])
|
||||
}
|
||||
|
||||
function updateAttrs(hash, name, attrs) {
|
||||
return executeFuntionInInspectWindow(setElementAttrByHash, [
|
||||
hash,
|
||||
name,
|
||||
attrs,
|
||||
])
|
||||
}
|
||||
|
||||
function consoleEl(hash, desc) {
|
||||
return executeFuntionInInspectWindow(consoleElementByHash, [hash, desc])
|
||||
}
|
||||
|
||||
function checkGraphAlive(hash) {
|
||||
return executeFuntionInInspectWindow(checkGraphByHash, [hash]).then((res) => {
|
||||
if (res) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getNowGraphData() {
|
||||
return executeFuntionInInspectWindow(getGlobalInstances)
|
||||
}
|
||||
function startFPSMonitor() {
|
||||
return executeFuntionInInspectWindow(doFPSThings)
|
||||
}
|
||||
|
||||
getNowGraphData().then(function (data) {
|
||||
const container = document.getElementById('container')
|
||||
mount(data, container, {
|
||||
showRect,
|
||||
getAttrs,
|
||||
cleanRect,
|
||||
updateAttrs,
|
||||
consoleEl,
|
||||
checkGraphAlive,
|
||||
getNowGraphData,
|
||||
cleanAllRect,
|
||||
startFPSMonitor,
|
||||
})
|
||||
})
|
||||
|
||||
startFPSMonitor()
|
2
packages/x6-devtool/devtools/ui/ui.js
Normal file
2
packages/x6-devtool/devtools/ui/ui.js
Normal file
File diff suppressed because one or more lines are too long
49
packages/x6-devtool/devtools/ui/ui.js.LICENSE.txt
Normal file
49
packages/x6-devtool/devtools/ui/ui.js.LICENSE.txt
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
@license MIT
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/** @license React v0.20.2
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v17.0.2
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v17.0.2
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
8
packages/x6-devtool/devtools/x6_devtools.html
Normal file
8
packages/x6-devtool/devtools/x6_devtools.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="./script/main.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
29
packages/x6-devtool/package.json
Normal file
29
packages/x6-devtool/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@antv/x6-devtool",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"description": "devtool for x6 in browser",
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "webpack -w",
|
||||
"build": "webpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"antd": "4.18.3",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-json-view": "1.21.3",
|
||||
"@ant-design/icons": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.7",
|
||||
"@babel/preset-env": "^7.16.8",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"babel-loader": "^8.2.3",
|
||||
"css-loader": "^6.5.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"webpack": "^5.66.0",
|
||||
"webpack-cli": "4.9.1"
|
||||
}
|
||||
}
|
189
packages/x6-devtool/ui/components/Devtool.js
Normal file
189
packages/x6-devtool/ui/components/Devtool.js
Normal file
@ -0,0 +1,189 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Row, Select, Col, Button, Tooltip, Tag, Empty } from 'antd'
|
||||
import { CodeOutlined } from '@ant-design/icons'
|
||||
import GTree from './GTree'
|
||||
|
||||
const countTree = (tree) => {
|
||||
if (!tree) {
|
||||
return 0
|
||||
}
|
||||
const count = tree?.children?.reduce((a, b) => a + countTree(b), 1) || 1
|
||||
tree.count = count
|
||||
return count
|
||||
}
|
||||
|
||||
export function convertMemoryUnit(number, digits = 2) {
|
||||
let value
|
||||
let unit
|
||||
if (number > 1000000000) {
|
||||
unit = 'GB'
|
||||
value = number / 1000000000
|
||||
} else if (number > 1000000) {
|
||||
unit = 'MB'
|
||||
value = number / 1000000
|
||||
} else if (number > 1000) {
|
||||
unit = 'KB'
|
||||
value = number / 1000
|
||||
} else {
|
||||
unit = 'B'
|
||||
value = number
|
||||
}
|
||||
value = value && value % 1 !== 0 ? value.toFixed(digits) : value
|
||||
return value + unit
|
||||
}
|
||||
|
||||
const HeadBar = (props) => {
|
||||
const {
|
||||
data,
|
||||
setSelectedHash,
|
||||
actions,
|
||||
selectedData,
|
||||
setData,
|
||||
selectedHash,
|
||||
} = props
|
||||
const [graphAlive, setGraphAlive] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
const itv = setInterval(() => {
|
||||
actions.checkGraphAlive(selectedHash).then((res) => {
|
||||
setGraphAlive(res)
|
||||
if (res) {
|
||||
actions.getNowGraphData().then((d) => {
|
||||
if (d) {
|
||||
setData(d)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
return () => {
|
||||
clearInterval(itv)
|
||||
}
|
||||
}, [actions, setData, selectedData, selectedHash])
|
||||
|
||||
useEffect(() => {
|
||||
if (!graphAlive) {
|
||||
actions.getNowGraphData().then((d) => {
|
||||
if (d) {
|
||||
setData(d)
|
||||
setSelectedHash(d[0].hash)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [actions, graphAlive, setData, setSelectedHash])
|
||||
|
||||
return (
|
||||
<Row
|
||||
align="middle"
|
||||
style={{
|
||||
padding: 2,
|
||||
marginBottom: 6,
|
||||
borderBottom: '1px solid #ddd',
|
||||
background: 'rgba(0, 0, 0, 0.05)',
|
||||
position: 'fixed',
|
||||
width: '100%',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 999,
|
||||
}}
|
||||
gutter={[12, 12]}
|
||||
>
|
||||
<Col>
|
||||
<Select
|
||||
bordered={false}
|
||||
size="small"
|
||||
defaultValue={0}
|
||||
options={data.map((e, i) => ({
|
||||
label: `Graph ${i}`,
|
||||
value: e.hash,
|
||||
info: e,
|
||||
}))}
|
||||
value={selectedHash}
|
||||
onChange={(val) => {
|
||||
setSelectedHash(val)
|
||||
}}
|
||||
placeholder="Choose a graph to inspect"
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
{graphAlive ? (
|
||||
<Col>
|
||||
<Tag color="green">ALIVE</Tag>
|
||||
</Col>
|
||||
) : (
|
||||
<Col>
|
||||
<Tag color="red">DEAD</Tag>
|
||||
<span>Trying to reconnect</span>
|
||||
</Col>
|
||||
)}
|
||||
{selectedData && <Col>{selectedData?.count} Shapes</Col>}
|
||||
{selectedData?.memory > 0 && (
|
||||
<Col>HeapMemory:{convertMemoryUnit(selectedData.memory)}</Col>
|
||||
)}
|
||||
{selectedData?.fps > 0 && <Col>FPS: {selectedData?.fps}</Col>}
|
||||
<Col flex={1} />
|
||||
<Col>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => {
|
||||
actions.consoleEl(selectedData.hash)
|
||||
}}
|
||||
>
|
||||
<Tooltip arrowPointAtCenter title="Console X6 Graph">
|
||||
<CodeOutlined />
|
||||
</Tooltip>
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
const Devtool = (props) => {
|
||||
const { data: initData = [], actions = {} } = props
|
||||
const [selectedData, setSelectedData] = useState(initData[0])
|
||||
const [selectedHash, setSelectedHash] = useState(initData[0].hash)
|
||||
const [data, setData] = useState(initData)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
actions.cleanAllRect()
|
||||
actions.startFPSMonitor()
|
||||
}
|
||||
}, [actions, selectedHash])
|
||||
|
||||
useEffect(() => {
|
||||
const target = data.find((e) => e.hash === selectedHash)
|
||||
countTree(target)
|
||||
setSelectedData(target)
|
||||
}, [selectedHash, data])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HeadBar
|
||||
data={data}
|
||||
setSelectedHash={setSelectedHash}
|
||||
selectedData={selectedData}
|
||||
selectedHash={selectedHash}
|
||||
actions={actions}
|
||||
setData={setData}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
marginTop: 48,
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
{selectedData ? (
|
||||
<GTree actions={actions} data={selectedData} />
|
||||
) : (
|
||||
<Empty />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Devtool
|
179
packages/x6-devtool/ui/components/GTree.js
Normal file
179
packages/x6-devtool/ui/components/GTree.js
Normal file
@ -0,0 +1,179 @@
|
||||
import { Drawer, Empty, Space, Tree, Typography } from 'antd'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import ReactJson from 'react-json-view'
|
||||
import {
|
||||
BlockOutlined,
|
||||
PartitionOutlined,
|
||||
AppstoreOutlined,
|
||||
NodeIndexOutlined,
|
||||
ToolOutlined,
|
||||
} from '@ant-design/icons'
|
||||
|
||||
const iconMap = {
|
||||
group: <BlockOutlined />,
|
||||
svg: <PartitionOutlined />,
|
||||
shape: <AppstoreOutlined />,
|
||||
node: <AppstoreOutlined />,
|
||||
edge: <NodeIndexOutlined />,
|
||||
plugin: <ToolOutlined />,
|
||||
}
|
||||
|
||||
const AttrsDrawer = ({ hash, getAttrs, onCancel, updateAttrs }) => {
|
||||
const [val, setVal] = useState(hash)
|
||||
const change = (all) => {
|
||||
const { updated_src, namespace, name, existing_value, new_value } = all
|
||||
|
||||
const key = namespace[0] || name
|
||||
const value = updated_src[key]
|
||||
|
||||
// 这个函数,递归对新的value进行预处理。
|
||||
// input框接收的new_value是字符串,需要按照旧值做转换
|
||||
const setNewValue = (value, paths, existing_value, new_value) => {
|
||||
const key = paths.shift()
|
||||
if (paths.length > 0) {
|
||||
setNewValue(value[key], paths, existing_value, new_value)
|
||||
} else {
|
||||
if (new_value === undefined) {
|
||||
// 删除
|
||||
delete value[key]
|
||||
} else if (typeof existing_value === 'undefined') {
|
||||
// 新增
|
||||
value[key] = new_value
|
||||
} else if (typeof existing_value === 'boolean') {
|
||||
value[key] = Boolean(new_value)
|
||||
} else if (typeof existing_value === 'number') {
|
||||
const val = Number(new_value)
|
||||
if (!isNaN(val)) {
|
||||
value[key] = val
|
||||
}
|
||||
} else if (typeof existing_value === 'string') {
|
||||
value[key] = '' + new_value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNewValue(
|
||||
value,
|
||||
namespace.slice(1).concat(name),
|
||||
existing_value,
|
||||
new_value,
|
||||
)
|
||||
|
||||
updateAttrs(hash, key, value, all)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (hash && getAttrs) {
|
||||
getAttrs(hash).then((res) => {
|
||||
setVal(res)
|
||||
})
|
||||
} else {
|
||||
onCancel()
|
||||
getAttrs()
|
||||
}
|
||||
}, [getAttrs, hash, onCancel])
|
||||
|
||||
return (
|
||||
<Drawer mask={false} onClose={onCancel} visible={hash}>
|
||||
<ReactJson
|
||||
style={{ fontSize: 12 }}
|
||||
onAdd={change}
|
||||
onEdit={change}
|
||||
onDelete={change}
|
||||
src={val}
|
||||
/>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
const buildTreeData = (data = {}, isRoot) => {
|
||||
const node = {
|
||||
title: data.name || data.shape || data.type,
|
||||
type: data.type,
|
||||
key: data.hash,
|
||||
name: data.name,
|
||||
id: data.id,
|
||||
hash: data.hash,
|
||||
count: data.count,
|
||||
num: data.children?.length || 0,
|
||||
}
|
||||
|
||||
if (data.children) {
|
||||
node.children = data.children.map((e) => buildTreeData(e))
|
||||
}
|
||||
|
||||
if (isRoot) {
|
||||
node.type = 'svg'
|
||||
node.title = 'svg'
|
||||
// node.key = node.hash || 'svg'
|
||||
return node
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
const GTree = (props) => {
|
||||
const { data, actions = {} } = props
|
||||
const [selectedKey, setSelected] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
actions.showRect(selectedKey, '__x6_select__', 'rgba(29, 57, 196, 0.5)')
|
||||
return () => {
|
||||
actions.cleanRect('__x6_select__')
|
||||
}
|
||||
}, [actions, selectedKey])
|
||||
|
||||
if (!data) {
|
||||
return <Empty />
|
||||
}
|
||||
|
||||
const treeData = buildTreeData(data, true)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tree
|
||||
selectedKeys={[selectedKey]}
|
||||
onSelect={(keys) => setSelected(keys[0])}
|
||||
showLine={{ showLeafIcon: false }}
|
||||
height={document.body.clientHeight - 45}
|
||||
titleRender={(node) => (
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
actions.showRect(node.key, '__x6_hover__')
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
actions.cleanRect('__x6_hover__')
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
{iconMap[node.type]}
|
||||
{node.title}
|
||||
{node.name && (
|
||||
<Typography.Text type="secondary">
|
||||
name:{node.name}
|
||||
</Typography.Text>
|
||||
)}
|
||||
{node.id && (
|
||||
<Typography.Text type="secondary">id:{node.id}</Typography.Text>
|
||||
)}
|
||||
{node.num > 0 && (
|
||||
<Typography.Text type="secondary">
|
||||
({node.num} children / {node.count || 0} descendants)
|
||||
</Typography.Text>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
treeData={[treeData]}
|
||||
/>
|
||||
<AttrsDrawer
|
||||
hash={selectedKey}
|
||||
onCancel={() => setSelected()}
|
||||
getAttrs={actions.getAttrs}
|
||||
updateAttrs={actions.updateAttrs}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default GTree
|
8
packages/x6-devtool/ui/index.js
Normal file
8
packages/x6-devtool/ui/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import Devtool from './components/Devtool'
|
||||
import 'antd/dist/antd.css'
|
||||
|
||||
window.mount = (data = [], container, actions = {}) => {
|
||||
ReactDOM.render(<Devtool data={data} actions={actions} />, container)
|
||||
}
|
30
packages/x6-devtool/webpack.config.js
Normal file
30
packages/x6-devtool/webpack.config.js
Normal file
@ -0,0 +1,30 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
entry: './ui/index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'devtools', 'ui'),
|
||||
filename: 'ui.js',
|
||||
},
|
||||
optimization: {
|
||||
usedExports: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@ -74,17 +74,20 @@ Graph.prototype.unbindKey = function (
|
||||
return this
|
||||
}
|
||||
|
||||
Graph.prototype.clearKeys = function() {
|
||||
Graph.prototype.clearKeys = function () {
|
||||
const keyboard = this.getPlugin('keyboard') as Keyboard
|
||||
if(keyboard) {
|
||||
if (keyboard) {
|
||||
keyboard.clear()
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
Graph.prototype.triggerKey = function(key: string, action: KeyboardImpl.Action) {
|
||||
Graph.prototype.triggerKey = function (
|
||||
key: string,
|
||||
action: KeyboardImpl.Action,
|
||||
) {
|
||||
const keyboard = this.getPlugin('keyboard') as Keyboard
|
||||
if(keyboard) {
|
||||
if (keyboard) {
|
||||
keyboard.trigger(key, action)
|
||||
}
|
||||
return this
|
||||
|
@ -1,5 +1,30 @@
|
||||
import { Graph, Node } from '@antv/x6'
|
||||
import { TransformImpl } from './transform'
|
||||
import { Transform } from './index'
|
||||
|
||||
declare module '@antv/x6/lib/graph/graph' {
|
||||
interface Graph {
|
||||
createTransformWidget: (node: Node) => Graph
|
||||
clearTransformWidgets: () => Graph
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@antv/x6/lib/graph/events' {
|
||||
interface EventArgs extends TransformImpl.EventArgs {}
|
||||
}
|
||||
|
||||
Graph.prototype.createTransformWidget = function (node) {
|
||||
const transform = this.getPlugin('transform') as Transform
|
||||
if (transform) {
|
||||
transform.createWidget(node)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
Graph.prototype.clearTransformWidgets = function () {
|
||||
const transform = this.getPlugin('transform') as Transform
|
||||
if (transform) {
|
||||
transform.clearWidgets()
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export class Transform extends Basecoat<Transform.EventArgs> {
|
||||
return !this.disabled
|
||||
}
|
||||
|
||||
protected onNodeClick({ node }: EventArgs['node:click']) {
|
||||
createWidget(node: Node) {
|
||||
this.clearWidgets()
|
||||
const widget = this.createTransform(node)
|
||||
if (widget) {
|
||||
@ -62,6 +62,10 @@ export class Transform extends Basecoat<Transform.EventArgs> {
|
||||
}
|
||||
}
|
||||
|
||||
protected onNodeClick({ node }: EventArgs['node:click']) {
|
||||
this.createWidget(node)
|
||||
}
|
||||
|
||||
protected onBlankMouseDown() {
|
||||
this.clearWidgets()
|
||||
}
|
||||
@ -135,7 +139,7 @@ export class Transform extends Basecoat<Transform.EventArgs> {
|
||||
return options
|
||||
}
|
||||
|
||||
protected clearWidgets() {
|
||||
clearWidgets() {
|
||||
this.widgets.forEach((widget, node) => {
|
||||
if (this.graph.getCellById(node.id)) {
|
||||
widget.dispose()
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-react-shape",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"description": "X6 shape for rendering react components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-vue-shape",
|
||||
"version": "2.0.9",
|
||||
"version": "2.0.10",
|
||||
"description": "X6 shape for rendering vue components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6",
|
||||
"version": "2.5.3",
|
||||
"version": "2.5.6",
|
||||
"description": "JavaScript diagramming library that uses SVG and HTML for rendering",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -44,8 +44,8 @@
|
||||
"pretest": "rss"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/x6-common": "^2.0.x",
|
||||
"@antv/x6-geometry": "^2.0.x",
|
||||
"@antv/x6-common": "^2.0.11",
|
||||
"@antv/x6-geometry": "^2.0.4",
|
||||
"utility-types": "^3.10.0"
|
||||
},
|
||||
"author": {
|
||||
|
@ -45,8 +45,7 @@ export class Cell<
|
||||
} else if (typeof propHooks === 'function') {
|
||||
this.propHooks.push(propHooks)
|
||||
} else {
|
||||
Object.keys(propHooks).forEach((name) => {
|
||||
const hook = propHooks[name]
|
||||
Object.values(propHooks).forEach((hook) => {
|
||||
if (typeof hook === 'function') {
|
||||
this.propHooks.push(hook)
|
||||
}
|
||||
@ -1292,8 +1291,7 @@ export class Cell<
|
||||
const defaultAttrs = defaults.attrs || {}
|
||||
const finalAttrs: Attr.CellAttrs = {}
|
||||
|
||||
Object.keys(props).forEach((key) => {
|
||||
const val = props[key]
|
||||
Object.entries(props).forEach(([key, val]) => {
|
||||
if (
|
||||
val != null &&
|
||||
!Array.isArray(val) &&
|
||||
|
@ -315,8 +315,8 @@ export class Model extends Basecoat<Model.EventArgs> {
|
||||
return this.batchUpdate(
|
||||
'update',
|
||||
() => {
|
||||
Object.keys(prop).forEach((key) =>
|
||||
existing.setProp(key, prop[key], options),
|
||||
Object.entries(prop).forEach(([key, val]) =>
|
||||
existing.setProp(key, val, options),
|
||||
)
|
||||
return true
|
||||
},
|
||||
|
@ -116,7 +116,7 @@ export namespace Attr {
|
||||
}
|
||||
|
||||
export namespace Attr {
|
||||
export type Presets = typeof Attr['presets']
|
||||
export type Presets = (typeof Attr)['presets']
|
||||
export type NativeNames = keyof Presets
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ export namespace Background {
|
||||
}
|
||||
|
||||
export namespace Background {
|
||||
export type Presets = typeof Background['presets']
|
||||
export type Presets = (typeof Background)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[1] & {
|
||||
|
@ -38,7 +38,7 @@ export namespace ConnectionPoint {
|
||||
}
|
||||
|
||||
export namespace ConnectionPoint {
|
||||
export type Presets = typeof ConnectionPoint['presets']
|
||||
export type Presets = (typeof ConnectionPoint)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[3]
|
||||
|
@ -20,7 +20,7 @@ export namespace ConnectionStrategy {
|
||||
}
|
||||
|
||||
export namespace ConnectionStrategy {
|
||||
export type Presets = typeof ConnectionStrategy['presets']
|
||||
export type Presets = (typeof ConnectionStrategy)['presets']
|
||||
|
||||
export type NativeNames = keyof Presets
|
||||
|
||||
|
@ -20,7 +20,7 @@ export namespace Connector {
|
||||
}
|
||||
|
||||
export namespace Connector {
|
||||
export type Presets = typeof Connector['presets']
|
||||
export type Presets = (typeof Connector)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[3]
|
||||
|
@ -17,15 +17,15 @@ function setupUpdating(view: EdgeView) {
|
||||
if (updateList == null) {
|
||||
updateList = (view.graph as any)._jumpOverUpdateList = []
|
||||
|
||||
/**
|
||||
* Handler for a batch:stop event to force
|
||||
* update of all registered links with jump over connector
|
||||
*/
|
||||
view.graph.on('cell:mouseup', () => {
|
||||
const list = (view.graph as any)._jumpOverUpdateList
|
||||
for (let i = 0; i < list.length; i += 1) {
|
||||
list[i].update()
|
||||
}
|
||||
// add timeout to wait for the target node to be connected
|
||||
// fix https://github.com/antvis/X6/issues/3387
|
||||
setTimeout(() => {
|
||||
for (let i = 0; i < list.length; i += 1) {
|
||||
list[i].update()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
view.graph.on('model:reseted', () => {
|
||||
|
@ -27,7 +27,7 @@ export namespace EdgeAnchor {
|
||||
}
|
||||
|
||||
export namespace EdgeAnchor {
|
||||
export type Presets = typeof EdgeAnchor['presets']
|
||||
export type Presets = (typeof EdgeAnchor)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[3]
|
||||
|
@ -9,7 +9,7 @@ export namespace Filter {
|
||||
}
|
||||
|
||||
export namespace Filter {
|
||||
export type Presets = typeof Filter['presets']
|
||||
export type Presets = (typeof Filter)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: NonUndefined<Parameters<Presets[K]>[0]>
|
||||
|
@ -79,7 +79,7 @@ export namespace Grid {
|
||||
}
|
||||
|
||||
export namespace Grid {
|
||||
export type Presets = typeof Grid['presets']
|
||||
export type Presets = (typeof Grid)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
dot: patterns.DotOptions
|
||||
|
@ -32,7 +32,7 @@ export namespace Highlighter {
|
||||
}
|
||||
|
||||
export namespace Highlighter {
|
||||
export type Presets = typeof Highlighter['presets']
|
||||
export type Presets = (typeof Highlighter)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]['highlight']>[2]
|
||||
|
@ -23,7 +23,7 @@ export namespace Marker {
|
||||
}
|
||||
|
||||
export namespace Marker {
|
||||
export type Presets = typeof Marker['presets']
|
||||
export type Presets = (typeof Marker)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[0]
|
||||
|
@ -42,7 +42,7 @@ export namespace NodeAnchor {
|
||||
}
|
||||
|
||||
export namespace NodeAnchor {
|
||||
export type Presets = typeof NodeAnchor['presets']
|
||||
export type Presets = (typeof NodeAnchor)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[3]
|
||||
|
@ -28,7 +28,7 @@ export namespace PortLabelLayout {
|
||||
}
|
||||
|
||||
export namespace PortLabelLayout {
|
||||
export type Presets = typeof PortLabelLayout['presets']
|
||||
export type Presets = (typeof PortLabelLayout)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[2]
|
||||
|
@ -35,7 +35,7 @@ export namespace PortLayout {
|
||||
}
|
||||
|
||||
export namespace PortLayout {
|
||||
export type Presets = typeof PortLayout['presets']
|
||||
export type Presets = (typeof PortLayout)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[2]
|
||||
|
@ -35,8 +35,8 @@ export class Registry<
|
||||
force = false,
|
||||
) {
|
||||
if (typeof name === 'object') {
|
||||
Object.keys(name).forEach((key) => {
|
||||
this.register(key, name[key], options)
|
||||
Object.entries(name).forEach(([key, val]) => {
|
||||
this.register(key, val, options)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export namespace Router {
|
||||
}
|
||||
|
||||
export namespace Router {
|
||||
export type Presets = typeof Router['presets']
|
||||
export type Presets = (typeof Router)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: Parameters<Presets[K]>[1]
|
||||
|
@ -53,7 +53,7 @@ export namespace NodeTool {
|
||||
}
|
||||
|
||||
export namespace NodeTool {
|
||||
export type Presets = typeof NodeTool['presets']
|
||||
export type Presets = (typeof NodeTool)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: ConstructorParameters<Presets[K]>[0]
|
||||
@ -122,7 +122,7 @@ export namespace EdgeTool {
|
||||
}
|
||||
|
||||
export namespace EdgeTool {
|
||||
export type Presets = typeof EdgeTool['presets']
|
||||
export type Presets = (typeof EdgeTool)['presets']
|
||||
|
||||
export type OptionsMap = {
|
||||
readonly [K in keyof Presets]-?: ConstructorParameters<Presets[K]>[0]
|
||||
|
@ -259,9 +259,7 @@ export class Scheduler extends Disposable {
|
||||
}
|
||||
|
||||
protected flushWaittingViews() {
|
||||
const ids = Object.keys(this.views)
|
||||
for (let i = 0, len = ids.length; i < len; i += 1) {
|
||||
const viewItem = this.views[ids[i]]
|
||||
Object.values(this.views).forEach((viewItem) => {
|
||||
if (viewItem && viewItem.state === Scheduler.ViewState.WAITTING) {
|
||||
const { view, flag, options } = viewItem
|
||||
this.requestViewUpdate(
|
||||
@ -272,7 +270,7 @@ export class Scheduler extends Disposable {
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.flush()
|
||||
}
|
||||
@ -331,7 +329,7 @@ export class Scheduler extends Disposable {
|
||||
protected removeView(view: CellView) {
|
||||
const cell = view.cell
|
||||
const viewItem = this.willRemoveViews[cell.id]
|
||||
if (view) {
|
||||
if (viewItem && view) {
|
||||
viewItem.view.remove()
|
||||
delete this.willRemoveViews[cell.id]
|
||||
this.graph.trigger('view:unmounted', { view })
|
||||
@ -402,8 +400,7 @@ export class Scheduler extends Disposable {
|
||||
|
||||
protected removeZPivots() {
|
||||
if (this.zPivots) {
|
||||
Object.keys(this.zPivots).forEach((z) => {
|
||||
const elem = this.zPivots[z]
|
||||
Object.values(this.zPivots).forEach((elem) => {
|
||||
if (elem && elem.parentNode) {
|
||||
elem.parentNode.removeChild(elem)
|
||||
}
|
||||
|
@ -67,8 +67,7 @@ export class CellView<
|
||||
}
|
||||
|
||||
if (actions) {
|
||||
Object.keys(actions).forEach((key) => {
|
||||
const val = actions[key]
|
||||
Object.entries(actions).forEach(([key, val]) => {
|
||||
const raw = ret.actions[key]
|
||||
if (val && raw) {
|
||||
ret.actions[key] = mergeActions(raw, val)
|
||||
|
@ -213,8 +213,7 @@ export class NodeView<
|
||||
}
|
||||
|
||||
protected removePorts() {
|
||||
Object.keys(this.portsCache).forEach((portId) => {
|
||||
const cached = this.portsCache[portId]
|
||||
Object.values(this.portsCache).forEach((cached) => {
|
||||
Dom.remove(cached.portElement)
|
||||
})
|
||||
}
|
||||
|
66405
pnpm-lock.yaml
generated
66405
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -5,4 +5,4 @@
|
||||
"previewer.actions.codepen": "在 CodePen 中打开(未实现)",
|
||||
"previewer.actions.stackblitz": "在 StackBlitz 中打开",
|
||||
"previewer.actions.separate": "在独立页面中打开"
|
||||
}
|
||||
}
|
||||
|
@ -389,3 +389,18 @@ graph.on("edge:transition:complete", (args: Animation.CallbackArgs) => {});
|
||||
graph.on("edge:transition:stop", (args: Animation.StopArgs) => {});
|
||||
graph.on("edge:transition:finish", (args: Animation.CallbackArgs) => {});
|
||||
```
|
||||
|
||||
|
||||
## 视图
|
||||
|
||||
由于X6实现了异步的渲染调度算法,所以节点的添加不一定意味着挂载到画布上。节点在被挂载到画布时以及从画布上卸载时会分别触发单独的事件。
|
||||
|
||||
| 事件名 | 回调参数 | 说明 |
|
||||
| ---------------- | ----------------------- | ------------------------------ |
|
||||
| `view:mounted` | `{ view: CellView }` | 节点被挂载到画布上时触发。 |
|
||||
| `view:unmounted` | `{ view: CellView }` | 节点从画布上卸载时触发。 |
|
||||
|
||||
```ts
|
||||
graph.on("view:mounted", ({ view }) => {});
|
||||
graph.on("view:unmounted", ({ view }) => {});
|
||||
```
|
||||
|
@ -18,6 +18,10 @@ redirect_from:
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-angular-shape` 以支持将 Angular 的组件/模板作为节点进行渲染。
|
||||
|
||||
:::warning{title=注意:}
|
||||
需要注意的是,x6 的版本要和 x6-angular-shape 的版本匹配,也就是两个包需要用同一个大版本。
|
||||
:::
|
||||
|
||||
### Component 渲染
|
||||
|
||||
```ts
|
||||
|
@ -17,6 +17,11 @@ redirect_from:
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-react-shape` 来使用 React 渲染节点。
|
||||
|
||||
:::warning{title=注意:}
|
||||
需要注意的是,x6 的版本要和 x6-react-shape 的版本匹配,也就是两个包需要用同一个大版本。
|
||||
:::
|
||||
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-react-shape";
|
||||
|
||||
|
@ -17,6 +17,11 @@ redirect_from:
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-vue-shape` 来使用 Vue 组件渲染节点。
|
||||
|
||||
:::warning{title=注意:}
|
||||
需要注意的是,x6 的版本要和 x6-vue-shape 的版本匹配,也就是两个包需要用同一个大版本。
|
||||
:::
|
||||
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div class="app-content">
|
||||
|
@ -55,6 +55,17 @@ graph.use(
|
||||
|
||||
## 配置
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### graph.createTransformWidget(node: Node)
|
||||
|
||||
给节点创建widget
|
||||
|
||||
### graph.clearTransformWidgets()
|
||||
|
||||
清除所有widget
|
||||
|
||||
### 调整尺寸
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 必选 | 描述 |
|
||||
|
@ -48,11 +48,13 @@ const graph = new Graph({
|
||||
connectionPoint: 'anchor',
|
||||
},
|
||||
})
|
||||
graph.use(new Transform({
|
||||
rotating: {
|
||||
enabled: true,
|
||||
}
|
||||
}))
|
||||
graph.use(
|
||||
new Transform({
|
||||
rotating: {
|
||||
enabled: true,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
Graph.registerConnector(
|
||||
'curve',
|
||||
|
@ -1,51 +1,51 @@
|
||||
import { Graph, Shape } from "@antv/x6";
|
||||
import { Graph, Shape } from '@antv/x6'
|
||||
|
||||
Shape.Rect.config({
|
||||
attrs: {
|
||||
body: {
|
||||
fill: "#f5f5f5",
|
||||
stroke: "#d9d9d9",
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
ports: {
|
||||
groups: {
|
||||
in: {
|
||||
position: { name: "top" },
|
||||
position: { name: 'top' },
|
||||
},
|
||||
out: {
|
||||
position: { name: "bottom" },
|
||||
position: { name: 'bottom' },
|
||||
},
|
||||
},
|
||||
},
|
||||
portMarkup: [
|
||||
{
|
||||
tagName: "circle",
|
||||
selector: "portBody",
|
||||
tagName: 'circle',
|
||||
selector: 'portBody',
|
||||
attrs: {
|
||||
r: 5,
|
||||
magnet: true,
|
||||
stroke: "#31d0c6",
|
||||
fill: "#fff",
|
||||
stroke: '#31d0c6',
|
||||
fill: '#fff',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
const magnetAvailabilityHighlighter = {
|
||||
name: "stroke",
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 3,
|
||||
attrs: {
|
||||
strokeWidth: 3,
|
||||
stroke: "#52c41a",
|
||||
stroke: '#52c41a',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById("container"),
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
highlighting: {
|
||||
magnetAvailable: magnetAvailabilityHighlighter,
|
||||
@ -57,24 +57,24 @@ const graph = new Graph({
|
||||
allowNode: false,
|
||||
highlight: true,
|
||||
validateMagnet({ magnet }) {
|
||||
return magnet.getAttribute("port-group") !== "in";
|
||||
return magnet.getAttribute('port-group') !== 'in'
|
||||
},
|
||||
|
||||
validateConnection({ sourceMagnet, targetMagnet }) {
|
||||
// 只能从输出连接桩创建连接
|
||||
if (!sourceMagnet || sourceMagnet.getAttribute("port-group") === "in") {
|
||||
return false;
|
||||
if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
|
||||
return false
|
||||
}
|
||||
|
||||
// 只能连接到输入连接桩
|
||||
if (!targetMagnet || targetMagnet.getAttribute("port-group") !== "in") {
|
||||
return false;
|
||||
if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
|
||||
return false
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
x: 40,
|
||||
@ -82,12 +82,12 @@ const source = graph.addNode({
|
||||
width: 100,
|
||||
height: 40,
|
||||
ports: [
|
||||
{ id: "in-1", group: "in" },
|
||||
{ id: "in-2", group: "in" },
|
||||
{ id: "out-1", group: "out" },
|
||||
{ id: "out-2", group: "out" },
|
||||
{ id: 'in-1', group: 'in' },
|
||||
{ id: 'in-2', group: 'in' },
|
||||
{ id: 'out-1', group: 'out' },
|
||||
{ id: 'out-2', group: 'out' },
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
const target = graph.addNode({
|
||||
x: 140,
|
||||
@ -95,12 +95,12 @@ const target = graph.addNode({
|
||||
width: 100,
|
||||
height: 40,
|
||||
ports: [
|
||||
{ id: "in-1", group: "in" },
|
||||
{ id: "in-2", group: "in" },
|
||||
{ id: "out-1", group: "out" },
|
||||
{ id: "out-2", group: "out" },
|
||||
{ id: 'in-1', group: 'in' },
|
||||
{ id: 'in-2', group: 'in' },
|
||||
{ id: 'out-1', group: 'out' },
|
||||
{ id: 'out-2', group: 'out' },
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
x: 320,
|
||||
@ -108,34 +108,34 @@ graph.addNode({
|
||||
width: 100,
|
||||
height: 40,
|
||||
ports: [
|
||||
{ id: "in-1", group: "in" },
|
||||
{ id: "in-2", group: "in" },
|
||||
{ id: "out-1", group: "out" },
|
||||
{ id: "out-2", group: "out" },
|
||||
{ id: 'in-1', group: 'in' },
|
||||
{ id: 'in-2', group: 'in' },
|
||||
{ id: 'out-1', group: 'out' },
|
||||
{ id: 'out-2', group: 'out' },
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source: { cell: source.id, port: "out-2" },
|
||||
target: { cell: target.id, port: "in-1" },
|
||||
});
|
||||
source: { cell: source.id, port: 'out-2' },
|
||||
target: { cell: target.id, port: 'in-1' },
|
||||
})
|
||||
|
||||
graph.on("edge:mouseenter", ({ cell }) => {
|
||||
graph.on('edge:mouseenter', ({ cell }) => {
|
||||
cell.addTools([
|
||||
{
|
||||
name: "source-arrowhead",
|
||||
name: 'source-arrowhead',
|
||||
},
|
||||
{
|
||||
name: "target-arrowhead",
|
||||
name: 'target-arrowhead',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: "red",
|
||||
fill: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
])
|
||||
})
|
||||
|
||||
graph.on("edge:mouseleave", ({ cell }) => {
|
||||
cell.removeTools();
|
||||
});
|
||||
graph.on('edge:mouseleave', ({ cell }) => {
|
||||
cell.removeTools()
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Graph, Node, Color } from '@antv/x6'
|
||||
import { Graph, Color } from '@antv/x6'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
|
||||
const MyComponent = ({ node }) => {
|
||||
@ -26,7 +26,7 @@ register({
|
||||
width: 120,
|
||||
height: 50,
|
||||
effect: ['color'],
|
||||
component: MyComponent
|
||||
component: MyComponent,
|
||||
})
|
||||
|
||||
const graph = new Graph({
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Graph } from "@antv/x6";
|
||||
import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById("container"),
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
});
|
||||
})
|
||||
|
||||
// 文档:https://x6.antv.vision/zh/docs/tutorial/basic/port
|
||||
|
||||
@ -14,8 +14,8 @@ const rect = graph.addNode({
|
||||
height: 180,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: "#f5f5f5",
|
||||
stroke: "#d9d9d9",
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
@ -26,50 +26,50 @@ const rect = graph.addNode({
|
||||
circle: {
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: "#31d0c6",
|
||||
fill: "#fff",
|
||||
stroke: '#31d0c6',
|
||||
fill: '#fff',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{ id: "port1", group: "group1" },
|
||||
{ id: "port2", group: "group1" },
|
||||
{ id: "port3", group: "group1" },
|
||||
{ id: 'port1', group: 'group1' },
|
||||
{ id: 'port2', group: 'group1' },
|
||||
{ id: 'port3', group: 'group1' },
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source: { x: 40, y: 150 },
|
||||
target: {
|
||||
cell: rect,
|
||||
port: "port1", // 连接桩 ID
|
||||
port: 'port1', // 连接桩 ID
|
||||
},
|
||||
attrs: {
|
||||
line: { stroke: "#d9d9d9" },
|
||||
line: { stroke: '#d9d9d9' },
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source: { x: 40, y: 150 },
|
||||
target: {
|
||||
cell: rect,
|
||||
port: "port2", // 连接桩 ID
|
||||
port: 'port2', // 连接桩 ID
|
||||
},
|
||||
attrs: {
|
||||
line: { stroke: "#d9d9d9" },
|
||||
line: { stroke: '#d9d9d9' },
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source: { x: 40, y: 150 },
|
||||
target: {
|
||||
cell: rect,
|
||||
port: "port3", // 连接桩 ID
|
||||
port: 'port3', // 连接桩 ID
|
||||
},
|
||||
attrs: {
|
||||
line: { stroke: "#d9d9d9" },
|
||||
line: { stroke: '#d9d9d9' },
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Graph } from "@antv/x6";
|
||||
import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById("container"),
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
});
|
||||
})
|
||||
|
||||
// 文档:https://x6.antv.vision/zh/docs/tutorial/basic/port
|
||||
|
||||
@ -14,39 +14,39 @@ const rect = graph.addNode({
|
||||
height: 180,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: "#f5f5f5",
|
||||
stroke: "#d9d9d9",
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
ports: [
|
||||
// 默认样式
|
||||
{ id: "port1" },
|
||||
{ id: 'port1' },
|
||||
// 自定义连接桩样式
|
||||
{
|
||||
id: "port2",
|
||||
id: 'port2',
|
||||
attrs: {
|
||||
circle: {
|
||||
magnet: true,
|
||||
r: 8,
|
||||
stroke: "#31d0c6",
|
||||
fill: "#fff",
|
||||
stroke: '#31d0c6',
|
||||
fill: '#fff',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
rect.addPort({
|
||||
id: "port3",
|
||||
id: 'port3',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: "#31d0c6",
|
||||
fill: "#fff",
|
||||
stroke: '#31d0c6',
|
||||
fill: '#fff',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Graph } from "@antv/x6";
|
||||
import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById("container"),
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
});
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
x: 100,
|
||||
@ -12,8 +12,8 @@ graph.addNode({
|
||||
height: 120,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: "#f5f5f5",
|
||||
stroke: "#d9d9d9",
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
@ -24,37 +24,37 @@ graph.addNode({
|
||||
circle: {
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: "#31d0c6",
|
||||
stroke: '#31d0c6',
|
||||
strokeWidth: 2,
|
||||
fill: "#fff",
|
||||
fill: '#fff',
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fill: "#888",
|
||||
fill: '#888',
|
||||
},
|
||||
},
|
||||
// 文档:https://x6.antv.vision/zh/docs/api/registry/port-layout#absolute
|
||||
position: {
|
||||
name: "absolute",
|
||||
name: 'absolute',
|
||||
},
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: "port1",
|
||||
group: "group1",
|
||||
id: 'port1',
|
||||
group: 'group1',
|
||||
// 通过 args 指定绝对位置
|
||||
args: {
|
||||
x: 0,
|
||||
y: 60,
|
||||
},
|
||||
attrs: {
|
||||
text: { text: "{ x: 0, y: 60 }" },
|
||||
text: { text: '{ x: 0, y: 60 }' },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "port2",
|
||||
group: "group1",
|
||||
id: 'port2',
|
||||
group: 'group1',
|
||||
// 通过 args 指定绝对位置和连接桩的旋转角度
|
||||
args: {
|
||||
x: 0.6,
|
||||
@ -64,40 +64,40 @@ graph.addNode({
|
||||
// 自定义连接桩渲染的 SVG
|
||||
markup: [
|
||||
{
|
||||
tagName: "path",
|
||||
selector: "path",
|
||||
tagName: 'path',
|
||||
selector: 'path',
|
||||
},
|
||||
],
|
||||
zIndex: 10,
|
||||
attrs: {
|
||||
path: {
|
||||
d: "M -6 -8 L 0 8 L 6 -8 Z",
|
||||
d: 'M -6 -8 L 0 8 L 6 -8 Z',
|
||||
magnet: true,
|
||||
fill: "red",
|
||||
fill: 'red',
|
||||
},
|
||||
text: {
|
||||
text: "{ x: 0.6, y: 32, angle: 45 }",
|
||||
fill: "red",
|
||||
text: '{ x: 0.6, y: 32, angle: 45 }',
|
||||
fill: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "port3",
|
||||
group: "group1",
|
||||
id: 'port3',
|
||||
group: 'group1',
|
||||
// 通过 args 指定绝对位置
|
||||
args: {
|
||||
x: "100%",
|
||||
y: "100%",
|
||||
x: '100%',
|
||||
y: '100%',
|
||||
},
|
||||
attrs: {
|
||||
text: { text: "{ x: '100%', y: '100%' }" },
|
||||
},
|
||||
label: {
|
||||
position: {
|
||||
name: "right",
|
||||
name: 'right',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Graph, Node, Path, Cell } from '@antv/x6'
|
||||
import { Graph, Path, Cell } from '@antv/x6'
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
import insertCss from 'insert-css'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
@ -27,12 +27,12 @@ const AlgoNode = (props) => {
|
||||
|
||||
return (
|
||||
<div className={`node ${status}`}>
|
||||
<img src={image.logo} />
|
||||
<img src={image.logo} alt="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} />}
|
||||
{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>
|
||||
)
|
||||
@ -71,8 +71,7 @@ register({
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
Graph.registerEdge(
|
||||
'dag-edge',
|
||||
@ -234,14 +233,16 @@ const graph: Graph = new Graph({
|
||||
},
|
||||
},
|
||||
})
|
||||
graph.use(new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberEdge: true,
|
||||
rubberNode: true,
|
||||
modifiers: 'shift',
|
||||
rubberband: true,
|
||||
}))
|
||||
graph.use(
|
||||
new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberEdge: true,
|
||||
rubberNode: true,
|
||||
modifiers: 'shift',
|
||||
rubberband: true,
|
||||
}),
|
||||
)
|
||||
|
||||
graph.on('edge:connected', ({ edge }) => {
|
||||
edge.attr({
|
||||
@ -287,7 +288,7 @@ const showNodeStatus = async (statusList: NodeStatus[][]) => {
|
||||
const data = node.getData() as NodeStatus
|
||||
node.setData({
|
||||
...data,
|
||||
status: status,
|
||||
status,
|
||||
})
|
||||
})
|
||||
setTimeout(() => {
|
||||
|
Reference in New Issue
Block a user