Compare commits
89 Commits
@antv/x6-e
...
@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 | |||
d72ff80be7 | |||
1a22248945 | |||
5d68501568 | |||
1de8ebe77a | |||
42011b7bb2 | |||
3bb76edd2e | |||
05fd60952e | |||
0138ef02ea | |||
2685e331bb | |||
ab0c7fe8f2 | |||
c76a23b534 | |||
2285e5592e | |||
8ebd6dfd76 | |||
a1d86424cf | |||
309b5a7ff7 | |||
5338b73861 | |||
90f5912529 | |||
3cd75ec40e | |||
1904e28f77 | |||
75c878009e | |||
ece81529bb | |||
94a7f85882 | |||
11ae288eb0 | |||
3cc8b764b1 | |||
5758ef80ef | |||
3811a6c0b2 | |||
672f104991 | |||
2571cb4ceb | |||
d83bcea863 | |||
38bdf65dde | |||
f5db2bb415 | |||
a3aa2a0da2 | |||
2bce01dee8 | |||
a30b6632a0 | |||
7656b38735 | |||
d953a732b3 | |||
6317493347 | |||
8fc0b72b66 | |||
18fca29bd7 | |||
7e61014b65 | |||
8dd2b66633 | |||
76fb1acf74 | |||
709a141e28 | |||
2ee81fd94b | |||
054eb998fa | |||
e32227ae31 | |||
278b798c0a | |||
c4e11dc98f | |||
df8466aa33 | |||
1b958d626f | |||
946582c242 | |||
482d77ad09 | |||
3103c11991 | |||
3c9093f3ec | |||
8a89caab27 | |||
ed999c630c | |||
34bcd12038 | |||
9138978918 | |||
46f4c8ac2a | |||
7519b11e66 | |||
5882b6a599 | |||
9781fb48f5 | |||
c8a03ed2ba | |||
b944419572 | |||
bebc5652d1 | |||
8daa2c9b98 |
.github/workflows
backup
ci.ymlcodeql.ymlconfig
create-issue-branch.ymldeploy-sites.ymlpr-label-status.ymlpreview.ymlreport-monthly.ymlreport-weekly.ymlstale.ymlsync-labels.ymlsync-to-gitee.ymlexamples/x6-example-features
package.jsonpackages
x6-angular-shape
x6-common
x6-devtool
.gitignoreREADME.md
devtools
package.jsonui
webpack.config.jsx6-geometry
x6-plugin-clipboard
x6-plugin-dnd
x6-plugin-export
x6-plugin-history
x6-plugin-keyboard
x6-plugin-minimap
x6-plugin-scroller
x6-plugin-selection
x6-plugin-snapline
x6-plugin-stencil
x6-plugin-transform
x6-react-components
x6-react-shape
x6-vue-shape
x6
CHANGELOG.mdLICENSEpackage.json
src
graph
model
registry
attr
background
connection-point
connection-strategy
connector
edge-anchor
filter
grid
highlighter
marker
node-anchor
port-label-layout
port-layout
registry.tsrouter
tool
renderer
view
sites/x6-sites
.dumi/theme/locales
.dumirc.ts.gitignoreCHANGELOG.mddocs
api
temp
tutorial
examples
edge
node
custom-node/demo
native-node/demo
port/demo
showcase/practices/demo
src/tutorial
basic
edge
connector
custom-marker
labels
native-marker
prop
registry
router
vertices
event/custom-click
graph
auto-resize
background-grid
panning-mousewheel
transform
interacting
connecting
embedding
highlighting
interacting
validate
node
ports
serialization/to-json
getting-started
intermediate
connection-point/multi
group
collapsable
embed-edge
expand-shrink
restrict
html
react
tools
plugins
clipboard
dnd
history
keyboard
minimap
scroller
selection
snapline
stencil
transform
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
|
||||
|
@ -8,12 +8,16 @@ Draco <Draco.coder@gmail.com>
|
||||
Eve-Sama <17764594863@163.com>
|
||||
Eve-Sama <948832626@qq.com>
|
||||
Gossypol <31892817+gossypol@users.noreply.github.com>
|
||||
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>
|
||||
Ko.Rei <32183014+Ko-Rei@users.noreply.github.com>
|
||||
Limbo <49612796+JUST-Limbo@users.noreply.github.com>
|
||||
Lixu <37231473+wflixu@users.noreply.github.com>
|
||||
Lloyd Zhou <lloydzhou@users.noreply.github.com>
|
||||
@ -57,6 +61,8 @@ kelin.zrh <34393362+AricZhu@users.noreply.github.com>
|
||||
kingshuaishuai <ken.wang@mrs.ai>
|
||||
kio <1421104933@qq.com>
|
||||
lijing666 <lijing241@yeah.net>
|
||||
linkun <33945539+linkun-wang@users.noreply.github.com>
|
||||
linkun <linkun0922@163.com>
|
||||
lopn <lopnxrp@126.com>
|
||||
luchunwei <luchunwei@gmail.com>
|
||||
luzhuang <364439895@qq.com>
|
||||
@ -66,6 +72,7 @@ newbyvector <vectorse@126.com>
|
||||
niexq <1879633916@qq.com>
|
||||
niexq <niexq@firstgrid.cn>
|
||||
njshuisheng <34205271+njshuisheng@users.noreply.github.com>
|
||||
nobugforever <84232410+mengYu-Jin@users.noreply.github.com>
|
||||
pengxingjian.pxj <pengxingjian.pxj@alibaba-inc.com>
|
||||
pfdgithub <pfdgithub@users.noreply.github.com>
|
||||
qingchi <qinky94@163.com>
|
||||
@ -78,6 +85,7 @@ wenbei <38773084+wb-wenbei@users.noreply.github.com>
|
||||
wgf <34190465+evelope@users.noreply.github.com>
|
||||
wind X <35559153+XueMeijing@users.noreply.github.com>
|
||||
wjqsummer <52412389+wjqsummer@users.noreply.github.com>
|
||||
wseven7677 <caoyu_92@126.com>
|
||||
wtzeng1 <wtzeng1@gmail.com>
|
||||
x6-bot <x6-bot@users.noreply.github.com>
|
||||
xrkffgg <xrkffgg@gmail.com>
|
||||
|
224
CONTRIBUTORS.svg
224
CONTRIBUTORS.svg
File diff suppressed because one or more lines are too long
Before (image error) Size: 13 MiB After (image error) Size: 14 MiB |
@ -90,6 +90,7 @@ graph.addEdge({
|
||||
- [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)
|
||||
- [awesome-x6](https://github.com/lloydzhou/awesome-x6)
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -89,6 +89,7 @@ graph.addEdge({
|
||||
- [更新日志](https://www.yuque.com/antv/x6/bbfu6r)
|
||||
- [常见问题](https://www.yuque.com/antv/x6/tox1ukbz5cw57qfy)
|
||||
- [CodeSanbox 模板](https://codesandbox.io/s/mo-ban-wchooy?file=/src/App.tsx)
|
||||
- [awesome-x6](https://github.com/lloydzhou/awesome-x6)
|
||||
|
||||
## 本地开发
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-example-features [2.1.1](https://github.com/antvis/X6/compare/@antv/x6-example-features@2.1.0...@antv/x6-example-features@2.1.1) (2023-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* mindmap demo duplicate node id, close [#3256](https://github.com/antvis/X6/issues/3256) ([#3257](https://github.com/antvis/X6/issues/3257)) ([c510756](https://github.com/antvis/X6/commit/c510756fe4e96c8e7471c2fb558e6019ec69b057))
|
||||
|
||||
# @antv/x6-example-features [2.1.0](https://github.com/antvis/X6/compare/@antv/x6-example-features@2.0.3...@antv/x6-example-features@2.1.0) (2023-02-17)
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@antv/x6-example-features",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"scripts": {
|
||||
"start": "umi dev",
|
||||
"build": "umi build",
|
||||
|
@ -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'
|
||||
|
12
package.json
12
package.json
@ -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",
|
||||
@ -51,7 +51,7 @@
|
||||
"prettier --write --ignore-unknown"
|
||||
],
|
||||
"*.less": [
|
||||
"stylelint --syntax less --fix"
|
||||
"stylelint --customSyntax postcss-less --fix"
|
||||
],
|
||||
"*.js": [
|
||||
"prettier --write"
|
||||
@ -159,9 +159,13 @@
|
||||
"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"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=7"
|
||||
}
|
||||
}
|
||||
|
21
packages/x6-angular-shape/LICENSE
Normal file
21
packages/x6-angular-shape/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
136
packages/x6-angular-shape/README.md
Normal file
136
packages/x6-angular-shape/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
# @antv/x6-angular-shape
|
||||
|
||||
## 渲染节点
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-angular-shape` 以支持将 Angular 的组件/模板作为节点进行渲染。
|
||||
|
||||
### Component 渲染
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'app-node',
|
||||
templateUrl: './node.component.html',
|
||||
styleUrls: ['./node.component.scss'],
|
||||
})
|
||||
export class NodeComponent implements AfterViewInit, OnChanges {
|
||||
@Input() value: string;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-component-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: NodeComponent,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-component-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
// Input 的参数必须放在这里
|
||||
ngArguments: {
|
||||
value: '糟糕糟糕 Oh my god',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### TemplateRef 渲染
|
||||
|
||||
```html
|
||||
<ng-template #template let-data="ngArguments">
|
||||
<section class="template-container">
|
||||
<span class="value">{{ data.value }}</span>
|
||||
</section>
|
||||
</ng-template>
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
@ViewChild('template') template: TemplateRef<{}>;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-template-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: this.template,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-template-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
ngArguments: {
|
||||
value: '魔法怎么失灵啦',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 更新节点
|
||||
|
||||
无论是使用 Component 还是 TemplateRef, 都是一样的更新方式.
|
||||
```ts
|
||||
node.setData({
|
||||
ngArguments: {
|
||||
value: '晚风中闪过 几帧从前啊',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 有 demo 吗?
|
||||
|
||||
有的, 因为X6渲染节点部分与框架是解耦的. 因此 `x6-angular-shape` 包并非是直接在源代码里改的, 而是在一个单独的Angular环境中开发的. 该 demo 还提供了多种节点类型的性能测试, 详情请参考[Eve-Sama/x6-angular-shape](https://github.com/Eve-Sama/x6-angular-shape)、[X6与G6的性能对比, 以及X6多节点类型下的FPS临界点讨论](https://github.com/antvis/X6/issues/3266)
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为什么输入属性不能直接放在 data 中而需要放在 ngArguments 中? 且为什么不叫 ngInput?
|
||||
|
||||
因为并非所有 `node.data` 中的属性都是输入属性, 所以遍历 `data` 中的所有属性进行赋值是不合适的. 至于为什么叫 `ngArguments` 主要是有两点考虑.
|
||||
- 1.x版本中已经这么用了, 沿用该API可以降低用户升级成本
|
||||
- `Input` 的概念其实是来自 `Component`, 而 `TemplateRef` 中是 `context`, 在二者的基础上抽象一个 `Arguments` 的概念更通用些
|
||||
|
||||
### 2.x版本的 x6-angular-shape 相比较1.x版本有什么新特性吗?
|
||||
|
||||
实现思路其实和之前是差不多的. 但是确实有几个点值得一提.
|
||||
|
||||
#### demo更聚焦
|
||||
|
||||
1.x版本的 demo 除了渲染组件外, 还写了连线、清除等一系列案例. 看似扩展, 实则眼花缭乱. 作为 `x6-angular-shape`的 demo, 2.x版本更加聚焦, 更加聚焦于shape的使用与性能测试等, 与插件无关的内容请查看X6官网.
|
||||
|
||||
#### 功能更稳定
|
||||
|
||||
在1.x版本中, 虽然实现了功能, 但是使用场景的思考不够全面. 比如`ngArguments`的变化, 对 `TemplateRef`的场景并不生效. 虽然对`Component`生效但是无法触发`ngOnChanges`. 而在新版本中, 这些问题都将不复存在.
|
||||
|
||||
### 版本要求
|
||||
|
||||
你的Angular版本至少在14及以上才可以. 14以下需要用 hack 的方式实现一些特性, 比较麻烦. 暂时不提供, 如有需要可提issue, 我再专门介绍下如何实现.
|
67
packages/x6-angular-shape/package.json
Normal file
67
packages/x6-angular-shape/package.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "@antv/x6-angular-shape",
|
||||
"version": "2.0.0",
|
||||
"description": "X6 shape for rendering angular components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"unpkg": "dist/index.js",
|
||||
"jsdelivr": "dist/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"shape",
|
||||
"angular",
|
||||
"render",
|
||||
"x6",
|
||||
"antv"
|
||||
],
|
||||
"scripts": {
|
||||
"clean:turbo": "rss",
|
||||
"clean:build": "rss",
|
||||
"clean:coverage": "rss",
|
||||
"clean": "rss",
|
||||
"build:esm": "rss",
|
||||
"build:cjs": "rss",
|
||||
"build:umd": "rss",
|
||||
"build:dev": "rss",
|
||||
"build:watch": "rss",
|
||||
"build:watch:esm": "rss",
|
||||
"build:watch:cjs": "rss",
|
||||
"build": "rss",
|
||||
"prebuild": "rss",
|
||||
"test": "rss",
|
||||
"coveralls": "rss",
|
||||
"pretest": "rss"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x",
|
||||
"@angular/core": ">= 14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antv/x6": "^2.x",
|
||||
"@angular/core": ">= 14"
|
||||
},
|
||||
"author": {
|
||||
"name": "Eve-Sama",
|
||||
"email": "948832626@qq.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://x6.antv.antgroup.com/tutorial/intermediate/angular",
|
||||
"bugs": {
|
||||
"url": "https://github.com/antvis/x6/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/antvis/x6.git",
|
||||
"directory": "packages/x6-angular-shape"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org"
|
||||
}
|
||||
}
|
3
packages/x6-angular-shape/src/index.ts
Normal file
3
packages/x6-angular-shape/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './node'
|
||||
export * from './view'
|
||||
export * from './registry'
|
102
packages/x6-angular-shape/src/node.ts
Normal file
102
packages/x6-angular-shape/src/node.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { Node, Markup, ObjectExt } from '@antv/x6'
|
||||
|
||||
export class AngularShape<
|
||||
Properties extends AngularShape.Properties = AngularShape.Properties,
|
||||
> extends Node<Properties> {}
|
||||
|
||||
export namespace AngularShape {
|
||||
export type Primer =
|
||||
| 'rect'
|
||||
| 'circle'
|
||||
| 'path'
|
||||
| 'ellipse'
|
||||
| 'polygon'
|
||||
| 'polyline'
|
||||
|
||||
export interface Properties extends Node.Properties {
|
||||
primer?: Primer
|
||||
}
|
||||
}
|
||||
|
||||
export namespace AngularShape {
|
||||
function getMarkup(primer?: Primer) {
|
||||
const markup: Markup.JSONMarkup[] = []
|
||||
const content = Markup.getForeignObjectMarkup()
|
||||
|
||||
if (primer) {
|
||||
markup.push(
|
||||
...[
|
||||
{
|
||||
tagName: primer,
|
||||
selector: 'body',
|
||||
},
|
||||
content,
|
||||
],
|
||||
)
|
||||
} else {
|
||||
markup.push(content)
|
||||
}
|
||||
|
||||
return markup
|
||||
}
|
||||
|
||||
AngularShape.config<Properties>({
|
||||
view: 'angular-shape-view',
|
||||
markup: getMarkup(),
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'none',
|
||||
stroke: 'none',
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
},
|
||||
fo: {
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
},
|
||||
},
|
||||
propHooks(metadata: Properties) {
|
||||
if (metadata.markup == null) {
|
||||
const primer = metadata.primer
|
||||
if (primer) {
|
||||
metadata.markup = getMarkup(primer)
|
||||
|
||||
let attrs = {}
|
||||
switch (primer) {
|
||||
case 'circle':
|
||||
attrs = {
|
||||
refCx: '50%',
|
||||
refCy: '50%',
|
||||
refR: '50%',
|
||||
}
|
||||
break
|
||||
case 'ellipse':
|
||||
attrs = {
|
||||
refCx: '50%',
|
||||
refCy: '50%',
|
||||
refRx: '50%',
|
||||
refRy: '50%',
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
metadata.attrs = ObjectExt.merge(
|
||||
{},
|
||||
{
|
||||
body: {
|
||||
refWidth: null,
|
||||
refHeight: null,
|
||||
...attrs,
|
||||
},
|
||||
},
|
||||
metadata.attrs || {},
|
||||
)
|
||||
}
|
||||
}
|
||||
return metadata
|
||||
},
|
||||
})
|
||||
|
||||
Node.registry.register('angular-shape', AngularShape, true)
|
||||
}
|
32
packages/x6-angular-shape/src/registry.ts
Normal file
32
packages/x6-angular-shape/src/registry.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Injector, TemplateRef, Type } from '@angular/core'
|
||||
import { Graph, Node } from '@antv/x6'
|
||||
|
||||
export type Content = TemplateRef<any> | Type<any>
|
||||
|
||||
export type AngularShapeConfig = Node.Properties & {
|
||||
shape: string
|
||||
injector: Injector
|
||||
content: Content
|
||||
}
|
||||
|
||||
export const registerInfo: Map<
|
||||
string,
|
||||
{
|
||||
injector: Injector
|
||||
content: Content
|
||||
}
|
||||
> = new Map()
|
||||
|
||||
export function register(config: AngularShapeConfig) {
|
||||
const { shape, injector, content, ...others } = config
|
||||
registerInfo.set(shape, { injector, content })
|
||||
|
||||
Graph.registerNode(
|
||||
shape,
|
||||
{
|
||||
inherit: 'angular-shape',
|
||||
...others,
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
124
packages/x6-angular-shape/src/view.ts
Normal file
124
packages/x6-angular-shape/src/view.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import {
|
||||
ComponentRef,
|
||||
EmbeddedViewRef,
|
||||
TemplateRef,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core'
|
||||
import { Dom, NodeView } from '@antv/x6'
|
||||
import { AngularShape } from './node'
|
||||
import { Content, registerInfo } from './registry'
|
||||
|
||||
export class AngularShapeView extends NodeView<AngularShape> {
|
||||
getNodeContainer(): HTMLDivElement {
|
||||
return this.selectors && (this.selectors.foContent as HTMLDivElement)
|
||||
}
|
||||
|
||||
override confirmUpdate(flag: number): number {
|
||||
const ret = super.confirmUpdate(flag)
|
||||
return this.handleAction(ret, AngularShapeView.action, () =>
|
||||
this.renderAngularContent(),
|
||||
)
|
||||
}
|
||||
|
||||
private getNgArguments(): Record<string, any> {
|
||||
const input = (this.cell.data?.ngArguments as Record<string, any>) || {}
|
||||
return input
|
||||
}
|
||||
|
||||
/** 当执行 node.setData() 时需要对实例设置新的输入值 */
|
||||
private setInstanceInput(
|
||||
content: Content,
|
||||
ref: EmbeddedViewRef<any> | ComponentRef<any>,
|
||||
): void {
|
||||
const ngArguments = this.getNgArguments()
|
||||
if (content instanceof TemplateRef) {
|
||||
const embeddedViewRef = ref as EmbeddedViewRef<any>
|
||||
embeddedViewRef.context = { ngArguments }
|
||||
} else {
|
||||
const componentRef = ref as ComponentRef<any>
|
||||
Object.keys(ngArguments).forEach((v) =>
|
||||
componentRef.setInput(v, ngArguments[v]),
|
||||
)
|
||||
componentRef.changeDetectorRef.detectChanges()
|
||||
}
|
||||
}
|
||||
|
||||
protected renderAngularContent(): void {
|
||||
this.unmountAngularContent()
|
||||
const container = this.getNodeContainer()
|
||||
if (container) {
|
||||
const node = this.cell
|
||||
const { injector, content } = registerInfo.get(node.shape)!
|
||||
const viewContainerRef = injector.get(ViewContainerRef)
|
||||
if (content instanceof TemplateRef) {
|
||||
const ngArguments = this.getNgArguments()
|
||||
const embeddedViewRef = viewContainerRef.createEmbeddedView(content, {
|
||||
ngArguments,
|
||||
})
|
||||
embeddedViewRef.rootNodes.forEach((node) => container.appendChild(node))
|
||||
embeddedViewRef.detectChanges()
|
||||
node.on('change:data', () =>
|
||||
this.setInstanceInput(content, embeddedViewRef),
|
||||
)
|
||||
} else {
|
||||
const componentRef = viewContainerRef.createComponent(content)
|
||||
const insertNode = (componentRef.hostView as EmbeddedViewRef<any>)
|
||||
.rootNodes[0] as HTMLElement
|
||||
container.appendChild(insertNode)
|
||||
this.setInstanceInput(content, componentRef)
|
||||
node.on('change:data', () =>
|
||||
this.setInstanceInput(content, componentRef),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected unmountAngularContent(): HTMLDivElement {
|
||||
const container = this.getNodeContainer()
|
||||
container.innerHTML = ''
|
||||
return container
|
||||
}
|
||||
|
||||
override onMouseDown(e: Dom.MouseDownEvent, x: number, y: number) {
|
||||
const target = e.target as Element
|
||||
const tagName = target.tagName.toLowerCase()
|
||||
if (tagName === 'input') {
|
||||
const type = target.getAttribute('type')
|
||||
if (
|
||||
type == null ||
|
||||
[
|
||||
'text',
|
||||
'password',
|
||||
'number',
|
||||
'email',
|
||||
'search',
|
||||
'tel',
|
||||
'url',
|
||||
].includes(type)
|
||||
) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.onMouseDown(e, x, y)
|
||||
}
|
||||
|
||||
override unmount(): this {
|
||||
this.unmountAngularContent()
|
||||
super.unmount()
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export namespace AngularShapeView {
|
||||
export const action = 'angular' as any
|
||||
|
||||
AngularShapeView.config({
|
||||
bootstrap: [action],
|
||||
actions: {
|
||||
component: action,
|
||||
},
|
||||
})
|
||||
|
||||
NodeView.registry.register('angular-shape-view', AngularShapeView, true)
|
||||
}
|
3
packages/x6-angular-shape/tsconfig.json
Normal file
3
packages/x6-angular-shape/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
@ -1,3 +1,17 @@
|
||||
## @antv/x6-common [2.0.10](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.9...@antv/x6-common@2.0.10) (2023-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add textLength & lengthAdjust to CASE_SENSITIVE_ATTR ([#3281](https://github.com/antvis/x6/issues/3281)) ([76fb1ac](https://github.com/antvis/x6/commit/76fb1acf74b0f1c308f7c824d02c12244b7ac8f3))
|
||||
|
||||
## @antv/x6-common [2.0.8](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.7...@antv/x6-common@2.0.8) (2023-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix typo for dom event handlers ([#3255](https://github.com/antvis/x6/issues/3255)) ([9b4fa86](https://github.com/antvis/x6/commit/9b4fa86daa587fe8818f3615bc1e40738a0f2319))
|
||||
|
||||
## @antv/x6-common [2.0.6](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.5...@antv/x6-common@2.0.6) (2023-01-31)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-common",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.11",
|
||||
"description": "Basic toolkit for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"util",
|
||||
|
@ -6,6 +6,8 @@ export const CASE_SENSITIVE_ATTR = [
|
||||
'attributeName',
|
||||
'attributeType',
|
||||
'repeatCount',
|
||||
'textLength',
|
||||
'lengthAdjust',
|
||||
]
|
||||
|
||||
export type Attributes = { [key: string]: string | number | null | undefined }
|
||||
|
@ -1,4 +1,4 @@
|
||||
export { debounce } from 'lodash-es'
|
||||
export { debounce, throttle } from 'lodash-es'
|
||||
|
||||
type Fn = (...args: any[]) => any
|
||||
|
||||
|
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'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"geometry",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -11,7 +11,7 @@ export class Clipboard
|
||||
public options: Clipboard.Options
|
||||
public name = 'clipboard'
|
||||
|
||||
constructor(options: Clipboard.Options) {
|
||||
constructor(options: Clipboard.Options = { enabled: true }) {
|
||||
super()
|
||||
this.options = options
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -12,6 +12,10 @@ declare module '@antv/x6/lib/graph/graph' {
|
||||
undoAndCancel: (options?: KeyValue) => Graph
|
||||
canUndo: () => boolean
|
||||
canRedo: () => boolean
|
||||
getHistoryStackSize: () => number
|
||||
getUndoStackSize: () => number
|
||||
getRedoStackSize: () => number
|
||||
getUndoRemainSize: () => number
|
||||
cleanHistory: (options?: KeyValue) => Graph
|
||||
}
|
||||
}
|
||||
@ -107,3 +111,23 @@ Graph.prototype.cleanHistory = function (options?: KeyValue) {
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
Graph.prototype.getHistoryStackSize = function () {
|
||||
const history = this.getPlugin('history') as History
|
||||
return history.getSize()
|
||||
}
|
||||
|
||||
Graph.prototype.getUndoStackSize = function () {
|
||||
const history = this.getPlugin('history') as History
|
||||
return history.getUndoSize()
|
||||
}
|
||||
|
||||
Graph.prototype.getRedoStackSize = function () {
|
||||
const history = this.getPlugin('history') as History
|
||||
return history.getRedoSize()
|
||||
}
|
||||
|
||||
Graph.prototype.getUndoRemainSize = function () {
|
||||
const history = this.getPlugin('history') as History
|
||||
return history.getUndoRemainSize()
|
||||
}
|
||||
|
@ -127,6 +127,23 @@ export class History
|
||||
return this
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.stackSize
|
||||
}
|
||||
|
||||
getUndoRemainSize() {
|
||||
const ul = this.undoStack.length
|
||||
return this.stackSize - ul
|
||||
}
|
||||
|
||||
getUndoSize() {
|
||||
return this.undoStack.length
|
||||
}
|
||||
|
||||
getRedoSize() {
|
||||
return this.redoStack.length
|
||||
}
|
||||
|
||||
canUndo() {
|
||||
return !this.disabled && this.undoStack.length > 0
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -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
|
||||
|
@ -7,7 +7,7 @@ export class Keyboard extends Disposable {
|
||||
public name = 'keyboard'
|
||||
public options: KeyboardImpl.Options
|
||||
|
||||
constructor(options: KeyboardImpl.Options) {
|
||||
constructor(options: KeyboardImpl.Options = { enabled: true }) {
|
||||
super()
|
||||
this.options = options
|
||||
}
|
||||
@ -69,7 +69,6 @@ export class Keyboard extends Disposable {
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
unbindKey(keys: string | string[], action?: KeyboardImpl.Action) {
|
||||
this.keyboardImpl.off(keys, action)
|
||||
return this
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -36,7 +36,7 @@ export class Selection extends Basecoat<SelectionImpl.EventArgs> {
|
||||
return this.selectionImpl.cells
|
||||
}
|
||||
|
||||
constructor(options: Selection.Options) {
|
||||
constructor(options: Selection.Options = { enabled: true }) {
|
||||
super()
|
||||
this.options = ObjectExt.merge({}, Selection.defaultOptions, options)
|
||||
CssLoader.ensure(this.name, content)
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -8,7 +8,7 @@ export class Snapline extends Disposable {
|
||||
public options: Snapline.Options
|
||||
public name = 'snapline'
|
||||
|
||||
constructor(options: Snapline.Options) {
|
||||
constructor(options: Snapline.Options = { enabled: true }) {
|
||||
super()
|
||||
this.options = { tolerance: 10, ...options }
|
||||
CssLoader.ensure(this.name, content)
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-plugin-transform [2.1.6](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.5...@antv/x6-plugin-transform@2.1.6) (2023-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* transform active-handle class should remove when active removed ([#3298](https://github.com/antvis/x6/issues/3298)) ([709a141](https://github.com/antvis/x6/commit/709a141e28e9f25d54ece0ade353bd343ac0e55f))
|
||||
|
||||
## @antv/x6-plugin-transform [2.1.5](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.4...@antv/x6-plugin-transform@2.1.5) (2022-12-24)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-plugin-transform",
|
||||
"version": "2.1.5",
|
||||
"version": "2.1.6",
|
||||
"description": "transform plugin for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"plugin",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export class Transform extends Basecoat<Transform.EventArgs> {
|
||||
public name = 'transform'
|
||||
private disabled = false
|
||||
|
||||
constructor(public readonly options: Transform.Options) {
|
||||
constructor(public readonly options: Transform.Options = {}) {
|
||||
super()
|
||||
CssLoader.ensure(this.name, content)
|
||||
}
|
||||
@ -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()
|
||||
|
@ -493,7 +493,7 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
|
||||
Dom.removeClass(this.container, `${this.containerClassName}-active`)
|
||||
|
||||
if (this.handle) {
|
||||
Dom.removeClass(this.handle, `${this.containerClassName}-active`)
|
||||
Dom.removeClass(this.handle, `${this.containerClassName}-active-handle`)
|
||||
|
||||
const pos = this.handle.getAttribute(
|
||||
'data-position',
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"sideEffects": [
|
||||
"es/**/style/*",
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user