Compare commits
344 Commits
@antv/x6-s
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
e667300183 | |||
003491bd17 | |||
9565e27bde | |||
6e31b9650e | |||
cfc1b672e5 | |||
40f91fcda0 | |||
99a20381e1 | |||
72c95c9192 | |||
781eb3bdfd | |||
78179da0cd | |||
f9663278b6 | |||
37b71d18c2 | |||
623249c152 | |||
a431f520b2 | |||
13cd329f19 | |||
d633e1f781 | |||
a16d94c2e9 | |||
c071361da6 | |||
c5d19fd4ed | |||
4eea5efc85 | |||
c3c12b149c | |||
bc266fc216 | |||
23e9aa1544 | |||
6e87a6d270 | |||
cf395646f1 | |||
fa14f356ea | |||
0bbff8fcc7 | |||
3bb9bee3fa | |||
a87fb3b91e | |||
8e2e2b17ba | |||
06148e52d5 | |||
48ce40b581 | |||
b20cdf87bc | |||
3b3edb4f36 | |||
be8a9c1ee5 | |||
c3b02e5786 | |||
f4d1412efd | |||
acb60e5e64 | |||
45bb0b21be | |||
c6f953690d | |||
4dbc5e560e | |||
2bc15cb2c7 | |||
fb77e64ce0 | |||
705fbdb907 | |||
f02a90fd9a | |||
a228f30d77 | |||
d0609d54db | |||
b6fe9d2a52 | |||
ac3d5d9abb | |||
475ff7dad9 | |||
2279042b8d | |||
5ebb6d32f9 | |||
df6609ce5a | |||
6c2496ce36 | |||
9187f35d55 | |||
e399da4289 | |||
d700d006cb | |||
fe3b7ace50 | |||
018eafa07a | |||
0f83b1a89a | |||
75e1ee98bb | |||
f2e58f96ef | |||
6decb75c85 | |||
a769284074 | |||
17ae229971 | |||
f6475ac75f | |||
dd63fa7b02 | |||
84e363ef3c | |||
cf4cf1f010 | |||
b3f593335b | |||
0db56d0474 | |||
f29fe2d3e3 | |||
93490da29f | |||
f1b23d202a | |||
281209ac56 | |||
8169d423dc | |||
c1358c7255 | |||
16a57df181 | |||
36c0c62dfd | |||
8d0a8506ec | |||
c91a89f642 | |||
31be706335 | |||
f8df99a1eb | |||
a989de6325 | |||
fa66d3a514 | |||
a250071310 | |||
4641d39dd8 | |||
1b031d5339 | |||
b2461f10c1 | |||
b13d2f7842 | |||
7327daf9df | |||
26d37cdf2f | |||
80306218c8 | |||
928c008f54 | |||
cf010176a9 | |||
1a27a2a94a | |||
f2cae9637e | |||
3c5856d3f6 | |||
4d4a2eb2e5 | |||
fd5b0612c1 | |||
12ca0e1816 | |||
b767453742 | |||
6fcc1a0394 | |||
e35a7a9e2d | |||
5c722242d5 | |||
f19c848c52 | |||
58fe40c3e1 | |||
b0a2cdd3e8 | |||
2fb6eb0df4 | |||
101eac071a | |||
33152c3b8f | |||
540e3c2c53 | |||
0178e486aa | |||
df1f387ee3 | |||
f07574a302 | |||
3141593d6a | |||
9efe791233 | |||
b7878923b8 | |||
0afbbb507a | |||
ffbc7edbb5 | |||
339cade1b5 | |||
01318ece9a | |||
03a4546872 | |||
1d6c29402e | |||
2d3b365a22 | |||
f8f3421235 | |||
cabfa0b077 | |||
b92a23e74b | |||
6266d911a7 | |||
e6da6fb55f | |||
9488c0410e | |||
a505b19de0 | |||
f99f0c0406 | |||
1c2d637c76 | |||
e58a0cc87a | |||
7674edb02b | |||
5a4169a0ca | |||
4dc74f1645 | |||
c6800afdf2 | |||
331a4f3c23 | |||
90004eeebb | |||
cbd56e3dfe | |||
e271293e6f | |||
17dc1517f5 | |||
016a2be788 | |||
21a9739960 | |||
f3efd68edc | |||
9a356b30de | |||
92d6913411 | |||
678883fb54 | |||
eac458ce88 | |||
ff350883b5 | |||
264e1e4eab | |||
4356660123 | |||
8b8df8ce4f | |||
f84f7f0313 | |||
e9f41adfc9 | |||
09a2c14339 | |||
78e5274d48 | |||
0c2c1e1c6e | |||
ce24b9e608 | |||
9823c7e7ba | |||
548288c056 | |||
84c63871cf | |||
b5cc1dcd11 | |||
1afa724af1 | |||
743112d2c9 | |||
365839b26d | |||
9cc7737007 | |||
d9167a22f1 | |||
7a160d266a | |||
8cf1ed4841 | |||
2e10838360 | |||
45efc11dab | |||
dbd0219f0f | |||
eb3d0067d7 | |||
b3887ca247 | |||
c06b0e2881 | |||
2c79ef8863 | |||
ddad5e86fa | |||
103ed2e547 | |||
3e1daae5f8 | |||
dedd102202 | |||
00b75517f8 | |||
c7b5c1d6f1 | |||
e2a33f0915 | |||
c42a69ea2d | |||
7c2541807b | |||
ea058706bf | |||
3cf590797c | |||
79eb3084f2 | |||
a00f06cd11 | |||
a6c4509589 | |||
8ecfc86202 | |||
a9aa2b8db9 | |||
785a97210b | |||
ccc77552d0 | |||
6cc9ebf2da | |||
2c0477e351 | |||
ab255df459 | |||
bc81583e5d | |||
7eb9748f3f | |||
3b8dfcfc51 | |||
f4ea33afae | |||
d38baf112e | |||
1d6f138de0 | |||
ce15fbae18 | |||
90324fca58 | |||
09c6f2a142 | |||
dfa00c8795 | |||
c70021f1ea | |||
b0bc56d6fc | |||
fb10ef0879 | |||
543de1999d | |||
37e8c2242c | |||
78f05b6287 | |||
6037fdeb10 | |||
8835ee6a56 | |||
db6f49d65a | |||
01e911b5f8 | |||
377af16922 | |||
ef5388ed4a | |||
6e8422ebd2 | |||
8f136d12db | |||
38d28c0626 | |||
7716765910 | |||
2a05b02c4f | |||
7a5019028d | |||
a3fef50df3 | |||
e08c3a9bd7 | |||
ebee229402 | |||
51a512ae67 | |||
82e0aefc21 | |||
4cb3bea6b7 | |||
101e3f96b6 | |||
8c233a9419 | |||
2421fa3513 | |||
9684766150 | |||
075f54059e | |||
1eccc05f76 | |||
86b5a23630 | |||
161e702916 | |||
9a8fa8a925 | |||
0da7693f5b | |||
b92976a278 | |||
1d64938758 | |||
876e8b91bb | |||
01bb8105c9 | |||
6273fd55ac | |||
5010a94d14 | |||
aa65bfaa88 | |||
148d7d72bc | |||
0b1a298cb9 | |||
35aa68ba6f | |||
18f6d9bae3 | |||
0bd4429fb3 | |||
7d33889855 | |||
c5b80402dd | |||
9495b4c90d | |||
e0719054b5 | |||
c08d2ceb50 | |||
7f8fb69e21 | |||
8ff81807a7 | |||
ec5c67d84c | |||
ea01b1d3eb | |||
0b1e0c754b | |||
071ef37569 | |||
8b4602b980 | |||
cd1ee4a77c | |||
242316b459 | |||
2a35be764b | |||
f437269e6f | |||
7f300fe551 | |||
73dbd1ef58 | |||
ffa0431e35 | |||
f8490a029d | |||
b56fc2c3eb | |||
f3ef783b7d | |||
7d458bff3b | |||
89d5465db0 | |||
5edfc8885e | |||
ba370df246 | |||
506ab14595 | |||
837bbee715 | |||
b2e1315f79 | |||
6c76deefd2 | |||
9fa0f844c7 | |||
fa69ddbe68 | |||
fb3535dc75 | |||
20da5acb37 | |||
595f60597c | |||
9e759518c8 | |||
632b7dc078 | |||
2b651274a3 | |||
8f20c66b1d | |||
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 |
.changeset
.github
.husky
.npmrc.prettierignoreCODE_OF_CONDUCT.mdCONTRIBUTING.mdCONTRIBUTING.zh-CN.mdCONTRIBUTORSCONTRIBUTORS.svgLICENSEREADME.en-us.mdREADME.mdSECURITY.mdexamples/x6-example-features
CHANGELOG.mdpackage.json
package.jsonsrc
collaboration
pages
animation
auto-resize
basic
case
clipboard
history
keyboard
minimap
position
scroller
selection
shape/flowchart/shapes
snapline
tools
undo
v2
packages
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.mdpackage.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
shape
style
util
view
scripts
sites/x6-sites
.dumi
.dumirc.ts.gitignoreCHANGELOG.mdLEGAL.mddocs
api
graph
interacting
model
mvc
registry
temp
tutorial
about.zh.md
basic
devtool.zh.mdgetting-started.en.mdgetting-started.zh.mdintermediate
plugins
clipboard.zh.mddnd.zh.mdexport.zh.mdhistory.zh.mdkeyboard.zh.mdminimap.zh.mdscroller.zh.mdselection.zh.mdsnapline.zh.mdstencil.mdtransform.zh.md
update.zh.mdxflow
examples
edge
layout
node
custom-node/demo
native-node/demo
port/demo
tool/demo
showcase/practices/demo
public
src
api
attrs
edge-relative-position
edge-subelement-labels
ref-elem
ref-node
text-anchor
text-wrap
x-align
background/playground
connection-point/playground
connector
jumpover
normal
rounded
smooth
wobble
coord/playground
edge-anchor/playground
edge-tool
arrowhead
boundary
button-remove
button
custom-arrowhead
custom-vertices
segments
vertices
filter
blur
brightness
contrast
drop-shadow
gray-scale
highlight
hue-rotate
invert
outline
saturate
sepia
grid/playground
label
append-label
label-attrs
label-markup
label-offset
label-position
label-rotate
marker
custom
image
native
normalize-path
path
tagname
mousewheel/playground
node-anchor/playground
node-tool
boundary
button-remove
button
custom-button
node-editor
panning/playground
port-label-layout
inside-outside
radial
side
port-layout
absolute
ellipse-spread
ellipse
line
side
sin
router
er
manhattan
metro
oneside
orth
random
tutorial
basic
getting-started
intermediate/group/collapsable
plugins
minimap
scroller
selection
stencil
transform/resizing
xflow
components
background
clipboard
control
graph
grid
dot
double-mesh
fixed-dot
mesh
size
history
minimap
snapline
transform
xflow-graph/basic
guide
hooks
use-dnd
use-graph-event
use-graph-store
use-key-board
8
.changeset/README.md
Normal file
8
.changeset/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
11
.changeset/config.json
Normal file
11
.changeset/config.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "restricted",
|
||||
"baseBranch": "master",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -75,7 +75,7 @@ body:
|
||||
value: |
|
||||
- OS: [e.g. macOS, Windows, Linux]
|
||||
- Browser: [e.g. Chrome, Safari, Firefox]
|
||||
- Version: [e.g. 91.1]
|
||||
- Version: [e.g. 2.11.1]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
4
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
@ -51,8 +51,8 @@ body:
|
||||
label: 平台
|
||||
value: |
|
||||
- 操作系统: [macOS, Windows, Linux, React Native ...]
|
||||
- 网页浏览器: [Google Chrome, Safari, Firefox]
|
||||
- X6 版本: [1.28.2 ... ]
|
||||
- 网页浏览器: [Google Chrome, Safari, Firefox ...]
|
||||
- X6 版本: [2.11.1 ...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -35,4 +35,4 @@
|
||||
- [ ] I have updated the documentation accordingly.
|
||||
- [ ] I have read the [**CONTRIBUTING**](https://github.com/antvis/x6/blob/master/CONTRIBUTING.md) document.
|
||||
- [ ] I have added tests to cover my changes.
|
||||
- [ ] All new and existing tests passed.
|
||||
- [ ] All new and existing tests passed.
|
||||
|
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
|
@ -3,7 +3,7 @@
|
||||
|
||||
branch="$(git rev-parse --abbrev-ref HEAD)"
|
||||
user="$(git config user.name)"
|
||||
whitelist=("bubkoo" "NewByVector")
|
||||
whitelist=("bubkoo" "newbyvector")
|
||||
|
||||
if [[ ! " ${whitelist[@]} " =~ " ${user} " ]]; then
|
||||
if [ "$branch" = "master" ]; then
|
||||
|
2
.npmrc
Normal file
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
||||
registry=https://registry.npmmirror.com
|
||||
strict-peer-dependencies=false
|
@ -1,9 +1,9 @@
|
||||
*.md
|
||||
*.sh
|
||||
*.yml
|
||||
*.svg
|
||||
*.gif
|
||||
*.log
|
||||
*.md
|
||||
.DS_Store
|
||||
CNAME
|
||||
AUTHORS
|
||||
@ -11,6 +11,9 @@ LICENSE
|
||||
es/
|
||||
lib/
|
||||
dist/
|
||||
public/
|
||||
.dumi/
|
||||
coverage/
|
||||
sites/public
|
||||
csstype.ts
|
||||
ui.js
|
||||
|
@ -2,75 +2,46 @@
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at antv@antfin.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at antv@antfin.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Contribution Guide
|
||||
|
||||
If you have any comment or advice, please report your [issue](https://github.com/antvis/x6/issues),
|
||||
or make any change as you wish and submit a [PR](https://github.com/antvis/x6/pulls).
|
||||
If you have any comment or advice, please report your [issue](https://github.com/antvis/x6/issues), or make any change as you wish and submit a [PR](https://github.com/antvis/x6/pulls).
|
||||
|
||||
## Reporting New Issues
|
||||
|
||||
|
@ -45,8 +45,7 @@ $ git push origin branch-name
|
||||
|
||||
### Commit 提交规范
|
||||
|
||||
根据 [angular 规范](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format)提交 commit,
|
||||
这样 history 看起来更加清晰,还可以自动生成 changelog。
|
||||
根据 [angular 规范](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format)提交 commit,这样 history 看起来更加清晰,还可以自动生成 changelog。
|
||||
|
||||
```xml
|
||||
<type>(<scope>): <subject>
|
||||
@ -121,7 +120,7 @@ X6 基于 [semver](http://semver.org/lang/zh-CN/) 语义化版本号进行发布
|
||||
|
||||
### 发布策略
|
||||
|
||||
在每个大版本的发布中,都会有一个PM,他在发布的不同阶段负有以下职责:
|
||||
在每个大版本的发布中,都会有一个 PM,他在发布的不同阶段负有以下职责:
|
||||
|
||||
#### 准备工作:
|
||||
|
||||
|
39
CONTRIBUTORS
39
CONTRIBUTORS
@ -1,30 +1,48 @@
|
||||
91jojo <jstxhl@live.com>
|
||||
@thinkinggis <lzx199065@gmail.com>
|
||||
Aflext Yang <aflext@gmail.com>
|
||||
BARM <284942955@qq.com>
|
||||
CJrZhang <39872522+CJrZhang@users.noreply.github.com>
|
||||
Candy <563378816@qq.com>
|
||||
Chaoqi ZHANG <prncoprs@163.com>
|
||||
Clifford Fajardo <cliffordfajardo@users.noreply.github.com>
|
||||
DaiGang <42136433+daigang666@users.noreply.github.com>
|
||||
David <36500514+qiufeihong2018@users.noreply.github.com>
|
||||
Dong <48054715+halodong@users.noreply.github.com>
|
||||
Draco <Draco.coder@gmail.com>
|
||||
Eve-Sama <17764594863@163.com>
|
||||
Eve-Sama <948832626@qq.com>
|
||||
Frank William <65594180+ai-qing-hai@users.noreply.github.com>
|
||||
Gomi <gxy880520@qq.com>
|
||||
Gossypol <31892817+gossypol@users.noreply.github.com>
|
||||
HQidea <HQidea@users.noreply.github.com>
|
||||
ImgBotApp <ImgBotHelp@gmail.com>
|
||||
Indigo-w <59961969+Indigo-w@users.noreply.github.com>
|
||||
Indomi <indomi126@gmail.com>
|
||||
JackyChen02 <70377567+JackyChen02@users.noreply.github.com>
|
||||
James Tsang <wtzeng1@gmail.com>
|
||||
JasonSun <42314340+LolipopJ@users.noreply.github.com>
|
||||
Jie <51285767+DimplesY@users.noreply.github.com>
|
||||
Jimwan <897527394@qq.com>
|
||||
Jinxing Lin <172601673@qq.com>
|
||||
Jógvan Olsen <jogvanolsen@hotmail.com>
|
||||
Ken Geis <geis.ken@gmail.com>
|
||||
Kent Wood <minzojian@hotmail.com>
|
||||
KevinXi <48853785+Sorryhx@users.noreply.github.com>
|
||||
Ko.Rei <32183014+Ko-Rei@users.noreply.github.com>
|
||||
LNAhri <lukas@lukas-craft.de>
|
||||
Libin Song <songlibin1994@gmail.com>
|
||||
Limbo <49612796+JUST-Limbo@users.noreply.github.com>
|
||||
Lixu <37231473+wflixu@users.noreply.github.com>
|
||||
Lloyd Zhou <lloydzhou@users.noreply.github.com>
|
||||
Lyn <47809781+lyn-boyu@users.noreply.github.com>
|
||||
MOMO <329053928@qq.com>
|
||||
Mingfei <az8641683@163.com>
|
||||
Mingfei Ding <35296199+aMoonkin@users.noreply.github.com>
|
||||
MrMengJ <2646973632@qq.com>
|
||||
Naveen <172697+naveensrinivasan@users.noreply.github.com>
|
||||
NewByVector <NewByVector@users.noreply.github.com>
|
||||
OZiyuTao <127707782+OZiyuTao@users.noreply.github.com>
|
||||
Olive.Wang <olivewind.wang@gmail.com>
|
||||
Opportunity <opportunity@live.in>
|
||||
Questions <chip@twostewards.com>
|
||||
@ -33,31 +51,38 @@ SSC <273702440@qq.com>
|
||||
Samuel Bodin <1637651+bodinsamuel@users.noreply.github.com>
|
||||
Simon He <57086651+Simon-He95@users.noreply.github.com>
|
||||
Sindori <441933726@qq.com>
|
||||
Struggle <1178825961@qq.com>
|
||||
Struggle Roue <47975400+struggleRoue@users.noreply.github.com>
|
||||
Susan <527971893@qq.com>
|
||||
Thomas Zeugner <tomsoftware@gmx.de>
|
||||
Tony Wu <93302820+tonywu6@users.noreply.github.com>
|
||||
Utopia <greatauk11@gmail.com>
|
||||
WBbug <1056342711@qq.com>
|
||||
XLZY <1017866168@qq.com>
|
||||
Xia Wenqi <xiawenqi90@gmail.com>
|
||||
Xingjian Zhang <44231913+THUzxj@users.noreply.github.com>
|
||||
Yue JIN <40021217+kingyue737@users.noreply.github.com>
|
||||
Zhenyu Hou <skyking_H@hotmail.com>
|
||||
_XiaoTian <istianlei@qq.com>
|
||||
aimagic <40253639+aimagic@users.noreply.github.com>
|
||||
arthur657834 <kingkom7834@126.com>
|
||||
boyu.zlj <boyu.zlj@antgroup.com>
|
||||
breezefaith <nyzhangzc@qq.com>
|
||||
bubkoo <bubkoo.wy@gmail.com>
|
||||
bubkoo <bubkoo@users.noreply.github.com>
|
||||
budlion <dongqi.ldq@alibaba-inc.com>
|
||||
chenBoy <129058082+myBoringCode@users.noreply.github.com>
|
||||
cuidong626 <cuidong1234@outlook.com>
|
||||
cyrilluce <cyrilluce@gmail.com>
|
||||
daigang <1210242662@qq.com>
|
||||
doublewu <592581554@qq.com>
|
||||
fang-ng4 <907648506@qq.com>
|
||||
hylerrix <hylerrix@gmail.com>
|
||||
iceytea <liyunheasap@yeah.net>
|
||||
jiqili <43718732+jiqili@users.noreply.github.com>
|
||||
kelin.zrh <34393362+AricZhu@users.noreply.github.com>
|
||||
kingshuaishuai <ken.wang@mrs.ai>
|
||||
kio <1421104933@qq.com>
|
||||
leondt <168417370+leondt1@users.noreply.github.com>
|
||||
lijing666 <lijing241@yeah.net>
|
||||
linkun <33945539+linkun-wang@users.noreply.github.com>
|
||||
linkun <linkun0922@163.com>
|
||||
@ -65,6 +90,7 @@ lopn <lopnxrp@126.com>
|
||||
luchunwei <luchunwei@gmail.com>
|
||||
luzhuang <364439895@qq.com>
|
||||
lvhuiyang <ilvhuiyang@gmail.com>
|
||||
markliao <liaodalin19903@126.com>
|
||||
myzxlin <myzxlin@163.com>
|
||||
newbyvector <vectorse@126.com>
|
||||
niexq <1879633916@qq.com>
|
||||
@ -88,22 +114,33 @@ wtzeng1 <wtzeng1@gmail.com>
|
||||
x6-bot <x6-bot@users.noreply.github.com>
|
||||
xrkffgg <xrkffgg@gmail.com>
|
||||
yaojin2070 <48686959+yaojin2070@users.noreply.github.com>
|
||||
yinhf <yinhangfeng@gmail.com>
|
||||
yuxuan-ctrl <83435945+yuxuan-ctrl@users.noreply.github.com>
|
||||
zdc1111 <39116292+zdc1111@users.noreply.github.com>
|
||||
zzyyu <33147972+zzyyu@users.noreply.github.com>
|
||||
€alix <qq287649920@gmail.com>
|
||||
一纸忘忧 <54543761+ikxin@users.noreply.github.com>
|
||||
九思⚡⚡⚡ <2228429150@qq.com>
|
||||
云剪者 <584518260@qq.com>
|
||||
何腾飞 <avrin.live.cn@outlook.com>
|
||||
你捉不到的this <2228429150@qq.com>
|
||||
依枫 <deng25st@163.com>
|
||||
偏右 <afc163@gmail.com>
|
||||
大卫 <36500514+qiufeihong2018@users.noreply.github.com>
|
||||
小耀 <jinyue.gjy@antfin.com>
|
||||
崖 <bubkoo.wy@gmail.com>
|
||||
崖崖崖 <bubkoo.wy@gmail.com>
|
||||
张子睿 <411489774@qq.com>
|
||||
徒言 <chaimaoyuan@foxmail.com>
|
||||
德布罗煜 <1056317718@qq.com>
|
||||
文瑀 <wenyu.jqq@antfin.com>
|
||||
映月 <38279397+orientMoon@users.noreply.github.com>
|
||||
杨凌 <89915256@qq.com>
|
||||
柏愚 <boyu.zlj@antfin.com>
|
||||
粑粑超 <842486229@qq.com>
|
||||
練氣士 <62411296+hongfaqiu@users.noreply.github.com>
|
||||
诸岳 <dengfuping_private@163.com>
|
||||
迷悟 <1010953107@qq.com>
|
||||
金强强 <wenyu.jqq@antfin.com>
|
||||
问崖 <bubkoo.wy@gmail.com>
|
||||
问崖 <pengxingjian.pxj@antfin.com>
|
||||
|
414
CONTRIBUTORS.svg
414
CONTRIBUTORS.svg
File diff suppressed because one or more lines are too long
Before (image error) Size: 14 MiB After (image error) Size: 22 MiB |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
Copyright (c) 2021-2024 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
|
||||
|
@ -22,10 +22,10 @@
|
||||
|
||||
## Features
|
||||
|
||||
- 🌱 Easy-to-customize: based on well known SVG/HTML/CSS or React/Vue/Angular to custom nodes and edges
|
||||
- 🚀 Out-of-the-box: built-in 10+ plugins, such as selection, dnd, redo/undo, snapline, minimap, etc.
|
||||
- 🧲 Data-driven: base on MVC architecture, you can focus on data logic and business logic
|
||||
- 💯 Highly-event-driven: you can react on any event that happens inside the graph
|
||||
- 🌱 Easy-to-customize: based on well known SVG/HTML/CSS or React/Vue/Angular to custom nodes and edges
|
||||
- 🚀 Out-of-the-box: built-in 10+ plugins, such as selection, dnd, redo/undo, snapline, minimap, etc.
|
||||
- 🧲 Data-driven: base on MVC architecture, you can focus on data logic and business logic
|
||||
- 💯 Highly-event-driven: you can react on any event that happens inside the graph
|
||||
|
||||
## Environment Support
|
||||
|
||||
@ -33,8 +33,8 @@
|
||||
- Server-side Rendering
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
|
||||
| --- | --- | --- | --- |
|
||||
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## Installation
|
||||
|
||||
@ -57,7 +57,7 @@ import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container'),
|
||||
grid: true
|
||||
grid: true,
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
@ -89,7 +89,8 @@ graph.addEdge({
|
||||
- [Blog](https://www.yuque.com/antv/x6/gcinvi)
|
||||
- [Versioning Release Note](https://www.yuque.com/antv/x6/bbfu6r)
|
||||
- [FAQ](https://www.yuque.com/antv/x6/be9pfx)
|
||||
- [CodeSanbox Template](https://codesandbox.io/s/qosj0?file=/src/app.tsx)
|
||||
- [Template](https://codesandbox.io/s/qosj0?file=/src/app.tsx)
|
||||
- [awesome-x6](https://github.com/lloydzhou/awesome-x6)
|
||||
|
||||
## Development
|
||||
|
||||
|
18
README.md
18
README.md
@ -21,10 +21,10 @@
|
||||
|
||||
## 特性
|
||||
|
||||
- 🌱 极易定制:支持使用 SVG/HTML/React/Vue/Angular 定制节点样式和交互
|
||||
- 🚀 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等
|
||||
- 🧲 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑
|
||||
- 💯 事件驱动:完备的事件系统,可以监听图表内发生的任何事件
|
||||
- 🌱 极易定制:支持使用 SVG/HTML/React/Vue/Angular 定制节点样式和交互
|
||||
- 🚀 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等
|
||||
- 🧲 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑
|
||||
- 💯 事件驱动:完备的事件系统,可以监听图表内发生的任何事件
|
||||
|
||||
## 兼容环境
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
- 支持服务端渲染。
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari |
|
||||
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| last 2 versions | last 2 versions | last 2 versions |
|
||||
| --- | --- | --- |
|
||||
| last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## 安装
|
||||
|
||||
@ -56,7 +56,7 @@ import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container'),
|
||||
grid: true
|
||||
grid: true,
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
@ -88,7 +88,8 @@ graph.addEdge({
|
||||
- [博客](https://www.yuque.com/antv/x6/huhla47wqalq5n7r)
|
||||
- [更新日志](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)
|
||||
- [复现模板](https://codesandbox.io/s/mo-ban-55i8dp)
|
||||
- [awesome-x6](https://github.com/lloydzhou/awesome-x6)
|
||||
|
||||
## 本地开发
|
||||
|
||||
@ -113,7 +114,6 @@ pnpm run start
|
||||
<img src="https://raw.githubusercontent.com/antvis/X6/master/CONTRIBUTORS.svg" alt="Contributors" />
|
||||
</a>
|
||||
|
||||
|
||||
## 开源协议
|
||||
|
||||
该项目的代码和文档基于 [MIT License](/LICENSE) 开源协议。
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
Use this section to tell people about which versions of your project are currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
@ -16,6 +15,4 @@ currently being supported with security updates.
|
||||
|
||||
Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc.
|
||||
Tell them where to go, how often they can expect to get an update on a reported vulnerability, what to expect if the vulnerability is accepted or declined, etc.
|
||||
|
@ -1,122 +0,0 @@
|
||||
## @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)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* history add max stack size ([#3253](https://github.com/antvis/X6/issues/3253)) ([fba5310](https://github.com/antvis/X6/commit/fba531064ad8027c451a81b60d5efd7f7314a0fa))
|
||||
|
||||
## @antv/x6-example-features [2.0.2](https://github.com/antvis/X6/compare/@antv/x6-example-features@2.0.1...@antv/x6-example-features@2.0.2) (2023-01-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mindmap demo:** can not find target id when create edge ([#3144](https://github.com/antvis/X6/issues/3144)) ([bfc8d7f](https://github.com/antvis/X6/commit/bfc8d7f17ac900f70b696c1fa7a3f3f3a389103f))
|
||||
|
||||
## @antv/x6-example-features [2.0.1](https://github.com/antvis/X6/compare/@antv/x6-example-features@2.0.0...@antv/x6-example-features@2.0.1) (2022-12-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* make resizing options take effect ([#3014](https://github.com/antvis/X6/issues/3014)) ([604c024](https://github.com/antvis/X6/commit/604c0244cd71ec8e911754dfe524f12c04e4e9ad))
|
||||
|
||||
# @antv/x6-example-features [2.0.0](https://github.com/antvis/X6/compare/@antv/x6-example-features@1.1.2...@antv/x6-example-features@2.0.0) (2022-11-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 add return value for autoScroller in scroller plugin ([5e102a3](https://github.com/antvis/X6/commit/5e102a39c5bd14a478edd4f36c4264997027c2a9))
|
||||
* 🐛 add timeout for schedule ([#2303](https://github.com/antvis/X6/issues/2303)) ([a6a2d12](https://github.com/antvis/X6/commit/a6a2d12b07add27ef19eebbf7b5ca7cd17dde09e))
|
||||
* 🐛 break text with chinese characters(double byte character) ([14199bc](https://github.com/antvis/X6/commit/14199bc8529adddb347ef934926503a789b64980)), closes [#596](https://github.com/antvis/X6/issues/596)
|
||||
* 🐛 change jobqueue to transient ([0e39d94](https://github.com/antvis/X6/commit/0e39d9447bc8c0ba0b11c272bf9b64df9ba95a33))
|
||||
* 🐛 do not generate new commands on redoing/undoing ([5b3d713](https://github.com/antvis/X6/commit/5b3d7133f3a7b4841f461e67af5963ec84820741)), closes [#627](https://github.com/antvis/X6/issues/627)
|
||||
* 🐛 do not update pagesize automatically when set graph size ([949a42d](https://github.com/antvis/X6/commit/949a42dacfc5023d25bcabc0a3a1a7d8578f1b96)), closes [#644](https://github.com/antvis/X6/issues/644) [#564](https://github.com/antvis/X6/issues/564)
|
||||
* 🐛 fix add tools not work ([f5d1d6a](https://github.com/antvis/X6/commit/f5d1d6a326021247ee8967675fc9490ddbb6d0aa))
|
||||
* 🐛 fix model event trigger twice ([#789](https://github.com/antvis/X6/issues/789)) ([7638143](https://github.com/antvis/X6/commit/7638143b04c0a50a333200423753f6bd19a6ceb3))
|
||||
* 🐛 fix running error of x6-example-demo ([#1111](https://github.com/antvis/X6/issues/1111)) ([d5c854f](https://github.com/antvis/X6/commit/d5c854f644e4926dba2913a216870bdbaafd425a))
|
||||
* 🐛 fix the error in selected nodes position when snapline enabled ([#2797](https://github.com/antvis/X6/issues/2797)) ([1e7f132](https://github.com/antvis/X6/commit/1e7f132bed15006cc5535f1294f0b8a545dd6441))
|
||||
* 🐛 fix type error ([30ca7a9](https://github.com/antvis/X6/commit/30ca7a92817d28e58589413e36d3d2931360b8ae))
|
||||
* 🐛 fix x6-react-components version in demo ([709cdae](https://github.com/antvis/X6/commit/709cdae33d13acfd77af11e8bb5fb4f493dd5bd5))
|
||||
* 🐛 interact with input rendered in react component ([82478b1](https://github.com/antvis/X6/commit/82478b1d66e3b8b4346dab9041cb00e54fea9be1))
|
||||
* 🐛 linear gradient along edge path ([669fc5b](https://github.com/antvis/X6/commit/669fc5bd2d57635ce9d45dc0470674dad74f4add)), closes [#635](https://github.com/antvis/X6/issues/635)
|
||||
* 🐛 liner gradient not available on horizontal and vertical edges ([333689a](https://github.com/antvis/X6/commit/333689a880a30dbc0879705b7f655cec8d30f1df)), closes [#635](https://github.com/antvis/X6/issues/635)
|
||||
* 🐛 optimize cell remove method ([391fe8f](https://github.com/antvis/X6/commit/391fe8fd88f10d936c5860f465c7a423632f30f9))
|
||||
* 🐛 optimize contextmenu tools ([#1391](https://github.com/antvis/X6/issues/1391)) ([cc01fdf](https://github.com/antvis/X6/commit/cc01fdf208f4fbd283a6ce3d7a106716e8e10300))
|
||||
* 🐛 set the async of minimapGraph to be the same as sourceGraph ([9dded68](https://github.com/antvis/X6/commit/9dded6853d66b86e7bbeb738b2df15b51d1a8627))
|
||||
* 🐛 should render vertices tool with lowest z-index ([213a01f](https://github.com/antvis/X6/commit/213a01fca28b1e790ce58d228aa460ea798bb98f)), closes [#638](https://github.com/antvis/X6/issues/638)
|
||||
* 🐛 update x6-react-shape version ([#1425](https://github.com/antvis/X6/issues/1425)) ([4208846](https://github.com/antvis/X6/commit/4208846337326d8983f1662faa8da67efd8568b4))
|
||||
* fix contextmenu show multiple times ([5d437ce](https://github.com/antvis/X6/commit/5d437cef07427bf9f2cbae9b2e08dd4a6544ff70))
|
||||
* fix demo import path error ([2ebf581](https://github.com/antvis/X6/commit/2ebf581dc1ec9c5ee4501917a7cbddbbb4b69c0f))
|
||||
* fix path error in custom router demo ([#620](https://github.com/antvis/X6/issues/620)) ([7cd3a7e](https://github.com/antvis/X6/commit/7cd3a7e57d772481ad33949ee832a36aab59ef3a))
|
||||
* refactor example ([#2831](https://github.com/antvis/X6/issues/2831)) ([3d8f005](https://github.com/antvis/X6/commit/3d8f005696021f1d9f91a96812ebadce179f2d73))
|
||||
* remove x6-common and x6-geometry deps ([#2830](https://github.com/antvis/X6/issues/2830)) ([5b5f5aa](https://github.com/antvis/X6/commit/5b5f5aa7ea6fded1b15abc79b9b5a5e2281b3ab9))
|
||||
* update dependencies and fix type errors ([#1103](https://github.com/antvis/X6/issues/1103)) ([49d4371](https://github.com/antvis/X6/commit/49d43716ada672e609e4e6d9c6fdca3f494b6f68))
|
||||
* **wip:** 🐛 click event of contextmenu was not triggered ([2c9363e](https://github.com/antvis/X6/commit/2c9363e46904979901d4b467995d289c094d329a))
|
||||
|
||||
|
||||
### chore
|
||||
|
||||
* release beta ([b5f3cfa](https://github.com/antvis/X6/commit/b5f3cfa2042f5196a995a38a8f41f140cabdce57))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* refresh changelogs ([44f89a1](https://github.com/antvis/X6/commit/44f89a1e1a85513a9bf548be87be38e3cdc82574))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ add `primer` and `useForeignObject` option for react-shape ([ab6a06f](https://github.com/antvis/X6/commit/ab6a06f1fe70b71ae31acc47b0d9cb02c86097e2))
|
||||
* ✨ add autoResize feature ([5aeae97](https://github.com/antvis/X6/commit/5aeae976cd7638b2b5c05bc12bc56b562366fe5f))
|
||||
* ✨ add clipboard plugin ([8107f6d](https://github.com/antvis/X6/commit/8107f6df5de52a33e1b8094a44d59ee7fd2a8042))
|
||||
* ✨ add dnd plugin ([269fae9](https://github.com/antvis/X6/commit/269fae9e5eeb969c6a7884373aa3a32002c064e6))
|
||||
* ✨ add history plugin ([#2819](https://github.com/antvis/X6/issues/2819)) ([fd8d384](https://github.com/antvis/X6/commit/fd8d384a29d0f2e02bf066efd19ed3f92614c524))
|
||||
* ✨ add html shape ([8d75504](https://github.com/antvis/X6/commit/8d7550413f9f6f3177eab9d0f7fef14c55949fb8))
|
||||
* ✨ add keyboard plugin ([#2665](https://github.com/antvis/X6/issues/2665)) ([bf53677](https://github.com/antvis/X6/commit/bf536778ca7ee3229390dfcfcb085ec55edd9fb2))
|
||||
* ✨ add library for manipulating and animating SVG ([c07a177](https://github.com/antvis/X6/commit/c07a17785fc99372baaa66ea2525acf1d332fa11))
|
||||
* ✨ add minimap plugin ([6cdecbb](https://github.com/antvis/X6/commit/6cdecbbba9a4db1f67189e23fb89f2a7ba2af99e))
|
||||
* ✨ add panning and mousewheel module ([#2243](https://github.com/antvis/X6/issues/2243)) ([55d36e4](https://github.com/antvis/X6/commit/55d36e46808a4c79b086d7798bce396d5211a1dc))
|
||||
* ✨ add scroller api ([12173bf](https://github.com/antvis/X6/commit/12173bf500624f197ed56cf6a797499587178cba))
|
||||
* ✨ add selection plugin ([#2742](https://github.com/antvis/X6/issues/2742)) ([50a5dc7](https://github.com/antvis/X6/commit/50a5dc7cd8c2e39a1f8bf8359a0eb189dda8cb86))
|
||||
* ✨ add snapline plugin ([294672b](https://github.com/antvis/X6/commit/294672b3066b15ab834ce2a3172facc49004c950))
|
||||
* ✨ add some missing api ([1dcb3d9](https://github.com/antvis/X6/commit/1dcb3d92fd83e5dfd1a1af9670d539a99dd9f55a))
|
||||
* ✨ add stencil plugin ([#2815](https://github.com/antvis/X6/issues/2815)) ([4e1fb7b](https://github.com/antvis/X6/commit/4e1fb7bef8ff5548edf2529eb27be0a66a600996))
|
||||
* ✨ add transform plugin ([#2818](https://github.com/antvis/X6/issues/2818)) ([660e2d7](https://github.com/antvis/X6/commit/660e2d7689bfa59a0f4a4a5e3c0ace70dec21e9e))
|
||||
* ✨ add virtual render feature ([#2198](https://github.com/antvis/X6/issues/2198)) ([fcba5e1](https://github.com/antvis/X6/commit/fcba5e14808d44c80b658c090cc2a4ebcdc64f6d))
|
||||
* ✨ add xmind demo ([adb2c98](https://github.com/antvis/X6/commit/adb2c98e23e93b7084fd20f05801f2595d4ac990))
|
||||
* ✨ auto resize graph when container resized ([9c7bc9a](https://github.com/antvis/X6/commit/9c7bc9a4bb210451283663cd99a29bd6c79e2ec4)), closes [#531](https://github.com/antvis/X6/issues/531)
|
||||
* ✨ export common and geometry in x6 package ([#2820](https://github.com/antvis/X6/issues/2820)) ([df28200](https://github.com/antvis/X6/commit/df282000cc5e17521147c77c210e172c444c9938))
|
||||
* ✨ expose the selection api ([#2756](https://github.com/antvis/X6/issues/2756)) ([f3edbbc](https://github.com/antvis/X6/commit/f3edbbc95d2038a61116fa71bb0c3016f1c92d5e))
|
||||
* ✨ improve auto-resize feature ([40d5335](https://github.com/antvis/X6/commit/40d53355cedc0bbbeb1e26948b67254dc6a40d85))
|
||||
* ✨ random path demo ([38ec683](https://github.com/antvis/X6/commit/38ec683673e2da64296521f23a91f951a442adc0))
|
||||
* ✨ support inherit options for react-shape registry ([#2596](https://github.com/antvis/X6/issues/2596)) ([ad63046](https://github.com/antvis/X6/commit/ad63046e89fa5853b0cf15947af1ed2a7b625188))
|
||||
* ✨ support panning scroller graph byrightmousedown ([6ffdb50](https://github.com/antvis/X6/commit/6ffdb5004401b30ff5852a08de9286a934780be3))
|
||||
* add scroller plugin ([#2580](https://github.com/antvis/X6/issues/2580)) ([5e0e2ac](https://github.com/antvis/X6/commit/5e0e2acde7d7e259ea27d001983e950878d0ecc8))
|
||||
* attach plugin api and events to grpah instance ([#2864](https://github.com/antvis/X6/issues/2864)) ([774f547](https://github.com/antvis/X6/commit/774f547b85522eb2411dca949d36ecfe535503f3))
|
||||
* force release 2.0-beta ([6987d9c](https://github.com/antvis/X6/commit/6987d9ce64454cd76f697d33f96715dbdf56524a))
|
||||
* support mouseenter and mouseleave event ([#2559](https://github.com/antvis/X6/issues/2559)) ([ecfd426](https://github.com/antvis/X6/commit/ecfd4263b1266a128bf8651c4dd745ff8ab038b3))
|
||||
* sync code from master ([#2004](https://github.com/antvis/X6/issues/2004)) ([c681405](https://github.com/antvis/X6/commit/c68140504bd21f654870f3d2fc1ad2f16f1113c8)), closes [#1974](https://github.com/antvis/X6/issues/1974) [#1977](https://github.com/antvis/X6/issues/1977) [#1985](https://github.com/antvis/X6/issues/1985) [#1988](https://github.com/antvis/X6/issues/1988) [#1991](https://github.com/antvis/X6/issues/1991) [#1989](https://github.com/antvis/X6/issues/1989)
|
||||
* upgrade react to 18 in react-components ([#2836](https://github.com/antvis/X6/issues/2836)) ([5138562](https://github.com/antvis/X6/commit/5138562515ddbd3975adc9d93514f21d6fc2bb3e))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* ⚡️ add getMatrixByElementAttr and getBBoxByElementAttr to reduce reflow ([ba5b22a](https://github.com/antvis/X6/commit/ba5b22a33a0af067d77735c5cc46a60a45734dca))
|
||||
* ⚡️ add simple config to remove rect and text element ([#1449](https://github.com/antvis/X6/issues/1449)) ([0b5f241](https://github.com/antvis/X6/commit/0b5f2413f0b907316784149027615ae2d09616a4))
|
||||
* ⚡️ check whether label existed in port ([#2063](https://github.com/antvis/X6/issues/2063)) ([5ae7271](https://github.com/antvis/X6/commit/5ae7271a25e804a9321aa80e31dcf6e43144728b))
|
||||
* ⚡️ optimize breakText for a high performance version ([#2242](https://github.com/antvis/X6/issues/2242)) ([0aced58](https://github.com/antvis/X6/commit/0aced58056d908ec092bca1889b5ef367a94fe68))
|
||||
* ⚡️ optimize node render performance ([6554959](https://github.com/antvis/X6/commit/65549599d2f82f8052d16776c8d36ce7ee2fba9b))
|
||||
* ⚡️ repalce getTransformToElement and getBBox to improve performance ([#2177](https://github.com/antvis/X6/issues/2177)) ([1436586](https://github.com/antvis/X6/commit/1436586f85cc2e2f6ec71548f6d6c232be793154))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* dump to 2.0
|
||||
* force release 2.0-beta
|
||||
* 2.0-beta
|
@ -3,26 +3,26 @@
|
||||
"name": "@antv/x6-example-features",
|
||||
"version": "2.1.1",
|
||||
"scripts": {
|
||||
"start": "umi dev",
|
||||
"start": "export NODE_OPTIONS=--openssl-legacy-provider && umi dev",
|
||||
"build": "umi build",
|
||||
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/hierarchy": "^0.6.8",
|
||||
"@antv/x6": "^2.x",
|
||||
"@antv/x6-plugin-clipboard": "^2.x",
|
||||
"@antv/x6-plugin-dnd": "^2.x",
|
||||
"@antv/x6-plugin-export": "^2.x",
|
||||
"@antv/x6-plugin-history": "^2.x",
|
||||
"@antv/x6-plugin-keyboard": "^2.x",
|
||||
"@antv/x6-plugin-minimap": "^2.x",
|
||||
"@antv/x6-plugin-scroller": "^2.x",
|
||||
"@antv/x6-plugin-selection": "^2.x",
|
||||
"@antv/x6-plugin-snapline": "^2.x",
|
||||
"@antv/x6-plugin-stencil": "^2.x",
|
||||
"@antv/x6-plugin-transform": "^2.x",
|
||||
"@antv/x6-react-components": "^2.x",
|
||||
"@antv/x6-react-shape": "^2.x",
|
||||
"@antv/x6": "workspace:latest",
|
||||
"@antv/x6-plugin-clipboard": "workspace:latest",
|
||||
"@antv/x6-plugin-dnd": "workspace:latest",
|
||||
"@antv/x6-plugin-export": "workspace:latest",
|
||||
"@antv/x6-plugin-history": "workspace:latest",
|
||||
"@antv/x6-plugin-keyboard": "workspace:latest",
|
||||
"@antv/x6-plugin-minimap": "workspace:latest",
|
||||
"@antv/x6-plugin-scroller": "workspace:latest",
|
||||
"@antv/x6-plugin-selection": "workspace:latest",
|
||||
"@antv/x6-plugin-snapline": "workspace:latest",
|
||||
"@antv/x6-plugin-stencil": "workspace:latest",
|
||||
"@antv/x6-plugin-transform": "workspace:latest",
|
||||
"@antv/x6-react-components": "workspace:latest",
|
||||
"@antv/x6-react-shape": "workspace:latest",
|
||||
"antd": "^4.4.2",
|
||||
"classnames": "^2.2.6",
|
||||
"dagre": "^0.8.5",
|
||||
@ -48,7 +48,10 @@
|
||||
"react-test-renderer": "^16.7.0",
|
||||
"umi": "^2.9.0",
|
||||
"umi-plugin-react": "^1.8.0",
|
||||
"umi-types": "^0.3.0"
|
||||
"umi-types": "^0.3.0",
|
||||
"@fluidframework/aqueduct": "^0.33.5",
|
||||
"@fluidframework/get-tinylicious-container": "^0.33.5",
|
||||
"@fluidframework/map": "^0.33.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
|
52
examples/x6-example-features/src/collaboration/app.ts
Normal file
52
examples/x6-example-features/src/collaboration/app.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import type { Graph } from '@antv/x6'
|
||||
import { getDefaultObjectFromContainer } from '@fluidframework/aqueduct'
|
||||
import { getTinyliciousContainer } from '@fluidframework/get-tinylicious-container'
|
||||
|
||||
import { GraphDataObjectContainerRuntimeFactory } from './containerCode'
|
||||
import type { IGraphDataObject } from './dataObject'
|
||||
import { connectGraph } from './view'
|
||||
|
||||
// In interacting with the service, we need to be explicit about whether we're creating a new document vs. loading
|
||||
// an existing one. We also need to provide the unique ID for the document we are creating or loading from.
|
||||
|
||||
// In this app, we'll choose to create a new document when navigating directly to http://localhost:8080. For the ID,
|
||||
// we'll choose to use the current timestamp. We'll also choose to interpret the URL hash as an existing document's
|
||||
// ID to load from, so the URL for a document load will look something like http://localhost:8080/#1596520748752.
|
||||
// These policy choices are arbitrary for demo purposes, and can be changed however you'd like.
|
||||
|
||||
const createNew = false
|
||||
// if (location.hash.length === 0) {
|
||||
// createNew = true;
|
||||
// location.hash = Date.now().toString();
|
||||
// }
|
||||
// const documentId = location.hash.substring(1);
|
||||
// document.title = documentId;
|
||||
|
||||
export async function start(graph: Graph): Promise<void> {
|
||||
// The getTinyliciousContainer helper function facilitates loading our container code into a Container and
|
||||
// connecting to a locally-running test service called Tinylicious. This will look different when moving to a
|
||||
// production service, but ultimately we'll still be getting a reference to a Container object. The helper
|
||||
// function takes the ID of the document we're creating or loading, the container code to load into it, and a
|
||||
// flag to specify whether we're creating a new document or loading an existing one.
|
||||
const container = await getTinyliciousContainer(
|
||||
'test',
|
||||
GraphDataObjectContainerRuntimeFactory,
|
||||
createNew,
|
||||
)
|
||||
|
||||
// In this app, we know our container code provides a default data object that is an IGraphDataObject.
|
||||
const graphDataObject: IGraphDataObject =
|
||||
await getDefaultObjectFromContainer<IGraphDataObject>(container)
|
||||
|
||||
connectGraph(graphDataObject, graph)
|
||||
|
||||
// Reload the page on any further hash changes, e.g. in case you want to paste in a different document ID.
|
||||
// window.addEventListener('hashchange', () => {
|
||||
// location.reload();
|
||||
// });
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ContainerRuntimeFactoryWithDefaultDataStore } from '@fluidframework/aqueduct'
|
||||
|
||||
import { GraphDataObjectInstantiationFactory } from './dataObject'
|
||||
|
||||
/**
|
||||
* The GraphDataObjectContainerRuntimeFactory is the container code for our scenario.
|
||||
*
|
||||
* Since we only need to instantiate and retrieve a single dice roller for our scenario, we can use a
|
||||
* ContainerRuntimeFactoryWithDefaultDataStore. We provide it with the type of the data object we want to create
|
||||
* and retrieve by default, and the registry entry mapping the type to the factory.
|
||||
*
|
||||
* This container code will create the single default data object on our behalf and make it available on the
|
||||
* Container with a URL of "/", so it can be retrieved via container.request("/").
|
||||
*/
|
||||
export const GraphDataObjectContainerRuntimeFactory =
|
||||
new ContainerRuntimeFactoryWithDefaultDataStore(
|
||||
GraphDataObjectInstantiationFactory,
|
||||
new Map([GraphDataObjectInstantiationFactory.registryEntry]),
|
||||
)
|
252
examples/x6-example-features/src/collaboration/dataObject.ts
Normal file
252
examples/x6-example-features/src/collaboration/dataObject.ts
Normal file
@ -0,0 +1,252 @@
|
||||
/*!
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import type { EventEmitter } from 'events'
|
||||
|
||||
import { StringExt } from '@antv/x6'
|
||||
import { DataObject, DataObjectFactory } from '@fluidframework/aqueduct'
|
||||
import type { IFluidHandle } from '@fluidframework/core-interfaces'
|
||||
import type { IValueChanged } from '@fluidframework/map'
|
||||
import { SharedMap } from '@fluidframework/map'
|
||||
|
||||
/**
|
||||
* IGraphDataObject describes the public API surface for our graph data object.
|
||||
*/
|
||||
export interface IGraphDataObject extends EventEmitter {
|
||||
cells: SharedMap
|
||||
users: SharedMap
|
||||
|
||||
userId: string
|
||||
|
||||
on(event: string, listener: (id: string, attributes: any) => void): this
|
||||
on(
|
||||
event: string,
|
||||
listener: (id: string, attributes: any, prevAttributes: any) => void,
|
||||
): this
|
||||
|
||||
setCell(id: string, attributes: any): void
|
||||
|
||||
deleteCell(id: string): void
|
||||
|
||||
updateUser(attributes: any): void
|
||||
}
|
||||
|
||||
export interface IUser {
|
||||
id: string
|
||||
name: string
|
||||
color: string
|
||||
x?: number
|
||||
y?: number
|
||||
selection?: string
|
||||
}
|
||||
|
||||
export const initialCells = [
|
||||
{
|
||||
id: 'test_node_1',
|
||||
x: 100,
|
||||
y: 100,
|
||||
shape: 'dag-node',
|
||||
data: {
|
||||
id: 'test_node_1',
|
||||
codeName: 'ss_sgd_train',
|
||||
label: '逻辑回归',
|
||||
status: 0,
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
id: 'test_node_1_input_0',
|
||||
group: 'top',
|
||||
type: 'sf.table.vtable',
|
||||
},
|
||||
{
|
||||
id: 'test_node_1_input_1',
|
||||
group: 'top',
|
||||
type: 'sf.table.individual',
|
||||
},
|
||||
{
|
||||
id: 'test_node_1_output_0',
|
||||
group: 'bottom',
|
||||
type: 'sf.model.ss_sgb',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test_node_2',
|
||||
x: 300,
|
||||
y: 300,
|
||||
shape: 'dag-node',
|
||||
data: {
|
||||
id: 'test_node_2',
|
||||
codeName: 'ss_sgd_predict',
|
||||
label: '模型预测',
|
||||
status: 2,
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
id: 'test_node_2_input_0',
|
||||
group: 'top',
|
||||
type: 'sf.model.ss_sgb',
|
||||
},
|
||||
{
|
||||
id: 'test_node_2_input_1',
|
||||
group: 'top',
|
||||
type: 'sf.table.vtable',
|
||||
},
|
||||
{
|
||||
id: 'test_node_2_output_0',
|
||||
group: 'bottom',
|
||||
type: 'sf.table.individual',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
shape: 'dag-edge',
|
||||
id: 'test_node_1_output_0__test_node_2_input_0',
|
||||
source: {
|
||||
cell: 'test_node_1',
|
||||
port: 'test_node_1_output_0',
|
||||
},
|
||||
target: {
|
||||
cell: 'test_node_2',
|
||||
port: 'test_node_2_input_0',
|
||||
},
|
||||
data: {
|
||||
id: 'test_node_1_output_0__test_node_2_input_0',
|
||||
source: 'test_node_1',
|
||||
sourceAnchor: 'test_node_1_output_0',
|
||||
target: 'test_node_2',
|
||||
targetAnchor: 'test_node_2_input_0',
|
||||
},
|
||||
zIndex: -1,
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* The GraphDataObject is our data object that implements the IGraphDataObject interface.
|
||||
*/
|
||||
export class GraphDataObject extends DataObject implements IGraphDataObject {
|
||||
/**
|
||||
* initializingFirstTime is run only once by the first client to create the DataObject. Here we use it to
|
||||
* initialize the state of the DataObject.
|
||||
*/
|
||||
|
||||
private _cells: SharedMap
|
||||
private _users: SharedMap
|
||||
|
||||
protected async initializingFirstTime() {
|
||||
const cellsMap = SharedMap.create(this.runtime)
|
||||
const usersMap = SharedMap.create(this.runtime)
|
||||
|
||||
this.root.set('cellsMap', cellsMap.handle)
|
||||
this.root.set('usersMap', usersMap.handle)
|
||||
|
||||
await this.initMaps()
|
||||
initialCells.forEach((cell) => {
|
||||
this.setCell(cell.id, { ...cell })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* hasInitialized is run by each client as they load the DataObject. Here we use it to set up usage of the
|
||||
* DataObject, by registering an event listener for graph data object.
|
||||
*/
|
||||
protected async hasInitialized() {
|
||||
await this.initMaps()
|
||||
|
||||
this.cells.on('valueChanged', (changed: IValueChanged) => {
|
||||
this.emit('cellChanged', changed.key, this.cells.get(changed.key))
|
||||
})
|
||||
|
||||
this.users.on('valueChanged', (changed: IValueChanged) => {
|
||||
this.emit(
|
||||
'userChanged',
|
||||
changed.key,
|
||||
this.users.get(changed.key),
|
||||
changed.previousValue,
|
||||
)
|
||||
})
|
||||
|
||||
this.addUser()
|
||||
}
|
||||
|
||||
private async initMaps() {
|
||||
if (!this._cells) {
|
||||
const mapHandle = this.root.get<IFluidHandle<SharedMap>>('cellsMap')
|
||||
if (!mapHandle) throw Error('Something went wrong')
|
||||
this._cells = await mapHandle.get()
|
||||
}
|
||||
if (!this._users) {
|
||||
const mapHandle = this.root.get<IFluidHandle<SharedMap>>('usersMap')
|
||||
if (!mapHandle) throw Error('Something went wrong')
|
||||
this._users = await mapHandle.get()
|
||||
}
|
||||
}
|
||||
|
||||
public get cells() {
|
||||
return this._cells
|
||||
}
|
||||
|
||||
public get users() {
|
||||
return this._users
|
||||
}
|
||||
|
||||
public setCell(id: string, attributes: any) {
|
||||
this.cells.set(id, attributes)
|
||||
}
|
||||
|
||||
public deleteCell(id: string) {
|
||||
if (this.cells.has(id)) {
|
||||
this.cells.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
public userId: string
|
||||
|
||||
public addUser() {
|
||||
if (
|
||||
sessionStorage.getItem('userId') &&
|
||||
this.users.get<IUser>(<string>sessionStorage.getItem('userId'))
|
||||
) {
|
||||
this.userId = <string>sessionStorage.getItem('userId') //This session might have has a user
|
||||
} else {
|
||||
const user: IUser = {
|
||||
id: StringExt.uuid(),
|
||||
name: 'Fake',
|
||||
color: getRandomColor(),
|
||||
}
|
||||
this.userId = user.id
|
||||
sessionStorage.setItem('userId', user.id)
|
||||
this.users.set(user.id, user)
|
||||
}
|
||||
}
|
||||
|
||||
public getUser(): IUser | undefined {
|
||||
return this.users.get<IUser>(this.userId)
|
||||
}
|
||||
|
||||
public updateUser(attributes: any) {
|
||||
return this.users.set(this.userId, { ...this.getUser(), ...attributes })
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomColor(): string {
|
||||
const letters = '0123456789ABCDEF'
|
||||
let color = '#'
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)]
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
/**
|
||||
* The DataObjectFactory is used by Fluid Framework to instantiate our DataObject. We provide it with a unique name
|
||||
* and the constructor it will call. In this scenario, the third and fourth arguments are not used.
|
||||
*/
|
||||
export const GraphDataObjectInstantiationFactory = new DataObjectFactory(
|
||||
'graph-data-object',
|
||||
GraphDataObject,
|
||||
[],
|
||||
{},
|
||||
)
|
1
examples/x6-example-features/src/collaboration/index.ts
Normal file
1
examples/x6-example-features/src/collaboration/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './app'
|
92
examples/x6-example-features/src/collaboration/view.ts
Normal file
92
examples/x6-example-features/src/collaboration/view.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import type { Graph } from '@antv/x6'
|
||||
import { Vector } from '@antv/x6'
|
||||
|
||||
import type { IGraphDataObject, IUser } from './dataObject'
|
||||
|
||||
export function connectGraph(graphDataObject: IGraphDataObject, graph: Graph) {
|
||||
const updateCell = (id: string, attributes: any) => {
|
||||
const cell = graph.getCellById(id)
|
||||
if (cell) {
|
||||
if (attributes) {
|
||||
cell.setProp(attributes)
|
||||
} else {
|
||||
cell.remove()
|
||||
}
|
||||
} else {
|
||||
if (!attributes) return
|
||||
if (attributes.shape === 'dag-edge') {
|
||||
graph.addEdge(attributes)
|
||||
} else if (attributes.shape === 'dag-node') {
|
||||
graph.addNode(attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
graphDataObject.cells.forEach((cell) => updateCell(cell.id, cell))
|
||||
|
||||
graphDataObject.on('cellChanged', updateCell)
|
||||
|
||||
graph.on('cell:added', function ({ cell }) {
|
||||
graphDataObject.setCell(cell.id, cell.prop())
|
||||
})
|
||||
|
||||
graph.on('cell:change:*', function ({ cell }) {
|
||||
graphDataObject.setCell(cell.id, cell.prop())
|
||||
})
|
||||
|
||||
graph.on('cell:removed', function ({ cell }) {
|
||||
graphDataObject.deleteCell(cell.id)
|
||||
})
|
||||
|
||||
const remoteCursors: { [userId: string]: Vector } = {}
|
||||
|
||||
graphDataObject.on(
|
||||
'userChanged',
|
||||
function (id: string, user: IUser, previous: IUser) {
|
||||
if (user.selection) {
|
||||
const cell = graph.getCellById(user.selection)
|
||||
if (cell) {
|
||||
graph.select(cell)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
previous &&
|
||||
previous.selection &&
|
||||
previous.selection !== user.selection
|
||||
) {
|
||||
const cell = graph.getCellById(previous.selection)
|
||||
if (cell) {
|
||||
graph.unselect(cell)
|
||||
}
|
||||
}
|
||||
|
||||
if (id === graphDataObject.userId) return
|
||||
let circle: Vector
|
||||
if (!remoteCursors[id]) {
|
||||
circle = Vector.create('circle').attr({
|
||||
r: 5,
|
||||
'pointer-events': 'none',
|
||||
})
|
||||
circle.appendTo(graph.view.decorator)
|
||||
remoteCursors[id] = circle
|
||||
} else {
|
||||
circle = remoteCursors[id]
|
||||
}
|
||||
circle.attr({ cx: user.x || 0, cy: user.y || 0, fill: user.color })
|
||||
},
|
||||
)
|
||||
|
||||
graph.container.addEventListener('mousemove', (evt: any) => {
|
||||
const point = graph.clientToLocal(evt.clientX, evt.clientY)
|
||||
graphDataObject.updateUser(point.toJSON())
|
||||
})
|
||||
|
||||
graph.on('node:click', function ({ cell }) {
|
||||
graphDataObject.updateUser({ selection: cell.id })
|
||||
})
|
||||
|
||||
graph.on('blank:click', function () {
|
||||
graphDataObject.updateUser({ selection: '' })
|
||||
})
|
||||
}
|
@ -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 {
|
||||
|
@ -35,11 +35,7 @@ export default class Example extends React.Component {
|
||||
},
|
||||
autoResize: true,
|
||||
})
|
||||
graph.use(
|
||||
new Scroller({
|
||||
enabled: true,
|
||||
}),
|
||||
)
|
||||
graph.use(new Scroller())
|
||||
}
|
||||
|
||||
refContainer1 = (container: HTMLDivElement) => {
|
||||
|
@ -10,7 +10,6 @@ export default class Example extends React.Component {
|
||||
container: this.container,
|
||||
width: 800,
|
||||
height: 600,
|
||||
grid: true,
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
|
@ -374,7 +374,6 @@ export default class Example extends React.Component {
|
||||
})
|
||||
|
||||
const selection = new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberEdge: true,
|
||||
rubberNode: true,
|
||||
@ -382,7 +381,7 @@ export default class Example extends React.Component {
|
||||
rubberband: true,
|
||||
})
|
||||
graph.use(selection)
|
||||
graph.use(new Snapline({ enabled: true }))
|
||||
graph.use(new Snapline())
|
||||
|
||||
graph.on('edge:connected', ({ edge }) => {
|
||||
edge.attr({
|
||||
|
@ -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'
|
||||
@ -184,13 +184,9 @@ export default class Example extends React.Component {
|
||||
connectionPoint: 'anchor',
|
||||
},
|
||||
})
|
||||
const selection = new Selection({
|
||||
enabled: true,
|
||||
})
|
||||
const selection = new Selection()
|
||||
graph.use(selection)
|
||||
const keyboard = new Keyboard({
|
||||
enabled: true,
|
||||
})
|
||||
const keyboard = new Keyboard()
|
||||
graph.use(keyboard)
|
||||
|
||||
const render = () => {
|
||||
@ -220,7 +216,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,
|
||||
|
@ -18,19 +18,13 @@ export default class Example extends React.Component {
|
||||
height: 600,
|
||||
grid: true,
|
||||
})
|
||||
const clipboard = new Clipboard({
|
||||
enabled: true,
|
||||
useLocalStorage: true,
|
||||
})
|
||||
const clipboard = new Clipboard()
|
||||
const selection = new Selection({
|
||||
enabled: true,
|
||||
rubberband: true,
|
||||
multiple: true,
|
||||
strict: true,
|
||||
})
|
||||
const keyboard = new Keyboard({
|
||||
enabled: true,
|
||||
})
|
||||
const keyboard = new Keyboard()
|
||||
|
||||
graph.use(clipboard)
|
||||
graph.use(selection)
|
||||
|
@ -3,13 +3,12 @@ import { Graph } from '@antv/x6'
|
||||
import { Keyboard } from '@antv/x6-plugin-keyboard'
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
import { History } from '@antv/x6-plugin-history'
|
||||
import { Button } from 'antd'
|
||||
import '../index.less'
|
||||
|
||||
export default class Example extends React.Component<
|
||||
{},
|
||||
{ graph: Graph | undefined }
|
||||
> {
|
||||
export default class Example extends React.Component {
|
||||
private container: HTMLDivElement
|
||||
private graph: Graph
|
||||
|
||||
componentDidMount() {
|
||||
const graph = new Graph({
|
||||
@ -19,11 +18,9 @@ export default class Example extends React.Component<
|
||||
grid: true,
|
||||
})
|
||||
|
||||
this.setState({ graph })
|
||||
|
||||
const selection = new Selection({ enabled: true })
|
||||
const keyboard = new Keyboard({ enabled: true })
|
||||
const history = new History({ enabled: true, stackSize: 5 })
|
||||
const selection = new Selection()
|
||||
const keyboard = new Keyboard()
|
||||
const history = new History({ stackSize: 5 })
|
||||
|
||||
graph.use(selection)
|
||||
graph.use(keyboard)
|
||||
@ -62,6 +59,8 @@ export default class Example extends React.Component<
|
||||
keyboard.bindKey('command+shift+z', () => {
|
||||
this.redo()
|
||||
})
|
||||
|
||||
this.graph = graph
|
||||
}
|
||||
|
||||
refContainer = (container: HTMLDivElement) => {
|
||||
@ -69,35 +68,31 @@ export default class Example extends React.Component<
|
||||
}
|
||||
|
||||
enablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph?.enablePlugins('keyboard')
|
||||
this.graph.enablePlugins('history')
|
||||
}
|
||||
|
||||
disablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph?.disablePlugins('keyboard')
|
||||
this.graph.disablePlugins('history')
|
||||
}
|
||||
|
||||
undo = () => {
|
||||
const { graph } = this.state
|
||||
const history = graph?.getPlugin('history') as History
|
||||
history?.undo()
|
||||
const history = this.graph.getPlugin('history') as History
|
||||
history.undo()
|
||||
}
|
||||
|
||||
redo = () => {
|
||||
const { graph } = this.state
|
||||
const history = graph?.getPlugin('history') as History
|
||||
history?.redo()
|
||||
const history = this.graph.getPlugin('history') as History
|
||||
history.redo()
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="x6-graph-wrap">
|
||||
<div ref={this.refContainer} className="x6-graph" />
|
||||
<button onClick={this.enablePlugins}>enable</button>
|
||||
<button onClick={this.disablePlugins}>disable</button>
|
||||
<button onClick={this.undo}>undo</button>
|
||||
<button onClick={this.redo}>redo</button>
|
||||
<Button onClick={this.enablePlugins}>enable</Button>
|
||||
<Button onClick={this.disablePlugins}>disable</Button>
|
||||
<Button onClick={this.undo}>undo</Button>
|
||||
<Button onClick={this.redo}>redo</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -2,13 +2,12 @@ import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import { Keyboard } from '@antv/x6-plugin-keyboard'
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
import { Button } from 'antd'
|
||||
import '../index.less'
|
||||
|
||||
export default class Example extends React.Component<
|
||||
{},
|
||||
{ graph: Graph | undefined }
|
||||
> {
|
||||
export default class Example extends React.Component {
|
||||
private container: HTMLDivElement
|
||||
private graph: Graph
|
||||
|
||||
componentDidMount() {
|
||||
const graph = new Graph({
|
||||
@ -18,10 +17,8 @@ export default class Example extends React.Component<
|
||||
grid: true,
|
||||
})
|
||||
|
||||
this.setState({ graph })
|
||||
|
||||
const selection = new Selection({ enabled: true })
|
||||
const keyboard = new Keyboard({ enabled: true })
|
||||
const selection = new Selection()
|
||||
const keyboard = new Keyboard()
|
||||
graph.use(selection)
|
||||
graph.use(keyboard)
|
||||
|
||||
@ -52,6 +49,8 @@ export default class Example extends React.Component<
|
||||
keyboard.bindKey('backspace', () => {
|
||||
graph.removeCells(selection.getSelectedCells())
|
||||
})
|
||||
|
||||
this.graph = graph
|
||||
}
|
||||
|
||||
refContainer = (container: HTMLDivElement) => {
|
||||
@ -59,21 +58,19 @@ export default class Example extends React.Component<
|
||||
}
|
||||
|
||||
enablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph.enablePlugins('keyboard')
|
||||
this.graph.enablePlugins('keyboard')
|
||||
}
|
||||
|
||||
disablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph.disablePlugins('keyboard')
|
||||
this.graph.disablePlugins('keyboard')
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="x6-graph-wrap">
|
||||
<div ref={this.refContainer} className="x6-graph" />
|
||||
<button onClick={this.enablePlugins}>enable</button>
|
||||
<button onClick={this.disablePlugins}>disable</button>
|
||||
<Button onClick={this.enablePlugins}>enable</Button>
|
||||
<Button onClick={this.disablePlugins}>disable</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
25
examples/x6-example-features/src/pages/minimap/index.less
Normal file
25
examples/x6-example-features/src/pages/minimap/index.less
Normal file
@ -0,0 +1,25 @@
|
||||
.minimap-app {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
|
||||
.app-btns {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.app-minimap {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 620px;
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.x6-widget-minimap-viewport {
|
||||
border: 2px solid #8f8f8f;
|
||||
}
|
||||
|
||||
.x6-widget-minimap-viewport-zoom {
|
||||
border: 2px solid #8f8f8f;
|
||||
}
|
||||
}
|
168
examples/x6-example-features/src/pages/minimap/index.tsx
Normal file
168
examples/x6-example-features/src/pages/minimap/index.tsx
Normal file
@ -0,0 +1,168 @@
|
||||
import * as React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import { MiniMap } from '@antv/x6-plugin-minimap'
|
||||
import { Scroller } from '@antv/x6-plugin-scroller'
|
||||
import { Radio } from 'antd'
|
||||
import { SimpleNodeView } from './simple-view'
|
||||
import './index.less'
|
||||
|
||||
const options = [
|
||||
{ label: '简单视图', value: 'simple' },
|
||||
{ label: '详细视图', value: 'detailed' },
|
||||
]
|
||||
|
||||
export default class Example extends React.Component {
|
||||
private container: HTMLDivElement
|
||||
private minimapContainer: HTMLDivElement
|
||||
private graph: Graph
|
||||
|
||||
componentDidMount() {
|
||||
this.graph = new Graph({
|
||||
container: this.container,
|
||||
width: 600,
|
||||
height: 320,
|
||||
background: {
|
||||
color: '#F2F7FA',
|
||||
},
|
||||
})
|
||||
|
||||
this.graph.use(
|
||||
new Scroller({
|
||||
pageVisible: true,
|
||||
pageBreak: false,
|
||||
pannable: true,
|
||||
}),
|
||||
)
|
||||
this.graph.use(
|
||||
new MiniMap({
|
||||
container: this.minimapContainer,
|
||||
width: 200,
|
||||
height: 160,
|
||||
padding: 10,
|
||||
}),
|
||||
)
|
||||
|
||||
this.graph.addNode({
|
||||
x: 200,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 40,
|
||||
label: 'Rect',
|
||||
attrs: {
|
||||
body: {
|
||||
stroke: '#8f8f8f',
|
||||
strokeWidth: 1,
|
||||
fill: '#fff',
|
||||
rx: 6,
|
||||
ry: 6,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const source = this.graph.addNode({
|
||||
x: 32,
|
||||
y: 32,
|
||||
width: 100,
|
||||
height: 40,
|
||||
label: 'Hello',
|
||||
attrs: {
|
||||
body: {
|
||||
stroke: '#8f8f8f',
|
||||
strokeWidth: 1,
|
||||
fill: '#fff',
|
||||
rx: 6,
|
||||
ry: 6,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const target = this.graph.addNode({
|
||||
shape: 'circle',
|
||||
x: 160,
|
||||
y: 180,
|
||||
width: 60,
|
||||
height: 60,
|
||||
label: 'World',
|
||||
attrs: {
|
||||
body: {
|
||||
stroke: '#8f8f8f',
|
||||
strokeWidth: 1,
|
||||
fill: '#fff',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
this.graph.addEdge({
|
||||
source,
|
||||
target,
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#8f8f8f',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
onMinimapViewChange = (val: string) => {
|
||||
this.graph.disposePlugins('minimap')
|
||||
if (val === 'simple') {
|
||||
this.graph.use(
|
||||
new MiniMap({
|
||||
container: this.minimapContainer,
|
||||
width: 200,
|
||||
height: 160,
|
||||
padding: 10,
|
||||
graphOptions: {
|
||||
createCellView(cell) {
|
||||
// 可以返回三种类型数据
|
||||
// 1. null: 不渲染
|
||||
// 2. undefined: 使用 X6 默认渲染方式
|
||||
// 3. CellView: 自定义渲染
|
||||
if (cell.isEdge()) {
|
||||
return null
|
||||
}
|
||||
if (cell.isNode()) {
|
||||
return SimpleNodeView
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
this.graph.use(
|
||||
new MiniMap({
|
||||
container: this.minimapContainer,
|
||||
width: 200,
|
||||
height: 160,
|
||||
padding: 10,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
refContainer = (container: HTMLDivElement) => {
|
||||
this.container = container
|
||||
}
|
||||
|
||||
refMiniMapContainer = (container: HTMLDivElement) => {
|
||||
this.minimapContainer = container
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="minimap-app">
|
||||
<div className="app-btns">
|
||||
<Radio.Group
|
||||
options={options}
|
||||
onChange={(e) => this.onMinimapViewChange(e.target.value)}
|
||||
defaultValue={'detailed'}
|
||||
optionType="button"
|
||||
/>
|
||||
</div>
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
<div className="app-minimap" ref={this.refMiniMapContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { NodeView } from '@antv/x6'
|
||||
|
||||
export class SimpleNodeView extends NodeView {
|
||||
protected renderMarkup() {
|
||||
return this.renderJSONMarkup({
|
||||
tagName: 'rect',
|
||||
selector: 'body',
|
||||
})
|
||||
}
|
||||
|
||||
update() {
|
||||
super.update({
|
||||
body: {
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
fill: '#8f8f8f',
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ export default class Example extends React.Component {
|
||||
grid: true,
|
||||
})
|
||||
|
||||
this.scroller = new Scroller({ enabled: true })
|
||||
this.scroller = new Scroller()
|
||||
this.graph2.use(this.scroller)
|
||||
|
||||
const data = [
|
||||
|
@ -36,7 +36,6 @@ export default class Example extends React.Component {
|
||||
})
|
||||
|
||||
this.scroller = new Scroller({
|
||||
enabled: true,
|
||||
pageVisible: true,
|
||||
pageBreak: true,
|
||||
pannable: {
|
||||
@ -45,7 +44,6 @@ export default class Example extends React.Component {
|
||||
},
|
||||
})
|
||||
this.selection = new Selection({
|
||||
enabled: true,
|
||||
rubberband: true,
|
||||
modifiers: 'shift',
|
||||
})
|
||||
|
@ -13,13 +13,14 @@ export default class Example extends React.Component {
|
||||
width: 800,
|
||||
height: 600,
|
||||
grid: true,
|
||||
panning: {
|
||||
enabled: true,
|
||||
eventTypes: ['mouseWheelDown'],
|
||||
},
|
||||
})
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
enabled: true,
|
||||
})
|
||||
const keyboard = new Keyboard()
|
||||
const selection = new Selection({
|
||||
enabled: true,
|
||||
rubberband: true,
|
||||
multiple: true,
|
||||
strict: true,
|
||||
|
@ -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
|
||||
|
@ -15,7 +15,6 @@ export default class Example extends React.Component {
|
||||
})
|
||||
|
||||
const snapline = new Snapline({
|
||||
enabled: true,
|
||||
sharp: true,
|
||||
})
|
||||
graph.use(snapline)
|
||||
|
@ -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'
|
||||
|
@ -24,9 +24,7 @@ export default class Example extends React.Component<
|
||||
grid: true,
|
||||
})
|
||||
|
||||
this.history = new History({
|
||||
enabled: true,
|
||||
})
|
||||
this.history = new History()
|
||||
this.history.on('change', () => {
|
||||
this.setState({
|
||||
canRedo: this.history.canRedo(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import data from './data'
|
||||
import { Button } from 'antd'
|
||||
import './index.less'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
|
||||
@ -138,7 +139,7 @@ export default class Canvas extends React.Component {
|
||||
return (
|
||||
<div className="x6-graph-wrap">
|
||||
<div ref={this.refContainer} className="x6-graph" />
|
||||
<button id="add-btn">add</button>
|
||||
<Button id="add-btn">add</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
23
package.json
23
package.json
@ -14,14 +14,16 @@
|
||||
"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:demo": "cd ./examples/x6-example-features && pnpm start",
|
||||
"start:site": "cd ./sites/x6-sites && pnpm start",
|
||||
"release": "pnpm publish --no-git-checks -r --filter @antv/x6"
|
||||
},
|
||||
"rss": {
|
||||
"clean:turbo": "rimraf .turbo",
|
||||
@ -36,8 +38,8 @@
|
||||
"build:umd": "pnpm run --if-present build:less && rollup -c ../../rollup.config.js --bundleConfigAsCjs",
|
||||
"build:dev": "pnpm run --if-present build:less && run-p -s build:cjs build:esm",
|
||||
"build:watch": "run-s -s build:watch:esm",
|
||||
"build:watch:esm": "run-s -s 'build:esm -- -w'",
|
||||
"build:watch:cjs": "run-s -s 'build:cjs -- -w'",
|
||||
"build:watch:esm": "run-s -s \"build:esm -- -w\"",
|
||||
"build:watch:cjs": "run-s -s \"build:cjs -- -w\"",
|
||||
"build": "run-p -s build:dev build:umd",
|
||||
"prebuild": "run-s -s clean:build",
|
||||
"test": {
|
||||
@ -96,6 +98,7 @@
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-replace": "^5.0.1",
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@rollup/plugin-terser": "^0.2.0",
|
||||
"@semantic-release-monorepo/cli": "^2.1.2",
|
||||
"@semantic-release/changelog": "^6.0.2",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
@ -108,6 +111,7 @@
|
||||
"boxen": "^7.0.0",
|
||||
"colors": "^1.4.0",
|
||||
"coveralls": "^3.1.1",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
@ -136,7 +140,7 @@
|
||||
"less": "^4.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.20",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-less": "^6.0.0",
|
||||
"prettier": "^2.8.0",
|
||||
"pretty-quick": "^3.1.1",
|
||||
@ -149,7 +153,7 @@
|
||||
"run-shared-scripts": "^1.1.5",
|
||||
"semantic-release": "^19.0.5",
|
||||
"sinon": "^15.0.1",
|
||||
"stylelint": "^14.15.0",
|
||||
"stylelint": "^15.10.1",
|
||||
"stylelint-config-prettier": "^9.0.4",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-standard": "^29.0.0",
|
||||
@ -159,9 +163,10 @@
|
||||
"ts-node": "^10.2.1",
|
||||
"tslib": "^2.4.1",
|
||||
"turbo": "^1.6.3",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"@changesets/cli": "2.26.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-terser": "^0.2.0"
|
||||
"engines": {
|
||||
"pnpm": ">=7"
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,12 @@
|
||||
styleUrls: ['./node.component.scss'],
|
||||
})
|
||||
export class NodeComponent implements AfterViewInit, OnChanges {
|
||||
@Input() value: string;
|
||||
@Input() value: string
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
import { register } from '@antv/x6-angular-shape'
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -33,7 +33,7 @@ export class AppComponent implements AfterViewInit {
|
||||
height: 20,
|
||||
content: NodeComponent,
|
||||
injector: this.injector,
|
||||
});
|
||||
})
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-component-node',
|
||||
@ -45,10 +45,9 @@ export class AppComponent implements AfterViewInit {
|
||||
value: '糟糕糟糕 Oh my god',
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### TemplateRef 渲染
|
||||
@ -62,7 +61,7 @@ export class AppComponent implements AfterViewInit {
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
import { register } from '@antv/x6-angular-shape'
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -70,7 +69,7 @@ import { register } from "@antv/x6-angular-shape";
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
@ViewChild('template') template: TemplateRef<{}>;
|
||||
@ViewChild('template') template: TemplateRef<{}>
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
@ -79,7 +78,7 @@ export class AppComponent implements AfterViewInit {
|
||||
height: 20,
|
||||
content: this.template,
|
||||
injector: this.injector,
|
||||
});
|
||||
})
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-template-node',
|
||||
@ -90,47 +89,48 @@ export class AppComponent implements AfterViewInit {
|
||||
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)
|
||||
有的, 因为 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版本有什么新特性吗?
|
||||
- 1.x 版本中已经这么用了, 沿用该 API 可以降低用户升级成本
|
||||
- `Input` 的概念其实是来自 `Component`, 而 `TemplateRef` 中是 `context`, 在二者的基础上抽象一个 `Arguments` 的概念更通用些
|
||||
|
||||
### 2.x 版本的 x6-angular-shape 相比较 1.x 版本有什么新特性吗?
|
||||
|
||||
实现思路其实和之前是差不多的. 但是确实有几个点值得一提.
|
||||
|
||||
#### demo更聚焦
|
||||
#### demo 更聚焦
|
||||
|
||||
1.x版本的 demo 除了渲染组件外, 还写了连线、清除等一系列案例. 看似扩展, 实则眼花缭乱. 作为 `x6-angular-shape`的 demo, 2.x版本更加聚焦, 更加聚焦于shape的使用与性能测试等, 与插件无关的内容请查看X6官网.
|
||||
1.x 版本的 demo 除了渲染组件外, 还写了连线、清除等一系列案例. 看似扩展, 实则眼花缭乱. 作为 `x6-angular-shape`的 demo, 2.x 版本更加聚焦, 更加聚焦于 shape 的使用与性能测试等, 与插件无关的内容请查看 X6 官网.
|
||||
|
||||
#### 功能更稳定
|
||||
|
||||
在1.x版本中, 虽然实现了功能, 但是使用场景的思考不够全面. 比如`ngArguments`的变化, 对 `TemplateRef`的场景并不生效. 虽然对`Component`生效但是无法触发`ngOnChanges`. 而在新版本中, 这些问题都将不复存在.
|
||||
在 1.x 版本中, 虽然实现了功能, 但是使用场景的思考不够全面. 比如`ngArguments`的变化, 对 `TemplateRef`的场景并不生效. 虽然对`Component`生效但是无法触发`ngOnChanges`. 而在新版本中, 这些问题都将不复存在.
|
||||
|
||||
### 版本要求
|
||||
|
||||
你的Angular版本至少在14及以上才可以. 14以下需要用 hack 的方式实现一些特性, 比较麻烦. 暂时不提供, 如有需要可提issue, 我再专门介绍下如何实现.
|
||||
你的 Angular 版本至少在 14 及以上才可以. 14 以下需要用 hack 的方式实现一些特性, 比较麻烦. 暂时不提供, 如有需要可提 issue, 我再专门介绍下如何实现.
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-angular-shape",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.2",
|
||||
"description": "X6 shape for rendering angular components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"shape",
|
||||
@ -42,7 +43,8 @@
|
||||
"@angular/core": ">= 14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
"@antv/x6": "^2.x",
|
||||
"@angular/core": ">= 14"
|
||||
},
|
||||
"author": {
|
||||
"name": "Eve-Sama",
|
||||
|
@ -44,9 +44,9 @@ export class AngularShapeView extends NodeView<AngularShape> {
|
||||
}
|
||||
|
||||
protected renderAngularContent(): void {
|
||||
this.unmountAngularContent()
|
||||
const container = this.getNodeContainer()
|
||||
if (container) {
|
||||
this.unmountAngularContent()
|
||||
const node = this.cell
|
||||
const { injector, content } = registerInfo.get(node.shape)!
|
||||
const viewContainerRef = injector.get(ViewContainerRef)
|
||||
@ -61,7 +61,9 @@ export class AngularShapeView extends NodeView<AngularShape> {
|
||||
this.setInstanceInput(content, embeddedViewRef),
|
||||
)
|
||||
} else {
|
||||
const componentRef = viewContainerRef.createComponent(content)
|
||||
const componentRef = viewContainerRef.createComponent(content, {
|
||||
injector,
|
||||
})
|
||||
const insertNode = (componentRef.hostView as EmbeddedViewRef<any>)
|
||||
.rootNodes[0] as HTMLElement
|
||||
container.appendChild(insertNode)
|
||||
@ -69,6 +71,7 @@ export class AngularShapeView extends NodeView<AngularShape> {
|
||||
node.on('change:data', () =>
|
||||
this.setInstanceInput(content, componentRef),
|
||||
)
|
||||
node.on('removed', () => componentRef.destroy())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,7 @@
|
||||
## @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)
|
||||
# @antv/x6-common
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Bug Fixes
|
||||
### Patch Changes
|
||||
|
||||
* 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix index error for priorityQueue ([#3179](https://github.com/antvis/x6/issues/3179)) ([d64150b](https://github.com/antvis/x6/commit/d64150bfadf10fe21f44734a0267261260b8c53b))
|
||||
|
||||
## @antv/x6-common [2.0.5](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.4...@antv/x6-common@2.0.5) (2023-01-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* optimize css loader ([#3156](https://github.com/antvis/x6/issues/3156)) ([9c48ad8](https://github.com/antvis/x6/commit/9c48ad8dfc99e623a57855295d07c35be5483073))
|
||||
|
||||
## @antv/x6-common [2.0.4](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.3...@antv/x6-common@2.0.4) (2022-12-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix window incompatibility problem ([#3070](https://github.com/antvis/x6/issues/3070)) ([d8e1e63](https://github.com/antvis/x6/commit/d8e1e637d8027b9494cd26efc87815d74bd51366))
|
||||
|
||||
## @antv/x6-common [2.0.1](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.0...@antv/x6-common@2.0.1) (2022-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* npm version ([cb0cfde](https://github.com/antvis/x6/commit/cb0cfdeb4dbe8858569e6899db08ccb9ab8ba4e7))
|
||||
|
||||
## @antv/x6-common [2.0.1](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.0...@antv/x6-common@2.0.1) (2022-11-24)
|
||||
- add case sensitive attr
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-common",
|
||||
"version": "2.0.10",
|
||||
"version": "2.0.17",
|
||||
"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",
|
||||
|
@ -294,10 +294,16 @@ describe('EventDom', () => {
|
||||
expect(() => div.off('click', false)).not.toThrowError()
|
||||
})
|
||||
|
||||
it('should do noting for elem which do not bind any events', () => {
|
||||
it('should do nothing for elem which do not bind any events', () => {
|
||||
const div = new EventDom()
|
||||
expect(() => div.off()).not.toThrowError()
|
||||
})
|
||||
|
||||
it('should do nothing for unexist event', () => {
|
||||
const div = new EventDom()
|
||||
div.on('whatever', () => {})
|
||||
expect(() => div.off('unexist')).not.toThrowError()
|
||||
})
|
||||
})
|
||||
|
||||
describe('trigger()', () => {
|
||||
|
@ -3,7 +3,15 @@ import { EventArgs } from '../event/types'
|
||||
import { ObjectExt } from '../object'
|
||||
import { Disposable } from './disposable'
|
||||
|
||||
export class Basecoat<A extends EventArgs = any> extends Events<A> {}
|
||||
export class Basecoat<A extends EventArgs = any>
|
||||
extends Events<A>
|
||||
implements Disposable
|
||||
{
|
||||
@Disposable.dispose()
|
||||
dispose() {
|
||||
this.off()
|
||||
}
|
||||
}
|
||||
|
||||
export interface Basecoat extends Disposable {}
|
||||
|
||||
|
@ -56,11 +56,11 @@ export namespace Disposable {
|
||||
) => {
|
||||
const raw = descriptor.value
|
||||
const proto = target.__proto__ as IDisposable // eslint-disable-line
|
||||
descriptor.value = function (this: IDisposable) {
|
||||
descriptor.value = function (this: IDisposable, ...args: any[]) {
|
||||
if (this.disposed) {
|
||||
return
|
||||
}
|
||||
raw.call(this)
|
||||
raw.call(this, ...args)
|
||||
proto.dispose.call(this)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ export const CASE_SENSITIVE_ATTR = [
|
||||
'repeatCount',
|
||||
'textLength',
|
||||
'lengthAdjust',
|
||||
'gradientUnits',
|
||||
]
|
||||
|
||||
export type Attributes = { [key: string]: string | number | null | undefined }
|
||||
|
@ -148,7 +148,10 @@ export namespace Core {
|
||||
let type = originType
|
||||
const hook = EventHook.get(type)
|
||||
type = (selector ? hook.delegateType : hook.bindType) || type
|
||||
const bag = events[type] || {}
|
||||
const bag = events[type]
|
||||
if (!bag) {
|
||||
return
|
||||
}
|
||||
const rns =
|
||||
namespaces.length > 0
|
||||
? new RegExp(`(^|\\.)${namespaces.join('\\.(?:.*\\.|)')}(\\.|$)`)
|
||||
|
@ -62,7 +62,7 @@ export class EventObject<
|
||||
}
|
||||
}
|
||||
|
||||
preventDefault() {
|
||||
preventDefault = () => {
|
||||
const e = this.originalEvent
|
||||
|
||||
this.isDefaultPrevented = Util.returnTrue
|
||||
@ -72,7 +72,7 @@ export class EventObject<
|
||||
}
|
||||
}
|
||||
|
||||
stopPropagation() {
|
||||
stopPropagation = () => {
|
||||
const e = this.originalEvent
|
||||
|
||||
this.isPropagationStopped = Util.returnTrue
|
||||
@ -82,7 +82,7 @@ export class EventObject<
|
||||
}
|
||||
}
|
||||
|
||||
stopImmediatePropagation() {
|
||||
stopImmediatePropagation = () => {
|
||||
const e = this.originalEvent
|
||||
|
||||
this.isImmediatePropagationStopped = Util.returnTrue
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { PointLike } from '../types'
|
||||
import { createSvgElement } from './elem'
|
||||
|
||||
const svgDocument = createSvgElement('svg') as SVGSVGElement
|
||||
const transformRegex = /(\w+)\(([^,)]+),?([^)]+)?\)/gi
|
||||
const transformSeparatorRegex = /[ ,]+/
|
||||
const transformationListRegex = /^(\w+)\((.*)\)/
|
||||
@ -36,6 +35,7 @@ export interface Scale {
|
||||
* @see https://developer.mozilla.org/en/docs/Web/API/SVGPoint
|
||||
*/
|
||||
export function createSVGPoint(x: number, y: number) {
|
||||
const svgDocument = createSvgElement('svg') as SVGSVGElement
|
||||
const p = svgDocument.createSVGPoint()
|
||||
p.x = x
|
||||
p.y = y
|
||||
@ -58,6 +58,7 @@ export function createSVGPoint(x: number, y: number) {
|
||||
* @see https://developer.mozilla.org/en/docs/Web/API/SVGMatrix
|
||||
*/
|
||||
export function createSVGMatrix(matrix?: DOMMatrix | MatrixLike | null) {
|
||||
const svgDocument = createSvgElement('svg') as SVGSVGElement
|
||||
const mat = svgDocument.createSVGMatrix()
|
||||
if (matrix != null) {
|
||||
const source = matrix as any
|
||||
@ -75,6 +76,7 @@ export function createSVGMatrix(matrix?: DOMMatrix | MatrixLike | null) {
|
||||
* @see https://developer.mozilla.org/en/docs/Web/API/SVGTransform
|
||||
*/
|
||||
export function createSVGTransform(matrix?: DOMMatrix | MatrixLike) {
|
||||
const svgDocument = createSvgElement('svg') as SVGSVGElement
|
||||
if (matrix != null) {
|
||||
if (!(matrix instanceof DOMMatrix)) {
|
||||
matrix = createSVGMatrix(matrix) // eslint-disable-line
|
||||
|
@ -5,7 +5,7 @@ function camelize(str: string) {
|
||||
|
||||
const memoized: { [key: string]: string | null } = {}
|
||||
const prefixes = ['webkit', 'ms', 'moz', 'o']
|
||||
const testStyle = document ? document.createElement('div').style : {}
|
||||
const testStyle = typeof document !== 'undefined' ? document.createElement('div').style : {}
|
||||
|
||||
function getWithPrefix(name: string) {
|
||||
for (let i = 0; i < prefixes.length; i += 1) {
|
||||
|
@ -1,4 +1,6 @@
|
||||
export const clearSelection = (function () {
|
||||
if (typeof document == 'undefined')
|
||||
return function () {}
|
||||
const doc = document as any
|
||||
if (doc.selection) {
|
||||
return function () {
|
||||
|
@ -1,13 +1,12 @@
|
||||
/* eslint-disable no-control-regex */
|
||||
|
||||
import { Size } from '../types'
|
||||
import { StringExt } from '../string'
|
||||
import { Text } from '../text'
|
||||
import { attr } from './attr'
|
||||
import { Vector } from '../vector'
|
||||
import { createSvgElement, empty } from './elem'
|
||||
|
||||
const canvasContext = document.createElement('canvas').getContext('2d')!
|
||||
|
||||
function createTextPathNode(
|
||||
attrs: { d?: string; 'xlink:href'?: string },
|
||||
elem: SVGElement,
|
||||
@ -198,12 +197,16 @@ export function text(
|
||||
const autoLineHeight = defaultLineHeight === 'auto'
|
||||
const lineHeight = autoLineHeight ? '1.5em' : defaultLineHeight || '1em'
|
||||
|
||||
let needEmptyElem = true
|
||||
const childs = elem.children
|
||||
if (childs.length === 1 && childs[0].tagName.toUpperCase() === 'TITLE') {
|
||||
needEmptyElem = false
|
||||
let needEmpty = true
|
||||
const childNodes = elem.childNodes
|
||||
if (childNodes.length === 1) {
|
||||
const node = childNodes[0] as any
|
||||
if (node && node.tagName.toUpperCase() === 'TITLE') {
|
||||
needEmpty = false
|
||||
}
|
||||
}
|
||||
if (needEmptyElem) {
|
||||
|
||||
if (needEmpty) {
|
||||
empty(elem)
|
||||
}
|
||||
|
||||
@ -369,6 +372,7 @@ export function text(
|
||||
}
|
||||
|
||||
export function measureText(text: string, styles: any = {}) {
|
||||
const canvasContext = document.createElement('canvas').getContext('2d')!
|
||||
if (!text) {
|
||||
return { width: 0 }
|
||||
}
|
||||
@ -438,6 +442,27 @@ export function breakText(
|
||||
const width = size.width
|
||||
const height = size.height
|
||||
const eol = options.eol || '\n'
|
||||
const fontSize = styles.fontSize || 14
|
||||
const lineHeight = styles.lineHeight
|
||||
? parseFloat(styles.lineHeight)
|
||||
: Math.ceil(fontSize * 1.4)
|
||||
const maxLines = Math.floor(height / lineHeight)
|
||||
|
||||
if (text.indexOf(eol) > -1) {
|
||||
const delimiter = StringExt.uuid()
|
||||
const splitText: string[] = []
|
||||
|
||||
text.split(eol).map((line) => {
|
||||
const part = breakText(line, { ...size, height: Number.MAX_SAFE_INTEGER }, styles, { ...options, eol: delimiter })
|
||||
|
||||
if (part) {
|
||||
splitText.push(...part.split(delimiter))
|
||||
}
|
||||
})
|
||||
|
||||
return splitText.slice(0, maxLines).join(eol)
|
||||
}
|
||||
|
||||
const { width: textWidth } = measureText(text, styles)
|
||||
|
||||
if (textWidth < width) {
|
||||
@ -445,11 +470,6 @@ export function breakText(
|
||||
}
|
||||
|
||||
const lines = []
|
||||
const fontSize = styles.fontSize || 14
|
||||
const lineHeight = styles.lineHeight
|
||||
? parseFloat(styles.lineHeight)
|
||||
: Math.ceil(fontSize * 1.4)
|
||||
const maxLines = Math.floor(height / lineHeight)
|
||||
|
||||
let remainText = text
|
||||
let remainWidth = textWidth
|
||||
|
@ -10,27 +10,29 @@ if (
|
||||
|
||||
// compatible with ParentNode.append() before chrome 54
|
||||
// https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md
|
||||
;(function (arr) {
|
||||
arr.forEach((item) => {
|
||||
if (Object.prototype.hasOwnProperty.call(item, 'append')) {
|
||||
return
|
||||
}
|
||||
Object.defineProperty(item, 'append', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value(...args: any[]) {
|
||||
const docFrag = document.createDocumentFragment()
|
||||
if (typeof window !== 'undefined') {
|
||||
;(function (arr) {
|
||||
arr.forEach((item) => {
|
||||
if (Object.prototype.hasOwnProperty.call(item, 'append')) {
|
||||
return
|
||||
}
|
||||
Object.defineProperty(item, 'append', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value(...args: any[]) {
|
||||
const docFrag = document.createDocumentFragment()
|
||||
|
||||
args.forEach((arg: any) => {
|
||||
const isNode = arg instanceof Node
|
||||
docFrag.appendChild(
|
||||
isNode ? arg : document.createTextNode(String(arg)),
|
||||
)
|
||||
})
|
||||
args.forEach((arg: any) => {
|
||||
const isNode = arg instanceof Node
|
||||
docFrag.appendChild(
|
||||
isNode ? arg : document.createTextNode(String(arg)),
|
||||
)
|
||||
})
|
||||
|
||||
this.appendChild(docFrag)
|
||||
},
|
||||
this.appendChild(docFrag)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})([Element.prototype, Document.prototype, DocumentFragment.prototype])
|
||||
})([Element.prototype, Document.prototype, DocumentFragment.prototype])
|
||||
}
|
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
|
46
packages/x6-devtool/README.md
Normal file
46
packages/x6-devtool/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# X6 Devtool
|
||||
|
||||
> A devtool for @antv/x6 in chrome, it's still WIP, you can load it in unpack way;
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Install from chrome web store
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
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.
23
packages/x6-devtool/devtools/manifest.json
Normal file
23
packages/x6-devtool/devtools/manifest.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "AntV X6 Dev Tool",
|
||||
"description": "devtool for x6 graph",
|
||||
"version": "0.0.1",
|
||||
"devtools_page": "x6_devtools.html",
|
||||
"minimum_chrome_version": "88",
|
||||
"manifest_version": 3,
|
||||
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
|
||||
"icons": {
|
||||
"16": "icons/16.png",
|
||||
"32": "icons/32.png",
|
||||
"48": "icons/48.png",
|
||||
"128": "icons/128.png"
|
||||
},
|
||||
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["main.html", "panel.html", "script/backend.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
],
|
||||
"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.94.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,12 +0,0 @@
|
||||
## @antv/x6-geometry [2.0.4](https://github.com/antvis/x6/compare/@antv/x6-geometry@2.0.3...@antv/x6-geometry@2.0.4) (2022-11-29)
|
||||
|
||||
## @antv/x6-geometry [2.0.3](https://github.com/antvis/x6/compare/@antv/x6-geometry@2.0.2...@antv/x6-geometry@2.0.3) (2022-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* npm version ([cb0cfde](https://github.com/antvis/x6/commit/cb0cfdeb4dbe8858569e6899db08ccb9ab8ba4e7))
|
||||
|
||||
## @antv/x6-geometry [2.0.2](https://github.com/antvis/x6/compare/@antv/x6-geometry@2.0.1...@antv/x6-geometry@2.0.2) (2022-11-25)
|
||||
|
||||
## @antv/x6-geometry [2.0.1](https://github.com/antvis/x6/compare/@antv/x6-geometry@2.0.0...@antv/x6-geometry@2.0.1) (2022-11-24)
|
@ -2,15 +2,6 @@
|
||||
|
||||
> Some useful geometry operations.
|
||||
|
||||
<a href="/LICENSE"><img src="https://img.shields.io/github/license/antvis/x6?style=flat-square" alt="MIT License"></a>
|
||||
<a href="https://www.typescriptlang.org"><img alt="Language" src="https://img.shields.io/badge/language-TypeScript-blue.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/antvis/x6/pulls"><img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=flat-square"></a>
|
||||
<a href="https://x6.antv.antgroup.com"><img alt="website" src="https://img.shields.io/static/v1?label=&labelColor=505050&message=website&color=0076D6&style=flat-square&logo=google-chrome&logoColor=0076D6"></a>
|
||||
<a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/workflow/status/antvis/x6/%F0%9F%91%B7%E3%80%80CI/master?logo=github&style=flat-square"></a>
|
||||
<a href="https://app.codecov.io/gh/antvis/x6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&flag=x6-geometry&style=flat-square&token=15CO54WYUV"></a>
|
||||
<a href="https://lgtm.com/projects/g/antvis/x6/context:javascript"><img alt="Language grade: JavaScript" src="https://img.shields.io/lgtm/grade/javascript/g/antvis/x6.svg?logo=lgtm&style=flat-square"></a>
|
||||
<a href="/LICENSE"><img src="https://img.shields.io/github/license/antvis/x6?style=flat-square" alt="MIT License"></a> <a href="https://www.typescriptlang.org"><img alt="Language" src="https://img.shields.io/badge/language-TypeScript-blue.svg?style=flat-square"></a> <a href="https://github.com/antvis/x6/pulls"><img alt="PRs Welcome" src="https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=flat-square"></a> <a href="https://x6.antv.antgroup.com"><img alt="website" src="https://img.shields.io/static/v1?label=&labelColor=505050&message=website&color=0076D6&style=flat-square&logo=google-chrome&logoColor=0076D6"></a> <a href="https://github.com/antvis/X6/actions/workflows/ci.yml"><img alt="build" src="https://img.shields.io/github/workflow/status/antvis/x6/%F0%9F%91%B7%E3%80%80CI/master?logo=github&style=flat-square"></a> <a href="https://app.codecov.io/gh/antvis/x6"><img alt="coverage" src="https://img.shields.io/codecov/c/gh/antvis/x6?logo=codecov&flag=x6-geometry&style=flat-square&token=15CO54WYUV"></a> <a href="https://lgtm.com/projects/g/antvis/x6/context:javascript"><img alt="Language grade: JavaScript" src="https://img.shields.io/lgtm/grade/javascript/g/antvis/x6.svg?logo=lgtm&style=flat-square"></a>
|
||||
|
||||
<a href="https://www.npmjs.com/package/@antv/x6-geometry"><img alt="NPM Package" src="https://img.shields.io/npm/v/@antv/x6-geometry.svg?style=flat-square"></a>
|
||||
<a href="https://www.npmjs.com/package/@antv/x6-geometry"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@antv/x6-geometry?logo=npm&style=flat-square"></a>
|
||||
<a href="https://david-dm.org/antvis/x6?path=packages/x6-geometry"><img alt="Dependency Status" src="https://david-dm.org/antvis/x6.svg?style=flat-square&path=packages/x6-geometry"></a>
|
||||
<a href="https://david-dm.org/antvis/x6?type=dev&path=packages/x6-geometry"><img alt="devDependencies Status" src="https://david-dm.org/antvis/x6/dev-status.svg?style=flat-square&path=packages/x6-geometry" ></a>
|
||||
<a href="https://www.npmjs.com/package/@antv/x6-geometry"><img alt="NPM Package" src="https://img.shields.io/npm/v/@antv/x6-geometry.svg?style=flat-square"></a> <a href="https://www.npmjs.com/package/@antv/x6-geometry"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@antv/x6-geometry?logo=npm&style=flat-square"></a> <a href="https://david-dm.org/antvis/x6?path=packages/x6-geometry"><img alt="Dependency Status" src="https://david-dm.org/antvis/x6.svg?style=flat-square&path=packages/x6-geometry"></a> <a href="https://david-dm.org/antvis/x6?type=dev&path=packages/x6-geometry"><img alt="devDependencies Status" src="https://david-dm.org/antvis/x6/dev-status.svg?style=flat-square&path=packages/x6-geometry" ></a>
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.5",
|
||||
"name": "@antv/x6-geometry",
|
||||
"description": "Geometry operations for X6",
|
||||
"main": "lib/index.js",
|
||||
@ -10,7 +10,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"geometry",
|
||||
|
@ -1,22 +0,0 @@
|
||||
## @antv/x6-plugin-clipboard [2.1.3](https://github.com/antvis/x6/compare/@antv/x6-plugin-clipboard@2.1.2...@antv/x6-plugin-clipboard@2.1.3) (2022-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* broken file ([d6df2d5](https://github.com/antvis/x6/commit/d6df2d59811dc18791208af36b452e11e6391f3b))
|
||||
|
||||
## @antv/x6-plugin-clipboard [2.1.2](https://github.com/antvis/x6/compare/@antv/x6-plugin-clipboard@2.1.1...@antv/x6-plugin-clipboard@2.1.2) (2022-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* npm version ([cb0cfde](https://github.com/antvis/x6/commit/cb0cfdeb4dbe8858569e6899db08ccb9ab8ba4e7))
|
||||
|
||||
## @antv/x6-plugin-clipboard [2.1.1](https://github.com/antvis/x6/compare/@antv/x6-plugin-clipboard@2.1.0...@antv/x6-plugin-clipboard@2.1.1) (2022-11-25)
|
||||
|
||||
# @antv/x6-plugin-clipboard [2.1.0](https://github.com/antvis/x6/compare/@antv/x6-plugin-clipboard@2.0.0...@antv/x6-plugin-clipboard@2.1.0) (2022-11-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* attach plugin api and events to grpah instance ([#2864](https://github.com/antvis/x6/issues/2864)) ([774f547](https://github.com/antvis/x6/commit/774f547b85522eb2411dca949d36ecfe535503f3))
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user