Compare commits
46 Commits
@antv/x6-p
...
@antv/x6-a
Author | SHA1 | Date | |
---|---|---|---|
2571cb4ceb | |||
d83bcea863 | |||
38bdf65dde | |||
f5db2bb415 | |||
a3aa2a0da2 | |||
2bce01dee8 | |||
a30b6632a0 | |||
7656b38735 | |||
d953a732b3 | |||
6317493347 | |||
8fc0b72b66 | |||
18fca29bd7 | |||
7e61014b65 | |||
8dd2b66633 | |||
76fb1acf74 | |||
709a141e28 | |||
2ee81fd94b | |||
054eb998fa | |||
e32227ae31 | |||
278b798c0a | |||
c4e11dc98f | |||
df8466aa33 | |||
1b958d626f | |||
946582c242 | |||
482d77ad09 | |||
3103c11991 | |||
3c9093f3ec | |||
8a89caab27 | |||
ed999c630c | |||
34bcd12038 | |||
9138978918 | |||
46f4c8ac2a | |||
7519b11e66 | |||
5882b6a599 | |||
9781fb48f5 | |||
c8a03ed2ba | |||
b944419572 | |||
bebc5652d1 | |||
8daa2c9b98 | |||
c510756fe4 | |||
9b4fa86daa | |||
7e86ba90d6 | |||
f27bec6bb8 | |||
c38006a358 | |||
5f2783aade | |||
fba531064a |
CONTRIBUTORSCONTRIBUTORS.svgpnpm-lock.yaml
examples/x6-example-features
package.jsonpackages
x6-angular-shape
x6-common
x6-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
sites/x6-sites
.dumirc.tsCHANGELOG.mdpackage.json
tsconfig.jsondocs
api
temp
tutorial
src/tutorial
basic/graph
auto-resize
background-grid
panning-mousewheel
transform
getting-started
@ -8,12 +8,14 @@ Draco <Draco.coder@gmail.com>
|
||||
Eve-Sama <17764594863@163.com>
|
||||
Eve-Sama <948832626@qq.com>
|
||||
Gossypol <31892817+gossypol@users.noreply.github.com>
|
||||
HQidea <HQidea@users.noreply.github.com>
|
||||
ImgBotApp <ImgBotHelp@gmail.com>
|
||||
Indomi <indomi126@gmail.com>
|
||||
James Tsang <wtzeng1@gmail.com>
|
||||
Jógvan Olsen <jogvanolsen@hotmail.com>
|
||||
Ken Geis <geis.ken@gmail.com>
|
||||
Kent Wood <minzojian@hotmail.com>
|
||||
Ko.Rei <32183014+Ko-Rei@users.noreply.github.com>
|
||||
Limbo <49612796+JUST-Limbo@users.noreply.github.com>
|
||||
Lixu <37231473+wflixu@users.noreply.github.com>
|
||||
Lloyd Zhou <lloydzhou@users.noreply.github.com>
|
||||
@ -57,6 +59,8 @@ kelin.zrh <34393362+AricZhu@users.noreply.github.com>
|
||||
kingshuaishuai <ken.wang@mrs.ai>
|
||||
kio <1421104933@qq.com>
|
||||
lijing666 <lijing241@yeah.net>
|
||||
linkun <33945539+linkun-wang@users.noreply.github.com>
|
||||
linkun <linkun0922@163.com>
|
||||
lopn <lopnxrp@126.com>
|
||||
luchunwei <luchunwei@gmail.com>
|
||||
luzhuang <364439895@qq.com>
|
||||
@ -66,6 +70,7 @@ newbyvector <vectorse@126.com>
|
||||
niexq <1879633916@qq.com>
|
||||
niexq <niexq@firstgrid.cn>
|
||||
njshuisheng <34205271+njshuisheng@users.noreply.github.com>
|
||||
nobugforever <84232410+mengYu-Jin@users.noreply.github.com>
|
||||
pengxingjian.pxj <pengxingjian.pxj@alibaba-inc.com>
|
||||
pfdgithub <pfdgithub@users.noreply.github.com>
|
||||
qingchi <qinky94@163.com>
|
||||
@ -78,6 +83,7 @@ wenbei <38773084+wb-wenbei@users.noreply.github.com>
|
||||
wgf <34190465+evelope@users.noreply.github.com>
|
||||
wind X <35559153+XueMeijing@users.noreply.github.com>
|
||||
wjqsummer <52412389+wjqsummer@users.noreply.github.com>
|
||||
wseven7677 <caoyu_92@126.com>
|
||||
wtzeng1 <wtzeng1@gmail.com>
|
||||
x6-bot <x6-bot@users.noreply.github.com>
|
||||
xrkffgg <xrkffgg@gmail.com>
|
||||
@ -91,6 +97,7 @@ zdc1111 <39116292+zdc1111@users.noreply.github.com>
|
||||
小耀 <jinyue.gjy@antfin.com>
|
||||
崖 <bubkoo.wy@gmail.com>
|
||||
崖崖崖 <bubkoo.wy@gmail.com>
|
||||
张子睿 <411489774@qq.com>
|
||||
文瑀 <wenyu.jqq@antfin.com>
|
||||
映月 <38279397+orientMoon@users.noreply.github.com>
|
||||
杨凌 <89915256@qq.com>
|
||||
|
124
CONTRIBUTORS.svg
124
CONTRIBUTORS.svg
File diff suppressed because one or more lines are too long
Before (image error) Size: 13 MiB After (image error) Size: 14 MiB |
@ -1,3 +1,17 @@
|
||||
## @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)
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@antv/x6-example-features",
|
||||
"version": "2.0.2",
|
||||
"version": "2.1.1",
|
||||
"scripts": {
|
||||
"start": "umi dev",
|
||||
"build": "umi build",
|
||||
|
@ -309,9 +309,14 @@ export default class Example extends React.Component {
|
||||
if (dataItem) {
|
||||
let item: MindMapData | null = null
|
||||
const length = dataItem.children ? dataItem.children.length : 0
|
||||
let nid = `${id}-${length + 1}`
|
||||
if (graph.hasCell(nid)) {
|
||||
// 如果通过length + 1拼接出来的节点id在画布中存在了,就在id后面加上随机数
|
||||
nid = nid + Math.random()
|
||||
}
|
||||
if (type === 'topic') {
|
||||
item = {
|
||||
id: `${id}-${length + 1}`,
|
||||
id: nid,
|
||||
type: 'topic-branch',
|
||||
label: `分支主题${length + 1}`,
|
||||
width: 100,
|
||||
@ -319,7 +324,7 @@ export default class Example extends React.Component {
|
||||
}
|
||||
} else if (type === 'topic-branch') {
|
||||
item = {
|
||||
id: `${id}-${length + 1}`,
|
||||
id: nid,
|
||||
type: 'topic-child',
|
||||
label: `子主题${length + 1}`,
|
||||
width: 60,
|
||||
|
104
examples/x6-example-features/src/pages/history/index.tsx
Normal file
104
examples/x6-example-features/src/pages/history/index.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import React from 'react'
|
||||
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 '../index.less'
|
||||
|
||||
export default class Example extends React.Component<
|
||||
{},
|
||||
{ graph: Graph | undefined }
|
||||
> {
|
||||
private container: HTMLDivElement
|
||||
|
||||
componentDidMount() {
|
||||
const graph = new Graph({
|
||||
container: this.container,
|
||||
width: 800,
|
||||
height: 600,
|
||||
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 })
|
||||
|
||||
graph.use(selection)
|
||||
graph.use(keyboard)
|
||||
graph.use(history)
|
||||
|
||||
graph.addNode({
|
||||
x: 50,
|
||||
y: 50,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: { label: { text: 'A' } },
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
x: 250,
|
||||
y: 50,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: { label: { text: 'B' } },
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
x: 350,
|
||||
y: 150,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: { label: { text: 'C' } },
|
||||
})
|
||||
|
||||
keyboard.bindKey('backspace', () => {
|
||||
graph.removeCells(selection.getSelectedCells())
|
||||
})
|
||||
keyboard.bindKey('command+z', () => {
|
||||
this.undo()
|
||||
})
|
||||
keyboard.bindKey('command+shift+z', () => {
|
||||
this.redo()
|
||||
})
|
||||
}
|
||||
|
||||
refContainer = (container: HTMLDivElement) => {
|
||||
this.container = container
|
||||
}
|
||||
|
||||
enablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph?.enablePlugins('keyboard')
|
||||
}
|
||||
|
||||
disablePlugins = () => {
|
||||
const { graph } = this.state
|
||||
graph?.disablePlugins('keyboard')
|
||||
}
|
||||
|
||||
undo = () => {
|
||||
const { graph } = this.state
|
||||
const history = graph?.getPlugin('history') as History
|
||||
history?.undo()
|
||||
}
|
||||
|
||||
redo = () => {
|
||||
const { graph } = this.state
|
||||
const history = 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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -179,6 +179,10 @@ const dataSource = [
|
||||
example: 'animation/transition',
|
||||
description: '动画',
|
||||
},
|
||||
{
|
||||
example: 'history',
|
||||
description: '时光回溯',
|
||||
},
|
||||
].map((item, index) => ({ key: index, ...item }))
|
||||
|
||||
const columns = [
|
||||
|
@ -51,7 +51,7 @@
|
||||
"prettier --write --ignore-unknown"
|
||||
],
|
||||
"*.less": [
|
||||
"stylelint --syntax less --fix"
|
||||
"stylelint --customSyntax postcss-less --fix"
|
||||
],
|
||||
"*.js": [
|
||||
"prettier --write"
|
||||
|
21
packages/x6-angular-shape/LICENSE
Normal file
21
packages/x6-angular-shape/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
136
packages/x6-angular-shape/README.md
Normal file
136
packages/x6-angular-shape/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
# @antv/x6-angular-shape
|
||||
|
||||
## 渲染节点
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-angular-shape` 以支持将 Angular 的组件/模板作为节点进行渲染。
|
||||
|
||||
### Component 渲染
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'app-node',
|
||||
templateUrl: './node.component.html',
|
||||
styleUrls: ['./node.component.scss'],
|
||||
})
|
||||
export class NodeComponent implements AfterViewInit, OnChanges {
|
||||
@Input() value: string;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-component-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: NodeComponent,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-component-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
// Input 的参数必须放在这里
|
||||
ngArguments: {
|
||||
value: '糟糕糟糕 Oh my god',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### TemplateRef 渲染
|
||||
|
||||
```html
|
||||
<ng-template #template let-data="ngArguments">
|
||||
<section class="template-container">
|
||||
<span class="value">{{ data.value }}</span>
|
||||
</section>
|
||||
</ng-template>
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
@ViewChild('template') template: TemplateRef<{}>;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-template-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: this.template,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-template-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
ngArguments: {
|
||||
value: '魔法怎么失灵啦',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 更新节点
|
||||
|
||||
无论是使用 Component 还是 TemplateRef, 都是一样的更新方式.
|
||||
```ts
|
||||
node.setData({
|
||||
ngArguments: {
|
||||
value: '晚风中闪过 几帧从前啊',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 有 demo 吗?
|
||||
|
||||
有的, 因为X6渲染节点部分与框架是解耦的. 因此 `x6-angular-shape` 包并非是直接在源代码里改的, 而是在一个单独的Angular环境中开发的. 该 demo 还提供了多种节点类型的性能测试, 详情请参考[Eve-Sama/x6-angular-shape](https://github.com/Eve-Sama/x6-angular-shape)、[X6与G6的性能对比, 以及X6多节点类型下的FPS临界点讨论](https://github.com/antvis/X6/issues/3266)
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为什么输入属性不能直接放在 data 中而需要放在 ngArguments 中? 且为什么不叫 ngInput?
|
||||
|
||||
因为并非所有 `node.data` 中的属性都是输入属性, 所以遍历 `data` 中的所有属性进行赋值是不合适的. 至于为什么叫 `ngArguments` 主要是有两点考虑.
|
||||
- 1.x版本中已经这么用了, 沿用该API可以降低用户升级成本
|
||||
- `Input` 的概念其实是来自 `Component`, 而 `TemplateRef` 中是 `context`, 在二者的基础上抽象一个 `Arguments` 的概念更通用些
|
||||
|
||||
### 2.x版本的 x6-angular-shape 相比较1.x版本有什么新特性吗?
|
||||
|
||||
实现思路其实和之前是差不多的. 但是确实有几个点值得一提.
|
||||
|
||||
#### demo更聚焦
|
||||
|
||||
1.x版本的 demo 除了渲染组件外, 还写了连线、清除等一系列案例. 看似扩展, 实则眼花缭乱. 作为 `x6-angular-shape`的 demo, 2.x版本更加聚焦, 更加聚焦于shape的使用与性能测试等, 与插件无关的内容请查看X6官网.
|
||||
|
||||
#### 功能更稳定
|
||||
|
||||
在1.x版本中, 虽然实现了功能, 但是使用场景的思考不够全面. 比如`ngArguments`的变化, 对 `TemplateRef`的场景并不生效. 虽然对`Component`生效但是无法触发`ngOnChanges`. 而在新版本中, 这些问题都将不复存在.
|
||||
|
||||
### 版本要求
|
||||
|
||||
你的Angular版本至少在14及以上才可以. 14以下需要用 hack 的方式实现一些特性, 比较麻烦. 暂时不提供, 如有需要可提issue, 我再专门介绍下如何实现.
|
65
packages/x6-angular-shape/package.json
Normal file
65
packages/x6-angular-shape/package.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "@antv/x6-angular-shape",
|
||||
"version": "2.0.0",
|
||||
"description": "X6 shape for rendering angular components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"unpkg": "dist/index.js",
|
||||
"jsdelivr": "dist/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
],
|
||||
"keywords": [
|
||||
"shape",
|
||||
"angular",
|
||||
"render",
|
||||
"x6",
|
||||
"antv"
|
||||
],
|
||||
"scripts": {
|
||||
"clean:turbo": "rss",
|
||||
"clean:build": "rss",
|
||||
"clean:coverage": "rss",
|
||||
"clean": "rss",
|
||||
"build:esm": "rss",
|
||||
"build:cjs": "rss",
|
||||
"build:umd": "rss",
|
||||
"build:dev": "rss",
|
||||
"build:watch": "rss",
|
||||
"build:watch:esm": "rss",
|
||||
"build:watch:cjs": "rss",
|
||||
"build": "rss",
|
||||
"prebuild": "rss",
|
||||
"test": "rss",
|
||||
"coveralls": "rss",
|
||||
"pretest": "rss"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x",
|
||||
"@angular/core": ">= 14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
},
|
||||
"author": {
|
||||
"name": "Eve-Sama",
|
||||
"email": "948832626@qq.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://x6.antv.antgroup.com/tutorial/intermediate/angular",
|
||||
"bugs": {
|
||||
"url": "https://github.com/antvis/x6/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/antvis/x6.git",
|
||||
"directory": "packages/x6-angular-shape"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org"
|
||||
}
|
||||
}
|
3
packages/x6-angular-shape/src/index.ts
Normal file
3
packages/x6-angular-shape/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './node'
|
||||
export * from './view'
|
||||
export * from './registry'
|
102
packages/x6-angular-shape/src/node.ts
Normal file
102
packages/x6-angular-shape/src/node.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { Node, Markup, ObjectExt } from '@antv/x6'
|
||||
|
||||
export class AngularShape<
|
||||
Properties extends AngularShape.Properties = AngularShape.Properties,
|
||||
> extends Node<Properties> {}
|
||||
|
||||
export namespace AngularShape {
|
||||
export type Primer =
|
||||
| 'rect'
|
||||
| 'circle'
|
||||
| 'path'
|
||||
| 'ellipse'
|
||||
| 'polygon'
|
||||
| 'polyline'
|
||||
|
||||
export interface Properties extends Node.Properties {
|
||||
primer?: Primer
|
||||
}
|
||||
}
|
||||
|
||||
export namespace AngularShape {
|
||||
function getMarkup(primer?: Primer) {
|
||||
const markup: Markup.JSONMarkup[] = []
|
||||
const content = Markup.getForeignObjectMarkup()
|
||||
|
||||
if (primer) {
|
||||
markup.push(
|
||||
...[
|
||||
{
|
||||
tagName: primer,
|
||||
selector: 'body',
|
||||
},
|
||||
content,
|
||||
],
|
||||
)
|
||||
} else {
|
||||
markup.push(content)
|
||||
}
|
||||
|
||||
return markup
|
||||
}
|
||||
|
||||
AngularShape.config<Properties>({
|
||||
view: 'angular-shape-view',
|
||||
markup: getMarkup(),
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'none',
|
||||
stroke: 'none',
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
},
|
||||
fo: {
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
},
|
||||
},
|
||||
propHooks(metadata: Properties) {
|
||||
if (metadata.markup == null) {
|
||||
const primer = metadata.primer
|
||||
if (primer) {
|
||||
metadata.markup = getMarkup(primer)
|
||||
|
||||
let attrs = {}
|
||||
switch (primer) {
|
||||
case 'circle':
|
||||
attrs = {
|
||||
refCx: '50%',
|
||||
refCy: '50%',
|
||||
refR: '50%',
|
||||
}
|
||||
break
|
||||
case 'ellipse':
|
||||
attrs = {
|
||||
refCx: '50%',
|
||||
refCy: '50%',
|
||||
refRx: '50%',
|
||||
refRy: '50%',
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
metadata.attrs = ObjectExt.merge(
|
||||
{},
|
||||
{
|
||||
body: {
|
||||
refWidth: null,
|
||||
refHeight: null,
|
||||
...attrs,
|
||||
},
|
||||
},
|
||||
metadata.attrs || {},
|
||||
)
|
||||
}
|
||||
}
|
||||
return metadata
|
||||
},
|
||||
})
|
||||
|
||||
Node.registry.register('angular-shape', AngularShape, true)
|
||||
}
|
32
packages/x6-angular-shape/src/registry.ts
Normal file
32
packages/x6-angular-shape/src/registry.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Injector, TemplateRef, Type } from '@angular/core'
|
||||
import { Graph, Node } from '@antv/x6'
|
||||
|
||||
export type Content = TemplateRef<any> | Type<any>
|
||||
|
||||
export type AngularShapeConfig = Node.Properties & {
|
||||
shape: string
|
||||
injector: Injector
|
||||
content: Content
|
||||
}
|
||||
|
||||
export const registerInfo: Map<
|
||||
string,
|
||||
{
|
||||
injector: Injector
|
||||
content: Content
|
||||
}
|
||||
> = new Map()
|
||||
|
||||
export function register(config: AngularShapeConfig) {
|
||||
const { shape, injector, content, ...others } = config
|
||||
registerInfo.set(shape, { injector, content })
|
||||
|
||||
Graph.registerNode(
|
||||
shape,
|
||||
{
|
||||
inherit: 'angular-shape',
|
||||
...others,
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
124
packages/x6-angular-shape/src/view.ts
Normal file
124
packages/x6-angular-shape/src/view.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import {
|
||||
ComponentRef,
|
||||
EmbeddedViewRef,
|
||||
TemplateRef,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core'
|
||||
import { Dom, NodeView } from '@antv/x6'
|
||||
import { AngularShape } from './node'
|
||||
import { Content, registerInfo } from './registry'
|
||||
|
||||
export class AngularShapeView extends NodeView<AngularShape> {
|
||||
getNodeContainer(): HTMLDivElement {
|
||||
return this.selectors && (this.selectors.foContent as HTMLDivElement)
|
||||
}
|
||||
|
||||
override confirmUpdate(flag: number): number {
|
||||
const ret = super.confirmUpdate(flag)
|
||||
return this.handleAction(ret, AngularShapeView.action, () =>
|
||||
this.renderAngularContent(),
|
||||
)
|
||||
}
|
||||
|
||||
private getNgArguments(): Record<string, any> {
|
||||
const input = (this.cell.data?.ngArguments as Record<string, any>) || {}
|
||||
return input
|
||||
}
|
||||
|
||||
/** 当执行 node.setData() 时需要对实例设置新的输入值 */
|
||||
private setInstanceInput(
|
||||
content: Content,
|
||||
ref: EmbeddedViewRef<any> | ComponentRef<any>,
|
||||
): void {
|
||||
const ngArguments = this.getNgArguments()
|
||||
if (content instanceof TemplateRef) {
|
||||
const embeddedViewRef = ref as EmbeddedViewRef<any>
|
||||
embeddedViewRef.context = { ngArguments }
|
||||
} else {
|
||||
const componentRef = ref as ComponentRef<any>
|
||||
Object.keys(ngArguments).forEach((v) =>
|
||||
componentRef.setInput(v, ngArguments[v]),
|
||||
)
|
||||
componentRef.changeDetectorRef.detectChanges()
|
||||
}
|
||||
}
|
||||
|
||||
protected renderAngularContent(): void {
|
||||
this.unmountAngularContent()
|
||||
const container = this.getNodeContainer()
|
||||
if (container) {
|
||||
const node = this.cell
|
||||
const { injector, content } = registerInfo.get(node.shape)!
|
||||
const viewContainerRef = injector.get(ViewContainerRef)
|
||||
if (content instanceof TemplateRef) {
|
||||
const ngArguments = this.getNgArguments()
|
||||
const embeddedViewRef = viewContainerRef.createEmbeddedView(content, {
|
||||
ngArguments,
|
||||
})
|
||||
embeddedViewRef.rootNodes.forEach((node) => container.appendChild(node))
|
||||
embeddedViewRef.detectChanges()
|
||||
node.on('change:data', () =>
|
||||
this.setInstanceInput(content, embeddedViewRef),
|
||||
)
|
||||
} else {
|
||||
const componentRef = viewContainerRef.createComponent(content)
|
||||
const insertNode = (componentRef.hostView as EmbeddedViewRef<any>)
|
||||
.rootNodes[0] as HTMLElement
|
||||
container.appendChild(insertNode)
|
||||
this.setInstanceInput(content, componentRef)
|
||||
node.on('change:data', () =>
|
||||
this.setInstanceInput(content, componentRef),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected unmountAngularContent(): HTMLDivElement {
|
||||
const container = this.getNodeContainer()
|
||||
container.innerHTML = ''
|
||||
return container
|
||||
}
|
||||
|
||||
override onMouseDown(e: Dom.MouseDownEvent, x: number, y: number) {
|
||||
const target = e.target as Element
|
||||
const tagName = target.tagName.toLowerCase()
|
||||
if (tagName === 'input') {
|
||||
const type = target.getAttribute('type')
|
||||
if (
|
||||
type == null ||
|
||||
[
|
||||
'text',
|
||||
'password',
|
||||
'number',
|
||||
'email',
|
||||
'search',
|
||||
'tel',
|
||||
'url',
|
||||
].includes(type)
|
||||
) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.onMouseDown(e, x, y)
|
||||
}
|
||||
|
||||
override unmount(): this {
|
||||
this.unmountAngularContent()
|
||||
super.unmount()
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export namespace AngularShapeView {
|
||||
export const action = 'angular' as any
|
||||
|
||||
AngularShapeView.config({
|
||||
bootstrap: [action],
|
||||
actions: {
|
||||
component: action,
|
||||
},
|
||||
})
|
||||
|
||||
NodeView.registry.register('angular-shape-view', AngularShapeView, true)
|
||||
}
|
3
packages/x6-angular-shape/tsconfig.json
Normal file
3
packages/x6-angular-shape/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
@ -1,3 +1,17 @@
|
||||
## @antv/x6-common [2.0.10](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.9...@antv/x6-common@2.0.10) (2023-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add textLength & lengthAdjust to CASE_SENSITIVE_ATTR ([#3281](https://github.com/antvis/x6/issues/3281)) ([76fb1ac](https://github.com/antvis/x6/commit/76fb1acf74b0f1c308f7c824d02c12244b7ac8f3))
|
||||
|
||||
## @antv/x6-common [2.0.8](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.7...@antv/x6-common@2.0.8) (2023-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix typo for dom event handlers ([#3255](https://github.com/antvis/x6/issues/3255)) ([9b4fa86](https://github.com/antvis/x6/commit/9b4fa86daa587fe8818f3615bc1e40738a0f2319))
|
||||
|
||||
## @antv/x6-common [2.0.6](https://github.com/antvis/x6/compare/@antv/x6-common@2.0.5...@antv/x6-common@2.0.6) (2023-01-31)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-common",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.10",
|
||||
"description": "Basic toolkit for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -6,6 +6,8 @@ export const CASE_SENSITIVE_ATTR = [
|
||||
'attributeName',
|
||||
'attributeType',
|
||||
'repeatCount',
|
||||
'textLength',
|
||||
'lengthAdjust',
|
||||
]
|
||||
|
||||
export type Attributes = { [key: string]: string | number | null | undefined }
|
||||
|
@ -729,7 +729,7 @@ type TypeEventHandlersBase<TDelegateTarget, TData, TCurrentTarget, TTarget> = {
|
||||
TCurrentTarget,
|
||||
TTarget
|
||||
>]?:
|
||||
| TypeEventHandler<TDelegateTarget, TData, TCurrentTarget, TTarget, TType>
|
||||
| TypeEventHandler<TDelegateTarget, TData, TCurrentTarget, TTarget, string>
|
||||
| false
|
||||
| Record<string, unknown>
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export { debounce } from 'lodash-es'
|
||||
export { debounce, throttle } from 'lodash-es'
|
||||
|
||||
type Fn = (...args: any[]) => any
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,3 +1,10 @@
|
||||
# @antv/x6-plugin-history [2.2.0](https://github.com/antvis/x6/compare/@antv/x6-plugin-history@2.1.3...@antv/x6-plugin-history@2.2.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-plugin-history [2.1.3](https://github.com/antvis/x6/compare/@antv/x6-plugin-history@2.1.2...@antv/x6-plugin-history@2.1.3) (2022-11-25)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-plugin-history",
|
||||
"version": "2.1.3",
|
||||
"version": "2.2.0",
|
||||
"description": "history plugin for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -25,6 +25,7 @@ export class History
|
||||
protected batchLevel = 0
|
||||
protected lastBatchIndex = -1
|
||||
protected freezed = false
|
||||
protected stackSize = 0 // 0: not limit
|
||||
|
||||
protected readonly handlers: (<T extends History.ModelEvents>(
|
||||
event: T,
|
||||
@ -33,6 +34,8 @@ export class History
|
||||
|
||||
constructor(options: History.Options) {
|
||||
super()
|
||||
const { stackSize = 0 } = options
|
||||
this.stackSize = stackSize
|
||||
this.options = Util.getOptions(options)
|
||||
this.validator = new History.Validator({
|
||||
history: this,
|
||||
@ -101,7 +104,7 @@ export class History
|
||||
const cmd = this.redoStack.pop()
|
||||
if (cmd) {
|
||||
this.applyCommand(cmd, options)
|
||||
this.undoStack.push(cmd)
|
||||
this.undoStackPush(cmd)
|
||||
this.notify('redo', cmd, options)
|
||||
}
|
||||
}
|
||||
@ -424,7 +427,7 @@ export class History
|
||||
const cmds = this.filterBatchCommand(this.batchCommands)
|
||||
if (cmds.length > 0) {
|
||||
this.redoStack = []
|
||||
this.undoStack.push(cmds)
|
||||
this.undoStackPush(cmds)
|
||||
this.consolidateCommands()
|
||||
this.notify('add', cmds, options)
|
||||
}
|
||||
@ -498,7 +501,7 @@ export class History
|
||||
this.lastBatchIndex = Math.max(this.lastBatchIndex, 0)
|
||||
this.emit('batch', { cmd, options })
|
||||
} else {
|
||||
this.undoStack.push(cmd)
|
||||
this.undoStackPush(cmd)
|
||||
this.consolidateCommands()
|
||||
this.notify('add', cmd, options)
|
||||
}
|
||||
@ -560,6 +563,17 @@ export class History
|
||||
this.undoStack.pop()
|
||||
}
|
||||
|
||||
protected undoStackPush(cmd: History.Commands) {
|
||||
if (this.stackSize === 0) {
|
||||
this.undoStack.push(cmd)
|
||||
return
|
||||
}
|
||||
if (this.undoStack.length >= this.stackSize) {
|
||||
this.undoStack.shift()
|
||||
}
|
||||
this.undoStack.push(cmd)
|
||||
}
|
||||
|
||||
@Basecoat.dispose()
|
||||
dispose() {
|
||||
this.validator.dispose()
|
||||
@ -614,7 +628,9 @@ export namespace History {
|
||||
cancelInvalid?: boolean
|
||||
}
|
||||
|
||||
export interface Options extends Partial<CommonOptions> {}
|
||||
export interface Options extends Partial<CommonOptions> {
|
||||
stackSize?: number
|
||||
}
|
||||
|
||||
interface Data {
|
||||
id?: string
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-plugin-transform [2.1.6](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.5...@antv/x6-plugin-transform@2.1.6) (2023-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* transform active-handle class should remove when active removed ([#3298](https://github.com/antvis/x6/issues/3298)) ([709a141](https://github.com/antvis/x6/commit/709a141e28e9f25d54ece0ade353bd343ac0e55f))
|
||||
|
||||
## @antv/x6-plugin-transform [2.1.5](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.4...@antv/x6-plugin-transform@2.1.5) (2022-12-24)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-plugin-transform",
|
||||
"version": "2.1.5",
|
||||
"version": "2.1.6",
|
||||
"description": "transform plugin for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -493,7 +493,7 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
|
||||
Dom.removeClass(this.container, `${this.containerClassName}-active`)
|
||||
|
||||
if (this.handle) {
|
||||
Dom.removeClass(this.handle, `${this.containerClassName}-active`)
|
||||
Dom.removeClass(this.handle, `${this.containerClassName}-active-handle`)
|
||||
|
||||
const pos = this.handle.getAttribute(
|
||||
'data-position',
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6",
|
||||
"version": "2.3.0",
|
||||
"version": "2.5.1",
|
||||
"description": "JavaScript diagramming library that uses SVG and HTML for rendering",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Dom } from '@antv/x6-common'
|
||||
import { Model } from '../model'
|
||||
import { CellView } from '../view'
|
||||
import { Scheduler } from '../renderer/scheduler'
|
||||
|
||||
interface CommonEventArgs<E> {
|
||||
e: E
|
||||
@ -13,7 +14,8 @@ interface PositionEventArgs<E> extends CommonEventArgs<E> {
|
||||
|
||||
export interface EventArgs
|
||||
extends Omit<Model.EventArgs, 'sorted' | 'updated' | 'reseted'>,
|
||||
CellView.EventArgs {
|
||||
CellView.EventArgs,
|
||||
Scheduler.EventArgs {
|
||||
'model:sorted'?: Model.EventArgs['sorted']
|
||||
'model:updated': Model.EventArgs['updated']
|
||||
'model:reseted': Model.EventArgs['reseted']
|
||||
|
@ -3,7 +3,9 @@ import { Base } from './base'
|
||||
|
||||
export class VirtualRenderManager extends Base {
|
||||
protected init() {
|
||||
this.resetRenderArea = FunctionExt.debounce(this.resetRenderArea, 200)
|
||||
this.resetRenderArea = FunctionExt.throttle(this.resetRenderArea, 200, {
|
||||
leading: true,
|
||||
})
|
||||
this.resetRenderArea()
|
||||
this.startListening()
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ export class CellEditor extends ToolsView.ToolItem<
|
||||
index: this.labelIndex,
|
||||
})
|
||||
}
|
||||
|
||||
editor.innerText = text || ''
|
||||
|
||||
// clear display value when edit status because char ghosting.
|
||||
@ -105,7 +106,8 @@ export class CellEditor extends ToolsView.ToolItem<
|
||||
const cell = this.cell
|
||||
const value = this.editor.innerText.replace(/\n$/, '') || ''
|
||||
// set value
|
||||
this.setCellText(value)
|
||||
// when value is null, we will remove label in edge
|
||||
this.setCellText(value !== '' ? value : null)
|
||||
// remove tool
|
||||
cell.removeTool(cell.isEdge() ? 'edge-editor' : 'node-editor')
|
||||
this.undelegateDocumentEvents()
|
||||
@ -137,7 +139,7 @@ export class CellEditor extends ToolsView.ToolItem<
|
||||
}
|
||||
}
|
||||
|
||||
setCellText(value: string) {
|
||||
setCellText(value: string | null) {
|
||||
const setText = this.options.setText
|
||||
if (typeof setText === 'function') {
|
||||
FunctionExt.call(setText, this.cellView, {
|
||||
@ -170,7 +172,7 @@ export namespace CellEditor {
|
||||
this: CellView,
|
||||
args: {
|
||||
cell: Cell
|
||||
value: string
|
||||
value: string | null
|
||||
index?: number
|
||||
distance?: number
|
||||
},
|
||||
@ -204,7 +206,9 @@ export namespace CellEditor {
|
||||
return cell.attr('text/text')
|
||||
},
|
||||
setText({ cell, value }) {
|
||||
cell.attr('text/text', value)
|
||||
if (value !== null) {
|
||||
cell.attr('text/text', value)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@ -225,18 +229,20 @@ export namespace CellEditor {
|
||||
setText({ cell, value, index, distance }) {
|
||||
const edge = cell as Edge
|
||||
if (index === -1) {
|
||||
edge.appendLabel({
|
||||
position: {
|
||||
distance: distance!,
|
||||
},
|
||||
attrs: {
|
||||
label: {
|
||||
text: value,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
if (value) {
|
||||
edge.appendLabel({
|
||||
position: {
|
||||
distance: distance!,
|
||||
},
|
||||
attrs: {
|
||||
label: {
|
||||
text: value,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (value !== null) {
|
||||
edge.prop(`labels/${index}/attrs/label/text`, value)
|
||||
} else if (typeof index === 'number') {
|
||||
edge.removeLabelAt(index)
|
||||
|
@ -313,6 +313,7 @@ export class Scheduler extends Disposable {
|
||||
}
|
||||
|
||||
viewItem.state = Scheduler.ViewState.MOUNTED
|
||||
this.graph.trigger('view:mounted', { view })
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,6 +335,7 @@ export class Scheduler extends Disposable {
|
||||
if (view) {
|
||||
viewItem.view.remove()
|
||||
delete this.willRemoveViews[cell.id]
|
||||
this.graph.trigger('view:unmounted', { view })
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,10 +452,16 @@ export class Scheduler extends Disposable {
|
||||
for (let i = 0, n = edges.length; i < n; i += 1) {
|
||||
const edge = edges[i]
|
||||
const viewItem = this.views[edge.id]
|
||||
|
||||
if (!viewItem) {
|
||||
continue
|
||||
}
|
||||
|
||||
const edgeView = viewItem.view
|
||||
if (!this.isViewMounted(edgeView)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const flagLabels: FlagManager.Action[] = ['update']
|
||||
if (edge.getTargetCell() === cell) {
|
||||
flagLabels.push('target')
|
||||
@ -472,10 +480,33 @@ export class Scheduler extends Disposable {
|
||||
}
|
||||
|
||||
protected isInRenderArea(view: CellView) {
|
||||
return (
|
||||
!this.renderArea ||
|
||||
this.renderArea.isIntersectWithRect(view.cell.getBBox())
|
||||
)
|
||||
if (!this.renderArea) {
|
||||
return true
|
||||
}
|
||||
if (view.isNodeView()) {
|
||||
const node = view.cell
|
||||
return this.renderArea.isIntersectWithRect(node.getBBox())
|
||||
}
|
||||
if (view.isEdgeView()) {
|
||||
const edge = view.cell
|
||||
const sourceCell = edge.getSourceCell()
|
||||
const targetCell = edge.getTargetCell()
|
||||
if (sourceCell) {
|
||||
const sourceViewItem = this.views[sourceCell.id]
|
||||
if (sourceViewItem && !this.isViewMounted(sourceViewItem.view)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (targetCell) {
|
||||
const targetViewItem = this.views[targetCell.id]
|
||||
if (targetViewItem && !this.isViewMounted(targetViewItem.view)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
protected getRenderPriority(view: CellView) {
|
||||
@ -507,4 +538,9 @@ export namespace Scheduler {
|
||||
options: any
|
||||
state: ViewState
|
||||
}
|
||||
|
||||
export interface EventArgs {
|
||||
'view:mounted': { view: CellView }
|
||||
'view:unmounted': { view: CellView }
|
||||
}
|
||||
}
|
||||
|
62166
pnpm-lock.yaml
generated
62166
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
import { defineConfig } from 'dumi'
|
||||
import { repository, version } from './package.json'
|
||||
import { repository } from './package.json'
|
||||
|
||||
export default defineConfig({
|
||||
locales: [
|
||||
@ -22,7 +22,7 @@ export default defineConfig({
|
||||
showChartResize: true, // 是否在 demo 页展示图表视图切换
|
||||
showAPIDoc: false, // 是否在 demo 页展示API文档
|
||||
versions: {
|
||||
[version]: 'https://x6.antv.antgroup.com',
|
||||
'2.x': 'https://x6.antv.antgroup.com',
|
||||
'1.x': 'https://x6.antv.vision',
|
||||
},
|
||||
navs: [
|
||||
@ -288,8 +288,10 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
docsearchOptions: {
|
||||
apiKey: 'fe8bee8366e56a9463229c3c81200866',
|
||||
indexName: 'antv_x6',
|
||||
appId: '7J0MWEOGMO',
|
||||
apiKey: 'e0d8089bb224298dfd4415b3e98bb700',
|
||||
indexName: 'x6_sites_2.0',
|
||||
versionV3: true,
|
||||
},
|
||||
playground: {
|
||||
extraLib: '',
|
||||
|
@ -1,3 +1,11 @@
|
||||
## @antv/x6-sites [1.5.5](https://github.com/antvis/x6/compare/@antv/x6-sites@1.5.4...@antv/x6-sites@1.5.5) (2023-02-27)
|
||||
|
||||
## @antv/x6-sites [1.5.4](https://github.com/antvis/x6/compare/@antv/x6-sites@1.5.3...@antv/x6-sites@1.5.4) (2023-02-24)
|
||||
|
||||
## @antv/x6-sites [1.5.3](https://github.com/antvis/x6/compare/@antv/x6-sites@1.5.2...@antv/x6-sites@1.5.3) (2023-02-23)
|
||||
|
||||
## @antv/x6-sites [1.5.2](https://github.com/antvis/x6/compare/@antv/x6-sites@1.5.1...@antv/x6-sites@1.5.2) (2023-02-18)
|
||||
|
||||
# @antv/x6-sites [1.5.0](https://github.com/antvis/x6/compare/@antv/x6-sites@1.4.1...@antv/x6-sites@1.5.0) (2023-02-06)
|
||||
|
||||
|
||||
|
@ -241,8 +241,9 @@ getBBox(): Rectangle
|
||||
|
||||
返回边的包围盒。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该方法通过边的端点和路径点计算包围盒,并不是渲染到画布后的包围盒,涉及的计算只是一些算数运算。
|
||||
:::
|
||||
|
||||
#### getPolyline()
|
||||
|
||||
|
@ -499,7 +499,7 @@ function parseStringLabel(label: string): Label {
|
||||
|
||||
```ts
|
||||
Edge.config({
|
||||
defaultlabel: {
|
||||
defaultLabel: {
|
||||
markup: [
|
||||
{
|
||||
tagName: "rect",
|
||||
|
@ -716,7 +716,7 @@ toJSON(options?: ToJSONOptions): object
|
||||
|
||||
| 名称 | 类型 | 必选 | 默认值 | 描述 |
|
||||
| ------------ | ---- | :--: | ------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| options.deep | diff | | `false` | 是否导出节点和边的差异数据(与节点和边的[默认配置](/zh/docs/tutorial/basic/cell#选项默认值)不同的部分)。 |
|
||||
| options.deep | diff | | `false` | 是否导出节点和边的差异数据(与节点和边的[默认配置](/zh/docs/api/model/cell#选项默认值)不同的部分)。 |
|
||||
|
||||
### parseJSON(...)
|
||||
|
||||
|
@ -247,8 +247,9 @@ getBBox(options: { deep?: boolean }): Rectangle
|
||||
|
||||
获取节点的包围盒。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该方法通过节点的大小和位置计算包围盒,并不是渲染到画布后的包围盒,涉及的计算只是一些算数运算。
|
||||
:::
|
||||
|
||||
<span class="tag-param">参数<span>
|
||||
|
||||
|
@ -78,8 +78,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的宽度是参照宽度百分之多少。例如 `refWidth: 0.75` 表示元素的宽度是参照宽度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的宽度在参照宽度的基础上减少或增加多少。例如 `refWidth: 20` 表示元素比相对元素宽 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持宽度 `width` 和高度 `height` 的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refWidth2
|
||||
|
||||
@ -101,8 +102,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的高度是参照高度百分之多少。例如 `refHeight: 0.75` 表示元素的高度是参照高度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的高度在参照高度的基础上减少或增加多少。例如 `refHeight: 20` 表示元素比相对元素高 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持宽度 `width` 和高度 `height` 的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refHeight2
|
||||
|
||||
@ -124,8 +126,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的 `cx` 是参照宽度百分之多少。例如 `refCx: 0.75` 表示元素中心 `x` 坐标位于参照宽度的 `75%` 处。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的 `cx` 是在参照宽度的基础上减少或增加多少。例如 `refCx: 20` 表示元素中心 `x` 坐标位于参照宽度加 `20px` 处。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `cx` 和 `cy` 属性的元素,如 `<ellipse>` 元素。
|
||||
:::
|
||||
|
||||
### refCy
|
||||
|
||||
@ -134,8 +137,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的 `cy` 是参照高度百分之多少。例如 `refCy: 0.75` 表示元素中心 `y` 坐标位于参照高度的 `75%` 处。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的 `cy` 是在参照宽度的基础上减少或增加多少。例如 `refCy: 20` 表示元素中心 `y` 坐标位于参照高度加 `20px` 处。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `cx` 和 `cy` 属性的元素,如 `<ellipse>` 元素。
|
||||
:::
|
||||
|
||||
### refRx
|
||||
|
||||
@ -144,8 +148,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的 `rx` 是参照宽度百分之多少。例如 `refRx: 0.75` 表示元素的 `rx` 是参照宽度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的 `rx` 是在参照宽度的基础上减少或增加多少。例如 `refRx: 20` 表示元素的 `rx` 是参照宽度加 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `rx` 和 `ry` 属性的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refRy
|
||||
|
||||
@ -154,8 +159,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示元素的 `ry` 是参照高度百分之多少。例如 `refRy: 0.75` 表示元素的 `ry` 是参照高度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示元素的 `ry` 是在参照宽度的基础上减少或增加多少。例如 `refRy: 20` 表示元素的 `ry` 是参照高度加 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `rx` 和 `ry` 属性的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refRCircumscribed
|
||||
|
||||
@ -164,8 +170,9 @@ redirect_from:
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示 `r` 是参照长度百分之多少。例如 `refRCircumscribed: 0.75` 表示 `r` 是参照长度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示 `r` 是在参照长度的基础上减少或增加多少。例如 `refRCircumscribed: 20` 表示 `r` 是参照长度加 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `r` 属性的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refRInscribed
|
||||
|
||||
@ -176,8 +183,9 @@ _简称_:**`refR`**
|
||||
- 当其值在 `[0, 1]` 之间或为百分比(如 `75%`)时,表示 `r` 是参照长度百分之多少。例如 `refRInscribed: 0.75` 表示 `r` 是参照长度的 `75%`。
|
||||
- 当其值 `<0` 或 `>1` 时,表示 `r` 是在参照长度的基础上减少或增加多少。例如 `refRInscribed: 20` 表示 `r` 是参照长度加 `20px`。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该属性只适用于那些支持 `r` 属性的元素,如 `<rect>` 元素。
|
||||
:::
|
||||
|
||||
### refDKeepOffset
|
||||
|
||||
@ -561,8 +569,9 @@ edge.attr("connection/sourceMarker", {
|
||||
|
||||
适用于所有 `<path>` 元素,在路径的终点添加一个 SVG 元素(如终点箭头),并自动旋转该元素,使其与根据路径方向保持一致。了解更多详情请参考[这篇教程](/zh/docs/tutorial/intermediate/marker)。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,该元素初始时就被旋转了 `180` 度,在此基础上再自动调整旋转角度,并与路径的方向保持一致。例如,对于一个水平的直线,我们为其起点指定了一个向左的箭头,我们也可以为其重点指定相同的箭头,这个箭头会自动指向右侧(自动旋转了 `180` 度)。
|
||||
:::
|
||||
|
||||
### vertexMarker
|
||||
|
||||
|
@ -62,8 +62,9 @@ graph.addNode({
|
||||
|
||||
上面这些属性默认相对于节点的大小进行计算,另外我们可以通过 `ref` 属性来提供一个子元素选择器,这时所有的计算都相对于 `ref` 指代的元素,从而实现相对于子元素的大小和位置。
|
||||
|
||||
[[warning]]
|
||||
:::warning{title=注意:}
|
||||
| 需要注意的是,设置 `ref` 后,所有计算都依赖子元素在浏览器中的 bbox 测量,所以性能会比相对于节点的方式要慢。
|
||||
:::
|
||||
|
||||
```ts
|
||||
graph.addNode({
|
||||
|
@ -21,7 +21,7 @@ redirect_from:
|
||||
|
||||
在项目实践中,经常会遇到下面两种场景:
|
||||
|
||||
- 画布容器还没有渲染完成(此时尺寸为 0),就实例化画布对象,导致布元素显示异常。
|
||||
- 画布容器还没有渲染完成(此时尺寸为 0),就实例化画布对象,导致画布元素显示异常。
|
||||
- 页面的 `resize` 导致画布容器大小改变,导致画布元素显示异常。
|
||||
|
||||
我们可以使用 `autoResize` 配置来解决上述问题。
|
||||
|
150
sites/x6-sites/docs/tutorial/intermediate/angular.md
Normal file
150
sites/x6-sites/docs/tutorial/intermediate/angular.md
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
title: Angular 节点
|
||||
order: 4
|
||||
redirect_from:
|
||||
- /zh/docs
|
||||
- /zh/docs/tutorial
|
||||
- /zh/docs/tutorial/inermediate
|
||||
---
|
||||
|
||||
:::info{title=在本章节中,你可以了解到:}
|
||||
|
||||
- 如何使用 Angular 来渲染节点内容
|
||||
- 如何更新节点内容
|
||||
- FAQ
|
||||
:::
|
||||
|
||||
## 渲染节点
|
||||
|
||||
我们提供了一个独立的包 `@antv/x6-angular-shape` 以支持将 Angular 的组件/模板作为节点进行渲染。
|
||||
|
||||
### Component 渲染
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'app-node',
|
||||
templateUrl: './node.component.html',
|
||||
styleUrls: ['./node.component.scss'],
|
||||
})
|
||||
export class NodeComponent implements AfterViewInit, OnChanges {
|
||||
@Input() value: string;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-component-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: NodeComponent,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-component-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
// Input 的参数必须放在这里
|
||||
ngArguments: {
|
||||
value: '糟糕糟糕 Oh my god',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### TemplateRef 渲染
|
||||
|
||||
```html
|
||||
<ng-template #template let-data="ngArguments">
|
||||
<section class="template-container">
|
||||
<span class="value">{{ data.value }}</span>
|
||||
</section>
|
||||
</ng-template>
|
||||
```
|
||||
|
||||
```ts
|
||||
import { register } from "@antv/x6-angular-shape";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements AfterViewInit {
|
||||
@ViewChild('template') template: TemplateRef<{}>;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
register({
|
||||
shape: 'custom-angular-template-node',
|
||||
width: 120,
|
||||
height: 20,
|
||||
content: this.template,
|
||||
injector: this.injector,
|
||||
});
|
||||
|
||||
this.graph.addNode({
|
||||
shape: 'custom-angular-template-node',
|
||||
x: 100,
|
||||
y: 100,
|
||||
data: {
|
||||
ngArguments: {
|
||||
value: '魔法怎么失灵啦',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 更新节点
|
||||
|
||||
无论是使用 Component 还是 TemplateRef, 都是一样的更新方式.
|
||||
```ts
|
||||
node.setData({
|
||||
ngArguments: {
|
||||
value: '晚风中闪过 几帧从前啊',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 有 demo 吗?
|
||||
|
||||
有的, 因为X6渲染节点部分与框架是解耦的. 因此 `x6-angular-shape` 包并非是直接在源代码里改的, 而是在一个单独的Angular环境中开发的. 该 demo 还提供了多种节点类型的性能测试, 详情请参考[Eve-Sama/x6-angular-shape](https://github.com/Eve-Sama/x6-angular-shape)、[X6与G6的性能对比, 以及X6多节点类型下的FPS临界点讨论](https://github.com/antvis/X6/issues/3266)
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为什么输入属性不能直接放在 data 中而需要放在 ngArguments 中? 且为什么不叫 ngInput?
|
||||
|
||||
因为并非所有 `node.data` 中的属性都是输入属性, 所以遍历 `data` 中的所有属性进行赋值是不合适的. 至于为什么叫 `ngArguments` 主要是有两点考虑.
|
||||
- 1.x版本中已经这么用了, 沿用该API可以降低用户升级成本
|
||||
- `Input` 的概念其实是来自 `Component`, 而 `TemplateRef` 中是 `context`, 在二者的基础上抽象一个 `Arguments` 的概念更通用些
|
||||
|
||||
### 2.x版本的 x6-angular-shape 相比较1.x版本有什么新特性吗?
|
||||
|
||||
实现思路其实和之前是差不多的. 但是确实有几个点值得一提.
|
||||
|
||||
#### demo更聚焦
|
||||
|
||||
1.x版本的 demo 除了渲染组件外, 还写了连线、清除等一系列案例. 看似扩展, 实则眼花缭乱. 作为 `x6-angular-shape`的 demo, 2.x版本更加聚焦, 更加聚焦于shape的使用与性能测试等, 与插件无关的内容请查看X6官网.
|
||||
|
||||
#### 功能更稳定
|
||||
|
||||
在1.x版本中, 虽然实现了功能, 但是使用场景的思考不够全面. 比如`ngArguments`的变化, 对 `TemplateRef`的场景并不生效. 虽然对`Component`生效但是无法触发`ngOnChanges`. 而在新版本中, 这些问题都将不复存在.
|
||||
|
||||
### 版本要求
|
||||
|
||||
你的Angular版本至少在14及以上才可以. 14以下需要用 hack 的方式实现一些特性, 比较麻烦. 暂时不提供, 如有需要可提issue, 我再专门介绍下如何实现.
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: HTML 节点
|
||||
order: 4
|
||||
order: 7
|
||||
redirect_from:
|
||||
- /zh/docs
|
||||
- /zh/docs/tutorial
|
||||
|
@ -54,6 +54,7 @@ graph.use(
|
||||
| 属性名 | 类型 | 默认值 | 必选 | 描述 |
|
||||
| ---------------- | ------------------------------- | ------- | ---- | ---------------------------------------------------------------------------------------------------- |
|
||||
| enabled | boolean | `false` | | 是否开启撤销重做功能 |
|
||||
| stackSize | number | `0` | | `stackSize` 为 0 表示不限制历史记录栈的长度,如果设置为其他数字表示最多只会记录该数字长度的历史记录 |
|
||||
| ignoreAdd | boolean | `false` | | `ignoreAdd` 如果为 `true`,添加添加元素不会被记录到历史记录 |
|
||||
| ignoreRemove | boolean | `false` | | `ignoreRemove` 如果为 `true`,删除元素不会被记录到历史记录 |
|
||||
| ignoreChange | boolean | `false` | | `ignoreChange` 如果为 `true`,元素属性变化是否被记录到历史记录 |
|
||||
|
@ -97,7 +97,7 @@ export interface Group {
|
||||
graphWidth?: number; // 模板画布宽度
|
||||
graphHeight?: number; // 模板画布高度
|
||||
graphPadding?: number; // 模板画布边距
|
||||
graphOptions?: Graph.Options; // 模板画布线下
|
||||
graphOptions?: Graph.Options; // 模板画布选项
|
||||
layout?: (this: Stencil, model: Model, group?: Group | null) => any;
|
||||
layoutOptions?: any; // 布局选项
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@antv/x6-sites",
|
||||
"version": "2.3.0",
|
||||
"version": "1.5.5",
|
||||
"description": "X6 sites deployed on gh-pages",
|
||||
"scripts": {
|
||||
"dev": "dumi dev",
|
||||
@ -31,9 +31,9 @@
|
||||
"@antv/x6-plugin-transform": "^2.x",
|
||||
"@antv/x6-react-components": "^2.x",
|
||||
"@antv/x6-react-shape": "^2.x",
|
||||
"antd": "^4.4.2",
|
||||
"antd": "^5.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dumi": "2.0.16",
|
||||
"dumi": "^2.1.14",
|
||||
"elkjs": "^0.8.2",
|
||||
"highlight.js": "^10.1.2",
|
||||
"react": "^18.0.0",
|
||||
|
@ -1,29 +1,26 @@
|
||||
.app {
|
||||
.auto-resize-app {
|
||||
display: flex;
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.full {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:global {
|
||||
.x6-split-box-horizontal > .x6-split-box-resizer,
|
||||
.x6-split-box-vertical > .x6-split-box-resizer {
|
||||
background: #e3e6e9;
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.full {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.x6-split-box-horizontal > .x6-split-box-resizer,
|
||||
.x6-split-box-vertical > .x6-split-box-resizer {
|
||||
background: #e3e6e9;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import { SplitBox } from '@antv/x6-react-components'
|
||||
import '@antv/x6-react-components/es/split-box/style/index.css'
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
export default class Example extends React.Component {
|
||||
private container1: HTMLDivElement
|
||||
@ -50,16 +50,16 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className="auto-resize-app">
|
||||
<SplitBox split="horizontal">
|
||||
<div className={styles.full}>
|
||||
<div className="full">
|
||||
<div ref={this.refContainer1} />
|
||||
</div>
|
||||
<SplitBox split="vertical">
|
||||
<div className={styles.full}>
|
||||
<div className="full">
|
||||
<div ref={this.refContainer2} />
|
||||
</div>
|
||||
<div className={styles.full}>
|
||||
<div className="full">
|
||||
<div ref={this.refContainer3} />
|
||||
</div>
|
||||
</SplitBox>
|
||||
|
@ -1,15 +1,15 @@
|
||||
.app {
|
||||
.backgournd-grid-app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
@ -93,8 +93,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="backgournd-grid-app">
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
.app {
|
||||
.panning-mousewheel-app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
@ -98,8 +98,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="panning-mousewheel-app">
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.transform-app {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-btns {
|
||||
bottom: 0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
.app-btns {
|
||||
bottom: 0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
height: 240px;
|
||||
margin-top: 16px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
.app-content {
|
||||
width: 100%;
|
||||
height: 240px;
|
||||
margin-top: 16px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import { Button } from 'antd'
|
||||
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
@ -150,8 +149,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-btns']}>
|
||||
<div className="transform-app">
|
||||
<div className="app-btns">
|
||||
<Button.Group>
|
||||
{commands.map((item) => (
|
||||
<Button onClick={() => this.transform(item.key)} key={item.key}>
|
||||
@ -160,7 +159,7 @@ export default class Example extends React.Component {
|
||||
))}
|
||||
</Button.Group>
|
||||
</div>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
.app {
|
||||
.helloworld-app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Graph } from '@antv/x6'
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
@ -81,8 +81,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="helloworld-app">
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
.app {
|
||||
.react-shape-app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.custom-react-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #8f8f8f;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.custom-react-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #8f8f8f;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.custom-react-node span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.custom-react-node span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { Graph, Node } from '@antv/x6'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
import { Dropdown } from 'antd'
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const CustomComponent = ({ node }: { node: Node }) => {
|
||||
const label = node.prop('label')
|
||||
@ -26,7 +26,7 @@ const CustomComponent = ({ node }: { node: Node }) => {
|
||||
}}
|
||||
trigger={['contextMenu']}
|
||||
>
|
||||
<div className={styles['custom-react-node']}>{label}</div>
|
||||
<div className="custom-react-node">{label}</div>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@ -92,8 +92,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="react-shape-app">
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
.app {
|
||||
.use-plugin-app {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
padding: 16px 8px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.custom-react-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #8f8f8f;
|
||||
border-radius: 6px;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
height: 280px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.custom-react-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #8f8f8f;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ import { Graph, Node } from '@antv/x6'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
import { Dropdown } from 'antd'
|
||||
import { Snapline } from '@antv/x6-plugin-snapline'
|
||||
|
||||
import styles from './index.less'
|
||||
import './index.less'
|
||||
|
||||
const CustomComponent = ({ node }: { node: Node }) => {
|
||||
const label = node.prop('label')
|
||||
@ -28,7 +27,7 @@ const CustomComponent = ({ node }: { node: Node }) => {
|
||||
}}
|
||||
trigger={['contextMenu']}
|
||||
>
|
||||
<div className={styles['custom-react-node']}>{label}</div>
|
||||
<div className="custom-react-node">{label}</div>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@ -99,8 +98,8 @@ export default class Example extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<div className={styles['app-content']} ref={this.refContainer} />
|
||||
<div className="use-plugin-app">
|
||||
<div className="app-content" ref={this.refContainer} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "react",
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"lib": ["DOM", "ES2020"]
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user